Search code examples
cpointerscastingprintflow-level

Cast content of variable to pointer results in NULL after printf


I try to achieve the following: I'm having a pointer p pointing to an address holding again an address (this address is also a valid address). Now I want to have another pointer pp pointing to the address which is the content of p. So I'm doing the following:

// Retrieve the start address
unsigned long long *p = getInitialAddress();

// Let pp point to next address
unsigned long long *pp = (unsigned long long*)(*p);

// Print address
printf("0x%llx %p\n", *p, pp);

This prints for example: 0x7fffedc47a70 0x7fffedc47a70 which is the desired result.

However, putting another printf into the code, like this:

// Retrieve the start address
unsigned long long *p = getInitialAddress();

// Print
printf("%p 0x%llx\n", p, *p);

// Let pp point to next address
unsigned long long *pp = (unsigned long long*)(*p);

// Print address
printf("0x%llx %p\n", *p, pp);

Leads to:

0x7fffacea3660 0x7fffacea3680
0x0 (nil)

And this is not the correct result, because it should be

0x7fffacea3660 0x7fffacea3680
0x7fffacea3680 0x7fffacea3680

So does the printf alter something within the pointers or what is wrong?

Edit: Complete code

unsigned long long* readRBP();

int main(void) {
    // Retrieve the start address
    unsigned long long *p = readRBP();

    // Print
    printf("%p 0x%llx\n", p, *p);

    // Let pp point to next address
    unsigned long long *pp = (unsigned long long*)(*p);

    // Print address
    printf("0x%llx %p\n", *p, pp);

    return 0;
}

unsigned long long* readRBP() {
    unsigned long long rbp;
    __asm__ volatile("mov %%rbp, $0" : "=r"(rbp));
    return (unsigned long long*)rbp;
}

This gets the rbp (Stack base pointer). The content of this pointer is the pointer to the next rbp and so on. This rbp is from readRBP() itself, the next rbp belongs to main and the next one after main is 0x0, i. e. the very beginning.


Solution

  • The value that readRBP returns is the base pointer for the readRBP function. You then call printf which creates its own stack frame. And that stack frame obliterates the data at *p.

    To see that this is so you can write your code this way round:

    int main(void) {
        // Retrieve the start address
        unsigned long long *p = readRBP();
        unsigned long long pContents = *p
        unsigned long long *pp = (unsigned long long*)(*p);
    
        // Print
        printf("%p 0x%llx %p\n", p, pContents, pp);
    
        return 0;
    }
    

    In other words you gather up all the information into the stack frame of main, before you stomp on it by calling printf.