auto vec = std::vector<int>({1, 2, 3});
std::cout << *vec.end() << std::endl;
Here is some simple code that I believe to be UB. However, compiling this with the following steps:
g++ -std=c++23 -Wall -Wextra -g -fsanitize=undefined -o ./target/src/main.cpp.o src/main.cpp
g++ -fsanitize=undefined -o ./target/main ./target/src/main.cpp.o
Results in a perfectly happy sanitizer and an output of 0
!
I thought that the way contiguous collection iterators worked in C++ was that they pointed to the first out-of-bounds memory location.
{1, 2, 3} ?, ?, ?, ...
^ begin ^ end
My thinking is that the creation of any arbitrary pointer is technically safe, but the dereferencing of this pointer is what is unsafe, so this is a fine method of creating iterators. Of course, this is very unlikely to be something wrong with fsanitize
so let me know where I'm going wrong! :)
You are right; this is undefined behavior, and some sanitizer should pick up on it. Clang's UBSan detects it, and GCC's ASan does:
#include <iostream>
#include <vector>
int main() {
auto vec = std::vector<int>({1, 2, 3});
std::cout << *vec.end() << std::endl;
}
This produces the error:
==1==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x50200000001c at pc 0x00000040153e bp 0x7ffcd56c77c0 sp 0x7ffcd56c77b8
READ of size 4 at 0x50200000001c thread T0
#0 0x40153d in main /app/example.cpp:6
#1 0x7faa3ef48082 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x24082) (BuildId: 1878e6b475720c7c51969e69ab2d276fae6d1dee)
#2 0x40120d in _start (/app/output.s+0x40120d) (BuildId: b859bb13bb93e5af8f52cb0ac4198ad4bf2002c3)
See live example at Compiler Explorer
In general, you should typically use -fsanitize=address,undefined
to catch a wider range of errors. Alternatively, use external tools like valgrind.