"4의 가치를 바꾸는가?"


24

1989 년 펠릭스 리, 존 헤이스, 안젤라 토마스는 내부자 농담으로 퀴즈 형태의 해커 테스트를 작성했습니다 . "

다음 시리즈를 고려하고 있습니다.

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

시리즈에서 숫자 "4"를 만드는 특별한 일화가 있습니까?

일부 포트란 구현에서 상수 값을 수정할 수 있습니까? 그 당시 다른 언어로도 이것이 가능 했습니까?


2
@Ordous 여기서 두 번째 질문을 계속한다면, 특히 응답자들이 왜 그러한 행동이 현대 언어로 존재하는지 (즉, 실용적으로 사용 되는가) 설명 할 때 신경 쓰지 않아도됩니다. 즉 것이라고 말했다 또한 훌륭한 있도록 코드 골프 질문입니다.
yannis

8
관련 : 2 + 2 = 5로 만드는 프로그램을 작성하십시오 . Java 및 Python 답변 은 내부 정수 목록에서 대체 4됩니다 5.
Martijn Pieters

5
그리고 그 페이지에 대한 의견 은 FORTRAN IV에서 리터럴을 재정의 할 수 있다고 말합니다. 4 = 5가능했다.
Martijn Pieters

7
해커의 테스트 링크에 ​​감사드립니다. 당신은 이제 내가 늙었다 고 느끼게 만들었고, 얼마나 자주 질문에 '예'라고 대답 할 수 있는지에 대해 충격을 받았습니다.
Martijn Pieters

5
포트란 프로그램에서 상수 0의 값을 한 번 변경했습니다. 추적하기가 매우 어려운 버그였습니다.
Bryan Oakley

답변:


32

예전 (1970 년대와 그 이전)에는 일부 컴퓨터에 MMU 가 없었습니다 (이것은 오늘날 매우 저렴한 마이크로 컨트롤러에 해당됩니다).

이러한 시스템에서는 메모리 보호 기능이 없으므로 주소 공간 에 읽기 전용 세그먼트가 없으며 버그가있는 프로그램은 상수 (데이터 메모리 또는 머신 코드 내부)를 겹쳐 쓸 수 있습니다.

당시 포트란 컴파일러는 공식적인 인수를 참조로 전달했다 . 당신이 한 그래서 경우 CALL FUN(4)와는 SUBROUTINE FUN(I)변화하는 몸을 가지고 I- 예를 들어 if 문으로 I = I + 1몸에, 당신은 발신자 (또는 악화)에 5에 4를 변경, 재해있을 수 있습니다.

1984 년 최초의 IBM PC AT 와 같은 최초의 마이크로 컴퓨터에서도 마찬가지였습니다. MS-DOS

FWIW, 나는 1970 년대 초 10 대 청소년으로서 IBM1620과 CAB500 컴퓨터 (박물관에서 1960 년대 컴퓨터)를 사용하기에 충분히 나이가 들었습니다. IBM1620은 메모리 테이블에서 덧셈과 곱셈에 사용되었습니다 (이 테이블을 덮어 쓴 경우 혼돈이 발생했습니다). 따라서 4를 덮어 쓸 수있을뿐만 아니라 모든 미래의 2 + 2 추가 또는 7 * 8 곱셈을 덮어 쓸 수도 있습니다 (그러나이 더러운 세부 사항을 잊어 버렸으므로 잘못 될 수 있습니다).

오늘날 충분히 인내한다면 플래시 메모리의 BIOS 코드를 덮어 쓸 수 있습니다. 슬프게도, 나는 더 이상 재미를 느끼지 않기 때문에 결코 시도하지 않았습니다. (마더 보드에 일부 LinuxBios를 설치하는 것이 두렵습니다).

현재 컴퓨터와 운영 체제에서 참조로 상수를 전달하고 수신자 내부에서 변경하면 세그먼트 위반 이 발생하여 많은 C 또는 C ++ 개발자에게 친숙하게 들립니다.

BTW : 질리다 : 4를 덮어 쓰는 것은 언어의 문제가 아니라 구현의 문제입니다.


