Có bao giờ thay đổi giá trị của 4? Một - làm thế nào điều này đi vào bài kiểm tra Hayes-Thomas?


24

Vào năm 1989, Felix Lee, John Hayes và Angela Thomas đã viết một bài kiểm tra của Hacker dưới dạng một câu đố với nhiều câu chuyện cười trong cuộc, như Bạn có ăn chất nhờn không? Giáo dục

Tôi đang xem xét các loạt sau:

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

Có giai thoại cụ thể nào làm cho số Số 4 đặc biệt trong sê-ri không?

Có phải một số thực hiện Fortran cho phép sửa đổi giá trị của hằng số? Điều này có thể trong các ngôn ngữ khác được sử dụng phổ biến tại thời điểm đó?


2
@Ordous Tôi không phiền nếu chúng tôi giữ câu hỏi thứ hai ở đây, đặc biệt nếu người trả lời cẩn thận giải thích tại sao một hành vi như vậy tồn tại trong các ngôn ngữ hiện đại (tức là có cách sử dụng thực tế nào cho nó không?). Điều đó nói rằng, nó cũng sẽ làm cho một câu hỏi Code Golf xuất sắc .
yannis

8
Liên quan: Viết chương trình tạo 2 + 2 = 5 . Một câu trả lời Java và Python ở đó thay thế 4cho 5trong danh sách số nguyên được thực hiện.
Martijn Pieters

5
Và một bình luận trên trang đó nói rằng bạn có thể xác định lại nghĩa đen trong FORTRAN IV; 4 = 5có khả năng.
Martijn Pieters

7
Và cảm ơn vì liên kết thử nghiệm của Hacker. Bây giờ bạn làm tôi cảm thấy già nua, cũng như kinh hoàng về tần suất tôi có thể trả lời 'có' cho các câu hỏi.
Martijn Pieters

5
Tôi đã thay đổi giá trị của hằng số 0 trong một chương trình fortran. Đó là một lỗi rất khó theo dõi.
Bryan Oakley

Câu trả lời:


32

Ngày xưa (những năm 1970 trở về trước), một số máy tính không có MMU (và điều này đúng cho ngày nay đối với các bộ vi điều khiển rất rẻ).

Trên các hệ thống như vậy, không có bảo vệ bộ nhớ nên không có phân đoạn chỉ đọc trong không gian địa chỉ và chương trình lỗi có thể ghi đè lên hằng số (trong bộ nhớ dữ liệu hoặc thậm chí bên trong mã máy).

Các trình biên dịch Fortran tại thời điểm đó đã thông qua các đối số chính thức bằng cách tham chiếu . Vì vậy, nếu bạn đã làm CALL FUN(4)SUBROUTINE FUN(I)cơ thể của nó thay đổi I- ví dụ như với một tuyên bố I = I + 1trong cơ thể của nó, bạn có thể gặp thảm họa, thay đổi 4 thành 5 trong người gọi (hoặc tệ hơn).

Điều này cũng đúng trên các máy vi tính đầu tiên như IBM PC AT gốc từ năm 1984, với MS-DOS

FWIW, tôi đã đủ tuổi để sử dụng, khi còn là một thanh niên mới lớn vào đầu những năm 1970, những máy tính như vậy: IBM1620 và CAB500 (trong một bảo tàng: đây là những máy tính thời kỳ những năm 1960!). IBM1620 khá thú vị: nó được sử dụng trong các bảng bộ nhớ để bổ sung và nhân (và nếu bạn ghi đè lên các bảng này, sự hỗn loạn xảy ra sau đó). Vì vậy, không chỉ bạn có thể ghi đè lên 4, mà thậm chí bạn có thể ghi đè lên mọi phép cộng 2 + 2 trong tương lai hoặc phép nhân 7 * 8 (nhưng tôi thực sự quên những chi tiết bẩn này nên có thể sai).

Hôm nay, bạn có thể ghi đè mã BIOS vào bộ nhớ flash, nếu bạn đủ kiên trì. Đáng buồn thay, tôi không cảm thấy niềm vui đó nữa, vì vậy tôi không bao giờ thử. (Tôi thậm chí sợ cài đặt một số LinuxBios trên bo mạch chủ của mình).

Trên các máy tính và hệ điều hành hiện tại vượt qua hằng số bằng cách tham chiếu và thay đổi nó bên trong callee sẽ chỉ gây ra vi phạm phân đoạn , nghe có vẻ quen thuộc với nhiều nhà phát triển C hoặc C ++.

BTW: to nitpicking: ghi đè 4 không phải là vấn đề ngôn ngữ, mà là việc thực hiện.


