Безпека пам’яті на основі типу без ручного управління пам’яттю або збирання сміття під час виконання?


13

Скажімо, ми хотіли такого типу, чисто функціональної мови програмування, як Haskell або Idris, яка спрямована на програмування систем без збору сміття і не має часу виконання (або принаймні не більше, ніж "час виконання" C і Rust). Щось, що може бігати більш-менш на голий метал.

Назвіть деякі варіанти безпеки статичної пам’яті, які не потребують ручного управління пам’яттю або збирання сміття під час виконання, і як можна вирішити проблему за допомогою типової системи чистого функціоналу, подібної до Haskell або Idris?


Ви хочете сказати, що ви хочете, щоб типи в мові слугували способом уникнути вивезення сміття? Основна проблема виникає при оцінці функцій. Функція оцінюється до закриття, яке інкапсулює поточне середовище виконання. Це головне джерело необхідності займатися вивезенням сміття. Якщо ви не зміните правило набору тексту для функцій, я не бачу, як типи допоможуть у цьому допомогти. Java та інші мови зі зламаними -abstractions отримують це, змішуючи утворення закриттів: вони забороняють посилання, які потребували б збірного збору. λ
Андрій Бауер

Напевно, Руст повинен був вирішити ту ж проблему оцінювання функцій та закриття її моделі власності та перевірки позики? Управління пам'яттю просто означає знати, як довго живуть ці значення, які інші значення залежать від них, і знищувати невикористані значення, коли вони мертві, правда? Тож, напевно, я справді запитую, чи можна керувати пам’яттю інкапсульованим набором типів, які можна перевірити на правильність за допомогою системи типів, не розширюючи основні механізми мови чи компілятора, додавши цілу нову систему власності та «запозичивши шашка "(це шлях Руста).
Чейз

Що з LFPL Мартіна Гофмана ? Він має спеціальний базовий тип, "алмаз", на якому застосовується дисципліна лінійного типу, що дозволяє враховувати типи основного використання пам'яті (розподілу / угоди). Чи піде це в тому напрямку, про який ви говорите?
Даміано Мацца

Відповіді:


18

Грубо кажучи, є дві основні стратегії безпечного керування пам'яттю вручну.

  1. Перший підхід полягає у використанні такої субструктурної логіки, як лінійна логіка для управління використанням ресурсів. Ця ідея лежить в основному з моменту створення лінійної логіки, і в основному працює на спостереженні, що забороняючи структурне правило скорочення, кожна змінна використовується щонайбільше одночасно, і тому немає збитку. Як результат, різниця між оновленням на місці та перерозподілом не помітна для програми, і тому ви можете реалізувати свою мову за допомогою керування вручну.

    Це те, що робить Руст (він використовує систему афінного типу). Якщо вас цікавить теорія мов у стилі іржа, однією з найкращих книг для читання є L3: Лінійна мова з локаціями Ахмеда та ін . Крім того, згадане числення LFPL Даміано Мацца є також лінійним, має повну мову, похідну від нього в мові RAML .

    Якщо вас зацікавила перевірка стилю Idris, слід переглянути мову ATS Xi et al , яка є мовою стилю Rust / L3 з підтримкою перевірки на основі типів, що індексуються в стилі Haskell, лише зробила доказ невідповідним і лінійним, щоб надати більше контроль за роботою.

    Ще більш агресивно-залежним підходом є мова зірок F, розроблена в Microsoft Research, яка є повною залежною теорією типу. Ця мова має монадійний інтерфейс з до- та після умов у дусі теорії типу Хоара Наневського та інших (або навіть мого власного інтегруючого лінійного та залежного типів ) та має певний підмножина, яку можна компілювати до коду низького рівня С - насправді вони вже доставляють перевірений криптокод як частина Firefox!

    Зрозуміло, що ні F-зірка, ні HTT не є лінійно типовими мовами, але індексна мова для їх монадів зазвичай заснована на логіці поділу Рейнольда та О'Герна , що є субструктурною логікою, пов'язаною з лінійною логікою, яка спричинила великий успіх як мову твердження для логіки Хоара для програм покажчиків.

  2. Другий підхід полягає в тому, щоб просто вказати, яку саме збірку (або будь-який ІР низького рівня ви хочете), а потім використати певну форму лінійної чи роздільної логіки, щоб розмірковувати про свою поведінку безпосередньо у помічника перевірки. По суті, ви можете використовувати асистент перевірки або залежно набрану мову як дуже фантазійний макроскладач, який генерує лише правильні програми.

    Логіка розділення високого рівня для коду низького рівня - Єнсен та ін - особливо чистий приклад цього - вона будує логіку розділення для складання x86! Однак у цьому напрямку є багато проектів, як, наприклад, Verified Software Toolchain у Принстоні та проект CertiKOS в Єлі.

