diff --git a/.gitattributes b/.gitattributes
index e501f6fa274f5008912cdf4fd1d944d7e2d03b74..3e9d8ca4b85e42683ee4558725831da7bfc95906 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -5,6 +5,8 @@
 /clean-all.sh -text
 /get-peasoup-packages.sh -text
 /irdb_vars -text
+non_overlapping_heap/Makefile -text
+non_overlapping_heap/noh.c -text
 /postgres_setup.sh -text
 /set_command_envs -text
 /set_env_vars -text
diff --git a/build-all.sh b/build-all.sh
index c4d8df8eef685a4e4e35e7184066a1c7521418c9..8931bebc7589c4f8eee8cb3d5893ebab2aacddf9 100755
--- a/build-all.sh
+++ b/build-all.sh
@@ -109,6 +109,11 @@ if [ -d DieHard ]; then
 	./build_diehard.sh
 fi
 
+cd $PEASOUP_UMBRELLA_DIR
+if [ -d non_overlapping_stack ]; then
+	make -C non_overlapping_stack
+fi
+
 cd $PEASOUP_UMBRELLA_DIR
 
 
diff --git a/clean-all.sh b/clean-all.sh
index cd329ecea58b271118f52ac8c8892a3a1529b227..6d9c11e6d0a0737968916bfe99b98610f5ed4ee7 100755
--- a/clean-all.sh
+++ b/clean-all.sh
@@ -64,4 +64,8 @@ if [ -d DieHard ]; then
 	./clean_diehard.sh
 fi
 
+if [ -d non_overlapping_heap ]; then
+	make -C non_overlapping_heap clean
+fi
+
 cd $PEASOUP_UMBRELLA_DIR
diff --git a/non_overlapping_heap/Makefile b/non_overlapping_heap/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..fde094efcbe9ec14e2242d3b7694ddfdfcbd7953
--- /dev/null
+++ b/non_overlapping_heap/Makefile
@@ -0,0 +1,15 @@
+CC=gcc
+LD=ld
+CFLAGS= -c -Wall -Werror -fPIC
+LFLAGS= -shared -ldl -fPIC
+
+all: noh.so
+noh.so: noh.o
+	$(LD) $(LFLAGS) noh.o -o noh.so
+noh.o: noh.c
+	$(CC) $(CFLAGS) noh.c
+test:
+	LD_PRELOAD="./noh.so" ls
+	LD_PRELOAD="./noh.so ../DieHard/src/libheaprand.so" ls
+clean:
+	rm *.so *.o
diff --git a/non_overlapping_heap/noh.c b/non_overlapping_heap/noh.c
new file mode 100644
index 0000000000000000000000000000000000000000..be535a0f2f658915ee18cf40d592fd228041dd24
--- /dev/null
+++ b/non_overlapping_heap/noh.c
@@ -0,0 +1,135 @@
+#define _GNU_SOURCE
+#include <errno.h>
+#include <stddef.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+/*
+ * The approach to getting non-overlapping heaps here is pretty simple - instead
+ * of simply allowing users to mmap in multiple variants and get the same
+ * result, we override the glibc mmap implementation (through LD_PRELOAD) and
+ * use our own instead, which allocates NUMVARIANTS multiples of the same amount
+ * of memory, and assigns a different section to each variant. This allows us to
+ * get most of the cases where memory is allocated, but not all of them. In some
+ * cases, programs will call mmap with specific memory addresses as the targets.
+ * This may indicate some sort of dependence on the memory layout, so we let the
+ * program have the same memory section in all variants. In others, programs may
+ * call mmap through a system call (which may even be in a non-transformed lib),
+ * which would require significantly more extensive analysis to catch and handle
+ * properly (and in many cases wouldn't be doable statically without solving the
+ * halting problem).
+ */
+
+int nthisvar = 0;
+int nnumvar  = 1;
+void* initializedvariables = NULL;
+
+extern void* mmap(void*, size_t, int, int, int, off_t);
+//extern void* mmap64(void*, size_t, int, int, int, off64_t);
+
+void* (*orig_mmap)(void*, size_t, int, int ,int, off_t) = NULL;
+//void* (*orig_mmap64)(void*, size_t, int, int ,int, off64_t) = NULL;
+
+
+void _init(void) {
+	orig_mmap = (void*(*)(void*, size_t, int, int, int, off_t)) dlsym(RTLD_NEXT, "mmap");
+	//orig_mmap64 = (void*(*)(void*, size_t, int, int, int, off64_t)) dlsym(RTLD_DEFAULT, "mmap64");
+	char* sthisvar = getenv("VARIANTINDEX"); // 0-based variant index
+	char* snumvar  = getenv("NUMVARIANTS");  // total number of variants running
+	if(!sthisvar || !snumvar) {
+		printf("didn't find environment arguments for structnoh, disabling...\n");
+	} else {
+		nthisvar = atoi(sthisvar);
+		nnumvar  = atoi(snumvar);
+		initializedvariables = (void*)1;
+	}
+}
+
+void* mmap(void* address, size_t length, int protect, int flags, int filedes, off_t offset) {
+	bool is_diversified = false;
+	size_t originallength = length;
+	void* new_mapping = MAP_FAILED;
+	if(
+			(address && (flags & MAP_FIXED))	// must use normal mmap, since the program is now guaranteed the destination address or failure
+			|| (flags & MAP_SHARED)			// we're sharing between multiple programs, which is complex enough as it is - alignment is important, and we'd have to do funky stuff to ensure non-overlappingness with this regardless
+			|| ((!flags) & MAP_ANONYMOUS)		// we're mapping a file, so the kernel needs to know the actual location
+	  ) {
+		//return orig_mmap(address, length, protect, flags, filedes, offset);
+		// don't modify the arguments - we unfortunately can't touch this much, since it's going to be mapped in a way that we can't nicely diversify (yet)
+	} else {
+		is_diversified = true;
+
+#if defined(MAP_ALIGN)
+	// gotta round up to the next barrier, but this only matters on solaris (in theory)
+	// support it as soon as it actually comes up
+#error "MAP_ALIGN IS NOT YET SUPPORTED - IF YOU RUN INTO THIS CONGRATS, YOU HAVE SURPRISED ME"
+#endif
+		// we want to allocate a bit more space - this is so that each variant gets its own part of the allocated segment, in a non-overlapping fashion
+		length = length * nnumvar;
+	}
+	// ok, now we need to actually do the call
+	if(orig_mmap == NULL) {
+		/*
+		 * NOTE: WE CANNOT DO THIS - causes deadlock, infinite loops, and unpredictability
+		 */
+		//orig_mmap = (void*(*)(void*, size_t, int, int, int, off_t)) dlsym(RTLD_NEXT, "mmap");
+		/*
+		 * The reason is that if our _init function hasn't been called yet -
+		 * which happens with surprising frequency - then the dlsym lookup
+		 * eventually goes, acquires a lock, and calls mmap. This is bad, as
+		 * that mmap call gets back here, and on the second pass, it deadlocks
+		 * on the lock.
+		 * Instead, we do essentially what the glibc mmap wrapper does here, and
+		 * hope that no one is doing something esoteric that relies on any change
+		 * in glibc's wrapper.
+		 */
+#ifndef SYSCALL_MMAP2_UNIT
+#define SYSCALL_MMAP2_UNIT 4096ULL
+#endif
+#define UNIT SYSCALL_MMAP2_UNIT
+#define OFF_MASK ((-0x2000ULL << (8*sizeof(long)-1)) | (UNIT-1))
+		if (offset & OFF_MASK) {
+			errno = EINVAL;
+			return MAP_FAILED;
+		}
+		if (length >= PTRDIFF_MAX) {
+			errno = ENOMEM;
+			return MAP_FAILED;
+		}
+#ifdef SYS_mmap2
+		new_mapping = (void*)syscall(SYS_mmap2, address, length, protect, flags, filedes, offset/UNIT);
+#else
+		new_mapping = (void*)syscall(SYS_mmap, address, length, protect, flags, filedes, offset);
+#endif
+	} else {
+		// it's actually been initialized, so use the original glibc/other mmap implementation - let's hope it plays nice with the hacky stuff above
+		new_mapping = orig_mmap(address, length, protect, flags, filedes, offset);
+	}
+	if(new_mapping == MAP_FAILED) {
+		// it failed, and if we were to retry, it would diverge anyway - just return the failure
+		return new_mapping;
+	}
+	if(is_diversified) {
+		// we got the extra memory, now return the right part
+		return new_mapping + originallength * nthisvar;
+	} else {
+		// we had to do just a normal mmap, so just return the pointer
+		return new_mapping;
+	}
+}
+/*void* mmap64(void* address, size_t length, int protect, int flags, int filedes, off64_t offset) {
+	printf("FOOBAR64\n");
+	if(orig_mmap64 == NULL) {
+		// this is only going to come up in dlsym, I think, don't worry about it too much...
+		return bad_decision_64;
+		orig_mmap64 = (void*(*)(void*, size_t, int, int, int, off64_t)) dlsym(RTLD_DEFAULT, "mmap64");
+	}
+	return orig_mmap64(address, length, protect, flags, filedes, offset);
+}*/