When tokens in macro definitions need cstr_buf inside get_tok_str, the second might overwrite the first (happens when tokens are multi-character non-identifiers, see testcase) in macro_is_equal, failing to diagnose a difference. Use a real local buffer.
Unified · Split
| @@ -1280,17 +1280,18 @@ static int macro_is_equal(const int *a, const int *b) · 1279 unmodified lines | |||
| 1280 | { | 1280 | { |
| 1281 | CValue cv; | 1281 | CValue cv; |
| 1282 | int t; | 1282 | int t; |
| 1283 | static CString localbuf; | ||
| 1283 | 1284 | ||
| 1284 | if (!a || !b) | 1285 | if (!a || !b) |
| 1285 | return 1; | 1286 | return 1; |
| 1286 | 1287 | ||
| 1287 | while (*a && *b) { | 1288 | while (*a && *b) { |
| 1288 | /* first time preallocate static cstr_buf, next time only reset position to start */ | 1289 | /* first time preallocate static localbuf, next time only reset position to start */ |
| 1289 | cstr_reset(&cstr_buf); | 1290 | cstr_reset(&localbuf); |
| 1290 | TOK_GET(&t, &a, &cv); | 1291 | TOK_GET(&t, &a, &cv); |
| 1291 | cstr_cat(&cstr_buf, get_tok_str(t, &cv), 0); | 1292 | cstr_cat(&localbuf, get_tok_str(t, &cv), 0); |
| 1292 | TOK_GET(&t, &b, &cv); | 1293 | TOK_GET(&t, &b, &cv); |
| 1293 | if (strcmp(cstr_buf.data, get_tok_str(t, &cv))) | 1294 | if (strcmp(localbuf.data, get_tok_str(t, &cv))) |
| 1294 | return 0; | 1295 | return 0; |
| 1295 | } | 1296 | } |
| 1296 | return !(*a || *b); | 1297 | return !(*a || *b); |
| @@ -0,0 +1,3 @@ | |||
| 1 | /* The following should warn */ | ||
| 2 | #define A ... | ||
| 3 | #define A <<= | ||
| @@ -0,0 +1,2 @@ | |||
| 1 | |||
| 2 | 16.c:3: warning: A redefined | ||