dksdk_ffi_c/mem.h

Defines

__STDC_WANT_LIB_EXT1__
DKSDK_FFI_C_ATOMIC_STORAGE_PTR()

Usage: For pointers the DKSDK_FFI_C_ATOMIC_STORAGE() is a storage qualifier for the pointed-to value, not the pointer.

Example:

DKSDK_FFI_C_ATOMIC_STORAGE_VALUE()
DKSDK_FFI_C_ATOMIC_EXCHANGE(E_PTR, E_VALUE)
DKSDK_FFI_C_ATOMIC_COMPARENULL_EXCHANGE(PTR_TYP, E_PTR, E_DESIRED, E_EXCHANGED)
DKSDK_FFI_C_ATOMIC_LOAD(E_PTR)
DKSDK_FFI_C_MEMCPY_MAYBE_SAFE(DEST, SRC, N)
DKSDK_FFI_C_MEMMOVE_MAYBE_SAFE(DEST, SRC, N)
DKSDK_FFI_C_MEMCMP(S1, S2, N)
DKSDK_SNPRINTF_S(S, N, ...)

Typedefs

typedef void *MEMORY_ALLOC(size_t)
typedef void *MEMORY_CALLOC(size_t, size_t)
typedef void *ALIGNED_ALLOC_WITH_ALIGNMENT_SIZE(size_t, size_t)
typedef void MEMORY_FREE(void*)
typedef void MEMORY_FREE_OPAQUE(uintptr_t)

Enums

enum dksdk_ffi_c_memrequest_type

Values:

enumerator DKSDK_FFI_C_MEMREQUEST_DEFAULT
enumerator DKSDK_FFI_C_MEMREQUEST_ZEROED
enumerator DKSDK_FFI_C_MEMREQUEST_ALIGNED
enumerator DKSDK_FFI_C_MEMREQUEST_ZEROED_ALIGNED
enum dksdk_ffi_c_heap_type

The type of heap allocator given to dksdk_ffi_c_heap_init.

Values:

enumerator DKSDK_FFI_C_HEAP_ALLOC_DEFAULT
enumerator DKSDK_FFI_C_HEAP_ALLOC_ZEROED

A type indicating that the supplied aligned allocator, allocator and re-allocator fill its memory blocks with zeros.

All three (3) allocators must be supplied for this type to be valid.

Do not use this type if the supplied allocators fill its memory blocks with some other constant value (ex. 77) or some pattern of bytes.

Functions

int dksdk_ffi_c_validate_memrequest(const struct dksdk_ffi_c_memrequest request, size_t *alignment)

Validate the memory request.

Parameters:
  • request -- [in] The memory request to be validated.

  • alignment -- [inout] May be NULL. If not NULL and if successful, this parameter will be set to the alignment of the requested memory. There is a default non-zero alignment when an alignment was not specifically requested.

Returns:

  • DKSDK_FFI_OK when validated

  • DKSDK_FFI_ERR_INVALID_ARGUMENT when not validated

int dksdk_ffi_c_is_memrequest_type_zeroed(enum dksdk_ffi_c_memrequest_type type)

Does the memory requested need to be zero-ed?

Parameters:

type -- The memory request type

Returns:

Non-zero if the memory request is zero-ed.

int dksdk_ffi_c_is_memrequest_type_aligned(enum dksdk_ffi_c_memrequest_type type)

Does the memory requested need to be aligned?

Parameters:

type -- The memory request type

Returns:

Non-zero if the memory request is aligned.

DKSDK_FFI_C_EXPORT void dksdk_ffi_c_memblock_free(struct dksdk_ffi_c_memblock *memblock)

Free the memory block.

Parameters:

memblock -- the memory block

void dksdk_ffi_c_memblock_freer_free(struct dksdk_ffi_c_memblock_freer *memblock_freer)

Free the memory block using a freer.

Parameters:

memblock_freer -- the memory block freer

DKSDK_FFI_C_EXPORT void dksdk_ffi_c_zero_mem(void *ptr, size_t size)

Zero the memory range.

Parameters:
  • ptr -- The start of the memory range to be zero-ed

  • size -- The size of the memory range to be zero-ed

int dksdk_ffi_c_heap_type_is_zeroed(enum dksdk_ffi_c_heap_type type)
DKSDK_FFI_C_EXPORT struct dksdk_ffi_c_heap *dksdk_ffi_c_heap_get_default()

