Приветствую всех!

Думаю, при упоминании знаменитого бага в процессоре 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)


  1. Tzimie
    27.03.2026 10:45

    А как это можно было исправить на уровне ОС если код мог быть создан динамически?


    1. unreal_undead2
      27.03.2026 10:45

      Исправлялась обработка исключения по неправильной инструкции (настройкой таблиц прерываний), чтобы процессор не зависал. На вики описано (раздел Workarounds).


      1. zatim
        27.03.2026 10:45

        Так ведь там в том то и суть бага, что до обработки исключения дело не доходило.


        1. unreal_undead2
          27.03.2026 10:45

          А вы вики читали? Таблицы настраиваются так, чтобы при зачитывании адреса обработчика invalid instruction происходил page fault - и он тогда обрабатывается без блокировки шины и зависания, дальше уже в обработчике page fault детектируем, что на самом деле был invalid instruction и обрабатывем соответственно.


          1. Voldemaar
            27.03.2026 10:45

            Спасибо за информацию.


  1. Veska
    27.03.2026 10:45

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


    1. MaFrance351 Автор
      27.03.2026 10:45

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


      1. unreal_undead2
        27.03.2026 10:45

        Скорее всего будет обычное исключение по неправильной инструкции. debug работает в 16битном режиме, там у этих байтов другой смысл.

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


        1. MaFrance351 Автор
          27.03.2026 10:45

          Могу попробовать.

          Тут ради интереса ещё запустил на x86Box:

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


          1. unreal_undead2
            27.03.2026 10:45

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


            1. MaFrance351 Автор
              27.03.2026 10:45

              Закинул. Ответили, что сомневаются в возможности это реализовать.


  1. SIISII
    27.03.2026 10:45

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


    1. MaFrance351 Автор
      27.03.2026 10:45

      Спасибо за правку.


  1. LeshaRB
    27.03.2026 10:45

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


    1. MaFrance351 Автор
      27.03.2026 10:45

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


  1. Dimon41
    27.03.2026 10:45

    А .com файл из 4х байт не выполнится?


    1. MaFrance351 Автор
      27.03.2026 10:45

      Должен


  1. mynameco
    27.03.2026 10:45

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


  1. ro_user
    27.03.2026 10:45

    Мне кажется, что наглядности не хватает. Было бы эффектнее, если бы завесили NT4 SP2, но не завесили NT4 SP6a, а после применения мер против виндового статического патчера, борющегося с"F00F", завесили и NT4 SP6a.

    Для NT4 32 MB RAM - объём, не заставляющий страдать от свопинга.


    1. ro_user
      27.03.2026 10:45

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


  1. mayorovp
    27.03.2026 10:45

    Что-то в статье какая-то каша и без дополнительного гугления ничего не понятно.

    Сама по себе эта инструкция использовалась для сравнения значения данных в регистре с 8 байтами в памяти, а при неправильном её использовании процессор просто бы выдал исключение.

    А чем правильное использование инструкции отличается от неправильного?

    На самом деле эта инструкция неправильна в принципе, и при её использовании процессор всегда выдаёт исключение Invalid Opcode. И в этом исключении и проблема - префикс lock некорректно работает когда команда выдаёт исключение Invalid Opcode.

    Сначала программно, путём создания различных патчей для ОС, не дававших выполнить эту инструкцию и повесить ПК

    Как вообще можно на уровне ОС не давать выполнять непривилегированную инструкцию?

    Спасибо @unreal_undead2 что объяснил выше. Разумеется, никакого запрета не было, вместо этого путём манипуляций с таблицами дескрипторов исключение Invalid Opcode заменялось на Page Fault. Видимо, Page Fault был отлажен лучше и не приводил к зависанию.