Line data Source code
1 : #include "fd_types_harness.h"
2 : #include "../../../types/fd_types_yaml.h"
3 : #include "../../../types/fd_types_reflect.h"
4 : #include <ctype.h>
5 :
6 : #include "generated/type.pb.h"
7 :
8 : struct CustomerSerializer {
9 : void * file;
10 : };
11 : typedef struct CustomerSerializer CustomerSerializer;
12 :
13 : static void
14 : custom_serializer_walk( void * _self,
15 : void const * arg,
16 : char const * name,
17 : int type,
18 : char const * type_name,
19 : uint level,
20 0 : uint varint ) {
21 0 : (void)name;
22 0 : (void)type;
23 0 : (void)type_name;
24 0 : (void)level;
25 :
26 0 : CustomerSerializer * self = (CustomerSerializer *)_self;
27 0 : FILE * file = self->file;
28 :
29 0 : switch( type ) {
30 0 : case FD_FLAMENCO_TYPE_MAP:
31 0 : case FD_FLAMENCO_TYPE_MAP_END:
32 0 : break;
33 0 : case FD_FLAMENCO_TYPE_ENUM:
34 : // print the enum discriminant
35 0 : fprintf( file, "%u,", *(uint const*) arg );
36 0 : break;
37 0 : case FD_FLAMENCO_TYPE_ENUM_END:
38 0 : case FD_FLAMENCO_TYPE_ARR:
39 0 : case FD_FLAMENCO_TYPE_ARR_END:
40 0 : break;
41 0 : case FD_FLAMENCO_TYPE_NULL:
42 0 : break;
43 0 : case FD_FLAMENCO_TYPE_BOOL:
44 0 : fprintf( file, "%s,", (*(uchar const *)arg) ? "true" : "false" );
45 0 : break;
46 0 : case FD_FLAMENCO_TYPE_UCHAR:
47 0 : if (arg) fprintf( file, "%u,", *(uchar const *)arg );
48 0 : break;
49 0 : case FD_FLAMENCO_TYPE_SCHAR:
50 0 : fprintf( file, "%d,", *(schar const *)arg );
51 0 : break;
52 0 : case FD_FLAMENCO_TYPE_USHORT:
53 0 : fprintf( file, "%u,", *(ushort const *)arg );
54 0 : break;
55 0 : case FD_FLAMENCO_TYPE_SSHORT:
56 0 : fprintf( file, "%d,", *(short const *)arg );
57 0 : break;
58 0 : case FD_FLAMENCO_TYPE_UINT:
59 0 : if (varint) {
60 0 : uchar b[8];
61 0 : fd_bincode_encode_ctx_t ctx = { .data = b, .dataend = &b[sizeof(b)-1] };
62 0 : fd_bincode_varint_encode( *(uint const *)arg, &ctx );
63 0 : int len = (int) ((char *) ctx.data - (char *) &b[0]);
64 0 : for (int i = 0; i < len; i++) {
65 0 : fprintf( file, "%d,", (uchar) b[i] );
66 0 : }
67 0 : } else
68 0 : fprintf( file, "%u,", *(uint const *)arg );
69 0 : break;
70 0 : case FD_FLAMENCO_TYPE_SINT:
71 0 : fprintf( file, "%d,", *(int const *)arg );
72 0 : break;
73 0 : case FD_FLAMENCO_TYPE_ULONG:
74 0 : if (varint) {
75 0 : uchar b[8];
76 0 : fd_bincode_encode_ctx_t ctx = { .data = b, .dataend = &b[sizeof(b)-1] };
77 0 : fd_bincode_varint_encode( *(ulong const *)arg, &ctx );
78 0 : int len = (int) ((char *) ctx.data - (char *) &b[0]);
79 0 : for (int i = 0; i < len; i++) {
80 0 : fprintf( file, "%d,", (uchar) b[i] );
81 0 : }
82 0 : } else
83 0 : fprintf( file, "%lu,", *(ulong const *)arg );
84 0 : break;
85 0 : case FD_FLAMENCO_TYPE_SLONG:
86 0 : fprintf( file, "%ld,", *(long const *)arg );
87 0 : break;
88 0 : # if FD_HAS_INT128
89 0 : case FD_FLAMENCO_TYPE_UINT128:
90 0 : case FD_FLAMENCO_TYPE_SINT128: {
91 0 : uint128 v = *(uint128 const *)arg;
92 : // fprintf( file, "%s: 0x%016lx%016lx\n", name,
93 : // (ulong)(v>>64), (ulong)v );
94 0 : if( v <= ULONG_MAX ) {
95 0 : fprintf( file, "%lu,", (ulong)v );
96 0 : } else {
97 0 : char str[40] = {0};
98 0 : char *p = str + sizeof(str) - 1;
99 :
100 0 : if( v == 0 ) {
101 0 : *--p = '0';
102 0 : } else {
103 0 : while( v != 0 ) {
104 0 : *--p = (char)('0' + (int)( v % 10 ));
105 0 : v /= 10;
106 0 : }
107 0 : }
108 0 : fprintf( file, "%s,", p );
109 0 : }
110 0 : break;
111 0 : }
112 0 : # endif
113 0 : case FD_FLAMENCO_TYPE_FLOAT: {
114 0 : double f = (double)( *(float const *)arg );
115 0 : for( ulong i=0; i < sizeof(f); ++i ) {
116 0 : fprintf( file, "0x%02X,", ((uchar *)&f)[i] );
117 0 : }
118 0 : break;
119 0 : }
120 0 : case FD_FLAMENCO_TYPE_DOUBLE: {
121 0 : double f = *(double const *)arg;
122 0 : for( ulong i=0; i < sizeof(f); ++i ) {
123 0 : fprintf( file, "0x%02X,", ((uchar *)&f)[i] );
124 0 : }
125 0 : break;
126 0 : }
127 0 : case FD_FLAMENCO_TYPE_HASH256: {
128 0 : for( ulong i=0; i < 32; ++i ) {
129 0 : fprintf( file, "%u,", ((uchar *)arg)[i] );
130 0 : }
131 0 : break;
132 0 : }
133 0 : case FD_FLAMENCO_TYPE_HASH1024:
134 0 : for( ulong i=0; i < 128; ++i ) {
135 0 : fprintf( file, "%u,", ((uchar *)arg)[i] );
136 0 : }
137 0 : break;
138 0 : case FD_FLAMENCO_TYPE_HASH16384:
139 0 : for( ulong i=0; i < 2048; ++i ) {
140 0 : fprintf( file, "%u,", ((uchar *)arg)[i] );
141 0 : }
142 0 : break;
143 0 : case FD_FLAMENCO_TYPE_SIG512: {
144 0 : for( ulong i=0; i < 64; ++i ) {
145 0 : fprintf( file, "%u,", ((uchar *)arg)[i] );
146 0 : }
147 0 : break;
148 0 : }
149 0 : case FD_FLAMENCO_TYPE_CSTR:
150 0 : if( arg==NULL ) {
151 0 : fprintf( file, "," );
152 0 : } else {
153 0 : fprintf( file, "'%s',", (char const *)arg );
154 0 : }
155 0 : break;
156 0 : case FD_FLAMENCO_TYPE_ENUM_DISC:
157 0 : break;
158 0 : default:
159 0 : FD_LOG_CRIT(( "unknown type %#x", (uint)type ));
160 0 : break;
161 0 : }
162 0 : }
163 :
164 : static int
165 : fd_runtime_fuzz_decode_type_run( fd_runtime_fuzz_runner_t * runner,
166 : uchar const * input,
167 : ulong input_sz,
168 : uchar * output,
169 0 : ulong * output_sz ) {
170 :
171 0 : FD_SPAD_FRAME_BEGIN( runner->spad ) {
172 0 : if( input_sz < 1 ) {
173 0 : *output_sz = 0;
174 0 : return 0;
175 0 : }
176 :
177 : // First byte is the type ID
178 0 : uchar type_id = input[0];
179 0 : if( type_id >= fd_types_vt_list_cnt ) {
180 0 : FD_LOG_WARNING(( "Invalid type ID: %d", type_id ));
181 0 : *output_sz = 0;
182 0 : return 0;
183 0 : }
184 :
185 0 : fd_types_vt_t const * type_meta = &fd_types_vt_list[ type_id ];
186 :
187 : // Set up decode context
188 0 : fd_bincode_decode_ctx_t decode_ctx = {
189 0 : .data = input + 1,
190 0 : .dataend = (void *)( (ulong)input + input_sz ),
191 0 : };
192 :
193 : // Get the size needed for the decoded object
194 0 : ulong total_sz = 0UL;
195 0 : int err = type_meta->decode_footprint( &decode_ctx, &total_sz );
196 0 : if( err != FD_BINCODE_SUCCESS ) {
197 0 : *output_sz = 0;
198 0 : return 0;
199 0 : }
200 :
201 : // Allocate memory for the decoded object
202 0 : void * decoded = fd_spad_alloc( runner->spad, 1UL, total_sz );
203 0 : if( !decoded ) {
204 0 : *output_sz = 0;
205 0 : return 0;
206 0 : }
207 :
208 : // Decode the object
209 0 : void * result = type_meta->decode( decoded, &decode_ctx );
210 0 : if (result == NULL) {
211 0 : *output_sz = 0;
212 0 : return 0;
213 0 : }
214 :
215 : // Output buffer structure:
216 : // - serialized_sz (ulong)
217 : // - serialized data (bytes)
218 : // - yaml data (bytes)
219 :
220 0 : uchar * output_ptr = output;
221 0 : ulong remaining_sz = *output_sz;
222 :
223 : // Skip serialized_sz for now (we'll write it after serialization)
224 0 : uchar * serialized_sz_ptr = output_ptr;
225 0 : output_ptr += sizeof(ulong);
226 0 : remaining_sz -= sizeof(ulong);
227 :
228 : // Serialize the memory representation
229 0 : uchar * serialized_data_ptr = output_ptr;
230 0 : FILE * file = fmemopen( serialized_data_ptr, remaining_sz, "w" );
231 0 : if( !file ) {
232 0 : *output_sz = 0;
233 0 : return 0;
234 0 : }
235 :
236 0 : CustomerSerializer serializer = {
237 0 : .file = file,
238 0 : };
239 :
240 : // Walk the decoded object and serialize it
241 0 : type_meta->walk( &serializer, decoded, custom_serializer_walk, type_meta->name, 0U, 0U );
242 0 : if( ferror( file ) ) {
243 0 : fclose( file );
244 0 : *output_sz = 0;
245 0 : return 0;
246 0 : }
247 0 : long serialized_sz = ftell( file );
248 0 : fclose( file );
249 :
250 : // Write serialized_sz
251 0 : *(ulong *)serialized_sz_ptr = (ulong)serialized_sz;
252 :
253 : // Update output_ptr and remaining_sz
254 0 : output_ptr += serialized_sz;
255 0 : remaining_sz -= (ulong)serialized_sz;
256 :
257 : // Generate YAML representation
258 0 : uchar * yaml_data_ptr = output_ptr;
259 0 : file = fmemopen( yaml_data_ptr, remaining_sz, "w" );
260 0 : if( !file ) {
261 0 : *output_sz = 0;
262 0 : return 0;
263 0 : }
264 :
265 0 : void * yaml_mem = fd_spad_alloc( runner->spad, fd_flamenco_yaml_align(), fd_flamenco_yaml_footprint() );
266 0 : fd_flamenco_yaml_t * yaml = fd_flamenco_yaml_init( fd_flamenco_yaml_new( yaml_mem ), file );
267 :
268 : // Walk the decoded object and generate YAML
269 0 : type_meta->walk( yaml, decoded, fd_flamenco_yaml_walk, type_meta->name, 0U, 0U );
270 0 : if( ferror( file ) ) {
271 0 : fclose( file );
272 0 : *output_sz = 0;
273 0 : return 0;
274 0 : }
275 :
276 0 : long yaml_sz = ftell( file );
277 0 : fclose( file );
278 :
279 : // Update output_ptr and remaining_sz
280 0 : output_ptr += yaml_sz;
281 0 : remaining_sz -= (ulong)yaml_sz;
282 :
283 : // Calculate total size
284 0 : *output_sz = (ulong)(output_ptr - output);
285 0 : return 1;
286 0 : } FD_SPAD_FRAME_END;
287 :
288 0 : *output_sz = 0;
289 0 : return 0;
290 0 : }
291 :
292 : ulong
293 : fd_runtime_fuzz_type_run( fd_runtime_fuzz_runner_t * runner,
294 : void const * input_,
295 : void ** output_,
296 : void * output_buf,
297 0 : ulong output_bufsz ) {
298 0 : fd_exec_test_type_context_t const * input = fd_type_pun_const( input_ );
299 0 : fd_exec_test_type_effects_t ** output = fd_type_pun( output_ );
300 :
301 0 : ulong output_end = (ulong)output_buf + output_bufsz;
302 0 : FD_SCRATCH_ALLOC_INIT(l, output_buf);
303 :
304 0 : fd_exec_test_type_effects_t * effects =
305 0 : FD_SCRATCH_ALLOC_APPEND(l, alignof(fd_exec_test_type_effects_t),
306 0 : sizeof(fd_exec_test_type_effects_t));
307 0 : if (FD_UNLIKELY(_l > output_end)) {
308 0 : return 0UL;
309 0 : }
310 :
311 0 : if( input == NULL || input->content == NULL ) {
312 0 : return 0UL;
313 0 : }
314 :
315 0 : if(input->content->size == 0) {
316 0 : return 0UL;
317 0 : }
318 :
319 : // Initialize effects
320 0 : effects->result = 0;
321 0 : effects->representation = NULL;
322 0 : effects->yaml = NULL;
323 :
324 : // Decode the type
325 0 : ulong max_content_size = output_bufsz - (_l - (ulong)output_buf);
326 0 : uchar * temp_buffer = (uchar *)_l;
327 0 : if (FD_UNLIKELY(_l > output_end)) {
328 0 : return 0UL;
329 0 : }
330 :
331 0 : ulong decoded_sz = max_content_size;
332 0 : int success = fd_runtime_fuzz_decode_type_run( runner,
333 0 : input->content->bytes,
334 0 : input->content->size,
335 0 : temp_buffer,
336 0 : &decoded_sz);
337 :
338 0 : if (!success || decoded_sz == 0) {
339 0 : effects->result = 1;
340 0 : } else {
341 0 : effects->result = 0;
342 :
343 : // The decoded data contains:
344 : // - serialized_sz (ulong)
345 : // - serialized data (bytes)
346 : // - yaml data (bytes)
347 :
348 : // Extract serialized_sz
349 0 : ulong serialized_sz = *(ulong*)temp_buffer;
350 :
351 : // Allocate and copy the representation (serialized data)
352 0 : _l += decoded_sz;
353 0 : effects->representation = FD_SCRATCH_ALLOC_APPEND(l, alignof(pb_bytes_array_t),
354 0 : PB_BYTES_ARRAY_T_ALLOCSIZE(serialized_sz));
355 0 : if( FD_UNLIKELY( _l > output_end ) ) {
356 0 : return 0UL;
357 0 : }
358 0 : effects->representation->size = (pb_size_t)serialized_sz;
359 0 : fd_memcpy(effects->representation->bytes, temp_buffer + sizeof(ulong), serialized_sz);
360 :
361 : // Allocate and copy the yaml data
362 0 : ulong yaml_sz = decoded_sz - sizeof(ulong) - serialized_sz;
363 0 : effects->yaml = FD_SCRATCH_ALLOC_APPEND(l, alignof(pb_bytes_array_t),
364 0 : PB_BYTES_ARRAY_T_ALLOCSIZE(yaml_sz));
365 0 : if( FD_UNLIKELY( _l > output_end ) ) {
366 0 : return 0UL;
367 0 : }
368 0 : effects->yaml->size = (pb_size_t)yaml_sz;
369 0 : fd_memcpy(effects->yaml->bytes, temp_buffer + sizeof(ulong) + serialized_sz, yaml_sz);
370 0 : }
371 :
372 0 : ulong actual_end = FD_SCRATCH_ALLOC_FINI(l, 1UL);
373 0 : *output = effects;
374 0 : return actual_end - (ulong)output_buf;
375 0 : }
|