Pyromaniac

Heap debugging

Overview

Heap regions are commonly where data corruption causes system failures. As OS_Heap is entirely under the control of the RISC OS Pyromaniac system, it has been extended to allow more diagnostics when problems occur, and better defaults. The configuration also allows greater control over the invariants from the original heap, but keeps to the RISC OS Classic allocation system for compatibility.

Dynamic Area Heaps are a fully managed allocation region. As such, they have more diagnostics features, and can detect corruption and misuse more easily than the standard OS_Heap regions. This includes guard words to detect over and underruns, and protection for regions of the heap.

These options should help to find the cause of failures by detecting them with increasing costs in speed.

OS_Heap regions

Clearing regions

The OS_Heap can be configured to clear regions when they are allocated, and when they are freed. This ensures that use-after-free will result in unexpected (usually fatal) behaviour which can be corrected. By default, this feature is disabled, but the can be enabled independantly for allocation and free.

For example, with these options enabled, reusing a region of unintialised or freed memory may cause a Data Abort. Printing a pointer from a region of freed memory may produce a stream of óòñð characters (when the alphabet is set to Latin 1), which should be recognisable.

Block alignment and limits

The OS_Heap regions can be rounded to blocks of a known size. This allows testing of the behaviour when assumptions have been made about the actual size of allocations (as opposed to the requested size). Similarly, the minimum block allocation size can be configured.

The behaviour of a block extension to 0 (or smaller) is able to be configured to report an error. On RISC OS Classic this operation would return a pointer of -1, without error.

Heaps as a whole can be restricted in size, which may detect some oversized heaps, or heap header corruption for applications.

The standard OS_Heap will interfaces will report errors if the heap is found to be corrupted. This may include trace reports which include information about the call stack in C programs, when the corruption is detected. As corruption can only be detected within calls to OS_Heap, problems may be reported long after they were introduced.

Dynamic Area Heaps

Dynamic Area heaps are persistent managed memory allocation regions, and so can have greater diagnostic abilities. This applies to the System Heap and the Relocatable Module Area. In particular, this means that the OS_Module calls to allocate, free and extend memory blocks has greater facilities available to it.

Administrative area protection

The header word on allocated blocks, and the words used for freed blocks may be protected as a separate watchpoint region. This means that they can be configured to perform different operations on access. This may detect heap misuse and overflows.

Enabling the watch regions for Dynamic area heaps will slow the system down considerably as these regions will be checked on each data access, and may cause a large number of slow operations. This may detect overflow writes in the heap, where they have become a problem, although remember tha the heap allocations have a minimum size and will be rounded up if necessary; this may mean that the actual allocation of the heap block is larger than requested.

Guard words

Allocations (and frees) within the heap can be given a 'guard' region before and after the allocated block. This region is assigned a constant value, and can be checked when the allocation and free operations are performed. If the guard value is found to have been changed, an error can be triggered.

If the watch regions for Dynamic Area heaps are enabled, they will include the guard regions. This means that overflow and underflow of the blocks may be detected much more quickly, without corrupting the heap itself.

Tracked heap blocks

The heap block allocations may be tracked by the system. This means that on allocation the block remembers who made the call to allocate it, as best as can be determined from the call stack. These allocations can be reported when corruption or other failures are detected. This is the current default.