幽灵警告MSVC C5040的解决方法

时间:2018-05-17 20:22:24

标签: c visual-c++ visual-studio-2017 spectre

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

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;
}

“在上面的示例中,代码执行数组边界检查以确保untrusted_index小于array1的长度。这是确保程序不读取超出数组边界所必需的。虽然这看起来像是书面的,但它没有考虑涉及推测性执行的CPU的微体系结构行为。“

所以你现在收到警告:

  

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

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

因为似乎你不能把任何事情视为理所当然,我怀疑做出“只是让警告消失”的改变。例如,将untrusted_index < array1_length更改为untrusted_index != array1_length似乎是这样做的,用于我在此处提供的MCVE代码的特定实例。但这是一个可行的补丁,还是他们的警告只是不完整 - 在下一次更新中,它会抱怨这个?

我知道我可以使用/ wd5040或其他方式禁用警告。但我有兴趣确保如果使用/ Qspectre编译代码没有减速,并且如果没有使用/ Qspectre编译则没有警告。我不想在循环条件下触摸将<更改为!=的文件 - 或者其他 - 如果只是流失。

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

2 个答案:

答案 0 :(得分:1)

来自文章本身:

  

值得注意的是,分析存在限制   MSVC和编译器通常可以在尝试识别时执行   变体1的实例。因此,并不能保证全部   变体1的可能实例将在/ Qspectre下进行检测。

您可能遇到过/ Qspectre的当前实施无法通过设计缓解漏洞的情况之一。这是合理的,因为过度使用LFENCE可能会显着降低性能。减轻代码中出现的变体1的每个实例都太昂贵了,无法在软件中完全完成(使用LFENCE)。

在评论中,有人问:

  

您能否为开发人员描述MSVC的限制是什么,以及什么   更多开发人员需要做些什么来保护自己免受“变种1”的侵害?

文章的作者回答说:

  

我们不会详细介绍MSVC的实施细节。许多   人们和公司依赖我们的工具,所以我们会犯错误   关于我们公开讨论的问题,我们谨慎行事。

因此,微软似乎并不想确切地披露/ Qspectre不会减少变体1的哪些实例。

答案 1 :(得分:0)

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

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

请记住,这个诊断只是告诉你编译器会在启用幽灵缓解的情况下做一些与以前不同的事情,它并不是真的告诉你,你一定需要对代码进行任何