การเข้าถึงอาร์เรย์นั้นมีอันตรายแค่ไหน


221

การเข้าถึงอาเรย์นั้นมีอันตรายเพียงใดนอกขอบเขต (ใน C)? บางครั้งมันอาจเกิดขึ้นที่ฉันอ่านจากนอกอาร์เรย์ (ตอนนี้ฉันเข้าใจแล้วฉันเข้าถึงหน่วยความจำที่ใช้โดยส่วนอื่น ๆ ของโปรแกรมของฉันหรือมากกว่านั้น) หรือฉันพยายามตั้งค่าเป็นดัชนีนอกอาร์เรย์ บางครั้งโปรแกรมขัดข้อง แต่บางครั้งก็ทำงานเพียงให้ผลลัพธ์ที่ไม่คาดคิด

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

คำถามของฉัน:

  1. การอ่านค่าจากด้านนอกอาเรย์จะทำให้เกิดความเสียหายอะไรนอกเหนือจากโปรแกรมของฉันหรือไม่? ฉันคิดว่าการดูสิ่งต่าง ๆ จะไม่เปลี่ยนแปลงอะไรเลยหรืออย่างเช่นจะเปลี่ยนแอตทริบิวต์ 'เปิดครั้งล่าสุด' ของไฟล์ที่ฉันไปให้ถึง
  2. การตั้งค่าต่าง ๆ นอกอาร์เรย์สามารถทำให้เกิดความเสียหายอะไรนอกเหนือจากโปรแกรมของฉันได้หรือไม่? จาก คำถาม Stack Overflowฉันรวบรวมว่าเป็นไปได้ที่จะเข้าถึงตำแหน่งหน่วยความจำใด ๆ ที่ไม่มีการรับประกันความปลอดภัย
  3. ตอนนี้ฉันรันโปรแกรมเล็ก ๆ ของฉันจากภายใน XCode นั่นให้การป้องกันพิเศษรอบ ๆ โปรแกรมของฉันซึ่งมันไม่สามารถเข้าถึงภายนอกหน่วยความจำของตัวเองได้หรือไม่? มันจะเป็นอันตรายต่อ XCode หรือไม่?
  4. คำแนะนำใด ๆ เกี่ยวกับวิธีเรียกใช้โค้ด buggy ของฉันอย่างปลอดภัยหรือไม่

ฉันใช้ OSX 10.7, Xcode 4.6


โดยทั่วไประบบปฏิบัติการจะป้องกันตัวเองและกระบวนการอื่น ๆ จากความผิดพลาดของคุณ ไม่ใช่สิ่งที่คุณจำเป็นต้องพึ่งพาอย่างจริงจัง
Hot Licks

7
นอกจากนี้คุณจะไม่ "บังเอิญเข้าถึง" ไฟล์ในฮาร์ดดิสก์ของคุณเมื่อเข้าถึงและจัดทำดัชนีแถวนอกขอบเขต (ในหน่วยความจำของคุณ)
DrummerB

1
ฉันเชื่อว่าคุณกำลังถามเกี่ยวกับ C array ใช่ไหม ดังนั้นจึงไม่มีส่วนเกี่ยวข้องกับ ObjC และไม่เกี่ยวข้องกับ IDE ใด ๆ
ไบรอันเฉิน

17
นี่คือตัวอย่างที่ฉันชอบในผลลัพธ์แปลก ๆ (มันเกี่ยวข้องกับสแต็ก แต่ฉันพบว่ามันแจ่มใสจริงๆ ... )
phipsgabler

คำตอบ:


125

ตราบใดที่เกี่ยวข้องกับมาตรฐาน ISO C (คำจำกัดความที่เป็นทางการของภาษา) การเข้าถึงอาเรย์นอกขอบเขตนั้นมี " พฤติกรรมที่ไม่ได้กำหนด " ความหมายที่แท้จริงของสิ่งนี้คือ:

พฤติกรรมเมื่อมีการสร้างโปรแกรมที่ไม่สามารถทำได้หรือผิดพลาดหรือใช้ข้อมูลที่ผิดพลาดซึ่งมาตรฐานสากลนี้ไม่มีข้อกำหนด

บันทึกที่ไม่เป็นบรรทัดฐานขยายตัวในเรื่องนี้:

พฤติกรรมที่ไม่เป็นไปได้มีตั้งแต่ช่วงที่ไม่สนใจสถานการณ์อย่างสมบูรณ์ด้วยผลลัพธ์ที่ไม่สามารถคาดการณ์ได้จนถึงพฤติกรรมในระหว่างการแปลหรือการดำเนินการโปรแกรมในลักษณะที่เป็นเอกสารของสภาพแวดล้อม (ไม่ว่าจะมีหรือไม่มีการออกข้อความวินิจฉัย) ของข้อความวินิจฉัย)

นั่นคือทฤษฎี ความจริงคืออะไร

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

นั่นคือสมมติว่าโปรแกรมของคุณกำลังทำงานภายใต้ระบบปฏิบัติการที่พยายามปกป้องกระบวนการที่กำลังรันอยู่พร้อมกัน หากรหัสของคุณทำงานบน "โลหะเปลือย" ให้บอกว่าเป็นส่วนหนึ่งของเคอร์เนลระบบปฏิบัติการหรือระบบฝังตัวแสดงว่าไม่มีการป้องกันดังกล่าว รหัสที่ทำงานผิดปกติของคุณคือสิ่งที่ควรให้การป้องกันนั้น ในกรณีดังกล่าวความเป็นไปได้ของความเสียหายมีมากขึ้นรวมถึงในบางกรณีความเสียหายทางกายภาพต่อฮาร์ดแวร์ (หรือสิ่งต่าง ๆ หรือผู้คนใกล้เคียง)

