幽灵警告MSVC C5040的解决方法

Hos*_*ork 12 c visual-c++ visual-studio-2017 spectre

MSVC刚刚发布了一个更新,它添加了一个关于编译器将注入的一些代码的新警告,以缓解(显然是一些小的)Spectre:

https://blogs.msdn.microsoft.com/vcblog/2018/01/15/spectre-mitigations-in-msvc/

这是一个来自他们的"有问题"代码示例的小MCVE:

#include <stdio.h>

int main(int argc, char *argv) {
    unsigned char array1[1] = {0};
    int array1_length = 1;
    unsigned char array2[1] = {99};
    int untrusted_index = 0; /* in this MCVE, I trust it, compiler doesn't */
    for (; untrusted_index < array1_length; ++untrusted_index) {
        unsigned char value = array1[untrusted_index];
        unsigned char value2 = array2[value * 64];
        printf("Picked value %d\n", value2);
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

"在上面的例子中,代码执行数组边界检查以确保untrusted_index小于array1的长度.这是确保程序不读取超出数组边界所必需的.虽然这似乎是声音正如所写,它没有考虑涉及推测性执行的CPU的微体系结构行为."

所以你现在得到一个警告:

警告C5045:如果指定了/ Qspectre开关,编译器将为内存加载插入Spectre缓解

这是告诉你这个代码最终可能比你想要的慢(如果编译/ Qspectre)的方式,因为它会提供一些额外的保护.

既然你似乎没有把任何事情视为理所当然,我怀疑做出"只是让警告消失"的改变.例如,untrusted_index < array1_length改为untrusted_index != array1_length似乎这样做,对于我在这里给出的MCVE代码的特定实例.但这是一个可行的补丁,还是他们的警告只是不完整 - 在下一次更新中,它也会抱怨这个?

我知道我可以使用/ wd5040或其他方式禁用警告.但我有兴趣确保如果使用/ Qspectre编译代码没有减速,并且如果没有使用/ Qspectre编译则没有警告.我不想去触摸周围不断变化的文件<,以!=在循环的条件-无论-如果这只是翻腾.

所以一个更大的问题是,如果存在这种基本的合法解决方案模式,为什么没有提到它们呢?例如,我描述的情况是一个迭代,我控制索引,而不必担心它来自"不受信任的来源".然而,我得到了一个警告,并且在切换<!=使其消失.为什么?应该有吗?

Sor*_*tir 1

如果您不希望出现警告,只需使用#pragma warning(disable :5040),或在项目属性页中禁用它。

请注意,您对“untrusted_index!= array1_length”提供的更改是不够的,因为它使整个范围大于可被滥用的大小。

请记住,此诊断只是告诉您,在启用幽灵缓解功能的情况下,编译器将执行与以前不同的操作,它并不是真正告诉您必须对代码执行任何操作。

  • *“请注意,您对“untrusted_index != array1_length”提供的更改是不够的,因为它使整个范围大于可滥用的大小。”*我的示例专门针对此类别的 for 循环迭代,其中我控制如果启用了 Qspectre,则不需要缓解代码(如果未启用则发出警告)。那么 != 究竟是什么导致警告不被触发。 (5认同)