การศึกษาเชิงลึกเมื่อเร็ว ๆ นี้เกี่ยวกับความสามารถในการทำงานร่วมกันของหน่วยความจำระหว่าง Rust และ C ได้ดึงดูดความสนใจของนักพัฒนา โดยเผยให้เห็นพฤติกรรมที่น่าประหลาดใจเมื่อมีการผสมผสาน memory allocator ระหว่างสองภาษานี้ การสำรวจทางเทคนิคแสดงให้เห็นว่าการจัดสรรหน่วยความจำด้วยภาษาหนึ่งและปลดปล่อยด้วยอีกภาษาหนึ่งไม่ได้ทำให้เกิดข้อผิดพลาดทันทีเสมอไป ซึ่งขัดกับสิ่งที่นักพัฒนาหลายคนอาจคาดหวัง
รหัสการออกของความปลอดภัยหน่วยความจำ
0x00000000
(SUCCESS): โปรแกรมทำงานสำเร็จ0x00000001
(FAILURE): ข้อผิดพลาดการแบ่งส่วน ข้อผิดพลาดทั่วไปที่บ่งชี้ถึงความเสียหายของหน่วยความจำ
พฤติกรรมของ Default Allocator อธิบายความลึกลับนี้
ข้อมูลเชิงลึกที่สำคัญจากการอภิปรายในชุมชนมุ่งเน้นไปที่เหตุผลว่าทำไมการดำเนินการ mixed allocator มักจะดูเหมือนทำงานได้โดยไม่เกิดข้อผิดพลาด ดังที่นักพัฒนาคนหนึ่งชี้ให้เห็น Rust ใช้ libc allocator เดียวกันโดยค่าเริ่มต้น ซึ่งอธิบายได้ว่าทำไมการข้ามขอบเขตภาษาสำหรับการดำเนินการหน่วยความจำจึงไม่ล้มเหลวทันที รากฐานที่ใช้ร่วมกันนี้หมายความว่าในหลายกรณี หน่วยความจำที่จัดสรรโดย malloc ของ C สามารถปลดปล่อยได้โดย deallocator ของ Rust โดยไม่ก่อให้เกิดข้อผิดพลาดที่เห็นได้ชัด แม้ว่าแนวทางปฏิบัตินี้จะยังคงเป็นอันตรายและไม่สามารถคาดเดาได้
พฤติกรรมของ allocator ที่ใช้ร่วมกันสร้างความรู้สึกปลอดภัยที่ผิดพลาด แม้ว่าการดำเนินการอาจทำงานได้ในกรณีทดสอบง่าย ๆ แต่อาจล้มเหลวอย่างไม่สามารถคาดเดาได้ในสถานการณ์ที่ซับซ้อนกว่าหรือการกำหนดค่าระบบที่แตกต่างกัน สิ่งนี้ทำให้แนวทางปฏิบัตินี้เป็นอันตรายอย่างยิ่งสำหรับโค้ดที่ใช้ในการผลิต
ความกังวลของชุมชนเกี่ยวกับคุณภาพเนื้อหา
การอภิปรายด้านข้างที่น่าสนใจเกิดขึ้นเกี่ยวกับรูปแบบการเขียนของบทความและการใช้เนื้อหาที่สร้างโดย AI ที่อาจเป็นไปได้ ผู้อ่านบางคนแสดงความสงสัยเกี่ยวกับการไว้วางใจเนื้อหาทางเทคนิคที่อาจสร้างขึ้นโดยเครื่องจักร โดยเน้นย้ำถึงความกังวลที่เพิ่มขึ้นในชุมชนนักพัฒนาเกี่ยวกับความน่าเชื่อถือของการเขียนทางเทคนิคที่ช่วยเหลือโดย AI การอภิปรายสัมผัสกับคำถามที่กว้างขึ้นเกี่ยวกับวิธีที่นักพัฒนาประเมินและไว้วางใจแหล่งข้อมูลทางเทคนิคในยุคของการสร้างเนื้อหา AI ที่เพิ่มขึ้น
โซลูชันการทำงานร่วมกันในทางปฏิบัติ
การอภิปรายเผยให้เห็นแนวทางที่ได้รับการยอมรับหลายแนวทางสำหรับการทำงานร่วมกันระหว่าง Rust-C อย่างปลอดภัย แอตทริบิวต์ #[repr(C)]
ช่วยให้ struct ของ Rust สามารถเข้าถึงได้โดยตรงจากทั้งสองภาษาโดยไม่ต้องใช้ฟังก์ชัน accessor ตราบใดที่ layout ของ struct เป็นไปตามข้อตกลงของ C เครื่องมืออย่าง bindgen สามารถสร้าง Rust bindings ที่เหมาะสมจาก C headers โดยอัตโนมัติ จัดการกับสถานการณ์การทำงานร่วมกันทั่วไปอย่างปลอดภัย
สำหรับสถานการณ์การรวมระบบที่ซับซ้อน เช่น การรวม Rust code เข้ากับระบบอย่าง PostgreSQL ที่มี custom allocators นักพัฒนามักจะใช้แนวทาง handle-based ซึ่งเกี่ยวข้องกับการจัดเก็บโครงสร้างข้อมูลที่ซับซ้อนแบบ global และส่งผ่าน handles ระหว่างภาษา หลีกเลี่ยงการแบ่งปันหน่วยความจำโดยตรงทั้งหมด
เครื่องมือสำหรับการทำงานร่วมกันระหว่าง Rust-C
cbindgen
: สร้าง bindings ของ Rust จาก headers ของ Ccc-rs
: ไลบรารี Rust สำหรับคอมไพล์โค้ด C/C++[repr(C)]
: แอตทริบิวต์สำหรับการจัดเรียง struct ที่เข้ากันได้กับ Cbindgen
: สร้าง structs ดั้งเดิมของ Rust จาก headers ของ C โดยอัตโนมัติ
มองไปข้างหน้า
การสนับสนุนที่จะมาถึงสำหรับ custom allocators ใน standard library ของ Rust สัญญาว่าจะทำให้สถานการณ์ mixed-language ง่ายต่อการจัดการอย่างปลอดภัย การพัฒนานี้อาจช่วยให้โครงสร้างข้อมูลของ Rust ใช้ system-specific allocators ได้โดยตรง ลดความจำเป็นในการใช้แนวทางแก้ไขชั่วคราวในส่วนขยายฐานข้อมูลและการรวมระบบระดับอื่น ๆ
การอภิปรายเน้นย้ำหลักการสำคัญในการเขียนโปรแกรมระบบ: แม้ว่าการดำเนินการที่ไม่ปลอดภัยจะดูเหมือนทำงานได้ การเข้าใจว่าทำไมมันถึงทำงานได้และเมื่อไหร่ที่อาจล้มเหลวยังคงเป็นสิ่งสำคัญสำหรับการสร้างซอฟต์แวร์ที่เชื่อถือได้ ความสำเร็จที่ปรากฏของการดำเนินการ mixed allocator ทำหน้าที่เป็นเครื่องเตือนใจว่าข้อผิดพลาดทันทีไม่ใช่ตัวบ่งชี้ที่ดีที่สุดเสมอไปของความถูกต้องของโค้ด
อ้างอิง: Part 1. A Deep Dive Into Rust and C Memory Interoperability