Include proto3 messages in fuzztest.
diff --git a/tests/alltypes_proto3/alltypes.proto b/tests/alltypes_proto3/alltypes.proto
index a0fdde5..c7f87ba 100644
--- a/tests/alltypes_proto3/alltypes.proto
+++ b/tests/alltypes_proto3/alltypes.proto
@@ -86,8 +86,8 @@
oneof oneof
{
- SubMessage oneof_msg1 = 59;
- EmptyMessage oneof_msg2 = 60;
+ SubMessage oneof_msg1 = 60;
+ EmptyMessage oneof_msg2 = 61;
}
// Check that extreme integer values are handled correctly
diff --git a/tests/fuzztest/SConscript b/tests/fuzztest/SConscript
index 7723d99..02529b4 100644
--- a/tests/fuzztest/SConscript
+++ b/tests/fuzztest/SConscript
@@ -20,9 +20,21 @@
p1 = env.NanopbProto(["alltypes_pointer", "alltypes_pointer.options"])
p2 = env.NanopbProto(["alltypes_static", "alltypes_static.options"])
+
+# Do the same for proto3 versions
+env.Command("alltypes_proto3_static.proto", "#alltypes_proto3/alltypes.proto",
+ lambda target, source, env: set_pkgname(source[0], target[0], 'alltypes_proto3_static'))
+env.Command("alltypes_proto3_pointer.proto", "#alltypes_proto3/alltypes.proto",
+ lambda target, source, env: set_pkgname(source[0], target[0], 'alltypes_proto3_pointer'))
+
+p1 = env.NanopbProto(["alltypes_proto3_pointer", "alltypes_proto3_pointer.options"])
+p2 = env.NanopbProto(["alltypes_proto3_static", "alltypes_proto3_static.options"])
+
fuzz = malloc_env.Program(["fuzztest.c",
"alltypes_pointer.pb.c",
"alltypes_static.pb.c",
+ "alltypes_proto3_pointer.pb.c",
+ "alltypes_proto3_static.pb.c",
"$COMMON/pb_encode_with_malloc.o",
"$COMMON/pb_decode_with_malloc.o",
"$COMMON/pb_common_with_malloc.o",
diff --git a/tests/fuzztest/alltypes_proto3_pointer.options b/tests/fuzztest/alltypes_proto3_pointer.options
new file mode 100644
index 0000000..e495787
--- /dev/null
+++ b/tests/fuzztest/alltypes_proto3_pointer.options
@@ -0,0 +1,3 @@
+* type:FT_POINTER
+*.*fbytes fixed_length:true max_size:4
+*.req_limits proto3_singular_msgs:true
diff --git a/tests/fuzztest/alltypes_proto3_static.options b/tests/fuzztest/alltypes_proto3_static.options
new file mode 100644
index 0000000..b90eb38
--- /dev/null
+++ b/tests/fuzztest/alltypes_proto3_static.options
@@ -0,0 +1,4 @@
+* max_size:32
+* max_count:8
+*.*fbytes fixed_length:true max_size:4
+*.req_limits proto3_singular_msgs:true
diff --git a/tests/fuzztest/fuzztest.c b/tests/fuzztest/fuzztest.c
index 0e06469..e82fd57 100644
--- a/tests/fuzztest/fuzztest.c
+++ b/tests/fuzztest/fuzztest.c
@@ -12,6 +12,8 @@
#include "test_helpers.h"
#include "alltypes_static.pb.h"
#include "alltypes_pointer.pb.h"
+#include "alltypes_proto3_static.pb.h"
+#include "alltypes_proto3_pointer.pb.h"
/* Longer buffer size allows hitting more branches, but lowers performance. */
#ifdef __AVR__
@@ -260,99 +262,160 @@
static bool do_static_decode(const uint8_t *buffer, size_t msglen, bool assert_success)
{
pb_istream_t stream;
- bool status;
+ bool status_proto2, status_proto3;
- alltypes_static_AllTypes *msg = malloc_with_check(sizeof(alltypes_static_AllTypes));
+ {
+ alltypes_static_AllTypes *msg = malloc_with_check(sizeof(alltypes_static_AllTypes));
#ifdef LLVMFUZZER
- memset(msg, 0xAA, sizeof(alltypes_static_AllTypes));
+ memset(msg, 0xAA, sizeof(alltypes_static_AllTypes));
#else
- rand_fill((uint8_t*)msg, sizeof(alltypes_static_AllTypes));
+ rand_fill((uint8_t*)msg, sizeof(alltypes_static_AllTypes));
#endif
- stream = pb_istream_from_buffer(buffer, msglen);
- status = pb_decode(&stream, alltypes_static_AllTypes_fields, msg);
+ stream = pb_istream_from_buffer(buffer, msglen);
+ status_proto2 = pb_decode(&stream, alltypes_static_AllTypes_fields, msg);
- if (status)
- {
- sanity_check_static(msg);
+ if (status_proto2)
+ {
+ sanity_check_static(msg);
+ }
+
+ if (assert_success)
+ {
+ if (!status_proto2) fprintf(stderr, "pb_decode: %s\n", PB_GET_ERROR(&stream));
+ assert(status_proto2);
+ }
+
+ free_with_check(msg);
}
- if (assert_success)
{
- if (!status) fprintf(stderr, "pb_decode: %s\n", PB_GET_ERROR(&stream));
- assert(status);
+ alltypes_proto3_static_AllTypes *msg = malloc_with_check(sizeof(alltypes_proto3_static_AllTypes));
+#ifdef LLVMFUZZER
+ memset(msg, 0xAA, sizeof(alltypes_proto3_static_AllTypes));
+#else
+ rand_fill((uint8_t*)msg, sizeof(alltypes_proto3_static_AllTypes));
+#endif
+ stream = pb_istream_from_buffer(buffer, msglen);
+ status_proto3 = pb_decode(&stream, alltypes_proto3_static_AllTypes_fields, msg);
+
+ if (status_proto2)
+ {
+ /* Anything decodeable as the proto2 message should be decodeable as proto3 also */
+ if (!status_proto3) fprintf(stderr, "pb_decode: %s\n", PB_GET_ERROR(&stream));
+ assert(status_proto3);
+ }
+
+ free_with_check(msg);
}
- free_with_check(msg);
- return status;
+ return status_proto2;
}
static bool do_pointer_decode(const uint8_t *buffer, size_t msglen, bool assert_success)
{
pb_istream_t stream;
- bool status;
+ bool status_proto2, status_proto3;
size_t initial_alloc_count;
- alltypes_pointer_AllTypes *msg;
- msg = malloc_with_check(sizeof(alltypes_pointer_AllTypes));
- memset(msg, 0, sizeof(alltypes_pointer_AllTypes));
- stream = pb_istream_from_buffer(buffer, msglen);
-
- initial_alloc_count = get_alloc_count();
- status = pb_decode(&stream, alltypes_pointer_AllTypes_fields, msg);
-
- if (assert_success)
{
- if (!status) fprintf(stderr, "pb_decode: %s\n", PB_GET_ERROR(&stream));
- assert(status);
- }
-
- pb_release(alltypes_pointer_AllTypes_fields, msg);
- assert(get_alloc_count() == initial_alloc_count);
-
- free_with_check(msg);
+ /* For proto2 syntax message */
+ alltypes_pointer_AllTypes *msg;
- return status;
+ msg = malloc_with_check(sizeof(alltypes_pointer_AllTypes));
+ memset(msg, 0, sizeof(alltypes_pointer_AllTypes));
+ stream = pb_istream_from_buffer(buffer, msglen);
+
+ initial_alloc_count = get_alloc_count();
+ status_proto2 = pb_decode(&stream, alltypes_pointer_AllTypes_fields, msg);
+
+ if (assert_success)
+ {
+ if (!status_proto2) fprintf(stderr, "pb_decode: %s\n", PB_GET_ERROR(&stream));
+ assert(status_proto2);
+ }
+
+ pb_release(alltypes_pointer_AllTypes_fields, msg);
+ assert(get_alloc_count() == initial_alloc_count);
+
+ free_with_check(msg);
+ }
+
+ {
+ /* For proto3 syntax message */
+ alltypes_proto3_pointer_AllTypes *msg;
+
+ msg = malloc_with_check(sizeof(alltypes_proto3_pointer_AllTypes));
+ memset(msg, 0, sizeof(alltypes_proto3_pointer_AllTypes));
+ stream = pb_istream_from_buffer(buffer, msglen);
+
+ initial_alloc_count = get_alloc_count();
+ status_proto3 = pb_decode(&stream, alltypes_proto3_pointer_AllTypes_fields, msg);
+
+ if (status_proto2)
+ {
+ /* Anything decodeable as the proto2 message should be decodeable as proto3 also */
+ if (!status_proto3) fprintf(stderr, "pb_decode: %s\n", PB_GET_ERROR(&stream));
+ assert(status_proto3);
+ }
+
+ pb_release(alltypes_proto3_pointer_AllTypes_fields, msg);
+ assert(get_alloc_count() == initial_alloc_count);
+
+ free_with_check(msg);
+ }
+
+ return status_proto2;
}
/* Do a decode -> encode -> decode -> encode roundtrip */
-static void do_static_roundtrip(const uint8_t *buffer, size_t msglen)
+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);
size_t msglen2, msglen3;
- alltypes_static_AllTypes *msg = malloc_with_check(sizeof(alltypes_static_AllTypes));
+ void *msg = malloc_with_check(structsize);
{
pb_istream_t stream = pb_istream_from_buffer(buffer, msglen);
- memset(msg, 0, sizeof(alltypes_static_AllTypes));
- status = pb_decode(&stream, alltypes_static_AllTypes_fields, msg);
- if (!status) fprintf(stderr, "srt1 pb_decode: %s\n", PB_GET_ERROR(&stream));
+ memset(msg, 0, structsize);
+ status = pb_decode(&stream, msgtype, msg);
+ if (!status) fprintf(stderr, "pb_decode: %s\n", PB_GET_ERROR(&stream));
assert(status);
- sanity_check_static(msg);
+
+ if (msgtype == alltypes_static_AllTypes_fields)
+ {
+ sanity_check_static(msg);
+ }
}
{
pb_ostream_t stream = pb_ostream_from_buffer(buf2, g_bufsize);
- status = pb_encode(&stream, alltypes_static_AllTypes_fields, msg);
- if (!status) fprintf(stderr, "srt2 pb_encode: %s\n", PB_GET_ERROR(&stream));
+ status = pb_encode(&stream, msgtype, msg);
+ if (!status) fprintf(stderr, "pb_encode: %s\n", PB_GET_ERROR(&stream));
assert(status);
msglen2 = stream.bytes_written;
}
+ pb_release(msgtype, msg);
+
{
pb_istream_t stream = pb_istream_from_buffer(buf2, msglen2);
- memset(msg, 0, sizeof(alltypes_static_AllTypes));
- status = pb_decode(&stream, alltypes_static_AllTypes_fields, msg);
- if (!status) fprintf(stderr, "srt3 pb_decode: %s\n", PB_GET_ERROR(&stream));
+ memset(msg, 0, structsize);
+ status = pb_decode(&stream, msgtype, msg);
+ if (!status) fprintf(stderr, "pb_decode: %s\n", PB_GET_ERROR(&stream));
assert(status);
- sanity_check_static(msg);
+
+ if (msgtype == alltypes_static_AllTypes_fields)
+ {
+ sanity_check_static(msg);
+ }
}
{
pb_ostream_t stream = pb_ostream_from_buffer(buf3, g_bufsize);
- status = pb_encode(&stream, alltypes_static_AllTypes_fields, msg);
- if (!status) fprintf(stderr, "srt4 pb_decode: %s\n", PB_GET_ERROR(&stream));
+ status = pb_encode(&stream, msgtype, msg);
+ if (!status) fprintf(stderr, "pb_encode: %s\n", PB_GET_ERROR(&stream));
assert(status);
msglen3 = stream.bytes_written;
}
@@ -360,65 +423,13 @@
assert(msglen2 == msglen3);
assert(memcmp(buf2, buf3, msglen2) == 0);
+ pb_release(msgtype, msg);
free_with_check(msg);
free_with_check(buf2);
free_with_check(buf3);
}
-/* Do decode -> encode -> decode -> encode roundtrip */
-static void do_pointer_roundtrip(const uint8_t *buffer, size_t msglen)
-{
- bool status;
- uint8_t *buf2 = malloc_with_check(g_bufsize);
- uint8_t *buf3 = malloc_with_check(g_bufsize);
- size_t msglen2, msglen3;
- alltypes_pointer_AllTypes *msg = malloc_with_check(sizeof(alltypes_pointer_AllTypes));
-
- {
- pb_istream_t stream = pb_istream_from_buffer(buffer, msglen);
- memset(msg, 0, sizeof(alltypes_pointer_AllTypes));
- status = pb_decode(&stream, alltypes_pointer_AllTypes_fields, msg);
- if (!status) fprintf(stderr, "prt1 pb_decode: %s\n", PB_GET_ERROR(&stream));
- assert(status);
- }
-
- {
- pb_ostream_t stream = pb_ostream_from_buffer(buf2, g_bufsize);
- status = pb_encode(&stream, alltypes_pointer_AllTypes_fields, msg);
- if (!status) fprintf(stderr, "prt2 pb_encode: %s\n", PB_GET_ERROR(&stream));
- assert(status);
- msglen2 = stream.bytes_written;
- }
-
- pb_release(alltypes_pointer_AllTypes_fields, msg);
-
- {
- pb_istream_t stream = pb_istream_from_buffer(buf2, msglen2);
- memset(msg, 0, sizeof(alltypes_pointer_AllTypes));
- status = pb_decode(&stream, alltypes_pointer_AllTypes_fields, msg);
- if (!status) fprintf(stderr, "prt3 pb_decode: %s\n", PB_GET_ERROR(&stream));
- assert(status);
- }
-
- {
- pb_ostream_t stream = pb_ostream_from_buffer(buf3, g_bufsize);
- status = pb_encode(&stream, alltypes_pointer_AllTypes_fields, msg);
- if (!status) fprintf(stderr, "prt4 pb_encode: %s\n", PB_GET_ERROR(&stream));
- assert(status);
- msglen3 = stream.bytes_written;
- }
-
- assert(msglen2 == msglen3);
- assert(memcmp(buf2, buf3, msglen2) == 0);
-
- pb_release(alltypes_pointer_AllTypes_fields, msg);
- free_with_check(msg);
- free_with_check(buf2);
- free_with_check(buf3);
-}
-
-#ifdef LLVMFUZZER
-
+/* Fuzzer stub for Google OSSFuzz integration */
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
g_bufsize = 65536;
@@ -427,16 +438,23 @@
return 0;
if (do_static_decode(data, size, false))
- do_static_roundtrip(data, size);
+ {
+ do_roundtrip(data, size, sizeof(alltypes_static_AllTypes), alltypes_static_AllTypes_fields);
+ do_roundtrip(data, size, sizeof(alltypes_proto3_static_AllTypes), alltypes_proto3_static_AllTypes_fields);
+ }
if (do_pointer_decode(data, size, false))
- do_pointer_roundtrip(data, size);
+ {
+ do_roundtrip(data, size, sizeof(alltypes_pointer_AllTypes), alltypes_pointer_AllTypes_fields);
+ do_roundtrip(data, size, sizeof(alltypes_proto3_pointer_AllTypes), alltypes_proto3_pointer_AllTypes_fields);
+ }
return 0;
}
-#else
+#ifndef LLVMFUZZER
+/* Stand-alone fuzzer iteration, generates random data itself */
static void run_iteration()
{
uint8_t *buffer = malloc_with_check(g_bufsize);
@@ -452,12 +470,18 @@
status = do_static_decode(buffer, msglen, true);
if (status)
- do_static_roundtrip(buffer, msglen);
+ {
+ do_roundtrip(buffer, msglen, sizeof(alltypes_static_AllTypes), alltypes_static_AllTypes_fields);
+ do_roundtrip(buffer, msglen, sizeof(alltypes_proto3_static_AllTypes), alltypes_proto3_static_AllTypes_fields);
+ }
status = do_pointer_decode(buffer, msglen, true);
if (status)
- do_pointer_roundtrip(buffer, msglen);
+ {
+ do_roundtrip(buffer, msglen, sizeof(alltypes_pointer_AllTypes), alltypes_pointer_AllTypes_fields);
+ do_roundtrip(buffer, msglen, sizeof(alltypes_proto3_pointer_AllTypes), alltypes_proto3_pointer_AllTypes_fields);
+ }
/* Apply randomness to the encoded data */
while (rand_bool())
@@ -472,8 +496,10 @@
if (status)
{
- do_static_roundtrip(buffer, msglen);
- do_pointer_roundtrip(buffer, msglen);
+ do_roundtrip(buffer, msglen, sizeof(alltypes_static_AllTypes), alltypes_static_AllTypes_fields);
+ do_roundtrip(buffer, msglen, sizeof(alltypes_proto3_static_AllTypes), alltypes_proto3_static_AllTypes_fields);
+ do_roundtrip(buffer, msglen, sizeof(alltypes_pointer_AllTypes), alltypes_pointer_AllTypes_fields);
+ do_roundtrip(buffer, msglen, sizeof(alltypes_proto3_pointer_AllTypes), alltypes_proto3_pointer_AllTypes_fields);
}
}
@@ -481,28 +507,6 @@
assert(get_alloc_count() == 0);
}
-static void run_stub()
-{
- uint8_t *buffer = malloc_with_check(g_bufsize);
- size_t msglen;
- bool status;
-
- SET_BINARY_MODE(stdin);
- msglen = fread(buffer, 1, g_bufsize, stdin);
-
- status = do_static_decode(buffer, msglen, false);
-
- if (status)
- do_static_roundtrip(buffer, msglen);
-
- status = do_pointer_decode(buffer, msglen, false);
-
- if (status)
- do_pointer_roundtrip(buffer, msglen);
-
- free_with_check(buffer);
-}
-
int main(int argc, char **argv)
{
int i;
@@ -523,10 +527,20 @@
else
{
/* Run as a stub for afl-fuzz and similar */
+ uint8_t *buffer;
+ size_t msglen;
+
#ifndef __AVR__
g_bufsize = 65536;
#endif
- run_stub();
+
+ buffer = malloc_with_check(g_bufsize);
+
+ SET_BINARY_MODE(stdin);
+ msglen = fread(buffer, 1, g_bufsize, stdin);
+ LLVMFuzzerTestOneInput(buffer, msglen);
+
+ free_with_check(buffer);
}
return 0;