diff options
Diffstat (limited to 'libparc/parc/algol/parc_SafeMemory.h')
-rw-r--r-- | libparc/parc/algol/parc_SafeMemory.h | 335 |
1 files changed, 335 insertions, 0 deletions
diff --git a/libparc/parc/algol/parc_SafeMemory.h b/libparc/parc/algol/parc_SafeMemory.h new file mode 100644 index 00000000..0383fe39 --- /dev/null +++ b/libparc/parc/algol/parc_SafeMemory.h @@ -0,0 +1,335 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file parc_SafeMemory.h + * @ingroup developer + * + * @brief Facade to memory functions to make calls safer. + * + * This is a facade to interpose between an application and the standard C library functions posix_memalign(3), + * malloc(3), calloc(3), realloc(3) and free(3) that establishes detectable boundaries around an allocated memory segment, + * records a stack backtrace for each allocation, + * detects buffer overruns and underruns by checking the boundaries when the memory is deallocated, + * and tries to prevent a stray pointer to reference the memory again once it's been deallocated. + * + * The allocated memory consists of three contiguous segments: the prefix, the memory usable by the caller, and the suffix. + * The memory usable by the caller is aligned as specified by the caller. + * The alignment must be a power of 2 greater than or equal to the size of a {@code void *}. + * <pre> + * +--base +-prefix +-- aligned memory +-- suffix aligned on (void *) + * v v v v + * |________|PPPPPPPPPPPP|mmmmmmmmm...mmmm|___|SSSSSSSSS + * ^ + * +-- variable padding + * </pre> + * Where '-' indicates padding, 'P' indicates the prefix data structure, 'm' + * indicates contiguous memory for use by the caller, and 'S" indicates the suffix data structure. + * + * To enable this facade, you must include the following line in your execution before any allocations are performed. + * + * @code + * { + * parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + * } + * @endcode + * + */ +#ifndef libparc_parc_SafeMemory_h +#define libparc_parc_SafeMemory_h + +#include <stdlib.h> +#include <stdint.h> +#include <stdbool.h> + +#include <parc/algol/parc_Memory.h> + +typedef enum parc_safety_memory_state { + PARCSafeMemoryState_OK = 0, + PARCSafeMemoryState_MISMATCHED = 1, + PARCSafeMemoryState_UNDERRUN = 2, + PARCSafeMemoryState_OVERRUN = 3, + PARCSafeMemoryState_NOTHINGALLOCATED = 4, + PARCSafeMemoryState_ALREADYFREE = 5 +} PARCSafeMemoryState; + +/** + * Generate a readable, null-terminated C string representation + * for the specified `PARCSafeMemoryState` type. + * + * @param [in] status A `PARCSafeMemoryState` value. + * + * @return A null-terminated C string that must be freed when done. + * + * Example: + * @code + * { + * size_t size = 100; + * uint32_t alignment = sizeof(void *); + * void *memory; + * + * memory = parcSafeMemory_Allocate(size); + * PARCSafeMemoryState state = parcSafeMemory_Destroy(&memory); + * + * printf("SafeMemoryState = %s\n", parcSafeMemoryState_ToString(state)); + * } + * @endcode + */ +const char *parcSafeMemoryState_ToString(PARCSafeMemoryState status); + +/** + * Memory operations defined by {@link PARCMemoryInterface} + * and implemented by the Safe Memory functions. + */ +extern PARCMemoryInterface PARCSafeMemoryAsPARCMemory; + +/** + * Allocate Safe Memory. + * + * Allocate memory through the configured memory allocator, setting the environment to track this memory. + * + * @param [in] size The number of bytes necessary. + * + * @return non-NULL A pointer to allocated memory. + * @return NULL Memory could not be allocated. + * + * Example: + * @code + * { + * size_t size = 100; + * void *memory = parcSafeMemory_Allocate(size); + * } + * @endcode + */ +void *parcSafeMemory_Allocate(size_t size); + +/** + * Allocate Safe Memory. + * + * Allocate memory through the configured memory allocator, setting the environment to track this memory. + * + * @param [in] requestedSize The number of bytes necessary. + * + * @return non-NULL A pointer to allocated memory. + * @return NULL Memory could not be allocated. + * + * Example: + * @code + * { + * size_t size = 100; + * void *memory = parcSafeMemory_Allocate(size); + * } + * @endcode + */ +void *parcSafeMemory_AllocateAndClear(size_t requestedSize); + +/** + * Allocate aligned memory. + * + * Allocates @p size bytes of memory such that the allocation's + * base address is an exact multiple of alignment, + * and returns the allocation in the value pointed to by @p pointer. + * + * The requested alignment must be a power of 2 greater than or equal to `sizeof(void *)`. + * + * Memory that is allocated can be used as an argument in subsequent call `Reallocate`, however + * `Reallocate` is not guaranteed to preserve the original alignment. + * + * @param [out] pointer A pointer to a `void *` pointer that will be set to the address of the allocated memory. + * @param [in] alignment A power of 2 greater than or equal to `sizeof(void *)` + * @param [in] size The number of bytes to allocate. + * + * @return 0 Successful + * @return EINVAL The alignment parameter is not a power of 2 at least as large as sizeof(void *) + * @return ENOMEM Memory allocation error. + * + * Example: + * @code + * { + * void *allocatedMemory; + * + * int failure = parcSafeMemory_MemAlign(&allocatedMemory, sizeof(void *), 100); + * if (failure == 0) { + * parcSafeMemory_Deallocate(&allocatedMemory); + * // allocatedMemory is now equal to zero. + * } + * } + * @endcode + * @see `posix_memalign` + */ +int parcSafeMemory_MemAlign(void **pointer, size_t alignment, size_t size); + +/** + * Deallocate memory previously allocated with {@link parcSafeMemory_Allocate} + * + * The value pointed to by @p pointer will be set to NULL. + * + * @param [in,out] pointer A pointer to a pointer to the allocated memory. + * + * Example: + * @code + * { + * size_t size = 100; + * void *memory = parcSafeMemory_Allocate(size); + * + * parcSafeMemory_Deallocate(&memory); + * } + * @endcode + */ +void parcSafeMemory_Deallocate(void **pointer); + +/** + * A (mostly) suitable replacement for realloc(3). + * The primary difference is that it is an error if newSize is zero. + * If the newSize is equal to the old size, then NULL is returned. + * + * @param [in] original Pointer to the original memory + * @param [in] newSize The size of the newly re-allocated memory. + * + * @return Non-NULL A pointer to the newly allocated memory + * @return NULL An error occurred (newSize == oldSize, or newSize == 0) + * + * Example: + * @code + * { + * void *memory = parcSafeMemory_Allocate(100); + * + * size_t newLength = 0; + * unsigned char *newMemory = parcSafeMemory_Reallocate(memory, newLength); + * + * assertTrue(newMemory == NULL, "Expected NULL, actual %p", newMemory); + * } + * @endcode + */ +void *parcSafeMemory_Reallocate(void *original, size_t newSize); + +/** + * Duplicate the given null-terminated C string. + * + * @param [in] string A pointer to a null-terminated C string. + * @param [in] length The length of the string, not including the terminating null character. + * + * @return non-NULL Allocated Safe Memory containing the duplicate string. This must be freed via `parcSafeMemory_Deallocate`. + * @return NULL Memory could not be allocated. + * + * Example: + * @code + * { + * char *string = "hello world"; + * char *actual = parcSafeMemory_StringDuplicate(string, strlen(string)); + * ... + * } + * @endcode + * + * @see parcSafeMemory_Deallocate + */ +char *parcSafeMemory_StringDuplicate(const char *string, size_t length); + +/** + * Return the number of outstanding allocations. + * + * In practice, every allocation should be matched with a corresponding deallocation. + * This return the number of allocations that have not been deallocated. + * + * @return The number of outstanding allocations. + * + */ +uint32_t parcSafeMemory_Outstanding(void); + +/** + * Display information about outstanding memory allocations. + * + * To enable this function, you must include the following line in your execution before any allocations are performed. + * + * @code + * { + * parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + * } + * @endcode + * + * @param [in] outputFd Output file descriptor. + * + * @return The number of currenly outstanding allocations. + * + * Example: + * @code + * { + * parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + * + * ... + * + * FILE *fd = fopen ("log.txt", "w"); + * size_t outstandingAllocations = parcSafeMemory_ReportAllocation(fd); + * } + * @endcode + */ +uint32_t parcSafeMemory_ReportAllocation(int outputFd); + +/** + * Determine if a pointer to Safe Memory is valid. + * + * Invalid indicates the memory is overrun or underrun. + * + * To enable this function, you must include the following line in your execution before any allocations are performed. + * + * @code + * { + * parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + * } + * @endcode + * + * @param [in] memory A pointer to previously allocated Safe Memory. + * + * @return true The memory is valid; + * @return false The memory is invalid; + * + * Example: + * @code + * { + * void *memory = parcSafeMemory_Allocate(100); + * if (parcSafeMemory_IsValid(memory) == false) { + * printf("Memory is invalid\n"); + * } + * @endcode + */ +bool parcSafeMemory_IsValid(const void *memory); + +/** + * Print a human readable representation of the given PARC Safe Memory array. + * + * To enable this function, you must include the following line in your execution before any allocations are performed. + * + * @code + * { + * parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + * } + * @endcode + * + * @param [in] indentation The level of indentation to use to pretty-print the output. + * @param [in] memory A pointer to the memory to display. + * + * Example: + * @code + * { + * PARCBuffer *instance = parcBuffer_Create(); + * + * parcBuffer_Display(instance, 0); + * + * parcBuffer_Release(&instance); + * } + * @endcode + */ +void parcSafeMemory_Display(const void *memory, int indentation); +#endif // libparc_parc_SafeMemory_h |