อ่าน 4 นาที
รหัสที่ไม่สามารถเข้าถึงได้
ใน การเขียน โปรแกรมคอมพิวเตอร์โค้ดที่ไม่สามารถเข้าถึงได้คือส่วนหนึ่งของซอร์สโค้ดของโปรแกรมซึ่งไม่สามารถเรียกใช้งานได้เลย เนื่องจากไม่มี เส้นทาง...
รหัสที่ไม่สามารถเข้าถึงได้
ใน การเขียน โปรแกรมคอมพิวเตอร์โค้ดที่ไม่สามารถเข้าถึงได้คือส่วนหนึ่งของซอร์สโค้ดของโปรแกรมซึ่งไม่สามารถเรียกใช้งานได้เลย เนื่องจากไม่มี เส้นทาง ควบคุมการไหลไปยังโค้ดจากส่วนที่เหลือของโปรแกรม[ 1 ]
บางครั้งโค้ดที่ไม่สามารถเข้าถึงได้ก็เรียกว่าโค้ดที่ตายแล้ว [ 2 ] [ 3 ]แม้ว่าโค้ดที่ตายแล้วอาจหมายถึงโค้ดที่ถูกเรียกใช้งานแต่ไม่มีผลต่อผลลัพธ์ของโปรแกรมก็ตาม[ 4 ]
โดยทั่วไปแล้ว การเข้าถึงโค้ดไม่ได้ถือเป็นสิ่งที่ไม่พึงประสงค์ด้วยเหตุผลหลายประการ:
- มันใช้หน่วยความจำโดยไม่จำเป็น
- อาจทำให้เกิดการใช้งาน แคชคำสั่งของ CPU โดยไม่จำเป็น
- สิ่งนี้อาจลดความเฉพาะที่ของข้อมูล ลงได้เช่นกัน
- อาจเสียเวลาและแรงงานไปกับการทดสอบ บำรุงรักษา และจัดทำเอกสารโค้ดที่ไม่เคยถูกใช้งานเลย
- บางครั้ง การทดสอบอัตโนมัติเป็นสิ่งเดียวที่ใช้โค้ดนั้น
โค้ดที่ไม่สามารถเข้าถึงได้อาจมีประโยชน์ในบางเรื่อง เช่น การจัดเตรียมไลบรารีของฟังก์ชันสำหรับการเรียกใช้หรือการกระโดดไปยังฟังก์ชันเหล่านั้นด้วยตนเองผ่านดีบักเกอร์ในขณะที่โปรแกรมหยุดทำงานหลังจากเบรกพอยต์โดยเฉพาะอย่างยิ่งมีประโยชน์สำหรับการตรวจสอบและแสดงสถานะภายในของโปรแกรมอย่างสวยงาม การมีโค้ดดังกล่าวอยู่ในผลิตภัณฑ์ที่ส่งมอบอาจเป็นเรื่องสมเหตุสมผล เพื่อให้นักพัฒนาสามารถแนบดีบักเกอร์เข้ากับอินสแตนซ์ที่กำลังทำงานของลูกค้าได้
สาเหตุ
โค้ดที่ไม่สามารถเข้าถึงได้อาจเกิดขึ้นได้จากหลายสาเหตุ เช่น:
- ข้อผิดพลาดในการเขียนโปรแกรมในเงื่อนไขที่ซับซ้อน
- ผลสืบเนื่องมาจากการแปลงภายในที่ดำเนินการโดย คอมไพเลอ ร์ที่ทำการปรับแต่งประสิทธิภาพ
- การทดสอบโค้ดใหม่หรือโค้ดที่แก้ไขยังไม่เสร็จสมบูรณ์
- โค้ดเก่า
- โค้ดถูกแทนที่ด้วยการใช้งานแบบอื่น
- โค้ดที่ไม่สามารถเข้าถึงได้ซึ่งโปรแกรมเมอร์ตัดสินใจไม่ลบออกเพราะมันปะปนอยู่กับโค้ดที่สามารถเข้าถึงได้
- โค้ดที่อาจเข้าถึงได้ แต่กรณีการใช้งานปัจจุบันไม่เคยต้องการ
- โค้ดที่ไม่ได้ใช้งานซึ่งถูกเก็บไว้โดยเจตนาเผื่อในกรณีที่อาจจำเป็นต้องใช้ในภายหลัง
- โค้ดนี้ใช้สำหรับการดีบัgเท่านั้น
โค้ดเก่าคือโค้ดที่เคยมีประโยชน์แต่ปัจจุบันไม่ได้ใช้งานหรือไม่จำเป็นอีกต่อไปแล้ว แต่โค้ดที่ไม่สามารถเข้าถึงได้อาจเป็นส่วนหนึ่งของไลบรารี โมดูล หรือรูทีนที่ซับซ้อน ซึ่งมีประโยชน์ต่อส่วนอื่นๆ หรือภายใต้เงื่อนไขที่ไม่ได้เกิดขึ้นในสถานการณ์เฉพาะนั้นๆ
ตัวอย่างของโค้ดที่ไม่สามารถเข้าถึงได้ตามเงื่อนไข อาจเป็นการใช้งานฟังก์ชันจัดรูปแบบสตริงทั่วไปในไลบรารีรันไทม์ ของคอมไพเลอร์ ซึ่งมีโค้ดที่ซับซ้อนในการประมวลผลอาร์กิวเมนต์ที่เป็นไปได้ทั้งหมด โดยที่ใช้จริงเพียงส่วนน้อยเท่านั้น คอมไพเลอร์โดยทั่วไปจะไม่สามารถลบส่วนของโค้ดที่ไม่ได้ใช้งานในระหว่างการคอมไพล์ได้เนื่องจากพฤติกรรมส่วนใหญ่ถูกกำหนดโดยค่าของอาร์กิวเมนต์ในขณะรันไทม์
ตัวอย่าง
ในส่วนของโค้ดภาษาซีนี้:
int foo ( int x , int y ) { return x + y ; int z = x + y ; }นิยามนี้จะไม่ถูกเรียกใช้เลย เนื่องจากฟังก์ชันจะส่งค่ากลับก่อนเสมอ ดังนั้น ตัวแปรจึงไม่จำเป็นต้องได้รับการจัดสรรพื้นที่จัดเก็บหรือกำหนดค่าเริ่มต้น intz=x+y;z
goto ล้มเหลว บั๊ก
SSL/TLSของ Apple จากเดือนกุมภาพันธ์ 2014 มีช่องโหว่ด้านความปลอดภัยที่สำคัญซึ่งรู้จักกันอย่างเป็นทางการในชื่อCVE - 2014-1266และเรียกกันอย่างไม่เป็นทางการว่า "goto fail bug" [ 5 ] [ 6 ] ส่วนของโค้ดที่เกี่ยวข้อง[ 7 ] คือ:
static OSStatus SSLVerifySignedServerKeyExchange ( SSLContext * ctx , bool isRsa , SSLBuffer signedParams , uint8_t * signature , uint16_t signatureLen ) { OSStatus err ; // ... if (( err = SSLHashSHA1 . update ( & hashCtx , & serverRandom )) != 0 ) goto fail ; if (( err = SSLHashSHA1 . update ( & hashCtx , & signedParams )) != 0 ) goto fail ; goto fail ; if (( err = SSLHashSHA1 . final ( & hashCtx , & hashOut )) != 0 ) goto fail ;// ... ล้มเหลว: SSLFreeBuffer ( & signedHashes ); SSLFreeBuffer ( & hashCtx ); ส่งคืนerr ; }ในที่นี้มีgoto failคำสั่งสองคำสั่งที่ต่อเนื่องกัน ในไวยากรณ์ของภาษา Cคำสั่งแรกหลังจากifคำสั่งที่ไม่มีวงเล็บปีกกาเท่านั้นที่จะเป็นเงื่อนไข ดังนั้นคำสั่งที่สองgoto failจึงไม่มีเงื่อนไข และด้วยเหตุนี้จึงข้ามการเรียกใช้เสมอSSLHashSHA1.finalผลที่ตามมาคือerrจะเก็บสถานะของ การดำเนินการอัปเดต SHA1และตราบใดที่การเรียกใช้ ทั้งสองครั้งSSLHashSHA1.updateสำเร็จ การตรวจสอบลายเซ็นจะไม่ล้มเหลว[ 5 ]
ในที่นี้ โค้ดที่ไม่สามารถเข้าถึงได้คือการเรียกใช้finalฟังก์ชัน[ 6 ]การใช้ คอมไพเลอร์ Clangพร้อมตัวเลือก-Weverythingจะรวมการวิเคราะห์โค้ดที่ไม่สามารถเข้าถึงได้ ซึ่งจะทำให้เกิดสัญญาณเตือนสำหรับโค้ดนี้[ 6 ]
ซี++
ในC++โครงสร้างบางอย่างถูกกำหนดให้มีพฤติกรรมที่ไม่แน่นอนคอมไพเลอร์มีอิสระที่จะใช้งานพฤติกรรมใดๆ หรือไม่มีเลย และโดยทั่วไปคอมไพเลอร์ที่ปรับแต่งประสิทธิภาพจะถือว่าโค้ดนั้นไม่สามารถเข้าถึงได้[ 8 ]
การวิเคราะห์
การตรวจจับโค้ดที่ไม่สามารถเข้าถึงได้เป็นรูปแบบหนึ่งของการวิเคราะห์การไหลของควบคุมเพื่อค้นหาโค้ดที่ไม่สามารถเข้าถึงได้ในสถานะโปรแกรมที่เป็นไปได้ใดๆ ในบางภาษา (เช่นJava [ 9 ] ) โค้ดที่ไม่สามารถเข้าถึงได้บางรูปแบบจะถูกห้ามโดยชัดแจ้ง การเพิ่มประสิทธิภาพที่ลบโค้ดที่ไม่สามารถเข้าถึงได้เรียกว่าการกำจัดโค้ดที่ตายแล้ว
โค้ดอาจไม่สามารถเข้าถึงได้อันเป็นผลมาจากการแปลงที่ดำเนินการโดยคอมไพเลอร์ที่ปรับแต่งประสิทธิภาพ (เช่นการกำจัดนิพจน์ย่อยที่เหมือนกัน )
ในทางปฏิบัติ ความซับซ้อนของการวิเคราะห์มีผลกระทบอย่างมากต่อปริมาณโค้ดที่ไม่สามารถเข้าถึงได้ที่ตรวจพบ ตัวอย่างเช่นการพับค่าคงที่และการวิเคราะห์การไหลแบบง่ายแสดงให้เห็นว่าส่วนภายในของคำสั่ง if ในโค้ดต่อไปนี้ไม่สามารถเข้าถึงได้:
int n = 2 + 1 ;ถ้า( n == 4 ) { // เข้าถึงไม่ได้}อย่างไรก็ตาม จำเป็นต้องใช้ความซับซ้อนมากกว่านี้มากจึงจะสามารถระบุได้ว่าบล็อกที่เกี่ยวข้องนั้นไม่สามารถเข้าถึงได้ในโค้ดต่อไปนี้:
#include <math.h>double x = sqrt ( 2 );ถ้า( x > 5 ) { // เข้าถึงไม่ได้}เทคนิคการกำจัดโค้ดที่ไม่สามารถเข้าถึงได้นั้น จัดอยู่ในกลุ่มการเพิ่มประสิทธิภาพเดียวกับการกำจัดโค้ดที่ไม่ได้ใช้งานและการกำจัด โค้ดที่ซ้ำซ้อน
บางภาษาอนุญาตให้ระบุโค้ดที่ไม่สามารถเข้าถึงได้โดยชัดเจน:
- C : ผ่านมาโคร (ใน) [ 10 ]
unreachable()<stddef.h> - C++ : ผ่านฟังก์ชัน (ใน) ซึ่งคือ[ 11 ]
std::unreachable()<utility>[[noreturn]] - C# : สามารถระบุได้โดยใช้คลาส โดยใช้เมธอด[ 12 ]
System.Diagnostics.DebugDebug.Fail() - Java : โดยปกติจะทำเครื่องหมายโดยการโยนข้อยกเว้น[ 13 ]
java.lang.AssertionError - Rust : ผ่านทางมาโคร[ 14 ]
unreachable!() - Swift : ผ่านหรือฟังก์ชันที่ส่งคืน[ 15 ]
fatalError()Never - Zig : ผ่าน
unreachableคำหลัก[ 16 ]
การเข้าถึงไม่ได้เทียบกับการสร้างโปรไฟล์
ในบางกรณี แนวทางปฏิบัติอาจเป็นการผสมผสานระหว่างเกณฑ์การเข้าถึงไม่ได้แบบง่ายๆ และการใช้เครื่องมือวิเคราะห์ประสิทธิภาพ (profiler)เพื่อจัดการกับกรณีที่ซับซ้อนกว่า การวิเคราะห์ประสิทธิภาพโดยทั่วไปไม่สามารถพิสูจน์อะไรได้เกี่ยวกับการเข้าถึงไม่ได้ของโค้ด แต่เป็นวิธี ง่ายๆ ที่อาจ ช่วยค้นหาโค้ดที่เข้าถึงไม่ได้ เมื่อพบโค้ดที่น่าสงสัยแล้ว อาจใช้วิธีอื่นๆ เช่น เครื่องมือวิเคราะห์โค้ดที่มีประสิทธิภาพมากกว่า หรือแม้แต่การวิเคราะห์ด้วยตนเอง เพื่อตัดสินว่าโค้ดนั้นเข้าถึงไม่ได้จริงหรือไม่
ดูเพิ่มเติม
- ความครอบคลุมของรหัส
- รหัสที่ซ้ำซ้อน
- รหัสตาย
- รหัสอ็อกซ์โบว์
- ปัญหาการหยุดทำงาน – ปัญหาทั่วไปในการพิจารณาว่าโค้ดส่วนใดส่วนหนึ่งไม่สามารถเข้าถึงได้หรือไม่นั้น ยากพอๆ กับปัญหาการหยุดทำงาน และด้วยเหตุนี้จึงเป็นปัญหาที่ไม่สามารถตัดสิน ได้
สรุปเนื้อหา
ข้อมูลสำคัญจากบทความ
ข้อมูลสำคัญเกี่ยวกับ รหัสที่ไม่สามารถเข้าถึงได้
ใน การเขียน โปรแกรมคอมพิวเตอร์โค้ดที่ไม่สามารถเข้าถึงได้คือส่วนหนึ่งของซอร์สโค้ดของโปรแกรมซึ่งไม่สามารถเรียกใช้งานได้เลย เนื่องจากไม่มี เส้นทาง...
สาเหตุ
โค้ดที่ไม่สามารถเข้าถึงได้อาจเกิดขึ้นได้จากหลายสาเหตุ เช่น:
goto ล้มเหลว บั๊ก
SSL/TLS ของ Apple จากเดือนกุมภาพันธ์ 2014 มีช่องโหว่ด้านความปลอดภัยที่สำคัญซึ่งรู้จักกันอย่างเป็นทางการในชื่อ CVE - 2014-1266และเรียกกันอย่างไม่เป็นทางการว่า "goto fail bug" [ 5 ] [ 6 ] ส่วนของโค้ดที่เกี่ยวข้อง [ 7 ] คือ:
ซี++
ใน C++ โครงสร้างบางอย่างถูกกำหนดให้มี พฤติกรรมที่ไม่แน่นอน คอมไพเลอร์มีอิสระที่จะใช้งานพฤติกรรมใดๆ หรือไม่มีเลย และโดยทั่วไปคอมไพเลอร์ที่ปรับแต่งประสิทธิภาพจะถือว่าโค้ดนั้นไม่สามารถเข้าถึงได้ [ 8 ]