Sakebi Sakebi - 9 months ago 33
C Question

C - trying to change values on the stack works in one case, but not in another, why is that?

I am trying to play with a c code and see how I can access elements on the stack by just changing the value of the pointer.
In the following code, I have two variables - i and f - and a pointer to f. My foolish aim (it's just playing) was to change the pointer to i, without doing it directly, and giving i the address of a function as a value.
Now, it all worked just fine, and I managed to run the function by casting i to that function type.

#include <stdio.h>

void function(void)
printf("Inside function\n");

int main(void)
size_t i = 0;
size_t f = 15;
size_t *ptr = &f;

/* why do I need that line?? */
printf("i is: %p\n", &i);

/* pointing ptr to i */
ptr = (size_t *)((size_t)ptr - sizeof(size_t));

/* making sure I can change the value of i */
*ptr = 12;
printf("i should be 12: %lu\n", i);

/* inserting the address of function to it */
*ptr = (size_t)function;

/* validating i has the same address as function */
printf("i has the value of: 0x%lx\n", i);
printf("address of function: %p\n", function);

/* calling the function through i */
typedef void (*func)(void);

return (0);

My question is, this works fine only when I first print the address of i. If I remove that line, it won't work and I'll get a segmentation fault (i still gets to have the first value it received). My guess was that it had something to do with the compiler, but what does the compiler do and why does it do it? I compile using gcc.

Thank you
(It's the first time I ever ask a question on here. I didn't know how to look up that kind of question, so I am sorry if something similar has been already posted in the past)

Answer Source

Here printf("i is: %p\n", &i); you are taking the address of i. This forces the compiler to actually give it an address.

Otherwise the compiler will likely notice that size_t i = 0; sets i to zero, and that never changes throughout the program. So it can just use 0 instead of i for the rest of the program.

Your code here

/*  pointing ptr to i   */
ptr = (size_t *)((size_t)ptr - sizeof(size_t));

makes heavy assumptions on how the compiler places variables in memory. The language doesn't say anything about this, so the compiler can do anything it wants - including not placing a variable in memory at all.