开发者

Explicit assignment of addresses for C pointers

开发者 https://www.devze.com 2023-04-11 21:28 出处:网络
$ cat x.c #include<stdio.h> void main() { int *x,q; int *y,w; x=0x7fffffffe2bc; y=0x7fffffffe3bc; *x=3;*y=4;
$ cat x.c 
#include<stdio.h>
void main()
{
    int *x,q;
    int *y,w;
    x=0x7fffffffe2bc;
    y=0x7fffffffe3bc;
    *x=3;*y=4;
    printf("%d",(*x)/(*y));
}

Produces a segmentation fault at runtime (There are no compile time warnings/errors) EDIT: (Warnings:Thanks @KeithThompson)

x.c: In function ‘main’:

x.c:6: warning: assignment makes pointer from integer without a cast

[ 8626.812415] x[3198]: segfault at 7fffffffe2bc ip 000000000040054c sp 00007fff66a1dd70 error 6 in x[400000+1000]

But when I assign x, y to q, w as this

$ cat x.c 
#include<stdio.h>
void main()
{
    int *x,q;
    int *y,w;
    x=&q;
    y=&w;
    *x=3;*y=4;
    printf("%d",(*x)/(*y));
}

and get the output I get 0. I even checked the address of q and w from gdb, I got 0x7fffffffe2bc for q

Why can't I force a pointer to point at a particular location and provide it wi开发者_StackOverflow社区th a value to be stored?

EDIT The address 0x7fffffffe2bc is not unallocated. This is the address of q from gdb

Breakpoint 1, main () at x.c:10
10      *x=3;*y=4;
(gdb) p q
$1 = 0
(gdb) p &q
$2 = (int *) 0x7fffffffe2bc
(gdb) 

I understand this way of writing code is bad if not incorrect. I merely wrote this to see if explicit assignment of addresses works or not. I would never waste my time explicitly assigning addresses. Doing something like that actually sounds very retarded :)

$ gdb -q ./a.out 
Reading symbols from /home/eknath/needed2/a.out...done.
(gdb) r
Starting program: /home/eknath/needed2/a.out 
0

Program exited normally.
(gdb) q


Because you haven't allocated memory for the data, just the pointer. You are trashing memory at best and hitting an unallocated memory segment at worst. There is no way to know what addresses to use -- every time you run an application they could be different.

If you want to dynamically allocate variables (ie, under your own control), use malloc:

int *x = (int*) malloc( sizeof(int) );
*x = 2;

// when done, free the memory
free( (void*) x );


This code:

int *x,q;
...
x=0x7fffffffe2bc;

is invalid. It is a constraint violation, meaning that any conforming compiler is required to issue a diagnostic message. You said "There are no warnings/errors while compiling this program", which means either that you're using an old compiler, or you're using a new compiler incorrectly.

x is of type int*; 0x7fffffffe2bc is of some integer type. There is no implicit conversion from an integer type to int* (except for the special case of 0, a null pointer constant).

You can legally write something like:

x = (int*)0x7fffffffe2bc;

but it's a very bad idea. It makes your program extremely non-portable. It might (or might not) happen to work on your particular system.

Whatever it is you're trying to accomplish, this is not the way to do it. You have no way of knowing that 0x7fffffffe2bc (when converted to int*) is a valid address -- and even if it is a valid address, it won't be when you run the program in an even slightly different environment.

EDIT:

I tried reproducing your program on my system (where the addresses are quite different) by printing the addresses of q and w and then hard-wiring the addresses into the code. The actual address change every time I execute the program, even when I don't change or recompile the program itself. I think some systems do this intentionally, as a security feature. (I see dmckee's answer already mentioned this.)

Printing the address of a variable, or viewing it with gdb, only tells you the address of that variable in that particular execution of the program. Once the program finishes running, that information is useless, even if you re-run the same program with no changes.

If you want the address of q, the way to get it is &q.


This kind of thing is completely implementation/environment dependent (and is in general undefined behavior), but it does have its place in embedded systems and other environments where you don't have a OS layer between you and absolutely everything.

Many full services OSes randomize the starting address of the stack and/or heap in order to make some attacks harder, and if that is the case you won't be able to perform any reliable tricks.


The problem is neither in code nor compiler/linker. Both programs work as you would expect them to. Just there is one big BUT: just because you can point to the memory it doesn't mean you will be allowed to access it by MMU (let's say Operating System).

Let me clarify this: normally you can only access memory that you "own" (stack/heap). In both cases assignments to x and y are valid. The tricky part is when you access the memory (read or write). In the first case you assign some random value to pointer, therefore there is no considerable possibility that that location will be in program's scope (== can't touch this). Although, in the second case you are accessing memory location of a variable that you might own.

Why might? Because with optimization on variables q and w will be optimized out, because they are never used.

Remember: never ever reference not initialized variable unless you like problems


void myFunction(char *addr)
{
#ifdef UMEM_DEBUG
    if (addr == (char *) 0xdeadbeefdeadbeef)
    {
        return;
    }
#endif
...
}

This works, and is a good example of when you do want to do this. Just get the type cast correct based on the type of addr

0

精彩评论

暂无评论...
验证码 换一张
取 消