Il "bug di livello 256" nel gioco di Pacman può essere considerato un segfault non gestito?


51

Sto cercando di spiegare i difetti di segmentazione a qualcuno, e stavo pensando allo kill-screen di livello 256 in Pacman, a come è innescato da un overflow di numeri interi e quanto sia simile il comportamento allo "stato sconosciuto" spesso descritto in una segmentazione colpa.

Voglio dire che questo è un buon esempio di ciò che chiamo un "segfault non gestito", ma preferirei avere una seconda opinione prima di diffondere potenzialmente la disinformazione.

Ho provato a cercarlo, ma tutto quello che sto ricevendo sono documenti sull'errore stesso, così come quella collaborazione tra Hipster Whale e Namco.

Quindi, considereresti il ​​comportamento nel livello 256 di Pacman come un esempio di violazione della segmentazione non gestita?


3
Ecco una descrizione esatta del bug, insieme a una patch per risolverlo: donhodges.com/how_high_can_you_get2.htm
circa

26
Gli errori di segmentazione vengono generati dall'hardware per evitare l'accesso alla memoria illegale. Non sono un esperto di Pacman, ma l'hardware su cui funzionava quasi certamente non aveva questa funzionalità di sicurezza per cominciare.
BlueRaja - Danny Pflughoeft,

3
Secondo Wikipedia Pacman ha usato una Z80. Gli Z80 sicuramente non avevano protezione della memoria.
Gort the Robot

Non è un segfault: il sistema non aveva alcuna forma di protezione della memoria. L'errore che Pac-Man sperimenta al livello 256 è semplicemente un overflow di numeri interi che non è gestito correttamente dal codice del gioco.
bwDraco,

3
Cordiali saluti, non credo che questo si qualifichi come un bug. Un errore è un errore o un errore in un programma per computer o in un sistema che provoca un risultato errato o imprevisto o che si comporta in modo non intenzionale. Fu programmato intenzionalmente in quel modo, poiché si pensava che nessuno sarebbe arrivato a quel livello. In realtà, è solo una cattiva progettazione del software.
Keltari,

Risposte:


113

Sicuramente no.

L'accesso a un indirizzo di memoria non allocato è sempre un errore di programmazione. E agire sulle informazioni che ne ricava produce comportamenti indefiniti, molto accurati. Non ho idea per quale piattaforma sia stata scritta la Pac-man originale, ma sono abbastanza sicuro che abbia mostrato questo comportamento proprio come qualsiasi altra macchina di von Neumann.

Tuttavia, "errore di segmentazione" è un termine tecnico per una condizione molto più specifica. Succede quando il computer rileva automaticamente che ciò è accaduto e termina il processo anziché consentire che si verifichino comportamenti indefiniti. Ciò richiede un modello di memoria specifico (segmentato) con una sofisticata codifica della proprietà. Non credo che 1980 giochi arcade avevano quella, e in effetti il comportamento del gioco suggerisce che l'errore è stato non rilevato, e il comportamento non definito si verifica.


19
@ B1KMusic: stai davvero chiedendo "questo codice" bug "è un esempio di invocazione di comportamenti indefiniti attraverso l'accesso alla memoria fuori dai limiti", e la risposta è "sì". Qualsiasi razionalizzazione nel prendere, ignorare, non ottenere un segnale SIGSEGV è solo confusione.
Lightness Races con Monica il

5
@ B1KMusic non tutti i sovraccarichi del buffer generano un segfault. Dipende da come è stata allocata la memoria. Se la memoria è allocata staticamente (un grosso buffer suddiviso manualmente in diverse zone) e l'area immediatamente dietro l'ultimo livello è stata utilizzata per qualcosa (come la grafica sprite), allora non sarebbe segfault.
maniaco del cricchetto

6
Quei vecchi sistemi arcade utilizzavano sistemi operativi primitivi che davano al gioco il pieno controllo dell'hardware, simile alle prime versioni di DOS. L'idea di un segfault in quel tipo di architettura non è un inizio, perché presuppone che il processo in esecuzione (Pac-Man) non possieda tutta la memoria. Per ulteriori informazioni, si può leggere sul progetto MAME e sulla sua storia.

20
Il comportamento indefinito non è una proprietà delle macchine von Neumann, è una proprietà di C, il linguaggio di programmazione. I programmi scritti in linguaggio assembly non possono presentare comportamenti indefiniti, poiché il comportamento delle istruzioni del linguaggio assembly è sempre ben definito (anche se i risultati a volte non sono specificati).
Dietrich Epp,

