Czy „błąd 256 poziomu” w grze Pacman można uznać za nieobsługiwany błąd?

51

Usiłuję wyjaśnić komuś błędy segmentacji i zastanawiałem się nad ekranem zabijania na poziomie 256 w Pacmanie, jak jest on wywoływany przez przepełnienie liczb całkowitych i jak podobne jest zachowanie do „nieznanego stanu” często opisywanego w segmentacji wina.

Chcę powiedzieć, że jest to dobry przykład tego, co nazywam „nieobsługiwanym segfaultem”, ale wolę uzyskać drugą opinię, zanim potencjalnie rozpowszechnię dezinformację.

Próbowałem to sprawdzić, ale dostaję tylko dokumenty o samym błędzie, a także o współpracy między Hipster Whale a Namco.

Czy zatem uważasz zachowanie na poziomie 256 Pacmana za przykład nieobsługiwanego naruszenia segmentacji?

Braden Best
źródło
3
Oto dokładny opis błędu wraz z łatką do jego naprawy: donhodges.com/how_high_can_you_get2.htm
abligh
26
Błędy segmentacji są podnoszone przez sprzęt, aby uniknąć nielegalnego dostępu do pamięci. Nie jestem ekspertem od Pacmana, ale sprzęt, na którym działał, prawie na pewno nie miał tej funkcji bezpieczeństwa.
BlueRaja - Danny Pflughoeft
3
Według wikipedii Pacman użył Z80. Z80 zdecydowanie nie miał ochrony pamięci.
Gort the Robot
To nie jest awaria - system nie miał żadnej formy ochrony pamięci. Błąd, którego doświadcza Pac-Man na poziomie 256, to po prostu przepełnienie liczb całkowitych, które nie jest poprawnie obsługiwane przez kod gry.
bwDraco
3
Do twojej wiadomości, nie sądzę, że to kwalifikuje się jako błąd. Błąd to awaria lub usterka programu komputerowego lub systemu, która powoduje, że generuje niepoprawny lub nieoczekiwany wynik lub zachowuje się w niezamierzony sposób. Zostało to celowo zaprogramowane w ten sposób, ponieważ uważano, że nikt nie dojdzie do tego poziomu. W rzeczywistości jest to po prostu kiepski projekt oprogramowania.
Keltari

Odpowiedzi:

113

Absolutnie nie.

Uzyskiwanie dostępu do adresu pamięci, który nie został przydzielony, jest zawsze błędem programowania. A działanie w oparciu o informacje, które z nich otrzymujesz, powoduje nieokreślone zachowanie, które jest dokładne. Nie mam pojęcia, dla jakiej platformy został napisany oryginalny Pac-man, ale jestem prawie pewien, że wykazywał takie zachowanie, jak każda inna maszyna von Neumanna.

„Błąd segmentacji” jest jednak terminem technicznym na znacznie bardziej szczegółowy warunek. Dzieje się tak, gdy komputer automatycznie wykrywa, że ​​tak się stało, i kończy proces, a nie zezwala na wystąpienie niezdefiniowanego zachowania. Wymaga to określonego (segmentowanego) modelu pamięci z wyrafinowanym tagowaniem własności. Nie sądzę, 1980 gry zręcznościowe, które miałem, aw rzeczywistości zachowanie gry sugeruje, że błąd był nie wykryte, a niezdefiniowane zachowanie nie występuje.

Kilian Foth
źródło
19
@ B1KMusic: Naprawdę pytasz „czy ten kod jest„ błędem ”, przykładem wywoływania niezdefiniowanego zachowania poprzez dostęp do pamięci poza zakresem”, a odpowiedź brzmi „tak”. Wszelkie racjonalizacje dotyczące łapania, ignorowania, nie otrzymywania sygnału SIGSEGV są po prostu mylące.
Lekkość ściga się z Moniką
5
@ B1KMusic nie wszystkie przepełnienia bufora powodują awarię. To zależy od sposobu przydzielenia pamięci. Jeśli pamięć zostanie przydzielona statycznie (jeden duży bufor ręcznie podzielony na różne strefy), a obszar znajdujący się bezpośrednio za ostatnim poziomem zostanie wykorzystany do czegoś (jak grafika sprite), to nie ulegnie segregacji.
maniak zapadkowy
6
Te stare systemy zręcznościowe używały prymitywnych systemów operacyjnych, które dawały grze prawie pełną kontrolę nad sprzętem, podobnie jak we wczesnych wersjach DOS. Idea segfault w tego typu architekturze nie jest startowa, ponieważ zakłada, że ​​jeden działający proces (Pac-Man) nie jest właścicielem całej pamięci. Aby uzyskać więcej informacji, można przeczytać o projekcie MAME i jego historii.
20
Niezdefiniowane zachowanie nie jest własnością maszyn von Neumanna, jest własnością C, języka programowania. Programy napisane w języku asemblera nie mogą wykazywać nieokreślonego zachowania, ponieważ zachowanie instrukcji języka asemblera jest zawsze dobrze zdefiniowane (nawet jeśli wyniki są czasami nieokreślone).
Dietrich Epp,
8
@ Snowman nie ma takiej warstwy na maszynie Pac-Man. Nie ma modułu ładującego - gra znajduje się w ROM-ie wykonawczym. Nie ma zarządzania pamięcią - wszystko jest statyczne. Nie ma „usług”; gra uzyskuje bezpośredni dostęp do sprzętu i nie ma bajtu kodu w systemie, który nie jest częścią gry i nie jest napisany dla gry.
hobbs
38

