3

当我发现你可以增加指针时,我开始在 c 中玩了一下。所以我想,为什么不试试看是否可以用这个程序清除我的 RAM:

#include <stdio.h>

int main()
{
    int number = 0;
    int *pointer = &number;
    while (true) {
        pointer++;
        *pointer = 0;
    }
    return 0;
}

这是我的操作系统无法运行的原因,还是 C 语言对此有例外?

提前致谢!

4

5 回答 5

3

这是我的操作系统无法运行的原因,还是 C 语言对此有例外?

就语言而言,这是未定义的行为。由操作系统决定当您使用不属于您的内存时会发生什么。

您为 分配sizeof int了字节number,将其地址存储在指针中,然后继续遍历该内存块,直到出现明显的问题。一旦您递增pointer并写入该位置,您就会调用未定义的行为。

您不能随心所欲地读写随机内存位置(好吧,您可以,只是不能保证您的程序以任何特定方式运行)。

于 2012-09-18T22:57:29.447 回答
3

在任何现代操作系统中,每个进程都有自己的地址空间。在其中,它将找到自己的可执行代码和数据。因此,您不能简单地访问“计算机的 RAM”。您所能做的就是在程序的地址空间中搞砸。

您可以通过并行运行以下代码轻松看到这一点:

int main()
{
    int i=0;
    printf("The address of i = %p\n",&i);
    sleep(60);
}

您将(可能)看到所有进程都打印出相同的内存地址。当然,它们并没有指向相同的物理内存位。

ps。当共享库(“DLL”)被加载时,你拥有所有进程都指向内存中相同的物理位。这样,许多可执行代码只需为所有进程加载一次。这将被读取- 仅内存,因此没有进程可以使用同一库更改其他进程的可执行代码。其背后的机制称为内存映射,请查看mmap()系统调用以获取更多信息。)

于 2012-09-18T23:00:23.747 回答
2

number在堆栈上声明,您正在擦除它和随后的内存位置。所以你正在破坏堆栈。这可能会也可能不会导致您的程序崩溃;这是未定义的行为。堆栈损坏可能会导致您的函数看起来干净地退出而没有不利影响,但是当您的进程尝试访问无效的内存位置时,它更有可能发生 SEGV。

于 2012-09-18T22:59:00.973 回答
1

只是为了备份其他人已经说过的内容,当您写入某个无效或非法的内存位置时,您的程序很可能会导致分段错误。

为了看到这是因为更新了一些随机内存地址的内容而发生的,我将显示您的程序在 GDB 下运行。

[jrn@localhost SO]$ gcc -ggdb dumb.c 
[jrn@localhost SO]$ gdb ./a.out 
GNU gdb (GDB) CentOS (7.0.1-42.el5.centos)
Reading symbols from /home/jrn/source/SO/a.out...done.
(gdb) run
Starting program: /home/jrn/source/SO/a.out 

Program received signal SIGSEGV, Segmentation fault.
0x08048399 in main () at dumb.c:9
9               *pointer = 0;
(gdb) list
4       {
5           int number = 0;
6           int *pointer = &number;
7           while (1) {
8               pointer++;
9               *pointer = 0;
10          }
11          return 0;
12      }
13

您将在第 9 行看到错误发生在您写入某个不应该写入的内存地址时。操作系统使用通常由 CPU 提供的内存保护来检测错误写入。

于 2012-09-18T23:10:04.127 回答
1

称为内存保护的东西会阻止你这样做。基本上,如果操作系统试图更改尚未分配的 RAM 部分,操作系统将终止程序,通常称为分段错误

当您的程序以特权模式运行时,您可以(理论上)执行此操作,例如在编写设备驱动程序或为裸机嵌入式系统编程时。

于 2012-09-18T22:59:00.740 回答