aboutsummaryrefslogtreecommitdiff
path: root/tests/fuzztest/fuzzstub.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/fuzztest/fuzzstub.c')
-rw-r--r--tests/fuzztest/fuzzstub.c189
1 files changed, 189 insertions, 0 deletions
diff --git a/tests/fuzztest/fuzzstub.c b/tests/fuzztest/fuzzstub.c
new file mode 100644
index 0000000..ec9e2af
--- /dev/null
+++ b/tests/fuzztest/fuzzstub.c
@@ -0,0 +1,189 @@
+/* Fuzz testing for the nanopb core.
+ * This can be used with external fuzzers, e.g. radamsa.
+ * It performs most of the same checks as fuzztest, but does not feature data generation.
+ */
+
+#include <pb_decode.h>
+#include <pb_encode.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <time.h>
+#include <malloc_wrappers.h>
+#include "alltypes_static.pb.h"
+#include "alltypes_pointer.pb.h"
+
+#define BUFSIZE 4096
+
+static bool do_static_decode(uint8_t *buffer, size_t msglen, bool assert_success)
+{
+ pb_istream_t stream;
+ bool status;
+
+ alltypes_static_AllTypes *msg = malloc_with_check(sizeof(alltypes_static_AllTypes));
+ stream = pb_istream_from_buffer(buffer, msglen);
+ status = pb_decode(&stream, alltypes_static_AllTypes_fields, msg);
+
+ if (!status && assert_success)
+ {
+ /* Anything that was successfully encoded, should be decodeable.
+ * One exception: strings without null terminator are encoded up
+ * to end of buffer, but refused on decode because the terminator
+ * would not fit. */
+ if (strcmp(stream.errmsg, "string overflow") != 0)
+ assert(status);
+ }
+
+ free_with_check(msg);
+ return status;
+}
+
+static bool do_pointer_decode(uint8_t *buffer, size_t msglen, bool assert_success)
+{
+ pb_istream_t stream;
+ bool status;
+ 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);
+
+ assert(get_alloc_count() == 0);
+ status = pb_decode(&stream, alltypes_pointer_AllTypes_fields, msg);
+
+ if (assert_success)
+ assert(status);
+
+ pb_release(alltypes_pointer_AllTypes_fields, msg);
+ assert(get_alloc_count() == 0);
+
+ free_with_check(msg);
+
+ return status;
+}
+
+/* Do a decode -> encode -> decode -> encode roundtrip */
+static void do_static_roundtrip(uint8_t *buffer, size_t msglen)
+{
+ bool status;
+ uint8_t *buf2 = malloc_with_check(BUFSIZE);
+ uint8_t *buf3 = malloc_with_check(BUFSIZE);
+ size_t msglen2, msglen3;
+ alltypes_static_AllTypes *msg1 = malloc_with_check(sizeof(alltypes_static_AllTypes));
+ alltypes_static_AllTypes *msg2 = malloc_with_check(sizeof(alltypes_static_AllTypes));
+ memset(msg1, 0, sizeof(alltypes_static_AllTypes));
+ memset(msg2, 0, sizeof(alltypes_static_AllTypes));
+
+ {
+ pb_istream_t stream = pb_istream_from_buffer(buffer, msglen);
+ status = pb_decode(&stream, alltypes_static_AllTypes_fields, msg1);
+ assert(status);
+ }
+
+ {
+ pb_ostream_t stream = pb_ostream_from_buffer(buf2, BUFSIZE);
+ status = pb_encode(&stream, alltypes_static_AllTypes_fields, msg1);
+ assert(status);
+ msglen2 = stream.bytes_written;
+ }
+
+ {
+ pb_istream_t stream = pb_istream_from_buffer(buf2, msglen2);
+ status = pb_decode(&stream, alltypes_static_AllTypes_fields, msg2);
+ assert(status);
+ }
+
+ {
+ pb_ostream_t stream = pb_ostream_from_buffer(buf3, BUFSIZE);
+ status = pb_encode(&stream, alltypes_static_AllTypes_fields, msg2);
+ assert(status);
+ msglen3 = stream.bytes_written;
+ }
+
+ assert(msglen2 == msglen3);
+ assert(memcmp(buf2, buf3, msglen2) == 0);
+
+ free_with_check(msg1);
+ free_with_check(msg2);
+ free_with_check(buf2);
+ free_with_check(buf3);
+}
+
+/* Do decode -> encode -> decode -> encode roundtrip */
+static void do_pointer_roundtrip(uint8_t *buffer, size_t msglen)
+{
+ bool status;
+ uint8_t *buf2 = malloc_with_check(BUFSIZE);
+ uint8_t *buf3 = malloc_with_check(BUFSIZE);
+ size_t msglen2, msglen3;
+ alltypes_pointer_AllTypes *msg1 = malloc_with_check(sizeof(alltypes_pointer_AllTypes));
+ alltypes_pointer_AllTypes *msg2 = malloc_with_check(sizeof(alltypes_pointer_AllTypes));
+ memset(msg1, 0, sizeof(alltypes_pointer_AllTypes));
+ memset(msg2, 0, sizeof(alltypes_pointer_AllTypes));
+
+ {
+ pb_istream_t stream = pb_istream_from_buffer(buffer, msglen);
+ status = pb_decode(&stream, alltypes_pointer_AllTypes_fields, msg1);
+ assert(status);
+ }
+
+ {
+ pb_ostream_t stream = pb_ostream_from_buffer(buf2, BUFSIZE);
+ status = pb_encode(&stream, alltypes_pointer_AllTypes_fields, msg1);
+ assert(status);
+ msglen2 = stream.bytes_written;
+ }
+
+ {
+ pb_istream_t stream = pb_istream_from_buffer(buf2, msglen2);
+ status = pb_decode(&stream, alltypes_pointer_AllTypes_fields, msg2);
+ assert(status);
+ }
+
+ {
+ pb_ostream_t stream = pb_ostream_from_buffer(buf3, BUFSIZE);
+ status = pb_encode(&stream, alltypes_pointer_AllTypes_fields, msg2);
+ assert(status);
+ msglen3 = stream.bytes_written;
+ }
+
+ assert(msglen2 == msglen3);
+ assert(memcmp(buf2, buf3, msglen2) == 0);
+
+ pb_release(alltypes_pointer_AllTypes_fields, msg1);
+ pb_release(alltypes_pointer_AllTypes_fields, msg2);
+ free_with_check(msg1);
+ free_with_check(msg2);
+ free_with_check(buf2);
+ free_with_check(buf3);
+}
+
+static void run_iteration()
+{
+ uint8_t *buffer = malloc_with_check(BUFSIZE);
+ size_t msglen;
+ bool status;
+
+ msglen = fread(buffer, 1, 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)
+{
+ run_iteration();
+
+ return 0;
+}
+