From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-pf1-x42f.google.com (mail-pf1-x42f.google.com [IPv6:2607:f8b0:4864:20::42f]) by sourceware.org (Postfix) with ESMTPS id 313343858D38 for ; Tue, 19 Dec 2023 11:04:03 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 313343858D38 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gmail.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 313343858D38 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::42f ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1702983853; cv=none; b=Wuq/VPLo4eqr5VH98FhsgLkY/COoFonJF21OwSqWkvf5x9Yoce2hJLjR+FFASsJjE0KucotxSrqxDPs9Oe8gxtkIDM1NhOilrUKfs9jY/qR52PfTnyxk+6duwAYYEuXRlhhFSDrICNPrETmHdG6sLtcbSPIEcqJukrA2mgof0P0= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1702983853; c=relaxed/simple; bh=+IF62qoW21CexqjfIIpoowus5K9bsqn01A0PKwoPypA=; h=DKIM-Signature:Message-ID:Date:From:To:Subject:MIME-Version; b=ZYcSdfVtZ7vgwGbXkF4rRHO6u+05Fa73AX8L4PBwyWwnOpP02AqkX3kN5mRBJY1O3X8KNgRNhUpL7AzwFYZsAv9+X16MqKptL01tok37SuX7AHYVCvle1fi6SRJBeWuyGzFVPHHXg1K2IKrIy+4KUJJnxNFpQ43PT55VllZ50UU= ARC-Authentication-Results: i=1; server2.sourceware.org Received: by mail-pf1-x42f.google.com with SMTP id d2e1a72fcca58-6d7395ab92cso1249736b3a.2 for ; Tue, 19 Dec 2023 03:04:03 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1702983842; x=1703588642; darn=gcc.gnu.org; h=in-reply-to:content-disposition:mime-version:references:subject:cc :to:from:date:message-id:from:to:cc:subject:date:message-id:reply-to; bh=hyaMk8WPSOdPIVSOwhAubLAtjGvvkEB4JaQx1Qu+5Qg=; b=QMpm/8YjrKRyoUNkEKGKbhsXUOge3ukDX/tPpPVeCx4/i74CGF7MseR7np362l4RO2 KmNZuTJSMH/6+YS/IRfQQEi45rv7sEh2Um4QHGV9cb5FRAgNPbnjYqiy4rAYYn6+BeoB 2axNnC2mUwCL8prpFFbrw41DKpD4au8EnapLB/wu+hf+ppDuvHy0Ns6sW+GV+OwcWRUw xjU7QaRi3e35hsjO00g3XhHmUrdEeOd9iQqNAaigecMmmT2RXmM9mTokO8I/YzKDD21B LsuGXZcehysJaOIcND3hPONjdlyPP9MESxqasU+NmuHm7Uayk+huPzLiLLlV1e+BNjoE xsiw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1702983842; x=1703588642; h=in-reply-to:content-disposition:mime-version:references:subject:cc :to:from:date:message-id:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=hyaMk8WPSOdPIVSOwhAubLAtjGvvkEB4JaQx1Qu+5Qg=; b=IXfKEspVFrxnzcVJFW643u95/VcqafTDStgQ0JF9qkyg+MCZRpqEl0YMUg7nGjITEI kPHlbjtv9x2AsEJHH2LYOLdaLsuOpgh60SEA5J78mcMHCgDwoVglb4xZHKwMlVTvTO62 ujy3c5vQ/ojf4YESbEj9eJA5ZC2Gp9kUg08manBblzsAX8fb48LCqd0jMTtAkx1pSHbL dOnxRQI2q3m33o9nG6PnRjUzA2a3qOkr3wZOYbQAD1In96MWlfpLp+BqMZTU4Jcl42Ng 1FuKuRnmmpgL1O3ZN0QNfqkK/imRHZGeswGzF5Mj6rngjcezUIejclu6pHni3t7ot8Xr TRvg== X-Gm-Message-State: AOJu0YzI2NXb2CSQuTIsVUJo51munOAH+5h0nE4EdQTLmNxCDSP0kH2U MTi5ZIJLBtKH9pAK/6OEcEc= X-Google-Smtp-Source: AGHT+IHRxxc34xeMUk/SAxJLwMcHtCSK7wcnXHkJWhQ+lMAe4MDE15I9OTvgWD2UG+izculL4mD+4w== X-Received: by 2002:aa7:844c:0:b0:6d9:3b99:bbf0 with SMTP id r12-20020aa7844c000000b006d93b99bbf0mr239376pfn.5.1702983841778; Tue, 19 Dec 2023 03:04:01 -0800 (PST) Received: from Thaum. ([203.166.236.30]) by smtp.gmail.com with ESMTPSA id y15-20020aa7854f000000b006ce71af841bsm3013196pfn.4.2023.12.19.03.03.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 19 Dec 2023 03:04:01 -0800 (PST) Message-ID: <658178a1.a70a0220.dd1bf.7993@mx.google.com> X-Google-Original-Message-ID: Date: Tue, 19 Dec 2023 22:03:54 +1100 From: Nathaniel Shead To: Jason Merrill Cc: gcc-patches@gcc.gnu.org Subject: Re: [PATCH] c++: Check null pointer deref when calling memfn in constexpr [PR102420] References: <657f6d54.170a0220.7e557.2d05@mx.google.com> <4201c638-a4a8-42cc-9b91-321545c1b972@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <4201c638-a4a8-42cc-9b91-321545c1b972@redhat.com> X-Spam-Status: No, score=-12.1 required=5.0 tests=BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,FREEMAIL_FROM,GIT_PATCH_0,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_PASS,TXREP,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: On Mon, Dec 18, 2023 at 01:32:58PM -0500, Jason Merrill wrote: > On 12/17/23 16:51, Nathaniel Shead wrote: > > Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk? > > > > An alternative approach for the lambda issue would be to modify > > 'maybe_add_lambda_conv_op' to not pass a null pointer, but I wasn't sure > > what the best approach for that would be. > > I don't see a way to do that. Better IMO would have been for the C++ > committee to make the op() static in this case when we introduced static > lambdas, but that didn't happen, so we're left with this kludge. I was thinking about doing something morally equivalent to (decltype(lambda){}).operator()(args...); (using 'build_value_init' or something?) but... > > -- >8 -- > > > > 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 lambda 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 > > --- > > gcc/cp/constexpr.cc | 17 +++++++++++++++++ > > gcc/testsuite/g++.dg/cpp0x/constexpr-memfn2.C | 10 ++++++++++ > > 2 files changed, 27 insertions(+) > > create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-memfn2.C > > > > diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc > > index 051f73fb73f..9c18538b302 100644 > > --- a/gcc/cp/constexpr.cc > > +++ b/gcc/cp/constexpr.cc > > @@ -1884,6 +1884,23 @@ 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 the lambda function pointer > > + conversion thunk, since this currently passes a null pointer. */ > > + && !(TREE_CODE (t) == CALL_EXPR > > + && CALL_FROM_THUNK_P (t) > > We might just stop here, since any CALL_FROM_THUNK_P is compiler internals, > and we should have already complained (if appropriate) about calling the > thunk. OK either way. > ... for future proofing it seems reasonable to ignore calls from compiler-generated code regardless, thanks. > > + && ctx->call > > + && ctx->call->fundef > > + && lambda_static_thunk_p (ctx->call->fundef->decl))) > > + { > > + 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 00000000000..4749190a1f0 > > --- /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" } > This is what I'll push once bootstrap & regtest is finished (currently only passed 'RUNTESTFLAGS="dg.exp=constexpr*"'): -- >8 -- 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 --- gcc/cp/constexpr.cc | 14 ++++++++++++++ gcc/testsuite/g++.dg/cpp0x/constexpr-memfn2.C | 10 ++++++++++ 2 files changed, 24 insertions(+) create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-memfn2.C diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index 051f73fb73f..eff43a42353 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 00000000000..dde9416d86f --- /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" } -- 2.42.0