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] New: Add basic_string throw logic_error when assigned a nullptr
Date: Wed, 22 Feb 2023 14:31:43 +0000	[thread overview]
Message-ID: <bug-108886-4@http.gcc.gnu.org/bugzilla/> (raw)

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

            Bug ID: 108886
           Summary: Add basic_string throw logic_error when assigned a
                    nullptr
           Product: gcc
           Version: 12.2.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: libstdc++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: jg at jguk dot org
  Target Milestone: ---

Checked this on godbolt trunk today.
https://godbolt.org/z/6xxEc85c9

basic_string.h will throw a logic_error at runtime if a nullptr gets through to
the basic_string() constructor. But assignment doesn't throw a logic_error, it
gives SEGV.

Could I suggest two improvements please:

1) Add throw logic_error to basic_string.h:815 if pointer is nullptr.
      _GLIBCXX20_CONSTEXPR
      basic_string&
      operator=(const _CharT* __s)
      { return this->assign(__s); }

2) Add throw logic_error to basic_string:1647

_GLIBCXX20_CONSTEXPR
      basic_string&
      assign(const _CharT* __s)
      {
        __glibcxx_requires_string(__s);
        return _M_replace(size_type(0), this->size(), __s,
                          traits_type::length(__s));
      }


This is what basic_string.h has for normal construction
std::__throw_logic_error(__N("basic_string: "
                                       "construction from null is not valid"));



The basic_string assignment = uses char_traits to check the length using
__builtin_strlen and then SEGV.

I believe it is the actual __builtin_strlen that does the nullptr dereference.

GDB output
Core was generated by `./str2'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  __strlen_sse2 () at ../sysdeps/x86_64/multiarch/strlen-sse2.S:142
142     ../sysdeps/x86_64/multiarch/strlen-sse2.S: No such file or directory.
(gdb) bt
#0  __strlen_sse2 () at ../sysdeps/x86_64/multiarch/strlen-sse2.S:142
#1  0x000055ca94a8327e in std::char_traits<char>::length (__s=0x0) at
/usr/include/c++/12/bits/char_traits.h:395
#2  std::__cxx11::basic_string<char, std::char_traits<char>,
std::allocator<char> >::assign (__s=0x0, this=0x7fff26f1e370) at
/usr/include/c++/12/bits/basic_string.h:1647
#3  std::__cxx11::basic_string<char, std::char_traits<char>,
std::allocator<char> >::operator= (__s=0x0, this=0x7fff26f1e370) at
/usr/include/c++/12/bits/basic_string.h:815
#4  make_string (str=str@entry=0x0, out_string="") at str2.cpp:8
#5  0x000055ca94a832d9 in main () at str2.cpp:15






Therefore I propose

1) Add throw logic_error to basic_string.h:815 if pointer is nullptr.
      _GLIBCXX20_CONSTEXPR
      basic_string&
      operator=(const _CharT* __s)
      { return this->assign(__s); }

2) Add throw logic_error to basic_string:1647

_GLIBCXX20_CONSTEXPR
      basic_string&
      assign(const _CharT* __s)
      {
        __glibcxx_requires_string(__s);
        return _M_replace(size_type(0), this->size(), __s,
                          traits_type::length(__s));
      }

3) I don't think char_traits allows exceptions, so I can't suggest a
logic_error
Is there anything else that could be added here? Maybe just a
_GLIBCXX_DEBUG_PEDASSERT ? strlen() doesn't have a way to even set errno and
return -1


This is what char_traits.h has


/usr/include/c++/12/bits/char_traits.h:395:25: runtime error: null pointer
passed as argument 1, which is declared to never be null
AddressSanitizer:DEADLYSIGNAL

/usr/include/c++/12/bits/char_traits.h

      static _GLIBCXX17_CONSTEXPR size_t
      length(const char_type* __s)
      {
#if __cplusplus >= 201703L
        if (std::__is_constant_evaluated())
          return __gnu_cxx::char_traits<char_type>::length(__s);
#endif
        return __builtin_strlen(__s);
      }






Example:

#include <string>
#include <cstdio>

void make_string(const char * const str, std::string & out_string)
{
    out_string = str;
}

int main()
{
    const char * a = NULL;
    std::string str;
    make_string(a, str);
    printf("%s\n", str.c_str());
}

             reply	other threads:[~2023-02-22 14:31 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-02-22 14:31 jg at jguk dot org [this message]
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
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@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).