• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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