Обходное решение для предупреждения Spectre MSVC C5040
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 меньше длины массива 1. Это необходимо для обеспечения того, чтобы программа не читала за пределами массива. Хотя это кажется звуковым как написано, он не учитывает микроархитектурное поведение ЦП с использованием спекулятивного исполнения ".
Итак, теперь вы получаете предупреждение:
Предупреждение C5045: Компилятор введет смягчение Spectre для загрузки памяти, если /Qspectre switch указан
Каков его способ сказать вам, что этот код может оказаться медленнее, чем вам может захотеть (если он скомпилирован /Qspectre), потому что он собирается внести некоторые дополнительные меры защиты.
Поскольку, похоже, вы ничего не можете принять как должное, я с подозрением отношусь к изменениям, которые "просто заставляют предупреждение уходить". Например, изменение этого параметра происходит следующим образом: для примера экземпляра кода MCVE, который я приводил здесь, кажется, это делает untrusted_index < array1_length
в untrusted_index != array1_length
. Но разве это жизнеспособный патч, или их предупреждение просто неполное - и в следующем обновлении он тоже будет жаловаться?
Я знаю, что могу отключить предупреждение с помощью /wd5040 или иначе. Но я заинтересован в том, чтобы убедиться, что если код скомпилирован с /Qspectre, что нет замедлений и что нет предупреждений, если он не скомпилирован с /Qspectre. Я не хочу обходить касание файлов, изменяя <
to !=
В условиях цикла - или что-то еще - если это просто оттолкнуть.
Таким образом, более серьезный вопрос заключается в том, что существуют закономерные шаблоны обходных путей, которые являются основными, почему нет упоминаний о них? Например, случай, который я описываю, - это итерация, в которой я управляю индексом, и не нужно беспокоиться об этом, исходя из "ненадежного источника". Но я получил предупреждение, и переход от <
to !=
Заставил его уйти. Зачем? Должно ли это быть?
Ответы
Ответ 1
Из самой статьи:
Важно отметить, что существуют ограничения на анализ, который MSVC и компиляторы в целом могут выполнять при попытке идентифицировать экземпляры варианта 1. Таким образом, нет гарантии, что все возможные экземпляры варианта 1 будут использоваться в /Qspectre.
Вероятно, вы столкнулись с одним из случаев, когда текущая реализация /Qspectre не уменьшает уязвимость по дизайну. Это разумно, потому что чрезмерное использование LFENCE может значительно снизить производительность. Смягчение каждого экземпляра варианта 1, которое появляется в коде, слишком дорого, чтобы полностью выполняться в программном обеспечении (используя LFENCE).
В комментариях кто-то спросил:
Можете ли вы охарактеризовать для разработчиков, какие ограничения для MSVC, и что еще нужно сделать разработчикам, чтобы защитить себя от "варианта 1"?
Автор статьи ответил:
Не входила в подробности реализации MSVC. Многие люди и компании полагаются на наши инструменты, поэтому собирались ошибиться с осторожностью в отношении того, что мы обсуждаем публично.
Поэтому Microsoft, похоже, не хочет раскрывать, какие экземпляры варианта 1 не будут смягчены /Qspectre.
Ответ 2
Если вы не хотите, чтобы предупреждение просто использовало предупреждение #pragma (отключить: 5040) или отключить его на странице свойств проекта.
Обратите внимание, что предложенное вами изменение на "untrusted_index! = Array1_length" недостаточно, поскольку оно оставляет весь диапазон больше, чем размер, открытый для злоупотребления.
Помните, что эта диагностика просто говорит вам, что компилятор сделает что-то другое, чем раньше, с включенным смягчением призраков, это не означает, что вам обязательно нужно что-то делать с кодом.
Ответ 3
У меня есть старый проект, который хорошо скомпилирован в Visual Studio 2017, но его нельзя скомпилировать в Visual Studio 2019 из-за предупреждения C5045. Уменьшение действия призрака отключено, но компилятор все еще выдает это предупреждение (в сторонней библиотеке)