Обходное решение для предупреждения 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. Уменьшение действия призрака отключено, но компилятор все еще выдает это предупреждение (в сторонней библиотеке)