แม้ในสภาพแวดล้อมระบบปฏิบัติการที่ได้รับการปกป้องการป้องกันอาจไม่ได้ 100% เสมอ มีข้อบกพร่องของระบบปฏิบัติการที่อนุญาตให้โปรแกรมที่ไม่ได้รับสิทธิพิเศษเพื่อรับสิทธิ์การเข้าถึงระดับราก (ระดับผู้ดูแลระบบ) แม้จะมีสิทธิ์ผู้ใช้ทั่วไปโปรแกรมทำงานผิดพลาดสามารถใช้ทรัพยากรมากเกินไป (CPU, หน่วยความจำ, ดิสก์) อาจนำมาซึ่งระบบทั้งหมด มัลแวร์จำนวนมาก (ไวรัสและอื่น ๆ ) ใช้ประโยชน์จากบัฟเฟอร์โอเวอร์รันเพื่อเข้าถึงระบบโดยไม่ได้รับอนุญาต

(ตัวอย่างในอดีต: ฉันได้ยินมาว่าในระบบเก่าบางรุ่นที่มีหน่วยความจำหลักการเข้าถึงตำแหน่งหน่วยความจำเดี่ยวซ้ำ ๆ ในวงแคบอาจทำให้หน่วยความจำอันนั้นละลายได้ความเป็นไปได้อื่น ๆ ได้แก่ การทำลายจอ CRT และการอ่าน / เขียนหัวของดิสก์ไดร์ฟด้วยความถี่ฮาร์มอนิกของตู้เก็บไดรฟ์ทำให้เดินข้ามโต๊ะและตกลงบนพื้น)

และมีSkynetเสมอที่จะต้องกังวล

บรรทัดล่างคือ: ถ้าคุณสามารถเขียนโปรแกรมที่จะทำบางสิ่งบางอย่างที่ไม่ดีจงใจก็อย่างน้อยเป็นไปได้ในทางทฤษฎีว่าเป็นโปรแกรมที่รถสามารถทำสิ่งเดียวกันโดยบังเอิญ

ในทางปฏิบัติมันไม่น่าเป็นไปได้มากที่โปรแกรมบั๊กกี้ของคุณที่ทำงานบนระบบ MacOS X จะทำอะไรที่ร้ายแรงกว่าความผิดพลาด แต่มันเป็นไปไม่ได้ที่จะสมบูรณ์ป้องกันรหัสรถจากการทำสิ่งที่ไม่ดีจริงๆ


1
ขอบคุณจริงๆฉันเข้าใจอย่างนี้ แต่มันทำให้เกิดคำถามติดตามทันที: โปรแกรมเมอร์เริ่มต้นทำอะไรได้บ้างเพื่อปกป้องคอมพิวเตอร์ของเขา / เธอจากการสร้างสรรค์ที่น่ากลัวของเขา / เธอ หลังจากที่ฉันได้ทดสอบโปรแกรมอย่างละเอียดฉันสามารถปลดปล่อยมันออกมาในโลก แต่การทดลองใช้ครั้งแรกนั้นถูกผูกไว้กับโปรแกรมที่ไม่ถูกต้อง พวกคุณทำให้ระบบของคุณปลอดภัยจากตัวเองได้อย่างไร?
ChrisD

6
@ChrisD: เรามักจะโชคดี 8-)} การป้องกันระดับ OS อย่างจริงจังในทุกวันนี้ กรณีที่เลวร้ายที่สุดถ้าฉันเขียนระเบิดส้อมโดยบังเอิญฉันอาจต้องรีบู๊ตเพื่อกู้คืน แต่ความเสียหายที่แท้จริงของระบบอาจไม่คุ้มค่าที่จะต้องกังวลตราบใดที่โปรแกรมของคุณไม่ได้พยายามทำอะไรซักอย่างที่จะเป็นอันตราย หากคุณกังวลจริง ๆ การรันโปรแกรมบนเครื่องเสมือนอาจไม่ใช่ความคิดที่ผิด
Keith Thompson

1
ในทางกลับกันฉันได้เห็นสิ่งแปลก ๆ มากมายเกิดขึ้นบนคอมพิวเตอร์ที่ฉันใช้ (ไฟล์ที่เสียหายข้อผิดพลาดของระบบที่ไม่สามารถกู้คืนได้ ฯลฯ ) และฉันไม่รู้ว่ามีบางสิ่งที่เกิดจากโปรแกรม C บางตัวที่แสดง พฤติกรรมที่ไม่ได้กำหนดหวั่น (จนถึงตอนนี้ยังไม่มีปีศาจจริงบินออกมาจากจมูกของฉัน)
Keith Thompson

1
ขอบคุณสำหรับการเรียนการสอนให้ฉันแยกระเบิด - ฉันมีสิ่งที่ใกล้เสร็จแล้วนั้นเมื่อพยายามที่จะเข้าใจการเรียกซ้ำ :)
ChrisD

2
Scientificamerican.com/article/…ดังนั้นไฟจึงยังเป็นไปได้ด้วยอุปกรณ์อิเล็กทรอนิกส์ที่ทันสมัย
Mooing Duck

25

โดยทั่วไประบบปฏิบัติการของวันนี้ (ตัวที่ได้รับความนิยม) เรียกใช้แอปพลิเคชันทั้งหมดในภูมิภาคหน่วยความจำที่มีการป้องกันโดยใช้ตัวจัดการหน่วยความจำเสมือน ปรากฎว่าไม่ใช่เรื่องง่ายมาก (ต่อการพูด) เพียงแค่อ่านหรือเขียนไปยังตำแหน่งที่มีอยู่ในพื้นที่ REAL นอกภูมิภาคที่ได้รับมอบหมาย / จัดสรรให้กระบวนการของคุณ

