18. Debugging pools

Several pool classes have debugging counterparts:

Pool class

Debugging counterpart

AMS (Automatic Mark and Sweep)

mps_class_ams_debug()

MV (Manual Variable)

mps_class_mv_debug()

MVFF (Manual Variable First Fit)

mps_class_mvff_debug()

These debugging pool classes provide two features that are useful for debugging:

  • fenceposts are patterns of data that are written before and after each allocated block. In manually managed pools, fenceposts are checked when the block is deallocated, to see that they are unchanged. This helps detect underwriting and overwriting errors. Fenceposts for all objects in a pool are checked when the pool is destroyed, and can be checked at any time by calling mps_pool_check_fenceposts().

  • free space splatting overwrites recycled space with a pattern of data. If the pattern is designed so that it does not resemble a live object (and if code checks the consistency of its data structues), then this helps to detect dangling pointer dereferences. The pattern is checked just before allocation, and when a block of memory is released from the pool to the arena, to see that it is unchanged. All free space in a pool can be checked for the pattern at any time by calling mps_pool_check_free_space().

The client program specifies templates for both of these features via the mps_pool_debug_option_s structure. This allows it to specify patterns:

  • that mimic illegal data values;

  • that cause bus errors if wrongly interpreted as pointers;

  • that cause assertions to fire if wrongly interpreted as data values;

  • that contain an instruction sequence that wold cause the program to signal an error or stop if wrongly interpreted as executable code.

For example:

mps_pool_debug_option_s debug_options = {
   (const void *)"postpost", 8,
   (const void *)"freefree", 8,
};
mps_pool_t pool;
mps_res_t res;
MPS_ARGS_BEGIN(args) {
    MPS_ARGS_ADD(args, MPS_KEY_POOL_DEBUG_OPTIONS, &debug_options);
    MPS_ARGS_ADD(args, MPS_KEY_FORMAT, &fmt);
    res = mps_pool_create_k(&pool, arena, mps_class_ams_debug(), args);
} MPS_ARGS_END(args);
if (res != MPS_RES_OK) error("can't create debug pool");
mps_pool_debug_option_s

The type of the structure passed as the MPS_KEY_POOL_DEBUG_OPTIONS keyword argument to mps_pool_create_k() when creating a debugging pool class.

typedef struct mps_pool_debug_option_s {
    const void *fence_template;
    size_t fence_size;
    const void *free_template;
    size_t free_size;
} mps_pool_debug_option_s;

fence_template points to a template for fenceposts.

fence_size is the size of fence_template in bytes (1), or zero if the debugging pool should not use fenceposts.

free_template points to a template for splatting free space.

free_size is the size of free_template in bytes, or zero if the debugging pool should not splat free space.

Both fence_size and free_size must be a multiple of the alignment of the pool, and also a multiple of the alignment of the pool’s object format if it has one.

The debugging pool will copy the fence_size bytes pointed to by fence_template in a repeating pattern onto each fencepost during allocation, and it will copy the bytes pointed to by free_template in a repeating pattern over free space after the space is reclaimed.

The MPS may not always use the whole of a template: it may use pieces smaller than the given size, for example to pad out part of a block that was left unused because of alignment requirements.

void mps_pool_check_fenceposts(mps_pool_t pool)

Check all the fenceposts in a pool.

pool is the pool whose fenceposts are to be checked.

If a corrupted fencepost is found, the MPS will assert. It is only useful to call this on a debugging pool that has fenceposts turned on. It does nothing on non-debugging pools.

void mps_pool_check_free_space(mps_pool_t pool)

Check all the free space in a pool for overwriting errors.

pool is the pool whose free space is to be checked.

If corrupted free space is found, the MPS will assert. It is only useful to call this on a debugging pool that has free space splatting turned on. It does nothing on non-debugging pools.