ผมขอพูดเรื่องนี้อย่างชัดเจนเราไม่เรียกไม่ได้กำหนดพฤติกรรมในโปรแกรมของเรา มันไม่เคยเป็นความคิดที่ดี กฎนี้มีข้อยกเว้นที่หายากน้อยมาก ตัวอย่างเช่นหากคุณเป็นผู้ดำเนินการห้องสมุดที่ใช้ออฟเซ็ต หากกรณีของคุณตกอยู่ภายใต้ข้อยกเว้นดังกล่าวคุณน่าจะรู้เรื่องนี้อยู่แล้ว ในกรณีนี้เรารู้ว่าการใช้ตัวแปรอัตโนมัติเตรียมเป็นพฤติกรรมที่ไม่ได้กำหนด
คอมไพเลอร์กลายเป็นคนก้าวร้าวด้วยการปรับให้เหมาะสมกับพฤติกรรมที่ไม่ได้กำหนดและเราสามารถค้นหาได้หลายกรณีที่พฤติกรรมที่ไม่ได้กำหนดนั้นนำไปสู่ข้อบกพร่องด้านความปลอดภัย กรณีที่น่าอับอายที่สุดคือลีนุกซ์เคอร์เนลตัวชี้ตรวจสอบการลบซึ่งฉันพูดถึงในคำตอบของฉันในการรวบรวมข้อผิดพลาด C ++? ซึ่งการปรับให้เหมาะสมกับคอมไพเลอร์รอบพฤติกรรมที่ไม่ได้กำหนดเปลี่ยนลูป จำกัด ให้เป็นอนันต์
เราสามารถอ่านการเพิ่มประสิทธิภาพที่เป็นอันตรายของ CERT และการสูญเสียความเป็นเวร ( วิดีโอ ) ซึ่งกล่าวว่าเหนือสิ่งอื่นใด:
มากขึ้นผู้เขียนคอมไพเลอร์ใช้ประโยชน์จากพฤติกรรมที่ไม่ได้กำหนดในภาษาการเขียนโปรแกรม C และ C ++ เพื่อปรับปรุงการเพิ่มประสิทธิภาพ
บ่อยครั้งที่การปรับให้เหมาะสมเหล่านี้รบกวนความสามารถของนักพัฒนาในการทำการวิเคราะห์สาเหตุ - ผลบนซอร์สโค้ดของพวกเขานั่นคือการวิเคราะห์การพึ่งพาของผลลัพธ์ดาวน์สตรีมในผลลัพธ์ก่อนหน้า
ดังนั้นการเพิ่มประสิทธิภาพเหล่านี้จึงกำจัดสาเหตุในซอฟต์แวร์และเพิ่มความน่าจะเป็นของความผิดพลาดของซอฟต์แวร์ข้อบกพร่องและช่องโหว่
โดยเฉพาะอย่างยิ่งเกี่ยวกับค่าที่ไม่แน่นอนรายงานข้อบกพร่องมาตรฐาน C 451: ความไม่แน่นอนของตัวแปรอัตโนมัติที่ไม่ได้กำหนดค่าเริ่มต้นสำหรับการอ่านที่น่าสนใจ ยังไม่ได้รับการแก้ไข แต่นำเสนอแนวคิดของค่าสั่นคลอนซึ่งหมายถึงความไม่แน่นอนของค่าอาจแพร่กระจายผ่านโปรแกรมและสามารถมีค่าไม่แน่นอนที่แตกต่างกันที่จุดที่แตกต่างกันในโปรแกรม
ฉันไม่รู้ตัวอย่างที่เกิดขึ้น แต่ ณ จุดนี้เราไม่สามารถแยกแยะได้
ตัวอย่างจริงไม่ใช่ผลลัพธ์ที่คุณคาดหวัง
คุณไม่น่าจะได้รับค่าสุ่ม คอมไพเลอร์สามารถเพิ่มประสิทธิภาพวงออกไปโดยสิ้นเชิง ตัวอย่างเช่นกรณีที่ง่ายนี้:
void updateEffect(int arr[20]){
for(int i=0;i<20;i++){
int r ;
arr[i] = r ;
}
}
เสียงดังกราวปรับมันให้เหมาะสม ( ดูภาพสด ):
updateEffect(int*): # @updateEffect(int*)
retq
หรืออาจรับค่าศูนย์ทั้งหมดเช่นเดียวกับกรณีที่แก้ไขนี้:
void updateEffect(int arr[20]){
for(int i=0;i<20;i++){
int r ;
arr[i] = r%255 ;
}
}
ดูมันมีชีวิตอยู่ :
updateEffect(int*): # @updateEffect(int*)
xorps %xmm0, %xmm0
movups %xmm0, 64(%rdi)
movups %xmm0, 48(%rdi)
movups %xmm0, 32(%rdi)
movups %xmm0, 16(%rdi)
movups %xmm0, (%rdi)
retq
ทั้งสองกรณีนี้เป็นรูปแบบที่ยอมรับได้อย่างสมบูรณ์แบบของพฤติกรรมที่ไม่ได้กำหนด
หมายเหตุถ้าเราอยู่บน Itanium เราสามารถจบด้วยค่ากับดัก :
[... ] หากการลงทะเบียนเกิดขึ้นเพื่อเก็บค่าที่ไม่ได้เป็นสิ่งพิเศษให้อ่านกับดักการลงทะเบียนยกเว้นสำหรับคำแนะนำบางอย่าง [... ]
หมายเหตุสำคัญอื่น ๆ
มันเป็นเรื่องที่น่าสนใจที่จะสังเกตเห็นความแปรปรวนระหว่าง gcc กับเสียงดังในโครงการ UB Canariesว่าพวกเขาเต็มใจที่จะใช้ประโยชน์จากพฤติกรรมที่ไม่ได้กำหนดซึ่งเกี่ยวข้องกับหน่วยความจำที่ไม่ได้เตรียมการ บันทึกบทความ ( เหมืองเน้น ):
แน่นอนว่าเราต้องชัดเจนอย่างสมบูรณ์กับตัวเราเองว่าความคาดหวังใด ๆ นั้นไม่เกี่ยวข้องกับมาตรฐานภาษาและทุกอย่างเกี่ยวกับสิ่งที่คอมไพเลอร์เกิดขึ้นเนื่องจากผู้ให้บริการของคอมไพเลอร์นั้นไม่เต็มใจที่จะใช้ประโยชน์จาก UB หรือเพียงแค่ เพราะพวกเขายังไม่ได้อากาศรอบ ๆ เพื่อใช้ประโยชน์จากมันยัง เมื่อไม่มีการรับประกันที่แท้จริงจากผู้ให้บริการคอมไพเลอร์เราอยากจะบอกว่า UB ที่ยังไม่ได้ใช้เป็นระเบิดเวลาพวกเขากำลังรอที่จะออกไปข้างนอกในเดือนหน้าหรือปีหน้าเมื่อคอมไพเลอร์เริ่มก้าวร้าวมากขึ้น
ดังที่ Matthieu M. ชี้ให้เห็นสิ่งที่โปรแกรมเมอร์ C ทุกคนควรรู้เกี่ยวกับพฤติกรรมที่ไม่ได้กำหนด # 2/3นั้นเกี่ยวข้องกับคำถามนี้ มันบอกว่าท่ามกลางสิ่งอื่น ๆ ( เน้นฉัน ):
สิ่งที่สำคัญและน่ากลัวที่จะตระหนักคือว่าเพียงเกี่ยวกับการใด ๆ
เพิ่มประสิทธิภาพขึ้นอยู่กับพฤติกรรมที่ไม่ได้กำหนดสามารถเริ่มต้นถูกเรียกรหัสรถในเวลาใด ๆ ในอนาคต การอินไลน์การวนลูปการเลื่อนระดับหน่วยความจำและการปรับให้เหมาะสมอื่น ๆ จะทำให้ดีขึ้นเรื่อย ๆ และส่วนสำคัญของเหตุผลที่มีอยู่คือการเปิดเผยการเพิ่มประสิทธิภาพรองเช่นเดียวกับที่กล่าวมาข้างต้น
สำหรับฉันนี่เป็นเรื่องที่ไม่น่าพอใจอย่างมากบางส่วนเพราะคอมไพเลอร์กลายเป็นถูกตำหนิอย่างหลีกเลี่ยงไม่ได้ แต่ก็เพราะนั่นหมายความว่าร่างใหญ่ของรหัส C เป็นเหมืองที่ดินรอการระเบิด
เพื่อประโยชน์ครบถ้วนฉันอาจจะพูดถึงว่าการใช้งานสามารถเลือกที่จะทำพฤติกรรมที่ไม่ได้กำหนดไว้เป็นอย่างดีเช่นgcc อนุญาตประเภทเล่นสำนวนผ่านสหภาพแรงงานในขณะที่ใน C ++ นี้ดูเหมือนว่าพฤติกรรมที่ไม่ได้กำหนด หากเป็นกรณีนี้การนำไปปฏิบัติควรจัดทำเอกสารและโดยทั่วไปจะไม่สามารถพกพาได้