Check duplicate struct/union member names tcc.h: Add cnt field in TokenSym tccgen.c: New function check_fields to find duplicate member names. This avoids quadratic behavior and can be used for large structs.
Unified · Split
| @@ -432,6 +432,7 @@ typedef struct TokenSym { · 431 unmodified lines | ||
| 432 | 432 | struct Sym *sym_struct; /* direct pointer to structure */ |
| 433 | 433 | struct Sym *sym_identifier; /* direct pointer to identifier */ |
| 434 | 434 | int tok; /* token number */ |
| 435 | + int cnt; | |
| 435 | 436 | int len; |
| 436 | 437 | char str[1]; |
| 437 | 438 | } TokenSym; |
| @@ -4321,6 +4321,41 @@ static Sym * find_field (CType *type, int v, int *cumofs) · 4320 unmodified lines | ||
| 4321 | 4321 | return s; |
| 4322 | 4322 | } |
| 4323 | 4323 | |
| 4324 | +/* | |
| 4325 | + * c = 0: reset symbol counter | |
| 4326 | + * c = 1: increment symbol counter | |
| 4327 | + * c = 2: check symbol counter | |
| 4328 | + */ | |
| 4329 | + | |
| 4330 | +static void check_fields (CType *type, int c) | |
| 4331 | +{ | |
| 4332 | + Sym *s = type->ref; | |
| 4333 | + int v; | |
| 4334 | + | |
| 4335 | + while ((s = s->next) != NULL) { | |
| 4336 | + if ((s->v & SYM_FIELD) && | |
| 4337 | + (s->type.t & VT_BTYPE) == VT_STRUCT && | |
| 4338 | + (s->v & ~SYM_FIELD) >= SYM_FIRST_ANOM) { | |
| 4339 | + check_fields (&s->type, c); | |
| 4340 | + } | |
| 4341 | + v = s->v & ~SYM_FIELD; | |
| 4342 | + if (v < tok_ident) | |
| 4343 | + switch (c) { | |
| 4344 | + case 0: | |
| 4345 | + table_ident[v - TOK_IDENT]->cnt = 0; | |
| 4346 | + break; | |
| 4347 | + case 1: | |
| 4348 | + table_ident[v - TOK_IDENT]->cnt++; | |
| 4349 | + break; | |
| 4350 | + case 2: | |
| 4351 | + if (table_ident[v - TOK_IDENT]->cnt != 1) | |
| 4352 | + tcc_error("duplicate member '%s'", | |
| 4353 | + get_tok_str(v, NULL)); | |
| 4354 | + break; | |
| 4355 | + } | |
| 4356 | + } | |
| 4357 | +} | |
| 4358 | + | |
| 4324 | 4359 | static void struct_layout(CType *type, AttributeDef *ad) |
| 4325 | 4360 | { |
| 4326 | 4361 | int size, align, maxalign, offset, c, bit_pos, bit_size; |
| @@ -4774,6 +4809,9 @@ do_decl: · 447 unmodified lines | ||
| 4774 | 4809 | if (ad.cleanup_func) { |
| 4775 | 4810 | tcc_warning("attribute '__cleanup__' ignored on type"); |
| 4776 | 4811 | } |
| 4812 | + check_fields(type, 0); | |
| 4813 | + check_fields(type, 1); | |
| 4814 | + check_fields(type, 2); | |
| 4777 | 4815 | struct_layout(type, &ad); |
| 4778 | 4816 | } |
| 4779 | 4817 | } |
| @@ -366,4 +366,21 @@ n[sizeof({3;})]; // crashed in block() due to missing local scope · 365 unmodified lines | ||
| 366 | 366 | f(){"12"3;} // second const token killed the value of the first |
| 367 | 367 | |
| 368 | 368 | /******************************************************************/ |
| 369 | +#elif defined test_duplicate_member | |
| 370 | +struct S { | |
| 371 | + int a, a; | |
| 372 | +}; | |
| 373 | +#elif defined test_duplicate_member_anon | |
| 374 | +struct S1 { | |
| 375 | + int b; | |
| 376 | + struct { | |
| 377 | + int b; | |
| 378 | + } c; | |
| 379 | +}; | |
| 380 | +struct S2 { | |
| 381 | + int d; | |
| 382 | + struct { | |
| 383 | + int d; | |
| 384 | + }; | |
| 385 | +}; | |
| 369 | 386 | #endif |
| @@ -174,3 +174,9 @@ bar : 3 ; 3 · 173 unmodified lines | ||
| 174 | 174 | |
| 175 | 175 | [test_invalid_tokckill] |
| 176 | 176 | 60_errors_and_warnings.c:366: error: ';' expected (got "3") |
| 177 | + | |
| 178 | +[test_duplicate_member] | |
| 179 | +60_errors_and_warnings.c:372: error: duplicate member 'a' | |
| 180 | + | |
| 181 | +[test_duplicate_member_anon] | |
| 182 | +60_errors_and_warnings.c:385: error: duplicate member 'd' | |