ความปลอดภัยของหน่วยความจำประเภทที่ไม่มีหน่วยความจำแบบแมนนวลจัดการหรือการรวบรวมขยะรันไทม์?


13

สมมติว่าเราต้องการภาษาการเขียนโปรแกรมที่ใช้งานง่ายและบริสุทธิ์เช่น Haskell หรือ Idris ซึ่งมีจุดประสงค์เพื่อการเขียนโปรแกรมระบบโดยไม่มีการรวบรวมขยะและไม่มีเวลาทำงาน (หรืออย่างน้อยก็ไม่เกิน C และ Rust "runtimes") สิ่งที่สามารถทำงานได้ไม่มากก็น้อยบนโลหะเปลือย

มีตัวเลือกอะไรบ้างสำหรับความปลอดภัยของหน่วยความจำแบบสแตติกที่ไม่ต้องการการจัดการหน่วยความจำแบบแมนนวลหรือการรวบรวมขยะแบบเรียลไทม์และวิธีการแก้ไขปัญหาโดยใช้ระบบประเภทของฟังก์ชั่นบริสุทธิ์เช่น Haskell หรือ Idris


คุณกำลังบอกว่าคุณต้องการประเภทของภาษาเพื่อใช้เป็นวิธีหลีกเลี่ยงการเก็บขยะหรือไม่? ปัญหาพื้นฐานเกิดขึ้นในการประเมินฟังก์ชั่น ฟังก์ชั่นจะถูกประเมินเป็นค่าปิดซึ่งจะสรุปสภาวะแวดล้อมรันไทม์ปัจจุบัน นั่นคือแหล่งที่มาหลักของการทำคอลเลกชันขยะ ถ้าคุณไม่เปลี่ยนกฎการพิมพ์สำหรับฟังก์ชั่นฉันไม่เห็นว่าจะช่วยได้อย่างไร Java และภาษาอื่น ๆ ที่มี -abstractions ได้รับการแจ้งเตือนนี้โดยการปิดกั้นการก่อตัวของการปิด: พวกเขาไม่อนุญาตการอ้างอิงที่จะต้องมีการรวบรวม gabrage λ
Andrej Bauer

สนิมแน่นอนต้องแก้ไขปัญหาเดียวกันของการประเมินฟังก์ชั่นและการปิดด้วยรูปแบบความเป็นเจ้าของและตัวตรวจสอบการยืม? การจัดการหน่วยความจำหมายถึงการรู้ว่าค่ายังมีชีวิตอยู่นานแค่ไหนค่าอื่น ๆ ขึ้นอยู่กับพวกเขาและทำลายค่าที่ไม่ได้ใช้เมื่อมันตายใช่ไหม? ดังนั้นฉันเดาว่าฉันถามจริง ๆ ว่าการจัดการหน่วยความจำสามารถถูกห่อหุ้มในชุดประเภทที่สามารถตรวจสอบความถูกต้องผ่านระบบประเภทโดยไม่ขยายกลไกพื้นฐานของภาษาหรือคอมไพเลอร์โดยเพิ่มระบบความเป็นเจ้าของใหม่ทั้งหมดและ "ยืม ตัวตรวจสอบ "(ซึ่งเป็นวิธีของ Rust)
Chase May

แล้วLFPLของ Martin Hofmann ล่ะ มันมีประเภทฐานพิเศษ "เพชร" ซึ่งมีการบังคับใช้ประเภทเชิงเส้นประเภทการอนุญาตให้ประเภทบัญชีสำหรับการใช้งานหน่วยความจำขั้นพื้นฐาน (การจัดสรร / การจัดสรรคืน) ไปในทิศทางที่คุณกำลังพูดถึงหรือไม่
Damiano Mazza

คำตอบ:


18