คำตอบโดยตรง:

1) การอ่านแทบจะไม่เกิดความเสียหายโดยตรงต่อกระบวนการอื่น แต่มันสามารถสร้างความเสียหายทางอ้อมกระบวนการถ้าคุณเกิดขึ้นในการอ่านค่าคีย์ที่ใช้ในการเข้ารหัสถอดรหัสหรือตรวจสอบโปรแกรม / กระบวนการ การอ่านนอกขอบเขตอาจส่งผลกระทบในทางลบ / คาดไม่ถึงกับรหัสของคุณหากคุณกำลังตัดสินใจตามข้อมูลที่คุณกำลังอ่าน

2) วิธีเดียวที่คุณสามารถทำลายบางสิ่งบางอย่างได้โดยการเขียนไปยัง loaction ที่สามารถเข้าถึงได้โดยที่อยู่หน่วยความจำคือถ้าที่อยู่หน่วยความจำที่คุณกำลังเขียนนั้นเป็นทะเบียนฮาร์ดแวร์ (สถานที่ที่ไม่ได้จัดเก็บข้อมูล ฮาร์ดแวร์) ไม่ใช่ตำแหน่ง RAM ในความเป็นจริงแล้วคุณยังคงไม่เกิดความเสียหายกับบางสิ่งยกเว้นว่าคุณกำลังเขียนตำแหน่งที่ตั้งโปรแกรมได้ครั้งหนึ่งซึ่งไม่สามารถเขียนซ้ำได้ (หรือบางสิ่งในลักษณะนั้น)

3) โดยทั่วไปแล้วการรันจากภายในตัวดีบักเกอร์จะรันโค้ดในโหมดดีบัก การทำงานในโหมดแก้ไขข้อผิดพลาดทำให้ Tend to (แต่ไม่เสมอไป) หยุดโค้ดของคุณเร็วขึ้นเมื่อคุณทำบางสิ่งที่ถือว่าผิดกฎหมายหรือผิดกฎหมาย

4) อย่าใช้มาโครใช้โครงสร้างข้อมูลที่มีการตรวจสอบขอบเขตดัชนีอาร์เรย์อยู่แล้ว ฯลฯ ....

เพิ่มเติม ฉันควรเพิ่มว่าข้อมูลข้างต้นเป็นจริงสำหรับระบบที่ใช้ระบบปฏิบัติการที่มีหน้าต่างป้องกันหน่วยความจำเท่านั้น หากการเขียนโค้ดสำหรับระบบฝังตัวหรือแม้กระทั่งระบบที่ใช้ระบบปฏิบัติการ (แบบเรียลไทม์หรืออื่น ๆ ) ที่ไม่มีหน้าต่างป้องกันหน่วยความจำ (หรือ windows ที่ระบุไว้เสมือน) ว่าควรฝึกฝนอย่างระมัดระวังมากขึ้นในการอ่านและเขียนหน่วยความจำ นอกจากนี้ในกรณีเหล่านี้ควรใช้วิธีการเข้ารหัสที่ปลอดภัยและปลอดภัยเพื่อหลีกเลี่ยงปัญหาด้านความปลอดภัย


4
ปลอดภัยการเขียนโค้ดที่ควรเสมอได้รับการว่าจ้าง
Nik Bougalis

3
ฉันจะไม่แนะนำให้ลองใช้ / จับรหัส buggy จนกว่าคุณจะได้รับข้อยกเว้นเฉพาะเจาะจงและรู้วิธีกู้คืน Catch (... ) เป็นสิ่งที่แย่ที่สุดที่คุณสามารถเพิ่มไปยังรหัสรถบั๊กกี้
Eugene

1
@NikBougalis - ฉันเห็นด้วยอย่างสมบูรณ์ แต่มันก็มีความสำคัญมากขึ้นหากระบบปฏิบัติการไม่รวมถึงการป้องกันหน่วยความจำ / พื้นที่ที่อยู่เสมือนหรือมีการขาดระบบปฏิบัติการ :-)
trumpetlicks

@Eugene - ฉันไม่เคยสังเกตเห็นว่าเป็นปัญหาสำหรับฉัน แต่ฉันเห็นด้วยกับคุณฉันจะแก้ไขมันได้ไหม :-)
trumpetlicks

1) คุณหมายถึงความเสียหายเพราะฉันจะเปิดเผยสิ่งที่ควรเก็บเป็นความลับ? 2) ฉันไม่แน่ใจว่าฉันได้รับสิ่งที่คุณหมายถึง แต่ฉันเดาว่าฉันเพียงเข้าถึง RAM ด้วยการพยายามเข้าถึงสถานที่นอกขอบเขตอาร์เรย์?
ChrisD

9

การไม่ตรวจสอบขอบเขตอาจทำให้เกิดผลข้างเคียงที่น่าเกลียดรวมถึงช่องโหว่ด้านความปลอดภัย หนึ่งในคนที่น่าเกลียดคือการใช้รหัสโดยอำเภอใจ ในตัวอย่างแบบคลาสสิก: หากคุณมีอาร์เรย์ขนาดคงที่และใช้strcpy()เพื่อใส่สตริงที่ผู้ใช้ระบุผู้ใช้สามารถให้สตริงที่โอเวอร์โฟลว์บัฟเฟอร์และเขียนทับตำแหน่งหน่วยความจำอื่นรวมถึงที่อยู่รหัสที่ CPU ควรส่งคืนเมื่อฟังก์ชันของคุณ เสร็จสิ้น

