【发布时间】:2018-05-17 20:22:23
【问题描述】:
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),因为它会提供一些额外的保护。
由于您似乎无法将任何事情视为理所当然,因此我怀疑做出“只是让警告消失”的更改。例如,将untrusted_index < array1_length 更改为untrusted_index != array1_length 似乎可以做到这一点,对于我在这里给出的 MCVE 代码的具体实例。但这是一个可行的补丁,还是他们的警告只是不完整的——在下一次更新中,它也会抱怨这个?
我知道我可以使用 /wd5040 或其他方式禁用警告。但我有兴趣确保如果代码是使用 /Qspectre 编译的,则不会出现减速,并且如果它没有使用 /Qspectre 编译,则不会出现警告。我不想在循环条件下到处触摸将< 更改为!= 的文件——或者其他任何情况——如果这只是流失的话。
所以一个更大的问题是,如果有这种基本的合法解决方法模式,为什么没有提到它们?例如,我描述的情况是我控制索引的迭代,不必担心它来自“不受信任的来源”。然而我收到了警告,从< 切换到!= 让它消失了。为什么?应该有吗?
【问题讨论】:
-
您的示例在 Spectre 问题方面被破坏了:在访问数组之前没有边界检查。请坚持引用文章中提供的示例。
-
@YannDroneaud No. (a) 你在说什么,有一个边界检查。 (b) 如果我“坚持引用文章中的示例”,它就不是 MCVE,无法复制、粘贴和编译以显示警告,然后按给定的方式修改以显示它消失。
-
无论如何,我相信您应该默认使用 /Qspectre,只是为了不必检查您的所有代码库以查找需要击败推测执行以防止 Spectre 变体 #1 漏洞的位置
-
@YannDroneaud 问题不是“/Qspectre 好”或“我应该使用 /Qspectre”。
-
我想知道“代码执行数组边界检查以确保 untrusted_index 小于 array1 的长度”更像是“... 在数组中? IMO,如果
array1_length, untrusted_index都是无符号整数,问题应该会消失。建议size_t。
标签: c visual-c++ visual-studio-2017 spectre