/*############################################################################
# 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)
}