Wygląda na to, że mylisz „niezdefiniowane zachowanie” i „błąd segmentacji”.

Nie ma czegoś takiego jak nieobsługiwany błąd. Błąd segmentacji to z definicji obsługa błędów.

Jeśli nie masz systemu operacyjnego, który wykrył zły dostęp do pamięci i zakończył proces dla bezpieczeństwa, oznacza to, że nie występuje błąd segmentacji.

Jeśli tak, to jest to całkiem dobry przykład tego, że UB nie zawsze powoduje awarię.

Lekkość Wyścigi z Moniką
źródło
2
Mówiąc ściślej, system operacyjny może zdecydować o zabiciu (tj. Nieodwracalnie) procesu. Nowoczesne systemy operacyjne wolą zamiast tego go zakończyć , co może zostać przechwycone i obsługiwane przez FWIW.
edmz
@black: Czy to nie to, co powiedziałem?
Lekkość ściga się z Moniką
15
Może to nawet nie być „nieokreślone zachowanie”. Jeśli Pacman został napisany w czystym asemblerze, kod działał dokładnie tak, jak mu kazano, w całkowicie określony sposób. Nie niezdefiniowane zachowanie, ale tylko błąd. W związku z tym kod działałby dokładnie w ten sam sposób, działając na każdym systemie, który miał idealny port bazowego mikroukładu.
Gort the Robot
@StevenBurnap: To prawda.
Lekkość ściga się z Moniką
@black Jaka jest różnica między „zabijaniem” a „zakończeniem”? Poza tym, że „zabijanie” jest zwykle słownictwem w systemie UNIX, a „zakończenie” oznacza więcej Windows-y?
Brandin
24

Żaden z tych terminów nie jest odpowiedni dla błędu w grze zręcznościowej, która została zaprogramowana w języku asemblera i działa bez korzyści sprzętu chroniącego pamięć lub systemu operacyjnego.

„Niezdefiniowane zachowanie” to termin w języku C i językach pokrewnych, ukuty przez komitet normalizacyjny C w 1989 roku. Kod zachowuje się w sposób niezdefiniowany, gdy specyfikacja języka nie określa, co będzie robić. W języku asemblera Z80 nie ma czegoś takiego: efekt każdego kodu operacyjnego przy każdym możliwym wejściu jest dobrze zdefiniowany. Konwencjonalne angielskie znaczenie „niezdefiniowanego zachowania” można odczytać w celu zastosowania - ekran zabójstwa to zachowanie nie zdefiniowane przez ludzi, którzy napisali grę - ale nie użyłbym tego w tym kontekście, ponieważ jest zbyt prawdopodobne, aby podać zły wrażenie.

„Błąd segmentacji” jest terminem w POSIX, wywodzącym się ostatecznie z żargonu programistycznego systemu PDP. Błędy segmentacji występują, gdy program próbuje uzyskać dostęp do adresu pamięci, który nie jest „zmapowany” na nic: sprzęt i system operacyjny wykrywają to i zamykają nieprawidłowo działający program, w dokładnie określony sposób, który umożliwia programowi odzyskanie . Coś jakmogło się to zdarzyć w wyniku błędu w programie do gry Pac-Man, ponieważ płytka drukowana Pac-Man zapełnia pamięć ROM, RAM i urządzenia peryferyjne tylko nieco mniej niż połowę przestrzeni adresowej 64 kB Z80, ale nie mam byłem w stanie dowiedzieć się, co zrobiłby prawdziwy sprzęt, gdyby oprogramowanie próbowało uzyskać dostęp do niezapisanej pamięci. Cokolwiek by to jednak zrobiło, niewłaściwe byłoby opisanie go jako „błąd segmentacji”, ponieważ „system operacyjny” dla Pac-Mana (o ile go ma ) nie jest implementacją Uniksa i, znowu dałoby złe wrażenie.

Tymczasem błąd poziomu 256 nie ma dostępu do niezapisanej pamięci, więc jest dyskusyjny.

Trafne jest stwierdzenie, że w grze występuje błąd, który objawia się po przejściu na poziom 256. Trafne jest również stwierdzenie, że główną przyczyną błędu jest przepełnienie liczb całkowitych , a jego konsekwencjami jest uszkodzenie pamięci (lub, równoważnie, naruszenia) z pamięcią i bezpieczeństwa typu ). Są to wszystkie terminy CS ogólnego przeznaczenia zdefiniowane bez odniesienia do konkretnego języka lub środowiska systemu operacyjnego.

