Dereferencing pointer cast from an integer of a valid memory address give Segmentation fault

71 Views Asked by At

I was playing around with c pointer and wrote this code

#include <stdio.h>

int main() {
    int a = 17;
    int* p1 = &a;
    int* p2 = (int*)(&p1);
    p1 = (int*)(&p2);
    printf("%d\n", *((int*)(*p1)));
    printf("%d\n", *((int*)(*p2)));
    return 0;
}

the program exit with

[Done] exited with code=3221225477 in 0.23 seconds

the pointers work as expected

#include <stdio.h>

int main() {
    int a = 17;
    int* p1 = &a;
    int* p2 = (int*)(&p1);
    p1 = (int*)(&p2);
    printf("&p1 %d\n", &p1);
    printf("&p2 %d\n", &p2);
    printf("p1 %d\n", p1);
    printf("p2 %d\n", p2);
    printf("*p1 %d\n", *p1);
    printf("*p2 %d\n", *p2);
    // printf("%d\n", *((int*)(*p1)));
    // printf("%d\n", *((int*)(*p2)));
    return 0;
}
&p1 748680992
&p2 748680984
p1 748680984
p2 748680992
*p1 748680992
*p2 748680984

it only stopped working when i try to dereference arbitrary-ish address

according to the answers from another question, the reason dereferencing arbitrary memory address doesn't work is because the address is invalid

but here i dereference an address that i was able to dereference just fine before

is this because of some kind of protection to prevent bad code? if so i want to know the specifics of the protection mechanism or i'm just doing it wrong for what i'm trying to achieve?

2

There are 2 best solutions below

0
jinTgreater On

Lets work through all your printf's,

  • &p1 and &p2 are just addresses ( of pointers )
  • p1 and p2 are just addresses too
  • *p1, p1 is set to the address of p2 so *p1 will be p2
  • *p2, p2 is set to the address of p1 so *p2 will be p1

There is never an arbitrary address being dereferenced, so no segfaults.

printf is probably just casting pointers to ints.

Try printf( "%ld\n", (uintptr_t)&p1 ); ld for long int, uintptr_t is casting a pointer to unsigned int.

0
fanfly On

You cannot dereference a pointer if it does not correctly point to an object, or it causes undefined behavior (i.e., anything strange can happen).

Also note that the address of a "pointer" should be stored in "pointer to pointer".

Following are some examples:

int a = 42;

// This is a pointer to int. (It points to a.)
int *p = &a;

// A pointer to pointer to int. (It points to p.)
int **q = &p;

// This is okay: types match and *q == &a.
p = *q;

// This is also okay: types match and &(*q) == &p.
q = &(*q);

// If you write incorrect assignment such as:
// p = &q;
// Then you are likely to get a warning from compiler, since their types are different.