AddressSanitizer (GNAT User’s Guide for Native Platforms)

#### 6.8.1 AddressSanitizer ¶

AddressSanitizer (aka ASan) is a memory error detector activated with the `-fsanitize=address` switch. Note that many of the typical memory errors, such as use after free or buffer overflow, are detected by Ada’s `Access_Check` and `Index_Check`.

It can detect the following types of problems:

- Wrong memory overlay

  A memory overlay is a situation in which an object of one type is placed at the same memory location as a distinct object of a different type, thus overlaying one object over the other in memory. When there is an overflow because the objects do not overlap (like in the following example), the sanitizer can signal it.

  >     procedure Wrong_Size_Overlay is
  >        type Block is array (Natural range <>) of Integer;

  >        Block4 : aliased Block := (1 .. 4 => 4);
  >        Block5 : Block (1 .. 5) with Address => Block4'Address;
  >     begin
  >        Block5 (Block5'Last) := 5;  --  Outside the object
  >     end Wrong_Size_Overlay;

  If the code is built with the `-fsanitize=address` and `-g` options, the following error is shown at execution time:

  >     ...
  >     SUMMARY: AddressSanitizer: stack-buffer-overflow wrong_size_overlay.adb:7 in _ada_wrong_size_overlay
  >     ...

- Buffer overflow

  Ada’s `Index_Check` detects buffer overflows caused by out-of-bounds array access. If run-time checks are disabled, the sanitizer can still detect such overflows at execution time the same way as it signalled the previous wrong memory overlay. Note that if both the Ada run-time checks and the sanitizer are enabled, the Ada run-time exception takes precedence.

  >     procedure Buffer_Overrun is
  >        Size : constant := 100;
  >        Buffer : array (1 .. Size) of Integer := (others => 0);
  >        Wrong_Index : Integer := Size + 1 with Export;
  >     begin
  >        -- Access outside the boundaries
  >        Put_Line ("Value: " & Integer'Image (Buffer (Wrong_Index)));
  >     end Buffer_Overrun;

- Use after lifetime

  Ada’s `Accessibility_Check` helps prevent use-after-return and use-after-scope errors by enforcing lifetime rules. When these checks are bypassed using `Unchecked_Access`, sanitizers can still detect such violations during execution.

  >     with Ada.Text_IO; use Ada.Text_IO;

  >     procedure Use_After_Return is
  >        type Integer_Access is access all Integer;
  >        Ptr : Integer_Access;

  >        procedure Inner;

  >        procedure Inner is
  >           Local : aliased Integer := 42;
  >        begin
  >           Ptr := Local'Unchecked_Access;
  >        end Inner;

  >     begin
  >        Inner;
  >        --  Accessing Local after it has gone out of scope
  >        Put_Line ("Value: " & Integer'Image (Ptr.all));
  >     end Use_After_Return;

  If the code is built with the `-fsanitize=address` and `-g` options, the following error is shown at execution time:

  >     ...
  >     ==1793927==ERROR: AddressSanitizer: stack-use-after-return on address 0xf6fa1a409060 at pc 0xb20b6cb6cac0 bp 0xffffcc89c8b0 sp 0xffffcc89c8c8
  >     READ of size 4 at 0xf6fa1a409060 thread T0
  >         #0 0xb20b6cb6cabc in _ada_use_after_return use_after_return.adb:18
  >         ...

  >     Address 0xf6fa1a409060 is located in stack of thread T0 at offset 32 in frame
  >         #0 0xb20b6cb6c794 in use_after_return__inner use_after_return.adb:9

  >       This frame has 1 object(s):
  >         [32, 36) 'local' (line 10) <== Memory access at offset 32 is inside this variable
  >     SUMMARY: AddressSanitizer: stack-use-after-return use_after_return.adb:18 in _ada_use_after_return
  >     ...

- Memory leak

  A memory leak happens when a program allocates memory from the heap but fails to release it after it is no longer needed and loses all references to it like in the following example.

  >     procedure Memory_Leak is
  >        type Integer_Access is access Integer;

  >        procedure Allocate is
  >           Ptr : Integer_Access := new Integer'(42);
  >        begin
  >           null;
  >        end Allocate;
  >     begin
  >        --  Memory leak occurs in the following procedure
  >       Allocate;
  >     end Memory_Leak;

  If the code is built with the `-fsanitize=address` and `-g` options, the following error is emitted at execution time showing the location of the offending allocation.

  >     ==1810634==ERROR: LeakSanitizer: detected memory leaks

  >     Direct leak of 4 byte(s) in 1 object(s) allocated from:
  >         #0 0xe3cbee4bb4a8 in __interceptor_malloc asan_malloc_linux.cpp:69
  >         #1 0xc15bb25d0af8 in __gnat_malloc (memory_leak+0x10af8) (BuildId: f5914a6eac10824f81d512de50b514e7d5f733be)
  >         #2 0xc15bb25c9060 in memory_leak__allocate memory_leak.adb:5
  >         ...

  >     SUMMARY: AddressSanitizer: 4 byte(s) leaked in 1 allocation(s).