Категория >  Новости > Безопасность памяти. Учимся использовать указатели и линейные типы - «Новости»
Безопасность памяти. Учимся использовать указатели и линейные типы - «Новости»17-11-2020, 00:01. Автор: Ogden  | 
| 
предыдущей статьей, где я рассматривал механизмы сборки мусора и их особенности. Как мы видели на примере с использованием Boehm GC в C, сборка мусора сама по себе решает только проблему с утечками памяти. Безопасность памяти обеспечивают уже свойства самого языка. Ассоциация между сборкой мусора и безопасностью памяти возникает от того, что многие популярные прикладные языки не разрешают ручное управление памятью и адресную арифметику вовсе, — в этих условиях у пользователя просто нет возможности выполнить небезопасную операцию. Однако и возможности освободить память тоже нет, поэтому нужен какой-то механизм автоматического управления, и сборка мусора — самый популярный. Самый популярный не значит единственный и универсальный. Первая и главная проблема языков с принудительной сборкой мусора — на них можно писать только программы, которые выполняются в пространстве пользователя. Ядру операционной системы или прошивке микроконтроллера не на кого положиться, они вынуждены управлять памятью самостоятельно, а значит, и язык должен поддерживать указатели и адресную арифметику. Вторая проблема — потеря производительности и предсказуемости времени выполнения. Классические однопоточные сборщики мусора создают паузы в выполнении программы, которые могут быть заметны пользователю. При использовании многопоточных алгоритмов и верной настройке таймеров под задачи конкретного приложения можно свести паузы к минимуму, но свести затраты ресурсов на сборку мусора к нулю невозможно. Вполне логично, что разработчики языков ищут альтернативные и промежуточные варианты. Давай посмотрим, какими способами разные языки пытаются обеспечить безопасность памяти. Строгая типизация указателейПроблемы с безопасностью памяти в C возникают в первую очередь из-за отсутствия строгой типизации. Функция  Ну и самая классическая ошибка, конечно, — случайное обращение к нулевому указателю. #include <stdio.h>void main(void) {  char* str = NULL;  printf("%sn", str);}
 Более современные языки для системного программирования относятся к этому вопросу более ответственно. Например, в аде нетипизированные указатели — особый и редкий случай. Обычные указатели всегда типизированные. Вместо  Таким способом запросить или освободить неверный объем памяти гораздо сложнее. Использование после освобождения, впрочем, также будет обнаружено только во время выполнения программы. infoУказатели в аде называются access types. Например,  Для демонстрации сохраним следующий код в файл  with Ada.Unchecked_Deallocation;procedure Access_Example is   type Int_Ptr is access Integer;   -- Специализация дженерика РїРѕРґ Int_Ptr   procedure Free_Integer is new Ada.Unchecked_Deallocation(Object => Integer, Name => Int_Ptr);   P : Int_Ptr;   I : Integer;begin   -- Запрашиваем память РїРѕРґ целое число СЃ помощью new   -- Рё сохраняем туда значение 42   P := new Integer'(42);   -- Освобождаем память, теперь P = null   Free_Integer(P);   -- Пробуем получить значение РїРѕ указателю   I := P.all;end Access_Example;Теперь скомпилируем с помощью GNAT и запустим. 
 
 Как видим, тип указателя  Однако начиная с Ada 2005 поддерживается и проверка, что указатель ненулевой. Для этого нужно исправить  
 На практике от такого типа мало пользы, поскольку его память невозможно освободить. По этой причине опцию  type Int_Ptr is access Integer;subtype Initialized_Int_Ptr is not null Int_Ptr;procedure Some_Proc(Arg: Initialized_Int_Ptr);Перейти обратно к новости  |