public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
From: "jg at jguk dot org" <gcc-bugzilla@gcc.gnu.org>
To: gcc-bugs@gcc.gnu.org
Subject: [Bug libstdc++/108886] Add basic_string throw logic_error when assigned a nullptr
Date: Sun, 12 Mar 2023 23:03:33 +0000	[thread overview]
Message-ID: <bug-108886-4-QDatYe7TsU@http.gcc.gnu.org/bugzilla/> (raw)
In-Reply-To: <bug-108886-4@http.gcc.gnu.org/bugzilla/>

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108886

--- Comment #4 from Jonny Grant <jg at jguk dot org> ---
(In reply to Jonathan Wakely from comment #3)
> (In reply to Jonny Grant from comment #2)
> > I was taught to validate parameters at University. Personally I always
> > follow defensive programming approaches to avoid crashes.
>
> So stop passing null to these functions then :-)

Feels like we have a different opinion.  I know you know more about C++ than
me.

Defensive programming is carefulness in libraries too; particularly interfaces.
The C++ standard group have a paper "P2698R0 Unconditional termination is a
serious problem" you may have seen.

What I see is that the nullptr keyword is part of the language, and is used in
many places to indicate an object is not available. For me, a function that
requires a valid pointer, should check for the nullptr constant. The crash is
the code that de-references the nullptr because it requires a valid pointer. Of
course I would like all code to check for nullptr before passing to
std::string, and I would do those checks myself as well :-)

A nullptr is different from passing a use-after-free pointer.

Wrapping std::string is the workaround, as it doesn't always throw logic_error
for the nullptr constant.

It would just use up time when the STL implementation could handle it, as need
to check every method on std::string in the codebase to check for nullptr,
because it doesn't throw logic_error say for assign or other operators.

> > So I would check
> > parameters on all interface methods and operators. I would rely on the
> > compiler to remove any unnecessary duplicate sanity checks.
>
> That doesn't necessarily work when the member functions are separately
> compiled, as with most std::string member functions.

Ok, that's a shame. If it showed up in some performance measurements it could
be adjusted.

> > > What would be the point of _GLIBCXX_DEBUG_PEDASSERT when there's already a
> > > debug assertion there? Compiling with _GLIBCXX_DEBUG will already abort.
> >
> > I don't see a debug assertion for _GLIBCXX_DEBUG_PEDASSERT  could you point
> > out the file and line number to me please.
>
> You already quoted it in your comment 0 above, it's right there in
> assign(const _CharT*)!
>
>       basic_string&
>       assign(const _CharT* __s)
>       {
> 	__glibcxx_requires_string(__s);

Ok I see. Thank you for that example __glibcxx_requires_string is a macro that
compiles down to _GLIBCXX_DEBUG_PEDASSERT. I wonder why it wasn't written in
capitals as __GLIBCXX_REQUIRES_STRING_ASSERT?

Anyway, it is good there are asserts that report nullptr issues at runtime.

> > Just compiled with -D_GLIBCXX_DEBUG but I don't get any abort, just the same
> > SEGV
> > https://godbolt.org/z/rjYG8Yrnh
>
> If you want a PEDASSERT to fire you need to actually request pedantic
> assertions.
>
> https://godbolt.org/z/874x18G1G
>
> /opt/compiler-explorer/gcc-trunk-20230227/include/c++/13.0.1/bits/
> basic_string.h:1645: constexpr std::__cxx11::basic_string<_CharT, _Traits,
> _Alloc>& std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::assign(const
> _CharT*) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc =
> std::allocator<char>]: Assertion '__s != nullptr' failed.
>
> I'm not persuaded to change anything here. The performance of string
> assignments is very important and adding an extra branch and throwing an
> exception isn't free.

It sounds like you know the implementation really well.

Personally on embedded systems I don't find the cost of checking for NULL an
issue. The 'throw' should not impact performance, as it is within the if() and
code shouldn't often throw, still better than SEGV! Maybe you have some
performance comparison statistics showing that a NULL check really impacts
performance? STL string heap allocations and actual memory read/write are the
biggest performance impact on performance in my experience on embedded.

I doubt all uses of std::string are performance intensive. For performance
critical code identified by a profiler I just re-write that function in C.
Usually graphics code.

There is what might be a performance issue, I don't know if anyone has
measured, _M_construct() appears to copy copies byte by byte in
basic_string.tcc:177 rather than using an optimized memcpy(). I've not measured
this myself.

  parent reply	other threads:[~2023-03-12 23:03 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-02-22 14:31 [Bug libstdc++/108886] New: " jg at jguk dot org
2023-02-22 15:57 ` [Bug libstdc++/108886] " redi at gcc dot gnu.org
2023-02-26 23:02 ` jg at jguk dot org
2023-02-27  9:23 ` redi at gcc dot gnu.org
2023-03-12 23:03 ` jg at jguk dot org [this message]
2023-03-13 10:20 ` redi at gcc dot gnu.org
2023-03-13 10:26 ` redi at gcc dot gnu.org

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=bug-108886-4-QDatYe7TsU@http.gcc.gnu.org/bugzilla/ \
    --to=gcc-bugzilla@gcc.gnu.org \
    --cc=gcc-bugs@gcc.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).