Сбой в _snprintf_s() в "ucrtbase.dll" с STATUS_ILLEGAL_INSTRUCTION

Мне стало известно, что мой двоичный файл будет зависать на процессоре без поддержки SSE, за исключением кода 0xC000001D (STATUS_ILLEGAL_INSTRUCTION), несмотря на то, что я компилирую с опцией /arch:IA32, И я был в состоянии отследить точное место, где он падает _snprintf_s() вызывается впервые, он вылетит. Сбой происходит внутри ucrtbase.dll, а не в моем собственном коде.

Интересно, что когда я делаю "полностью статическую" сборку с опцией компилятора /MT, поэтому, чтобы избежать зависимости explicity от ucrtbase.dll, полученный бинарный файл работает просто отлично! Но, как только я скомпилирую точно какой-то код как "разделяемую" сборку, с опцией /MD, он снова потерпит крах в ucrtbase.dll.

Таким образом, может показаться, что "статическая" версия UCRT все еще может работать на ЦП без поддержки SSE, но "общая" (DLL) версия не может. Это несоответствие явно показалось бы мне ошибкой!

Какие-нибудь мысли?


Построить среду:

  • Windows 10 v1803
  • Visual Studio 2017.8 (v15.8.1)
  • Windows SDK v10.0. 17134,12
  • Toolset: v141_xp
  • Опция компилятора: /arch:IA32

Тестовая машина (используется только для тестирования):

  • Процессор: Pentium II
  • ОС: Windows XP с пакетом обновления 3

Примечание: Redist DLLs (ucrtbase.dll + api-ms-win-*.dll) для настройки "разделяемой" сборки были скопированы прямо из C:\Program Files (x86)\Windows Kits\10\Redist\ucrt\DLLs\x86 каталог! Насколько мне известно, это последняя доступная версия этих DLL (v10.0.17134.12).


Даже эта минимальная тестовая программа воспроизведет сбой:

#include <stdio.h>

int main()
{
    char buffer[128];
    _snprintf_s(buffer, 128, _TRUNCATE, "Hello %s!\n", "World!");
    fputs(buffer, stdout);
    getc(stdin);
    return 0;
}

1 ответ

Обновить:

После некоторой дополнительной отладки и возни, я сделал очень интересное наблюдение: "Redist" библиотеки UCRT, содержащиеся в последних vcredist_x86.exe (Распространяемый установщик Microsoft Visual C++ 2017), то есть версия, поставляемая с VS2017.8 (v14.15.26706), на самом деле сильно отличается от тех "Redist" библиотек UCRT, которые можно найти в Redist\ucrt\DLLs\x86 каталог последней версии Windows SDK (v10.0.17134.12):

  • ucrtbase.dll из последней версии Windows SDK
    v10.0.17134.12

  • ucrtbase.dll из последней версии распространяемого установщика Visual C++ 2017:
    v10.0.10586.15

Действительно, теперь я могу подтвердить, что приложение скомпилировано с последней версией Visual C++ 2017 (14.15.26706) и использует /MD Опция корректно работает на процессоре без SSE, если мы используем "старый" ucrtbase.dll версия, как извлечено из последней vcredist_x86.exe Установщик.

Я немного обеспокоен использованием такой старой версии UCRT, если Windows SDK уже предоставляет гораздо более новую версию. Но, по всей видимости, именно этим и занимается Microsoft с помощью распространяемого установщика Visual C++ 2017. Итак, я думаю, это то, что мы должны использовать...


На всякий случай, кто-нибудь в Microsoft читает это:

Вещи могли бы быть намного менее запутанными и подверженными ошибкам для разработчиков программного обеспечения, если бы в Redist\ucrt В каталоге Windows SDK были отдельные подпапки для каждого "воплощения" UCRT - последняя "передовая" версия UCRT и "совместимая" версия UCRT, которую мы фактически должны распространять. Если затем кто-то в Microsoft потратил три минуты на написание небольшого файла README, в котором говорится, какое "воплощение" CRT мы должны выбрать и поместить в Redist\ucrt\README.txt, было бы почти невозможно сделать неправильно...

Другие вопросы по тегам