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 via email to