O "bug de nível 256" no jogo Pacman pode ser considerado um segfault não tratado?

51

Estou tentando explicar as falhas de segmentação para alguém, e estava pensando sobre o kill-screen de nível 256 no Pacman, como é acionado pelo excesso de números inteiros e como o comportamento é semelhante ao "estado desconhecido" frequentemente descrito em uma segmentação. culpa.

Quero dizer que este é um bom exemplo do que chamo de "falha não tratada", mas prefiro ter uma segunda opinião antes de potencialmente espalhar informações erradas.

Tentei procurar, mas tudo o que estou conseguindo são documentos sobre o bug em si, bem como sobre a colaboração entre Hipster Whale e Namco.

Então, você consideraria o comportamento no nível 256 do Pacman um exemplo de violação de segmentação não tratada?

Braden Best
fonte
3
Aqui está uma descrição exata do bug, juntamente com um patch para corrigi-lo: donhodges.com/how_high_can_you_get2.htm
abligh
26
As falhas de segmentação são levantadas pelo hardware, para evitar acesso ilegal à memória. Não sou especialista em Pacman, mas o hardware em que ele executou quase certamente não tinha esse recurso de segurança para começar.
BlueRaja - Danny Pflughoeft 25/01
3
Segundo a wikipedia, Pacman usou um Z80. Os Z80s definitivamente não tinham proteção de memória.
Gort the Robot
Não é um segfault - o sistema não possui nenhuma forma de proteção de memória. A falha que Pac-Man experimenta no nível 256 é simplesmente um excesso de número inteiro que não é tratado corretamente pelo código do jogo.
precisa saber é o seguinte
3
Para sua informação, não acho que isso seja considerado um bug. Um bug é uma falha ou falha em um programa ou sistema de computador que faz com que produza um resultado incorreto ou inesperado ou se comporte de maneiras não intencionais. Foi intencionalmente programado dessa maneira, uma vez que sentimos que ninguém chegaria a esse nível. Na realidade, é apenas um design de software ruim.
Keltari

Respostas:

113

Definitivamente não.

Acessar um endereço de memória que você não alocou é sempre um erro de programação. E agir de acordo com as informações que você obtém produz um comportamento indefinido, isso é preciso. Não tenho idéia para qual plataforma o Pac-man original foi escrito, mas tenho certeza de que exibiu esse comportamento como qualquer outra máquina de von Neumann.

No entanto, "falha de segmentação" é um termo técnico para uma condição muito mais específica. Isso acontece quando o computador detecta automaticamente que isso aconteceu e finaliza o processo, em vez de permitir que comportamento indefinido ocorra. Isso requer um modelo de memória específico (segmentado) com marcação de propriedade sofisticada. Eu não acho que 1980 jogos de arcade tinha isso, e de fato o comportamento do jogo sugere que o erro foi não detectada e o comportamento indefinido que ocorrem.

Kilian Foth
fonte
19
@ B1KMusic: Você está realmente perguntando "este código 'bug' é um exemplo de invocação de comportamento indefinido através do acesso à memória fora dos limites", e a resposta é "sim". Qualquer racionalização sobre capturar, ignorar, não receber um sinal SIGSEGV é apenas uma questão confusa.
Lightness Races com Monica
5
@ B1KMusic nem todas as excedentes de buffer resultam em um segfault. Depende de como a memória foi alocada. Se a memória estiver alocada estaticamente (um grande buffer manualmente dividido em zonas diferentes) e a área imediatamente atrás do último nível for usada para algo (como gráficos de sprites), ela não será falhada.
catraca aberração
6
Esses antigos sistemas arcade usavam sistemas operacionais primitivos que davam ao jogo controle total sobre o hardware, semelhante às versões anteriores do DOS. A idéia de um segfault nesse tipo de arquitetura não é inicial, porque assume que o processo em execução (Pac-Man) não possui toda a memória. Para mais informações, pode-se ler sobre o projeto MAME e seu histórico.
20
O comportamento indefinido não é propriedade das máquinas von Neumann, é propriedade da linguagem C, a linguagem de programação. Os programas escritos em linguagem assembly não podem exibir um comportamento indefinido, porque o comportamento das instruções da linguagem assembly é sempre bem definido (mesmo que os resultados às vezes não sejam especificados).
Dietrich Epp
8
@ Snowman, não existe essa camada em uma máquina Pac-Man. Não há carregador - o jogo está na ROM executada no local. Não há gerenciamento de memória - tudo é estático. Não há "serviços"; o jogo acessa o hardware diretamente e não há um byte de código no sistema que não faça parte do jogo e escrito para o jogo.
hobbs
38

