On Wed, Sep 04, 2024 at 11:06:22AM -0400, Jason Merrill wrote:
> On 9/2/24 1:49 PM, Jakub Jelinek wrote:
> > Hi!
> > 
> > The following testcase is miscompiled, because
> > get_member_function_from_ptrfunc
> > emits something like
> > (((FUNCTION.__pfn & 1) != 0)
> >   ? ptr + FUNCTION.__delta + FUNCTION.__pfn - 1
> >   : FUNCTION.__pfn) (ptr + FUNCTION.__delta, ...)
> > or so, so FUNCTION tree is used there 5 times.  There is
> > if (TREE_SIDE_EFFECTS (function)) function = save_expr (function);
> > but in this case function doesn't have side-effects, just nested ARRAY_REFs.
> > Now, if all the FUNCTION trees would be shared, it would work fine,
> > FUNCTION is evaluated in the first operand of COND_EXPR; but unfortunately
> > that isn't the case, both the BIT_AND_EXPR shortening and conversion to
> > bool done for build_conditional_expr actually unshare_expr that first
> > expression, but none of the other 4 are unshared.  With -fsanitize=bounds,
> > .UBSAN_BOUNDS calls are added to the ARRAY_REFs and use SAVE_EXPRs to avoid
> > evaluating the argument multiple times, but because that FUNCTION tree is
> > first used in the second argument of COND_EXPR (i.e. conditionally), the
> > SAVE_EXPR initialization is done just there and then the third argument
> > of COND_EXPR just uses the uninitialized temporary and so does the first
> > argument computation as well.
> 
> If there are SAVE_EXPRs in FUNCTION, why is TREE_SIDE_EFFECTS false?

They aren't there when this function is called, they are added only during
cp_genericize when instrumenting the ARRAY_REFs with UBSAN.

And unlike this function, e.g. ubsan_instrument_bounds just calls save_expr
on the index and not if (TREE_SIDE_EFFECTS (index)) index = save_expr
(index).

> It seems desirable to only do the bounds-checking once.

So, one possibility would be to call save_expr unconditionally in
get_member_function_from_ptrfunc as well.

Or build a TARGET_EXPR (force_target_expr or similar).

        Jakub

Reply via email to