Get the default heap allocator.

DKSDK_FFI_C_EXPORT int dksdk_ffi_c_heap_init(enum dksdk_ffi_c_heap_type heapAllocType, void *(*alignedAllocWithAlignmentSize)(size_t, size_t), void (*alignedFree)(void*), void *(*malloc)(size_t), void *(*calloc)(size_t, size_t), void *(*realloc)(void*, size_t), void (*free)(void*), struct dksdk_ffi_c_heap *heap)

Create a heap allocator.

Parameters:
  • heapAllocType -- [in] A dksdk_ffi_c_heap_type

  • alignedAllocWithAlignmentSize -- [in] A custom aligned_alloc(alignment, size). When it is NULL, if there is a known aligned allocator for the platform, it will be used; otherwise the standard malloc will be used accompanied by a memory inefficient alignment algorithm.

  • alignedFree -- [in] A custom aligned_free for aligned memory created with alignedAllocWithAlignmentSize. When it is NULL a platform or generic aligned de-allocator will be used.

  • malloc -- [in] A custom malloc, or NULL for the standard malloc.

  • calloc -- [in] A custom calloc, or NULL for the standard calloc.

  • realloc -- [in] A custom realloc, or NULL for the standard realloc.

  • free -- [in] A custom free, or NULL for the standard free.

  • heap -- [inout] A pointer to an uninitialized heap structure. On success the heap structure will be valid.

Returns:

  • DKSDK_FFI_OK on success

  • DKSDK_FFI_ERR_INVALID_ARGUMENT when pheap is NULL or heapAllocType is invalid

  • DKSDK_FFI_ERR_INVALID_STATE when the library can't be initialized

DKSDK_FFI_C_EXPORT int dksdk_ffi_c_heap_alloc(struct dksdk_ffi_c_heap *heap, const struct dksdk_ffi_c_memrequest request, struct dksdk_ffi_c_memblock *memblock)

Allocate a memory block on the heap.

Use dksdk_ffi_c_memblock_free to free the memory block.

Parameters:
  • heap -- [in] The heap memory created by dksdk_ffi_c_heap_init

  • request -- [in] The requested amount and type of memory

  • memblock -- [inout] On success the structure will be initialized to the details of the newly allocated memory block

Returns:

  • DKSDK_FFI_OK on success

  • DKSDK_FFI_ERR_INVALID_ARGUMENT when heap or memblock is NULL, or when request is not valid.

DKSDK_FFI_C_EXPORT void dksdk_ffi_c_stack_init(size_t size, void *memory_buffer, size_t soft_trigger_heap_size, struct dksdk_ffi_c_stack *stack)

Create a stack allocator similar to alloca but backed by a memory buffer.

The main problems with alloca are that:

  • it uses the sometimes tiny C function call stack

  • it has undefined behavior if the stack overflows (ie. exploitable or can cause SIGSEGV signals)

The [soft_trigger_heap_size] parameter controls the advisory function dksdk_ffi_c_stack_is_heap_recommended. The recommendation is for stack users to check the advisory function before doing major stack allocations, and switch to heap allocations if it returned true (nonzero). Otherwise the stack may run out of memory.

However, switching to the heap may have a performance impact. If you don't want an unexpected runtime performance downgrade under presumably heavy stack usage (likely correlated to heavy load), you should turn off the advisory recommendation by setting [soft_trigger_heap_size] to zero.

Parameters:
  • size -- [in] The size of the memory buffer

  • memory_buffer -- [in] The region of memory where the stack allocations will live. Typically a static array or allocated on the heap.

  • soft_trigger_heap_size -- [in] How many bytes until the stack allocators gave an advisory to its callers that they should be using the heap rather than the stack. Set to 0 to always use the stack, even if the stack will overflow and return errors to its callers. The advisory is served through dksdk_ffi_c_stack_is_heap_recommended, which may or may not be used by the stack callers.

  • stack -- [inout] On success the structure will be initialized to be a valid stack allocator

DKSDK_FFI_C_EXPORT int dksdk_ffi_c_stack_is_heap_recommended(const struct dksdk_ffi_c_stack *stack)

Advice whether the caller should switch over to heap allocations.

Confer with dksdk_ffi_c_stack_init.

Parameters:

stack -- [in] The stack memory created by dksdk_ffi_c_stack_init

Returns:

0 if stack allocations should be used. 1 if heap allocations should be used.

