@@ -28,7 +28,7 @@ static const char git_attr__unknown[] = "(builtin)unknown";
2828#endif
2929
3030struct git_attr {
31- int attr_nr ; /* unique attribute number */
31+ unsigned int attr_nr ; /* unique attribute number */
3232 char name [FLEX_ARRAY ]; /* attribute name */
3333};
3434
@@ -210,7 +210,7 @@ static void report_invalid_attr(const char *name, size_t len,
210210 * dictionary. If no entry is found, create a new attribute and store it in
211211 * the dictionary.
212212 */
213- static const struct git_attr * git_attr_internal (const char * name , int namelen )
213+ static const struct git_attr * git_attr_internal (const char * name , size_t namelen )
214214{
215215 struct git_attr * a ;
216216
@@ -226,8 +226,8 @@ static const struct git_attr *git_attr_internal(const char *name, int namelen)
226226 a -> attr_nr = hashmap_get_size (& g_attr_hashmap .map );
227227
228228 attr_hashmap_add (& g_attr_hashmap , a -> name , namelen , a );
229- assert (a -> attr_nr ==
230- ( hashmap_get_size ( & g_attr_hashmap . map ) - 1 ));
229+ if (a -> attr_nr != hashmap_get_size ( & g_attr_hashmap . map ) - 1 )
230+ die ( _ ( "unable to add additional attribute" ));
231231 }
232232
233233 hashmap_unlock (& g_attr_hashmap );
@@ -272,7 +272,7 @@ struct match_attr {
272272 const struct git_attr * attr ;
273273 } u ;
274274 char is_macro ;
275- unsigned num_attr ;
275+ size_t num_attr ;
276276 struct attr_state state [FLEX_ARRAY ];
277277};
278278
@@ -289,7 +289,7 @@ static const char *parse_attr(const char *src, int lineno, const char *cp,
289289 struct attr_state * e )
290290{
291291 const char * ep , * equals ;
292- int len ;
292+ size_t len ;
293293
294294 ep = cp + strcspn (cp , blank );
295295 equals = strchr (cp , '=' );
@@ -333,8 +333,7 @@ static const char *parse_attr(const char *src, int lineno, const char *cp,
333333static struct match_attr * parse_attr_line (const char * line , const char * src ,
334334 int lineno , int macro_ok )
335335{
336- int namelen ;
337- int num_attr , i ;
336+ size_t namelen , num_attr , i ;
338337 const char * cp , * name , * states ;
339338 struct match_attr * res = NULL ;
340339 int is_macro ;
@@ -345,6 +344,11 @@ static struct match_attr *parse_attr_line(const char *line, const char *src,
345344 return NULL ;
346345 name = cp ;
347346
347+ if (strlen (line ) >= ATTR_MAX_LINE_LENGTH ) {
348+ warning (_ ("ignoring overly long attributes line %d" ), lineno );
349+ return NULL ;
350+ }
351+
348352 if (* cp == '"' && !unquote_c_style (& pattern , name , & states )) {
349353 name = pattern .buf ;
350354 namelen = pattern .len ;
@@ -381,10 +385,9 @@ static struct match_attr *parse_attr_line(const char *line, const char *src,
381385 goto fail_return ;
382386 }
383387
384- res = xcalloc (1 ,
385- sizeof (* res ) +
386- sizeof (struct attr_state ) * num_attr +
387- (is_macro ? 0 : namelen + 1 ));
388+ res = xcalloc (1 , st_add3 (sizeof (* res ),
389+ st_mult (sizeof (struct attr_state ), num_attr ),
390+ is_macro ? 0 : namelen + 1 ));
388391 if (is_macro ) {
389392 res -> u .attr = git_attr_internal (name , namelen );
390393 } else {
@@ -447,11 +450,12 @@ struct attr_stack {
447450
448451static void attr_stack_free (struct attr_stack * e )
449452{
450- int i ;
453+ unsigned i ;
451454 free (e -> origin );
452455 for (i = 0 ; i < e -> num_matches ; i ++ ) {
453456 struct match_attr * a = e -> attrs [i ];
454- int j ;
457+ size_t j ;
458+
455459 for (j = 0 ; j < a -> num_attr ; j ++ ) {
456460 const char * setto = a -> state [j ].setto ;
457461 if (setto == ATTR__TRUE ||
@@ -660,8 +664,8 @@ static void handle_attr_line(struct attr_stack *res,
660664 a = parse_attr_line (line , src , lineno , macro_ok );
661665 if (!a )
662666 return ;
663- ALLOC_GROW (res -> attrs , res -> num_matches + 1 , res -> alloc );
664- res -> attrs [res -> num_matches ++ ] = a ;
667+ ALLOC_GROW_BY (res -> attrs , res -> num_matches , 1 , res -> alloc );
668+ res -> attrs [res -> num_matches - 1 ] = a ;
665669}
666670
667671static struct attr_stack * read_attr_from_array (const char * * list )
@@ -700,21 +704,37 @@ void git_attr_set_direction(enum git_attr_direction new_direction)
700704
701705static struct attr_stack * read_attr_from_file (const char * path , int macro_ok )
702706{
707+ struct strbuf buf = STRBUF_INIT ;
703708 FILE * fp = fopen_or_warn (path , "r" );
704709 struct attr_stack * res ;
705- char buf [2048 ];
706710 int lineno = 0 ;
711+ int fd ;
712+ struct stat st ;
707713
708714 if (!fp )
709715 return NULL ;
710- res = xcalloc ( 1 , sizeof ( * res ));
711- while ( fgets ( buf , sizeof ( buf ), fp )) {
712- char * bufp = buf ;
713- if (! lineno )
714- skip_utf8_bom ( & bufp , strlen ( bufp ) );
715- handle_attr_line ( res , bufp , path , ++ lineno , macro_ok ) ;
716+
717+ fd = fileno ( fp );
718+ if ( fstat ( fd , & st )) {
719+ warning_errno ( _ ( "cannot fstat gitattributes file '%s'" ), path );
720+ fclose ( fp );
721+ return NULL ;
716722 }
723+ if (st .st_size >= ATTR_MAX_FILE_SIZE ) {
724+ warning (_ ("ignoring overly large gitattributes file '%s'" ), path );
725+ fclose (fp );
726+ return NULL ;
727+ }
728+
729+ CALLOC_ARRAY (res , 1 );
730+ while (strbuf_getline (& buf , fp ) != EOF ) {
731+ if (!lineno && starts_with (buf .buf , utf8_bom ))
732+ strbuf_remove (& buf , 0 , strlen (utf8_bom ));
733+ handle_attr_line (res , buf .buf , path , ++ lineno , macro_ok );
734+ }
735+
717736 fclose (fp );
737+ strbuf_release (& buf );
718738 return res ;
719739}
720740
@@ -725,13 +745,18 @@ static struct attr_stack *read_attr_from_index(const struct index_state *istate,
725745 struct attr_stack * res ;
726746 char * buf , * sp ;
727747 int lineno = 0 ;
748+ size_t size ;
728749
729750 if (!istate )
730751 return NULL ;
731752
732- buf = read_blob_data_from_index (istate , path , NULL );
753+ buf = read_blob_data_from_index (istate , path , & size );
733754 if (!buf )
734755 return NULL ;
756+ if (size >= ATTR_MAX_FILE_SIZE ) {
757+ warning (_ ("ignoring overly large gitattributes blob '%s'" ), path );
758+ return NULL ;
759+ }
735760
736761 res = xcalloc (1 , sizeof (* res ));
737762 for (sp = buf ; * sp ; ) {
@@ -1001,12 +1026,12 @@ static int macroexpand_one(struct all_attrs_item *all_attrs, int nr, int rem);
10011026static int fill_one (const char * what , struct all_attrs_item * all_attrs ,
10021027 const struct match_attr * a , int rem )
10031028{
1004- int i ;
1029+ size_t i ;
10051030
1006- for (i = a -> num_attr - 1 ; rem > 0 && i >= 0 ; i -- ) {
1007- const struct git_attr * attr = a -> state [i ].attr ;
1031+ for (i = a -> num_attr ; rem > 0 && i > 0 ; i -- ) {
1032+ const struct git_attr * attr = a -> state [i - 1 ].attr ;
10081033 const char * * n = & (all_attrs [attr -> attr_nr ].value );
1009- const char * v = a -> state [i ].setto ;
1034+ const char * v = a -> state [i - 1 ].setto ;
10101035
10111036 if (* n == ATTR__UNKNOWN ) {
10121037 debug_set (what ,
@@ -1025,11 +1050,11 @@ static int fill(const char *path, int pathlen, int basename_offset,
10251050 struct all_attrs_item * all_attrs , int rem )
10261051{
10271052 for (; rem > 0 && stack ; stack = stack -> prev ) {
1028- int i ;
1053+ unsigned i ;
10291054 const char * base = stack -> origin ? stack -> origin : "" ;
10301055
1031- for (i = stack -> num_matches - 1 ; 0 < rem && 0 <= i ; i -- ) {
1032- const struct match_attr * a = stack -> attrs [i ];
1056+ for (i = stack -> num_matches ; 0 < rem && 0 < i ; i -- ) {
1057+ const struct match_attr * a = stack -> attrs [i - 1 ];
10331058 if (a -> is_macro )
10341059 continue ;
10351060 if (path_matches (path , pathlen , basename_offset ,
@@ -1060,11 +1085,11 @@ static void determine_macros(struct all_attrs_item *all_attrs,
10601085 const struct attr_stack * stack )
10611086{
10621087 for (; stack ; stack = stack -> prev ) {
1063- int i ;
1064- for (i = stack -> num_matches - 1 ; i >= 0 ; i -- ) {
1065- const struct match_attr * ma = stack -> attrs [i ];
1088+ unsigned i ;
1089+ for (i = stack -> num_matches ; i > 0 ; i -- ) {
1090+ const struct match_attr * ma = stack -> attrs [i - 1 ];
10661091 if (ma -> is_macro ) {
1067- int n = ma -> u .attr -> attr_nr ;
1092+ unsigned int n = ma -> u .attr -> attr_nr ;
10681093 if (!all_attrs [n ].macro ) {
10691094 all_attrs [n ].macro = ma ;
10701095 }
@@ -1116,7 +1141,7 @@ void git_check_attr(const struct index_state *istate,
11161141 collect_some_attrs (istate , path , check );
11171142
11181143 for (i = 0 ; i < check -> nr ; i ++ ) {
1119- size_t n = check -> items [i ].attr -> attr_nr ;
1144+ unsigned int n = check -> items [i ].attr -> attr_nr ;
11201145 const char * value = check -> all_attrs [n ].value ;
11211146 if (value == ATTR__UNKNOWN )
11221147 value = ATTR__UNSET ;
0 commit comments