aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2024-12-12 19:47:46 +0100
committerJakub Jelinek <jakub@gcc.gnu.org>2024-12-12 19:47:46 +0100
commitf7d1b9cdc0dd811722798530efffd736bfc2bc1d (patch)
treedfb84b599f86fae2d1c8655fde02e9619a493819 /gcc
parent2cbb2408a830a63fbd901a4da3bfd341cec4b6ef (diff)
downloadgcc-f7d1b9cdc0dd811722798530efffd736bfc2bc1d.zip
gcc-f7d1b9cdc0dd811722798530efffd736bfc2bc1d.tar.gz
gcc-f7d1b9cdc0dd811722798530efffd736bfc2bc1d.tar.bz2
match.pd: Defer some CTZ/CLZ foldings until after ubsan pass for -fsanitize=builtin [PR115127]
As the following testcase shows, -fsanitize=builtin instruments the builtins in the ubsan pass which is done shortly after going into SSA, but if optimizations optimize the builtins away before that, nothing is instrumented. Now, I think it is just fine if the result of the builtins isn't used in any way and we just DCE them, but in the following optimizations the result is used. So, the following patch for -fsanitize=builtin only defers the optimizations that might turn single argument CLZ/CTZ (aka undefined at zero) until the ubsan pass is done. Now, we don't have PROP_ubsan and am not sure it is worth adding it, there is PROP_ssa set by the ssa pass which is 3 passes before ubsan, but there are only 2 warning passes in between, so PROP_ssa looked good enough to me. 2024-12-12 Jakub Jelinek <jakub@redhat.com> PR sanitizer/115127 * match.pd (clz (X) == C, ctz (X) == C, ctz (X) >= C): Don't optimize if -fsanitize=builtin and not yet in SSA form. * c-c++-common/ubsan/builtin-2.c: New test.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/match.pd43
-rw-r--r--gcc/testsuite/c-c++-common/ubsan/builtin-2.c89
2 files changed, 122 insertions, 10 deletions
diff --git a/gcc/match.pd b/gcc/match.pd
index 55617b2..4587658 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -9636,13 +9636,17 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
cmp (lt ge)
(simplify
(op (clz:s@2 @0) INTEGER_CST@1)
- (if (integer_zerop (@1) && single_use (@2))
- /* clz(X) == 0 is (int)X < 0 and clz(X) != 0 is (int)X >= 0. */
- (with { tree stype = signed_type_for (TREE_TYPE (@0)); }
- (cmp (convert:stype @0) { build_zero_cst (stype); }))
- /* clz(X) == (prec-1) is X == 1 and clz(X) != (prec-1) is X != 1. */
- (if (wi::to_wide (@1) == TYPE_PRECISION (TREE_TYPE (@0)) - 1)
- (op @0 { build_one_cst (TREE_TYPE (@0)); }))))))
+ (if (!sanitize_flags_p (SANITIZE_BUILTIN)
+ /* For -fsanitize=builtin give ubsan pass a chance
+ to instrument it first. */
+ || (cfun && (cfun->curr_properties & PROP_ssa) != 0))
+ (if (integer_zerop (@1) && single_use (@2))
+ /* clz(X) == 0 is (int)X < 0 and clz(X) != 0 is (int)X >= 0. */
+ (with { tree stype = signed_type_for (TREE_TYPE (@0)); }
+ (cmp (convert:stype @0) { build_zero_cst (stype); }))
+ /* clz(X) == (prec-1) is X == 1 and clz(X) != (prec-1) is X != 1. */
+ (if (wi::to_wide (@1) == TYPE_PRECISION (TREE_TYPE (@0)) - 1)
+ (op @0 { build_one_cst (TREE_TYPE (@0)); })))))))
(for op (eq ne)
cmp (lt ge)
(simplify
@@ -9682,7 +9686,13 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(op (ctz:s @0) INTEGER_CST@1)
(with { bool ok = true;
HOST_WIDE_INT val = 0;
- if (!tree_fits_shwi_p (@1))
+ if (sanitize_flags_p (SANITIZE_BUILTIN)
+ /* For -fsanitize=builtin give ubsan pass a chance
+ to instrument it first. */
+ && (!cfun
+ || (cfun->curr_properties & PROP_ssa) == 0))
+ ok = false;
+ else if (!tree_fits_shwi_p (@1))
ok = false;
else
{
@@ -9713,8 +9723,15 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(op (ctz:s @0) INTEGER_CST@1)
(with { tree type0 = TREE_TYPE (@0);
int prec = TYPE_PRECISION (type0);
+ bool ok = true;
+ if (sanitize_flags_p (SANITIZE_BUILTIN)
+ /* For -fsanitize=builtin give ubsan pass a chance
+ to instrument it first. */
+ && (!cfun
+ || (cfun->curr_properties & PROP_ssa) == 0))
+ ok = false;
}
- (if (prec <= MAX_FIXED_MODE_SIZE)
+ (if (ok && prec <= MAX_FIXED_MODE_SIZE)
(if (tree_int_cst_sgn (@1) < 0 || wi::to_widest (@1) >= prec)
{ constant_boolean_node (op == EQ_EXPR ? false : true, type); }
(op (bit_and @0 { wide_int_to_tree (type0,
@@ -9815,7 +9832,13 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
else if (TYPE_PRECISION (type0)
== TYPE_PRECISION (long_long_unsigned_type_node))
cfn = CFN_BUILT_IN_CTZLL;
- } }
+ }
+ if (sanitize_flags_p (SANITIZE_BUILTIN)
+ /* For -fsanitize=builtin give ubsan pass a chance
+ to instrument it first. */
+ && (!cfun
+ || (cfun->curr_properties & PROP_ssa) == 0))
+ cfn = CFN_LAST; }
(if (cfn == CFN_CTZ)
(IFN_CTZ (convert:type0 @0))
(if (cfn == CFN_BUILT_IN_CTZ)
diff --git a/gcc/testsuite/c-c++-common/ubsan/builtin-2.c b/gcc/testsuite/c-c++-common/ubsan/builtin-2.c
new file mode 100644
index 0000000..877bd53
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/ubsan/builtin-2.c
@@ -0,0 +1,89 @@
+/* PR sanitizer/115127 */
+/* { dg-do run } */
+/* { dg-options "-fsanitize=undefined" } */
+
+#include <stdio.h>
+
+__attribute__((noipa)) int
+f1 (unsigned a)
+{
+ return __builtin_clz (a) == 0;
+}
+
+__attribute__((noipa)) int
+f2 (unsigned long a)
+{
+ return __builtin_clzl (a) != 0;
+}
+
+__attribute__((noipa)) int
+f3 (unsigned long long a)
+{
+ return __builtin_clzll (a) == __CHAR_BIT__ * __SIZEOF_LONG_LONG__ - 1;
+}
+
+__attribute__((noipa)) int
+f4 (unsigned a)
+{
+ return __builtin_clz (a) != __CHAR_BIT__ * __SIZEOF_INT__ - 1;
+}
+
+__attribute__((noipa)) int
+f5 (unsigned long a)
+{
+ return __builtin_ctzl (a) == 0;
+}
+
+__attribute__((noipa)) int
+f6 (unsigned long long a)
+{
+ return __builtin_ctzll (a) != 0;
+}
+
+__attribute__((noipa)) int
+f7 (unsigned a)
+{
+ return __builtin_ctz (a) == 4;
+}
+
+__attribute__((noipa)) int
+f8 (unsigned long a)
+{
+ return __builtin_ctzl (a) != 4;
+}
+
+__attribute__((noipa)) int
+f9 (unsigned long long a)
+{
+ return __builtin_ctzll (a) >= 4;
+}
+
+__attribute__((noipa)) int
+f10 (unsigned a)
+{
+ return __builtin_ctz (a) < 4;
+}
+
+int
+main ()
+{
+ fprintf (stderr, "FOO MARKER1\n");
+ f1 (0);
+ f2 (0);
+ f3 (0);
+ f4 (0);
+ fprintf (stderr, "FOO MARKER2\n");
+ f5 (0);
+ f6 (0);
+ f7 (0);
+ f8 (0);
+ f9 (0);
+ f10 (0);
+ fprintf (stderr, "FOO MARKER3\n");
+}
+
+/* { dg-output "FOO MARKER1(\n|\r\n|\r)" } */
+/* { dg-output "(\[^\n\r]*runtime error: passing zero to __builtin_clz\\\(\\\), which is not a valid argument\[^\n\r]*(\n|\r\n|\r)){4}" } */
+/* { dg-output "FOO MARKER2(\n|\r\n|\r)" } */
+/* { dg-output "(\[^\n\r]*runtime error: passing zero to __builtin_ctz\\\(\\\), which is not a valid argument\[^\n\r]*(\n|\r\n|\r)){6}" } */
+/* { dg-output "FOO MARKER3" } */