Search code examples
cpointersmallocstrcpy

Understanding malloc with char pointers and strcpy


I want to write a simple program and I want it to fail to understand strcpy and proper memory management but it still executes. I am trying to dynamically allocate memory (with malloc) for a string enough for only 3 (or anything less than the source) chars to be used as the destination and allocate less memory (or chars) than the string array of the source which is allocated on the stack (string of 10 chars). It copies and prints the content no matter how I define the memory allocation. what's the mistake here?

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main()
{
    char *ch = NULL;
    char name[10] = "something";
    ch = (char*)malloc(3 * sizeof(char));
    strcpy(ch, name);
    
    printf("%s\n", name);
    free(ch);
    ch = NULL;
}

Solution

  • The behaviour of writing array out of bounds is undefined. On my computer, without optimization:

    % gcc overflow.c
    % ./a.out    
    something
    

    and with optimization enabled

    % gcc -O3 overflow.c
    In file included from /usr/include/string.h:495,
                     from overflow.c:2:
    In function ‘strcpy’,
        inlined from ‘main’ at overflow.c:10:5:
    /usr/include/x86_64-linux-gnu/bits/string_fortified.h:90:10: warning: 
         ‘__builtin___memcpy_chk’ writing 10 bytes into a region of size 3
         overflows the destination [-Wstringop-overflow=]
       90 |   return __builtin___strcpy_chk (__dest, __src, __bos (__dest));
          |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    % ./a.out       
    *** buffer overflow detected ***: terminated
    [2]    240741 abort (core dumped)  ./a.out
    

    The reason is that with optimization GCC will actually propagate the array sizes and will produce machine code equivalent to

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    int main(void)
    {
        char name[10] = "something";
        char *ch = malloc(3);
        __memcpy_chk(ch, name, sizeof name, 3);
        puts(name);
        free(ch);
    }
    

    and __memcpy_chk will check the length of the destination buffer, and since it is exceeded, the program will abort at runtime.

    Always when developing, remember to test your code optimizations enabled too!