4

当我通过 Jim Trevor为 PL 课程编写的“ Cyclone: A safe dialect of C ”时,我正在尝试掌握 C。Trevor 和他的合著者正在尝试制作一个安全的 C 版本,因此他们在他们的语言中消除了未初始化的指针。谷歌搜索了一下在未初始化的指针上,似乎未初始化的指针指向内存中的随机位置。似乎仅这一点就使他们不安全。如果你引用一个未初始化的指针,你会跳转到内存的不安全部分。时期。但特雷弗谈论它们的方式似乎暗示它更复杂。他引用了下面的代码,并解释说当函数 FrmGetObjectIndex 取消引用 f 时,它不是在访问一个有效的指针,而是一个不可预测的地址——当 f 的空间被分配时,堆栈上的任何内容。

Trevor 所说的“分配 f 的空间时堆栈上的任何内容”是什么意思?默认情况下,“未初始化”指针是否初始化为内存中的随机位置?或者它们的“随机”行为是否与分配给这些指针的内存有关,由于堆栈上的意外行为,这些指针被填充了奇怪的值(然后被引用)。

Form *f;
   switch (event->eType) {
   case frmOpenEvent:
   f = FrmGetActiveForm(); ...
   case ctlSelectEvent:
   i = FrmGetObjectIndex(f, field); ...
}
4

2 回答 2

5

Trevor 所说的“分配 f 的空间时堆栈上的任何内容”是什么意思?

他的意思是,在大多数汇编语言中,单独的指令用于在堆栈上保留空间并在新保留的空间内写入初始值。如果 C 程序使用未初始化的变量,程序通常会在运行时执行保留堆栈空间的指令,但不执行设置它的指令。当使用指针时,它实际上将包含在保留空间之前位于堆栈上的位模式。在好的情况下,这将是一个无效地址。在不好的情况下,这恰好是一个有效的地址,其影响将是不可预测的。

这只是一个典型的行为。从理论的角度来看,使用不确定的值是未定义的行为。可能会发生比简单地访问无效地址或有效地址更奇怪的事情(意外故意使用未初始化数据(非地址)的示例)。


以下是 C 的受限子集(例如 Cyclone)旨在防止的危险:

int a, *p;

int main(int c, char **v){
  int l, *lp, i;
  if (c & 1) 
    a = l + 1;      // danger
  if (c & 2)
    *lp = 3;        // danger
  if (c & 4)
    {
      p = &a;  
      for (i=0; i<=1; i++)
        {
          int block_local;
          *p = 4;   // danger
          p = &block_local;
        }
    }
}

在最后一个危险的行中,实际上,最有可能将 4 写入 variable block_local,但实际上,在第二次迭代时,p它是不确定的,程序不应该访问*p,并且当它访问时它是未定义的行为。

于 2012-11-12T16:58:53.480 回答
1

在现代操作系统上,危险是核心转储。在没有内存管理和可能内存映射 i/o 到外部硬件的早期系统上,危险程度完全不同。

于 2012-11-12T17:51:30.537 回答