std::string 从 char 数组调用 strlen 的子范围构造
std::string constructed from subrange of char array calls strlen
类似于
密码是
#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;
}
执行以地址清理器抱怨 strlen
的 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)
我希望 std::string s{buf, 2, 3};
调用具有已知边界的构造函数重载(从 2 开始,长度为 3)。为什么调用 strlen()
?使用了哪个重载?
Check cpp insights。这是查看重载解析期间使用的内容的好工具。
它生成这个:
#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;
}
清理后使其更具可读性:
#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;
}
因此请注意,buf
首先转换为 std::string
,此转换需要 strlen
。由于您的数组不包含终止零缓冲区溢出。
HolyBlackCat 的 answer and Marek R's 解释了为什么它是错误的。这是使用 (pointer, count) 构造函数的解决方案:
std::string s{buf + 2, 3};
类似于
密码是
#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;
}
执行以地址清理器抱怨 strlen
的 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)
我希望 std::string s{buf, 2, 3};
调用具有已知边界的构造函数重载(从 2 开始,长度为 3)。为什么调用 strlen()
?使用了哪个重载?
Check cpp insights。这是查看重载解析期间使用的内容的好工具。
它生成这个:
#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;
}
清理后使其更具可读性:
#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;
}
因此请注意,buf
首先转换为 std::string
,此转换需要 strlen
。由于您的数组不包含终止零缓冲区溢出。
HolyBlackCat 的 answer and Marek R's
std::string s{buf + 2, 3};