Dokładne jest również zaobserwowanie, że skutki błędu są podobne do skutków błędów w uszkodzeniu pamięci, które nie powodują błędów segmentacji we współczesnym środowisku . Jeśli przeczytasz którykolwiek z opisów exploitów Project Zero , zobaczysz niezwykłe podobieństwo do analizy Dona Hodgesa na ekranie zabicia Pac-Mana .

Zauważ, że emulator, który nie odtwarza wiernie ekranu zabicia po zasileniu ROM-ów Pac-Mana, nie emuluje poprawnie sprzętu gry.

zwol
źródło
Fraza „niezdefiniowane zachowanie” mogła nie zostać użyta w druku dokładnie w ten sposób przed 1989 r., Ale idea, którą opisuje to wyrażenie, jest tak stara jak samo programowanie. Common Lisp: The Language (Digital Press, 1984; ISBN 0-932376-41-X) użył słów „to błąd”, aby oznaczać dokładnie to samo. Np. „Błędem jest wywoływanie tej funkcji za pomocą x <0” oznacza, że ​​programista nie powinien zezwalać na wywoływanie tej funkcji za pomocą x <0 i że implementacja mogła robić dosłownie wszystko, co implementator chciał, aby to zrobiło, jeśli programista aplikacji nie spełnił wymagań.
Solomon Slow
5
@ jameslarge Rozumiem, co masz na myśli, ale nadal uważam, że błędem jest zastosowanie tej koncepcji do Pac-Mana. Można powiedzieć, że ekran zabicia jest błędem, ponieważ gra wyraźnie nie działa zgodnie z zamierzeniami projektanta. Nie możemy powiedzieć, że gra wywołała nieokreślone zachowanie , ponieważ nie ma specyfikacji języka, która mogłaby powiedzieć „pod żadnym pozorem programista nie może wykonać X” dla dowolnej wartości X. (Przypuszczam, że użycie nieudokumentowanych kodów Z80 może się kwalifikować, z wyjątkiem tego, że wiele gier arcade nie używać tych i AFAIK wszystkie one mają skutki przewidywalne).
Zwol
1
To najlepsza odpowiedź. „Niezdefiniowane zachowanie” oznacza, że ​​programista napisał kod, którego wyniku nie można przepowiedzieć na podstawie standardu. Jeśli Pacman jest napisany w asemblerze Z80 (i uważam, że tak było), wówczas napisany kod miał całkowicie zdefiniowane znaczenie, niezależnie od tego, czy program zrobił coś, czego programista nie zamierzał.
Gort the Robot
8

Błąd poziomu 256 w Pac Man powoduje, że program odczytuje dane, które znajdują się poza końcem planowanej tabeli, ale nadal są czytelne , i zapisują fragmenty ekranu, które wykraczają poza te, które program zamierza zapisać, ale są wciąż dobrze w obszarach ekranu, które program może pisać . Nie ma to wpływu na żadne inne obszary pamięci.

Powodem, dla którego błąd uniemożliwia grę, jest to, że maszyna określa, kiedy gracz je kropki, badając zawartość ekranu i decyduje, że poziom jest ukończony, gdy gracz zje 244 kropki. Nadpisując część ekranu, błąd uniemożliwia graczowi zjedzenie 244 kropek; w związku z tym gra nigdy nie przyzna graczowi ukończenia poziomu i przeładuje ekran kropkami.

supercat
źródło
1
Kiedy zabijesz się na poziomie 256, kropki odradzają się, ale ich nie tracisz.
Ave
@ardaozkal: Procedura losowania wymazuje ponad 100 kropek i rysuje kilka. Jeśli gracz miałby wystarczającą liczbę żyć, w końcu byłoby możliwe zjedzenie wystarczającej liczby kropek, aby przejść poziom, ale wymagałoby to więcej niż 30 żyć.
supercat
Pamiętam, jak oglądałem film, w którym gracz miał wystarczająco dużo żyć, a on to zrobił ... i właśnie go znalazłem .
Ave
@ardaozkal: Ile żywotów jest wymaganych do wyczyszczenia poziomu i ile żyć gracz może dostać na niezmodyfikowanej maszynie?
supercat
Nie można nawet dostać się do poziomu 256 na niezmodyfikowanej maszynie.
Ave
1

Jak powiedziano wcześniej nie, to nie jest wina seg. Dodam, dlaczego występuje problem: to przepełnienie .

Numer poziomu jest zapisywany w bajcie, więc zakres wynosi 0-255. Za każdym razem, gdy ukończysz poziom, licznik jest zwiększany. Na poziomie 256 licznik jest w rzeczywistości 0 z powodu przepełnienia.

Jednak gra próbuje wyświetlić niektóre owoce na dole poziomu. Liczba / rodzaj owoców zależy od poziomu. Ta formuła wyświetla jeden owoc na ukończonym poziomie poniżej poziomu 8. Według licznika jesteś na poziomie 0, a więc poniżej 8. Test jest wtedy prawdą i musisz wydrukować 255 owoców (stara wartość poziomu). Co jest niemożliwe i daje ten zepsuty ekran.

Romain Picot
źródło