From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from xry111.site (xry111.site [89.208.246.23]) by sourceware.org (Postfix) with ESMTPS id C26F8383FE12 for ; Mon, 20 Feb 2023 10:54:41 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org C26F8383FE12 Authentication-Results: sourceware.org; dmarc=pass (p=reject dis=none) header.from=xry111.site Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=xry111.site DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=xry111.site; s=default; t=1676890480; bh=v7c9SEa8gY2hTTNNKLI/FGz1FUhxNbryCf9ueFqLGv8=; h=Subject:From:To:Cc:Date:In-Reply-To:References:From; b=B9qwS7RN7MNk3NbosIuMowPO2Y0NSUfdKR//1B03igVKELlqFKD19gdzxFQ0UkG+T gd+QN27cf0QMvKeNQH8M4ZciXWAfks0HiacbKhHPTVC7ChsHG0aKHAyvUn3CYMXe7o TsYZG+KvljFUKX46vQ9vltEpzXx5UzBxIYRL4lBg= Received: from [IPv6:240e:358:11cb:bb00:dc73:854d:832e:6] (unknown [IPv6:240e:358:11cb:bb00:dc73:854d:832e:6]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-256) server-signature ECDSA (P-384)) (Client did not present a certificate) (Authenticated sender: xry111@xry111.site) by xry111.site (Postfix) with ESMTPSA id 0DD1F65CC2; Mon, 20 Feb 2023 05:54:38 -0500 (EST) Message-ID: <1e62a6f51b748454abe88438f2040486722c5803.camel@xry111.site> Subject: Re: std::string add nullptr attribute From: Xi Ruoyao To: Jonathan Wakely Cc: Jonny Grant , gcc-help Date: Mon, 20 Feb 2023 18:54:35 +0800 In-Reply-To: References: <7e6e3bbf-0dac-0632-0e8f-372bd32a6923@jguk.org> <6e30ed8e6c6f08407a5b8259e73fd18a492376b5.camel@xry111.site> <8cfbab8b-07e8-7dab-c829-6de77cc8cf39@jguk.org> <6b530d67-723a-a0c9-15bc-12b7341653a7@jguk.org> <96f99315a6ffd3dd3919b23a4ade2597747a580a.camel@xry111.site> Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable User-Agent: Evolution 3.46.4 MIME-Version: 1.0 X-Spam-Status: No, score=0.4 required=5.0 tests=BAYES_00,BODY_8BITS,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,LIKELY_SPAM_FROM,SPF_HELO_PASS,SPF_PASS,TXREP autolearn=no 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, 2023-02-20 at 10:37 +0000, Jonathan Wakely wrote: > On Mon, 20 Feb 2023 at 10:26, Xi Ruoyao wrote: > >=20 > > On Sun, 2023-02-19 at 21:33 +0000, Jonny Grant wrote: > >=20 > > > I noticed -Wanalyzer-null-dereference reports at build time a > > > dereference. Also works if a function parameter. I wondered why > > > std::string isn't detected by this static analyser option. > >=20 > > Because the analyzer does not know the C++ standard disallows to use > > NULL here.=C2=A0 It just analyzes the code.=C2=A0 The code in libstdc++= reads: > >=20 > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 basic_string(const _CharT* __s, const _A= lloc& __a =3D _Alloc()) > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 : _M_dataplus(_M_local_data(), __a) > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 { > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 // NB: Not required, but con= sidered best practice. > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (__s =3D=3D 0) > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 std::__throw_log= ic_error(__N("basic_string: " > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0 "construction from null is not valid")); > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 const _CharT* __end =3D __s = + traits_type::length(__s); > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 _M_construct(__s, __end, for= ward_iterator_tag()); > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 } > >=20 > > As you can see yourself, though the standard implies using NULL here is > > a UB, libstdc++ does not really code a UB here.=C2=A0 So the analyzer w= ill > > consider the code absolutely valid. >=20 > Right, it's defined behaviour in libstdc++, as an extension. >=20 > >=20 > > Note that throwing a C++ exception is not a programming error.=C2=A0 It= 's > > perfectly legal to catch the exception elsewhere.=C2=A0 It's also perfe= ctly > > legal not to catch it and treat it as an abort() (calling abort is also > > not a programming error). > >=20 > >=20 > > > It's not pretty, but this wrapper catches NULL passed at compile time= : > > >=20 > > > std::string make_std_string(const char * const str) > > > { > > > =C2=A0=C2=A0=C2=A0 // This line ensures: warning: dereference of NULL= '0' [CWE-476] > > > [-Wanalyzer-null-dereference] > > > =C2=A0=C2=A0=C2=A0 char b =3D *str; > >=20 > > You are invoking an undefined behavior here if str is NULL, so it's > > essentially same as using a nonnull attribute for make_std_string. >=20 > And turned defined behaviour back into UB. The warning isn't reliable > (only if the compiler can see the point is null, which isn't the case > without optimization, or if the pointer comes from some non-inline > function), the exception is. You're trading guaranteed exception for a > not guaranteed warning and unbounded misoptimization due to undefined > behaviour. Well, maybe we should have a warning here with -Wpedantic (or something) as the standard does not allow people to pass NULL and expect a logic_error. But "deliberately making a UB to raise the warning" is not good. --=20 Xi Ruoyao School of Aerospace Science and Technology, Xidian University