1 /* Fuzz testing for the nanopb core.
2 * This can be used with external fuzzers, e.g. radamsa.
3 * It performs most of the same checks as fuzztest, but does not feature data generation.
4 */
5
6 #include <pb_decode.h>
7 #include <pb_encode.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <assert.h>
12 #include <time.h>
13 #include <malloc_wrappers.h>
14 #include "alltypes_static.pb.h"
15 #include "alltypes_pointer.pb.h"
16
17 #define BUFSIZE 4096
18
do_static_decode(uint8_t * buffer,size_t msglen,bool assert_success)19 static bool do_static_decode(uint8_t *buffer, size_t msglen, bool assert_success)
20 {
21 pb_istream_t stream;
22 bool status;
23
24 alltypes_static_AllTypes *msg = malloc_with_check(sizeof(alltypes_static_AllTypes));
25 stream = pb_istream_from_buffer(buffer, msglen);
26 status = pb_decode(&stream, alltypes_static_AllTypes_fields, msg);
27
28 if (!status && assert_success)
29 {
30 /* Anything that was successfully encoded, should be decodeable.
31 * One exception: strings without null terminator are encoded up
32 * to end of buffer, but refused on decode because the terminator
33 * would not fit. */
34 if (strcmp(stream.errmsg, "string overflow") != 0)
35 assert(status);
36 }
37
38 free_with_check(msg);
39 return status;
40 }
41
do_pointer_decode(uint8_t * buffer,size_t msglen,bool assert_success)42 static bool do_pointer_decode(uint8_t *buffer, size_t msglen, bool assert_success)
43 {
44 pb_istream_t stream;
45 bool status;
46 alltypes_pointer_AllTypes *msg;
47
48 msg = malloc_with_check(sizeof(alltypes_pointer_AllTypes));
49 memset(msg, 0, sizeof(alltypes_pointer_AllTypes));
50 stream = pb_istream_from_buffer(buffer, msglen);
51
52 assert(get_alloc_count() == 0);
53 status = pb_decode(&stream, alltypes_pointer_AllTypes_fields, msg);
54
55 if (assert_success)
56 assert(status);
57
58 pb_release(alltypes_pointer_AllTypes_fields, msg);
59 assert(get_alloc_count() == 0);
60
61 free_with_check(msg);
62
63 return status;
64 }
65
66 /* Do a decode -> encode -> decode -> encode roundtrip */
do_static_roundtrip(uint8_t * buffer,size_t msglen)67 static void do_static_roundtrip(uint8_t *buffer, size_t msglen)
68 {
69 bool status;
70 uint8_t *buf2 = malloc_with_check(BUFSIZE);
71 uint8_t *buf3 = malloc_with_check(BUFSIZE);
72 size_t msglen2, msglen3;
73 alltypes_static_AllTypes *msg1 = malloc_with_check(sizeof(alltypes_static_AllTypes));
74 alltypes_static_AllTypes *msg2 = malloc_with_check(sizeof(alltypes_static_AllTypes));
75 memset(msg1, 0, sizeof(alltypes_static_AllTypes));
76 memset(msg2, 0, sizeof(alltypes_static_AllTypes));
77
78 {
79 pb_istream_t stream = pb_istream_from_buffer(buffer, msglen);
80 status = pb_decode(&stream, alltypes_static_AllTypes_fields, msg1);
81 assert(status);
82 }
83
84 {
85 pb_ostream_t stream = pb_ostream_from_buffer(buf2, BUFSIZE);
86 status = pb_encode(&stream, alltypes_static_AllTypes_fields, msg1);
87 assert(status);
88 msglen2 = stream.bytes_written;
89 }
90
91 {
92 pb_istream_t stream = pb_istream_from_buffer(buf2, msglen2);
93 status = pb_decode(&stream, alltypes_static_AllTypes_fields, msg2);
94 assert(status);
95 }
96
97 {
98 pb_ostream_t stream = pb_ostream_from_buffer(buf3, BUFSIZE);
99 status = pb_encode(&stream, alltypes_static_AllTypes_fields, msg2);
100 assert(status);
101 msglen3 = stream.bytes_written;
102 }
103
104 assert(msglen2 == msglen3);
105 assert(memcmp(buf2, buf3, msglen2) == 0);
106
107 free_with_check(msg1);
108 free_with_check(msg2);
109 free_with_check(buf2);
110 free_with_check(buf3);
111 }
112
113 /* Do decode -> encode -> decode -> encode roundtrip */
do_pointer_roundtrip(uint8_t * buffer,size_t msglen)114 static void do_pointer_roundtrip(uint8_t *buffer, size_t msglen)
115 {
116 bool status;
117 uint8_t *buf2 = malloc_with_check(BUFSIZE);
118 uint8_t *buf3 = malloc_with_check(BUFSIZE);
119 size_t msglen2, msglen3;
120 alltypes_pointer_AllTypes *msg1 = malloc_with_check(sizeof(alltypes_pointer_AllTypes));
121 alltypes_pointer_AllTypes *msg2 = malloc_with_check(sizeof(alltypes_pointer_AllTypes));
122 memset(msg1, 0, sizeof(alltypes_pointer_AllTypes));
123 memset(msg2, 0, sizeof(alltypes_pointer_AllTypes));
124
125 {
126 pb_istream_t stream = pb_istream_from_buffer(buffer, msglen);
127 status = pb_decode(&stream, alltypes_pointer_AllTypes_fields, msg1);
128 assert(status);
129 }
130
131 {
132 pb_ostream_t stream = pb_ostream_from_buffer(buf2, BUFSIZE);
133 status = pb_encode(&stream, alltypes_pointer_AllTypes_fields, msg1);
134 assert(status);
135 msglen2 = stream.bytes_written;
136 }
137
138 {
139 pb_istream_t stream = pb_istream_from_buffer(buf2, msglen2);
140 status = pb_decode(&stream, alltypes_pointer_AllTypes_fields, msg2);
141 assert(status);
142 }
143
144 {
145 pb_ostream_t stream = pb_ostream_from_buffer(buf3, BUFSIZE);
146 status = pb_encode(&stream, alltypes_pointer_AllTypes_fields, msg2);
147 assert(status);
148 msglen3 = stream.bytes_written;
149 }
150
151 assert(msglen2 == msglen3);
152 assert(memcmp(buf2, buf3, msglen2) == 0);
153
154 pb_release(alltypes_pointer_AllTypes_fields, msg1);
155 pb_release(alltypes_pointer_AllTypes_fields, msg2);
156 free_with_check(msg1);
157 free_with_check(msg2);
158 free_with_check(buf2);
159 free_with_check(buf3);
160 }
161
run_iteration()162 static void run_iteration()
163 {
164 uint8_t *buffer = malloc_with_check(BUFSIZE);
165 size_t msglen;
166 bool status;
167
168 msglen = fread(buffer, 1, BUFSIZE, stdin);
169
170 status = do_static_decode(buffer, msglen, false);
171
172 if (status)
173 do_static_roundtrip(buffer, msglen);
174
175 status = do_pointer_decode(buffer, msglen, false);
176
177 if (status)
178 do_pointer_roundtrip(buffer, msglen);
179
180 free_with_check(buffer);
181 }
182
main(int argc,char ** argv)183 int main(int argc, char **argv)
184 {
185 run_iteration();
186
187 return 0;
188 }
189
190