8
@Snowman non esiste un tale livello su una macchina Pac-Man. Non c'è alcun caricatore: il gioco è nella ROM di esecuzione sul posto. Non c'è gestione della memoria: tutto è statico. Non ci sono "servizi"; il gioco accede direttamente all'hardware e non c'è un byte di codice sul sistema che non fa parte del gioco e scritto per il gioco.
Hobbs,

38

Sembra che tu confonda "comportamento indefinito" e "errore di segmentazione".

Non esiste un segfault non gestito. Un errore di segmentazione è la gestione degli errori, per definizione.

Se non si dispone di un sistema operativo che ha rilevato l'accesso alla memoria errato e ha terminato il processo per sicurezza, non si verifica un errore di segmentazione.

Semmai, questo è un ottimo esempio di come UB non si traduca sempre in un segfault.


2
Per essere precisi, il sistema operativo può decidere di terminare (cioè irrimediabilmente) il processo. I sistemi operativi moderni preferiscono invece terminarlo , che può essere catturato e gestito, FWIW.
Edmz,

@black: non è quello che ho detto?
Lightness Races con Monica

15
Potrebbe anche non essere un "comportamento indefinito". Se Pacman è stato scritto in puro assemblaggio, il codice ha fatto esattamente quello che gli era stato detto di fare in un modo completamente definito. Comportamento non indefinito, ma semplicemente un bug. Come tale, il codice verrebbe eseguito esattamente allo stesso modo su qualsiasi sistema che avesse una porta perfetta del chipset sottostante.
Gort the Robot

@StevenBurnap: è vero.
Lightness Races con Monica

@black Qual è la differenza tra 'kill' e 'terminate'? A parte il fatto che "kill" è normalmente vocabolario UNIX, e "terminare" è più Windows-y?
Brandin,

24

Nessuno di questi termini è appropriato per un bug in un gioco arcade che è stato programmato in linguaggio assembly e viene eseguito senza beneficio dall'hardware o dal sistema operativo di protezione della memoria.

"Comportamento indefinito" è un termine dell'arte in C e linguaggi correlati, coniato dal comitato per le norme C nel 1989. Il codice ha un comportamento indefinito quando le specifiche del linguaggio non definiscono ciò che farà. Non esiste una cosa del genere nel linguaggio assembly Z80: l'effetto di ogni codice operativo con ogni possibile input è ben definito. Il significato inglese convenzionale di "comportamento indefinito" può essere letto per essere applicato - la schermata di uccisione è un comportamento non definito dalle persone che hanno scritto il gioco - ma non lo userei in questo contesto perché è troppo probabile che dia il torto impressione.

"Errore di segmentazione" è un termine dell'arte in POSIX, derivato in definitiva dal gergo di programmazione del sistema PDP. Gli errori di segmentazione si verificano quando un programma tenta di accedere a un indirizzo di memoria che non è "mappato" a nulla: l'hardware e il sistema operativo lo rilevano e arrestano il programma malfunzionante, in un modo accuratamente definito che consente al programma di recuperare . Qualcosa del generequesto potrebbe essere successo a causa di un bug nel programma di gioco Pac-Man, perché il circuito Pac-Man popola solo poco meno della metà dello spazio degli indirizzi da 64kB dello Z80 con ROM, RAM e periferiche, ma io non ho " non sono riuscito a scoprire cosa farebbe l'hardware reale se il software tentasse di accedere alla memoria non mappata. Qualunque cosa farebbe, tuttavia, sarebbe inappropriato descriverlo come un "errore di segmentazione", poiché il "sistema operativo" per Pac-Man (nella misura in cui ne ha anche uno) non è un'implementazione di Unix e, ancora, darebbe l'impressione sbagliata.

Il bug di livello 256, nel frattempo, non accede alla memoria non mappata, quindi è discutibile.

È esatto dire che il gioco ha un problema che si manifesta su avanzare al livello 256. È anche esatto dire che la causa principale del problema è un integer overflow , e che le sue conseguenze sono il danneggiamento della memoria (o, equivalentemente, violazioni di memoria e tipo di sicurezza ). Questi sono tutti termini CS di uso generale definiti senza riferimento a una lingua o ad un ambiente operativo particolari.

