diff --git a/src/system_allocator.c b/src/system_allocator.c
index f9dd291aebb4aec066e3ed02fd249f60c2f73be7..b47bf06a575cc08b63219814f91caefd96cc6bfb 100644
--- a/src/system_allocator.c
+++ b/src/system_allocator.c
@@ -2,41 +2,77 @@
 #include <stdlib.h>
 #include "internal.h"
 
-//#define DEBUG__MEMFILL 0xFF
+// NOTE(uucidl): undefine to automatically fill up newly allocated block
+// with this byte:
+// #define DEBUG__MEMFILL 0xFF
+
+/**
+ * Blocks allocated by the system_allocator start with this header.
+ * I.e. the user part of the allocation directly follows.
+ */
+typedef struct HDebugBlockHeader_
+{
+  size_t size; /** size of the user allocation */
+} HDebugBlockHeader;
+
+#define BLOCK_HEADER_SIZE (sizeof(HDebugBlockHeader))
+
+/**
+ * Compute the total size needed for a given allocation size.
+ */
+static inline size_t block_size(size_t alloc_size) {
+  return BLOCK_HEADER_SIZE + alloc_size;
+}
+
+/**
+ * Obtain the block containing the user pointer `uptr`
+ */
+static inline void* block_for_user_ptr(void *uptr) {
+  return ((char*)uptr) - BLOCK_HEADER_SIZE;
+}
+
+/**
+ * Obtain the user area of the allocation from a given block
+ */
+static inline void* user_ptr(void *block) {
+  return ((char*)block) + BLOCK_HEADER_SIZE;
+}
 
 static void* system_alloc(HAllocator *allocator, size_t size) {
-  
-  void* ptr = malloc(size + sizeof(size_t));
-  if (!ptr) {
+  void *block = malloc(block_size(size));
+  if (!block) {
     return NULL;
   }
+  void *uptr = user_ptr(block);
 #ifdef DEBUG__MEMFILL
-  memset(ptr, DEBUG__MEMFILL, size + sizeof(size_t));
+  memset(uptr, DEBUG__MEMFILL, size);
 #endif
-  *(size_t*)ptr = size;
-  return ptr + sizeof(size_t);
+  ((HDebugBlockHeader*)block)->size = size;
+  return uptr;
 }
 
-static void* system_realloc(HAllocator *allocator, void* ptr, size_t size) {
-  if (!ptr) {
+static void* system_realloc(HAllocator *allocator, void* uptr, size_t size) {
+  if (!uptr) {
     return system_alloc(allocator, size);
   }
-  ptr = realloc(ptr - sizeof(size_t), size + sizeof(size_t));
-  if (!ptr) {
+  void* block = realloc(block_for_user_ptr(uptr), block_size(size));
+  if (!block) {
     return NULL;
   }
-  *(size_t*)ptr = size;
+  uptr = user_ptr(block);
+
 #ifdef DEBUG__MEMFILL
-  size_t old_size = *(size_t*)ptr;
+  size_t old_size = ((HDebugBlockHeader*)block)->size;
   if (size > old_size)
-    memset(ptr+sizeof(size_t)+old_size, DEBUG__MEMFILL, size - old_size);
+    memset((char*)uptr+old_size, DEBUG__MEMFILL, size - old_size);
 #endif
-  return ptr + sizeof(size_t);
+  ((HDebugBlockHeader*)block)->size = size;
+  return uptr;
 }
 
-static void system_free(HAllocator *allocator, void* ptr) {
-  if (ptr) {
-    free(ptr - sizeof(size_t));
+static void system_free(HAllocator *allocator, void* uptr) {
+  if (uptr) {
+    free(block_for_user_ptr(uptr));
   }
 }
 
diff --git a/tools/windows/hammer_lib_src_list b/tools/windows/hammer_lib_src_list
index 87b3b280b48e3a720b3256da32e84c3c26544674..c332d2c2362e7a2760ca3c139a3f6a0bc7ab96ba 100644
--- a/tools/windows/hammer_lib_src_list
+++ b/tools/windows/hammer_lib_src_list
@@ -7,6 +7,7 @@ cfgrammar.c
 desugar.c 
 glue.c 
 hammer.c 
+system_allocator.c
 parsers/action.c 
 parsers/and.c 
 parsers/attr_bool.c