https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106558
--- Comment #3 from Jakub Jelinek <jakub at gcc dot gnu.org> --- Looks like a bug in the sanopt pass. For -O2, we have before sanopt in main: b.0_1 = b; e.2_3 = e; c.5_4 = c; .ASAN_CHECK (7, c.5_4, 8, 8); *c.5_4 = e.2_3; b.7_5 = b; .ASAN_CHECK (7, b.7_5, 4, 4); *b.7_5 = 2; .ASAN_CHECK (7, b.0_1, 4, 4); *b.0_1 = 2; return 2; and in sanopt: Leaving: .ASAN_CHECK (7, c.5_4, 8, 8); Leaving: .ASAN_CHECK (7, b.7_5, 4, 4); Optimizing out: .ASAN_CHECK (7, b.0_1, 4, 4); Expanded: .ASAN_CHECK (7, c.5_4, 8, 8); Expanded: .ASAN_CHECK (7, b.7_5, 4, 4); Even that is incorrect, we don't generally know what b points to before the *c store and after it, so neither of the stores is redundant because *c store can change the value of b. At -O1 we have before sanopt: b.0_1 = b; e.2_6 = e; e.3_7 = (long int) e.2_6; _9 = (int) e.3_7; .ASAN_CHECK (7, b.0_1, 4, 4); *b.0_1 = _9; c.5_10 = c; e.6_11 = e; .ASAN_CHECK (7, c.5_10, 8, 8); *c.5_10 = e.6_11; b.7_12 = b; .ASAN_CHECK (7, b.7_12, 4, 4); *b.7_12 = 2; *b.0_1 = 2; b.1_2 = b; .ASAN_CHECK (6, b.1_2, 4, 4); _5 = *b.1_2; return _5; because we optimize less at that optimization level, and sanopt: Leaving: .ASAN_CHECK (7, b.0_1, 4, 4); Leaving: .ASAN_CHECK (7, c.5_10, 8, 8); Optimizing out: .ASAN_CHECK (7, b.7_12, 4, 4); Optimizing out: .ASAN_CHECK (6, b.1_2, 4, 4); Expanded: .ASAN_CHECK (7, b.0_1, 4, 4); Expanded: .ASAN_CHECK (7, c.5_10, 8, 8); The b.1_2 .ASAN_CHECK is IMHO redundant (b couldn't change between b.7_12 = b and b.1_2 = b;) but the b.7_12 .ASAN_CHECK is not redundant.