มีกลวิธีหลักสองประการสำหรับการจัดการหน่วยความจำด้วยตนเองอย่างปลอดภัย

  1. วิธีแรกคือการใช้ตรรกะ substructural เช่นตรรกะเชิงเส้นเพื่อควบคุมการใช้ทรัพยากร ความคิดนี้ได้ลอยไปรอบ ๆ ตั้งแต่เริ่มต้นตรรกะเชิงเส้นและโดยทั่วไปทำงานในการสังเกตว่าโดยการห้ามกฎโครงสร้างของการหดตัวตัวแปรทุกตัวจะถูกใช้อย่างมากที่สุดในครั้งเดียวดังนั้นจึงไม่มีนามแฝง ดังนั้นความแตกต่างระหว่างการอัปเดตแบบแทนที่และการจัดสรรใหม่จะไม่ปรากฏในโปรแกรมดังนั้นคุณสามารถใช้ภาษาของคุณด้วยการจัดการหน่วยความจำด้วยตนเอง

    นี่คือสิ่งที่ Rust ทำ (ใช้ระบบพิมพ์เลียนแบบ) หากคุณมีความสนใจในทฤษฎีของภาษาสนิมสไตล์หนึ่งในเอกสารสิ่งที่ดีที่สุดที่จะอ่านเป็นอาเหม็ดอัลเอตของL3: ภาษาเชิงเส้นที่มีสถานที่ เช่นกัน LFPL แคลคูลัส Damiano Mazza ดังกล่าวยังเป็นเชิงเส้นมีภาษาเต็มรูปแบบมาจากในภาษา Raml

    หากคุณมีความสนใจในการตรวจสอบสไตล์ Idris คุณควรดูภาษา ATSของ Xi et al ซึ่งเป็นภาษาสไตล์ Rust / L3 พร้อมรองรับการตรวจสอบตามประเภทดัชนีแบบ Haskell ทำเฉพาะหลักฐานที่ไม่เกี่ยวข้องและเป็นเชิงเส้นเพื่อให้มากขึ้น ควบคุมประสิทธิภาพ

    วิธีการที่พึ่งพาอาศัยกันมากขึ้นคือภาษา F-star ที่พัฒนาโดย Microsoft Research ซึ่งเป็นทฤษฎีประเภทเต็มรูปแบบ ภาษานี้มีอินเทอร์เฟซแบบ monadic ที่มีก่อนและหลังเงื่อนไขในจิตวิญญาณของทฤษฎีประเภท Hoareของ Nanevski et al (หรือแม้กระทั่งประเภทการบูรณาการเชิงเส้นและเชิงเส้นของฉันเอง ) และมีชุดย่อยที่กำหนดซึ่งสามารถรวบรวมรหัส C ระดับต่ำ - อันที่จริงแล้วพวกเขากำลังส่งรหัส crypto ที่ผ่านการตรวจสอบแล้วซึ่งเป็นส่วนหนึ่งของ Firefox อยู่แล้ว!

    เพื่อความชัดเจนทั้ง F-star และ HTT ไม่ได้เป็นภาษาเชิงเส้น แต่ภาษาดรรชนีสำหรับพระของพวกเขามักจะใช้ตรรกะการแยกของ Reynold และ O'Hearn ซึ่งเป็นตรรกะเชิงโครงสร้างที่เกี่ยวข้องกับตรรกะเชิงเส้นที่ได้ประสบความสำเร็จเป็นอย่างมาก ภาษาการยืนยันสำหรับ Hoare logics สำหรับโปรแกรมตัวชี้

  2. วิธีที่สองคือการระบุแอสเซมบลี (หรืออะไรก็ตามที่คุณต้องการระดับ IR ต่ำ) แล้วใช้รูปแบบของตรรกะเชิงเส้นหรือการแยกเพื่อเหตุผลเกี่ยวกับพฤติกรรมของมันในผู้ช่วยพิสูจน์โดยตรง โดยพื้นฐานแล้วคุณสามารถใช้ผู้ช่วยหลักฐานหรือภาษาที่พิมพ์ได้อย่างพึ่งพากันเป็นแอสเซมเบลอร์มาโครที่สวยงามมากที่สร้างโปรแกรมที่ถูกต้องเท่านั้น

    ตรรกะการแยกระดับสูงของ Jensen et al สำหรับโค้ดระดับล่างเป็นตัวอย่างที่ชัดเจนโดยเฉพาะอย่างยิ่งของมัน - มันสร้างตรรกะการแยกสำหรับแอสเซมบลี x86! อย่างไรก็ตามมีหลายโครงการในหลอดเลือดดำนี้เช่นซอฟต์แวร์ซอฟต์แวร์ที่ตรวจสอบแล้วที่ Princeton และโครงการCertiKOSที่ Yale

วิธีการเหล่านี้ทั้งหมดจะ "รู้สึก" เหมือนเป็นสนิมเนื่องจากการติดตามความเป็นเจ้าของโดยการ จำกัด การใช้ตัวแปรเป็นกุญแจสำคัญสำหรับพวกเขาทั้งหมด


3

ชนิดเชิงเส้นและตรรกะการแยกมีทั้งยอดเยี่ยม แต่อาจต้องใช้ความพยายามของโปรแกรมเมอร์สักหน่อย ตัวอย่างเช่นการเขียนรายการลิงก์ที่ปลอดภัยใน Rust อาจเป็นเรื่องยาก

