https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112727

--- Comment #3 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
Actually no, ubsan_handle_shift is called here with
SAVE_EXPR <!(bool) VIEW_CONVERT_EXPR<const struct S
*>(x)->s[VIEW_CONVERT_EXPR<unsigned int>(j)] ? NON_LVALUE_EXPR <1> :
NON_LVALUE_EXPR <0>>
as op0.
And what goes out of it + the whole LSHIFT_EXPR with instrumentation looks
reasonable as well:
if (SAVE_EXPR <16 + VIEW_CONVERT_EXPR<unsigned int>(j)>;, SAVE_EXPR <!(bool)
VIEW_CONVERT_EXPR<const struct S *>(x)->s[VIEW_CONVERT_EXPR<unsigned int>(j)] ?
NON_LVALUE_EXPR <1> : NON_LVALUE_EXPR <0>>;, SAVE_EXPR <16 +
VIEW_CONVERT_EXPR<unsigned int>(j)> > 31;)
  {
    __builtin___ubsan_handle_shift_out_of_bounds (&*.Lubsan_data0, (unsigned
long) (SAVE_EXPR <!(bool) VIEW_CONVERT_EXPR<const struct S
*>(x)->s[VIEW_CONVERT_EXPR<unsigned int>(j)] ? NON_LVALUE_EXPR <1> :
NON_LVALUE_EXPR <0>>), (unsigned long) (SAVE_EXPR <16 +
VIEW_CONVERT_EXPR<unsigned int>(j)>));
  }
else
  {
    <<< Unknown tree: void_cst >>>
  }, (SAVE_EXPR <!(bool) VIEW_CONVERT_EXPR<const struct S
*>(x)->s[VIEW_CONVERT_EXPR<unsigned int>(j)] ? NON_LVALUE_EXPR <1> :
NON_LVALUE_EXPR <0>>) << SAVE_EXPR <16 + VIEW_CONVERT_EXPR<unsigned int>(j)>;;
i.e. the x->s[j] ? 0 : 1 is evaluated in SAVE_EXPR first, then 16 + j > 31
comparison, etc.

Seems the problem happens during cp_fold, which when called on the
COMPOUND_EXPR with
SAVE_EXPR <!(bool) VIEW_CONVERT_EXPR<const struct S
*>(x)->s[VIEW_CONVERT_EXPR<unsigned int>(j)] ? NON_LVALUE_EXPR <1> :
NON_LVALUE_EXPR <0>>
as first argument and
SAVE_EXPR <16 + VIEW_CONVERT_EXPR<unsigned int>(j)> > 31
second recurses using
3113          op0 = cp_fold_maybe_rvalue (TREE_OPERAND (x, 0), rval_ops,
flags);
on the first one and returns
(bool) VIEW_CONVERT_EXPR<const struct S *>(x)->s[j] ? 0 : 1
(i.e. extracts it out of the SAVE_EXPR).
    case SAVE_EXPR:
      /* A SAVE_EXPR might contain e.g. (0 * i) + (0 * j), which, after
         folding, evaluates to an invariant.  In that case no need to wrap
         this folded tree with a SAVE_EXPR.  */
      r = cp_fold (TREE_OPERAND (x, 0), flags);
      if (tree_invariant_p (r))
        x = r;
      break;
And then because it thinks it is invariant (the COND_EXPR has for some reason
TREE_READONLY set on it), it also drops it from the COMPOUND_EXPR.
Now, guess there is some tree sharing (while c-ubsan.cc calls unshare_expr when
it uses the expressions multiple times, the unsharing stops at SAVE_EXPR) and
so when the bounds-strict instrumentation modifies it and adds important
side-effect to it, it modifies both remaining copies of the SAVE_EXPR's
argument.

Reply via email to