Suppose there are two processes: One is my own process and the other process generates random memory address and modifies the content in it (we don't have any control over it).
假设有两个进程:一个是我自己的进程,另一个进程生成随机内存地址并修改其中的内容(我们对它没有任何控制权)。
The first process (my own process):
第一个过程(我自己的过程):
// Process 1
int *ptr = (int*)malloc(sizeof(int)); // Suppose the address is 0x138145800
*ptr = 45;
printf("%d", *ptr);
sleep();
printf("%d", *ptr);
The second process (an external process that I have no control):
第二个过程(我无法控制的外部过程):
// Process 2
int *ptr1;
ptr1 = (int*)0x138145800; // Random memory address is generated
*ptr1 = 25;
printf("%d", *ptr1);
When the first process is in sleep, the second process to which we don't have any control, modifies the value used by process 1.
当第一个进程处于休眠状态时,我们没有任何控制的第二个进程会修改进程1使用的值。
How to prevent the second process from doing so by changing only the first process?
如何通过仅更改第一个进程来防止第二个进程这样做?
One possible way might be to use locks. However to use lock for every variable process 1 uses will be very inefficient. Is there any efficient way to solve the problem?
一种可能的方法是使用锁。但是,对每个变量进程使用锁1使用效率非常低。有没有有效的方法来解决这个问题?
1 个解决方案
#1
2
The operating system prevents a program from accessing memory in another program's stack by design. No program needs to worry about this.
操作系统可以防止程序通过设计访问另一个程序堆栈中的内存。没有程序需要担心这一点。
For illustrative purposes, I ran this scenario on a CentOS image:
为了便于说明,我在CentOS映像上运行了这个场景:
Program 1:
计划1:
int main() {
char *p = "Hello World";
}
Which, when run produces:
哪个,运行时产生:
Dump of assembler code for function main:
0x00000000004004f0 <+0>: push %rbp
0x00000000004004f1 <+1>: mov %rsp,%rbp
=> 0x00000000004004f4 <+4>: movq $0x4005a0,-0x8(%rbp)
0x00000000004004fc <+12>: mov $0x0,%eax
0x0000000000400501 <+17>: pop %rbp
0x0000000000400502 <+18>: retq
End of assembler dump.
We can see that the register 0x4005a0
holds "Hello World"
:
我们可以看到寄存器0x4005a0保存“Hello World”:
(gdb) x /s 0x4005a0
0x4005a0: "Hello World"
Without killing the previous process, we can run another C program that accesses this register:
在不杀死前一个进程的情况下,我们可以运行另一个访问该寄存器的C程序:
int main() {
char * hello_world = (char *) 0x4005a0;
printf("%s", hello_world);
}
Which, when run, produces:
哪个在运行时产生:
L??L??D??A??H??H9?u?H?[]A\A]A^A_?ff.?
And in a separate GDB session (separate from the two programs):
在一个单独的GDB会话中(与两个程序分开):
(gdb) x /s 0x4005a0
0x4005a0: <Address 0x4005a0 out of bounds>
So we can observe a few principles of modern memory architecture at work here. The OS is managing the memory of the program so that the scenario you described would not occur.
所以我们可以在这里观察现代记忆体系结构的一些原理。操作系统正在管理程序的内存,以便您所描述的方案不会发生。
In the second run of the program, it's actually able to print out some text (gibberish) because when a program is run, is actually allotted a virtual address space which, by definition, is the set of ranges of virtual addresses that an operating system makes available to a process. While these two programs use the same virtual address (0x4005a0
), in the second instance it is just free memory.
在程序的第二次运行中,它实际上能够打印出一些文本(乱码),因为当程序运行时,实际上是分配了一个虚拟地址空间,根据定义,它是一组操作系统的虚拟地址范围使进程可用。虽然这两个程序使用相同的虚拟地址(0x4005a0),但在第二个实例中它只是空闲内存。
If a program were to step out of this boundary, the OS would send the classic SIGSEGV
and terminate the program. A segmentation fault by definition is triggered by the OS about a memory access violation.
如果程序要走出这个边界,操作系统将发送经典的SIGSEGV并终止程序。操作系统根据内存访问冲突触发定义的分段错误。
So clearly from a programmatic standpoint, there is nothing that can be done nor needs to be done as this memory management is handled by the OS. Your program is safe in this regard, presuming it's running on a modern OS.
从程序的角度来看,没有什么可以做,也不需要做,因为这个内存管理由操作系统处理。您的程序在这方面是安全的,假设它在现代操作系统上运行。
#1
2
The operating system prevents a program from accessing memory in another program's stack by design. No program needs to worry about this.
操作系统可以防止程序通过设计访问另一个程序堆栈中的内存。没有程序需要担心这一点。
For illustrative purposes, I ran this scenario on a CentOS image:
为了便于说明,我在CentOS映像上运行了这个场景:
Program 1:
计划1:
int main() {
char *p = "Hello World";
}
Which, when run produces:
哪个,运行时产生:
Dump of assembler code for function main:
0x00000000004004f0 <+0>: push %rbp
0x00000000004004f1 <+1>: mov %rsp,%rbp
=> 0x00000000004004f4 <+4>: movq $0x4005a0,-0x8(%rbp)
0x00000000004004fc <+12>: mov $0x0,%eax
0x0000000000400501 <+17>: pop %rbp
0x0000000000400502 <+18>: retq
End of assembler dump.
We can see that the register 0x4005a0
holds "Hello World"
:
我们可以看到寄存器0x4005a0保存“Hello World”:
(gdb) x /s 0x4005a0
0x4005a0: "Hello World"
Without killing the previous process, we can run another C program that accesses this register:
在不杀死前一个进程的情况下,我们可以运行另一个访问该寄存器的C程序:
int main() {
char * hello_world = (char *) 0x4005a0;
printf("%s", hello_world);
}
Which, when run, produces:
哪个在运行时产生:
L??L??D??A??H??H9?u?H?[]A\A]A^A_?ff.?
And in a separate GDB session (separate from the two programs):
在一个单独的GDB会话中(与两个程序分开):
(gdb) x /s 0x4005a0
0x4005a0: <Address 0x4005a0 out of bounds>
So we can observe a few principles of modern memory architecture at work here. The OS is managing the memory of the program so that the scenario you described would not occur.
所以我们可以在这里观察现代记忆体系结构的一些原理。操作系统正在管理程序的内存,以便您所描述的方案不会发生。
In the second run of the program, it's actually able to print out some text (gibberish) because when a program is run, is actually allotted a virtual address space which, by definition, is the set of ranges of virtual addresses that an operating system makes available to a process. While these two programs use the same virtual address (0x4005a0
), in the second instance it is just free memory.
在程序的第二次运行中,它实际上能够打印出一些文本(乱码),因为当程序运行时,实际上是分配了一个虚拟地址空间,根据定义,它是一组操作系统的虚拟地址范围使进程可用。虽然这两个程序使用相同的虚拟地址(0x4005a0),但在第二个实例中它只是空闲内存。
If a program were to step out of this boundary, the OS would send the classic SIGSEGV
and terminate the program. A segmentation fault by definition is triggered by the OS about a memory access violation.
如果程序要走出这个边界,操作系统将发送经典的SIGSEGV并终止程序。操作系统根据内存访问冲突触发定义的分段错误。
So clearly from a programmatic standpoint, there is nothing that can be done nor needs to be done as this memory management is handled by the OS. Your program is safe in this regard, presuming it's running on a modern OS.
从程序的角度来看,没有什么可以做,也不需要做,因为这个内存管理由操作系统处理。您的程序在这方面是安全的,假设它在现代操作系统上运行。