Search code examples
c++visual-c++buffer-overflowaddress-sanitizer

Address Sanitizer with Visual C++: ignore read buffer overflows while still catching write buffer overflows


Consider the following example:

int main()
{
    char* p = new char[10];
    
    srand(p[11]); // heap buffer overflow - read

    p[11] = rand(); // heap buffer overflow - write
}

I want ASan not to flag heap buffer overflow - read for now, while still flagging heap buffer overflow - write.

The reason I want this is to concentrate on more dangerous errors for now. Read overflow either crash immediately or don't have consequences, whereas write overflow may cause corruption that would trigger elsewhere later. For some small overflows, even immediate crash is excluded. So sure I'd look into read overflows too, but later.

Is there a way to accomplish this?


Solution

  • There are two directions to achieve this.

    1. Continue after the error is triggered

    To continue after an error, -fsanitize-recover=address option should be used. From FAQ:

    Q: Can AddressSanitizer continue running after reporting first error?

    A: Yes it can, AddressSanitizer has recently got continue-after-error mode. This is somewhat experimental so may not yet be as reliable as default setting (and not as timely supported). Also keep in mind that errors after the first one may actually be spurious. To enable continue-after-error, compile with -fsanitize-recover=address and then run your code with ASAN_OPTIONS=halt_on_error=0.

    This option is not yet supported by MSVC compiler. There's an issue to add it.

    If it would have worked, a custom handler could have been installed that would inspect whether it is read or write error, ignore read error, and report write error.

    2. Don't instrument read errors

    As @yugr pointed out, there's -mllvm -asan-instrument-reads=false option to achieve this. But this option is also not supported by MSVC compiler.

    But there's still a way to avoid compiler instrumentation in some places. It is __declspec(no_sanitize_address). So the goal could be achieved by isolating known read errors, like this:

    __declspec(no_sanitize_address)
    void isolate_read_heap_buffer_overflow(char* p)
    {
        srand(p[11]); // heap buffer overflow - read
    }
    
    int main()
    {
        char* p = new char[10];
        
        isolate_read_heap_buffer_overflow(p);
    
        p[11] = rand(); // heap buffer overflow - write
    
        return 0;
    }
    

    Other better alternative

    There's also clang-cl compiler, it is actually Clang that supports Visual C++ semantics. Visual Studio installer installs it. So if a project can be retargeted to use Clang, this would open all Address Sanitizer features usable in Clang. Unfortunately, retargeting some legacy code base may be a long task.