14
1620 có biệt danh CADET: Không thể thêm, thậm chí không thử.
Pete Becker

Thủ thuật có thể được lặp đi lặp lại ngay cả bây giờ với gfortran. Các hằng số được đưa vào phân khúc của chúng và được chuyển qua tham chiếu đến chương trình con. Theo mặc định, phần không đổi là chỉ đọc, do đó lỗi bảo vệ bộ nhớ sẽ giết chương trình.
Lấy

7

Đó là một tác dụng phụ không chủ ý của chiến lược đánh giá cuộc gọi chức năng của FORTRAN kết hợp với tối ưu hóa trình biên dịch sai.

FORTRAN II đã giới thiệu các hàm và chương trình con do người dùng định nghĩa với các đối số được truyền bằng tham chiếu . (Tại sao, tôi không biết. Nó có thể hiệu quả hơn so với giá trị truyền qua trên phần cứng của IBM thời đó.)

Thông thường, tham chiếu qua có nghĩa là bạn phải truyền một giá trị l (giống như một biến) thay vì giá trị r. Nhưng các nhà thiết kế của FORTRAN đã quyết định hữu ích và cho phép bạn vượt qua các giá trị r dưới dạng đối số. Trình biên dịch sẽ tự động tạo một biến cho bạn. Vì vậy, nếu bạn đã viết:

CALL SUBFOO(X + Y, 4)

trình biên dịch sẽ chuyển đổi điều này đằng sau hậu trường thành một cái gì đó như

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

Ngoài ra còn có một tối ưu hóa trình biên dịch phổ biến được gọi là pool pool theo nghĩa đen, có thể hợp nhất nhiều thể hiện của cùng một hằng số vào cùng một biến được tạo tự động. (Một số ngôn ngữ trong họ C yêu cầu điều này cho chuỗi ký tự.) Vì vậy, nếu bạn đã viết

CALL SUBBAR(4)
CALL SUBBAZ(4)

điều này sẽ được đối xử như thể nó là

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

có vẻ như là một điều hoàn toàn hợp lý để làm cho đến khi bạn có một chương trình con thay đổi giá trị của các tham số.

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

Bùng nổ! CALL SUBBAR(4)đã thay đổi giá trị của 4 trong nhóm nghĩa đen thành 5. Và sau đó bạn sẽ tự hỏi tại sao SUBBAZgiả sử bạn vượt qua nó 5 thay vì 4bạn thực sự đã viết trong mã.

Các phiên bản mới hơn của Fortran giảm thiểu vấn đề này bằng cách cho phép bạn khai báo INTENTbiến là INhoặc OUTvà đưa ra lỗi (hoặc ít nhất là cảnh báo) nếu bạn truyền hằng số dưới dạng OUTtham số.


5

Trong FORTRAN, khi một hằng số được truyền cho một thủ tục khác, nó không còn được bảo vệ nữa. Đó là những gì họ đề cập đến. Các ngôn ngữ lập trình phổ biến khác cùng thời đó là C và Pascal không (và vẫn không) có vấn đề này. Có thể có những ngôn ngữ lập trình cũ hơn mà tôi không biết có cùng một vấn đề.


Ngoài ra, nó đề cập đến thực tế là nhóm hằng số không nằm trong phân khúc chỉ đọc. Nếu có, và 4 được thông qua tham chiếu và được thay đổi bởi callee, SEGV sẽ xảy ra mà không thay đổi thành công 4.
Basile Starynkevitch

Đó là bởi vì không phải mọi hệ điều hành đều có phân khúc chỉ đọc. Cạm bẫy có thể được sử dụng trên DOS chẳng hạn, các hệ điều hành có phân đoạn chỉ đọc (sử dụng bộ nhớ ảo) như UNIX sẽ trả về lỗi lỗi phân đoạn trong thời gian chạy. Dù sao, trình biên dịch không nên cho phép nó.
dj bazzie wazzie

4
Tôi nhớ Pascal :(
Gareth

1
Để cụ thể hơn, FORTRAN vượt qua bằng cách tham khảo. Vì vậy, nếu bạn truyền hằng số dưới dạng tham số hàm, bạn có thể thay đổi giá trị đó cho mỗi lần sử dụng số đó.
Gabe

1
Chỉ khi hằng số đó (được truyền bởi tham chiếu) vẫn ở trong phân đoạn đọc-ghi. Nếu nó ở trong một .rodataphân đoạn chỉ đọc (như các trình biên dịch hiện tại làm) thay đổi thì nó sẽ không thay đổi hằng số mà sẽ gây ra SEGV.
Basile Starynkevitch
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.