/* 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 #include #include #include #include #include #include #include #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; }