14
1620의 별명은 CADET : 추가 할 수없고 시도조차하지 않습니다.
피트 베커

트릭은 지금도 거의 반복 될 수 있습니다 gfortran. 상수는 세그먼트에 넣고 서브 루틴을 참조하여 전달됩니다. 기본적으로 상수 섹션은 읽기 전용이므로 메모리 보호 오류로 인해 프로그램이 종료됩니다.
Netch

7

FORTRAN의 함수 호출 평가 전략이 잘못된 컴파일러 최적화와 함께 의도 치 않은 부작용이었습니다.

FORTRAN II는 참조로 전달 된 인수와 함께 사용자 정의 함수 및 서브 루틴을 도입 했습니다 . (왜 모르겠다. 아마도 당시의 IBM 하드웨어에서 가치를 전달하는 것보다 더 효율적이었을 것이다.)

일반적으로 기준 별 통과는 r 값 대신 l 값 (예 : 변수)을 전달해야 함을 의미합니다. 그러나 FORTRAN의 디자이너는 도움이되고 r- 값을 인수로 전달할 수 있도록 결정했습니다. 컴파일러는 자동으로 변수를 생성합니다. 당신이 쓴다면 :

CALL SUBFOO(X + Y, 4)

컴파일러는 이것을 배후에서 다음과 같이 변환합니다.

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

또한“리터럴 풀 (literal pool)”이라는 공통 컴파일러 최적화가 있었는데, 이는 동일한 숫자 상수의 여러 인스턴스를 동일한 자동 생성 변수로 통합합니다. (C 계열의 여러 언어에서는 문자열 리터럴에이 언어가 필요합니다.)

CALL SUBBAR(4)
CALL SUBBAZ(4)

마치 마치 마치

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

매개 변수의 값을 변경하는 서브 프로그램 이 생길 때까지 수행하는 것이 완전히 합리적인 것처럼 보입니다 .

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

팔! CALL SUBBAR(4)리터럴 풀에서 4의 값을 5로 변경했습니다. 그리고 실제로 코드에 작성한 SUBBAZ대신 5를 전달했다고 가정하는 이유 가 궁금 4합니다.

최신 버전의 포트란 INTENT은 변수를 IN또는 로 선언하고 OUT상수를 OUT매개 변수 로 전달하면 오류 (또는 최소한 경고)를 제공 하여이 문제를 완화합니다 .


5

FORTRAN에서 상수가 다른 프로 시저로 전달되면 더 이상 보호되지 않습니다. 그것이 그들이 말하는 것입니다. 같은 시간에 다른 인기있는 프로그래밍 언어는 C와 Pascal 이었고이 문제는 없었습니다. 어쩌면 내가 알지 못하는 오래된 프로그래밍 언어가있을 수도 있습니다.


또한 상수 풀이 읽기 전용 세그먼트에 있지 않다는 사실을 나타냅니다. 만약 4가 참조로 전달되고 수신자에 의해 변경되면, SEGV는 4 를 성공적으로 변경 하지 않고 발생합니다 .
Basile Starynkevitch

모든 OS에 읽기 전용 세그먼트가있는 것은 아니기 때문입니다. 예를 들어 함정은 DOS에서 사용될 수 있습니다. 예를 들어 UNIX와 같은 읽기 전용 세그먼트 (가상 메모리 사용)가있는 운영 체제는 런타임시 세그먼트 화 오류 오류를 반환합니다. 어쨌든 컴파일러는 그것을 허용해서는 안됩니다.
dj bazzie wazzie

4
Pascal이 그립습니다. (
Gareth

1
보다 구체적으로, FORTRAN은 참조로 전달합니다. 따라서 상수를 함수 매개 변수로 전달하면 해당 숫자를 사용할 때마다 해당 값을 변경할 수 있습니다.
Gabe

1
해당 상수 (참조로 전달됨)가 읽기 / 쓰기 세그먼트에 남아있는 경우에만 해당됩니다. .rodata읽기 전용 세그먼트 에 있으면 (현재 컴파일러와 마찬가지로) 변경하면 상수가 변경되지 않지만 SEGV가 발생합니다.
Basile Starynkevitch
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.