GCC different actual amount of memory allocation then i assigned to variables in program

0
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
        int value = 5;
        char buffer_one[9], buffer_two[9];

        strcpy(buffer_one, "one"); /* Put "one" into buffer_one. */
        strcpy(buffer_two, "two"); /* Put "two" into buffer_two. */

        printf("[BEFORE] buffer_two is at %p and contains \'%s\'\n", buffer_two, buffer_two);
        printf("[BEFORE] buffer_one is at %p and contains \'%s\'\n", buffer_one, buffer_one);
        printf("[BEFORE] value is at %p and is %d (0x%08x)\n", &value, value, value);
        printf("\n[STRCPY] copying %d bytes into buffer_two\n\n", strlen(argv[1]));

        strcpy(buffer_two, argv[1]); /* Copy first argument into buffer_two. */

        printf("[AFTER] buffer_two is at %p and contains \'%s\'\n", buffer_two, buffer_two);
        printf("[AFTER] buffer_one is at %p and contains \'%s\'\n", buffer_one, buffer_one);
        printf("[AFTER] value is at %p and is %d (0x%08x)\n", &value, value, value);
}

Output 1 :- I am giving 24 bytes of data to buffer_two variable and it is accepting it, however i assigned only 9-bytes of memory to buffer_two. And, why the address difference between buffer_two and buffer_one is 16 instead of 9.

ubuntus@ubuntus:~$ ./sample2 123456789012345678901234
[BEFORE] buffer_two is at 0x7ffe29136510 and contains 'two'
[BEFORE] buffer_one is at 0x7ffe29136500 and contains 'one'
[BEFORE] value is at 0x7ffe291364fc and is 5 (0x00000005)

[STRCPY] copying 24 bytes into buffer_two

[AFTER] buffer_two is at 0x7ffe29136510 and contains '123456789012345678901234'
[AFTER] buffer_one is at 0x7ffe29136500 and contains 'one'
[AFTER] value is at 0x7ffe291364fc and is 5 (0x00000005)

Output 2:-

ubuntus@ubuntus:~$ ./sample2 1234567890123456789012345
[BEFORE] buffer_two is at 0x7fff51549fe0 and contains 'two'
[BEFORE] buffer_one is at 0x7fff51549fd0 and contains 'one'
[BEFORE] value is at 0x7fff51549fcc and is 5 (0x00000005)

[STRCPY] copying 25 bytes into buffer_two

[AFTER] buffer_two is at 0x7fff51549fe0 and contains '1234567890123456789012345'
[AFTER] buffer_one is at 0x7fff51549fd0 and contains 'one'
[AFTER] value is at 0x7fff51549fcc and is 5 (0x00000005)
*** stack smashing detected ***: ./sample2 terminated
Aborted (core dumped)
c
gcc
gdb
binaryfiles
asked on Stack Overflow Jul 23, 2018 by Jaat • edited Jul 23, 2018 by Priya

1 Answer

1

Regarding this:

I am giving 24 bytes of data to buffer_two variable and it is accepting it

As already mentioned in the comments, this is a typical case of Undefined Behavior. C doesn't put checks on the boundaries of the array and it is left to the programmer to take care of it. If the boundary of the array is breached, anything can happen. You could accidentally write on the data of other variables or the program can crash or sometimes it may work (as it happened in your case).

When I ran your code, this was the output I got:

nandan@debian:~$ ./sample 123456789012345678901234 

    [BEFORE] buffer_two is at 0x7ffc2db1e19a and contains 'two'
    [BEFORE] buffer_one is at 0x7ffc2db1e1a3 and contains 'one'
    [BEFORE] value is at 0x7ffc2db1e1ac and is 5 (0x00000005)

    [STRCPY] copying 24 bytes into buffer_two

    [AFTER] buffer_two is at 0x7ffc2db1e19a and contains '1234567890123456789012345'
    [AFTER] buffer_one is at 0x7ffc2db1e1a3 and contains '0123456789012345'
    [AFTER] value is at 0x7ffc2db1e1ac and is 842084409 (0x32313039)

Many things can be noticed when we compare the outputs of mine and yours.

First, both of our programs didn't crash. Hurray!

Second, notice that in your output, buffer_one was allocated the memory first and then buffer_two was allocated (hence, buffer_two has higher address than buffer_one. That's obvious right? They are allocated in the order of which they are declared in the code). But, in my case, buffer_two was allocated first and then buffer_one was allocated (notice that, in my output, buffer_two has lower address than buffer_one). So, why did this happen in my case? Well, it is compiler-dependent feature. The order in which the automatic variables are allocated on the stack is entirely left to the compiler. I don't know why exactly this happened but I guess it has something to do with optimization. Here for more.

Third, since in my case buffer_two has lower address than buffer_one, an Undefined behavior can be noticed when copying the 24-byte string in the 9-byte buffer_two. buffer_one is getting overwritten!! [AFTER] buffer_one is at 0x7ffc2db1e1a3 and contains '0123456789012345'.

Now, Regarding this:

however i assigned only 9-bytes of memory to buffer_two. And, why the address difference between buffer_two and buffer_one is 16 instead of 9.

Notice that, in my case, exact 9 bytes are allocated for buffer_one and buffer_two by my GCC.

Normally, GCC tries to keep your automatic variables aligned to 2^n bytes on the stack so as to improve the performance even though it sacrifices few bytes for it. By default n=4. So, 16 (2^4) bytes are allocated in your case for a 9-byte array and the remaining 7 bytes are padded with null characters.

You can use -mpreferred-stack-boundary flag in GCC to change this alignment. Read the docs or search for other questions on SO on the usage of that flag.

answered on Stack Overflow Jul 23, 2018 by Nandan Desai

User contributions licensed under CC BY-SA 3.0