使用“指向易失变量的指针”是否始终防止编译器优化?

8
这里的问题是:您的程序暂时使用了一些敏感数据,并希望在不再需要时将其擦除。仅对自身使用std :: fill()并不能总是起到作用 - 编译器可能会认为内存块以后不会被访问,因此擦除代码是浪费时间,从而消除擦除代码。 用户ybungalobill建议{{link3:使用volatile关键字:}}
{
  char buffer[size];
  //obtain and use password
  std::fill_n( (volatile char*)buffer, size, 0);
}

意图是,当看到volatile关键字时,编译器将不会尝试消除对std::fill_n()的调用。 volatile关键字是否总能防止编译器消除此类内存修改代码?

嗯,我认为这不是完全相同的情况。在这里编译器知道内存是分配在堆栈上的,在那里它不知道。(所以它可能指向映射寄存器的内存) - Yakov Galka
我正要发布一个类似的问题,关于这个答案。有趣的是一个问题可以引发很多其他有趣的问题;) 这是我的+1。 - ereOn
尝试将缓冲区声明为 volatile char buffer[size]; 而不是在调用 std::fill_n 时进行转换。 - Thomas Matthews
4个回答

3

根据最新的C++0x草案[intro.execution]:

8 符合规范实现的最低要求包括:

— 访问volatile对象必须严格按照抽象机器规则进行评估。

[...]

12 访问由volatile值(3.10)指定的对象,修改对象,调用库I/O函数或调用执行任何这些操作的函数都是副作用[...]。

因此,即使您提供的代码也不能被优化。


2
至少,在 as-if 规则下,写入 volatile 对象的副作用不得被移除,这意味着代码执行应该如预期。编译器仍然可以在 fill_n 中执行其他优化,例如循环展开或汇编优化。 - Doug

3
编译器可以优化您的代码,因为buffer不是一个易失对象。标准仅要求编译器严格遵守易失对象的语义。以下是C++03的规定:
“符合实现的最小要求是:
在序列点上,易失对象是稳定的,这意味着先前的评估已经完成,后续的评估尚未发生。”
以及
“抽象机器的可观察行为是其对易失数据的读写序列和库I/O函数的调用。”
在您的示例中,您使用易失lvalue对非易失对象进行读写。 C++0x删除了我引用的第二段文本,因为它是多余的。 C++0x只是说:
“符合实现的最小要求是:
访问易失对象严格按照抽象机器的规则进行评估。”
总体而言,这些被称为程序的“可观察行为”。
虽然有人可能会认为“易失数据”可能意味着“由易失lvalue访问的数据”,但这仍然是一种很大的牵强解释,C++0x的措辞消除了有关您的代码的所有疑虑,并清楚地允许实现将其优化。
但是,正如人们向我指出的那样,在实践中这可能并不重要。优化这种东西的编译器很可能会违反程序员的意图(否则为什么要有指向易失性指针),因此很可能包含错误。尽管如此,我遇到过引用这些段落的编译器供应商,当他们面对过度积极的优化的错误报告时。最终,volatile是固有的平台特定的,您应该仔细检查结果。

1
为什么这些规则往往是在玩文字游戏? - Pooria

1
一致的实现可以在适当时候推迟任何易失性读写的实际执行,直到易失性读取的结果会影响易失性写入或I/O操作的执行为止。
例如,假设有以下内容:
volatile unsigned char vol1,vol2;
extern unsigned char res[1000];
void test(int scale)
{
  unsigned char ch;

  for (int 0=0; i<10000; i++)
  {
    res[i] = i*vol1*scale;
    vol2 = res[i];
  }
}

一个符合规范的编译器可以选择性地检查 scale 是否是 128 的倍数,如果是,则在从 vol1 进行任何读取或向 vol2 进行任何写入之前清除所有偶数索引值的 res。虽然编译器需要在进行以下对 vol2 的写入之前对每个 vol1 进行读取,但编译器可能能够推迟这两个操作,直到运行了基本上不受限制的代码。

1
您希望删除的内存内容可能已经从CPU / 核心的内部缓存刷新到 RAM 中,其他 CPU 可以继续查看它。在覆盖它之后,您需要使用互斥锁/内存屏障指令/原子操作或其他东西来触发与其他内核的同步。实际上,在调用任何外部函数之前,您的编译器可能会执行此操作(请参阅 Dave Butenhof 关于 volatile 在多线程中有限效用的帖子),因此,如果您的线程在此之后不久就这样做,那么这不是一个重大问题。简而言之:不需要使用 volatile。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接