]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: Check null pointer deref when calling memfn in constexpr [PR102420]
authorNathaniel Shead <nathanieloshead@gmail.com>
Sun, 17 Dec 2023 01:46:02 +0000 (12:46 +1100)
committerNathaniel Shead <nathanieloshead@gmail.com>
Tue, 19 Dec 2023 21:18:56 +0000 (08:18 +1100)
Calling a non-static member function on a null pointer is undefined
behaviour (see [expr.ref] p8) and should error in constant evaluation,
even if the 'this' pointer is never actually accessed within that
function.

One catch is that currently, the function pointer conversion operator
for lambdas passes a null pointer as the 'this' pointer to the
underlying 'operator()', so for now we ignore such calls.

PR c++/102420

gcc/cp/ChangeLog:

* constexpr.cc (cxx_bind_parameters_in_call): Check for calling
non-static member functions with a null pointer.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/constexpr-memfn2.C: New test.

Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com>
gcc/cp/constexpr.cc
gcc/testsuite/g++.dg/cpp0x/constexpr-memfn2.C [new file with mode: 0644]

index 051f73fb73f8c011575e4ba0805b7a169d1983f4..eff43a42353bb42d6d9e510d5b1ad39c5f582042 100644 (file)
@@ -1884,6 +1884,20 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t, tree fun,
         TARGET_EXPR, and use its CONSTRUCTOR as the value of the parm.  */
       arg = cxx_eval_constant_expression (ctx, x, vc_prvalue,
                                          non_constant_p, overflow_p);
+      /* Check we aren't dereferencing a null pointer when calling a non-static
+        member function, which is undefined behaviour.  */
+      if (i == 0 && DECL_NONSTATIC_MEMBER_FUNCTION_P (fun)
+         && integer_zerop (arg)
+         /* But ignore calls from within compiler-generated code, to handle
+            cases like lambda function pointer conversion operator thunks
+            which pass NULL as the 'this' pointer.  */
+         && !(TREE_CODE (t) == CALL_EXPR && CALL_FROM_THUNK_P (t)))
+       {
+         if (!ctx->quiet)
+           error_at (cp_expr_loc_or_input_loc (x),
+                     "dereferencing a null pointer");
+         *non_constant_p = true;
+       }
       /* Don't VERIFY_CONSTANT here.  */
       if (*non_constant_p && ctx->quiet)
        break;
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-memfn2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-memfn2.C
new file mode 100644 (file)
index 0000000..dde9416
--- /dev/null
@@ -0,0 +1,10 @@
+// PR c++/102420
+// { dg-do compile { target c++11 } }
+
+struct X {
+  constexpr int f() { return 0; }
+};
+constexpr int g(X* x) {
+  return x->f();  // { dg-error "dereferencing a null pointer" }
+}
+constexpr int t = g(nullptr);  // { dg-message "in .constexpr. expansion" }