如果 `size()` 为 0,如何从 `pop_back()` 得到错误?
How do I get an error from `pop_back()` if `size()` is 0?
我正在向一位同事解释为什么我们要对他们进行消毒剂小测试。他询问了关于多次弹出向量的问题,如果它是一个异常,断言,UB 以及哪个消毒剂捕获它
看来 NONE 抓住了他们。如果你在弹出太多次后调用 back()
,地址和内存将会出现,但如果你弹出并执行 size()
,由于包装
,你会得到一个很大的无效值
有什么方法可以在弹出次数过多时获得断言或异常或运行时终止?我真的认为没有消毒剂的调试版本会捕捉到这一点(有断言或异常)
我使用 clang sanitizer,但使用 gcc 构建选项也会有帮助
libstdc++ 和 libc++ 都有带断言的“调试模式”,可以使用以下方式启用:
-D_GLIBCXX_DEBUG
用于 libstdc++
-D_LIBCPP_DEBUG
用于 libc++
-fsanitize=undefined
似乎也能捕捉到它,但错误消息更加神秘。
消毒剂可能需要一些注释才能在库类型上做好工作。 g++ -fsanitize=address -D_GLIBCXX_SANITIZE_VECTOR
(documentation), clang++ -stdlib=libc++ -fsanitize=address
or clang++ -stdlib=libstdc++ -fsanitize=address -D_GLIBCXX_SANITIZE_VECTOR -D__SANITIZE_ADDRESS__
(the need for this last macro is a bug) 全部检测到问题并打印消息
=================================================================
==12312==ERROR: AddressSanitizer: bad parameters to __sanitizer_annotate_contiguous_container:
beg : 0x602000000010
end : 0x602000000014
old_mid : 0x602000000010
new_mid : 0x60200000000c
#0 0x7f6a9db3b707 in __sanitizer_annotate_contiguous_container ../../../../src/libsanitizer/asan/asan_poisoning.cpp:362
#1 0x55b9dcd1fc41 in std::_Vector_base<int, std::allocator<int> >::_Vector_impl::_Asan<std::allocator<int> >::_S_adjust(std::_Vector_base<int, std::allocator<int> >::_Vector_impl&, int*, int*) (/tmp/a.out+0x1c41)
#2 0x55b9dcd1fb66 in std::_Vector_base<int, std::allocator<int> >::_Vector_impl::_Asan<std::allocator<int> >::_S_shrink(std::_Vector_base<int, std::allocator<int> >::_Vector_impl&, unsigned long) (/tmp/a.out+0x1b66)
#3 0x55b9dcd1f6c4 in std::vector<int, std::allocator<int> >::pop_back() (/tmp/a.out+0x16c4)
#4 0x55b9dcd1f36d in main (/tmp/a.out+0x136d)
#5 0x7f6a9d57fe49 in __libc_start_main ../csu/libc-start.c:314
#6 0x55b9dcd1f199 in _start (/tmp/a.out+0x1199)
SUMMARY: AddressSanitizer: bad-__sanitizer_annotate_contiguous_container ../../../../src/libsanitizer/asan/asan_poisoning.cpp:362 in __sanitizer_annotate_contiguous_container
==12312==ABORTING
请注意,对于这种情况,不需要像消毒剂那样复杂的东西,正如另一个答案中提到的,图书馆通常有调试模式。例如对于 libstdc++,定义 _GLIBCXX_DEBUG
启用完整调试模式(ABI 与正常模式不兼容)
/usr/include/c++/11/debug/vector:523:
In function:
void std::__debug::vector<_Tp, _Allocator>::pop_back() [with _Tp = int;
_Allocator = std::allocator<int>]
Error: attempt to access an element in an empty container.
Objects involved in the operation:
sequence "this" @ 0x0x7ffe20bf5f80 {
type = std::__debug::vector<int, std::allocator<int> >;
}
在定义 _GLIBCXX_ASSERTIONS
时启用更轻量级的断言并保留 ABI,但提供的错误信息较少
/usr/include/c++/11/bits/stl_vector.h:1227: void std::vector<_Tp, _Alloc>::pop_back() [with _Tp = int; _Alloc = std::allocator<int>]: Assertion '!this->empty()' failed.
并使用 libc++ 打印定义 _LIBCPP_DEBUG
/usr/lib/llvm-11/bin/../include/c++/v1/vector:1703: _LIBCPP_ASSERT '!empty()' failed. vector::pop_back called for empty vector
我正在向一位同事解释为什么我们要对他们进行消毒剂小测试。他询问了关于多次弹出向量的问题,如果它是一个异常,断言,UB 以及哪个消毒剂捕获它
看来 NONE 抓住了他们。如果你在弹出太多次后调用 back()
,地址和内存将会出现,但如果你弹出并执行 size()
,由于包装
有什么方法可以在弹出次数过多时获得断言或异常或运行时终止?我真的认为没有消毒剂的调试版本会捕捉到这一点(有断言或异常)
我使用 clang sanitizer,但使用 gcc 构建选项也会有帮助
libstdc++ 和 libc++ 都有带断言的“调试模式”,可以使用以下方式启用:
-D_GLIBCXX_DEBUG
用于 libstdc++-D_LIBCPP_DEBUG
用于 libc++
-fsanitize=undefined
似乎也能捕捉到它,但错误消息更加神秘。
消毒剂可能需要一些注释才能在库类型上做好工作。 g++ -fsanitize=address -D_GLIBCXX_SANITIZE_VECTOR
(documentation), clang++ -stdlib=libc++ -fsanitize=address
or clang++ -stdlib=libstdc++ -fsanitize=address -D_GLIBCXX_SANITIZE_VECTOR -D__SANITIZE_ADDRESS__
(the need for this last macro is a bug) 全部检测到问题并打印消息
=================================================================
==12312==ERROR: AddressSanitizer: bad parameters to __sanitizer_annotate_contiguous_container:
beg : 0x602000000010
end : 0x602000000014
old_mid : 0x602000000010
new_mid : 0x60200000000c
#0 0x7f6a9db3b707 in __sanitizer_annotate_contiguous_container ../../../../src/libsanitizer/asan/asan_poisoning.cpp:362
#1 0x55b9dcd1fc41 in std::_Vector_base<int, std::allocator<int> >::_Vector_impl::_Asan<std::allocator<int> >::_S_adjust(std::_Vector_base<int, std::allocator<int> >::_Vector_impl&, int*, int*) (/tmp/a.out+0x1c41)
#2 0x55b9dcd1fb66 in std::_Vector_base<int, std::allocator<int> >::_Vector_impl::_Asan<std::allocator<int> >::_S_shrink(std::_Vector_base<int, std::allocator<int> >::_Vector_impl&, unsigned long) (/tmp/a.out+0x1b66)
#3 0x55b9dcd1f6c4 in std::vector<int, std::allocator<int> >::pop_back() (/tmp/a.out+0x16c4)
#4 0x55b9dcd1f36d in main (/tmp/a.out+0x136d)
#5 0x7f6a9d57fe49 in __libc_start_main ../csu/libc-start.c:314
#6 0x55b9dcd1f199 in _start (/tmp/a.out+0x1199)
SUMMARY: AddressSanitizer: bad-__sanitizer_annotate_contiguous_container ../../../../src/libsanitizer/asan/asan_poisoning.cpp:362 in __sanitizer_annotate_contiguous_container
==12312==ABORTING
请注意,对于这种情况,不需要像消毒剂那样复杂的东西,正如另一个答案中提到的,图书馆通常有调试模式。例如对于 libstdc++,定义 _GLIBCXX_DEBUG
启用完整调试模式(ABI 与正常模式不兼容)
/usr/include/c++/11/debug/vector:523:
In function:
void std::__debug::vector<_Tp, _Allocator>::pop_back() [with _Tp = int;
_Allocator = std::allocator<int>]
Error: attempt to access an element in an empty container.
Objects involved in the operation:
sequence "this" @ 0x0x7ffe20bf5f80 {
type = std::__debug::vector<int, std::allocator<int> >;
}
在定义 _GLIBCXX_ASSERTIONS
时启用更轻量级的断言并保留 ABI,但提供的错误信息较少
/usr/include/c++/11/bits/stl_vector.h:1227: void std::vector<_Tp, _Alloc>::pop_back() [with _Tp = int; _Alloc = std::allocator<int>]: Assertion '!this->empty()' failed.
并使用 libc++ 打印定义 _LIBCPP_DEBUG
/usr/lib/llvm-11/bin/../include/c++/v1/vector:1703: _LIBCPP_ASSERT '!empty()' failed. vector::pop_back called for empty vector