ซึ่งหมายความว่าผู้ใช้ของคุณสามารถส่งสตริงที่จะทำให้โปรแกรมของคุณโทรเป็นหลักexec("/bin/sh")ซึ่งจะเปลี่ยนเป็นเชลล์ดำเนินการสิ่งที่เขาต้องการในระบบของคุณรวมถึงการเก็บเกี่ยวข้อมูลทั้งหมดของคุณและเปลี่ยนเครื่องของคุณให้เป็นโหนด botnet

ดูSmashing The Stack เพื่อความสนุกสนานและกำไรสำหรับรายละเอียดเกี่ยวกับวิธีการนี้สามารถทำได้


ฉันรู้ว่าฉันไม่ควรเข้าถึงองค์ประกอบของอาเรย์ที่เกินขอบเขตขอบคุณสำหรับการเสริมจุดนั้น แต่คำถามคือนอกเหนือจากการทำอันตรายทุกประเภทกับโปรแกรมของฉันฉันสามารถเข้าถึงเกินหน่วยความจำของโปรแกรมของฉันโดยไม่ได้ตั้งใจหรือไม่? และฉันหมายถึงบน OSX
ChrisD

@ChrisD: OS X เป็นระบบปฏิบัติการที่ทันสมัยดังนั้นจึงจะให้การป้องกันหน่วยความจำเต็ม เช่นคุณไม่ควร จำกัด สิ่งที่โปรแกรมของคุณได้รับอนุญาตให้ทำ สิ่งนี้ไม่ควรรวมถึงการล้อเล่นกับกระบวนการอื่น ๆ (ยกเว้นว่าคุณกำลังทำงานภายใต้สิทธิ์ของรูท)
che

ฉันอยากบอกว่าภายใต้สิทธิพิเศษของแหวน 0 ไม่ใช่รูท
Ruslan

ที่น่าสนใจกว่านั้นก็คือคอมไพเลอร์ไฮเปอร์ทันสมัยอาจตัดสินใจว่าถ้ารหัสพยายามที่จะอ่านfoo[0]ผ่านfoo[len-1]หลังจากที่มีการใช้ก่อนหน้านี้การตรวจสอบของlenกับความยาวอาร์เรย์ทั้งดำเนินการหรือข้ามชิ้นส่วนของรหัสคอมไพเลอร์ควรจะรู้สึกอิสระในการทำงานว่ารหัสอื่น ๆ โดยไม่มีเงื่อนไขแม้กระทั่ง ถ้าแอปพลิเคชันเป็นเจ้าของที่เก็บข้อมูลผ่านอาร์เรย์และผลของการอ่านมันจะไม่เป็นอันตราย แต่ผลของการเรียกใช้โค้ดอื่นจะไม่เป็นเช่นนั้น
supercat

8

ที่คุณเขียน:

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

ให้พูดอย่างนั้น: โหลดปืน ชี้มันออกไปนอกหน้าต่างโดยไม่มีเป้าหมายและไฟ อันตรายคืออะไร?

ปัญหาคือคุณไม่รู้ หากรหัสของคุณเขียนทับสิ่งที่ขัดข้องโปรแกรมของคุณคุณก็ใช้ได้เพราะจะหยุดลงในสถานะที่กำหนดไว้ อย่างไรก็ตามถ้ามันไม่ผิดพลาดปัญหาก็เริ่มเกิดขึ้น ทรัพยากรใดบ้างที่อยู่ภายใต้การควบคุมของโปรแกรมของคุณและมันจะทำอะไรได้บ้าง ทรัพยากรใดบ้างที่อาจได้รับภายใต้การควบคุมของโปรแกรมของคุณและสิ่งเหล่านั้นจะทำอะไรได้บ้าง ฉันรู้ว่าอย่างน้อยหนึ่งประเด็นสำคัญที่เกิดจากการล้น ปัญหานี้อยู่ในฟังก์ชั่นสถิติที่ไม่มีความหมายซึ่งทำให้ตารางการแปลงที่ไม่เกี่ยวข้องสำหรับฐานข้อมูลการผลิตมีความยุ่งเหยิง ผลที่ได้คือการล้างข้อมูลที่มีราคาแพงมากในภายหลัง จริง ๆ แล้วมันจะถูกกว่าและจัดการได้ง่ายกว่าถ้าปัญหานี้จะมีการจัดรูปแบบฮาร์ดดิสก์ ... ด้วยคำอื่น ๆ : สีชมพูยูนิคอร์นอาจเป็นปัญหาน้อยที่สุดของคุณ

แนวคิดที่ว่าระบบปฏิบัติการของคุณจะปกป้องคุณในแง่ดี หากเป็นไปได้พยายามหลีกเลี่ยงการเขียนนอกขอบเขต


ตกลงนี่คือสิ่งที่ฉันกลัว ฉันจะ 'พยายามหลีกเลี่ยงการเขียนนอกขอบเขต' แต่เมื่อฉันเห็นสิ่งที่ฉันทำในช่วงสองสามเดือนที่ผ่านมาฉันจะทำมันอย่างแน่นอน พวกคุณเก่งเรื่องการเขียนโปรแกรมอย่างไรโดยไม่ต้องฝึกวิธีที่ปลอดภัย?
ChrisD

3
ใครบอกว่ามีสิ่งใดที่ปลอดภัย;)
Udo Klein

7

การไม่รันโปรแกรมของคุณในฐานะรูทหรือผู้ใช้ที่ได้รับสิทธิพิเศษอื่น ๆ จะไม่เป็นอันตรายต่อระบบของคุณดังนั้นโดยทั่วไปนี่อาจเป็นความคิดที่ดี

โดยการเขียนข้อมูลไปยังตำแหน่งหน่วยความจำแบบสุ่มคุณจะไม่ "ทำลาย" โปรแกรมอื่นใดที่ทำงานบนคอมพิวเตอร์ของคุณโดยตรงเนื่องจากแต่ละกระบวนการทำงานในพื้นที่หน่วยความจำของตัวเอง

