“¿Alguna vez cambiaste el valor de 4?”: ¿Cómo llegó esto al cuestionario de Hayes-Thomas?

24

En 1989, Felix Lee, John Hayes y Angela Thomas escribieron una prueba de Hacker que tomaba la forma de un cuestionario con muchas bromas internas, como “ ¿Comes moldes de limo? "

Estoy considerando la siguiente serie:

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

¿Hay alguna anécdota en particular que haga que el número "4" sea particular en la serie?

¿Alguna implementación de Fortran permitió modificar el valor de las constantes? ¿Era esto posible en otros idiomas de uso común en ese momento?

Michael Le Barbier Grünewald
fuente
2
@Ordous No me importa si mantenemos la segunda pregunta aquí, especialmente si los que responden se ocupan de explicar por qué existe tal comportamiento en los idiomas modernos (es decir, ¿tiene algún uso práctico?). Dicho esto, sería también para hacer un excelente Código Golf cuestión.
Yannis
8
Relacionado: Escriba un programa que haga 2 + 2 = 5 . Un Java y Python respuestas Hay reemplazar 4a 5las listas de números enteros internados.
Martijn Pieters
55
Y un comentario en esa página indica que podría redefinir literales en FORTRAN IV; 4 = 5Fue posible.
Martijn Pieters
77
Y gracias por el enlace de prueba de ese Hacker. Ahora me hacías sentir viejo, y te horrorizabas con la frecuencia con la que podía responder "sí" a las preguntas.
Martijn Pieters
55
Cambié el valor de la constante cero en un programa fortran una vez. Ese fue un error muy difícil de localizar.
Bryan Oakley

Respuestas:

32

En los viejos tiempos (1970 y antes) algunas computadoras no tenían ninguna MMU (y esto es cierto hoy en día para microcontroladores muy baratos).

En tales sistemas, no hay protección de memoria, por lo que no hay un segmento de solo lectura en el espacio de direcciones , y un programa con errores podría sobrescribir una constante (ya sea en la memoria de datos o incluso dentro del código de la máquina).

Los compiladores de Fortran en ese momento pasaron argumentos formales por referencia . Entonces, si lo hizo CALL FUN(4)y SUBROUTINE FUN(I)su cuerpo está cambiando I, por ejemplo, con una declaración I = I + 1en su cuerpo, podría tener un desastre, cambiando 4 a 5 en la persona que llama (o peor).

Esto también fue cierto en los primeros microordenadores como el IBM PC AT original de 1984, con MS-DOS

FWIW, soy lo suficientemente mayor como para haber usado, cuando era adolescente a principios de la década de 1970, tales computadoras: IBM1620 y CAB500 (en un museo: ¡estas son computadoras de la era de la década de 1960!). El IBM1620 fue bastante divertido: se usaba en tablas de memoria para adiciones y multiplicaciones (y si sobrescribió estas tablas, se produjo el caos). Entonces, no solo podría sobrescribir un 4, sino que incluso podría sobrescribir cada futura adición de 2 + 2 o multiplicaciones de 7 * 8 (pero realmente olvidé estos detalles sucios, por lo que podría estar equivocado).

Hoy, puede sobrescribir el código del BIOS en la memoria flash, si es lo suficientemente perseverante. Lamentablemente, ya no me siento tan divertido, así que nunca lo intenté. (Incluso tengo miedo de instalar algunos LinuxBios en mi placa base).

En las computadoras y sistemas operativos actuales, pasar una constante por referencia y cambiarla dentro de la persona que llama solo provocará una violación de la segmentación , que suena familiar para muchos desarrolladores de C o C ++.

Por cierto: ser quisquilloso: sobrescribir 4 no es una cuestión de lenguaje, sino de implementación.

Basile Starynkevitch
fuente
14
El 1620 fue apodado CADET: no se puede agregar, ni siquiera se intenta.
Pete Becker
El truco se puede repetir casi ahora incluso con gfortran. Las constantes se colocan en su segmento y se pasan por referencia a una subrutina. Por defecto, la sección constante es de solo lectura, por lo que el error de protección de memoria mata el programa.
Netch
7

Fue un efecto secundario involuntario de la estrategia de evaluación de llamadas de función de FORTRAN en combinación con una optimización de compilador errónea.

FORTRAN II introdujo funciones y subrutinas definidas por el usuario con sus argumentos pasados ​​por referencia . (Por qué, no lo sé. Probablemente fue más eficiente que el paso por valor en el hardware de IBM de la época).

Normalmente, pasar por referencia significa que tiene que pasar un valor l (como una variable) en lugar de un valor r. Pero los diseñadores de FORTRAN decidieron ser útiles y permitirle pasar valores r como argumentos de todos modos. El compilador generaría automáticamente una variable para usted. Entonces, si escribiste:

CALL SUBFOO(X + Y, 4)

el compilador convertiría esto detrás de escena en algo como

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

También había una optimización común del compilador llamada "grupo literal", que consolidaría múltiples instancias de la misma constante numérica en la misma variable autogenerada. (Varios lenguajes de la familia C requieren esto para los literales de cadena). Entonces, si escribió

CALL SUBBAR(4)
CALL SUBBAZ(4)

esto se trataría como si fuera

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

lo cual parece una cosa perfectamente razonable que hacer hasta que tenga un subprograma que cambie el valor de sus parámetros.

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

¡Auge! CALL SUBBAR(4)cambió el valor del 4 en el grupo literal a un 5. Y luego se pregunta por qué SUBBAZestá asumiendo que pasó un 5 en lugar del 4que realmente escribió en el código.

Las versiones más nuevas de Fortran mitigan este problema al permitirle declarar la INTENTvariable como INo OUT, y al darle un error (o al menos una advertencia) si pasa una constante como OUTparámetro.

dan04
fuente
5

En FORTRAN, cuando se pasa una constante a otro procedimiento, ya no está protegida. A eso se refieren. Otros lenguajes de programación populares en ese mismo tiempo fueron C y Pascal que no tenían (y aún no tienen) este problema. Tal vez hay lenguajes de programación más antiguos que no conozco que tengan el mismo problema.

dj bazzie wazzie
fuente
Además, se refiere al hecho de que el grupo constante no estaba en un segmento de solo lectura. Si lo hiciera, y 4 se pasa por referencia, y la persona que llama cambia, SEGV sucedería sin cambiar con éxito 4.
Basile Starynkevitch
Esto se debe a que no todos los sistemas operativos tenían un segmento de solo lectura. La trampa podría usarse en DOS, por ejemplo, los sistemas operativos con segmentos de solo lectura (que usan memoria virtual) como UNIX devolverían un error de falla de segmentación en tiempo de ejecución. De todos modos, el compilador no debería permitirlo.
dj bazzie wazzie
44
Echo de menos a Pascal :(
Gareth
1
Para ser más específico, FORTRAN pasa por referencia. Entonces, si pasa una constante como parámetro de función, puede cambiar ese valor para cada uso de ese número.
Gabe
1
Solo si esa constante (aprobada por referencia) permanece en un segmento de lectura-escritura. Si está en un .rodatasegmento de solo lectura (como lo hacen los compiladores actuales), cambiarlo no alterará la constante, pero provocaría un SEGV.
Basile Starynkevitch