From: Nathaniel Shead Date: Sun, 17 Dec 2023 01:46:02 +0000 (+1100) Subject: c++: Check null pointer deref when calling memfn in constexpr [PR102420] X-Git-Tag: basepoints/gcc-15~3417 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=5ba949c096f5250aa4efb94fb7c94d1304c1bf39;p=thirdparty%2Fgcc.git c++: Check null pointer deref when calling memfn in constexpr [PR102420] 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 --- diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index 051f73fb73f8..eff43a42353b 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -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 index 000000000000..dde9416d86fd --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-memfn2.C @@ -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" }