“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?

Michael Le Barbier Grünewald
fonte
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.

Basile Starynkevitch
fonte
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.

dan04
fonte
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.

DJ Bazzie Wazzie
fonte
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