Средства GNATDebug_Pools
Использование Unchecked_Deallocation и/или Unchecked_Conversion
может легко привести к некорректным ссылкам памяти.
От проблем, порождаемых подобными ссылками, достаточно сложно избавиться поскольку проявляемые симптомы, как правило, далеки от реального источника проблемы.
В подобных случаях, очень важно обнаружить наличие подобной проблемы как можно раньше.
Именно такая задача возлагается на Storage_Pool предусмотренный в GNAT.Debug_Pools.
Чтобы воспользоваться средствами отладочного пула динамической памяти GNAT, пользователь должен ассоциировать объект отладочного пула с каждым ссылочным типом, который потенциально способен быть источником проблем.
type Ptr is access Some_Type; Pool : GNAT.Debug_Pools.Debug_Pool; for Ptr'Storage_Pool use Pool; |
GNAT.Debug_Pool является производным от Checked_Pool, который является характерным для GNAT пулом динамической памяти.
Такие пулы динамической памяти, подобно стандартным пулам динамической памяти Ады, позволяют пользователю переопределять стратегию распределения (аллокацию) и освобождения (деаллокацию) динамической памяти.
Они также предусматривают контрольные точки, для каждого разыменования (расшифровки) ссылок посредством операции Dereference, которая неявно вызывается в процессе разыменования каждого значения ссылочного типа.
После того как ссылочный тип ассоциирован с отладочным пулом, операции над значениями этого типа способны возбудить четыре различных исключения, которые соответствуют четырем потенциальным видам разрушения памяти:
GNAT.Debug_Pools.Accessing_Not_Allocated_Storage
GNAT.Debug_Pools.Accessing_Deallocated_Storage
GNAT.Debug_Pools.Freeing_Not_Allocated_Storage
GNAT.Debug_Pools.Freeing_Deallocated_Storage
Для типов, ассоциированных с отладочным пулом Debug_Pool
динамическое распределение выполняется с помощью использования стандартных подпрограмм размещения динамической памяти GNAT.
Ссылки ко всем фрагментам распределенной памяти сохраняются во внутреннем каталоге.
Стратегия освобождения состоит не в освобождении памяти используемой системы, а в заполнении памяти шаблоном, который может быть легко распознан в процессе отладочной сессии.
Шаблон соответствует старому двоично десятичному соглашению IBM и имеет значение 16#DEADBEEF#.
При каждом разыменовании, осуществляется проверка того, что ссылочное значение указывает на правильно распределенное место памяти.
Ниже показан полный пример использования отладочного пула Debug_Pool, который содержит типичный образец разрушения памяти:
@leftskip=0cm with Gnat.Io; use Gnat.Io; with Unchecked_Deallocation; with Unchecked_Conversion; with GNAT.Debug_Pools; with System.Storage_Elements; with Ada.Exceptions; use Ada.Exceptions; procedure Debug_Pool_Test is type T is access Integer; type U is access all T; P : GNAT.Debug_Pools.Debug_Pool; for T'Storage_Pool use P; procedure Free is new Unchecked_Deallocation (Integer, T); function UC is new Unchecked_Conversion (U, T); A, B : aliased T; procedure Info is new GNAT.Debug_Pools.Print_Info(Put_Line); begin Info (P); A := new Integer; B := new Integer; B := A; Info (P); Free (A); begin Put_Line (Integer'Image(B.all)); exception when E : others => Put_Line ("raised: " & Exception_Name (E)); end; begin Free (B); exception when E : others => Put_Line ("raised: " & Exception_Name (E)); end; B := UC(A'Access); begin Put_Line (Integer'Image(B.all)); exception when E : others => Put_Line ("raised: " & Exception_Name (E)); end; begin Free (B); exception when E : others => Put_Line ("raised: " & Exception_Name (E)); end; Info (P); end Debug_Pool_Test; |
Debug Pool info: Total allocated bytes : 0 Total deallocated bytes : 0 Current Water Mark: 0 High Water Mark: 0 Debug Pool info: Total allocated bytes : 8 Total deallocated bytes : 0 Current Water Mark: 8 High Water Mark: 8 raised: GNAT.DEBUG_POOLS.ACCESSING_DEALLOCATED_STORAGE raised: GNAT.DEBUG_POOLS.FREEING_DEALLOCATED_STORAGE raised: GNAT.DEBUG_POOLS.ACCESSING_NOT_ALLOCATED_STORAGE raised: GNAT.DEBUG_POOLS.FREEING_NOT_ALLOCATED_STORAGE Debug Pool info: Total allocated bytes : 8 Total deallocated bytes : 4 Current Water Mark: 4 High Water Mark: 8 |