Приветствую всех!
Думаю, при упоминании знаменитого бага в процессоре Intel Pentium на ум сразу приходит ошибка деления. Но, как оказывается, она была не единственным косяком этих чипов.

Первые «пеньки» имели ещё одну интересную особенность: существовали «роковые» четыре байта, выполнение которых заставляло компьютер зависнуть намертво. Что же это была за ошибка, как она проявлялась и как её воспроизвести? Сейчас и узнаем.
❯ Суть такова
Наверное, многие кучу раз уже слышали про то, что в некоторых процессорах Intel Pentium существовал дефект, заставляющий их считать неправильно.

Этот косяк стал очень знаменитым и ныне встречается абсолютно в каждой статье в духе «10 самых разрушительных багов тысячелетия».
Но ошибка деления была не единственным багом в данном процессоре. Чуть менее знаменитым, но не менее впечатляющим стал F0 0F, о котором сегодня и пойдёт речь.
❯ Что же это вообще такое?
Немного поговорим о том, что же это вообще за дефект. Итак, некоторые процессоры Pentium (все с микроархитектурой P5) имели аппаратную ошибку: выполнение одной некорректной инструкции вместо исключения приводило к тому, что процессор переставал работать до полной перезагрузки. Сама эта команда (в самом популярном для демонстрации варианте) выглядела так:
lock cmpxchg8b eax
Сама по себе эта инструкция использовалась для сравнения значения данных в регистре с 8 байтами в памяти, а при неправильном её использовании процессор просто бы выдал исключение. Но в сочетании с префиксом lock пенёк блокировал шину памяти и ждал записи, которая так никогда и не происходила. В результате этого он переставал отвечать на любые запросы, в том числе на прерывания, обработчик которых тоже не работал. Команда эта кодировалась байтами F0 0F C7 C8, которые и послужили названием данного дефекта.
Данная ошибка не причиняла никакого вреда компьютеру, а после перезагрузки работоспособность восстанавливалась. Тем не менее, особых привилегий для выполнения «роковых» байт не требовалось, отчего любая программа могла заставить компьютер зависнуть, приведя к потере несохранённых данных или отказу в обслуживании (если инструкция была выполнена на сервере).
В дальнейшем проблема была решена. Сначала программно, путём создания различных патчей для ОС, не дававших выполнить эту инструкцию и повесить ПК, а после и аппаратно — в степпинге B2 баг был ликвидирован. Как удалось найти, дефектные процессоры тоже отзывались и бесплатно менялись, хотя и не в таких количествах, как в случае с ошибкой деления.
❯ Обзор оборудования
Ну что же, перейдём к тестированию.

Для этого нам понадобится компьютер. В качестве него взял уже ранее показанный пень.

Внутри него стоит вот такой камень, как и многочисленные его собратья, подверженный этому багу.

А вот другой пенёк. К нему всё, что будет упомянуто далее, тоже применимо.

Поиск по sSpec это подтверждает: процессор имеет степпинг B1.
❯ Ставим софт
Теперь очередь того, чем мы будем собирать тестовый экзешник. В качестве этого софта взял Microsoft Visual C++ 5.00. Так что включаем компьютер, загружаем Windows 98 и ставим всё необходимое.

Попытки поставить 6.0 или наоборот более ранние версии провалились: одна требовала вставить некий «Disk 1» и в упор не видела установочные файлы, другая требовала наличия лицензионного CD в приводе. То ли мне попался неполный дистрибутив, то ли его обязательно надо было ставить с диска, то ли что, но разбираться с этим я не стал, просто скачал тот архив, где таких проблем не было. Им и оказалась версия 5.00.

Открываем установщик и в открывшемся меню выбираем самый первый пункт. Далее при установке вводим CD-key из одних единиц, а все остальные параметры оставляем по умолчанию.

Спустя минут пятнадцать софт устанавливается.

Всё готово к работе.

Далее создаём проект и пишем какую-нибудь пробную программу, дабы убедиться, что все нужные компоненты встали правильно.
Всё отлично работает. Можно приступать к проверке.
❯ Роковые четыре байта
Итак, удаляем всё, что было, и пишем следующий код:
#include <stdlib.h> char main[] = {0xF0, 0x0F, 0xC7, 0xC8};
После этого собираем проект.

Ну что, момент истины?

Запускаем собранный экзешник. Чёрное окно, один раз мигнувший курсор, и… компьютер зависает наглухо.

Не работает даже переключение светодиодов на клавиатуре. Единственная возможность выйти из этого состояния — жмякнуть кнопку Reset.
❯ А что там на других системах?
Перезагрузим машину и попробуем загрузиться в Windows 2000.

Здесь эта проблема больше не проявляется. То же самое приложение при запуске просто вылетает. Компьютер при этом остаётся работоспособным.

