Можно ли считать «ошибку уровня 256» в игре Pacman необработанным сегфоутом?

51

Я пытаюсь объяснить кому-то ошибки сегментации, и я размышлял об уровне экрана уничтожения 256 в Pacman, и о том, как он вызывается целочисленным переполнением, и о том, как поведение похоже на «неизвестное состояние», часто описываемое в сегментации неисправность.

Я хочу сказать, что это хороший пример того, что я называю «необработанным сегфоутом», но я бы предпочел получить второе мнение, прежде чем распространять дезинформацию.

Я попытался найти его, но все, что я получаю, это документы о самой ошибке, а также о том, что произошло между Hipster Whale и Namco.

Итак, считаете ли вы поведение на уровне 256 Пакмана примером необработанного нарушения сегментации?

Брэден Бест
источник
3
Вот точное описание ошибки, а также патч для ее исправления: donhodges.com/how_high_can_you_get2.htm
abligh
26
Ошибки сегментации вызываются аппаратными средствами, чтобы избежать несанкционированного доступа к памяти. Я не эксперт по Pacman, но оборудование, на котором он работал, почти наверняка не имело этой функции безопасности с самого начала.
BlueRaja - Дэнни Пфлюгофт
3
Согласно википедии Пакман использовал Z80. У Z80s точно не было защиты памяти.
Gort the Robot
Это не ошибка, система не имела какой-либо формы защиты памяти. Ошибка, которую испытывает Pac-Man на уровне 256, является просто переполнением целого числа, которое неправильно обрабатывается кодом игры.
bwDraco
3
К вашему сведению, я не думаю, что это квалифицируется как ошибка. Ошибка - это сбой или сбой в компьютерной программе или системе, который приводит к неверному или неожиданному результату или ведет себя непреднамеренно. Это было специально запрограммировано таким образом, так как считалось, что никто не достигнет этого уровня. На самом деле это просто плохой дизайн программного обеспечения.
Келтари

Ответы:

113

Точно нет.

Доступ к адресу памяти, который вы не выделяли, всегда является ошибкой программирования. И действие на информации, которую вы получаете от нее, приводит к неопределенному поведению, это очень точно. Я понятия не имею, для какой платформы был написан оригинальный Pac-man, но я почти уверен, что он демонстрировал это поведение, как и любая другая машина фон Неймана.

Тем не менее, «ошибка сегментации» является техническим термином для гораздо более конкретного условия. Это происходит, когда компьютер автоматически обнаруживает, что это произошло, и завершает процесс, а не допускает неопределенного поведения. Для этого требуется специальная (сегментированная) модель памяти со сложными тегами владения. Я не думаю , что 1980 аркадных игр было что, и в самом деле поведение игры предполагает , что ошибка была не обнаружена, и неопределенное поведение было произойти.

Килиан Фот
источник
19
@ B1KMusic: Вы на самом деле спрашиваете: «Является ли этот код« багом », примером вызова неопределенного поведения через доступ за пределы памяти?», И ответ «да». Любые рассуждения о ловле, игнорировании, не получении сигнала SIGSEGV просто сбивают с толку.
Легкость гонок с Моникой
5
@ B1KMusic не все переполнения буфера приводят к segfault. Это зависит от того, как была выделена память. Если память статически распределена (один большой буфер разделен вручную на разные зоны) и область, расположенная сразу за последним уровнем, использовалась для чего-то (например, для спрайтовой графики), то она не будет работать по умолчанию.
фрик с трещоткой
6
В этих старых аркадных системах использовались примитивные ОС, которые давали игре полный контроль над оборудованием, подобно ранним версиям DOS. Идея сегментарного сбоя в архитектуре такого типа не является началом, поскольку предполагает, что один запущенный процесс (Pac-Man) не владеет всей памятью. Для получения дополнительной информации можно прочитать о проекте MAME и его истории.
20
Неопределенное поведение не является свойством машин фон Неймана, это свойство C, языка программирования. Программы, написанные на ассемблере, не могут демонстрировать неопределенное поведение, потому что поведение инструкций на ассемблере всегда четко определено (даже если результаты иногда не определены).
Дитрих Эпп
8
@ Снеговик, нет такого слоя на машине Pac-Man. Загрузчика нет - игра находится в ПЗУ «Выполнить на месте». Там нет управления памятью - все статично. Там нет "услуг"; игра напрямую обращается к оборудованию, и в системе отсутствует байт кода, который не является частью игры и написан для игры.
Хоббс
38

