Created attachment 34035 [details] Test case (scan16.ii) That's a new regression. It was working when I reduce PR63813 (i.e. on 2014-11-11) as that ICE came later. It now ICEs with todays GCC (r217759). g++ -S -std=c++11 -fsanitize=undefined scan16.ii scan16.ii:51:28: in constexpr expansion of ‘std::validator.std::unique_ptr<std::Validator>::unique_ptr()’ scan16.ii:51:28: internal compiler error: Segmentation fault unique_ptr < Validator > validator; ^ 0xcba72f crash_signal ../../gcc/toplev.c:359 0x81ea9a cxx_eval_call_expression ../../gcc/cp/constexpr.c:1147 0x820b1c cxx_eval_constant_expression ../../gcc/cp/constexpr.c:2864
Confirmed.
It looks like cxx_eval_call_expression just isn't prepared for internal functions, with NULL_TREE CALL_EXPR_FN.
Supposedly with the C++14 constexpr changes we need to be prepared to handle all the ubsan builtins and internal calls we create during genericization. Already in the still pending -fsanitize=vptr patch I had to deal with handling the ubsan vptr type cache miss builtin even before the C++14 constexpr changes, because that is created during static_cast handling, but if we now look at DECL_SAVED_TREE, it can see all the builtins / internal calls in there. I hope most of the ubsan stuff can be ignored for constexpr purposes.
(In reply to Jakub Jelinek from comment #3) > Supposedly with the C++14 constexpr changes we need to be prepared to handle > all the ubsan builtins and internal calls we create during genericization. Hmm, maybe I should make a copy of the pre-genericization DECL_SAVED_TREE instead...
If it would be just because of these 3-4 builtins/internal calls, then it is not worth it IMHO, making a copy would increase compiler memory footprint. Already from the earlier phases there are some ubsan builtins in there anyway (shift instrumentation e.g.).
Earlier today I tried the following and it seemed to work, but I don't know constexpr.c, so it may be totally bogus. --- gcc/cp/constexpr.c +++ gcc/cp/constexpr.c @@ -1149,6 +1149,10 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, constexpr_call *entry; bool depth_ok; + if (fun == NULL_TREE + && CALL_EXPR_IFN (t) == IFN_UBSAN_NULL) + return t; + if (TREE_CODE (fun) != FUNCTION_DECL) { /* Might be a constexpr function pointer. */
(In reply to Marek Polacek from comment #6) > Earlier today I tried the following and it seemed to work, but I don't know > constexpr.c, so it may be totally bogus. > > --- gcc/cp/constexpr.c > +++ gcc/cp/constexpr.c > @@ -1149,6 +1149,10 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, > tree t, > constexpr_call *entry; > bool depth_ok; > > + if (fun == NULL_TREE > + && CALL_EXPR_IFN (t) == IFN_UBSAN_NULL) > + return t; > + > if (TREE_CODE (fun) != FUNCTION_DECL) > { > /* Might be a constexpr function pointer. */ The -fsanitize=vptr patch has: if (is_builtin_fn (fun)) - return cxx_eval_builtin_function_call (old_call, t, allow_non_constant, - addr, non_constant_p, overflow_p); + { + /* Ignore -fsanitize=vptr instrumentation. */ + if ((flag_sanitize & SANITIZE_VPTR) + && DECL_BUILT_IN_CLASS (fun) == BUILT_IN_NORMAL + && (DECL_FUNCTION_CODE (fun) + == ((flag_sanitize_recover & SANITIZE_VPTR) + ? BUILT_IN_UBSAN_HANDLE_DYNAMIC_TYPE_CACHE_MISS + : BUILT_IN_UBSAN_HANDLE_DYNAMIC_TYPE_CACHE_MISS_ABORT)) + && call_expr_nargs (t) == 4) + return void_node; + + return cxx_eval_builtin_function_call (old_call, t, allow_non_constant, + addr, non_constant_p, overflow_p); + } hunk in it to ignore __builtin___ubsan_handle_dynamic_type_cache_miss*. For fun == NULL_TREE, guess what you want is a switch on the CALL_EXPR_IFN value and enumerate there all the internal calls and elsewhere builtins that should be ignored.
Thanks, will try that tomorrow. So to ignore the call I should return void_node instead of t, good to know.
In the light of -std=c++14 constexprs, please try to write testcases like (-std=c++14 -fsanitize=undefined,float-divide-by-zero,float-cast-overflow): constexpr int f1 (int a, int b) { if (b != 2) a <<= b; return a; } constexpr int x1 = f1 (5, 3); constexpr int x2 = f1 (5, -2); constexpr int f2 (int a, int b) { if (b != 2) a = a / b; return a; } constexpr int x3 = f2 (5, 3); constexpr int x4 = f2 (7, 0); constexpr int x5 = f2 (-__INT_MAX__ - 1, -1); constexpr float f3 (float a, float b) { if (b != 2.0) a = a / b; return a; } constexpr float x6 = f3 (5.0, 3.0); constexpr float x7 = f3 (7.0, 0.0); constexpr int f4 (const int *a, int b) { if (b != 2) b = a[b]; return b; } constexpr int x8[4] = { 1, 2, 3, 4 }; constexpr int x9 = f4 (x8, 3); constexpr int x10 = f4 (x8, 4); constexpr int f5 (const int &a, int b) { if (b != 2) b = a; return b; } constexpr int f6 (const int *a, int b) { if (b != 3) return f5 (*a, b); return 7; } constexpr int x12 = 7; constexpr int x13 = f6 (&x12, 5); constexpr int x14 = f6 ((const int *) 0, 8); (and add for all the other stuff we ubsan instrument in the FEs). For the first snippet we e.g. emit: m1.C:10:23: in constexpr expansion of ‘f1(5, -2)’ m1.C:5:7: error: ‘<ubsan routine call>’ is not a constant expression a <<= b; ^ m1.C:10:29: error: constexpr call flows off the end of the function constexpr int x2 = f1 (5, -2); ^ I'd say we should not, we should just ignore the ubsan routine call. If C++14 constexprs are supposed to be invalid if there is undefined behavior in them while being interpreted by the compiler with the given arguments, then supposedly the FE should regardless of -fsanitize=undefined error out or warn and say exactly what is invalid in there, talking about <ubsan routine call> is just too confusing. Don't know if rejecting it is just QoI or a requirement in C++14. And on the last snippet we ICE, that is the internal call. Haven't added all the cases there though, and even e.g. for shift I haven't tried to call it with all the kinds of arguments that are invalid in C++14.
BTW, wouldn't it make sense to not instrument things in constexpr functions? It is not always possible, but at least in cp/ we could skip instrumentation if DECL_DECLARED_CONSTEXPR_P (current_function_decl), similarly as we check for no_sanitize_undefined.
I thought you can call constexpr functions outside of constexpr contexts with non-constant arguments and they are executed then as any other function, so not instrumenting would mean you'd miss undefined behavior diagnostics.
Of course. Thanks.
Author: mpolacek Date: Mon Dec 1 15:29:11 2014 New Revision: 218221 URL: https://gcc.gnu.org/viewcvs?rev=218221&root=gcc&view=rev Log: 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. Added: trunk/gcc/testsuite/g++.dg/ubsan/pr63956.C Modified: trunk/gcc/ChangeLog trunk/gcc/cp/ChangeLog trunk/gcc/cp/constexpr.c trunk/gcc/cp/error.c trunk/gcc/testsuite/ChangeLog trunk/gcc/testsuite/c-c++-common/ubsan/shift-5.c trunk/gcc/testsuite/g++.dg/ubsan/div-by-zero-1.C trunk/gcc/ubsan.c
Fixed.