[Bug sanitizer/71962] error: ‘((& x) != 0u)’ is not a constant expression
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71962 Barry Revzin changed: What|Removed |Added CC||barry.revzin at gmail dot com --- Comment #12 from Barry Revzin --- Similar failure: struct A { void f(); }; int main() { constexpr auto pmf = ::f; static_assert(pmf != nullptr); // error with UBSAN only } This surfaces from attempting to implement function_ref (https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p0792r14.html) which has a constructor that takes the callable as a non-type template parameter and static_asserts that it's not a null pointer. Which apparently doesn't work with UBSAN.
[Bug sanitizer/71962] error: ‘((& x) != 0u)’ is not a constant expression
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71962 --- Comment #11 from Andrew Pinski --- *** Bug 110493 has been marked as a duplicate of this bug. ***
[Bug sanitizer/71962] error: ‘((& x) != 0u)’ is not a constant expression
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71962 Andrew Pinski changed: What|Removed |Added CC||trippels at gcc dot gnu.org --- Comment #10 from Andrew Pinski --- *** Bug 67762 has been marked as a duplicate of this bug. ***
[Bug sanitizer/71962] error: ‘((& x) != 0u)’ is not a constant expression
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71962 S. Davis Herring changed: What|Removed |Added CC||herring at lanl dot gov --- Comment #9 from S. Davis Herring --- Another very similar failure (let me know if you want a separate bug for it): inline constexpr int x=0,y=0; // -std=c++17 static_assert(!=); // error: '((& x) != (& y))' is not a constant expression No failure without the 'inline'.
[Bug sanitizer/71962] error: ‘((& x) != 0u)’ is not a constant expression
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71962 --- Comment #8 from Martin Sebor --- (In reply to Jakub Jelinek from comment #7) The null pointer check inserted by the sanitizer is eventually removed (see below) so there's obviously no point in emitting it to begin with. The DSP case you mention simply isn't important to worry about, and certainly not worth pessimizing the common case for. If there really were a need to handle this corner case then it should be provided as a separate feature, under its own option, and be disabled by default (even with -fsantize=undefined). It should also be tested, which judging by the absence of test suite failures with the patch, it currently isn't. $ cat a.C && gcc -O2 -S -Wall -Wpedantic -fsanitize=undefined -fdump-tree-ubsan=/dev/stdout -fdump-tree-optimized=/dev/stdout a.C int f () { static int i = 1; int *p = return *p; } ;; Function int f() (_Z1fv, funcdef_no=0, decl_uid=2604, cgraph_uid=0, symbol_order=1) Introduced new external node (long unsigned int __builtin_object_size(const void*, int)/2). Symbols to be put in SSA form { D.2610 } Incremental SSA update started at block: 0 Number of blocks in CFG: 3 Number of blocks to update: 2 ( 67%) int f() () { int * p; static int i = 1; int _3; long unsigned int _4; [0.00%] [count: INV]: p_1 = UBSAN_NULL (p_1, 0B, 4); _4 = __builtin_object_size (p_1, 0); UBSAN_OBJECT_SIZE (p_1, 4, _4, 0); _3 = *p_1; return _3; } ;; Function int f() (_Z1fv, funcdef_no=0, decl_uid=2604, cgraph_uid=0, symbol_order=1) Removing basic block 4 Merging blocks 2 and 3 int f() () { static int i = 1; int _2; [100.00%] [count: INV]: _2 = i; return _2; }
[Bug sanitizer/71962] error: ‘((& x) != 0u)’ is not a constant expression
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71962 --- Comment #7 from Jakub Jelinek --- (In reply to Martin Sebor from comment #6) > The difference between success and failure is due to this bit of code in > symtab.c: > > /* With !flag_delete_null_pointer_checks we assume that symbols may > bind to NULL. This is on by default on embedded targets only. > > Otherwise all non-WEAK symbols must be defined and thus non-NULL or > linking fails. Important case of WEAK we want to do well are comdats. > Those are handled by later check for definition. > > When parsing, beware the cases when WEAK attribute is added later. */ > if (!DECL_WEAK (decl) > && flag_delete_null_pointer_checks) > { > refuse_visibility_changes = true; > return true; > } > > But the address of a static local variable can never be null so the test > above is unnecessarily restrictive. The following patch relaxes the test, > letting GCC accept the test case even with -fsanitize=undefined. I didn't > spot any obvious failures in the test suite with it. -fno-delete-null-pointer-checks is an option that allows violating the C requirements and a user variable can live at address 0. That is something people need on various DSPs etc. where e.g. the data or rodata section can start at NULL. So this change is wrong. Whether automatic variables can have NULL addresses is a separate question. Now, as I said before, we could change the options handling not to force flag_delete_null_pointer_checks = 0; for the sanitizers and review the places that check flag_delete_null_pointer_checks and in most of them check also the corresponding sanitizer options. then we could on a case by case decide what is and what isn't possible.
[Bug sanitizer/71962] error: ‘((& x) != 0u)’ is not a constant expression
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71962 Martin Sebor changed: What|Removed |Added CC||msebor at gcc dot gnu.org --- Comment #6 from Martin Sebor --- The difference between success and failure is due to this bit of code in symtab.c: /* With !flag_delete_null_pointer_checks we assume that symbols may bind to NULL. This is on by default on embedded targets only. Otherwise all non-WEAK symbols must be defined and thus non-NULL or linking fails. Important case of WEAK we want to do well are comdats. Those are handled by later check for definition. When parsing, beware the cases when WEAK attribute is added later. */ if (!DECL_WEAK (decl) && flag_delete_null_pointer_checks) { refuse_visibility_changes = true; return true; } But the address of a static local variable can never be null so the test above is unnecessarily restrictive. The following patch relaxes the test, letting GCC accept the test case even with -fsanitize=undefined. I didn't spot any obvious failures in the test suite with it. --- a/gcc/symtab.c +++ b/gcc/symtab.c @@ -1937,7 +1937,8 @@ symtab_node::nonzero_address () When parsing, beware the cases when WEAK attribute is added later. */ if (!DECL_WEAK (decl) - && flag_delete_null_pointer_checks) + && (flag_delete_null_pointer_checks + || (TREE_STATIC (decl) && !DECL_EXTERNAL (decl { refuse_visibility_changes = true; return true;
[Bug sanitizer/71962] error: ‘((& x) != 0u)’ is not a constant expression
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71962 Jonathan Wakely changed: What|Removed |Added Status|UNCONFIRMED |NEW Last reconfirmed||2017-07-21 Ever confirmed|0 |1 Known to fail|7.0 |7.1.0, 8.0 --- Comment #5 from Jonathan Wakely --- A simpler test: int main() { static constexpr int x = 0; static_assert(bool(), ""); } ubsan.cc: In function ‘int main()’: ubsan.cc:4:3: error: non-constant condition for static assertion static_assert(bool(), ""); ^ ubsan.cc:4:17: error: ‘((& x) != 0)’ is not a constant expression static_assert(bool(), ""); ^~~~
[Bug sanitizer/71962] error: ‘((& x) != 0u)’ is not a constant expression
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71962 --- Comment #4 from Jakub Jelinek --- If we do that, the question is when to (temporarily) enable the null pointer check deletion (unless disabled explicitly with -fno-delete-null-pointer-checks or from the target defaults, like AVR ...). Because I think there should be a difference between when some constant expression is being evaluated in constexpr contexts (then -fsanitize=undefined should not make a difference on those), and when it is just evaluated as constant expression as an optimization only (maybe_constant_value and the like for warning purposes, or during cp_fully_fold etc.). In the latter case, I think we should just not fold it if there are the sanitizations etc. Is ctx->quiet what is relevant, or something different? Perhaps even the UBSAN_* ifns should not be ignored if just in optimization?
[Bug sanitizer/71962] error: ‘((& x) != 0u)’ is not a constant expression
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71962 --- Comment #3 from Jakub Jelinek --- But we still don't want to optimize aggressively based on assumed null pointer checks, after all, that is the whole point of the null sanitization. Would static inline bool delete_null_pointer_checks_p () { return flag_delete_null_pointer_checks && (flag_sanitize & (SANITIZE_NULL | SANITIZE_NONNULL_ATTRIBUTE | SANITIZE_RETURNS_NONNULL_ATTRIBUTE)) == 0; } and replacing most of flag_delete_null_pointer_checks with delete_null_pointer_checks_p () be that bad? Then constexpr evaluation could temporarily clear flag_sanitize (it doesn't want any sanitization while doing constexpr folding).
[Bug sanitizer/71962] error: ‘((& x) != 0u)’ is not a constant expression
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71962 --- Comment #2 from Richard Biener --- Maybe the sanitizers could use sth not visible to the middle-end for null pointer tests, like a new IFN?
[Bug sanitizer/71962] error: ‘((& x) != 0u)’ is not a constant expression
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71962 --- Comment #1 from Jakub Jelinek --- The thing is that -fsanitize=null (and a couple of other sanitizers) imply -fno-delete-null-pointer-checks, as it doesn't want all the checks it adds removed and fold obviously doesn't fold != NULL with -fno-delete-null-pointer-checks. The testcase fails the same with -fno-delete-null-pointer-checks instead of -fsanitize=undefined. Not sure what can be done here though? Either change all places that check flag_delete_null_pointer_checks to use some complex predicate and not change flag_delete_null_pointer_checks in if (opts->x_flag_sanitize & (SANITIZE_NULL | SANITIZE_NONNULL_ATTRIBUTE | SANITIZE_RETURNS_NONNULL_ATTRIBUTE)) opts->x_flag_delete_null_pointer_checks = 0; and during constexpr evaluation temporarily clear flag_sanitize, or something similar.