https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99673
Martin Sebor <msebor at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- Known to fail| |11.0 Status|UNCONFIRMED |NEW Ever confirmed|0 |1 CC| |msebor at gcc dot gnu.org Last reconfirmed| |2021-03-19 Summary|[11 Regression] bogus |[11 Regression] bogus |-Wstringop-overread warning |-Wstringop-overread warning |with address sanitizer |with address sanitizer due | |to member address | |substitution --- Comment #1 from Martin Sebor <msebor at gcc dot gnu.org> --- A further reduced/simplified test case is below. The root cause is similar to the one discussed in pr99578 comment 8. $ cat pr99673.c && gcc -Os -S -Wall -fsanitize=address -fno-inline-functions-called-once -m32 pr99673.c struct B { int i; struct A { short sa[8]; } a[2]; }; struct C { char n, ax[]; }; struct D { int i, j, k; }; int f (const short[8]); void g (struct C *pc, struct D *pd, int i) { struct B *pb = (void *)pc->ax; pd->i = pb->i; const short *psa = pb->a[i].sa; if (f (psa)) return; } pr99673.c: In function ‘g’: pr99673.c:22:7: warning: ‘f’ reading 16 bytes from a region of size 4 [-Wstringop-overread] 22 | if (f (psa)) | ^~~~~~~ pr99673.c:22:7: note: referencing argument 1 of type ‘const short int *’ pr99673.c:14:5: note: in a call to function ‘f’ 14 | int f (const short[8]); | ^ The output of -fdump-tree-optimized shows what triggers the warning. The difference between the case discussed in pr99578 comment 8 and this is here that it's the sanopt pass that replaces the pb->a[i].sa as the argument to f() with the address of pc->i plus some offset. pc->i is a 4-byte int, which is where the 4 bytes in the warning comes from. ;; Function g (g, funcdef_no=0, decl_uid=2314, cgraph_uid=1, symbol_order=0) void g (struct C * pc, struct D * pd, int i) { const short int * psa; int _1; sizetype _9; sizetype _10; sizetype _11; unsigned int _12; int * _13; int * _14; unsigned int _17; unsigned int _18; signed char * _19; signed char _20; _Bool _21; unsigned int _22; signed char _23; signed char _24; _Bool _25; _Bool _26; unsigned int _27; unsigned int _28; unsigned int _29; signed char * _30; signed char _31; _Bool _32; unsigned int _33; signed char _34; signed char _35; _Bool _36; _Bool _37; <bb 2> [local count: 1073741824]: _13 = &MEM[(struct B *)pc_2(D) + 1B].i; <<< address of pc.i _12 = (unsigned int) _13; _17 = _12 >> 3; _18 = _17 + 536870912; _19 = (signed char *) _18; _20 = *_19; _21 = _20 != 0; _22 = _12 & 7; _23 = (signed char) _22; _24 = _23 + 3; _25 = _24 >= _20; _26 = _21 & _25; if (_26 != 0) goto <bb 3>; [0.05%] else goto <bb 4>; [99.95%] <bb 3> [local count: 536864]: __builtin___asan_report_load4 (_12); <bb 4> [local count: 1073741824]: _1 = MEM[(struct B *)pc_2(D) + 1B].i; _14 = &pd_4(D)->i; _27 = (unsigned int) _14; _28 = _27 >> 3; _29 = _28 + 536870912; _30 = (signed char *) _29; _31 = *_30; _32 = _31 != 0; _33 = _27 & 7; _34 = (signed char) _33; _35 = _34 + 3; _36 = _35 >= _31; _37 = _32 & _36; if (_37 != 0) goto <bb 5>; [0.05%] else goto <bb 6>; [99.95%] <bb 5> [local count: 536864]: __builtin___asan_report_store4 (_27); <bb 6> [local count: 1073741824]: pd_4(D)->i = _1; _9 = (sizetype) i_6(D); _10 = _9 * 16; _11 = _10 + 4; psa_7 = _13 + _11; <<< &pc.i + (i * 16) + 4 f (psa_7); [tail call] return; } The output below shows the difference between the last "good" IL and the "bad" IL introduced by the sanopt transformation. To avoid the warning either the sanopt pass will need to be changed to avoid this substitution or to annotate it somehow so the warning knows not to trigger. --- pr99673.c.184t.slsr 2021-03-19 15:21:31.134229177 -0600 +++ pr99673.c.239t.sanopt 2021-03-19 15:21:31.135229188 -0600 @@ -1,13 +1,14 @@ ;; Function g (g, funcdef_no=0, decl_uid=2314, cgraph_uid=1, symbol_order=0) -;; 1 loops found -;; -;; Loop 0 -;; header 0, latch 1 -;; depth 0, outer -1 -;; nodes: 0 1 2 -;; 2 succs { 1 } + +Symbols to be put in SSA form +{ D.2322 } +Incremental SSA update started at block: 0 +Number of blocks in CFG: 7 +Number of blocks to update: 6 ( 86%) + + void g (struct C * pc, struct D * pd, int i) { const short int * psa; @@ -15,23 +16,81 @@ sizetype _9; sizetype _10; sizetype _11; - struct B * _12; + unsigned int _12; int * _13; int * _14; + unsigned int _17; + unsigned int _18; + signed char * _19; + signed char _20; + _Bool _21; + unsigned int _22; + signed char _23; + signed char _24; + _Bool _25; + _Bool _26; + unsigned int _27; + unsigned int _28; + unsigned int _29; + signed char * _30; + signed char _31; + _Bool _32; + unsigned int _33; + signed char _34; + signed char _35; + _Bool _36; + _Bool _37; <bb 2> [local count: 1073741824]: _13 = &MEM[(struct B *)pc_2(D) + 1B].i; - .ASAN_CHECK (6, _13, 4, 4); + _12 = (unsigned int) _13; + _17 = _12 >> 3; + _18 = _17 + 536870912; + _19 = (signed char *) _18; + _20 = *_19; + _21 = _20 != 0; + _22 = _12 & 7; + _23 = (signed char) _22; + _24 = _23 + 3; + _25 = _24 >= _20; + _26 = _21 & _25; + if (_26 != 0) + goto <bb 4>; [0.05%] + else + goto <bb 3>; [99.95%] + + <bb 4> [local count: 536864]: + __builtin___asan_report_load4 (_12); + + <bb 3> [local count: 1073741824]: _1 = MEM[(struct B *)pc_2(D) + 1B].i; _14 = &pd_4(D)->i; - .ASAN_CHECK (7, _14, 4, 4); + _27 = (unsigned int) _14; + _28 = _27 >> 3; + _29 = _28 + 536870912; + _30 = (signed char *) _29; + _31 = *_30; + _32 = _31 != 0; + _33 = _27 & 7; + _34 = (signed char) _33; + _35 = _34 + 3; + _36 = _35 >= _31; + _37 = _32 & _36; + if (_37 != 0) + goto <bb 6>; [0.05%] + else + goto <bb 5>; [99.95%] + + <bb 6> [local count: 536864]: + __builtin___asan_report_store4 (_27); + + <bb 5> [local count: 1073741824]: pd_4(D)->i = _1; _9 = (sizetype) i_6(D); _10 = _9 * 16; _11 = _10 + 4; - _12 = &MEM[(struct B *)pc_2(D) + 1B]; - psa_7 = _12 + _11; - f (psa_7); + psa_7 = _13 + _11; + f (psa_7); [tail call] return; }