แต่มีทางเลือกอื่นที่ต้องใช้ความพยายามของโปรแกรมเมอร์น้อยลงแม้ว่าจะมีการรับประกันที่เข้มงวดน้อยกว่าก็ตาม กระแสการทำงาน (ค่อนข้างเก่า) คือการรับประกันความปลอดภัยของหน่วยความจำโดยใช้ภูมิภาค การใช้การอนุมานภูมิภาคนั้นคอมไพเลอร์สามารถตัดสินใจว่าจะให้ส่วนใดส่วนหนึ่งของข้อมูลที่ถูกจัดสรรเข้ามาและจัดสรรคืนพื้นที่เมื่อมันอยู่นอกขอบเขต

การอนุมานภูมิภาคมีความปลอดภัย (ไม่สามารถจัดสรรคืนหน่วยความจำที่เข้าถึงได้) และต้องการการรบกวนของโปรแกรมเมอร์น้อยที่สุด แต่มันไม่ "รวม" (เช่นมันยังสามารถรั่วหน่วยความจำได้แม้ว่าจะดีกว่า "ไม่ทำอะไรเลย") ดังนั้นโดยทั่วไป ในทางปฏิบัติ GC MLtonคอมไพเลอร์ ML Kit ใช้พื้นที่เพื่อกำจัดการโทร GC ส่วนใหญ่ แต่ก็ยังมี GC เพราะมันจะยังคงรั่วไหลหน่วยความจำอย่างอื่น ตามที่ผู้บุกเบิกยุคแรก ๆ ในบางภูมิภาคกล่าวว่าการอนุมานพื้นที่ไม่ได้ถูกคิดค้นขึ้นมาเพื่อจุดประสงค์นี้ แต่มันกลับกลายเป็นว่ามันสามารถใช้สำหรับการจัดการหน่วยความจำได้เช่นกัน

สำหรับจุดเริ่มต้นฉันจะบอกว่าไปหากระดาษ "การดำเนินการตามประเภทค่าโทร Value-แคลคูลัสโดยใช้กองซ้อนของภูมิภาค" โดย Mads Tofte และ Jean-Pierre Talpin สำหรับเอกสารเพิ่มเติมเกี่ยวกับการอนุมานภูมิภาคให้ค้นหาเอกสารอื่น ๆ โดย M. Tofte และ J.-P Talpin งานของปิแอร์โจเวอทบางส่วนรวมถึงงานเกร็กมอร์เซ็ตต์, ไมค์ฮิกส์และชุดเอกสารของแดนกรอสแมนในไซโคลน


-2

โครงร่างเล็กน้อยสำหรับระบบ "โลหะเปลือย" คือการไม่อนุญาตให้จัดสรรหน่วยความจำรันไทม์ทั้งหมด โปรดจำไว้ว่าแม้แต่malloc/freeคู่C ต้องมีไลบรารีรันไทม์ แต่แม้ว่าวัตถุทั้งหมดจะถูกกำหนดในเวลารวบรวมพวกเขาสามารถกำหนดในรูปแบบที่ปลอดภัย

ปัญหาหลักที่นี่คือนวนิยายของค่าไม่เปลี่ยนรูปในภาษาหน้าที่บริสุทธิ์ซึ่งสร้างขึ้นในขณะที่โปรแกรมทำงาน ฮาร์ดแวร์จริง (และแน่นอนระบบโลหะเปลือย) พึ่งพา RAM ที่ไม่แน่นอนซึ่งอยู่ในปริมาณ จำกัด รันไทม์ของการใช้ภาษาที่ใช้งานได้จริงในทางปฏิบัติจัดสรร RAM แบบไดนามิกในขณะที่ค่าใหม่ "ไม่เปลี่ยนรูป" จะถูกสร้างขึ้นและขยะจะรวบรวมพวกเขาเมื่อไม่มีค่า "ไม่เปลี่ยนรูป" อีกต่อไป

และสำหรับปัญหาที่น่าสนใจที่สุดอายุการใช้งานของค่าอย่างน้อยบางค่าขึ้นอยู่กับอินพุตของรันไทม์ (ผู้ใช้) ดังนั้นจึงไม่สามารถกำหนดอายุการใช้งานแบบคงที่ได้ แต่ถึงแม้ว่าอายุการใช้งานจะไม่ขึ้นอยู่กับอินพุต แต่ก็อาจไม่ใช่เรื่องเล็กน้อย ใช้โปรแกรมง่ายๆซ้ำ ๆ sqrt(N)การหาช่วงเวลาเพียงโดยการตรวจสอบจำนวนทุกครั้งเพื่อตรวจสอบกับจำนวนเฉพาะทั้งหมดขึ้นอยู่กับ เห็นได้ชัดว่าความต้องการนี้จะรักษาช่วงเวลาไว้และสามารถนำหน่วยความจำที่ใช้แล้วกลับมาใช้ใหม่ได้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.