@@ -81,14 +81,26 @@ int git_tree_entry_icmp(const git_tree_entry *e1, const git_tree_entry *e2)
81
81
git__strncasecmp );
82
82
}
83
83
84
- static git_tree_entry * alloc_entry (const char * filename )
84
+ /**
85
+ * Allocate either from the pool or from the system allocator
86
+ */
87
+ static git_tree_entry * alloc_entry_base (git_pool * pool , const char * filename , size_t filename_len )
85
88
{
86
89
git_tree_entry * entry = NULL ;
87
- size_t filename_len = strlen (filename ), tree_len ;
90
+ size_t tree_len ;
91
+
92
+ if (filename_len > UINT16_MAX ) {
93
+ giterr_set (GITERR_INVALID , "tree entry is over UINT16_MAX in length" );
94
+ return NULL ;
95
+ }
88
96
89
97
if (GIT_ADD_SIZET_OVERFLOW (& tree_len , sizeof (git_tree_entry ), filename_len ) ||
90
- GIT_ADD_SIZET_OVERFLOW (& tree_len , tree_len , 1 ) ||
91
- !(entry = git__malloc (tree_len )))
98
+ GIT_ADD_SIZET_OVERFLOW (& tree_len , tree_len , 1 ))
99
+ return NULL ;
100
+
101
+ entry = pool ? git_pool_malloc (pool , tree_len ) :
102
+ git__malloc (tree_len );
103
+ if (!entry )
92
104
return NULL ;
93
105
94
106
memset (entry , 0x0 , sizeof (git_tree_entry ));
@@ -99,9 +111,31 @@ static git_tree_entry *alloc_entry(const char *filename)
99
111
return entry ;
100
112
}
101
113
114
+ /**
115
+ * Allocate a tree entry, using the poolin the tree which owns
116
+ * it. This is useful when reading trees, so we don't allocate a ton
117
+ * of small strings but can use the pool.
118
+ */
119
+ static git_tree_entry * alloc_entry_pooled (git_pool * pool , const char * filename , size_t filename_len )
120
+ {
121
+ git_tree_entry * entry = NULL ;
122
+
123
+ if (!(entry = alloc_entry_base (pool , filename , filename_len )))
124
+ return NULL ;
125
+
126
+ entry -> pooled = true;
127
+
128
+ return entry ;
129
+ }
130
+
131
+ static git_tree_entry * alloc_entry (const char * filename )
132
+ {
133
+ return alloc_entry_base (NULL , filename , strlen (filename ));
134
+ }
135
+
102
136
struct tree_key_search {
103
137
const char * filename ;
104
- size_t filename_len ;
138
+ uint16_t filename_len ;
105
139
};
106
140
107
141
static int homing_search_cmp (const void * key , const void * array_member )
@@ -198,7 +232,7 @@ static int tree_key_search(
198
232
199
233
void git_tree_entry_free (git_tree_entry * entry )
200
234
{
201
- if (entry == NULL )
235
+ if (entry == NULL || entry -> pooled )
202
236
return ;
203
237
204
238
git__free (entry );
@@ -233,6 +267,7 @@ void git_tree__free(void *_tree)
233
267
git_tree_entry_free (e );
234
268
235
269
git_vector_free (& tree -> entries );
270
+ git_pool_clear (& tree -> pool );
236
271
git__free (tree );
237
272
}
238
273
@@ -385,11 +420,14 @@ int git_tree__parse(void *_tree, git_odb_object *odb_obj)
385
420
const char * buffer = git_odb_object_data (odb_obj );
386
421
const char * buffer_end = buffer + git_odb_object_size (odb_obj );
387
422
423
+ git_pool_init (& tree -> pool , 1 );
388
424
if (git_vector_init (& tree -> entries , DEFAULT_TREE_SIZE , entry_sort_cmp ) < 0 )
389
425
return -1 ;
390
426
391
427
while (buffer < buffer_end ) {
392
428
git_tree_entry * entry ;
429
+ size_t filename_len ;
430
+ const char * nul ;
393
431
int attr ;
394
432
395
433
if (git__strtol32 (& attr , buffer , & buffer , 8 ) < 0 || !buffer )
@@ -398,26 +436,23 @@ int git_tree__parse(void *_tree, git_odb_object *odb_obj)
398
436
if (* buffer ++ != ' ' )
399
437
return tree_error ("Failed to parse tree. Object is corrupted" , NULL );
400
438
401
- if (memchr (buffer , 0 , buffer_end - buffer ) == NULL )
439
+ if (( nul = memchr (buffer , 0 , buffer_end - buffer ) ) == NULL )
402
440
return tree_error ("Failed to parse tree. Object is corrupted" , NULL );
403
441
442
+ filename_len = nul - buffer ;
404
443
/** Allocate the entry and store it in the entries vector */
405
444
{
406
- entry = alloc_entry ( buffer );
445
+ entry = alloc_entry_pooled ( & tree -> pool , buffer , filename_len );
407
446
GITERR_CHECK_ALLOC (entry );
408
447
409
- if (git_vector_insert (& tree -> entries , entry ) < 0 ) {
410
- git__free (entry );
448
+ if (git_vector_insert (& tree -> entries , entry ) < 0 )
411
449
return -1 ;
412
- }
413
450
414
451
entry -> attr = attr ;
415
452
}
416
453
417
- while (buffer < buffer_end && * buffer != 0 )
418
- buffer ++ ;
419
-
420
- buffer ++ ;
454
+ /* Advance to the ID just after the path */
455
+ buffer += filename_len + 1 ;
421
456
422
457
git_oid_fromraw (& entry -> oid , (const unsigned char * )buffer );
423
458
buffer += GIT_OID_RAWSZ ;
0 commit comments