Add a fuzz testing stub for ability to use external generators also
This commit is contained in:
@@ -47,4 +47,12 @@ Depends([p1, p2, fuzz], ["fuzz_syshdr.h", "malloc_wrappers.h"])
|
||||
|
||||
env.RunTest(fuzz)
|
||||
|
||||
fuzzstub = env.Program(["fuzzstub.c",
|
||||
"alltypes_pointer.pb.c",
|
||||
"alltypes_static.pb.c",
|
||||
"pb_encode_with_malloc.o",
|
||||
"pb_decode_with_malloc.o",
|
||||
"pb_common_with_malloc.o",
|
||||
"malloc_wrappers.c"])
|
||||
|
||||
|
||||
|
||||
189
tests/fuzztest/fuzzstub.c
Normal file
189
tests/fuzztest/fuzzstub.c
Normal file
@@ -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, BUFSIZE, 1, 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;
|
||||
}
|
||||
|
||||
12
tests/fuzztest/run_radamsa.sh
Executable file
12
tests/fuzztest/run_radamsa.sh
Executable file
@@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
|
||||
TMP=`tempfile`
|
||||
|
||||
echo $TMP
|
||||
while true
|
||||
do
|
||||
radamsa sample_data/* > $TMP
|
||||
$1 < $TMP
|
||||
test $? -gt 127 && break
|
||||
done
|
||||
|
||||
BIN
tests/fuzztest/sample_data/sample1.pb
Normal file
BIN
tests/fuzztest/sample_data/sample1.pb
Normal file
Binary file not shown.
BIN
tests/fuzztest/sample_data/sample2.pb
Normal file
BIN
tests/fuzztest/sample_data/sample2.pb
Normal file
Binary file not shown.
Reference in New Issue
Block a user