Parece que você está confundindo "comportamento indefinido" e "falha de segmentação".

Não existe um segfault não tratado. Uma falha de segmentação é o tratamento de erros, por definição.

Se você não possui um sistema operacional que detectou o acesso ruim à memória e encerrou o processo por segurança, não há uma falha de segmentação.

Se houver algo, então, este é um bom exemplo de como o UB nem sempre resulta em um segfault.

Corridas de leveza com Monica
fonte
2
Para ser mais preciso, o SO pode decidir matar (ou seja, irrecuperavelmente) o processo. Modern OSs em vez preferem encerrar -lo, o que pode ser capturada e tratada, FWIW.
Edmz
@ black: Não foi isso que eu disse?
Lightness Races com Monica
15
Pode até não ser "comportamento indefinido". Se Pacman foi escrito em assembly puro, o código fez exatamente o que foi solicitado a fazer de uma maneira totalmente definida. Não é um comportamento indefinido, mas apenas um bug. Como tal, o código seria executado exatamente da mesma maneira que em qualquer sistema que tivesse uma porta perfeita do chipset subjacente.
Gort the Robot
@StevenBurnap: Isso é verdade.
Lightness Races com Monica
@black Qual é a diferença entre 'kill' e 'terminate'? Além do fato de que 'kill' é normalmente o vocabulário UNIX, e 'terminate' é mais Windows-y?
Brandin
24

Nenhum desses termos é apropriado para um bug em um jogo arcade programado em linguagem assembly e executado sem o benefício de hardware ou sistema operacional de proteção de memória.

"Comportamento indefinido" é um termo de arte em C e linguagens relacionadas, cunhado pelo comitê de padrões C em 1989. O código tem um comportamento indefinido quando a especificação de linguagem não define o que fará. Não existe tal coisa na linguagem assembly Z80: o efeito de todo código de operação com todas as entradas possíveis é bem definido. O significado convencional em inglês de "comportamento indefinido" pode ser lido para aplicar - a tela de morte é um comportamento não definido pelas pessoas que escreveram o jogo - mas eu não o usaria neste contexto porque é muito provável que dê errado impressão.

"Falha de segmentação" é um termo de arte no POSIX, derivado em última análise do jargão de programação do sistema PDP. As falhas de segmentação acontecem quando um programa tenta acessar um endereço de memória que não é "mapeado" para nada: o hardware e o sistema operacional detectam isso e encerram o programa com defeito, de uma maneira cuidadosamente definida que permite ao programa a chance de se recuperar . Algo comoisso pode ter acontecido como resultado de um bug no programa de jogos Pac-Man, porque a placa de circuito Pac-Man ocupa apenas um pouco menos da metade do espaço de endereço de 64kB do Z80 com ROM, RAM e periféricos, mas eu não Não foi possível descobrir o que o hardware real faria se o software tentasse acessar a memória não mapeada. Seja o que for, seria inapropriado descrever como uma "falha de segmentação", porque o "sistema operacional" do Pac-Man (na medida em que possui um) não é uma implementação do Unix e, novamente, ele daria a impressão errada.

O bug do nível 256, enquanto isso, não acessa a memória não mapeada, por isso é discutível.

É preciso dizer que o jogo possui um bug que se manifesta ao avançar para o nível 256. Também é preciso dizer que a causa raiz do bug é um estouro de número inteiro e que suas conseqüências são corrupção de memória (ou, equivalentemente, violações) de memória e tipo de segurança ). Todos esses termos de uso geral são definidos sem referência a um idioma ou ambiente de SO específico.

Também é preciso observar que os efeitos do bug são semelhantes aos efeitos, em um ambiente moderno, de erros de corrupção de memória que não provocam falhas de segmentação. Se você ler algum dos escritos de exploração do Project Zero , verá uma notável semelhança com a análise de Don Hodges da tela de morte do Pac-Man .

