“ เคยเปลี่ยนค่าของ 4 หรือไม่?” - สิ่งนี้เกิดขึ้นได้อย่างไรในแบบทดสอบ Hayes-Thomas


24

ในปี 1989 เฟลิกซ์ลีจอห์นเฮย์สและแองเจลาโทมัสเขียนทดสอบแฮกเกอร์รูปแบบของการตอบคำถามที่มีเรื่องตลกภายในหลาย ๆ ขณะที่“ คุณกินเมือกแม่พิมพ์?

ฉันกำลังพิจารณาชุดต่อไปนี้:

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

มีเกร็ดเล็กเกร็ดน้อยเกี่ยวกับการสร้างหมายเลข“ 4” โดยเฉพาะในซีรี่ส์หรือไม่?

การใช้ Fortran บางอย่างอนุญาตให้แก้ไขค่าของค่าคงที่หรือไม่ เป็นไปได้ในภาษาอื่นที่ใช้งานทั่วไปในเวลานั้นหรือไม่?


2
@ เออร์ดิสฉันไม่รังเกียจหรอกถ้าเราเก็บคำถามที่สองไว้ที่นี่โดยเฉพาะถ้าผู้ตอบตอบระมัดระวังอธิบายว่าทำไมพฤติกรรมดังกล่าวจึงมีอยู่ในภาษาสมัยใหม่ ที่กล่าวว่ามันจะยังทำให้การที่ดีเยี่ยมรหัสกอล์ฟคำถาม
yannis

8
ที่เกี่ยวข้อง: เขียนโปรแกรมที่ทำให้ 2 + 2 = 5 จาวาและ Python ตอบมีแทน4สำหรับ5ใน interned รายการจำนวนเต็ม
Martijn Pieters

5
และความคิดเห็นในหน้านั้นระบุว่าคุณสามารถกำหนดตัวอักษรใหม่ใน FORTRAN IV; 4 = 5เป็นไปได้
Martijn Pieters

7
และขอขอบคุณสำหรับลิงค์ทดสอบของแฮ็กเกอร์ ตอนนี้คุณทำให้ฉันรู้สึกแก่เฒ่ารวมไปถึงความน่าสะพรึงกลัวว่าฉันจะตอบคำถาม 'ใช่' บ่อยแค่ไหน
Martijn Pieters

5
ฉันเปลี่ยนค่าของค่าคงที่ศูนย์ในโปรแกรม Fortran หนึ่งครั้ง นั่นเป็นข้อผิดพลาดที่ยากมากในการติดตาม
ไบรอัน Oakley

คำตอบ:


32

ในสมัยก่อน (1970 และก่อนหน้า) คอมพิวเตอร์บางเครื่องไม่มีMMU (และนี่เป็นความจริงในปัจจุบันสำหรับไมโครคอนโทรลเลอร์ที่มีราคาถูกมาก)

ในระบบดังกล่าวไม่มีการป้องกันหน่วยความจำจึงไม่มีเซ็กเมนต์แบบอ่านอย่างเดียวในพื้นที่ที่อยู่และโปรแกรม buggy สามารถเขียนทับค่าคงที่ (ทั้งในหน่วยความจำข้อมูลหรือแม้แต่ในรหัสเครื่อง)

คอมไพเลอร์ Fortran ในเวลานั้นอย่างเป็นทางการผ่านการขัดแย้งโดยการอ้างอิง ดังนั้นถ้าคุณทำCALL FUN(4)และสิ่งSUBROUTINE FUN(I)นั้นเปลี่ยนแปลงร่างกายI- เช่นด้วยคำแถลงI = I + 1ในร่างกายคุณอาจประสบภัยพิบัติเปลี่ยนเป็น 4 ใน 5 ในผู้โทร (หรือแย่กว่านั้น)

สิ่งนี้ก็เป็นจริงเช่นกันในไมโครคอมพิวเตอร์ตัวแรกเช่นIBM PC ATดั้งเดิมตั้งแต่ปี 1984 ด้วย MS-DOS

FWIW ฉันอายุมากพอที่จะใช้เป็นวัยรุ่นวัยต้นปี 1970 คอมพิวเตอร์เช่น IBM1620 และ CAB500 (ในพิพิธภัณฑ์: คอมพิวเตอร์ยุคนี้เป็นยุค 1960!) IBM1620 ค่อนข้างสนุก: มันใช้ในตารางหน่วยความจำสำหรับการเพิ่มและการคูณ (และถ้าคุณเขียนทับตารางเหล่านี้จะเกิดความโกลาหล) ดังนั้นไม่เพียง แต่คุณสามารถเขียนทับ 4 แต่คุณสามารถเขียนทับทุก 2 + 2 นอกจากนี้ในอนาคตหรือการคูณ 7 * 8 (แต่ฉันลืมรายละเอียดที่สกปรกเหล่านี้ดังนั้นอาจผิด)

