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 |
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 |
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 |
zero_terminated |
If |
maxsize |
Maximum number of bytes to copy (may be less if |
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 |
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 |
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 |
maxsize_ |
|
TE_FATAL_ERROR |
in an unlikely case of a memory allocation failure. |
Returns:
A pointer to a fresh copy of src_
.