Add pluggable heap allocator

This adds the glfwInitAllocator function for specifying a custom memory
allocator to use instead of the C runtime library.

The allocator is a struct of type GLFWallocator with fields
corresponding to malloc, realloc and free, while the internal API
corresponds to calloc, realloc and free.

Heap allocation calls are filtered before reaching the user-provided
functions, so deallocation of NULL and allocations of zero bytes are not
passed on, reallocating NULL is transformed into an allocation and
reallocating to size zero is transformed into deallocation.

The clearing of a new block to zero is performed by the internal
calloc-like function.

Closes #544.
Fixes #1628.
Closes #1947.
This commit is contained in:
Camilla Löwy
2021-08-03 20:53:48 +02:00
parent 4e557437f2
commit 22b586b3d8
33 changed files with 647 additions and 153 deletions

View File

@@ -1330,6 +1330,131 @@ typedef struct GLFWwindow GLFWwindow;
*/
typedef struct GLFWcursor GLFWcursor;
/*! @brief The function pointer type for memory allocation callbacks.
*
* This is the function pointer type for memory allocation callbacks. A memory
* allocation callback function has the following signature:
* @code
* void* function_name(size_t size, void* user)
* @endcode
*
* This function must return either a memory block at least `size` bytes long,
* or `NULL` if allocation failed. Note that not all parts of GLFW handle allocation
* failures gracefully yet.
*
* This function may be called during @ref glfwInit but before the library is
* flagged as initialized, as well as during @ref glfwTerminate after the
* library is no longer flagged as initialized.
*
* Any memory allocated by this function will be deallocated during library
* termination or earlier.
*
* The size will always be greater than zero. Allocations of size zero are filtered out
* before reaching the custom allocator.
*
* @param[in] size The minimum size, in bytes, of the memory block.
* @param[in] user The user-defined pointer from the allocator.
* @return The address of the newly allocated memory block, or `NULL` if an
* error occurred.
*
* @pointer_lifetime The returned memory block must be valid at least until it
* is deallocated.
*
* @reentrancy This function should not call any GLFW function.
*
* @thread_safety This function may be called from any thread that calls GLFW functions.
*
* @sa @ref init_allocator
* @sa @ref GLFWallocator
*
* @since Added in version 3.4.
*
* @ingroup init
*/
typedef void* (* GLFWallocatefun)(size_t size, void* user);
/*! @brief The function pointer type for memory reallocation callbacks.
*
* This is the function pointer type for memory reallocation callbacks.
* A memory reallocation callback function has the following signature:
* @code
* void* function_name(void* block, size_t size, void* user)
* @endcode
*
* This function must return a memory block at least `size` bytes long, or
* `NULL` if allocation failed. Note that not all parts of GLFW handle allocation
* failures gracefully yet.
*
* This function may be called during @ref glfwInit but before the library is
* flagged as initialized, as well as during @ref glfwTerminate after the
* library is no longer flagged as initialized.
*
* Any memory allocated by this function will be deallocated during library
* termination or earlier.
*
* The block address will never be `NULL` and the size will always be greater than zero.
* Reallocations of a block to size zero are converted into deallocations. Reallocations
* of `NULL` to a non-zero size are converted into regular allocations.
*
* @param[in] block The address of the memory block to reallocate.
* @param[in] size The new minimum size, in bytes, of the memory block.
* @param[in] user The user-defined pointer from the allocator.
* @return The address of the newly allocated or resized memory block, or
* `NULL` if an error occurred.
*
* @pointer_lifetime The returned memory block must be valid at least until it
* is deallocated.
*
* @reentrancy This function should not call any GLFW function.
*
* @thread_safety This function may be called from any thread that calls GLFW functions.
*
* @sa @ref init_allocator
* @sa @ref GLFWallocator
*
* @since Added in version 3.4.
*
* @ingroup init
*/
typedef void* (* GLFWreallocatefun)(void* block, size_t size, void* user);
/*! @brief The function pointer type for memory deallocation callbacks.
*
* This is the function pointer type for memory deallocation callbacks.
* A memory deallocation callback function has the following signature:
* @code
* void function_name(void* block, void* user)
* @endcode
*
* This function may deallocate the specified memory block. This memory block
* will have been allocated with the same allocator.
*
* This function may be called during @ref glfwInit but before the library is
* flagged as initialized, as well as during @ref glfwTerminate after the
* library is no longer flagged as initialized.
*
* The block address will never be `NULL`. Deallocations of `NULL` are filtered out
* before reaching the custom allocator.
*
* @param[in] block The address of the memory block to deallocate.
* @param[in] user The user-defined pointer from the allocator.
*
* @pointer_lifetime The specified memory block will not be accessed by GLFW
* after this function is called.
*
* @reentrancy This function should not call any GLFW function.
*
* @thread_safety This function may be called from any thread that calls GLFW functions.
*
* @sa @ref init_allocator
* @sa @ref GLFWallocator
*
* @since Added in version 3.4.
*
* @ingroup init
*/
typedef void (* GLFWdeallocatefun)(void* block, void* user);
/*! @brief The function pointer type for error callbacks.
*
* This is the function pointer type for error callbacks. An error callback
@@ -1887,6 +2012,23 @@ typedef struct GLFWgamepadstate
float axes[6];
} GLFWgamepadstate;
/*! @brief
*
* @sa @ref init_allocator
* @sa @ref glfwInitAllocator
*
* @since Added in version 3.4.
*
* @ingroup init
*/
typedef struct GLFWallocator
{
GLFWallocatefun allocate;
GLFWreallocatefun reallocate;
GLFWdeallocatefun deallocate;
void* user;
} GLFWallocator;
/*************************************************************************
* GLFW API functions
@@ -1930,6 +2072,8 @@ typedef struct GLFWgamepadstate
* @thread_safety This function must only be called from the main thread.
*
* @sa @ref intro_init
* @sa @ref glfwInitHint
* @sa @ref glfwInitAllocator
* @sa @ref glfwTerminate
*
* @since Added in version 1.0.
@@ -2004,6 +2148,33 @@ GLFWAPI void glfwTerminate(void);
*/
GLFWAPI void glfwInitHint(int hint, int value);
/*! @brief Sets the init allocator to the desired value.
*
* To use the default allocator, call this function with a `NULL` argument.
*
* If you specify an allocator struct, every member must be a valid function
* pointer. If any member is `NULL`, this function emits @ref
* GLFW_INVALID_VALUE and the init allocator is unchanged.
*
* @param[in] allocator The allocator to use at the next initialization, or
* `NULL` to use the default one.
*
* @errors Possible errors include @ref GLFW_INVALID_VALUE.
*
* @pointer_lifetime The specified allocator is copied before this function
* returns.
*
* @thread_safety This function must only be called from the main thread.
*
* @sa @ref init_allocator
* @sa @ref glfwInit
*
* @since Added in version 3.4.
*
* @ingroup init
*/
GLFWAPI void glfwInitAllocator(const GLFWallocator* allocator);
/*! @brief Retrieves the version of the GLFW library.
*
* This function retrieves the major, minor and revision numbers of the GLFW