Похоже, вы путаете «неопределенное поведение» и «ошибка сегментации».

Не существует такого понятия, как необработанное сегфо. Ошибка сегментации - обработка ошибок по определению.

Если у вас нет ОС, которая обнаружила плохой доступ к памяти и остановила процесс в целях безопасности, то у вас нет ошибки сегментации.

Во всяком случае, это довольно хороший пример того, как UB не всегда приводит к segfault.

Гонки легкости с Моникой
источник
2
Чтобы быть точным, ОС может решить убить (т.е. безвозвратно) процесс. Современные ОС вместо этого предпочитают прекратить его, что может быть перехвачено и обработано, FWIW.
edmz
@black: Разве это не то, что я сказал?
Легкость гонки с Моникой
15
Это может даже не быть "неопределенным поведением". Если Пакман был написан в чистом виде, то код делал именно то, что ему было сказано, совершенно определенным образом. Не неопределенное поведение, а просто ошибка. Таким образом, код будет работать точно так же, работая на любой системе, у которой есть идеальный порт базового чипсета.
Gort the Robot
@StevenBurnap: это правда.
Легкость гонок с Моникой
@black В чем разница между «убить» и «прекратить»? Кроме того факта, что «kill» - это, как правило, словарь UNIX, а «terminate» - больше Windows-y?
Брандин
24

Ни один из этих терминов не подходит для ошибки в аркадной игре, которая была запрограммирована на ассемблере и работает без использования аппаратных средств защиты памяти или операционной системы.

«Неопределенное поведение» - это термин «искусство» на C и родственных языках, разработанный Комитетом по стандартам C еще в 1989 году. Код имеет неопределенное поведение, когда спецификация языка не определяет, что он будет делать. В ассемблере Z80 такого нет: эффект каждого кода операции с каждым возможным вводом четко определен. Общепринятое английское значение «неопределенного поведения» можно прочитать, чтобы применить - экран уничтожения - это поведение, не определенное людьми, которые написали игру, - но я бы не стал использовать его в этом контексте, потому что это слишком вероятно, чтобы дать неверное представление впечатление.

«Ошибка сегментации» - это современный термин в POSIX, полученный в конечном итоге из жаргона программирования системы PDP. Ошибки сегментации возникают, когда программа пытается получить доступ к адресу памяти, который ни на что не «привязан»: аппаратное обеспечение и операционная система обнаруживают это и закрывают неисправную программу тщательно определенным способом, который дает программе возможность восстановить , Что-то вродеэто могло произойти из-за ошибки в игровой программе Pac-Man, потому что печатная плата Pac-Man заполняет чуть менее половины 64-килобайтного адресного пространства Z80 ПЗУ, ОЗУ и периферийными устройствами, но у меня нет Я не смог выяснить, что будет делать реальное оборудование, если оно попытается получить доступ к неотображенной памяти. Что бы это ни делало, это было бы неуместно называть «ошибкой сегментации», потому что «операционная система» для Pac-Man (в той степени, в которой она даже есть ) не является реализацией Unix и, опять же, она даст неправильное впечатление.

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

Можно с уверенностью сказать, что в игре есть ошибка, которая проявляется при переходе на уровень 256. Также можно с уверенностью сказать, что основной причиной ошибки является целочисленное переполнение и что ее последствия - повреждение памяти (или, что то же самое, нарушение из памяти и безопасности типа ). Все это термины CS общего назначения, определенные без ссылки на какой-либо конкретный язык или среду ОС.

Точно также можно заметить, что последствия ошибки аналогичны последствиям в современной среде ошибок повреждения памяти, которые не вызывают ошибок сегментации. Если вы прочтете какие-либо описания эксплойтов Project Zero , вы увидите замечательное сходство с анализом Дона Ходжеса экрана убийства Pac-Man .