E 'anche preciso osservare che gli effetti del bug sono simili agli effetti, all'interno di un ambiente moderno, di bug di memoria-corruzione che non provocano errori di segmentazione. Se leggi uno qualsiasi degli exploit del Progetto Zero , vedrai una notevole somiglianza con l' analisi di Don Hodges della schermata di uccisione di Pac-Man .

Si noti che un emulatore che non riproduce fedelmente la schermata di interruzione quando viene alimentato le ROM Pac-Man non emula correttamente l'hardware del gioco.


La frase "comportamento indefinito" potrebbe non essere stata usata per la stampa in modo esatto prima del 1989, ma l'idea che quella frase descrive è vecchia quanto la programmazione stessa. Common Lisp: The Language (Digital Press, 1984; ISBN 0-932376-41-X) ha usato le parole "è un errore" per significare esattamente la stessa cosa. Ad esempio, "È un errore chiamare questa funzione con x <0" significa che il programmatore non dovrebbe consentire alla funzione di essere chiamata con x <0 e che l'implementazione era autorizzata a fare letteralmente tutto ciò che l'importatore voleva che facesse se il programmatore dell'applicazione non ha rispettato.
Solomon lento

5
@jameslarge Capisco cosa intendi, ma penso ancora che sia un errore applicare questo concetto a Pac-Man. Possiamo dire che la schermata di uccisione è un bug perché il gioco chiaramente non si comporta come previsto dal progettista. Non possiamo dire che il gioco abbia provocato un comportamento indefinito , perché non esiste alcuna specifica del linguaggio per dire "in nessun caso il programmatore può fare X" per qualsiasi valore di X. (Suppongo che l'uso dei codici operativi non documentati Z80 potrebbe qualificarsi, tranne che molti giochi arcade hanno usato quelli e AFAIK hanno tutti effetti prevedibili.)
zwol

1
Questa è la risposta migliore "Comportamento indefinito" significa che il programmatore ha scritto codice per il quale non è possibile prevedere il risultato in base allo standard. Se Pacman è scritto nell'assembly Z80 (e credo che lo fosse), il codice scritto ha un significato completamente definito indipendentemente dal fatto che il programma abbia fatto qualcosa che il programmatore non intendeva.
Gort the Robot

8

Il bug di livello 256 in Pac Man porta al programma la lettura di dati che si trovano oltre la fine della tabella prevista, ma è comunque di archiviazione leggibile e la scrittura in porzioni dello schermo che vanno oltre quelle che il programma intende scrivere, ma sono ancora ben all'interno delle aree dello schermo che il programma è autorizzato a scrivere . Non sono interessate altre aree di memoria.

Il motivo per cui il bug rende il gioco ingiocabile è che la macchina determina quando un giocatore sta mangiando punti esaminando ciò che è sullo schermo e decide che un livello è completo quando il giocatore ha consumato 244 punti. Sovrascrivendo parte dello schermo, il bug rende impossibile per il giocatore mangiare 244 punti; di conseguenza, il gioco non accrediterà mai al giocatore il completamento del livello e ricaricherà lo schermo con punti.


1
Quando ti uccidi nel livello 256, i punti rinascono, ma non ne perdi nessuno.
Ave,

@ardaozkal: la routine del sorteggio di livello cancella più di 100 punti e ne disegna alcuni. Se un giocatore avesse abbastanza vite, alla fine sarebbe possibile mangiare abbastanza punti per avanzare di livello, ma ciò richiederebbe più di 30 vite.
supercat

Ricordo di aver visto un video in cui il giocatore aveva abbastanza vite, e ci è riuscito ... e l'ho appena trovato .
Ave,

@ardaozkal: quante vite sono necessarie per superare il livello e quante vite può ottenere un giocatore su una macchina non modificata ?
supercat

Non puoi nemmeno arrivare al livello 256 su una macchina non modificata.
Ave,

1

Come detto prima, non è un errore di seg. Aggiungerò il motivo per cui si verifica il problema: è un overflow .

I numeri di livello sono memorizzati su un byte, quindi l'intervallo è 0-255. Ogni volta che completi un livello, il contatore viene incrementato. Al livello 256 il contatore è in effetti 0 a causa dell'overflow.

Tuttavia, il gioco tenta di visualizzare alcuni frutti nella parte inferiore del livello. Il numero / tipo di frutto dipende dal livello. La formula mostra un frutto per livello finito sotto il livello 8. Secondo il contatore sei al livello 0, quindi sotto 8. Il test è vero allora e devi stampare 255 frutti (il vecchio valore di livello). Il che è impossibile e dà questo schermo glitch.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.