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)'.