Обратите внимание, что эмулятор, который точно не воспроизводит экран уничтожения при загрузке ПЗУ Pac-Man, неправильно эмулирует игровое оборудование.

zwol
источник
Фраза «неопределенное поведение», возможно, не использовалась в печати таким же образом до 1989 года, но идея, которую описывает эта фраза, так же стара, как само программирование. Common Lisp: The Language (Digital Press, 1984; ISBN 0-932376-41-X) использовал слова «это ошибка», чтобы обозначать одно и то же. Например, «вызывать эту функцию с x <0 ошибочно» означало, что программист не должен позволять вызывать функцию с x <0 и что реализации было разрешено делать буквально все, что хотел исполнитель, если программист приложения не соблюдает.
Соломон Слоу
5
@jameslarge Я понимаю, что вы имеете в виду, но все же считаю ошибкой применять эту концепцию к Pac-Man. Можно сказать, что экран уничтожения является ошибкой, потому что игра явно не ведет себя так, как задумал дизайнер. Мы не можем сказать, что игра вызвала неопределенное поведение , потому что нет спецификации языка, которая бы говорила: «Ни при каких обстоятельствах программист не может делать X» для любого значения X. (Полагаю, использование недокументированных кодов операций Z80 может быть приемлемо, за исключением того, что множество аркадных игр действительно использовали их, и AFAIK все они имеют предсказуемые эффекты.)
zwol
1
Это лучший ответ. «Неопределенное поведение» означает, что кодер написал код, для которого результат не может быть предсказан на основе стандарта. Если Pacman написан на сборке Z80 (и я верю, что это так), то написанный код имел полностью определенное значение независимо от того, что программа сделала то, чего не хотел кодер.
Gort the Robot
8

Ошибка уровня 256 в Pac Man приводит к тому, что программа читает данные, которые находятся за пределами предполагаемой таблицы, но все еще остается читаемым хранилищем , и записывает в те части экрана, которые находятся за пределами тех, которые программа намеревается записать, но все еще хорошо в тех областях экрана, которые разрешено писать программе . Другие области памяти не затрагиваются.

Причина, по которой ошибка делает игру непригодной для игры, состоит в том, что машина определяет, когда игрок ест точки, изучая то, что на экране, и решает, что уровень завершен, когда игрок съел 244 точки. Перезаписывая часть экрана, ошибка делает невозможным для игрока съесть 244 точки; следовательно, игра никогда не даст игроку возможность пройти уровень и перезагрузит экран точками.

Supercat
источник
1
Когда вы убиваете себя на уровне 256, точки возрождаются, но вы их не теряете.
Авен
@ardaozkal: Процедура прорисовки уровня стирает более 100 точек и рисует несколько. Если бы у игрока было достаточно жизней, в конечном итоге можно было бы съесть достаточно точек, чтобы повысить уровень, но для этого потребовалось бы более 30 жизней.
суперкат
Я помню, как смотрел видео, где у игрока было достаточно жизней, и ему это удалось ... и я только что нашел его .
Авен
@ardaozkal: Сколько жизней требуется, чтобы очистить уровень, и сколько жизней может получить игрок на неизмененной машине?
суперкат
Вы даже не можете добраться до 256 уровня на неизмененном компьютере.
Авен
1

Как уже говорилось, нет, это не ошибка сегмента. Я добавлю, почему проблема возникает: это переполнение .

Номер уровня хранится в байте, поэтому диапазон составляет 0-255. Каждый раз, когда вы проходите уровень, счетчик увеличивается. На уровне 256 счетчик фактически равен 0 из-за переполнения.

Однако в игре постарайтесь отобразить некоторые фрукты в нижней части уровня. Количество / тип плодов зависит от уровня. Формула отображает один фрукт на готовый уровень ниже уровня 8. Согласно счетчику вы находитесь на уровне 0, то есть ниже уровня 8. Тогда тест верен, и вы должны напечатать 255 фруктов (старое значение уровня). Что невозможно и дает этот сбойный экран.

Romain Picot
источник