Index: src/tests/heap.c
===================================================================
--- src/tests/heap.c	(revision 5d4fa18bc4bff0eb87535bc141fa9ffb76a6b33d)
+++ src/tests/heap.c	(revision 5d4fa18bc4bff0eb87535bc141fa9ffb76a6b33d)
@@ -0,0 +1,342 @@
+#include <thread>
+#include <kernel>										// processor
+#include <stdlib>										// *allocs
+#include <malloc.h>										// malloc_*
+
+// #include <time>
+// #define __CFA_DEFAULT_PREEMPTION__ 1000`us
+// //#define __CFA_DEFAULT_PREEMPTION__ 0
+
+// Duration default_preemption() {
+// 	return __CFA_DEFAULT_PREEMPTION__;
+// }
+
+#define __U_DEFAULT_MMAP_START__ (512 * 1024 + 1)
+size_t default_mmap_start() __attribute__(( weak )) {
+    return __U_DEFAULT_MMAP_START__;
+} // default_mmap_start
+
+thread Worker {
+}; // Worker
+
+void main( Worker & ) {
+    enum { NoOfAllocs = 5000, NoOfMmaps = 10 };
+    char *locns[NoOfAllocs];
+    int i;
+
+    // check alloc/free
+
+    for ( int j = 0; j < 40; j += 1 ) {
+		for ( i = 0; i < NoOfAllocs; i += 1 ) {
+			locns[i] = alloc( i );
+			//sout | (void *)locns[i] | endl;
+			for ( int k = 0; k < i; k += 1 ) locns[i][k] = '\345';
+		} // for
+		//sout | (char *)sbrk(0) - start | " bytes" | endl;
+
+		for ( i = 0; i < NoOfAllocs; i += 1 ) {
+			//sout | (void *)locns[i] | endl;
+			for ( int k = 0; k < i; k += 1 ) if ( locns[i][k] != '\345' ) abort( "new/delete corrupt storage1" );
+			free( locns[i] );
+		} // for
+		//sout | (char *)sbrk(0) - start | " bytes" | endl;
+
+		for ( i = 0; i < NoOfAllocs; i += 1 ) {
+			locns[i] = alloc( i );
+			//sout | (void *)locns[i] | endl;
+			for ( int k = 0; k < i; k += 1 ) locns[i][k] = '\345';
+		} // for
+		for ( i = NoOfAllocs - 1; i >=0 ; i -= 1 ) {
+			//sout | (void *)locns[i] | endl;
+			for ( int k = 0; k < i; k += 1 ) if ( locns[i][k] != '\345' ) abort( "new/delete corrupt storage2" );
+			free( locns[i] );
+		} // for
+    } // for
+
+    // check malloc/free (sbrk)
+
+    for ( i = 0; i < NoOfAllocs; i += 1 ) {
+		size_t s = (i + 1) * 20;
+		char *area = (char *)malloc( s );
+		if ( area == 0 ) abort( "malloc/free out of memory" );
+		area[0] = '\345'; area[s - 1] = '\345';			// fill first/last
+		area[malloc_usable_size( area ) - 1] = '\345';	// fill ultimate byte
+		free( area );
+    } // for
+
+    for ( i = 0; i < NoOfAllocs; i += 1 ) {
+		size_t s = i + 1;				// +1 to make initialization simpler
+		locns[i] = (char *)malloc( s );
+		if ( locns[i] == 0 ) abort( "malloc/free out of memory" );
+		locns[i][0] = '\345'; locns[i][s - 1] = '\345';	// fill first/last
+		locns[i][malloc_usable_size( locns[i] ) - 1] = '\345'; // fill ultimate byte
+    } // for
+    for ( i = 0; i < NoOfAllocs; i += 1 ) {
+		size_t s = i + 1;
+		if ( locns[i][0] != '\345' || locns[i][s - 1] != '\345' ||
+			 locns[i][malloc_usable_size( locns[i] ) - 1] != '\345' ) abort( "malloc/free corrupt storage" );
+		free( locns[i] );
+    } // for
+
+    // check malloc/free (mmap)
+
+    for ( i = 0; i < NoOfMmaps; i += 1 ) {
+		size_t s = i + default_mmap_start();				// cross over point
+		char *area = (char *)malloc( s );
+		if ( area == 0 ) abort( "malloc/free out of memory" );
+		area[0] = '\345'; area[s - 1] = '\345';			// fill first/last
+		area[malloc_usable_size( area ) - 1] = '\345';	// fill ultimate byte
+		free( area );
+    } // for
+
+    for ( i = 0; i < NoOfMmaps; i += 1 ) {
+		size_t s = i + default_mmap_start();				// cross over point
+		locns[i] = (char *)malloc( s );
+		if ( locns[i] == 0 ) abort( "malloc/free out of memory" );
+		locns[i][0] = '\345'; locns[i][s - 1] = '\345';	// fill first/last
+		locns[i][malloc_usable_size( locns[i] ) - 1] = '\345'; // fill ultimate byte
+    } // for
+    for ( i = 0; i < NoOfMmaps; i += 1 ) {
+		size_t s = i + default_mmap_start();				// cross over point
+		if ( locns[i][0] != '\345' || locns[i][s - 1] != '\345' ||
+			 locns[i][malloc_usable_size( locns[i] ) - 1] != '\345' ) abort( "malloc/free corrupt storage" );
+		free( locns[i] );
+    } // for
+
+    // check calloc/free (sbrk)
+
+    for ( i = 0; i < NoOfAllocs; i += 1 ) {
+		size_t s = (i + 1) * 20;
+		char *area = (char *)calloc( 5, s );
+		if ( area == 0 ) abort( "calloc/free out of memory" );
+		if ( area[0] != '\0' || area[s - 1] != '\0' ||
+			 area[malloc_usable_size( area ) - 1] != '\0' ||
+			 ! malloc_zero_fill( area ) ) abort( "calloc/free corrupt storage1" );
+		area[0] = '\345'; area[s - 1] = '\345';			// fill first/last
+		area[malloc_usable_size( area ) - 1] = '\345';	// fill ultimate byte
+		free( area );
+    } // for
+
+    for ( i = 0; i < NoOfAllocs; i += 1 ) {
+		size_t s = i + 1;
+		locns[i] = (char *)calloc( 5, s );
+		if ( locns[i] == 0 ) abort( "calloc/free out of memory" );
+		if ( locns[i][0] != '\0' || locns[i][s - 1] != '\0' ||
+			 locns[i][malloc_usable_size( locns[i] ) - 1] != '\0' ||
+			 ! malloc_zero_fill( locns[i] ) ) abort( "calloc/free corrupt storage2" );
+		locns[i][0] = '\345'; locns[i][s - 1] = '\345';	// fill first/last
+		locns[i][malloc_usable_size( locns[i] ) - 1] = '\345'; // fill ultimate byte
+    } // for
+    for ( i = 0; i < NoOfAllocs; i += 1 ) {
+		size_t s = i + 1;
+		if ( locns[i][0] != '\345' || locns[i][s - 1] != '\345' ||
+			 locns[i][malloc_usable_size( locns[i] ) - 1] != '\345' ) abort( "calloc/free corrupt storage3" );
+		free( locns[i] );
+    } // for
+
+    // check calloc/free (mmap)
+
+    for ( i = 0; i < NoOfMmaps; i += 1 ) {
+		size_t s = i + default_mmap_start();				// cross over point
+		char *area = (char *)calloc( 1, s );
+		if ( area == 0 ) abort( "calloc/free out of memory" );
+		if ( area[0] != '\0' || area[s - 1] != '\0' ) abort( "calloc/free corrupt storage4.1" );
+		if ( area[malloc_usable_size( area ) - 1] != '\0' ) abort( "calloc/free corrupt storage4.2" );
+		if ( ! malloc_zero_fill( area ) ) abort( "calloc/free corrupt storage4.3" );
+		area[0] = '\345'; area[s - 1] = '\345';			// fill first/last
+		area[malloc_usable_size( area ) - 1] = '\345';	// fill ultimate byte
+		free( area );
+    } // for
+
+    for ( i = 0; i < NoOfMmaps; i += 1 ) {
+		size_t s = i + default_mmap_start();				// cross over point
+		locns[i] = (char *)calloc( 1, s );
+		if ( locns[i] == 0 ) abort( "calloc/free out of memory" );
+		if ( locns[i][0] != '\0' || locns[i][s - 1] != '\0' ||
+			 locns[i][malloc_usable_size( locns[i] ) - 1] != '\0' ||
+			 ! malloc_zero_fill( locns[i] ) ) abort( "calloc/free corrupt storage5" );
+		locns[i][0] = '\345'; locns[i][s - 1] = '\345';	// fill first/last
+		locns[i][malloc_usable_size( locns[i] ) - 1] = '\345'; // fill ultimate byte
+    } // for
+    for ( i = 0; i < NoOfMmaps; i += 1 ) {
+		size_t s = i + default_mmap_start();				// cross over point
+		if ( locns[i][0] != '\345' || locns[i][s - 1] != '\345' ||
+			 locns[i][malloc_usable_size( locns[i] ) - 1] != '\345' ) abort( "calloc/free corrupt storage6" );
+		free( locns[i] );
+    } // for
+
+    // check memalign/free (sbrk)
+
+    enum { limit = 64 * 1024 };							// check alignments up to here
+
+    for ( size_t a = libAlign(); a <= limit; a += a ) {	// generate powers of 2
+		//sout | alignments[a] | endl;
+		for ( int s = 1; s < NoOfAllocs; s += 1 ) {		// allocation of size 0 can return null
+			char *area = (char *)memalign( a, s );
+			if ( area == 0 ) abort( "memalign/free out of memory" );
+			//sout | i | " " | area | endl;
+			if ( (size_t)area % a != 0 || malloc_alignment( area ) != a ) { // check for initial alignment
+				abort( "memalign/free bad alignment : memalign(%d,%d) = %p", (int)a, s, area );
+			} // if
+			area[0] = '\345'; area[s - 1] = '\345';	// fill first/last byte
+			area[malloc_usable_size( area ) - 1] = '\345'; // fill ultimate byte
+			free( area );
+		} // for
+    } // for
+
+    // check memalign/free (mmap)
+
+    for ( size_t a = libAlign(); a <= limit; a += a ) {	// generate powers of 2
+		//sout | alignments[a] | endl;
+		for ( i = 1; i < NoOfMmaps; i += 1 ) {
+			size_t s = i + default_mmap_start();			// cross over point
+			char *area = (char *)memalign( a, s );
+			if ( area == 0 ) abort( "memalign/free out of memory" );
+			//sout | i | " " | area | endl;
+			if ( (size_t)area % a != 0 || malloc_alignment( area ) != a ) { // check for initial alignment
+				abort( "memalign/free bad alignment : memalign(%d,%d) = %p", (int)a, (int)s, area );
+			} // if
+			area[0] = '\345'; area[s - 1] = '\345';		// fill first/last byte
+			area[malloc_usable_size( area ) - 1] = '\345'; // fill ultimate byte
+			free( area );
+		} // for
+    } // for
+
+    // check calloc/realloc/free (sbrk)
+
+    for ( i = 1; i < 10000; i += 12 ) {
+		// initial N byte allocation
+		char *area = (char *)calloc( 5, i );
+		if ( area == 0 ) abort( "calloc/realloc/free out of memory" );
+		if ( area[0] != '\0' || area[i - 1] != '\0' ||
+			 area[malloc_usable_size( area ) - 1] != '\0' ||
+			 ! malloc_zero_fill( area ) ) abort( "calloc/realloc/free corrupt storage1" );
+
+		// Do not start this loop index at 0 because realloc of 0 bytes frees the storage.
+		for ( int s = i; s < 256 * 1024; s += 26 ) {	// start at initial memory request
+			area = (char *)realloc( area, s );			// attempt to reuse storage
+			if ( area == 0 ) abort( "calloc/realloc/free out of memory" );
+			if ( area[0] != '\0' || area[s - 1] != '\0' ||
+				 area[malloc_usable_size( area ) - 1] != '\0' ||
+				 ! malloc_zero_fill( area ) ) abort( "calloc/realloc/free corrupt storage2" );
+		} // for
+		free( area );
+    } // for
+
+    // check calloc/realloc/free (mmap)
+
+    for ( i = 1; i < 1000; i += 12 ) {
+		// initial N byte allocation
+		size_t s = i + default_mmap_start();				// cross over point
+		char *area = (char *)calloc( 1, s );
+		if ( area == 0 ) abort( "calloc/realloc/free out of memory" );
+		if ( area[0] != '\0' || area[s - 1] != '\0' ||
+			 area[malloc_usable_size( area ) - 1] != '\0' ||
+			 ! malloc_zero_fill( area ) ) abort( "calloc/realloc/free corrupt storage1" );
+
+		// Do not start this loop index at 0 because realloc of 0 bytes frees the storage.
+		for ( int r = i; r < 256 * 1024; r += 26 ) {	// start at initial memory request
+			area = (char *)realloc( area, r );		// attempt to reuse storage
+			if ( area == 0 ) abort( "calloc/realloc/free out of memory" );
+			if ( area[0] != '\0' || area[r - 1] != '\0' ||
+				 area[malloc_usable_size( area ) - 1] != '\0' ||
+				 ! malloc_zero_fill( area ) ) abort( "calloc/realloc/free corrupt storage2" );
+		} // for
+		free( area );
+    } // for
+
+    // check memalign/realloc/free
+
+    size_t amount = 2;
+    for ( size_t a = libAlign(); a <= limit; a += a ) {	// generate powers of 2
+		// initial N byte allocation
+		char *area = (char *)memalign( a, amount );		// aligned N-byte allocation
+		if ( area == 0 ) abort( "memalign/realloc/free out of memory" ); // no storage ?
+		//sout | alignments[a] | " " | area | endl;
+		if ( (size_t)area % a != 0 || malloc_alignment( area ) != a ) { // check for initial alignment
+			abort( "memalign/realloc/free bad alignment : memalign(%d,%d) = %p", (int)a, (int)amount, area );
+		} // if
+		area[0] = '\345'; area[amount - 2] = '\345';	// fill first/penultimate byte
+
+		// Do not start this loop index at 0 because realloc of 0 bytes frees the storage.
+		for ( int s = amount; s < 256 * 1024; s += 1 ) { // start at initial memory request
+			if ( area[0] != '\345' || area[s - 2] != '\345' ) abort( "memalign/realloc/free corrupt storage" );
+			area = (char *)realloc( area, s );			// attempt to reuse storage
+			if ( area == 0 ) abort( "memalign/realloc/free out of memory" ); // no storage ?
+			//sout | i | " " | area | endl;
+			if ( (size_t)area % a != 0 ) {				// check for initial alignment
+				abort( "memalign/realloc/free bad alignment %p", area );
+			} // if
+			area[s - 1] = '\345';						// fill last byte
+		} // for
+		free( area );
+    } // for
+
+    // check cmemalign/free
+
+    for ( size_t a = libAlign(); a <= limit; a += a ) {	// generate powers of 2
+		//sout | alignments[a] | endl;
+		for ( int s = 1; s < limit; s += 1 ) {			// allocation of size 0 can return null
+			char *area = (char *)cmemalign( a, 1, s );
+			if ( area == 0 ) abort( "cmemalign/free out of memory" );
+			//sout | i | " " | area | endl;
+			if ( (size_t)area % a != 0 || malloc_alignment( area ) != a ) { // check for initial alignment
+				abort( "cmemalign/free bad alignment : cmemalign(%d,%d) = %p", (int)a, s, area );
+			} // if
+			if ( area[0] != '\0' || area[s - 1] != '\0' ||
+				 area[malloc_usable_size( area ) - 1] != '\0' ||
+				 ! malloc_zero_fill( area ) ) abort( "cmemalign/free corrupt storage" );
+			area[0] = '\345'; area[s - 1] = '\345';		// fill first/last byte
+			free( area );
+		} // for
+    } // for
+
+    // check cmemalign/realloc/free
+
+    amount = 2;
+    for ( size_t a = libAlign() + libAlign(); a <= limit; a += a ) { // generate powers of 2
+		// initial N byte allocation
+		char *area = (char *)cmemalign( a, 1, amount );	// aligned N-byte allocation
+		if ( area == 0 ) abort( "cmemalign/realloc/free out of memory" ); // no storage ?
+		//sout | alignments[a] | " " | area | endl;
+		if ( (size_t)area % a != 0 || malloc_alignment( area ) != a ) { // check for initial alignment
+			abort( "cmemalign/realloc/free bad alignment : cmemalign(%d,%d) = %p", (int)a, (int)amount, area );
+		} // if
+		if ( area[0] != '\0' || area[amount - 1] != '\0' ||
+			 area[malloc_usable_size( area ) - 1] != '\0' ||
+			 ! malloc_zero_fill( area ) ) abort( "cmemalign/realloc/free corrupt storage1" );
+		area[0] = '\345'; area[amount - 2] = '\345';	// fill first/penultimate byte
+
+		// Do not start this loop index at 0 because realloc of 0 bytes frees the storage.
+		for ( int s = amount; s < 256 * 1024; s += 1 ) { // start at initial memory request
+			if ( area[0] != '\345' || area[s - 2] != '\345' ) abort( "cmemalign/realloc/free corrupt storage2" );
+			area = (char *)realloc( area, s );			// attempt to reuse storage
+			if ( area == 0 ) abort( "cmemalign/realloc/free out of memory" ); // no storage ?
+			//sout | i | " " | area | endl;
+			if ( (size_t)area % a != 0 || malloc_alignment( area ) != a ) { // check for initial alignment
+				abort( "cmemalign/realloc/free bad alignment %p", area );
+			} // if
+			if ( area[s - 1] != '\0' || area[s - 1] != '\0' ||
+				 area[malloc_usable_size( area ) - 1] != '\0' ||
+				 ! malloc_zero_fill( area ) ) abort( "cmemalign/realloc/free corrupt storage3" );
+			area[s - 1] = '\345';						// fill last byte
+		} // for
+		free( area );
+    } // for
+	//sout | "worker" | thisTask() | "successful completion" | endl;
+} // Worker main
+
+int main() {
+    const unsigned int NoOfWorkers = 4;
+    {
+		processor processors[NoOfWorkers - 1] __attribute__(( unused )); // more than one processor
+		Worker workers[NoOfWorkers] __attribute__(( unused ));
+    }
+	// checkFreeOn();
+    // malloc_stats();
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// compile-command: "cfa -nodebug -O2 heap.c" //
+// End: //
