Search code examples
c++g++undefined-behaviorsanitizer

Why doesn't -fsanitize=undefined pick up on (what I think is) UB?


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! :)


Solution

  • 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.