Сбой в _snprintf_s () в "ucrtbase.dll" с STATUS_ILLEGAL_INSTRUCTION - PullRequest
0 голосов
/ 26 августа 2018

Мне стало известно, что мой двоичный файл будет зависать на процессоре без поддержки 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
  • Набор инструментов: v141_xp
  • Опция компилятора: /arch:IA32

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

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

Примечание: Redist DLL (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 Ответ

0 голосов
/ 26 августа 2018

Обновление:

После некоторой дополнительной отладки и возни, я сделал очень интересное наблюдение: «Redist» библиотеки UCRT, содержащиеся в последней vcredist_x86.exe (распространяемый установщик Microsoft Visual C ++ 2017 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

Действительно, теперь я могу подтвердить, что приложение, скомпилированное с latest Visual C ++ 2017 (v14.15.26706) и использующее параметр /MD, работает правильно на non -SSE CPU, пока мы используем «старую» ucrtbase.dll версию, извлеченную из последней vcredist_x86.exe установщика.

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


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

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

...