Search code examples
c++memory-managementmallocdynamic-memory-allocation

How to detect invalid reads (using code not valgrind)


Say you allocated a pointer to char like this

char *ptr = malloc(10 * sizeof(char))

If this ptr is passed to another function without passing its size, can we detect that ptr[10] is reading memory that does not belong to this pointer.

I know that if I used valgrind I will get and invalid read, but I want to write a code to throw an exception when this happens.


Solution

  • One possible way to achieve this is using page guards. This is expensive though but will allow you to get an exception when it happens.

    #include <cstdint>
    #include <cstdio>
    #include <sys/mman.h>
    #include <unistd.h>
    #include <errno.h>
    #include <string.h>
    #include <signal.h>
    #include <exception>
    #include <stdexcept>
    
    void doit( char* p ) {
        for ( int j=0; j<20; ++j ) {
            fprintf( stderr, "%d %d\n", j, int(p[j]) );
        }
    }
    
    void trapped(int) {
        throw std::runtime_error("Memory violation");
    }
    
    int main() {
        signal( SIGSEGV, trapped );
        int pgsize = getpagesize();
        fprintf( stderr, "Page size: %d\n", pgsize );
        uint8_t* ptr = (uint8_t*)mmap( NULL, 2*pgsize, PROT_READ|PROT_WRITE, 
        MAP_PRIVATE|MAP_ANONYMOUS, -1, 0 );
        if ( ptr == MAP_FAILED ) {
            fprintf(stderr, "Memory map failed: %s\n", strerror(errno) );
            return 1;
        }
        int res = mprotect(ptr+pgsize,pgsize,PROT_NONE);
        if ( res!=0 ) {
            fprintf(stderr, "Failed to protect memory\n");
            return 2;
        }
    
        char* s = (char*)(ptr + pgsize - 10);
    
        try {
            doit( s );
        }
        catch( std::exception& ex ) {
            fprintf( stderr, "Caught exception:%s\n", ex.what());
        }
    }
    

    Godbolt: https://godbolt.org/z/oaMoTnaPo

    The result of the run is:

    Page size: 4096
    0 0
    1 0
    2 0
    3 0
    4 0
    5 0
    6 0
    7 0
    8 0
    9 0
    Caught exception:Memory violation