15

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

“在上面的示例中,代码执行数组边界检查以确保 untrusted_index 小于 array1 的长度。这是确保程序不会读取超出数组边界所必需的。虽然这似乎是合理的正如所写的那样,它没有考虑 CPU 涉及推测执行的微架构行为。”

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

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

这是它告诉您此代码最终可能比您希望的要慢(如果编译/Qspectre)的方式,因为它将提供一些额外的保护。

由于您似乎无法将任何事情视为理所当然,因此我怀疑做出“只是让警告消失”的更改。例如,对于我在此处给出的 MCVE 代码的特定实例,更改untrusted_index < array1_lengthuntrusted_index != array1_length似乎可以做到这一点。但这是一个可行的补丁,还是他们的警告只是不完整的——在下一次更新中,它也会抱怨这个?

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

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

4

2 回答 2

2

从文章本身:

重要的是要注意,在尝试识别变体 1 的实例时,MSVC 和编译器通常可以执行的分析有限。因此,不能保证变体 1 的所有可能实例都将在 /Qspectre 下进行检测。

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

在评论中,有人问:

您能否向开发人员描述 MSVC 的限制是什么,以及开发人员需要做些什么来保护自己免受“变体 1”的影响?

文章作者回复:

我们不会详细介绍 MSVC 的实现。很多人和公司都依赖我们的工具,所以对于我们公开讨论的内容,我们会谨慎行事。

因此,微软似乎不想确切披露变体 1 的哪些实例不会被 /Qspectre 缓解。

于 2018-05-18T17:03:25.730 回答
1

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

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

记住,这个诊断只是告诉你编译器会在启用幽灵缓解的情况下做一些不同于以前的事情,它并没有真正告诉你必须对代码做任何事情

于 2018-05-17T21:11:56.013 回答