“Alguma vez mudou o valor de 4?” - como isso entrou no teste de Hayes-Thomas?


24

Em 1989, Felix Lee, John Hayes e Angela Thomas escreveram o teste de Hacker sob a forma de um questionário com muitas piadas internas, como “ Você come bolor de lodo? "

Estou considerando a seguinte série:

0015 Ever change the value of 4?
0016 ... Unintentionally?
0017 ... In a language other than Fortran?

Existe uma anedota específica tornando o número "4" particular na série?

Alguma implementação do Fortran permitiu modificar o valor das constantes? Isso foi possível em outros idiomas de uso comum na época?


2
@ Ordous Não me importo se mantivermos a segunda pergunta aqui, especialmente se os respondentes tomarem o cuidado de explicar por que esse comportamento existe nas linguagens modernas (ou seja, há algum uso prático para isso?). Dito isto, também seria uma excelente pergunta do Code Golf .
— yannis

8
Relacionado: Escreva um programa que produz 2 + 2 = 5 . A Java e Python responde não substituir 4para 5nas listas de números inteiros internados.
— Martijn Pieters

5
E um comentário nessa página indica que você pode redefinir literais no FORTRAN IV; 4 = 5foi possível.
— Martijn Pieters

7
E obrigado pelo link de teste do Hacker. Agora você me fez sentir velho, e horrorizado com a frequência com que eu podia responder 'sim' às perguntas.
— Martijn Pieters

5
Eu mudei o valor da constante zero em um programa fortran uma vez. Esse foi um bug muito difícil de rastrear.
— Bryan Oakley

Respostas:


32

Antigamente (anos 70 e anteriores), alguns computadores não tinham MMU (e isso é verdade hoje para microcontroladores muito baratos).

Nesses sistemas, não há proteção de memória e, portanto, nenhum segmento somente leitura no espaço de endereço , e um programa com erros pode sobrescrever uma constante (na memória de dados ou mesmo dentro do código da máquina).

Os compiladores Fortran na época passaram argumentos formais por referência . Portanto, se você fez CALL FUN(4)e o SUBROUTINE FUN(I)corpo dela está mudando I- por exemplo, com uma declaração I = I + 1no corpo, você pode sofrer um desastre, alterando 4 para 5 no chamador (ou pior).

Isso também aconteceu nos primeiros microcomputadores, como o IBM PC AT original de 1984, com o MS-DOS

FWIW, eu tenho idade suficiente para ter usado, como adolescente no início dos anos 1970, esses computadores: IBM1620 e CAB500 (em um museu: esses são computadores da década de 1960!). O IBM1620 foi bastante divertido: usado em tabelas de memória para adições e multiplicações (e se você sobrescreveu essas tabelas, o caos se seguiu). Portanto, não apenas você pode sobrescrever um 4, mas também pode sobrescrever todas as adições futuras de 2 + 2 ou multiplicações 7 * 8 (mas eu realmente esqueci esses detalhes sujos para que pudesse estar errado).

Hoje, você pode sobrescrever o código do BIOS na memória flash, se estiver perseverante o suficiente. Infelizmente, não me sinto mais tão divertido, então nunca tentei. (Tenho até medo de instalar alguns LinuxBios na minha placa-mãe).

Nos computadores e sistemas operacionais atuais, passar uma constante por referência e alterá-la dentro do receptor apenas provocará uma violação de segmentação , que parece familiar para muitos desenvolvedores de C ou C ++.

BTW: nitpicking: overwriting 4 não é uma questão de linguagem, mas de implementação.


14
O 1620 foi apelidado de CADET: Não é possível adicionar, nem mesmo tentar.
— Pete Becker

O truque pode ser quase repetido mesmo agora com gfortran. As constantes são colocadas em seu segmento e transmitidas por referência a uma sub-rotina. Por padrão, a seção constante é somente leitura, portanto, o erro de proteção de memória mata o programa.
— Netch 30/08/14

7

Foi um efeito colateral não intencional da estratégia de avaliação de chamadas de funções do FORTRAN em combinação com uma otimização de compilador incorreta.

O FORTRAN II introduziu funções e sub-rotinas definidas pelo usuário com seus argumentos passados ​​por referência . (Ora, eu não sei. Provavelmente era mais eficiente do que o valor de passagem no hardware IBM da época.)

Normalmente, passagem por referência significa que você precisa passar um valor l (como uma variável) em vez de um valor r. Mas os designers do FORTRAN decidiram ser úteis e permitir que você transmita valores-r como argumentos de qualquer maneira. O compilador geraria automaticamente uma variável para você. Então, se você escreveu:

CALL SUBFOO(X + Y, 4)

o compilador converteria isso nos bastidores para algo como

TEMP1 = X + Y
TEMP2 = 4
CALL SUBFOO(TEMP1, TEMP2)

Também havia uma otimização de compilador comum chamada “pool literal”, que consolidaria várias instâncias da mesma constante numérica na mesma variável gerada automaticamente. (Vários idiomas da família C exigem isso para literais de string.) Portanto, se você escreveu

CALL SUBBAR(4)
CALL SUBBAZ(4)

isso seria tratado como se fosse

FOUR = 4
CALL SUBBAR(FOUR)
CALL SUBBAZ(FOUR)

o que parece perfeitamente razoável até que você tenha um subprograma que altera o valor de seus parâmetros.

SUBROUTINE SUBBAR(X)
    !...lots of code...
    X = 5
    !...lots of code...
END SUBROUTINE SUBBAR

Estrondo! CALL SUBBAR(4)alterou o valor de 4 no pool literal para 5. E então você fica se perguntando por que SUBBAZestá assumindo que você passou um 5 em vez do que 4você realmente escreveu no código.

As versões mais recentes do Fortran atenuam esse problema, permitindo que você declare a INTENTvariável como INou ou OUTdando um erro (ou pelo menos um aviso) se você passar uma constante como OUTparâmetro.


5

No FORTRAN, quando uma constante é passada para outro procedimento, ela não é mais protegida. É a isso que eles se referem. Outras linguagens de programação populares na mesma época foram C e Pascal, que não tinham (e ainda não têm) esse problema. Talvez existam linguagens de programação mais antigas que eu não conheço e que tenham o mesmo problema.


Além disso, refere-se ao fato de que o pool constante não estava em um segmento somente leitura. Se isso acontecesse, e 4 fosse passado por referência e alterado pelo chamado, o SEGV ocorreria sem alterar com êxito o 4. #
— Basile Starynkevitch

Isso ocorre porque nem todos os sistemas operacionais tinham um segmento somente leitura. A armadilha poderia ser usada no DOS, por exemplo, sistemas operacionais com segmentos somente leitura (usando memória virtual) como o UNIX retornariam um erro de falha de segmentação no tempo de execução. De qualquer forma, o compilador não deve permitir isso.
— dj Bazzie wazzie

4
Estou com saudades de Pascal :(
— Gareth

11
Para ser mais específico, o FORTRAN passa por referência. Portanto, se você passar uma constante como parâmetro de função, poderá alterar esse valor para cada uso desse número.
— Gabe

11
Somente se essa constante (passada por referência) permanecer em um segmento de leitura e gravação. Se estiver em um .rodatasegmento somente leitura (como fazem os compiladores atuais), não alterará a constante, mas causaria um SEGV.
— Basile Starynkevitch
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.