หากคุณพยายามเข้าถึงหน่วยความจำใด ๆ ที่ไม่ได้ถูกจัดสรรให้กับกระบวนการของคุณระบบปฏิบัติการจะหยุดโปรแกรมของคุณไม่ให้ทำงานด้วยการแบ่งส่วนที่ผิดพลาด

ดังนั้นโดยตรง (โดยไม่ต้องรันในฐานะรูทและเข้าถึงไฟล์โดยตรงเช่น / dev / mem) จึงไม่มีอันตรายใด ๆ ที่โปรแกรมของคุณจะรบกวนการทำงานของโปรแกรมอื่น ๆ ที่รันบนระบบปฏิบัติการของคุณ

อย่างไรก็ตาม - และนี่อาจเป็นสิ่งที่คุณได้ยินเกี่ยวกับอันตราย - โดยการสุ่มข้อมูลสุ่มไปยังตำแหน่งหน่วยความจำแบบสุ่มโดยบังเอิญคุณสามารถทำลายสิ่งที่คุณสามารถสร้างความเสียหายได้

ตัวอย่างเช่นโปรแกรมของคุณอาจต้องการลบไฟล์เฉพาะที่กำหนดโดยชื่อไฟล์ที่จัดเก็บไว้ที่ใดที่หนึ่งในโปรแกรมของคุณ หากบังเอิญคุณเขียนทับตำแหน่งที่เก็บชื่อไฟล์คุณอาจลบไฟล์ที่แตกต่างออกไปแทน


1
หากคุณมีการทำงานเป็นราก (หรือบางส่วนของผู้ใช้ที่มีสิทธิพิเศษอื่น ๆ ) แต่ดูออก บัฟเฟอร์และการบุกรุกอาร์เรย์เป็นวิธีที่มีมัลแวร์ที่พบเห็น
John Bode

จริง ๆ แล้วบัญชีที่ฉันใช้สำหรับการคำนวณรายวันทั้งหมดไม่ใช่บัญชีผู้ดูแลระบบ (ฉันใช้คำศัพท์ OSX เนื่องจากเป็นระบบของฉัน) คุณหมายถึงบอกฉันว่าฉันไม่สามารถสร้างความเสียหายบางอย่างได้โดยพยายามตั้งค่าตำแหน่งหน่วยความจำใด ๆ นั่นเป็นข่าวดีจริง ๆ !
ChrisD

ดังที่ได้กล่าวไปแล้วก่อนที่จะเกิดอันตรายที่ร้ายแรงที่สุดที่คุณสามารถทำได้โดยอุบัติเหตุคืออันตรายที่เลวร้ายที่สุดที่คุณสามารถทำได้ในฐานะผู้ใช้ หากคุณต้องการ 100% แน่นอนว่าอย่าทำลายข้อมูลใด ๆ ของคุณคุณอาจต้องการเพิ่มบัญชีอื่นลงในคอมพิวเตอร์ของคุณและทำการทดลองด้วยข้อมูลนั้น
mikyra

1
@mikyra: นั่นเป็นความจริงเฉพาะในกรณีที่กลไกการป้องกันของระบบมีประสิทธิภาพ 100% การมีมัลแวร์แสดงให้เห็นว่าคุณไม่สามารถไว้ใจได้ (ผมไม่ต้องการที่จะแสดงให้เห็นว่าที่จำเป็นต้องกังวลเกี่ยวกับมูลค่าเป็นไปได้ แต่ไม่น่าว่าโปรแกรมอาจตั้งใจใช้ประโยชน์จากช่องโหว่เดียวกันโจมตีโดยมัลแวร์.)
คี ธ ธ อมป์สัน

1
รายการที่นี่รวมถึง: การเรียกใช้รหัสจากแหล่งที่ไม่น่าเชื่อถือ เพียงคลิกปุ่มตกลงบนป๊อปอัพของไฟร์วอลล์ใด ๆ โดยไม่ต้องอ่านอะไรเกี่ยวกับมันหรือปิดลงอย่างสมบูรณ์หากการเชื่อมต่อเครือข่ายที่ต้องการไม่สามารถทำได้ การปรับปรุงไบนารีด้วยแฮ็คใหม่ล่าสุดจากแหล่งที่น่าสงสัย มันไม่ใช่ความผิดของหลุมฝังศพถ้าเจ้าของจะเชิญขโมยด้วยแขนทั้งสองข้างและประตูป้อมปราการที่แข็งแกร่งเป็นพิเศษเปิดกว้าง
mikyra

4

NSArrays ใน Objective-C ได้รับมอบหมายบล็อกหน่วยความจำที่เฉพาะเจาะจง เกินขอบเขตของอาร์เรย์หมายความว่าคุณจะเข้าถึงหน่วยความจำที่ไม่ได้กำหนดให้กับอาร์เรย์ หมายความว่า:

  1. หน่วยความจำนี้สามารถมีค่าใด ๆ ไม่มีทางรู้ได้ว่าข้อมูลนั้นถูกต้องตามประเภทข้อมูลของคุณหรือไม่
  2. หน่วยความจำนี้อาจมีข้อมูลที่ละเอียดอ่อนเช่นคีย์ส่วนตัวหรือข้อมูลรับรองผู้ใช้อื่น ๆ
  3. ที่อยู่หน่วยความจำอาจไม่ถูกต้องหรือมีการป้องกัน
  4. หน่วยความจำสามารถมีค่าที่เปลี่ยนแปลงได้เนื่องจากกำลังถูกเข้าถึงโดยโปรแกรมหรือเธรดอื่น
  5. สิ่งอื่น ๆ ใช้พื้นที่ที่อยู่หน่วยความจำเช่นพอร์ตที่แมปหน่วยความจำ
  6. การเขียนข้อมูลไปยังที่อยู่หน่วยความจำที่ไม่รู้จักอาจขัดข้องโปรแกรมของคุณเขียนทับพื้นที่หน่วยความจำระบบปฏิบัติการและโดยทั่วไปจะทำให้เกิดการระเบิด

