Build separate fuzzer test cases.
diff --git a/tests/fuzztest/SConscript b/tests/fuzztest/SConscript
index 62fb91d..e98f877 100644
--- a/tests/fuzztest/SConscript
+++ b/tests/fuzztest/SConscript
@@ -122,3 +122,48 @@
     print('\033[32m[ OK ]\033[0m   Ran ' + str(args) + " against " + str(source[1]) + " (" + str(count) + " entries)")
 
 env.Command("corpus.zip.fuzzed", [fuzz, "corpus.zip"], run_against_corpus)
+
+# Build separate fuzzers for each test case.
+# Having them separate speeds up control flow based fuzzer engines.
+# These are mainly used by oss-fuzz project.
+common_objs = ["random_data.o",
+                "validation.o",
+                "flakystream.o",
+                "alltypes_pointer.pb.o",
+                "alltypes_static.pb.o",
+                "alltypes_callback.pb.o",
+                "alltypes_proto3_pointer.pb.o",
+                "alltypes_proto3_static.pb.o",
+                "$COMMON/malloc_wrappers.o"]
+objs_malloc = ["$COMMON/pb_encode_with_malloc.o",
+               "$COMMON/pb_decode_with_malloc.o",
+               "$COMMON/pb_common_with_malloc.o"] + common_objs
+objs_static = ["$COMMON/pb_encode.o",
+               "$COMMON/pb_decode.o",
+               "$COMMON/pb_common.o"] + common_objs
+
+env_proto2_static = env.Clone()
+env_proto2_static.Append(CPPDEFINES = {'FUZZTEST_PROTO2_STATIC': '1'})
+env_proto2_static.Program("fuzztest_proto2_static",
+    [env_proto2_static.Object("fuzztest_proto2_static.o", "fuzztest.c")] + objs_static)
+
+env_proto2_pointer = malloc_env.Clone()
+env_proto2_pointer.Append(CPPDEFINES = {'FUZZTEST_PROTO2_POINTER': '1'})
+env_proto2_pointer.Program("fuzztest_proto2_pointer",
+    [env_proto2_pointer.Object("fuzztest_proto2_pointer.o", "fuzztest.c")] + objs_malloc)
+
+env_proto3_static = env.Clone()
+env_proto3_static.Append(CPPDEFINES = {'FUZZTEST_PROTO3_STATIC': '1'})
+env_proto3_static.Program("fuzztest_proto3_static",
+    [env_proto3_static.Object("fuzztest_proto3_static.o", "fuzztest.c")] + objs_static)
+
+env_proto3_pointer = malloc_env.Clone()
+env_proto3_pointer.Append(CPPDEFINES = {'FUZZTEST_PROTO3_POINTER': '1'})
+env_proto3_pointer.Program("fuzztest_proto3_pointer",
+    [env_proto3_pointer.Object("fuzztest_proto3_pointer.o", "fuzztest.c")] + objs_malloc)
+
+env_io_errors = malloc_env.Clone()
+env_io_errors.Append(CPPDEFINES = {'FUZZTEST_IO_ERRORS': '1'})
+env_io_errors.Program("fuzztest_io_errors",
+    [env_io_errors.Object("fuzztest_io_errors.o", "fuzztest.c")] + objs_malloc)
+
diff --git a/tests/fuzztest/fuzztest.c b/tests/fuzztest/fuzztest.c
index bb8f606..f4eff7d 100644
--- a/tests/fuzztest/fuzztest.c
+++ b/tests/fuzztest/fuzztest.c
@@ -151,7 +151,7 @@
     return true;
 }
 
-static bool do_callback_decode(const uint8_t *buffer, size_t msglen, bool assert_success)
+bool do_callback_decode(const uint8_t *buffer, size_t msglen, bool assert_success)
 {
     bool status;
     pb_istream_t stream;
@@ -188,7 +188,7 @@
 }
 
 /* Do a decode -> encode -> decode -> encode roundtrip */
-static void do_roundtrip(const uint8_t *buffer, size_t msglen, size_t structsize, const pb_msgdesc_t *msgtype)
+void do_roundtrip(const uint8_t *buffer, size_t msglen, size_t structsize, const pb_msgdesc_t *msgtype)
 {
     bool status;
     uint32_t checksum2, checksum3;
@@ -280,7 +280,6 @@
 void do_roundtrips(const uint8_t *data, size_t size, bool expect_valid)
 {
     size_t initial_alloc_count = get_alloc_count();
-    size_t orig_max_alloc_bytes = get_max_alloc_bytes();
 
 #ifdef FUZZTEST_PROTO2_STATIC
     if (do_decode(data, size, sizeof(alltypes_static_AllTypes), alltypes_static_AllTypes_fields, 0, expect_valid))
@@ -316,11 +315,14 @@
 #endif
 
 #ifdef FUZZTEST_IO_ERRORS
-    /* Test decoding when memory size is limited */
-    set_max_alloc_bytes(get_alloc_bytes() + 1024);
-    do_decode(data, size, sizeof(alltypes_pointer_AllTypes), alltypes_pointer_AllTypes_fields, 0, false);
-    do_decode(data, size, sizeof(alltypes_proto3_pointer_AllTypes), alltypes_proto3_pointer_AllTypes_fields, 0, false);
-    set_max_alloc_bytes(orig_max_alloc_bytes);
+    {
+        size_t orig_max_alloc_bytes = get_max_alloc_bytes();
+        /* Test decoding when memory size is limited */
+        set_max_alloc_bytes(get_alloc_bytes() + 1024);
+        do_decode(data, size, sizeof(alltypes_pointer_AllTypes), alltypes_pointer_AllTypes_fields, 0, false);
+        do_decode(data, size, sizeof(alltypes_proto3_pointer_AllTypes), alltypes_proto3_pointer_AllTypes_fields, 0, false);
+        set_max_alloc_bytes(orig_max_alloc_bytes);
+    }
 
     /* Test decoding on a failing stream */
     do_stream_decode(data, size, size - 16, sizeof(alltypes_static_AllTypes), alltypes_static_AllTypes_fields, false);