Re: std::string add nullptr attribute

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 2/20/23 11:54, Xi Ruoyao via Gcc-help wrote:
On Mon, 2023-02-20 at 10:37 +0000, Jonathan Wakely wrote:
On Mon, 20 Feb 2023 at 10:26, Xi Ruoyao <xry111@xxxxxxxxxxx> wrote:
On Sun, 2023-02-19 at 21:33 +0000, Jonny Grant wrote:

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.
Because the analyzer does not know the C++ standard disallows to use
NULL here.  It just analyzes the code.  The code in libstdc++ reads:

       basic_string(const _CharT* __s, const _Alloc& __a = _Alloc())
       : _M_dataplus(_M_local_data(), __a)
       {
         // NB: Not required, but considered best practice.
         if (__s == 0)
           std::__throw_logic_error(__N("basic_string: "
                                        "construction from null is not valid"));
         const _CharT* __end = __s + traits_type::length(__s);
         _M_construct(__s, __end, forward_iterator_tag());
       }

As you can see yourself, though the standard implies using NULL here is
a UB, libstdc++ does not really code a UB here.  So the analyzer will
consider the code absolutely valid.
Right, it's defined behaviour in libstdc++, as an extension.

Note that throwing a C++ exception is not a programming error.  It's
perfectly legal to catch the exception elsewhere.  It's also perfectly
legal not to catch it and treat it as an abort() (calling abort is also
not a programming error).


It's not pretty, but this wrapper catches NULL passed at compile time:

std::string make_std_string(const char * const str)
{
     // This line ensures: warning: dereference of NULL '0' [CWE-476]
[-Wanalyzer-null-dereference]
     char b = *str;
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.
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.

This is the kind of thing that makes me wonder why there isn't some kind of `__builtin_unreachable_do_not_optimize()` builtin that allows one to mark places in code that should never be reached and should thus be warned about if such a thing happens while at the same time never doing any optimization on the basis of the presence of the call.




[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux