The Hackerlab at `regexps.com`

## Low-level Memory Management

up: libhackerlab next: Arrays prev: Machine-Specific Definitions

The programming interfaces described in this chapter provide some frequently needed functionality built on top of the standard functions `malloc` , `realloc` , and `free` .

There are functions that work like `malloc` and friends, but that cause the process to exit with an error message and a non-0 status if an allocation fails. See Allocate or Die.

There are functions that let you keep track of how much memory is used by a particular subsystem of your program, and limit that amount of memory if you choose. You can use these functions to trigger various forms of garbage collection. See Allocation With Limitations.

Finally, There are functions that operate on arrays of bytes. These do little more than replace standard functions such as `memcpy` , but are included for symmetry and completeness. See Array-of-Byte Functions.

- Allocate or Die
- Allocation With Limitations
- Array-of-Byte Functions

### Allocate or Die

up: Low-level Memory Management next: Allocation With Limitations

    #include <hackerlab/mem/must-malloc.h>

The functions in this section allocate memory. If an allocation fails, they call `panic` rather than returning. Thus, these functions may be used without checking for errors.

Function `must_calloc`

    void * must_calloc (size_t amt);

Return a newly allocated block large enough to hold `amt` bytes. If no such block can be allocated, exit by calling `panic` . Fill the newly allocated memory with `0` bytes.

Function `must_malloc`

    void * must_malloc (size_t amt);

Return a newly malloced block large enough to hold `amt` bytes. If no such block can be allocated, exit by calling `panic` .

Function `must_realloc`

    void * must_realloc (void * ptr, size_t amt);

Return a malloced block large enough to hold `amt` bytes. If `ptr` is not `0` , it should point to a previously malloced block. The contents of the new block are initialized from the contents of `ptr` . If the new block is not the same as `ptr` , `ptr` is freed.

If no block can be allocated, exit by calling `panic` .

Function `must_free`

    void must_free (void * ptr);

Free a block allocated by `must_calloc` , `must_malloc` , or `must_realloc` .

### Allocation With Limitations

up: Low-level Memory Management next: Array-of-Byte Functions prev: Allocate or Die

    #include <hackerlab/mem/alloc-limits.h>

In some situations it is desriable for a subsystem of a program to limit its use of memory, independently of the rest of the program. The `alloc_limits` functions are for such situations.

There are two steps to using the `alloc_limits` functions. First, you create an `alloc_limits` object which specifies how much memory your subsystem should, ideally, use, and how much it is permitted to use. See make_alloc_limits. Second, use functions like `lim_malloc` and `lim_free` instead of functions like `malloc` and `free` in the subsystem to which the limits apply.

- Specifying Allocation Limits
- Allocating and Freeing
- Reserving Limited Memory

#### Specifying Allocation Limits

up: Allocation With Limitations next: Allocating and Freeing

An object of the opaque type `alloc_limits` records the rules which limit memory use in a particular subsystem.

Function `make_alloc_limits`

    alloc_limits make_alloc_limits (t_uchar * name,
                                    size_t threshold,
                                    size_t failure_pt,
                                    int panic_on_failure,
                                    lim_free_memory_fn free_memory,
                                    void * closure);

Create a new `alloc_limits` object.

`name` is the name of the subsystem to which these allocation limits apply. The name is useful for debugging purposes.

`threshold` specifies an ideal limit on the amount of memory used by your subsystem. If a subsystem attempts to allocate more than `threshold` bytes, the `free_memory` function for that subsystem is invoked (see below). `threshold` may be `0` , in which case the `free_memory` function is never invoked.

`failure_pt` specifies an absolute limit on the amount of memory used by your subsystem. Allocations beyond `failure_pt` fail (return `0` ).

`panic_on_failure` , if non-0, means that if the failure point is reached, or allocation fails, the program will exit with a message to the standard error stream and a non-0 status. If `0` , allocation failures return `0` .

`free_memory` is a function pointer:

         typedef void (*lim_free_memory_fn)(void * closure,
                                            size_t needed);

