3

I have been noticing that some of the programs that I write in C have not been working on my machine, but they works other others. So to test this, I wrote a simple program to test how the stack is pushing and popping local variables:

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

int main() {
    char char_test[10];
    int int_test = 0;

    strcpy(char_test, "Hello");
}

I then debugged this program and found that int_test had a higher memory address than char_test, even though, according to my knowledge, the first declared local variable is supposed to have a higher memory address. I then added two print functions that printed the memory addresses of the variables:

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

int main() {
    char char_test[10];
    int int_test = 0;

    strcpy(char_test, "Hello");

    printf("Address of char_test: 0x%x\n", &char_test);
    printf("Address of int_test: 0x%x\n", &int_test);
}

Now, the first local variable has a higher memory address than the second. Does printing the addresses change the ordering of the variables? Am I doing something wrong?

nope122
  • 31
  • 2
  • AFAIK, the arrangement of local variables in memory is not defined in C, so the compiler is free to set it up whichever way is convenient. Is there a reason you need to know this? – Charles Srstka Mar 19 '18 at 20:58
  • I trying to learn about buffer overflows, and the ordering of the variables appears to be very important. – nope122 Mar 19 '18 at 21:03
  • Compiler may have re-ordered variables (since it's allowed to do so, as everyone has noted) because the `int` needs to be on a particular boundary, whereas the `char` does not. For many modern 32-bit machines, the `int` needs to be on a 4-byte boundary, so putting the `char` array first would necessitate wasting 2 padding bytes. (Of course, the stack probably has to be aligned too, so those two bytes have to be wasted anyway!) – Dave M. Mar 19 '18 at 21:03
  • For playing with buffer overflows, you might try putting variables into a structure. I'm not sure the compiler has the same flexibility in re-ordering structure members, although it obviously must observe alignment restrictions. – Dave M. Mar 19 '18 at 21:04
  • Aside: printing a pointer value should be `printf("Address of int_test: 0x%p\n", (void*)&int_test);`. Also consider how your version would behave with a 64-bit pointer and a 32-bit `unsigned int`. – Weather Vane Mar 19 '18 at 21:07
  • I still have a question as to why the ordering changed because I added the print functions. – nope122 Mar 19 '18 at 21:44
  • Better ask the compiler authors. Perhaps they had reasons, or thought it doesn't matter. It only matters if you want to the break the code. Perhaps they do it randomly, to fox stack smashers. – Weather Vane Mar 19 '18 at 21:58

3 Answers3

2

Sequential requirement to which you are referring is for members of structs. There is no requirement for a compiler to order local variables one way or the other. In fact, there is no a requirement for a compiler to use stack for its automatic variables, or even to allocate them at all, if it could get away with it.

In your example, it looks like the compiler did just that: since int_test is not used, the compiler pretended that it does not exist. Once you started using it by taking its address, the compiler was forced to allocate it. It happened to allocate the variable ahead of char_test, but it is not under an obligation to do so.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
2

The ordering of variables in memory (whether they're local or global) is of no concern to any reasonable program.

The behavior of already-buggy programs can of course depend on relative proximity of variables (especially arrays that are being overflowed), but that's obviously because the programs are, well, already buggy.

And, no, there are no rules which govern, no guarantees about how, your compiler (and linker) will assign addresses.

Steve Summit
  • 45,437
  • 7
  • 70
  • 103
  • So its completely impossible to predict how the variables will be ordered? – nope122 Mar 19 '18 at 21:21
  • 1
    @nope122 In general, yes, it's impossible. Obviously any particular compiler will have its patterns, which you might be able to work out. – Steve Summit Mar 19 '18 at 21:23
1

The ordering of variables in memory is an implementation detail of the compiler.

It may put them in order, or in reverse order, or grouped by datatype, or some other way. This differs from one compiler to the next, and can also differ with different optimization levels. Also, as you've seen, which strategy is used can change with seemingly unrelated code changes.

The C standard imposes no requirements on how this is done, so you can't portably depend on their order.

dbush
  • 205,898
  • 23
  • 218
  • 273