โพสต์บล็อกล่าสุดได้จุดประกายการอภิปรายอย่างเข้มข้นในชุมชนโปรแกรมเมอร์เกี่ยวกับปัญหาความปลอดภัยที่อาจเกิดขึ้นในการออกแบบอินเทอร์เฟซ I/O ใหม่ของ Zig ความขัดแย้งมีจุดศูนย์กลางอยู่ที่วิธีการที่ abstraction *std.lo.Reader
และ Writer
ของ Zig จัดการกับขนาด buffer ซึ่งนำไปสู่สถานการณ์ที่พฤติกรรมของโค้ดกลายเป็นสิ่งที่คาดเดาไม่ได้หรือล้มเหลวโดยสิ้นเชิง
ปัญหาหลักจากการพึ่งพา Buffer
ปัญหาเกิดขึ้นเมื่อพยายามเขียนฟังก์ชันแบบ generic ที่ทำงานกับ abstraction I/O ของ Zig เมื่อนักพัฒนาสร้างฟังก์ชันเพื่ออ่านข้อมูลและเขียนไปยัง stdout พวกเขาต้องระบุขนาด buffer โดยไม่ทราบว่า reader หรือ writer พื้นฐานต้องการอะไรจริงๆ สิ่งนี้สร้างปัญหาพื้นฐาน: reader และ writer ที่แตกต่างกันสามารถมีข้อกำหนดขนาด buffer เฉพาะที่ไม่ปรากฏใน type signature ของพวกมัน
ปัญหากลายเป็นที่ชัดเจนโดยเฉพาะกับไลบรารีการบีบอัด เมื่อใช้การคลายการบีบอัด zstd ของ Zig กับ buffer ที่เล็กเกินไป (เช่น 64 ไบต์) โค้ดจะล้มเหลวด้วย assertion ในโหมด debug และเข้าสู่ลูปอนันต์ในโหมด release ที่น่าวิตกยิ่งกว่านั้น ความล้มเหลวสามารถขึ้นอยู่กับข้อมูลอินพุต ทำให้ยากมากที่จะตรวจจับระหว่างการทดสอบ
การแสดงออกของปัญหา:
- บัฟเฟอร์ขนาดเล็ก (64 ไบต์): เกิดข้อผิดพลาดในการตรวจสอบในโหมดดีบัก เกิดลูปไม่สิ้นสุดในโหมดรีลีส
- บัฟเฟอร์ขนาดใหญ่: ทำงานได้อย่างถูกต้อง
- ความล้มเหลวสามารถขึ้นอยู่กับข้อมูลอินพุต ทำให้ยากต่อการตรวจจับในระหว่างการทดสอบ
การอภิปรายของชุมชน: Bug หรือข้อบกพร่องในการออกแบบ?
ชุมชนโปรแกรมเมอร์แบ่งออกเป็นสองฝ่ายว่าสิ่งนี้แสดงถึงปัญหาการออกแบบพื้นฐานหรือเพียงแค่ bug ในการ implementation นักพัฒนาบางคนโต้แย้งว่านี่เป็นเพียง bug ใน reader implementation เฉพาะมากกว่าปัญหาระบบกับ Writer interface พวกเขาแนะนำว่า reader ไม่ควรพึ่งพาขนาด buffer ของ writer ที่ส่งไปยัง stream implementation ของพวกมัน และหากพวกมันต้องการข้อกำหนดเฉพาะ พวกมันควรส่งคืน error ที่เหมาะสมแทนที่จะทำให้เกิดลูปอนันต์
อย่างไรก็ตาม คนอื่นๆ ชี้ให้เห็นว่าการออกแบบ API เองส่งเสริม implementation ที่พึ่งพาขนาด buffer สิ่งนี้ทำให้เกิดคำถามเกี่ยวกับวิธีที่ decompression reader ควรได้รับการ implement อย่างถูกต้อง - พวกมันควรจัดการ buffer ขนาดที่รับประกันของตัวเองหรือไม่ และหากเป็นเช่นนั้น พวกมันควร allocate หน่วยความจำนั้นอย่างไร?
รายละเอียดทางเทคนิค:
- ปัญหาเกิดขึ้นกับ abstractions ของ
*std.lo.Reader
และWriter
- ปัญหาเฉพาะที่แสดงให้เห็นด้วย
std.compress.zstd.Decompress
- ความต้องการขนาด buffer เป็นแบบ implicit และไม่สามารถมองเห็นได้ใน type signatures
- ฟังก์ชัน generic ไม่สามารถกำหนดขนาด buffer ที่ต้องการได้ในเวลา compile
ความท้าทายด้านเอกสาร
ในขณะที่บางคนโต้แย้งว่านี่เป็นปัญหาเอกสารอย่างหมดจด นักวิจารณ์โต้แย้งว่าเอกสารเพียงอย่างเดียวไม่สามารถแก้ไขปัญหาพื้นฐานได้ ในสถานการณ์โลกแห่งความจริง ลักษณะของ reader อาจไม่เป็นที่รู้จักหรือยากที่จะกำหนด ตัวอย่างเช่น ประเภทของ reader อาจขึ้นอยู่กับเงื่อนไขตาม HTTP response header หรือนักพัฒนาไลบรารีอาจรับ reader เป็นอินพุตในขณะที่นำเสนอ reader ของตัวเองเป็นเอาต์พุต - ทำให้ไม่ชัดเจนว่าข้อกำหนด buffer ใดควรได้รับการจัดทำเอกสาร
สิ่งนี้ดูเหมือนเป็นไปไม่ได้เกือบจะ - เหมือนกับว่าฉันต้องทำอะไรผิด และถ้าฉันทำ ฉันขอโทษ แต่ถ้าฉันไม่ได้ทำ นี่คือปัญหาใช่ไหม?
ผลกระทบที่กว้างขึ้นต่อปรัชญาการออกแบบของ Zig
ความขัดแย้งนี้สัมผัสกับคำถามที่ใหญ่กว่าเกี่ยวกับแนวทางของ Zig ต่อความปลอดภัยและความชัดเจน ในขณะที่ Zig มีเป้าหมายเพื่อหลีกเลี่ยง hidden control flow และทำให้ทุกอย่างชัดเจน ข้อกำหนดขนาด buffer สร้างการพึ่งพาแบบ implicit ที่สามารถนำไปสู่ความล้มเหลวในเวลาทำงาน การอภิปรายยังได้เน้นความตึงเครียดระหว่างแนวทางที่แตกต่างกันในการเขียนโปรแกรมระบบ โดยนักพัฒนาบางคนชอบการจัดการหน่วยความจำด้วยตนเองแบบชัดเจนของ Zig ในขณะที่คนอื่นๆ ชอบการรับประกันความปลอดภัยในเวลาคอมไพล์ของ Rust
การอภิปรายขยายไปเกินรายละเอียดทางเทคนิคไปสู่พลวัตของชุมชน โดยมีการวิจารณ์บางส่วนที่มุ่งไปที่วิธีการรับและประมวลผลความคิดเห็น ผู้เขียนบล็อกต้นฉบับได้เขียนเกี่ยวกับ Zig อย่างกว้างขวางในอดีต รวมถึงเนื้อหาการศึกษาที่เป็นประโยชน์ ทำให้การตอบสนองแบบดูถูกต่อการวิจารณ์เฉพาะนี้น่าสังเกตมากขึ้น
มองไปข้างหน้า
ปัญหานี้แสดงถึงจุดตัดสินใจที่สำคัญสำหรับการออกแบบอินเทอร์เฟซ I/O ของ Zig ทีมพัฒนาต้องตัดสินใจว่าจะถือว่านี่เป็น bug ในการ implementation ที่ต้องแก้ไขหรือเป็นปัญหาการออกแบบพื้นฐานที่ต้องการการเปลี่ยนแปลงทางสถาปัตยกรรม การแก้ไขน่าจะมีอิทธิพลต่อวิธีที่นักพัฒนามองการมุ่งมั่นของ Zig ต่อความปลอดภัยและความคาดเดาได้ในการเขียนโปรแกรมระบบ
ความขัดแย้งยังเน้นความท้าทายที่เผชิญหน้ากับภาษาการเขียนโปรแกรมระบบใหม่ใดๆ ที่พยายามสร้างสมดุลระหว่างประสิทธิภาพ ความปลอดภัย และความใช้งานได้ ในขณะที่สร้างชุมชนที่ต้อนรับรอบการวิจารณ์ทางเทคนิคที่สร้างสรรค์
อ้างอิง: Is Zig's New Writer Unsafe?