DKSDK_FFI_C_EXPORT int dksdk_ffi_c_stack_alloc(struct dksdk_ffi_c_stack *stack, const struct dksdk_ffi_c_memrequest request, struct dksdk_ffi_c_memblock *memblock)

Allocate a memory block on the stack memory (not the sometimes tiny C function call stack).

Use dksdk_ffi_c_memblock_free to free the memory block.

It is recommended to check with dksdk_ffi_c_stack_is_heap_recommended before doing major stack allocations, and switch to heap allocations if it is nonzero (true). Otherwise the stack may run out of memory, although for performance sensitive application running out of stack memory is sometimes the right approach.

Parameters:
  • stack -- [in] The stack memory created by dksdk_ffi_c_stack_init

  • request -- [in] The requested amount and type of memory

  • memblock -- [inout] On success the structure will be initialized to the details of the newly allocated memory block

Returns:

  • DKSDK_FFI_OK on success

  • DKSDK_FFI_ERR_INVALID_ARGUMENT when stack or memblock is NULL, or when request is not valid.

DKSDK_FFI_C_EXPORT int dksdk_ffi_c_stack_free_all(struct dksdk_ffi_c_stack *stack)

Free all allocated stack memory blocks.

Parameters:

stack -- [in] The stack memory created by dksdk_ffi_c_stack_init

Returns:

  • DKSDK_FFI_OK on success

  • DKSDK_FFI_ERR_INVALID_ARGUMENT when stack is NULL

struct dksdk_ffi_c_memrequest_aligned
#include <mem.h>

Details specific to aligned memory requests.

Public Members

size_t alignment

Must be a power of two multiple of sizeof(void*), to allow a fallback to posix_memalign.

struct dksdk_ffi_c_memrequest
#include <mem.h>

A request to allocate a block of memory.

Public Members

size_t size

The minimum number of bytes to allocate.

If zero, then the returned memory block may have NULL usable_when_nonempty as per POSIX.

enum dksdk_ffi_c_memrequest_type type

Whether the memory should be aligned (or not), or zeroed (or not).

struct dksdk_ffi_c_memrequest_aligned if_aligned

Must be set when any aligned memory is requested.

union dksdk_ffi_c_memrequest sum_type

Enumeration payloads keyed off of type.

struct dksdk_ffi_c_memblock_freer
#include <mem.h>

A free-er of allocated memory blocks.

Public Members

MEMORY_FREE_OPAQUE *freefunc

A function that will relinquish the usable memory block.

uintptr_t freeable

Opaque representation of what needs to be freed to relinquish the usable memory block.

struct dksdk_ffi_c_memblock
#include <mem.h>

An allocated block of memory.

Public Members

void *usable_when_nonempty

Pointer to usable memory block.

If the requested memory block was zero-sized the pointer may be NULL as per POSIX.

struct dksdk_ffi_c_memblock_freer freer

The free-er of the usable memory block.

struct dksdk_ffi_c_heap
#include <mem.h>

Member variables and functions for a DkSDK FFI C heap allocator.

Public Members

enum dksdk_ffi_c_heap_type allocType

The allocation type from dksdk_ffi_c_heap_init(heapAllocType).

ALIGNED_ALLOC_WITH_ALIGNMENT_SIZE *fpAlignedAllocWithAlignmentSizeUserOpt

The user-supplied aligned allocator with parameters (alignment,size), or NULL.

MEMORY_FREE *fpAlignedFreeUserOpt

The user-supplied aligned de-allocator, or NULL.

MEMORY_ALLOC *fpMallocUser

The user-supplied malloc, or the system default.

MEMORY_CALLOC *fpCallocUser

The user-supplied calloc, or the system default.

void *(*fpReallocUser)(void*, size_t)

The user-supplied realloc, or the system default.

MEMORY_FREE *fpFreeUser

The user-supplied unaligned de-allocator, or NULL.

struct dksdk_ffi_c_stack
#include <mem.h>

Member variables and functions for a DkSDK FFI C shadow stack allocator.

Public Members

unsigned char *buf
size_t buf_len
size_t prev_offset
size_t offset
size_t soft_trigger_heap_size
struct dksdk_ffi_c_stack_alloc_header
#include <mem.h>

The header block in memory that precedes each allocation in the shadow stack allocator.

Public Members

struct dksdk_ffi_c_stack *stack
size_t prev_offset
size_t padding