Safe memory allocation

Overview

Safe memory allocation. More…

// global functions

static bool te_alloc_adjust_extent(size_t total_length, size_t offset, size_t* extent);
void* te_alloc_internal(size_t size, bool initialize, const char* filename, int line);
void* te_realloc_internal(void* oldptr, size_t newsize, const char* filename, int line);
static bool te_is_valid_alloc(size_t nmemb, size_t size);
void* te_memdup_internal(const void* src, bool zero_terminated, size_t maxsize, const char* filename, int line);

// macros

#define TE_ALLOC(size_)
#define TE_ALLOC_UNINITIALIZED(size_)
#define TE_MEMDUP(src_, size_)
#define TE_REALLOC(ptr_, newsize_)
#define TE_STRDUP(src_)
#define TE_STRNDUP(src_, maxsize_)

Detailed Documentation

Safe memory allocation.

Global Functions

static bool te_alloc_adjust_extent(size_t total_length, size_t offset, size_t* extent)

Ensure that offset + extent is not out of bounds.

The function adjusts the value in extent so that a chunk starting at extent lie completely within a buffer of total_length bytes.

The function handles unsigned overflows correctly, so e.g. extent may contain SIZE_MAX.

offset should be within total_length.

Parameters:

total_length

Total length of a buffer.

offset

Offset of a chunk within the buffer.

extent

Length of the chunk.

Returns:

true if extent was reduced.

void* te_alloc_internal(size_t size, bool initialize, const char* filename, int line)

Allocate size bytes and optionally fill allocated memory with zeroes.

This function should never be called directly, use TE_ALLOC() or TE_ALLOC_UNINITIALIZED() macros instead.

On requesting zero bytes, the function actually returns a 1-byte buffer capturing ISO C permitted behaviour of recent glibc.

Parameters:

size

Number of bytes to allocate.

initialize

Zero the allocated memory if true.

filename

Caller’s filename.

line

Caller’s line.

TE_FATAL_ERROR

in an unlikely case of a memory allocation failure.

Returns:

A pointer to a fresh memory block (never NULL).

void* te_realloc_internal(void* oldptr, size_t newsize, const char* filename, int line)

Reallocate oldptr to have the size of newsize.

If oldptr is NULL, it is an exact equivalent of te_alloc_internal().

This function should never be called directly, use TE_REALLOC() macro instead.

Unlike system realloc, this function aborts if a non-null oldptr is tried to resize to zero bytes the behaviour of system realloc is really ill-defined.

Parameters:

oldptr

An existing memory block or NULL.

newsize

New size of the block.

filename

Caller’s filename.

line

Caller’s line.

TE_FATAL_ERROR

in an unlikely case of a memory allocation failure or zero-size reallocation.

Returns:

A pointer to a reallocated block (never NULL, may be the same as oldptr).

static bool te_is_valid_alloc(size_t nmemb, size_t size)

Check whether an array of nmemb elements of size bytes can be allocated.

Basically, it checks that nmemb * size would fit into size_t; it does not check for available memory and so on.

The primary purpose of this function is to ensure that TE_ALLOC(x * y) would not errneously return a small buffer due to overflow:

if (!te_is_valid_alloc(nmemb, size))
    TEST_FAIL("Array is too large");
arr = TE_ALLOC(nmemb * size);

See Hacker’s Delight, 2nd Edition, section 2.12.4

Parameters:

nmemb

Number of elements.

size

Size of an element.

Returns:

true if an array of nmemb elements may be allocated.

void* te_memdup_internal(const void* src, bool zero_terminated, size_t maxsize, const char* filename, int line)

Copy a block of memory src.

This function should never be called directly,

c NULL if and only if src is NULL.

Parameters:

src

Source buffer (may be NULL).

zero_terminated

If true, only copy bytes up to the first binary zero.

maxsize

Maximum number of bytes to copy (may be less if zero_terminated is true).

filename

Source filename.

line

TE_FATAL_ERROR

in an unlikely case of a memory allocation failure.

Returns:

A pointer to a fresh copy of src.

Macros

#define TE_ALLOC(size_)

Allocate size_ bytes and fill allocated memory with zeroes.

On requesting zero bytes, the macro actually returns a 1-byte buffer capturing ISO C permitted behaviour of recent glibc.

Parameters:

size_

Number of bytes to allocate.

TE_FATAL_ERROR

in an unlikely case of a memory allocation failure.

Returns:

A pointer to a fresh memory block (never NULL).

#define TE_ALLOC_UNINITIALIZED(size_)

Allocate size_ bytes without initializing it.

In most cases TE_ALLOC() shall be used instead. This macro is intended for performance-critical cases where the caller would immediately initialize the memory block itself, e.g. with memset or memcpy.

On requesting zero bytes, the macro actually returns a 1-byte buffer capturing ISO C permitted behaviour of recent glibc.

Parameters:

size_

Number of bytes to allocate.

TE_FATAL_ERROR

in an unlikely case of a memory allocation failure.

Returns:

A pointer to a fresh uninitialized memory block (never NULL).

#define TE_MEMDUP(src_, size_)

Make a copy of size_ bytes of memory starting from src_.

This macro is similiar to memdup function found in OpenBSD and some other OSes.

c NULL if and only if src_ is NULL.

Refer to TE_ALLOC() on behaviour when size_ is zero.

Parameters:

src_

Source buffer (may be NULL).

size_

TE_FATAL_ERROR

in an unlikely case of a memory allocation failure.

Returns:

A pointer to a fresh copy of src_.

#define TE_REALLOC(ptr_, newsize_)

Reallocate ptr_ to have the size of newsize_.

If ptr_ contains NULL, it is an exact equivalent of TE_ALLOC().

ptr_ must be an lvalue and its content is replaced upon reallocation, so the old invalidated address is not accessible anymore.

Unlike system realloc, this function aborts if a non-null ptr_ is tried to resize to zero bytes the behaviour of system realloc is really ill-defined.

Parameters:

ptr_

An lvalue holding an existing memory block or NULL.

newsize_

New size of the block.

TE_FATAL_ERROR

in an unlikely case of a memory allocation failure or zero-size reallocation.

#define TE_STRDUP(src_)

Make a copy of zero-terminated src_ like system strdup.

c NULL if and only if src_ is NULL.

Parameters:

src_

TE_FATAL_ERROR

in an unlikely case of a memory allocation failure.

Returns:

A pointer to a fresh copy of src_.

#define TE_STRNDUP(src_, maxsize_)

Make a copy of possibly zero-terminated src_ like system strndup.

The macro copies the content of src_ up to and including the first binary zero or the first maxsize_ bytes, whichever comes first.

The result is always zero-terminated.

c NULL if and only if src_ is NULL.

Parameters:

src_

A possibly zero-terminated string (may be NULL).

maxsize_

TE_FATAL_ERROR

in an unlikely case of a memory allocation failure.

Returns:

A pointer to a fresh copy of src_.