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.
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.
heap.clear_alloc_enable- enables the clearing of the allocated regions of memory using a constant configured by the option
heap.clear_alloc_value. This defaults to
&a110ced3. This is a stylised 'alloced' , with both bit 0 and 1 set to ensure that if used as a word this value will be unaligned.
heap.clear_free_enable- enables the clearing of the freed regions of memory using a constant configured by the option
heap.clear_free_value. This detaults to
&f0f1f2f3. This is intended to invoke the idea that it is free, whilst not looking like an obvious negative number. As with the allocation, both bit 0 and 1 are set.
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
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.
heap.rounding- controls the number of bytes that the allocation size will be rounded to before allocating the block.
heap.minimum_allocation- limits the minimum size of the block
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.
heap.extend_to_nothing_is_error- controls whether an error is returned.
Heaps as a whole can be restricted in size, which may detect some oversized heaps, or heap header corruption for applications.
heap.maximum_heap_size- configures the limit on the size of the heap.
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
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.
watchregions.daheap- may be set to a configuration value to detect the misuse of regions within the Dynamic Area heap. The values that may be commonly useful might be to make writes to the watched regions cause a trace event to be triggered (
write=trace, or just
write), or to make writes to the watched regions cause a data abort (
write=abort). It is also possible to trace reads of these protected blocks (
read=trace), or to make reads trace, and writes abort (
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.
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.
dynamicareaheap.guard_size- configures the number of bytes used for the guard region. If this is set to 0, no guard region is provided.
dynamicareaheap.guard_alloc_value- the value used within the allocated block's guard region. This defaults to
&81818181which is hopefully recognisable, and should cause an abort if used as a pointer.
dynamicareaheap.guard_free_value- the value used within the freed block's guard region. This defaults to
&82828282which is hopefully recognisable, and should cause an abort if used as a pointer.
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.
dynamicareaheap.tracking_full_checks- enables checking of heap blocks on every allocation and free.