วันนี้คุณอาจเขียนทับรหัส BIOS ในหน่วยความจำแฟลชถ้าคุณมีความพยายามมากพอ น่าเศร้าที่ฉันไม่รู้สึกสนุกอีกต่อไปดังนั้นฉันจึงไม่เคยลอง (ฉันกลัวที่จะติดตั้ง LinuxBios บางตัวบนเมนบอร์ดของฉัน)

ในคอมพิวเตอร์ปัจจุบันและระบบปฏิบัติการที่ผ่านค่าคงที่โดยการอ้างอิงและการเปลี่ยนแปลงภายใน callee เพียงแค่จะก่อให้เกิดการละเมิดการแบ่งส่วนซึ่งฟังดูคุ้นเคยกับนักพัฒนา C หรือ C ++ หลายคน

BTW: การเป็น nitpicking: การเขียนทับ 4 ไม่ใช่เรื่องของภาษา แต่เป็นการใช้งาน


14
1620 ได้รับฉายาว่า CADET: ไม่สามารถเพิ่มได้หรือแม้แต่ลอง
Pete Becker

gfortranเคล็ดลับที่สามารถทำซ้ำเกือบแม้ตอนนี้ด้วย ค่าคงที่จะถูกใส่เข้าไปในส่วนของพวกเขาและผ่านการอ้างอิงไปยังรูทีนย่อย ตามค่าเริ่มต้นส่วนค่าคงที่เป็นแบบอ่านอย่างเดียวดังนั้นข้อผิดพลาดในการป้องกันหน่วยความจำก็จะทำให้โปรแกรมฆ่าได้
Netch

7

มันเป็นผลข้างเคียงที่ไม่ได้ตั้งใจของกลยุทธ์การประเมินการเรียกใช้ฟังก์ชันของ FORTRAN ร่วมกับการเพิ่มประสิทธิภาพคอมไพเลอร์ที่ผิดพลาด

FORTRAN II แนะนำฟังก์ชั่นที่ผู้ใช้กำหนดและซับรูทีนที่มีการขัดแย้งของพวกเขาผ่านอ้างอิง (เพราะเหตุใดฉันไม่รู้มันอาจมีประสิทธิภาพมากกว่าฮาร์ดแวร์แบบ pass-by-value ในเวลานั้น)

โดยปกติการอ้างอิงแบบ pass-by-reference หมายความว่าคุณจะต้องผ่านค่า l-value (เช่นตัวแปร) แทนค่า r-value แต่นักออกแบบของ FORTRAN ตัดสินใจที่จะเป็นประโยชน์และให้คุณส่งค่า r-values ​​เป็นอาร์กิวเมนต์ต่อไป คอมไพเลอร์จะสร้างตัวแปรให้คุณโดยอัตโนมัติ ดังนั้นถ้าคุณเขียนว่า:

CALL SUBFOO(X + Y, 4)

คอมไพเลอร์จะแปลงสิ่งนี้เบื้องหลังให้เป็นอย่าง

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

นอกจากนี้ยังมีการเพิ่มประสิทธิภาพคอมไพเลอร์ทั่วไปที่เรียกว่า“ สระรวม” ซึ่งจะรวมหลายอินสแตนซ์ของค่าคงที่ตัวเลขเดียวกันเป็นตัวแปรที่สร้างขึ้นอัตโนมัติเดียวกัน (หลายภาษาในตระกูล 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เขียนโค้ดจริง

เวอร์ชั่นใหม่ของ Fortran ช่วยลดปัญหานี้โดยให้คุณประกาศINTENTตัวแปรเป็นINหรือOUTและทำให้คุณมีข้อผิดพลาด (หรืออย่างน้อยคำเตือน) หากคุณผ่านค่าคงที่เป็นOUTพารามิเตอร์


5

ใน FORTRAN เมื่อค่าคงที่ถูกส่งผ่านไปยังโพรซีเดอร์อื่นจะไม่ได้รับการป้องกันอีกต่อไป นั่นคือสิ่งที่พวกเขาอ้างถึง ภาษาการเขียนโปรแกรมยอดนิยมอื่น ๆ ในเวลาเดียวกันคือ C และ Pascal ซึ่งไม่มี (และยังไม่มี) มีปัญหานี้ อาจมีภาษาโปรแกรมเก่ากว่าซึ่งฉันไม่ทราบว่ามีปัญหาเดียวกัน


นอกจากนี้ยังหมายถึงความจริงที่ว่ากลุ่มคงที่ไม่ได้อยู่ในกลุ่มอ่านอย่างเดียว ถ้าเป็นเช่นนั้นและ 4 ถูกส่งผ่านโดยการอ้างอิงและเปลี่ยนแปลงโดยผู้ที่ได้รับการยอมรับ SEGV จะเกิดขึ้นโดยไม่มีการเปลี่ยนแปลงที่ประสบความสำเร็จ 4
Basile Starynkevitch

นั่นเป็นเพราะไม่ใช่ทุกระบบปฏิบัติการที่มีเซ็กเมนต์แบบอ่านอย่างเดียว ข้อผิดพลาดสามารถใช้กับ 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.