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