mirror of https://github.com/ludocode/mpack
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
171 lines
5.7 KiB
C
171 lines
5.7 KiB
C
/*
|
|
* Copyright (c) 2018-2021 Nicholas Fraser and the MPack authors
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
* this software and associated documentation files (the "Software"), to deal in
|
|
* the Software without restriction, including without limitation the rights to
|
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
|
* subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
* copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
|
|
#ifdef MPACK_FUZZ
|
|
|
|
/*
|
|
* fuzz.c is a test program to assist with fuzzing MPack. It:
|
|
*
|
|
* - decodes stdin with the dynamic Reader API;
|
|
* - encodes the data to a growable buffer with the Write API;
|
|
* - parses the resulting buffer with the Node API;
|
|
* - and finally, prints a debug dump of the node tree to stdout.
|
|
*
|
|
* It thus passes all data through three major components of MPack (but not
|
|
* the Expect API.)
|
|
*/
|
|
|
|
#include "mpack/mpack.h"
|
|
|
|
#ifndef MPACK_FUZZ_CONFIG_H
|
|
#error "This should be built with fuzz-config.h as a prefix header."
|
|
#endif
|
|
|
|
static void print_callback(void* context, const char* data, size_t count) {
|
|
fwrite(data, 1, count, stdout);
|
|
}
|
|
|
|
static void transfer_bytes(mpack_reader_t* reader, mpack_writer_t* writer, uint32_t count) {
|
|
if (mpack_should_read_bytes_inplace(reader, count)) {
|
|
const char* data = mpack_read_bytes_inplace(reader, count);
|
|
if (mpack_reader_error(reader) == mpack_ok)
|
|
mpack_write_bytes(writer, data, count);
|
|
return;
|
|
}
|
|
|
|
while (count > 0) {
|
|
char buffer[79];
|
|
uint32_t step = (count < sizeof(buffer)) ? count : sizeof(buffer);
|
|
mpack_read_bytes(reader, buffer, step);
|
|
if (mpack_reader_error(reader) != mpack_ok)
|
|
return;
|
|
mpack_write_bytes(writer, buffer, step);
|
|
count -= step;
|
|
}
|
|
}
|
|
|
|
static void transfer_element(mpack_reader_t* reader, mpack_writer_t* writer, int depth) {
|
|
|
|
// We apply a depth limit manually right now to avoid a stack overflow. A
|
|
// depth limit should probably be added to the reader and tree at some
|
|
// point because even though the reader and tree can themselves handle
|
|
// arbitrary depths, any dynamic use that doesn't account for this is
|
|
// likely to be vulnerable to such stack overflows.
|
|
if (depth >= 1024) {
|
|
fprintf(stderr, "hit depth limit!\n");
|
|
mpack_reader_flag_error(reader, mpack_error_too_big);
|
|
return;
|
|
}
|
|
++depth;
|
|
|
|
mpack_tag_t tag = mpack_read_tag(reader);
|
|
if (mpack_reader_error(reader) != mpack_ok) {
|
|
fprintf(stderr, "error reading tag!\n");
|
|
return;
|
|
}
|
|
|
|
/*
|
|
static char describe_buffer[64];
|
|
mpack_tag_debug_describe(tag, describe_buffer, sizeof(describe_buffer));
|
|
printf("%s\n", describe_buffer);
|
|
*/
|
|
|
|
mpack_write_tag(writer, tag);
|
|
|
|
switch (tag.type) {
|
|
#if MPACK_EXTENSIONS
|
|
case mpack_type_ext: // fallthrough
|
|
#endif
|
|
case mpack_type_str: // fallthrough
|
|
case mpack_type_bin:
|
|
transfer_bytes(reader, writer, mpack_tag_bytes(&tag));
|
|
if (mpack_reader_error(reader) != mpack_ok)
|
|
return;
|
|
mpack_done_type(reader, tag.type);
|
|
mpack_finish_type(writer, tag.type);
|
|
break;
|
|
|
|
case mpack_type_map:
|
|
for (uint32_t i = 0; i < mpack_tag_map_count(&tag); ++i) {
|
|
transfer_element(reader, writer, depth);
|
|
if (mpack_reader_error(reader) != mpack_ok)
|
|
return;
|
|
transfer_element(reader, writer, depth);
|
|
if (mpack_reader_error(reader) != mpack_ok)
|
|
return;
|
|
}
|
|
mpack_done_map(reader);
|
|
mpack_finish_map(writer);
|
|
break;
|
|
|
|
case mpack_type_array:
|
|
for (uint32_t i = 0; i < mpack_tag_array_count(&tag); ++i) {
|
|
transfer_element(reader, writer, depth);
|
|
if (mpack_reader_error(reader) != mpack_ok)
|
|
return;
|
|
}
|
|
mpack_done_array(reader);
|
|
mpack_finish_array(writer);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
int main(int argc, char** argv) {
|
|
char* data;
|
|
size_t size;
|
|
mpack_writer_t writer;
|
|
mpack_writer_init_growable(&writer, &data, &size);
|
|
|
|
mpack_reader_t reader;
|
|
mpack_reader_init_stdfile(&reader, stdin, false);
|
|
|
|
transfer_element(&reader, &writer, 0);
|
|
|
|
if (mpack_reader_destroy(&reader) != mpack_ok || mpack_writer_destroy(&writer) != mpack_ok) {
|
|
fprintf(stderr, "error in reader or writer!\n");
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
mpack_tree_t tree;
|
|
mpack_tree_init_stdfile(&tree, stdin, 0, false);
|
|
mpack_tree_parse(&tree);
|
|
if (mpack_tree_error(&tree) != mpack_ok) {
|
|
fprintf(stderr, "error parsing tree!\n");
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
mpack_node_print_to_callback(mpack_tree_root(&tree), print_callback, NULL);
|
|
|
|
if (mpack_tree_destroy(&tree) != mpack_ok) {
|
|
fprintf(stderr, "error printing or destroying tree!\n");
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
#else
|
|
typedef int mpack_pedantic_allow_empty_translation_unit;
|
|
#endif
|