/*############################################################################ # Copyright 2016-2017 Intel Corporation # # 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 * \brief Memory access implementation. */ #include "epid/common/src/memory.h" #include <stdint.h> #include <string.h> /// Maximum size of the destination buffer #ifndef RSIZE_MAX #define RSIZE_MAX ((SIZE_MAX) >> 1) #endif #ifndef MIN /// Evaluate to minimum of two values #define MIN(a, b) ((a) < (b) ? (a) : (b)) #endif // MIN /// Copies count of character from dest to src /*! \note Implementation follows C11 memcpy_s but with checks always enabled */ int memcpy_S(void* dest, size_t destsz, void const* src, size_t count) { size_t i; if (!dest || destsz > RSIZE_MAX) return -1; if (!src || count > RSIZE_MAX || count > destsz || count > (dest > src ? ((uintptr_t)dest - (uintptr_t)src) : ((uintptr_t)src - (uintptr_t)dest))) { // zero out dest if error detected memset(dest, 0, destsz); return -1; } for (i = 0; i < count; i++) ((uint8_t*)dest)[i] = ((uint8_t*)src)[i]; return 0; } void EpidZeroMemory(void* ptr, size_t size) { memset(ptr, 0, size); } #if defined(EPID_ENABLE_EPID_ZERO_MEMORY_ON_FREE) #if !defined(EPID_ALLOC_ALIGN) /// Alignment constant for EpidAlloc, must be a power of two #define EPID_ALLOC_ALIGN sizeof(size_t) #endif // !defined(EPID_ALLOC_ALIGN) #pragma pack(1) /// Allocated memory block information typedef struct EpidAllocHeader { size_t length; ///< number of bytes memory block is allocated for void* ptr; ///< pointer to whole memory block including EpidAllocHeader } EpidAllocHeader; #pragma pack() #endif // defined(EPID_ENABLE_EPID_ZERO_MEMORY_ON_FREE) void* EpidAlloc(size_t size) { #if defined(EPID_ENABLE_EPID_ZERO_MEMORY_ON_FREE) void* ptr = NULL; if (size <= 0) return NULL; // Allocate memory enough to store size bytes and EpidAllocHeader ptr = calloc(1, size + EPID_ALLOC_ALIGN - 1 + sizeof(EpidAllocHeader)); if (ptr) { void* aligned_pointer = (void*)(((uintptr_t)ptr + EPID_ALLOC_ALIGN + sizeof(EpidAllocHeader) - 1) & (~(EPID_ALLOC_ALIGN - 1))); ((EpidAllocHeader*)aligned_pointer)[-1].length = size; ((EpidAllocHeader*)aligned_pointer)[-1].ptr = ptr; return aligned_pointer; } return NULL; #else // defined(EPID_ENABLE_EPID_ZERO_MEMORY_ON_FREE) return calloc(1, size); #endif // defined(EPID_ENABLE_EPID_ZERO_MEMORY_ON_FREE) } void* EpidRealloc(void* ptr, size_t new_size) { #if defined(EPID_ENABLE_EPID_ZERO_MEMORY_ON_FREE) void* new_ptr = EpidAlloc(new_size); if (!new_ptr) return NULL; if (ptr) { // Memory copy is used to copy a buffer of variable length if (0 != memcpy_S(new_ptr, ((EpidAllocHeader*)new_ptr)[-1].length, ptr, MIN(((EpidAllocHeader*)ptr)[-1].length, ((EpidAllocHeader*)new_ptr)[-1].length))) { EpidFree(new_ptr); return NULL; } EpidFree(ptr); } return new_ptr; #else // defined(EPID_ENABLE_EPID_ZERO_MEMORY_ON_FREE) return realloc(ptr, new_size); #endif // defined(EPID_ENABLE_EPID_ZERO_MEMORY_ON_FREE) } void EpidFree(void* ptr) { #if defined(EPID_ENABLE_EPID_ZERO_MEMORY_ON_FREE) if (ptr) { EpidZeroMemory(ptr, ((EpidAllocHeader*)ptr)[-1].length); free(((EpidAllocHeader*)ptr)[-1].ptr); } #else // defined(EPID_ENABLE_EPID_ZERO_MEMORY_ON_FREE) free(ptr); #endif // defined(EPID_ENABLE_EPID_ZERO_MEMORY_ON_FREE) }