จากมุมมองของโปรแกรมของคุณคุณต้องการทราบเมื่อรหัสของคุณเกินขอบเขตของอาร์เรย์ สิ่งนี้อาจนำไปสู่การส่งคืนค่าที่ไม่ทราบสาเหตุทำให้แอปพลิเคชันของคุณทำงานผิดพลาดหรือให้ข้อมูลที่ไม่ถูกต้อง


NSArraysมีข้อยกเว้นนอกขอบเขต และคำถามนี้น่าจะเกี่ยวกับ C array
DrummerB

ฉันหมายถึงอาร์เรย์ C แน่นอน ฉันรู้ว่ามี NSArray แต่สำหรับตอนนี้แบบฝึกหัดส่วนใหญ่ของฉันอยู่ใน C
ChrisD

4

คุณอาจต้องการลองใช้memcheckเครื่องมือในValgrindเมื่อคุณทดสอบรหัสของคุณ - มันจะไม่จับการละเมิดขอบเขตอาเรย์เดี่ยวภายในกรอบสแต็ก แต่ควรจับปัญหาหน่วยความจำประเภทอื่น ๆ มากมายรวมถึงปัญหาที่อาจทำให้บอบบางและกว้างขึ้น ปัญหานอกขอบเขตของฟังก์ชั่นเดียว

จากคู่มือ:

Memcheck เป็นตัวตรวจจับข้อผิดพลาดของหน่วยความจำ สามารถตรวจพบปัญหาต่อไปนี้ที่พบได้ทั่วไปในโปรแกรม C และ C ++

  • การเข้าถึงหน่วยความจำที่คุณไม่ควรทำเช่นบล็อกฮีปที่ทับซ้อนและ underrunning การเขียนทับด้านบนสุดของสแต็กและการเข้าถึงหน่วยความจำหลังจากที่ได้รับการปล่อยให้เป็นอิสระ
  • การใช้ค่าที่ไม่ได้กำหนดเช่นค่าที่ไม่ได้ถูกกำหนดค่าเริ่มต้นหรือที่ได้มาจากค่าที่ไม่ได้กำหนดอื่น ๆ
  • การเพิ่มหน่วยความจำฮีปไม่ถูกต้องเช่นบล็อกฮีปสองครั้งหรือการใช้ malloc / new / new [] ไม่ตรงกันกับ free / delete / delete []
  • พอยน์เตอร์ที่ซ้อนทับ src และ dst ในฟังก์ชัน memcpy และที่เกี่ยวข้อง
  • หน่วยความจำรั่ว

การทางพิเศษแห่งประเทศไทย:แม้ว่าตามคำตอบของ Kaz กล่าวว่ามันไม่ใช่ยาครอบจักรวาลและไม่ให้ผลลัพธ์ที่เป็นประโยชน์มากที่สุดเสมอโดยเฉพาะเมื่อคุณใช้รูปแบบการเข้าถึงที่น่าตื่นเต้น


ฉันสงสัยว่าเครื่องวิเคราะห์ของ XCode จะพบว่าส่วนใหญ่ และคำถามของฉันไม่ได้เป็นวิธีการค้นหาข้อบกพร่องเหล่านี้ แต่ถ้าการดำเนินการโปรแกรมที่ยังคงมีข้อบกพร่องเหล่านี้เป็นอันตรายต่อหน่วยความจำไม่ได้จัดสรรให้กับโปรแกรมของฉัน ก็จะมีการดำเนินการโปรแกรมเพื่อให้เห็นข้อบกพร่องที่เกิดขึ้น
ChrisD

3

หากคุณเคยเขียนโปรแกรมระดับระบบหรือการเขียนโปรแกรมระบบฝังตัวสิ่งเลวร้ายมากอาจเกิดขึ้นได้หากคุณเขียนไปยังตำแหน่งหน่วยความจำแบบสุ่ม ระบบรุ่นเก่าและไมโครคอนโทรลเลอร์หลายตัวใช้หน่วยความจำที่แมป IO ดังนั้นการเขียนไปยังตำแหน่งหน่วยความจำที่แมปไปยังรีจิสเตอร์ต่อพ่วงสามารถสร้างความหายนะโดยเฉพาะอย่างยิ่งถ้ามันทำแบบอะซิงโครนัส

ตัวอย่างคือการเขียนโปรแกรมหน่วยความจำแฟลช โหมดการเขียนโปรแกรมบนชิปหน่วยความจำเปิดใช้งานโดยการเขียนลำดับค่าเฉพาะไปยังสถานที่เฉพาะภายในช่วงที่อยู่ของชิป หากกระบวนการอื่นต้องเขียนไปยังตำแหน่งอื่น ๆ ในชิปในขณะที่เกิดขึ้นมันจะทำให้วงจรการเขียนโปรแกรมล้มเหลว

ในบางกรณีฮาร์ดแวร์จะล้อมรอบที่อยู่ (บิตที่สำคัญที่สุด / ไบต์ของที่อยู่จะถูกละเว้น) ดังนั้นการเขียนไปยังที่อยู่นอกเหนือจากจุดสิ้นสุดของพื้นที่ที่อยู่ทางกายภาพจริง ๆ แล้วจะส่งผลให้ข้อมูลถูกเขียนตรงกลาง

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