Усі ці підходи будуть "схожими" на Руста, оскільки відстеження права власності шляхом обмеження використання змінних є ключовим для всіх.


3

Лінійні типи та логіка розділення є чудовими, але можуть вимагати небагато зусиль програміста. Наприклад, написання безпечного пов'язаного списку в Rust може бути досить важким.

Але є альтернатива, яка вимагає значно менших зусиль програміста, хоча і з менш суворими гарантіями. (Досить старий) потік роботи - це гарантувати безпеку пам’яті, використовуючи (як правило, стек) регіонів. Використовуючи умовивід регіону, компілятор може статично вирішити, в яку область повинен входити фрагмент виділених даних, і розподілити регіон, коли він виходить за межі області.

Вибір регіону є виразно безпечним (не може розібрати доступну пам'ять) і вимагає мінімальних втручань програміста, але він не є "загальним" (тобто він все одно може просочити пам'ять, хоча, безумовно, набагато краще, ніж "нічого не робити"), тому зазвичай поєднується з ГК на практиці. TheMLtonКомпілятор ML Kit використовує регіони для усунення більшості викликів GC, але він все ще має GC, оскільки в іншому випадку він все-таки просочить пам'ять. На думку деяких з перших піонерів у регіонах, висновок регіону насправді не був винайдений для цієї мети (я думаю, це було для автоматичної паралелізації, я думаю); але лише виявилося, що його можна використовувати і для управління пам'яттю.

Для початку я б сказав документ "Впровадження введеного λ-обчислення за типовою вартістю за допомогою цілої групи регіонів" Мадс Тофте та Жан-П'єр Талпін. Щоб отримати докладніші статті про висновки в регіоні, шукайте інші статті М. Тофте та Ж.-П. Талпін, деякі роботи П'єра Жувела, а також серія робіт про Циклона Грега Морріссета, Майка Хікса та Дана Гроссмана.


-2

Тривіальна схема для систем «голого металу» - це просто заборонити всі виділення пам’яті під час виконання. Пам’ятайте, навіть для malloc/freeпари C потрібна бібліотека часу виконання. Але навіть коли всі об'єкти визначені під час компіляції, їх можна визначити безпечним способом.

Основна проблема тут - вигадка незмінних значень у чистих функціональних мовах, які створюються під час роботи програми. Справжнє обладнання (і, звичайно, системи з голого металу) покладається на змінну оперативну пам’ять, яка обмежена. Час виконання функціональної мови на практиці динамічно розподіляє оперативну пам’ять, оскільки створюються нові "незмінні" значення, і сміття збирає їх тоді, коли значення "незмінне" більше не потрібно.

І для більшості цікавих проблем, термін експлуатації принаймні деяких значень залежить від введення (користувачем) часу виконання, тому тривалість життя не може бути визначена статично. Але навіть якщо час життя не залежить від введення, він може бути дуже нетривіальним. Візьміть просту програму, багаторазово знаходячи праймери, просто перевіряючи кожне число в порядку, перевіряючи проти всіх простих чисел sqrt(N). Зрозуміло, що це потребує збереження простих ліній і може переробити пам'ять, яка використовується для непроменеусів.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.