การผสมผสานหน่วยความจำระหว่าง Rust และ C ไม่ได้ทำให้เกิดข้อผิดพลาดเสมอไปตามที่คาดหวัง ก่อให้เกิดการอภิปรายในหมู่นักพัฒนา

ทีมชุมชน BigGo
การผสมผสานหน่วยความจำระหว่าง Rust และ C ไม่ได้ทำให้เกิดข้อผิดพลาดเสมอไปตามที่คาดหวัง ก่อให้เกิดการอภิปรายในหมู่นักพัฒนา

การศึกษาเชิงลึกเมื่อเร็ว ๆ นี้เกี่ยวกับความสามารถในการทำงานร่วมกันของหน่วยความจำระหว่าง 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 ของ C
  • cc-rs: ไลบรารี Rust สำหรับคอมไพล์โค้ด C/C++
  • [repr(C)]: แอตทริบิวต์สำหรับการจัดเรียง struct ที่เข้ากันได้กับ C
  • bindgen: สร้าง 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