From: Marek Polacek Date: Mon, 1 Dec 2014 15:29:11 +0000 (+0000) Subject: re PR sanitizer/63956 ([UBSAN] ICE segfault in cxx_eval_call_expression ../../gcc... X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=0b274c179f478df449d66bd0707cb9aa05dcafed;p=gcc.git re PR sanitizer/63956 ([UBSAN] ICE segfault in cxx_eval_call_expression ../../gcc/cp/constexpr.c) PR sanitizer/63956 * ubsan.c (is_ubsan_builtin_p): Check also built-in class. cp/ * constexpr.c: Include ubsan.h. (cxx_eval_call_expression): Bail out for IFN_UBSAN_{NULL,BOUNDS} internal functions and for ubsan builtins. * error.c: Include internal-fn.h. (dump_expr): Add printing of internal functions. testsuite/ * c-c++-common/ubsan/shift-5.c: Add xfails. * g++.dg/ubsan/div-by-zero-1.C: Don't use -w. Add xfail. * g++.dg/ubsan/pr63956.C: New test. From-SVN: r218221 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index ff430be9908..f75ecf5391e 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2014-12-01 Marek Polacek + + PR sanitizer/63956 + * ubsan.c (is_ubsan_builtin_p): Check also built-in class. + 2014-12-01 Jakub Jelinek * gimple.h (gimple_build_assign_stat): Remove prototype. diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 77b2b1e771e..93780c0a6a8 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,12 @@ +2014-12-01 Marek Polacek + + PR sanitizer/63956 + * constexpr.c: Include ubsan.h. + (cxx_eval_call_expression): Bail out for IFN_UBSAN_{NULL,BOUNDS} + internal functions and for ubsan builtins. + * error.c: Include internal-fn.h. + (dump_expr): Add printing of internal functions. + 2014-12-01 Marek Polacek * constexpr.c (literal_type_p): Return true for void type in C++14. diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 6fdb9f3657c..2184a2f300b 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -32,6 +32,7 @@ along with GCC; see the file COPYING3. If not see #include "gimplify.h" #include "builtins.h" #include "tree-inline.h" +#include "ubsan.h" static bool verify_constant (tree, bool, bool *, bool *); #define VERIFY_CONSTANT(X) \ @@ -1152,6 +1153,19 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, constexpr_call *entry; bool depth_ok; + if (fun == NULL_TREE) + switch (CALL_EXPR_IFN (t)) + { + case IFN_UBSAN_NULL: + case IFN_UBSAN_BOUNDS: + return void_node; + default: + if (!ctx->quiet) + error_at (loc, "call to internal function"); + *non_constant_p = true; + return t; + } + if (TREE_CODE (fun) != FUNCTION_DECL) { /* Might be a constexpr function pointer. */ @@ -1172,6 +1186,10 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, } if (DECL_CLONED_FUNCTION_P (fun)) fun = DECL_CLONED_FUNCTION (fun); + + if (is_ubsan_builtin_p (fun)) + return void_node; + if (is_builtin_fn (fun)) return cxx_eval_builtin_function_call (ctx, t, addr, non_constant_p, overflow_p); diff --git a/gcc/cp/error.c b/gcc/cp/error.c index 5dcc149e185..ff26fb91f73 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -33,6 +33,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-pretty-print.h" #include "c-family/c-objc.h" #include "ubsan.h" +#include "internal-fn.h" #include // For placement-new. @@ -2039,6 +2040,14 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags) tree fn = CALL_EXPR_FN (t); bool skipfirst = false; + /* Deal with internal functions. */ + if (fn == NULL_TREE) + { + pp_string (pp, internal_fn_name (CALL_EXPR_IFN (t))); + dump_call_expr_args (pp, t, flags, skipfirst); + break; + } + if (TREE_CODE (fn) == ADDR_EXPR) fn = TREE_OPERAND (fn, 0); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 715ea975b9b..d7635f2f21a 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2014-12-01 Marek Polacek + + PR sanitizer/63956 + * c-c++-common/ubsan/shift-5.c: Add xfails. + * g++.dg/ubsan/div-by-zero-1.C: Don't use -w. Add xfail. + * g++.dg/ubsan/pr63956.C: New test. + 2014-12-01 Marek Polacek * g++.dg/cpp0x/constexpr-function2.C: Limit dg-error to C++11. diff --git a/gcc/testsuite/c-c++-common/ubsan/shift-5.c b/gcc/testsuite/c-c++-common/ubsan/shift-5.c index 6f9c52a7288..9e85042b059 100644 --- a/gcc/testsuite/c-c++-common/ubsan/shift-5.c +++ b/gcc/testsuite/c-c++-common/ubsan/shift-5.c @@ -2,31 +2,41 @@ /* { dg-options "-fsanitize=shift -w" } */ /* { dg-shouldfail "ubsan" } */ -int x; int -foo (void) +foo (int x) { /* None of the following should pass. */ switch (x) { case 1 >> -1: -/* { dg-error "case label does not reduce to an integer constant" "" {target c } 12 } */ -/* { dg-error "is not a constant expression" "" { target c++ } 12 } */ +/* { dg-error "case label does not reduce to an integer constant" "" { target c } 11 } */ +/* { dg-error "is not a constant expression" "" { xfail { *-*-* } } 11 } */ case -1 >> -1: -/* { dg-error "case label does not reduce to an integer constant" "" {target c } 15 } */ -/* { dg-error "is not a constant expression" "" { target c++ } 15 } */ +/* { dg-error "case label does not reduce to an integer constant" "" { target c } 14 } */ +/* { dg-error "is not a constant expression" "" { xfail { *-*-* } } 14 } */ case 1 << -1: -/* { dg-error "case label does not reduce to an integer constant" "" {target c } 18 } */ -/* { dg-error "is not a constant expression" "" { target c++ } 18 } */ +/* { dg-error "case label does not reduce to an integer constant" "" { target c } 17 } */ +/* { dg-error "is not a constant expression" "" { xfail { *-*-* } } 17 } */ case -1 << -1: -/* { dg-error "case label does not reduce to an integer constant" "" {target c } 21 } */ -/* { dg-error "is not a constant expression" "" { target c++ } 21 } */ +/* { dg-error "case label does not reduce to an integer constant" "" { target c } 20 } */ +/* { dg-error "is not a constant expression" "" { xfail { *-*-* } } 20 } */ + return 1; + } + return 0; +} + +int +bar (int x) +{ + /* None of the following should pass. */ + switch (x) + { case -1 >> 200: -/* { dg-error "case label does not reduce to an integer constant" "" {target c } 24 } */ -/* { dg-error "is not a constant expression" "" { target c++ } 24 } */ +/* { dg-error "case label does not reduce to an integer constant" "" { target c } 34 } */ +/* { dg-error "is not a constant expression" "" { xfail { *-*-* } } 34 } */ case 1 << 200: -/* { dg-error "case label does not reduce to an integer constant" "" {target c } 27 } */ -/* { dg-error "is not a constant expression" "" { target c++ } 27 } */ +/* { dg-error "case label does not reduce to an integer constant" "" { target c } 37 } */ +/* { dg-error "is not a constant expression" "" { xfail { *-*-* } } 37 } */ return 1; } return 0; diff --git a/gcc/testsuite/g++.dg/ubsan/div-by-zero-1.C b/gcc/testsuite/g++.dg/ubsan/div-by-zero-1.C index 88acfa1517e..946f2e615f5 100644 --- a/gcc/testsuite/g++.dg/ubsan/div-by-zero-1.C +++ b/gcc/testsuite/g++.dg/ubsan/div-by-zero-1.C @@ -1,10 +1,14 @@ /* { dg-do compile } */ -/* { dg-options "-fsanitize=integer-divide-by-zero -w" } */ +/* { dg-options "-fsanitize=integer-divide-by-zero" } */ + +/* TODO: We expect an error on the invalid case here, because that + must be a constant-expression. This will be fixed when we have + proper delayed folding. */ void foo (int i) { switch (i) - case 0 * (1 / 0): /* { dg-error "is not a constant expression" } */ - ; + case 0 * (1 / 0): /* { dg-warning "division by zero" } */ + ; /* { dg-error "division by zero" "" { xfail *-*-* } 10 } */ } diff --git a/gcc/testsuite/g++.dg/ubsan/pr63956.C b/gcc/testsuite/g++.dg/ubsan/pr63956.C new file mode 100644 index 00000000000..adfb55f6797 --- /dev/null +++ b/gcc/testsuite/g++.dg/ubsan/pr63956.C @@ -0,0 +1,172 @@ +// PR sanitizer/63956 +// { dg-do compile } +// { dg-options "-std=c++14 -fsanitize=undefined,float-divide-by-zero,float-cast-overflow" } + +#define SA(X) static_assert((X),#X) +#define INT_MIN (-__INT_MAX__ - 1) + +constexpr int +fn1 (int a, int b) +{ + if (b != 2) + a <<= b; + return a; +} + +constexpr int i1 = fn1 (5, 3); +constexpr int i2 = fn1 (5, -2); +constexpr int i3 = fn1 (5, sizeof (int) * __CHAR_BIT__); +constexpr int i4 = fn1 (5, 256); +constexpr int i5 = fn1 (5, 2); +constexpr int i6 = fn1 (-2, 4); +constexpr int i7 = fn1 (0, 2); + +SA (i1 == 40); +SA (i5 == 5); +SA (i7 == 0); + +constexpr int +fn2 (int a, int b) +{ + if (b != 2) + a >>= b; + return a; +} + +constexpr int j1 = fn2 (4, 1); +constexpr int j2 = fn2 (4, -1); +constexpr int j3 = fn2 (10, sizeof (int) * __CHAR_BIT__); +constexpr int j4 = fn2 (1, 256); +constexpr int j5 = fn2 (5, 2); +constexpr int j6 = fn2 (-2, 4); +constexpr int j7 = fn2 (0, 4); + +SA (j1 == 2); +SA (j5 == 5); +SA (j7 == 0); + +constexpr int +fn3 (int a, int b) +{ + if (b != 2) + a = a / b; + return a; +} + +constexpr int k1 = fn3 (8, 4); +constexpr int k2 = fn3 (7, 0); // { dg-error "is not a constant expression" } +constexpr int k3 = fn3 (INT_MIN, -1); // { dg-error "overflow in constant expression" } + +SA (k1 == 2); + +constexpr float +fn4 (float a, float b) +{ + if (b != 2.0) + a = a / b; + return a; +} + +constexpr float l1 = fn4 (5.0, 3.0); +constexpr float l2 = fn4 (7.0, 0.0); // { dg-error "is not a constant expression" } + +constexpr int +fn5 (const int *a, int b) +{ + if (b != 2) + b = a[b]; + return b; +} + +constexpr int m1[4] = { 1, 2, 3, 4 }; +constexpr int m2 = fn5 (m1, 3); +constexpr int m3 = fn5 (m1, 4); // { dg-error "array subscript out of bound" } + +constexpr int +fn6 (const int &a, int b) +{ + if (b != 2) + b = a; + return b; +} + +constexpr int +fn7 (const int *a, int b) +{ + if (b != 3) + return fn6 (*a, b); + return 7; +} + +constexpr int n1 = 7; +constexpr int n2 = fn7 (&n1, 5); +constexpr int n3 = fn7 ((const int *) 0, 8); // { dg-error "is not a constant expression" } + +constexpr int +fn8 (int i) +{ + constexpr int g[10] = { }; + return g[i]; +} + +constexpr int o1 = fn8 (9); +constexpr int o2 = fn8 (10); // { dg-error "array subscript out of bound" } + +constexpr int +fn9 (int a, int b) +{ + if (b != 0) + return a + b; + return a; +} + +constexpr int p1 = fn9 (42, 7); +constexpr int p2 = fn9 (__INT_MAX__, 1); // { dg-error "overflow in constant expression" } +constexpr int p3 = fn9 (__INT_MAX__, -1); +constexpr int p4 = fn9 (INT_MIN, 1); +constexpr int p5 = fn9 (INT_MIN, -1); // { dg-error "overflow in constant expression" } + +SA (p1 == 49); +SA (p3 == __INT_MAX__ - 1); +SA (p4 == INT_MIN + 1); + +constexpr int +fn10 (int a, int b) +{ + if (b != 0) + return a * b; + return a; +} + +constexpr int q1 = fn10 (10, 10); +constexpr int q2 = fn10 (__INT_MAX__, 2); // { dg-error "overflow in constant expression" } +constexpr int q3 = fn10 (INT_MIN, 2); // { dg-error "overflow in constant expression" } +constexpr int q4 = fn10 (-1, -1); + +SA (q1 == 100); +SA (q4 == 1); + +constexpr int +fn11 (double d) +{ + int i = d; + if (i != 0) + return i; + return i * 2; +} + +constexpr int r1 = fn11 (3.4); +constexpr int r2 = fn11 (__builtin_inf ()); // { dg-error "overflow in constant expression" } + +constexpr int +fn12 (int i) +{ + if (i == 42) + __builtin_unreachable (); // { dg-error "is not a constant expression" } + return i + 10; +} + +constexpr int s1 = fn12 (1); +constexpr int s2 = fn12 (42); + +SA (s1 == 11); diff --git a/gcc/ubsan.c b/gcc/ubsan.c index 6d3caeefb38..cff0982eac7 100644 --- a/gcc/ubsan.c +++ b/gcc/ubsan.c @@ -653,6 +653,7 @@ bool is_ubsan_builtin_p (tree t) { return TREE_CODE (t) == FUNCTION_DECL + && DECL_BUILT_IN_CLASS (t) == BUILT_IN_NORMAL && strncmp (IDENTIFIER_POINTER (DECL_NAME (t)), "__builtin___ubsan_", 18) == 0; }