On Fri, Sep 12, 2025 at 8:31 PM H.J. Lu <[email protected]> wrote: > > Since IFUNC resolvers run early before the sanitizer run-time libraries > have a chance to set up the sanitizer infrastructure, disable sanitizer > in IFUNC resolver when the sanitizer infrastructure initialization is > needed. > > gcc/ > > PR sanitizer/110442 > * asan.h (sanitize_flags_p): Return false if the function is > called by IFUNC resolver. > (sanitize_coverage_p): Likewise. > * cgraph.cc (called_by_ifunc_resolver_p): New. > * internal-fn.cc (expand_TSAN_FUNC_EXIT): Return in function > called by IFUNC resolver. > * tree.h (called_by_ifunc_resolver_p): Likewise. > > gcc/testsuite/ > > PR sanitizer/110442 > * gcc.dg/asan/ifunc-1.c: New test. > * gcc.dg/tsan/ifunc-1.c: Likewise. > * gcc.dg/ubsan/ifunc-shift-1.c: Likewise. > > Signed-off-by: H.J. Lu <[email protected]> > --- > gcc/asan.h | 9 ++++- > gcc/cgraph.cc | 9 +++++ > gcc/internal-fn.cc | 6 ++- > gcc/testsuite/gcc.dg/asan/ifunc-1.c | 37 ++++++++++++++++++ > gcc/testsuite/gcc.dg/tsan/ifunc-1.c | 38 +++++++++++++++++++ > gcc/testsuite/gcc.dg/ubsan/ifunc-shift-1.c | 44 ++++++++++++++++++++++ > gcc/tree.h | 5 +++ > 7 files changed, 144 insertions(+), 4 deletions(-) > create mode 100644 gcc/testsuite/gcc.dg/asan/ifunc-1.c > create mode 100644 gcc/testsuite/gcc.dg/tsan/ifunc-1.c > create mode 100644 gcc/testsuite/gcc.dg/ubsan/ifunc-shift-1.c > > diff --git a/gcc/asan.h b/gcc/asan.h > index a24562f67a2..999ed0dd818 100644 > --- a/gcc/asan.h > +++ b/gcc/asan.h > @@ -251,6 +251,10 @@ sanitize_flags_p (sanitize_code_type flag, > > if (fn != NULL_TREE) > { > + if (TREE_CODE (fn) == FUNCTION_DECL > + && called_by_ifunc_resolver_p (fn)) > + return false; > + > tree value = lookup_attribute ("no_sanitize", DECL_ATTRIBUTES (fn)); > if (value) > result_flags &= ~tree_to_uhwi (TREE_VALUE (value)); > @@ -266,8 +270,9 @@ sanitize_coverage_p (const_tree fn = > current_function_decl) > { > return (flag_sanitize_coverage > && (fn == NULL_TREE > - || lookup_attribute ("no_sanitize_coverage", > - DECL_ATTRIBUTES (fn)) == NULL_TREE)); > + || (!called_by_ifunc_resolver_p (fn) > + && !lookup_attribute ("no_sanitize_coverage", > + DECL_ATTRIBUTES (fn))))); > } > > #endif /* TREE_ASAN */ > diff --git a/gcc/cgraph.cc b/gcc/cgraph.cc > index 32071a84bac..820c57695c2 100644 > --- a/gcc/cgraph.cc > +++ b/gcc/cgraph.cc > @@ -4494,6 +4494,15 @@ cgraph_node::former_thunk_p (void) > return true; > } > > +/* Return true if FN is called by an IFUNC resolver. */ > + > +bool > +called_by_ifunc_resolver_p (const_tree fn) > +{ > + struct cgraph_node *c_node = cgraph_node::get (fn); > + return c_node && c_node->called_by_ifunc_resolver; > +} > + > /* A stashed copy of "symtab" for use by selftest::symbol_table_test. > This needs to be a global so that it can be a GC root, and thus > prevent the stashed copy from being garbage-collected if the GC runs > diff --git a/gcc/internal-fn.cc b/gcc/internal-fn.cc > index bf2fac81807..f4cc0ce745d 100644 > --- a/gcc/internal-fn.cc > +++ b/gcc/internal-fn.cc > @@ -877,12 +877,14 @@ expand_ASAN_POISON_USE (internal_fn, gcall *) > gcc_unreachable (); > } > > -/* This should get expanded in the tsan pass. */ > +/* This should get expanded in the tsan pass unless it is in a function > + called by IFUNC resolver. */ > > static void > expand_TSAN_FUNC_EXIT (internal_fn, gcall *) > { > - gcc_unreachable (); > + if (!called_by_ifunc_resolver_p (current_function_decl)) > + gcc_unreachable (); > } > > /* This should get expanded in the lower pass. */ > diff --git a/gcc/testsuite/gcc.dg/asan/ifunc-1.c > b/gcc/testsuite/gcc.dg/asan/ifunc-1.c > new file mode 100644 > index 00000000000..3e944c4fb67 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/asan/ifunc-1.c > @@ -0,0 +1,37 @@ > +/* PR sanitizer/110442 */ > +/* Don't use dg-require-ifunc to avoid marking this test as UNSUPPORTED > + due to ICE caused by compiler bug during IFUNC check. */ > +/* { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } } */ > + > +#include <stdio.h> > + > +void > +f1 (void) > +{ > + puts ("f1"); > +} > + > +void > +f2 (void) > +{ > + puts ("f2"); > +} > + > +void * > +resolve (void) > +{ > + __builtin_cpu_init (); > + if (__builtin_cpu_supports ("f16c")) > + return f1; > + else > + return f2; > +} > + > +void f (void) __attribute__ ((ifunc ("resolve"))); > + > +int > +main (void) > +{ > + f (); > + return 0; > +} > diff --git a/gcc/testsuite/gcc.dg/tsan/ifunc-1.c > b/gcc/testsuite/gcc.dg/tsan/ifunc-1.c > new file mode 100644 > index 00000000000..da477e33983 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/tsan/ifunc-1.c > @@ -0,0 +1,38 @@ > +/* PR sanitizer/110442 */ > +/* Don't use dg-require-ifunc to avoid marking this test as UNSUPPORTED > + due to ICE caused by compiler bug during IFUNC check. */ > +/* { dg-do run { target { x86_64-*-linux* } } } */ > +/* { dg-options "-fsanitize=thread" } */ > + > +#include <stdio.h> > + > +void > +f1 (void) > +{ > + puts ("f1"); > +} > + > +void > +f2 (void) > +{ > + puts ("f2"); > +} > + > +void * > +resolve (void) > +{ > + __builtin_cpu_init (); > + if (__builtin_cpu_supports ("f16c")) > + return f1; > + else > + return f2; > +} > + > +void f (void) __attribute__ ((ifunc ("resolve"))); > + > +int > +main (void) > +{ > + f (); > + return 0; > +} > diff --git a/gcc/testsuite/gcc.dg/ubsan/ifunc-shift-1.c > b/gcc/testsuite/gcc.dg/ubsan/ifunc-shift-1.c > new file mode 100644 > index 00000000000..973097cf098 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/ubsan/ifunc-shift-1.c > @@ -0,0 +1,44 @@ > +/* PR sanitizer/110442 */ > +/* Don't use dg-require-ifunc to avoid marking this test as UNSUPPORTED > + due to ICE caused by compiler bug during IFUNC check. */ > +/* { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } } */ > +/* { dg-options "-fsanitize=shift-exponent -Wno-shift-count-overflow" } */ > + > +#include <stdio.h> > + > +int n = 30; > + > +void > +f1 (void) > +{ > + puts ("f1"); > +} > + > +void > +f2 (void) > +{ > + puts ("f2"); > +} > + > +void * > +resolve (void) > +{ > + if ((n << 32) != 0) > + return f1; > + __builtin_cpu_init (); > + if (__builtin_cpu_supports ("f16c")) > + return f1; > + else > + return f2; > +} > + > +void f (void) __attribute__ ((ifunc ("resolve"))); > + > +int > +main (void) > +{ > + f (); > + return 0; > +} > + > +/* { dg-output "shift exponent 32 is too large for 32-bit type > 'int'\[^\n\r]*(\n|\r\n|\r)" } */ > diff --git a/gcc/tree.h b/gcc/tree.h > index ce8c778087f..706e704b2e2 100644 > --- a/gcc/tree.h > +++ b/gcc/tree.h > @@ -7113,4 +7113,9 @@ extern auto_vec<string_slice> get_clone_versions (const > tree, int * = NULL); > directly. */ > extern auto_vec<string_slice> get_clone_attr_versions (const tree, int *); > > +/* In cgraph.cc */ > + > +/* Return true if the function is called by an IFUNC resolver. */ > +extern bool called_by_ifunc_resolver_p (const_tree); > + > #endif /* GCC_TREE_H */ > -- > 2.51.0 >
PING^1. -- H.J.
