This question already has answers here:
change a pointer of address of another application
(4 answers)
Closed 9 years ago.
I have edited 1.c as below.
#include<stdio.h>
int x=100;
int main(void)
{
printf("%p",&x);
while(1);
return 0;
}
Then I opened Command Prompt and run this program and got Output 00402000 while program still running. Now I run 2.c
#include<stdio.h>
int main(void)
{
int *p=(int *)0x00402000;
printf("%d",*p);
return 0;
}
in another instance of command prompt and got output -1, I expect 100 which is in location 00402000. please explain why is this behavior?
First and foremost, let me say that in modern operating systems, the address values that your program sees (like that 0x00402000) are not physical addresses. They are virtual addresses, they're private to the owning process (i. e. make no sense or mean something else in other processes), and are mapped to physical addresses via a CPU-based mechanism ("the paging unit") that only OS has control over.
If you want to share a variable between different processes, there's a mechanism called shared memory. Read up on it. The relevant APIs are CreateFileMapping with the the first parameter being INVALID_HANDLE_VALUE, MapViewOfFile, OpenFileMapping. There are other ways of interprocess communication, too.
If you want to read process' memory without that process' explicit cooperation, you need to read up on debugging API. This is a much trickier job than using shared memory.
What you've coded, by the way, is a classic undefined behavior.
To demo the address space concept, modify your second example to:
#include<stdio.h>
int y = 101;
int main(void)
{
int *p=(int *)0x00402000; // hope this works??
printf("%d",*p);
printf("%p", p); // print value of p to ensure correct assignment
return 0;
}
It probably/might print "101" !! This is because the OS treats each address space the same. So the, global var for an int regardless of its name probably gets allocated to location 0x004002000.
Appears to be undefined behavior. Since a user's process is only allowed to access memory which has been assigned to it.
So as you try to access the memory about the address, your assigning an invalid address, and you are running into undefined behavior.
Related
I'm trying to understand how memory address works. Here is the code.
#include <stdio.h>
int main()
{
int i = 127, * p;
p = &i;
long j = 0;
printf("%d\n", i);
printf("%d\n", *p);
printf("%p\n", (void*)&i);
scanf("%lx", &j);
p = (int *)j;
printf("%d\n", *p);
return 0;
}
I ran the code 2 times at the same time and got 2 running programs waiting input.
Assume program_1 gives 0x7ffd66359b78 while program_2 gives 0x7ffc8b0d7af8.
If I enter 7ffd66359b78 for program_1 I get 127.
If I enter 7ffc8b0d7af8 for program_1 I get
signal: segmentation fault (core dumped)
which means the memory address I get in a program during its execution only works within this program for that execution, is my understanding correct?
I guess it's some kind of OS security feature. What's the name of it? Is it possible to turn off this feature to allow different programs access the same block via memory address?
which means the memory address I get in a program during its execution only works within this program for that execution, is my understanding correct?
Yes.
I guess it's some kind of OS security feature. What's the name of it?
Most importantly, virtual memory and ASLR.
Basically, in a simplification, each process has a hidden number that is added to the address when accessing memory. https://en.wikipedia.org/wiki/Memory_management_unit
Is it possible to turn off this feature to allow different programs access the same block via memory address?
It's called shared memory and also https://en.wikipedia.org/wiki/Inter-process_communication#Approaches .
Could we point and address specific place in memory using pointer in c language?
Then modify it from another file (ANOTHER PROGRAM) and view it from any where.
Like :
Modifying it :
#include<stdio.h>
void main(){
int *p;
p= 12345678;
scanf("%d",p);
}
Viewing it :
#include<stdio.h>
void main(){
int *p;
p= 12345678;
printf("%d", *p);
}
No. Each process in your operating system has its own address space.
Processes can communicate, using the channels provided by the operating system.
Look into IPC, aka inter process communication, if you're interested in knowing more about it.
What about const volatile pointer (which will be pointing to some memory)? If I'm not wrong it will point to some memory it won't change during first program (also you will not be allowed to modify this memory) but that memory can be modified by another program/process etc.
EDIT:
Just to clarify if we use const volatile pointer it will do two things.
In program it won't allow us to change it value after initialisation
More important volatile keyword will disallow some compiler optimisations on readings and will always reload from memory each time it is accessed by the program. This dramatically reduces the possible optimisations. However, when the state of an object can change unexpectedly, it is the only way to ensure predictable program performance.
Is it possible to assign a variable the address you want, in the memory?
I tried to do so but I am getting an error as "Lvalue required as left operand of assignment".
int main() {
int i = 10;
&i = 7200;
printf("i=%d address=%u", i, &i);
}
What is wrong with my approach?
Is there any way in C in which we can assign an address we want, to a variable?
Not directly.
You can do this though : int* i = 7200;
.. and then use i (ie. *i = 10) but you will most likely get a crash. This is only meaningful when doing low level development - device drivers, etc... with known memory addreses.
Assuming you are on an x86-type processer on a modern operating system, it is not possible to write to aribtray memory locations; the CPU works in concert with the OS to protect memory so that one process cannot accidentally (or intentionally) overwrite another processes' memory. Allowing this would be a security risk (see: buffer overflow). If you try to anyway, you get the 'Segmentation fault' error as the OS/CPU prevents you from doing this.
For technical details on this, you want to start with 1, 2, and 3.
Instead, you ask the OS to give you a memory location you can write to, using malloc. In this case, the OS kernel (which is generally the only process that is allowed to write to arbitrary memory locations) finds a free area of memory and allocates it to your process. The allocation process also marks that area of memory as belonging to your process, so that you can read it and write it.
However, a different OS/processor architecture/configuration could allow you to write to an arbitrary location. In that case, this code would work:
#include <stdio.h>
void main() {
int *ptr;
ptr = (int*)7000;
*ptr = 10;
printf("Value: %i", *ptr);
}
C language provides you with no means for "attaching" a name to a specific memory address. I.e. you cannot tell the language that a specific variable name is supposed to refer to a lvalue located at a specific address. So, the answer to your question, as stated, is "no". End of story.
Moreover, formally speaking, there's no alternative portable way to work with specific numerical addresses in C. The language itself defines no features that would help you do that.
However, a specific implementation might provide you with means to access specific addresses. In a typical implementation, converting an integral value Ato a pointer type creates a pointer that points to address A. By dereferencing such pointer you can access that memory location.
Not portably. But some compilers (usually for the embedded world) have extensions to do it.
For example on IAR compiler (here for MSP430), you can do this:
static const char version[] # 0x1000 = "v1.0";
This will put object version at memory address 0x1000.
You can do in the windows system with mingw64 setup in visual studio code tool, here is my code
#include<stdio.h>
int main()
{
int *c;
c = (int *)0x000000000061fe14; // Allocating the address 8-bit with respect to your CPU arch.
*c = NULL; // Initializing the null pointer for allocated address
*c = 0x10; // Assign a hex value (you can assign integer also without '0x')
printf("%p\n",c); // Prints the address of the c pointer variable
printf("%x\n",*c); // Prints the assigned value 0x10 -hex
}
It is tested with mentioned environment. Hope this helps Happy coding !!!
No.
Even if you could, 7200 is not a pointer (memory address), it's an int, so that wouldn't work anyway.
There's probably no way to determine which address a variable will have. But as a last hope for you, there is something called "pointer", so you can modify a value on address 7200 (although this address will probably be inaccessible):
int *i = (int *)7200;
*i = 10;
Use ldscript/linker command file. This will however, assign at link time, not run time.
Linker command file syntax depends largely on specific compiler. So you will need to google for linker command file, for your compiler.
Approximate pseudo syntax would be somewhat like this:
In linker command file:
.section start=0x1000 lenth=0x100 myVariables
In C file:
#pragma section myVariables
int myVar=10;
It's not possible, maybe possible with compiler extensions. You could however access memory at an address you want (if the address is accessible to your process):
int addr = 7200;
*((int*)addr) = newVal;
I think '&' in &a evaluates the address of i at the compile time which i think is a virtual address .So it is not a Lvalue according to your compiler. Use pointer instead
After doing lot of research in Google, I found this program:
#include <stdio.h>
int main()
{
int val;
char *a = (char*) 0x1000;
*a = 20;
val = *a;
printf("%d", val);
}
But it is throwing a run time error, at *a = 20.
So how can I write and read a specific memory location?
You are doing it except on your system you cannot write to this memory causing a segmentation fault.
A segmentation fault (often shortened to segfault), bus error or access violation is generally an attempt to access memory that the CPU cannot physically address. It occurs when the hardware notifies an operating system about a memory access violation. The OS kernel then sends a signal to the process which caused the exception. By default, the process receiving the signal dumps core and terminates. The default signal handler can also be overridden to customize how the signal is handled.
If you are interested in knowing more look up MMU on wikipedia.
Here is how to legally request memory from the heap. The malloc() function takes a number of bytes to allocate as a parameter. Please note that every malloc() should be matched by a free() call to that same memory after you are done using it. The free() call should normally be in the same function as where you called malloc().
#include <stdio.h>
int main()
{
int val;
char *a;
a = (char*)malloc(sizeof(char) * 1);
*a = 20;
val = (int)*a;
printf("%d", val);
free(a);
return 0;
}
You can also allocate memory on the stack in a very simple way like so:
#include <stdio.h>
int main()
{
int val;
char *a;
char b;
a = &b;
*a = 20;
val = (int)*a;
printf("%d", val);
return 0;
}
This is throwing a segment violation (SEGFAULT), as it should, as you don't know what is put in that address. Most likely, that is kernel space, and the hosting environment doesn't want you willy-nilly writing to another application's memory. You should only ever write to memory that you KNOW your program has access to, or you will have inexplicable crashes at runtime.
If you are running your code in user space(which you are), then all the addresses you get are virtual addresses and not physical addresses. You cannot just assume and write to any virtual address.
In fact with virtual memory model you cannot just assume any address to be a valid address.It is up to the memory manager to return valid addresses to the compiler implementation which the handles it to your user program and not the other way round.
In order that your program be able to write to an address:
It should be a valid virtual address
It should accessible to the address space of your program
You can't just write at any random address. You can only modify the contents of memory where your program can write.
If you need to modify contents of some variable, thats why pointers are for.
char a = 'x';
char* ptr = &a; // stored at some 0x....
*ptr = 'b'; // you just wrote at 0x....
Issue of permission, the OS will protect memory space from random access.
You didn't specify the exact error, but my guess is you are getting a "segmentation fault" which would clearly indicate a memory access violation.
You can write to a specific memory location.
But only when you have the rights to write to that location.
What you are getting, is the operating system forbidding you to write to 0x1000.
That is the correct way to write data to memory location 0x1000. But in this day and age of virtual memory, you almost never know the actual memory location you want to write to in advance, so this type of thing is never used.
If you can tell us the actual problem you're trying to solve with this, maybe we can help.
You cannot randomly pick a memory location and write to. The memory location must be allocated to you and must be writable.
Generally speaking, you can get the reference/address of a variable with & and write data on it. Or you can use malloc() to ask for space on heap to write data to.
This answer only covers how to write and read data on memory. But I don't cover how to do it in the correct way, so that the program functions normally. Other answer probably covers this better than mine.
First you need to be sure about memory location where you want to write into.
Then, check if you have enough permission to write or not.
Can someone help me to understand the output of these program.
int* fun1();
void fun2();
int main()
{
int *p=fun1();
fun2();
printf("%d\n",*p);
return 0;
}
int* fun1()
{
int i=10;
return &i;
}
void fun2()
{
int a=100;
printf("%d\n",a);
}
It is 100 100 on windows and 100 10 on Linux. Windows output I am able to justify due to the fact that local variables are allocated on stack. but how come it is 100 10 in Linux.
Returning a pointer to a stack-allocated variable that went out of scope and using that pointer is undefined behavior, pure and simple.
But I'm guessing the answer "anything can happen" won't cut it for you.
What happens is that on *nix the memory isn't recycled so it's not overwritten yet, and on win it is. But that's just a guess, your best course of option is to use a debugger and walk through the assembler code.
Your problem relies on undefined behaviour [1], so anything can happen. You shouldn't even be expecting consistency on a given OS: factors such as changes to compiler options can alter the behaviour.
[1] fun1() returns the address of a variable on the stack, which is subsequently dereferenced.
Dangling pointer Problem , hence undefined behavior.
In a Linux (or other Operating System) process when a subroutine is called, the memory for local variables comes from stack area of the process. Any dynamically allocated memory (using malloc, new, etc.) comes from the heap area of the process. During recursion local memory is allocated from stack area during function call and get cleared when the function execution is done.
The memory is being represented with lowest address being at the bottom and highest being at the top. Here are the steps to find the direction of stack growth in recursion using a quick C code.
#include <stdio.h>
void test_stack_growth_direction(recursion_depth) {
int local_int1;
printf("%p\n", &local_int1);
if (recursion_depth < 10) {
test_stack_growth_direction(recursion_depth + 1);
}
}
main () {
test_stack_growth_direction(0);
}
out put on MAC
0x7fff6e9e19ac
0x7fff6f9e89a8
0x7fff6f9e8988
0x7fff6f9e8968
0x7fff6f9e8948
0x7fff6f9e8928
0x7fff6f9e8908
0x7fff6f9e88e8
0x7fff6f9e88c8
0x7fff6f9e88a8
0x7fff6f9e8888
output on ubuntu
0x7ffffeec790c
0x7ffffeec78dc
0x7ffffeec78ac
0x7ffffeec787c
0x7ffffeec784c
0x7ffffeec781c
0x7ffffeec77ec
0x7ffffeec77bc
0x7ffffeec778c
0x7ffffeec775c
0x7ffffeec772c
The stack is growing downwards on these specific setups as memory addresses are reducing. This depends on the architecture of the system and may have different behavior for other architectures. 0x7fff6f9e8868