#include <stdlib.h>
#include <string.h>

static void* (*const volatile memset_ptr)(void*, int, size_t) = memset;

static void moresecure_memzero(void* p, size_t len) {
  __asm__("" : : "m"(p));
  (memset_ptr)(p, 0, len);
}

void* secAlloc(size_t size) {
  if (size == 0) {
    return NULL;
  }
  size_t sizesize = sizeof(size);
  void*  p        = calloc(size + sizesize, 1);
  if (p == NULL) {
    return NULL;
  }
  *(size_t*)p = size;
  return p + sizesize;
}

#define secFree(ptr) \
  do {               \
    _secFree((ptr)); \
    (ptr) = NULL;    \
  } while (0)
#define secFreeN(ptr, len)   \
  do {                       \
    _secFreeN((ptr), (len)); \
    (ptr) = NULL;            \
  } while (0)

void _secFreeN(void* p, size_t len) {
  if (p == NULL) {
    return;
  }
  moresecure_memzero(p, len);
  free(p);
}

void _secFree(void* p) {
  if (p == NULL) {
    return;
  }
  void*  freeptr = p - sizeof(size_t);
  size_t len     = *(size_t*)freeptr;
  secFreeN(freeptr, len);
}

void* secRealloc(void* p, size_t size) {
  if (p == NULL) {
    return secAlloc(size);
  }
  if (size == 0) {
    secFree(p);
    return NULL;
  }
  size_t oldsize = *(size_t*)(p - sizeof(size_t));
  size_t movelen = oldsize < size ? oldsize : size;
  void*  newp    = secAlloc(size);
  if (newp == NULL) {
    return NULL;
  }
  memmove(newp, p, movelen);
  secFree(p);
  return newp;
}

