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

            Bug ID: 128592
           Summary: can_inline_edge_p checks flag_wrapv and flag_trapv but
                    omits flag_wrapv_pointer, inlining wrapv-pointer
                    always_inline callees into -fno-wrapv-pointer callers
                    and folding away pointer-wrap checks
           Product: gcc
           Version: 16.2.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: ipa
          Assignee: unassigned at gcc dot gnu.org
          Reporter: 220245569 at seu dot edu.cn
                CC: 220255623 at seu dot edu.cn, jianhao.xu at seu dot edu.cn
  Target Milestone: ---
            Target: *-*-*

Reproducer
----------
$ cat trigger.c
__attribute__((always_inline, optimize("wrapv-pointer"))) static inline int
callee_ptr(const char *p) {
    return (p + 16 < p);
}
int caller_ptr(const char *p) {
    return callee_ptr(p);
}

Compile command / flags:
podman exec defuzz-toolchain-daemon /opt/gcc16/bin/x86_64-linux-gnu-gcc -O2
-fno-strict-overflow -fno-wrapv-pointer -S -o - /tmp/t23_ai.c

Observed output (GCC 16.2.0):
caller_ptr:
        xorl    %eax, %eax
        ret
(The pointer wrap check 'p + 16 < p' in the wrapv-pointer callee is folded to
constant 0 after inlining into caller_ptr)

Expected behavior:
can_inline_edge_p must include check_match (flag_wrapv_pointer) alongside
check_match (flag_wrapv) and check_match (flag_trapv), and preserve callee
pointer-wrapping semantics across inlining boundaries.

Root cause
----------
Source location: gcc/ipa-inline.cc:579-595 (can_inline_edge_p)

In can_inline_edge_p (gcc/ipa-inline.cc:581-590), GCC lists options that alter
IL semantics and therefore block inlining even for always_inline functions
during IPA inlining: 'else if (check_match (flag_wrapv) || check_match
(flag_trapv) || check_match (flag_pcc_struct_return) ...)'. However,
flag_wrapv_pointer (-fwrapv-pointer) is omitted from this
semantic-compatibility check (and early inlining at line 579 skips the check
for always_inline functions while IPA inlining enforces it for non-early inline
edges). Consequently, when a function compiled with
__attribute__((optimize("wrapv-pointer"))) is inlined into a caller with
-fno-wrapv-pointer, the callee's pointer-overflow check (p + 16 < p) is
evaluated under the caller's pointer-overflow-is-UB regime and folded to
constant 0!

Impact:
Pointer bounds/overflow checks (such as 'buf + len < buf') inside functions
explicitly annotated with optimize("wrapv-pointer") are silently folded to
false (0) when inlined into callers with -fno-wrapv-pointer.

Suggested Fix
-------------
In gcc/ipa-inline.cc:584 (can_inline_edge_p), add '|| check_match
(flag_wrapv_pointer)' right after 'check_match (flag_wrapv)'.

Reply via email to