It is called immediately before an allocation that would exceed `threshold` (if `threshold` is not `0` ). `closure` is as passed to `make_alloc_limits` (see below). `needed` is the number of bytes by which the proposed allocation causes the total amount of memory used by the subsystem to exceed `threshold` . It is completely safe to call `lim_free` from your `free_memory` function. It is possible to call `lim_malloc` or `lim_realloc` , but if your program does this, `free_memory` must be reentrant.

`closure` is an opaque value passed to `free_memory` .

If a new `alloc_limits` object can not be allocated, this function calls `panic` and does not return.

As an alternative to calling `make_alloc_limits` in some situations, three pre-defined allocation limits are declared in `alloc-limits.h` :

         extern alloc_limits lim_use_malloc;
         extern alloc_limits lim_use_must_malloc;
         extern alloc_limits lim_no_allocations;

Allocations performed with `lim_use_malloc` are unlimited and are effectively like allocations performed with `malloc` or `realloc` . Failed allocations return `0` .

Allocations performed with `lim_use_must_malloc` are unlimited and are effectively like allocations performed with `must_malloc` or `must_realloc` . Failed allocations cause the process to exit with a non-0 status.

Allocations performed with `lim_no_allocations` always fail and return `0` . `lim_free` has no effect when passed `lim_no_allocations` .

Function `free_alloc_limits`

    void free_alloc_limits (alloc_limits limits);

Free an allocation limits object.

Function `lim_set_threshold`

    size_t lim_set_threshold (alloc_limits it, size_t threshold);

Modify the `threshold` of an `alloc_limits` object. Return the old `threshold` .

This function does not immediately call `free_memory` , even if the total amount of memory allocated exceeds the new `threshold` .

Function `lim_threshold`

    size_t lim_threshold (alloc_limits limits);

Return the current `threshold` of allocation limits `limits` .

Function `lim_set_failure_pt`

    size_t lim_set_failure_pt (alloc_limits limits, size_t failure_pt);

Modify the `failure_pt` of an `alloc_limits` object. Return the old `failure_pt` .

Function `lim_failure_pt`

    size_t lim_failure_pt (alloc_limits limits);

Return the `failure_pt` of allocation limits `limits` .

Function `lim_is_panic_on_failure`

    int lim_is_panic_on_failure (alloc_limits limits);

Return the value of the `panic_on_failure` flag of allocation limits `limits` .

Function `lim_set_panic_on_failure`

    int lim_set_panic_on_failure (alloc_limits limits, int value);

Set the `panic_on_failure` flag of allocation limits `limits` .

Return the old value.

Function `lim_in_use`

    size_t lim_in_use (alloc_limits limits);

Return the amount (in bytes) of memory allocation charged to `limits` and not yet freed.

Function `lim_high_water_mark`

    size_t lim_high_water_mark (alloc_limits limits);

Return the largest amount (in bytes) of outstanding memory allocation charged to `limits` during the lifetime of the process.

#### Allocating and Freeing

up: Allocation With Limitations next: Reserving Limited Memory prev: Specifying Allocation Limits

These functions allocate and free memory, similarly to `malloc` , `realloc` , and `free` , but with allocation limits.

Function `lim_malloc`

    void * lim_malloc (alloc_limits limits, size_t amt);

Allocate `amt` bytes of memory.

If the allocation would exceed the threshold of `limits` , invoke the `free_memory` function first.

If the allocation would exceed the `failure_pt` of `limits` , or if the underlying `malloc` fails, return `0` (if the `panic_on_failure` flag of `limits` is `0` ) or exit the process with a non-0 status (if `panic_on_failure` is non-0).

Adjust the `in_use` and `high_water_mark` of `limits` .

If `limits` is `0` , this function works like must_malloc.

Function `lim_zalloc`

    void * lim_zalloc (alloc_limits limits, size_t amt);

Use `lim_malloc` to attempt to allocate `amt` bytes of memory. If allocation succeeds, initialize that memory to all zero bytes.

Return the allocated region or `0` if allocation fails.