Observe que um emulador que não reproduz fielmente a tela de morte quando alimentado com as ROMs do Pac-Man não está emulando o hardware do jogo corretamente.

zwol
fonte
A frase "comportamento indefinido" pode não ter sido usada impressa exatamente dessa maneira antes de 1989, mas a idéia que essa frase descreve é ​​tão antiga quanto a própria programação. Lisp comum: The Language (Digital Press, 1984; ISBN 0-932376-41-X) usava as palavras "é um erro" para significar exatamente a mesma coisa. Por exemplo, "É um erro chamar esta função com x <0" significava que o programador não deveria permitir que a função fosse chamada com x <0 e que a implementação estava autorizada a fazer literalmente qualquer coisa que o implementador quisesse que fizesse se o programador de aplicativos não cumpriu.
Solomon Slow
5
@ Jameslarge Eu entendo o que você quer dizer, mas ainda acho que é um erro aplicar esse conceito ao Pac-Man. Podemos dizer que a tela de morte é um bug, porque o jogo claramente não está se comportando como planejado pelo designer. Não podemos dizer que o jogo provocou um comportamento indefinido , porque não há especificação de linguagem para dizer "sob nenhuma circunstância o programador pode executar X" por qualquer valor de X. (Suponho que o uso dos opcodes não documentados do Z80 possa se qualificar, exceto que abundância de jogos de arcade fez usar essas e AFAIK todos eles têm efeitos previsíveis).
Zwol
11
Esta é a melhor resposta. "Comportamento indefinido" significa que o codificador escreveu o código para o qual o resultado não pode ser predito com base no padrão. Se o Pacman estiver escrito no assembly Z80 (e acredito que sim), o código escrito terá um significado totalmente definido, independentemente de o programa ter feito algo que o codificador não pretendia.
Gort the Robot
8

O bug de nível 256 no Pac Man resulta na leitura de dados do programa que está além do final da tabela pretendida, mas ainda é um armazenamento legível e na gravação de partes da tela que estão além daquelas que o programa pretende gravar, mas são ainda bem dentro das áreas da tela que o programa está autorizado a escrever . Nenhuma outra área da memória é afetada.

A razão pela qual o bug torna o jogo impossível de jogar é que a máquina determina quando um jogador está comendo pontos examinando o que está na tela e decide que um nível está completo quando o jogador comeu 244 pontos. Ao sobrescrever parte da tela, o bug torna impossível para o jogador comer 244 pontos; consequentemente, o jogo nunca creditará ao jogador a conclusão do nível e recarregará a tela com pontos.

supercat
fonte
11
Quando você se mata no nível 256, os pontos reaparecem, mas você não perde nenhum.
Ave
@ardaozkal: A rotina de desenho de nível apaga mais de 100 pontos e desenha alguns. Se um jogador tivesse vidas suficientes, seria possível comer pontos suficientes para avançar um nível, mas isso exigiria mais de 30 vidas.
Supercat 26/01
Lembro-me de assistir a um vídeo em que o jogador tinha vidas suficientes, e ele conseguiu ... e eu o encontrei .
Ave
@ardaozkal: Quantas vidas são necessárias para limpar o nível e quantas vidas um jogador pode ter em uma máquina não modificada ?
Supercat
Você não pode nem chegar ao nível 256 em uma máquina não modificada.
Ave
1

Como disse antes não, não é uma falha seg. Vou acrescentar por que o problema ocorre: é um estouro .

O número do nível é armazenado em um byte, portanto o intervalo é de 0 a 255. Cada vez que você completa um nível, o contador é incrementado. No nível 256, o contador é de fato 0 devido ao estouro.

No entanto, o jogo tenta exibir algumas frutas na parte inferior do nível. O número / tipo de fruta depende do nível. A fórmula exibe uma fruta por nível final abaixo do nível 8. De acordo com o contador, você está no nível 0 e abaixo do 8. O teste é verdadeiro e você precisa imprimir 255 frutas (o valor do nível antigo). O que é impossível e fornece essa tela com falha.

Romain Picot
fonte