Search code examples
c++cpointersmemmove

Heap corruption from memory allocation using malloc: why did it happen?


Ok, I was trying to implement memmove just as a programming exercise, and I get a memory access violation in the memmove function when I try to use malloc. Here is the function:

//Start

void* MYmemmove (void* destination, const void* source, size_t num) { 

    int* midbuf = (int *) malloc(num); // This is where the access violation happens.
    int* refdes = (int *) destination; // A pointer to destination, except it is casted to int*
    int* refsrc = (int *) source; // Same, except with source
    for (int i = 0;num >= i;i++) { 
        midbuf[i] = *(refsrc + i); // Copy source to midbuf
    }
    for (int i = 0;num >= i;i++) { 
        refdes[i] = *(midbuf + i); // Copy midbuf to destination
    } 
    free(midbuf); // free midbuf 
    refdes = NULL; // Make refdes not point to destination anymore
    refsrc = NULL; // Make refsrc not point to source anymore
    return destination;
}

By the way, I am sort of a newbie to pointers, so don't be suprised if there is some mistakes. What am I doing wrong?


Solution

  • Please be careful with the other suggestions! The answer depends on how your memmove will be used. The other answers state you should change your malloc call to account for the size of an int. However, if your memmove function will be used to mean "move this number of bytes" then the implementation would be wrong. I would instead go about using char* as that takes care of several problems in one go.

    Also, an int is typically 4 bytes, and char is typically 1 byte. If the void* address you receive is not word aligned (not a multiple of 4 bytes), you will have a problem: To copy an int that is not word aligned you will have to do more than one read and expensive bit masking. This is inefficient.

    Finally, the memory access violation happened because you were incrementing your midbuf int pointer each time, and moving forward 4 bytes at a time. However, you only allocated num bytes, and thus would eventually try to access past the end of the allocated region.

    /** Moves num bytes(!) from source to destination */
    void* MYmemmove (void* destination, const void* source, size_t num) { 
    
        // transfer buffer to account for memory aliasing
        // http://en.wikipedia.org/wiki/Aliasing_%28computing%29
        char * midbuf = (char *) malloc(num); // malloc allocates in bytes(!)
        char * refdes = (char *) destination;
        char * refsrc = (char *) source;
    
        for (int i = 0; i < num; i++) { 
            midbuf[i] = *(refsrc + i); // Copy source to midbuf
        }
    
        for (int i = 0; i < num; i++) { 
            refdes[i] = *(midbuf + i); // Copy midbuf to destination
        } 
    
        free(midbuf); // free midbuf
        // no need to set the pointers to NULL here.
        return destination;
    }
    

    By copying byte by byte, we avoid alignment issues, and cases where num itself could be not a multiple of 4 bytes (e.g. 3, so an int is too large for that move).