На современном ПК всё ещё проще: пустое окно консоли, закрывающееся через пару секунд.
❯ Что же в итоге?
Как можно видеть, вскоре после того, как ошибка была обнаружена, её уже исправили. В ядре Linux патч для неё появился уже через неделю. Вскоре исправление вышло и для Windows — им стало обновление KB163852. Как мы сами сегодня убедились, поздние версии ОС уже не позволяют так просто заставить ПК зависнуть.
Позже так стали называть и другие схожие по проявлению баги. В частности, некоторые модели процессоров Cyrix тоже могли зависать при выполнении некоторых инструкций.

В Pentium Pro и более поздних процессорах этот баг был исправлен окончательно, на этот раз на аппаратном уровне.
Такие дела.
Новости, обзоры продуктов и конкурсы от команды Timeweb.Cloud — в нашем Telegram-канале ↩

Комментарии (21)

Veska
27.03.2026 10:45Зачем сложности с установкой C++, если debug.exe включен в состав ОС?

MaFrance351 Автор
27.03.2026 10:45Ага, только сейчас дошло. Можно было так же исполнить эти четыре байта и посмотреть, что будет.

unreal_undead2
27.03.2026 10:45Скорее всего будет обычное исключение по неправильной инструкции. debug работает в 16битном режиме, там у этих байтов другой смысл.
В принципе можно сделать копию какого нибудь 32битного EXEшника и тем же debug.exe поменять первые инструкции на f0 0f ... - только надо ещё разобраться, где в файле лежит первая исполняемая инструкция.

MaFrance351 Автор
27.03.2026 10:45Могу попробовать.
Тут ради интереса ещё запустил на x86Box:

Не получилось. Хотя стоит та же Win98, что и на пеньке (я с одного и того же образа ставил).

unreal_undead2
27.03.2026 10:45Можете баг репорт на эмулятор закинуть - поведение отличается от реального железа )

SIISII
27.03.2026 10:45P5 -- не архитектура, а микроархитектура. Ну а архитектура у Пентиумов та же самая, что и у 80386, 486, Пентиумов-2-3-4 и Коре, и официально она называется IA-32.

LeshaRB
27.03.2026 10:45Вы ж вроде уже писали об этом https://habr.com/ru/companies/timeweb/articles/975344/

MaFrance351 Автор
27.03.2026 10:45Здесь про другой дефект, менее известный, но не менее впечатляющий.

mynameco
27.03.2026 10:45я помню под дос, 486, создавал текстовой файл, переименовывал в .com. если там было пусто, комп перезагружался, если туда вписать мусор, то зависал намертво.

ro_user
27.03.2026 10:45Мне кажется, что наглядности не хватает. Было бы эффектнее, если бы завесили NT4 SP2, но не завесили NT4 SP6a, а после применения мер против виндового статического патчера, борющегося с"F00F", завесили и NT4 SP6a.
Для NT4 32 MB RAM - объём, не заставляющий страдать от свопинга.

ro_user
27.03.2026 10:45Или, для демонстрации серьёзности ситуации: завесить сервер непривилегированным юзером. В частности терминальный, nt4 tse.

mayorovp
27.03.2026 10:45Что-то в статье какая-то каша и без дополнительного гугления ничего не понятно.
Сама по себе эта инструкция использовалась для сравнения значения данных в регистре с 8 байтами в памяти, а при неправильном её использовании процессор просто бы выдал исключение.
А чем правильное использование инструкции отличается от неправильного?
На самом деле эта инструкция неправильна в принципе, и при её использовании процессор всегда выдаёт исключение Invalid Opcode. И в этом исключении и проблема - префикс lock некорректно работает когда команда выдаёт исключение Invalid Opcode.
Сначала программно, путём создания различных патчей для ОС, не дававших выполнить эту инструкцию и повесить ПК
Как вообще можно на уровне ОС не давать выполнять непривилегированную инструкцию?
Спасибо @unreal_undead2 что объяснил выше. Разумеется, никакого запрета не было, вместо этого путём манипуляций с таблицами дескрипторов исключение Invalid Opcode заменялось на Page Fault. Видимо, Page Fault был отлажен лучше и не приводил к зависанию.
Tzimie
А как это можно было исправить на уровне ОС если код мог быть создан динамически?
unreal_undead2
Исправлялась обработка исключения по неправильной инструкции (настройкой таблиц прерываний), чтобы процессор не зависал. На вики описано (раздел Workarounds).
zatim
Так ведь там в том то и суть бага, что до обработки исключения дело не доходило.
unreal_undead2
А вы вики читали? Таблицы настраиваются так, чтобы при зачитывании адреса обработчика invalid instruction происходил page fault - и он тогда обрабатывается без блокировки шины и зависания, дальше уже в обработчике page fault детектируем, что на самом деле был invalid instruction и обрабатывем соответственно.
Voldemaar
Спасибо за информацию.