It is similar to LeetCode C Convert char[] to string, throws AddressSanitizer: stack-buffer-overflow error
The code is
#include <string>
int main() {
char buf[10] = {6, 6, 6, 6, 6, 6, 6, 6, 6, 6};
std::string s{buf, 2, 3};
return 0;
}
Execution ends up with address sanitizer complaining about strlen's stack-buffer-overflow:
$ clang -g -fsanitize=address foo.cpp ; ./a.out
=================================================================
==1001715==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffd76b2510a at pc 0x00000042f029 bp 0x7ffd76b250b0 sp 0x7ffd76b24870
READ of size 23 at 0x7ffd76b2510a thread T0
#0 0x42f028 in strlen (/tmp/a.out 0x42f028)
#1 0x7fd6de786e9b in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) (/usr/lib/x86_64-linux-gnu/libstdc .so.6 0x145e9b)
#2 0x4c6cfe in main /tmp/foo.cpp:6:19
#3 0x7fd6de2d60b2 in __libc_start_main /build/glibc-eX1tMB/glibc-2.31/csu/../csu/libc-start.c:308:16
#4 0x41c3fd in _start (/tmp/a.out 0x41c3fd)
I'd expect that std::string s{buf, 2, 3}; calls a constructor overload with known bounds (start at 2, length is 3). Why is it calling strlen()? Which overload is used?
CodePudding user response:
Works as documented, see constructor (11).
(It works as if) first std::string_view is constructed from the passed array (which requires the strlen call), then .substr() is called on it (which throws if the second argument is out of range, and automatically clamps the third argument).
CodePudding user response:
HolyBlackCat's answer and Marek R's answer explain why it's wrong. Here is a solution using the (pointer, count) constructor:
std::string s{buf 2, 3};
CodePudding user response:
Check cpp insights. It is great tool to see what was used during overload resolution.
It generates this:
#include <string>
int main()
{
char buf[10] = {6, 6, 6, 6, 6, 6, 6, 6, 6, 6};
std::string s = std::basic_string<char, std::char_traits<char>, std::allocator<char> >{std::basic_string<char, std::char_traits<char>, std::allocator<char> >(buf, std::allocator<char>()), 2, 3};
return 0;
}
After cleaning up to make this more readable:
#include <string>
int main()
{
char buf[10] = {6, 6, 6, 6, 6, 6, 6, 6, 6, 6};
std::string s = std::string{std::string(buf), 2, 3};
return 0;
}
So note that buf is first converted to std::string and this conversion requires strlen. Since your array do not contain terminating zero buffer overflow happens.
