การถกเถียงล่าสุดเกี่ยวกับปัญหาความเข้ากันได้ของ curl กับ Clang's UndefinedBehaviorSanitizer (UBsan) ได้จุดประเด็นการถกเถียงอย่างเข้มข้นในชุมชนนักพัฒนาเกี่ยวกับพฤติกรรมที่ไม่ได้กำหนด (undefined behavior) ของภาษา C และผลกระทบต่อการใช้งานจริง เหตุการณ์นี้สะท้อนให้เห็นความตึงเครียดที่เพิ่มขึ้นระหว่างข้อกำหนดทางทฤษฎีของภาษาและการปฏิบัติในการเขียนโปรแกรมที่ใช้กันมานานหลายทศวรรษ
เหตุการณ์ที่เกิดขึ้น
จุดเริ่มต้นของการถกเถียงนี้มาจากการเปลี่ยนแปลงล่าสุดในโค้ดของ curl ที่ Daniel Haxx ต้องแก้ไขวิธีการกำหนดประเภท CURL เนื่องจาก UBsan แจ้งเตือนว่าการไม่ตรงกันของประเภทตัวชี้ฟังก์ชันเป็นพฤติกรรมที่ไม่ได้กำหนด สิ่งที่ดูเหมือนจะเป็นรูปแบบการใช้งานที่สมเหตุสมผล - การใช้การกำหนดประเภทที่แตกต่างกันสำหรับโค้ดภายในและภายนอก - กลับกลายเป็นสิ่งที่ไม่ถูกต้องทางเทคนิคตามมาตรฐานของภาษา C
ทำความเข้าใจปัญหาทางเทคนิค
ปัญหาหลักเกี่ยวข้องกับความเข้ากันได้ของตัวชี้ฟังก์ชันและการแปลงประเภท แม้ว่านักเขียนโปรแกรม C จำนวนมากจะเชื่อว่าตัวชี้ประเภทต่างๆ (เช่น void* และ char*) สามารถใช้แทนกันได้อย่างอิสระ แต่มาตรฐาน C จริงๆ แล้วถือว่าการเรียกฟังก์ชันผ่านตัวชี้ที่มีประเภทต่างกันเป็นพฤติกรรมที่ไม่ได้กำหนด
ผลกระทบต่อแพลตฟอร์ม
นักพัฒนาหลายคนในชุมชนได้ชี้ให้เห็นว่านี่ไม่ใช่แค่ความกังวลทางทฤษฎี:
- Pointer Authentication : แพลตฟอร์มสมัยใหม่ที่มีการตรวจสอบความถูกต้องของตัวชี้อาจเข้ารหัสประเภทฟังก์ชันลงในตัวชี้เอง
- CHERI Architecture : ระบบที่ใช้ CHERI สามารถบังคับใช้การตรวจสอบประเภทตัวชี้อย่างเข้มงวด
- Emscripten : แพลตฟอร์มนี้จะทำงานผิดพลาดอย่างชัดเจนเมื่อใช้การแปลงตัวชี้ฟังก์ชันที่ไม่เข้ากัน
บริบทที่กว้างขึ้น
สถานการณ์นี้แสดงให้เห็นการถกเถียงที่ใหญ่ขึ้นในชุมชนผู้เขียนโปรแกรมภาษา C:
- มาตรฐานกับการปฏิบัติ : รูปแบบการเขียนโปรแกรมที่ใช้งานได้อย่างน่าเชื่อถือในทางปฏิบัติหลายอย่าง ทางเทคนิคแล้วถือเป็นพฤติกรรมที่ไม่ได้กำหนดตามมาตรฐาน C
- วิวัฒนาการของฮาร์ดแวร์ : แม้ว่า C จะได้รับการยกย่องว่าใกล้ชิดกับฮาร์ดแวร์ แต่ฟีเจอร์ฮาร์ดแวร์สมัยใหม่และกลไกความปลอดภัยกำลังทำให้การปฏิบัติแบบดั้งเดิมของ C มีปัญหามากขึ้น
- การปรับปรุงประสิทธิภาพของคอมไพเลอร์ : โค้ดที่เคยถือว่าปลอดภัยและน่าเชื่อถืออาจทำงานผิดพลาดเมื่อการปรับปรุงประสิทธิภาพของคอมไพเลอร์ใช้ประโยชน์จากพฤติกรรมที่ไม่ได้กำหนดมากขึ้น
ก้าวต่อไป
ชุมชนได้เสนอแนวทางแก้ไขหลายประการ:
- การใช้ฟังก์ชัน trampoline เพื่อจัดการการแปลงประเภทอย่างปลอดภัย
- การเพิ่มหมวดหมู่ใหม่ของการกำหนดพฤติกรรมในมาตรฐาน C
- การใช้การตรวจสอบเฉพาะแพลตฟอร์มด้วยตัวเลือกของคอมไพเลอร์
ผลกระทบต่อนักพัฒนา
เหตุการณ์นี้เตือนให้นักพัฒนาที่มีประสบการณ์ต้องระมัดระวังเกี่ยวกับข้อสันนิษฐานเกี่ยวกับพฤติกรรมของ C ตามที่สมาชิกชุมชนหลายคนได้กล่าวไว้ เครื่องมืออย่าง UBsan กำลังมีความสำคัญมากขึ้นในการระบุปัญหาที่อาจเกิดขึ้นก่อนที่จะสร้างปัญหาในการใช้งานจริง
การถกเถียงนี้ยังชี้ให้เห็นถึงความต้องการที่เพิ่มขึ้นสำหรับภาษาโปรแกรมสมัยใหม่ที่สามารถให้ทั้งการควบคุมระดับต่ำและการรับประกันความปลอดภัยที่แข็งแกร่ง โดยหลายคนชี้ไปที่ Rust เป็นตัวอย่างของวิธีการรักษาสมดุลนี้
การแก้ไขของ Daniel Haxx สำหรับ curl แสดงให้เห็นถึงการประนีประนอมในทางปฏิบัติ โดยกลับไปใช้การกำหนดประเภทที่ง่ายขึ้นเพื่อให้แน่ใจว่าเข้ากันได้กับทุกแพลตฟอร์ม แม้จะต้องเสียสละความชัดเจนของโค้ดภายในบางส่วน
สถานการณ์นี้ยังคงพัฒนาต่อไปในขณะที่ชุมชน C พยายามรักษาสมดุลระหว่างความเข้ากันได้กับรุ่นเก่า ความปลอดภัย และความสามารถของฮาร์ดแวร์สมัยใหม่