Fuzztest: reduce memory usage (for AVR)
diff --git a/tests/common/malloc_wrappers.c b/tests/common/malloc_wrappers.c
index 93b9840..ad8cbdc 100644
--- a/tests/common/malloc_wrappers.c
+++ b/tests/common/malloc_wrappers.c
@@ -20,6 +20,10 @@
 #define MAX_REALLOC_SIZE 1024*1024
 #endif
 
+#ifndef DEBUG_MALLOC
+#define DEBUG_MALLOC 0
+#endif
+
 /* Allocate memory and place check values before and after. */
 void* malloc_with_check(size_t size)
 {
@@ -30,11 +34,12 @@
         ((size_t*)buf)[1] = CHECK1;
         ((size_t*)(buf + size))[2] = CHECK2;
         alloc_count++;
+        if (DEBUG_MALLOC) fprintf(stderr, "Alloc 0x%04x/%u\n", (unsigned)(uintptr_t)(buf + PREFIX_SIZE), (unsigned)size);
         return buf + PREFIX_SIZE;
     }
     else
     {
-        fprintf(stderr, "malloc(%u) failed\n", (unsigned)size);
+        if (DEBUG_MALLOC) fprintf(stderr, "malloc(%u) failed\n", (unsigned)size);
         return NULL;
     }
 }
@@ -50,6 +55,7 @@
         assert(((size_t*)(buf + size))[2] == CHECK2);
         assert(alloc_count > 0);
         alloc_count--;
+        if (DEBUG_MALLOC) fprintf(stderr, "Release 0x%04x/%u\n", (unsigned)(uintptr_t)mem, (unsigned)size);
         free(buf);
     }
 }
@@ -79,6 +85,8 @@
         ((size_t*)buf)[0] = size;
         ((size_t*)buf)[1] = CHECK1;
         ((size_t*)(buf + size))[2] = CHECK2;
+
+        if (DEBUG_MALLOC) fprintf(stderr, "Realloc 0x%04x/%u to 0x%04x/%u\n", (unsigned)(uintptr_t)ptr, (unsigned)oldsize, (unsigned)(uintptr_t)(buf + PREFIX_SIZE), (unsigned)size);
         return buf + PREFIX_SIZE;
     }
     else if (ptr && !size)
diff --git a/tests/fuzztest/SConscript b/tests/fuzztest/SConscript
index b2ae886..9a747cb 100644
--- a/tests/fuzztest/SConscript
+++ b/tests/fuzztest/SConscript
@@ -1,5 +1,6 @@
 # Run a fuzz test to verify robustness against corrupted/malicious data.
 
+import sys
 import time
 import zipfile
 import subprocess
@@ -81,9 +82,10 @@
     if env.has_key("TEST_RUNNER"):
         args = [env["TEST_RUNNER"]] + args
 
-    for filename in corpus.namelist():
-        if filename.endswith('/'):
-            continue
+    files = [n for n in corpus.namelist() if not n.endswith('/')]
+    for filename in files:
+        sys.stdout.write("Fuzzing: %5d/%5d: %-40.40s\r" % (count, len(files), filename))
+        sys.stdout.flush()
 
         count += 1
         process = subprocess.Popen(args, stdin=subprocess.PIPE,
diff --git a/tests/fuzztest/fuzztest.c b/tests/fuzztest/fuzztest.c
index e919a76..ab7824c 100644
--- a/tests/fuzztest/fuzztest.c
+++ b/tests/fuzztest/fuzztest.c
@@ -33,11 +33,26 @@
 static size_t g_bufsize = 4096;
 #endif
 
+static uint32_t xor32_checksum(const void *data, size_t len)
+{
+    const uint8_t *buf = (const uint8_t*)data;
+    uint32_t checksum = 1234;
+    while (len--)
+    {
+        checksum ^= checksum << 13;
+        checksum ^= checksum >> 17;
+        checksum ^= checksum << 5;
+        checksum += *buf++;
+    }
+    return checksum;
+}
+
 static bool do_decode(const uint8_t *buffer, size_t msglen, size_t structsize, const pb_msgdesc_t *msgtype, unsigned flags, bool assert_success)
 {
     bool status;
     pb_istream_t stream;
     size_t initial_alloc_count = get_alloc_count();
+    uint8_t *buf2 = malloc_with_check(g_bufsize); /* This is just to match the amount of memory allocations in do_roundtrips(). */
     void *msg = malloc_with_check(structsize);
     alltypes_static_TestExtension extmsg = alltypes_static_TestExtension_init_zero;
     pb_extension_t ext = pb_extension_init_zero;
@@ -72,6 +87,7 @@
 
     pb_release(msgtype, msg);
     free_with_check(msg);
+    free_with_check(buf2);
     assert(get_alloc_count() == initial_alloc_count);
     
     return status;
@@ -160,9 +176,9 @@
 static void do_roundtrip(const uint8_t *buffer, size_t msglen, size_t structsize, const pb_msgdesc_t *msgtype)
 {
     bool status;
-    uint8_t *buf2 = malloc_with_check(g_bufsize);
-    uint8_t *buf3 = malloc_with_check(g_bufsize);
+    uint32_t checksum2, checksum3;
     size_t msglen2, msglen3;
+    uint8_t *buf2 = malloc_with_check(g_bufsize);
     void *msg = malloc_with_check(structsize);
 
     /* For proto2 types, we also test extension fields */
@@ -202,11 +218,12 @@
         if (!status) fprintf(stderr, "pb_encode: %s\n", PB_GET_ERROR(&stream));
         assert(status);
         msglen2 = stream.bytes_written;
+        checksum2 = xor32_checksum(buf2, msglen2);
     }
     
     pb_release(msgtype, msg);
 
-    /* Then decode and encode again. Result should remain the same. */
+    /* Then decode from canonical format and re-encode. Result should remain the same. */
     {
         pb_istream_t stream = pb_istream_from_buffer(buf2, msglen2);
         memset(msg, 0, structsize);
@@ -219,20 +236,20 @@
     }
     
     {
-        pb_ostream_t stream = pb_ostream_from_buffer(buf3, g_bufsize);
+        pb_ostream_t stream = pb_ostream_from_buffer(buf2, g_bufsize);
         status = pb_encode(&stream, msgtype, msg);
         if (!status) fprintf(stderr, "pb_encode: %s\n", PB_GET_ERROR(&stream));
         assert(status);
         msglen3 = stream.bytes_written;
+        checksum3 = xor32_checksum(buf2, msglen3);
     }
     
     assert(msglen2 == msglen3);
-    assert(memcmp(buf2, buf3, msglen2) == 0);
+    assert(checksum2 == checksum3);
     
     pb_release(msgtype, msg);
     free_with_check(msg);
     free_with_check(buf2);
-    free_with_check(buf3);
 }
 
 void do_roundtrips(const uint8_t *data, size_t size, bool expect_valid)