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

Jakub Jelinek <jakub at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |ppalka at gcc dot gnu.org

--- Comment #6 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
get_member_function_from_ptrfunc already properly calls save_expr if function
has side-effects, but in this case it doesn't.
The thing is that the function tree (which contains nested ARRAY_REFs here) is
used several times, in particular
((long int) FUNCTION.__pfn & 1) != 0 ? (void C::<T40d> (struct C *) *) *(*(int
(*) () * *) ((struct C *) this + (sizetype) FUNCTION.__delta) + (sizetype)
((long int) FUNCTION.__pfn - 1)) : FUNCTION.__pfn;
where FUNCTION is that
VIEW_CONVERT_EXPR<struct D[1]>(e)[((struct C *)
this)->c[VIEW_CONVERT_EXPR<int>(x)]].d
If all the 4 locations would use the same tree, it would work just fine,
the first FUNCTION occurrence is evaluated unconditionally in the expression,
so when
cp_genericize then instruments it with .UBSAN_BOUNDS, the SAVE_EXPR which is
created for that is evaluated there and then can be used in all the remaining 3
copies.
But unfortunately build_conditional_expr -> build_conditional_expr ->
convert_like -> ... -> scalar_constant_value -> constant_value_1 uses
unshare_expr on the expression,
so there are actually 2 separate unshared copies of FUNCTION, one evaluated in
the (FUNCTION.__pfn & 1) != 0 check and one in the remaining 3 spots, and that
is the problem, because the .UBSAN_BOUNDS instrumentation creates then 2
SAVE_EXPRs and the second one will have the temporary initialized when
gimplifying the first occurrence,
which is in one of the COND_EXPR branches; that means in the other COND_EXPR
branch it will be uninitialized.

The #c5 patch (aside from a formatting issue) isn't IMHO the right fix,
save_expr doesn't really guarantee it will create a SAVE_EXPR.
Given that for the cast to bool unshare_expr will be done, one possible fix is
to
e3 = unshare_expr (e3); before the build_conditional_expr, another is to ensure
unshare_expr doesn't happen for the e1 case (say by using just build2 for the
BIT_AND_EXPR and NE_EXPR), and last one would be to make sure function is a
SAVE_EXPR or perhaps TARGET_EXPR whenever it isn't a non-side-effect decl or
constant.  E.g. through force_target_expr.

Reply via email to