Function `lim_soft_malloc`

    void * lim_soft_malloc (alloc_limits limits, size_t amt);

Allocate `amt` bytes of memory. Return the newly allocated memory.

If the allocation would exceed the `failure_pt` of `limits` , or if the underlying `malloc` fails, return `0` (if the `panic_on_failure` flag of `limits` is `0` ) or exit the process with a non-0 status.

Adjust the `in_use` and `high_water_mark` of `limits` .

This function does not invoke the `free_memory` function of `limits` , even if the allocation would exceed the threshold of `limits` .

If `limits` is `0` , this function works like must_malloc.

Function `lim_realloc`

    void * lim_realloc (alloc_limits limits, void * prev, size_t amt);

Reallocate `prev` as `amt` bytes of memory. Copy (up to) `amt` bytes of data from `prev` to the newly allocated memory.

If the allocation would exceed the threshold of `limits` , invoke the `free_memory` function first.

If the allocation would exceed the `failure_pt` of `limits` , or if the underlying `malloc` fails, return `0` (if the `panic_on_failure` flag of `limits` is `0` ) or exit the process with a non-0 status.

Adjust the `in_use` and `high_water_mark` of `limits` .

If `prev` is `0` , this function behaves like `lim_malloc` .

If `limits` is `0` , this function works like must_realloc.

Function `lim_soft_realloc`

    void * lim_soft_realloc (alloc_limits limits,
                             void * prev,
                             size_t amt);

Reallocate `prev` as `amt` bytes of memory. Copy (up to) `amt` bytes of data from `prev` to the newly allocated memory.

If the allocation would exceed the `failure_pt` of `limits` , or if the underlying `malloc` fails, return `0` (if the `panic_on_failure` flag of `limits` is `0` ) or exit the process with a non-0 status.

Adjust the `in_use` and `high_water_mark` of `limits` .

This function does not invoke the `free_memory` function of `limits` , even if the allocation would exceed the threshold of `limits` .

If `limits` is `0` , this function works like must_realloc.

Function `lim_free`

    void lim_free (alloc_limits limits, void * ptr);

Free `ptr` . Adjust the `in_use` and `high_water_mark` values of `limits` .

If `limits` is `0` , this function works like must_free.

#### Reserving Limited Memory

up: Allocation With Limitations prev: Allocating and Freeing

Function `lim_prepare`

    int lim_prepare (alloc_limits limits, size_t amt);

Prepare for an allocation of `amt` bytes.

If such an allocation would exceed the threshold of `limits` , invoke the `free_memory` function first.

If the allocation would exceed the `failure_pt` of `limits` , return `-1` . Otherwise, return `0` .

If `limits` is `0` , this function simply returns `0` .

### Array-of-Byte Functions

up: Low-level Memory Management prev: Allocation With Limitations

    #include <hackerlab/mem/mem.h>

These functions operate on regions of memory as arrays of unsigned bytes with no further interpretation.

Function `mem_set`

    void mem_set (t_uchar * mem, unsigned int c, size_t size);

Store `size` bytes of value `c` beginning at `mem` .

Function `mem_set0`

    void mem_set0 (t_uchar * mem, size_t n);

Store `n` `0` bytes beginning at `mem` .

Function `mem_move`

    void mem_move (t_uchar * to, const t_uchar * from, size_t amt);

Copy `amt` bytes from `from` to `to` . The source and destination regions may overlap.

Function `mem_cmp`

    int mem_cmp (const t_uchar * m1, const t_uchar * m2, size_t amt);

Compare `amt` bytes starting at `m1` and `m2` . If a difference is found, immediately return `-1` if the differing byte in `m1` is less than the byte in `m2` , `1` otherwise. If no difference is found, return `0` .

Function `mem_occurrences`

    size_t mem_occurrences (const t_uchar * mem,
                            unsigned int c,
                            size_t size);

Search `size` bytes of data for occurences of byte `c` beginning at `mem` . Return the number of occurences found.

libhackerlab: The Hackerlab C Library
The Hackerlab at `regexps.com`