-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
This was caught by some prototype code to warn for potential NULL pointer dereferences. Let's look at vt_equate_reg_base_value from alias.c: void vt_equate_reg_base_value (const_rtx reg1, const_rtx reg2) { VEC_replace (rtx, reg_base_value, REGNO (reg1), REG_BASE_VALUE (reg2)); } Seems pretty reasonable... I won't go through the insanely hairy cpp expansion, but instead go directly to the code that comes out of the SSA optimizers: # BLOCK 2 freq:10000 # PRED: ENTRY [100.0%] (fallthru,exec) D.56193_6 = MEM[(const struct rtx_def *)reg2_5(D) + 8B]; reg_base_value.11_8 = reg_base_value; if (reg_base_value.11_8 != 0B) goto <bb 3>; else goto <bb 9>; # SUCC: 3 [85.0%] (true,exec) 9 [15.0%] (false,exec) # BLOCK 3 freq:8500 # PRED: 2 [85.0%] (true,exec) prephitmp.736_31 = MEM[(const struct VEC_rtx_base *)reg_base_value.11_8].num; if (D.56193_6 < prephitmp.736_31) goto <bb 4>; else goto <bb 8>; # SUCC: 4 [58.8%] (true,exec) 8 [41.2%] (false,exec) # BLOCK 4 freq:4250 # PRED: 3 [58.8%] (true,exec) Invalid sum of incoming frequencies 5000, should be 4250 D.57686_40 = MEM[(const struct VEC_rtx_base *)reg_base_value.11_8].vec[D.56193_6]; goto <bb 8>; # SUCC: 8 [100.0%] (fallthru,exec) # BLOCK 5 freq:9996 # PRED: 8 [100.0%] (fallthru,exec) 9 [100.0%] (fallthru,exec) # iftmp.13_4 = PHI <iftmp.13_26(8), 0B(9)> # D.57686_48 = PHI <D.57686_32(8), 0B(9)> # D.56204_45 = PHI <D.56204_46(8), D.56204_42(9)> # prephitmp.736_17 = PHI <prephitmp.736_31(8), prephitmp.736_10(9)> if (prephitmp.736_17 <= D.56204_45) goto <bb 6>; else goto <bb 7>; # SUCC: 6 [0.0%] (true,exec) 7 [100.0%] (false,exec) # BLOCK 6 freq:4 # PRED: 5 [0.0%] (true,exec) vec_assert_fail ("replace", "VEC(rtx,base)", "/home/gcc/virgin-gcc/gcc/alias.c", 2921, &__FUNCTION__); # SUCC: # BLOCK 7 freq:9992 # PRED: 5 [100.0%] (false,exec) iftmp.13_4->vec[D.56204_45] = D.57686_48; return; # SUCC: EXIT [100.0%] # BLOCK 8 freq:8496 # PRED: 3 [41.2%] (false,exec) 4 [100.0%] (fallthru,exec) Invalid sum of incoming frequencies 7750, should be 8496 # D.57686_32 = PHI <0B(3), D.57686_40(4)> D.56204_46 = MEM[(const struct rtx_def *)reg1_21(D) + 8B]; iftmp.13_26 = ®_base_value.11_8->base; goto <bb 5>; # SUCC: 5 [100.0%] (fallthru,exec) # BLOCK 9 freq:1500 # PRED: 2 [15.0%] (false,exec) D.56204_42 = MEM[(const struct rtx_def *)reg1_21(D) + 8B]; prephitmp.736_10 = MEM[(struct VEC_rtx_base *)0B].num; goto <bb 5>; # SUCC: 5 [100.0%] (fallthru,exec) I'll draw your attention to blocks #7 and #9. In block #7 we dereference iftmp.13_4, which can flow from block #5 with the value 0 (if block #5 was reached from block #9) resulting in a NULL pointer dereference. Closely related block #9 has an explicit NULL pointer dereference. We can conclude that block #9 should never be reached. I first though this might be a missed jump threading optimization, but it turns out it's just bad code from our VEC implementation. Going back to the VEC_replace definition we can clearly see the problem: static inline T VEC_OP (T,base,replace) \ (VEC(T,base) *vec_, unsigned ix_, T obj_ VEC_CHECK_DECL) \ { \ T old_obj_; \ \ VEC_ASSERT (ix_ < vec_->prefix.num, "replace", T, base); \ old_obj_ = vec_->vec[ix_]; \ vec_->vec[ix_] = obj_; \ \ return old_obj_; \ } \ If the passed in BASE is null, then we explicitly dereference the null pointer within the VEC_ASSERT (block #9), and potentially dereference it later in the assignment to vec_->vec[ix_] (block #7). The fix is pretty clear, verify the vec_ is non-null like many of the other VEC_ routines already do. In fact, several are missing their checks which this patch addresses. For a checking-enabled compiler this results in a .06% increase in the size of the resulting cc1. It should have no effect if checking is not enabled. And (of course) the bogon warning goes away, in fact, for this testcase we actually get better code. Bootstrapped and regression tested on x86_64-unknown-linux-gnu. OK for trunk? Thanks, Jeff -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iQEcBAEBAgAGBQJOsgp0AAoJEBRtltQi2kC7AVwH/jwUXssTIprxgR3A7LosGUbG BXylyDkjay2A/1D+MJZckDWwFgfmhS8+dimdDHSYJvY0bGQ44u0aC4hS0o9wpGqU HTo5CLj6bEwbMTKJEV0umaYtChW6g7IrfgDe3hn9uUbOUb98ou+PRnEHOGNwfAkF CPTM7HUBwR+19Nd7xX/IBi/VuJxUxdHcZ9jcTxqXDHrzrFcjqvvz4uFdo/nVtMm1 x3GTQ1bHoICIkPMlt50SpHMv15VD2TkccML5Abjds6928kndphghS7POaRdYYSs8 23BKCSURz71L8vAnCONCBldZV3O61BjuM2tK3Qw7qp1Vv2aRHTSuY0tc0UG8UYg= =F4XR -----END PGP SIGNATURE-----
* vec.h (splice): Assert DST_ is non-null. (quick_push, pop, replace, quick_insert): Similarly for VEC_. (ordered_remove, unordered_remove, block_remove): Likewise. Index: vec.h =================================================================== *** vec.h (revision 180704) --- vec.h (working copy) *************** static inline void VEC_OP(T,base,splice) *** 648,654 **** if (src_) \ { \ unsigned len_ = src_->prefix.num; \ ! VEC_ASSERT (dst_->prefix.num + len_ <= dst_->prefix.alloc, "splice", T, base); \ \ memcpy (&dst_->vec[dst_->prefix.num], &src_->vec[0], len_ * sizeof (T)); \ dst_->prefix.num += len_; \ --- 648,654 ---- if (src_) \ { \ unsigned len_ = src_->prefix.num; \ ! VEC_ASSERT (dst_ && dst_->prefix.num + len_ <= dst_->prefix.alloc, "splice", T, base); \ \ memcpy (&dst_->vec[dst_->prefix.num], &src_->vec[0], len_ * sizeof (T)); \ dst_->prefix.num += len_; \ *************** static inline T *VEC_OP (T,base,quick_pu *** 660,666 **** { \ T *slot_; \ \ ! VEC_ASSERT (vec_->prefix.num < vec_->prefix.alloc, "push", T, base); \ slot_ = &vec_->vec[vec_->prefix.num++]; \ *slot_ = obj_; \ \ --- 660,666 ---- { \ T *slot_; \ \ ! VEC_ASSERT (vec_ && vec_->prefix.num < vec_->prefix.alloc, "push", T, base); \ slot_ = &vec_->vec[vec_->prefix.num++]; \ *slot_ = obj_; \ \ *************** static inline T VEC_OP (T,base,pop) (VEC *** 671,677 **** { \ T obj_; \ \ ! VEC_ASSERT (vec_->prefix.num, "pop", T, base); \ obj_ = vec_->vec[--vec_->prefix.num]; \ \ return obj_; \ --- 671,677 ---- { \ T obj_; \ \ ! VEC_ASSERT (vec_ && vec_->prefix.num, "pop", T, base); \ obj_ = vec_->vec[--vec_->prefix.num]; \ \ return obj_; \ *************** static inline T VEC_OP (T,base,replace) *** 690,696 **** { \ T old_obj_; \ \ ! VEC_ASSERT (ix_ < vec_->prefix.num, "replace", T, base); \ old_obj_ = vec_->vec[ix_]; \ vec_->vec[ix_] = obj_; \ \ --- 690,696 ---- { \ T old_obj_; \ \ ! VEC_ASSERT (vec_ && ix_ < vec_->prefix.num, "replace", T, base); \ old_obj_ = vec_->vec[ix_]; \ vec_->vec[ix_] = obj_; \ \ *************** static inline T *VEC_OP (T,base,quick_in *** 702,708 **** { \ T *slot_; \ \ ! VEC_ASSERT (vec_->prefix.num < vec_->prefix.alloc, "insert", T, base); \ VEC_ASSERT (ix_ <= vec_->prefix.num, "insert", T, base); \ slot_ = &vec_->vec[ix_]; \ memmove (slot_ + 1, slot_, (vec_->prefix.num++ - ix_) * sizeof (T)); \ --- 702,708 ---- { \ T *slot_; \ \ ! VEC_ASSERT (vec_ && vec_->prefix.num < vec_->prefix.alloc, "insert", T, base); \ VEC_ASSERT (ix_ <= vec_->prefix.num, "insert", T, base); \ slot_ = &vec_->vec[ix_]; \ memmove (slot_ + 1, slot_, (vec_->prefix.num++ - ix_) * sizeof (T)); \ *************** static inline T VEC_OP (T,base,ordered_r *** 717,723 **** T *slot_; \ T obj_; \ \ ! VEC_ASSERT (ix_ < vec_->prefix.num, "remove", T, base); \ slot_ = &vec_->vec[ix_]; \ obj_ = *slot_; \ memmove (slot_, slot_ + 1, (--vec_->prefix.num - ix_) * sizeof (T)); \ --- 717,723 ---- T *slot_; \ T obj_; \ \ ! VEC_ASSERT (vec_ && ix_ < vec_->prefix.num, "remove", T, base); \ slot_ = &vec_->vec[ix_]; \ obj_ = *slot_; \ memmove (slot_, slot_ + 1, (--vec_->prefix.num - ix_) * sizeof (T)); \ *************** static inline T VEC_OP (T,base,unordered *** 731,737 **** T *slot_; \ T obj_; \ \ ! VEC_ASSERT (ix_ < vec_->prefix.num, "remove", T, base); \ slot_ = &vec_->vec[ix_]; \ obj_ = *slot_; \ *slot_ = vec_->vec[--vec_->prefix.num]; \ --- 731,737 ---- T *slot_; \ T obj_; \ \ ! VEC_ASSERT (vec_ && ix_ < vec_->prefix.num, "remove", T, base); \ slot_ = &vec_->vec[ix_]; \ obj_ = *slot_; \ *slot_ = vec_->vec[--vec_->prefix.num]; \ *************** static inline void VEC_OP (T,base,block_ *** 744,750 **** { \ T *slot_; \ \ ! VEC_ASSERT (ix_ + len_ <= vec_->prefix.num, "block_remove", T, base); \ slot_ = &vec_->vec[ix_]; \ vec_->prefix.num -= len_; \ memmove (slot_, slot_ + len_, (vec_->prefix.num - ix_) * sizeof (T)); \ --- 744,750 ---- { \ T *slot_; \ \ ! VEC_ASSERT (vec_ && ix_ + len_ <= vec_->prefix.num, "block_remove", T, base); \ slot_ = &vec_->vec[ix_]; \ vec_->prefix.num -= len_; \ memmove (slot_, slot_ + len_, (vec_->prefix.num - ix_) * sizeof (T)); \