C - 指针如何覆盖局部 const 内存块而不是全局 const 内存块?

C - How can a pointer overwrite a local const block of memory but not the global const block of memory?

上次我问如何通过绕过编译器不覆盖 const 内存的承诺在程序中生成 segmentation 错误。用户 Marco Bonelli 描述了以下方法,效果很好。

const static int global = 123;

int main(void) {
  int *ptr = (int *)&global;
  *ptr = 456;

  // or, equivalent
  const int *ptr2 = &global;
  *(int *)ptr2 = 456;
}

无论哪种方式,我都能够生成分段错误。

现在我的问题是,是什么阻止了指针写入 global const 内存块而不是 local const 内存块。例如,在下面的代码中,我能够毫无问题地写入 const 内存块。

#include <stdio.h>

int main(void) {
  const int local = 123;
  
  int *ptr = (int *)&local;
  *ptr = 456;
  
  // how come this be possible?
  printf("%d\n", local); // -> 456

  // or, equivalent
  const int *ptr2 = &local;
  *(int *)ptr2 = 512;

  // how come this be possible?
  printf("%d\n", local); // -> 512
}

我很好奇这是怎么发生的。请赐教

如果重要的话,我正在使用 gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0

after the termination of the program what exactly happens to that block?

您的进程 virtual memory 会发生什么由操作系统决定。当程序终止时,操作系统将清除为您的程序分配的所有内存,无论这些内存用于什么。 const的概念与此无关

Was the compiler able to remove that const qualifier from that particular block? Can I be able to overwrite that block of memory, if so how can I do that explicitly?

您不能更改变量的声明方式。它在整个生命周期中都保持这种状态。您将无法做到这一点,即便如此,也 undefined behavior 尝试这样做。

What if I need to overwrite a const block of memory? Is there any way to do that?

如果您需要这样做,那么您编写的任何程序的逻辑都是有缺陷的。你不能也不应该这样做。这是未定义的行为,在最好的情况下会用 segmentation fault.

杀死你的程序

好的,如果你真的想用写入 const 变量导致的分段错误终止你的程序,假设你的编译器将全局 const 变量放在只读部分(例如 .rodata,那么以下内容就足够了:

const static int global = 123;

int main(void) {
    int *ptr = (int *)&global;
    *ptr = 456;

    // or, equivalent
    const int *ptr2 = &global;
    *(int *)ptr2 = 456;
}

您需要“丢弃”const 限定符,以便编译器不会将其视为错误。同样,这仅在编译器将 global 放入 read-only 部分(标准不要求)时才有效。如果这不会导致分段错误,那么这意味着您的编译器不会将所有 const 变量放入 read-only 部分。

这完全取决于实施。例如,const 裸机 ARM uC 上的数据存储在 FLASH 存储器中。你可以写到那里,但它根本没有作用。

托管系统的行为会因 OS、其版本和硬件而异。

How can I overwrite a const block of memory只要你想写就不要声明它const。如果你尊重给编译器的承诺。

如果只是初学者的好奇心,除了试验没有别的办法。实验、调试并尝试解释结果。

编辑。

在最常见的实现中:

  • constant local(自动变量是在堆栈上创建的,不受操作系统保护以防止写入 - 你没有得到段错误。

  • 常量全局(静态存储)变量放置在 .rodata 段中,该段受操作系统保护以防止写入 - 您遇到了段错误。