คำแนะนำที่ใหญ่ที่สุดของฉันคือปลั๊กที่เห็นได้ชัดสำหรับผลิตภัณฑ์ แต่ฉันไม่มีความสนใจส่วนตัวและฉันไม่ได้มีส่วนเกี่ยวข้องกับพวกเขา แต่อย่างใด แต่จากสองสามทศวรรษของการเขียนโปรแกรม C และระบบฝังตัวซึ่งความน่าเชื่อถือเป็นสิ่งสำคัญ ผ้าสำลีจะไม่เพียง แต่ตรวจจับข้อผิดพลาดเหล่านั้นเท่านั้น แต่จะทำให้โปรแกรมเมอร์ C / C ++ ที่ดีกว่าออกจากคุณโดยการหมั่นเพียรคุณเกี่ยวกับนิสัยที่ไม่ดีอย่างต่อเนื่อง

ฉันขอแนะนำให้อ่านมาตรฐานการเข้ารหัส MISRA C หากคุณสามารถขัดขวางสำเนาจากใครบางคน ฉันไม่ได้เห็นสิ่งใดมาก่อน แต่ในสมัยก่อนพวกเขาให้คำอธิบายที่ดีว่าทำไมคุณควร / ไม่ควรทำสิ่งที่พวกเขาพูดถึง

Dunno เกี่ยวกับคุณ แต่ประมาณครั้งที่ 2 หรือครั้งที่ 3 ฉันได้รับ coredump หรือ hangup จากแอปพลิเคชันใด ๆ ความเห็นของฉันเกี่ยวกับ บริษัท ที่สร้างมันลงไปครึ่งหนึ่ง ครั้งที่ 4 หรือครั้งที่ 5 และอะไรก็ตามที่บรรจุภัณฑ์นั้นกลายเป็นชั้นวางของและฉันก็ผลักเงินเดิมพันที่ทำจากไม้ผ่านศูนย์กลางของหีบห่อ / แผ่นดิสก์ที่มันเข้ามาเพื่อให้แน่ใจว่ามันจะไม่กลับมาหลอกหลอนฉัน


ทั้งนี้ขึ้นอยู่กับระบบการอ่านนอกช่วงอาจทำให้เกิดพฤติกรรมที่ไม่สามารถคาดการณ์ได้หรืออาจเป็นพิษเป็นภัยแม้ว่าพฤติกรรมของฮาร์ดแวร์ที่ไม่สุภาพในการโหลดนอกช่วงไม่ได้หมายความถึงพฤติกรรมของคอมไพเลอร์ที่ไม่สุภาพ
supercat

2

ฉันกำลังทำงานกับคอมไพเลอร์สำหรับชิป DSP ซึ่งจงใจสร้างรหัสที่เข้าถึงหนึ่งในตอนท้ายของอาร์เรย์ออกจากรหัส C ซึ่งไม่ได้!

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

การเขียนโค้ด C เช่นนั้นจะเรียกใช้พฤติกรรมที่ไม่ได้กำหนด แต่นั่นเป็นเพียงแบบแผนจากเอกสารมาตรฐานที่เกี่ยวข้องกับการพกพาได้สูงสุด

บ่อยครั้งที่ไม่ใช่โปรแกรมที่เข้าถึงขอบเขตไม่ได้รับการปรับปรุงอย่างชาญฉลาด มันเป็นรถบั๊กกี้ รหัสดึงค่าขยะบางอย่างและซึ่งแตกต่างจากลูปที่ปรับปรุงแล้วของคอมไพเลอร์ดังกล่าวรหัสจากนั้นใช้ค่าในการคำนวณครั้งต่อไปดังนั้นจึงทำลาย theim

มันเป็นสิ่งที่ควรค่าแก่การจับข้อบกพร่องแบบนั้นและมันก็คุ้มที่จะทำให้พฤติกรรมไม่ได้กำหนดไว้ด้วยเหตุผลเพียงอย่างเดียว: เพื่อให้เวลาทำงานสามารถสร้างข้อความวินิจฉัยเช่น "array overrun ในสาย 42 ของ main.c"

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

โปรดทราบว่าใน C เราได้รับอนุญาตให้สร้างตัวชี้ซึ่งเป็นจุดสิ้นสุดของอาร์เรย์ และตัวชี้นี้จะต้องเปรียบเทียบมากกว่าตัวชี้ใด ๆ กับการตกแต่งภายในของอาร์เรย์ ซึ่งหมายความว่าการใช้งาน C ไม่สามารถวางอาร์เรย์ได้ที่ส่วนท้ายของหน่วยความจำโดยที่ที่อยู่บวกหนึ่งจะถูกล้อมรอบและดูเล็กกว่าที่อยู่อื่น ๆ ในอาร์เรย์

อย่างไรก็ตามการเข้าใช้งานค่าเริ่มต้นหรือไม่อยู่ในขอบเขตนั้นบางครั้งก็เป็นเทคนิคการปรับให้เหมาะสมที่ถูกต้องแม้ว่าจะไม่สามารถพกพาได้อย่างเต็มที่ นี่เป็นตัวอย่างว่าทำไมเครื่องมือ Valgrind จึงไม่รายงานการเข้าถึงข้อมูลที่ไม่ได้กำหนดค่าเริ่มต้นเมื่อการเข้าถึงเหล่านั้นเกิดขึ้น แต่เมื่อใช้ค่าในภายหลังด้วยวิธีใดวิธีหนึ่งที่อาจส่งผลต่อผลลัพธ์ของโปรแกรม คุณได้รับการวินิจฉัยเช่น "สาขาตามเงื่อนไขใน xxx: nnn ขึ้นอยู่กับค่าที่ไม่ได้กำหนดค่าเริ่มต้น" และบางครั้งก็อาจยากที่จะติดตามตำแหน่งที่มา หากการเข้าถึงทั้งหมดดังกล่าวถูกดักจับในทันทีจะมีผลบวกปลอมจำนวนมากที่เกิดขึ้นจากโค้ดที่คอมไพเลอร์ปรับให้เหมาะสมรวมถึงโค้ดที่ปรับให้เหมาะสมด้วยมืออย่างถูกต้อง

เมื่อพูดถึงสิ่งที่ฉันได้ทำงานร่วมกับตัวแปลงสัญญาณบางอย่างจากผู้ขายซึ่งให้ข้อผิดพลาดเหล่านี้เมื่อพอร์ตไปยัง Linux และทำงานภายใต้ Valgrind แต่ผู้ขายเชื่อฉันว่ามีหลายบิตเท่านั้นของค่าที่ใช้จริงมาจากหน่วยความจำที่ไม่ได้กำหนดค่าเริ่มต้นและตรรกะเหล่านั้นถูกหลีกเลี่ยงอย่างระมัดระวัง .. เฉพาะบิตที่ดีของค่าที่ถูกใช้และ Valgrind ไม่มีความสามารถในการติดตามไปยังบิตส่วนบุคคล เนื้อหาที่ไม่ได้กำหนดมาจากการอ่านคำที่ผ่านจุดสิ้นสุดของบิตการเข้ารหัสข้อมูล แต่รหัสรู้จำนวนบิตที่อยู่ในกระแสและจะไม่ใช้บิตมากกว่าที่เป็นจริง เนื่องจากการเข้าถึงเกินจุดสิ้นสุดของบิตสตรีมอาเรย์ไม่ก่อให้เกิดอันตรายใด ๆ กับสถาปัตยกรรม DSP (ไม่มีหน่วยความจำเสมือนหลังจากอาเรย์ไม่มีพอร์ตที่แมปหน่วยความจำและที่อยู่ไม่ห่อ) จึงเป็นเทคนิคการเพิ่มประสิทธิภาพที่ถูกต้อง

"พฤติกรรมที่ไม่ได้กำหนด" ไม่ได้มีความหมายมากนักเนื่องจากตามมาตรฐาน ISO C เพียงรวมส่วนหัวที่ไม่ได้กำหนดไว้ในมาตรฐาน C หรือการเรียกใช้ฟังก์ชันที่ไม่ได้กำหนดไว้ในโปรแกรมเองหรือมาตรฐาน C เป็นตัวอย่างของการไม่ได้กำหนด พฤติกรรม. พฤติกรรมที่ไม่ได้กำหนดไม่ได้หมายความว่า "ไม่ได้กำหนดโดยทุกคนบนโลกนี้" เพียงแค่ "ไม่ได้กำหนดโดยมาตรฐาน ISO C" แต่แน่นอนว่าบางครั้งพฤติกรรมที่ไม่ได้กำหนดจริงๆก็ไม่ได้ถูกกำหนดโดยใคร


นอกจากนี้หากมีอย่างน้อยหนึ่งโปรแกรมที่กระบวนการดำเนินการเฉพาะอย่างถูกต้องแม้ว่าจะมีการเก็บภาษีตามขีด จำกัด การดำเนินการทั้งหมดที่กำหนดในมาตรฐานการดำเนินการนั้นอาจทำงานโดยพลการเมื่อมีการป้อนโปรแกรมอื่น ๆ ซึ่งปราศจากการละเมิดข้อ จำกัด สอดคล้อง" ดังนั้นโปรแกรม 99.999% ของ C (สิ่งอื่นนอกเหนือจาก "หนึ่งโปรแกรม" ของแพลตฟอร์ม) ขึ้นอยู่กับพฤติกรรมที่มาตรฐานไม่มีข้อกำหนดใด ๆ
supercat

1

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


3
..อะไร? วิธีการเกี่ยวกับการเขียนทับหน่วยความจำในกระบวนการของคุณใช้เพื่อเก็บตัวแปรที่ใช้ในภายหลัง ... ซึ่งตอนนี้ได้เปลี่ยนค่าของมันอย่างลึกลับ! ข้อบกพร่องเหล่านั้นเป็นเรื่องสนุกที่จะติดตามฉันมั่นใจได้เลยว่า segfault จะเป็นผลลัพธ์ที่ดีที่สุด -1
Ed S.

2
ผมหมายถึงเขาจะไม่ "หยุด" กระบวนการอื่น ๆ นอกเหนือจากโปรแกรมของตัวเอง;)
jbgs

ฉันไม่สนใจว่าฉันจะทำผิดพลาดในโปรแกรมของฉันหรือไม่ ฉันเพิ่งเรียนรู้โปรแกรมนี้ผิดอย่างเห็นได้ชัดถ้าฉันเข้าถึงสิ่งใดนอกขอบเขตของฉัน ฉันแค่เพิ่มความกังวลเกี่ยวกับความเสี่ยงที่จะทำลายสิ่งอื่นในขณะที่ดีบั๊กการสร้างสรรค์ของฉัน
ChrisD

สิ่งคือ: ฉันจะแน่ใจได้หรือไม่ถ้าฉันพยายามเข้าถึงหน่วยความจำที่ไม่ได้กำหนดให้ฉันกระบวนการของฉันจะถูกฆ่าหรือไม่ (อยู่ใน OSX)
ChrisD

3
ปีที่แล้วฉันเคยเป็นโปรแกรมเมอร์ C ที่เงอะงะ ฉันเข้าถึงอาร์เรย์นอกขอบเขตหลายร้อยครั้ง นอกจากกระบวนการของฉันที่ถูกฆ่าโดยระบบปฏิบัติการไม่มีอะไรเกิดขึ้น
jbgs
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.