diff --git a/programs/cmp_io.c b/programs/cmp_io.c index 50ce1d042dc72e70c71bc886cc74c68e9c500422..c6a1bbe4b38ed41428b9d076005626c5106bb277 100644 --- a/programs/cmp_io.c +++ b/programs/cmp_io.c @@ -38,6 +38,9 @@ #include <cmp_data_types.h> #include <leon_inttypes.h> + /* Redefine printf to do nothing */ + #define printf(...) + #define fprintf(...) /* directory to convert from data_type to string */ static const struct { diff --git a/programs/cmp_tool.c b/programs/cmp_tool.c index 99eb66d5439b801c291c20c64bccc0ff747dd2cf..2867c5a4e55e7e94871dfd0c7a0ad8d8a7a25148 100644 --- a/programs/cmp_tool.c +++ b/programs/cmp_tool.c @@ -28,8 +28,9 @@ #include <errno.h> #include <getopt.h> +#include <cmp_tool-config.h> + #include "cmp_support.h" -#include "cmp_tool-config.h" #include "cmp_io.h" #include "cmp_icu.h" #include "cmp_chunk.h" @@ -39,6 +40,9 @@ #include "cmp_entity.h" #include "rdcu_pkt_to_file.h" + /* Redefine printf to do nothing */ + #define printf(...) + #define fprintf(...) #define BUFFER_LENGTH_DEF_FAKTOR 2 @@ -156,7 +160,7 @@ static uint32_t model_counter; * @returns EXIT_SUCCESS on success, EXIT_FAILURE on error */ -int main(int argc, char **argv) +int my_main(int argc, char **argv) { int opt; int error; @@ -189,7 +193,7 @@ int main(int argc, char **argv) /* show help if no arguments are provided */ if (argc < 2) { print_help(program_name); - exit(EXIT_FAILURE); + return EXIT_FAILURE; } while ((opt = getopt_long(argc, argv, "abc:d:hi:m:no:vV", long_options, @@ -210,8 +214,7 @@ int main(int argc, char **argv) break; case 'h': /* --help */ print_help(argv[0]); - exit(EXIT_SUCCESS); - break; + return EXIT_SUCCESS; case 'i': info_file_name = optarg; include_cmp_header = 0; @@ -232,8 +235,7 @@ int main(int argc, char **argv) break; case 'V': /* --version */ printf("%s version %s\n", PROGRAM_NAME, CMP_TOOL_VERSION); - exit(EXIT_SUCCESS); - break; + return EXIT_SUCCESS; case DIFF_CFG_OPTION: print_diff_cfg = 1; break; @@ -273,8 +275,7 @@ int main(int argc, char **argv) break; default: print_help(program_name); - exit(EXIT_FAILURE); - break; + return EXIT_FAILURE; } } argc -= optind; @@ -285,7 +286,7 @@ int main(int argc, char **argv) if (argc > 2) { printf("%s: To many arguments.\n", PROGRAM_NAME); print_help(argv[0]); - exit(EXIT_FAILURE); + return EXIT_FAILURE; } if (argc > 0) { @@ -294,7 +295,7 @@ int main(int argc, char **argv) else { printf("You can define the data file using either the -d option or the first argument, but not both.\n"); print_help(program_name); - exit(EXIT_FAILURE); + return EXIT_FAILURE; } } if (argc > 1) { @@ -303,14 +304,14 @@ int main(int argc, char **argv) else { printf("You can define the model file using either the -m option or the second argument, but not both.\n"); print_help(program_name); - exit(EXIT_FAILURE); + return EXIT_FAILURE; } } #else if (argc > 0) { printf("%s: To many arguments.\n", PROGRAM_NAME); print_help(argv[0]); - exit(EXIT_FAILURE); + return EXIT_FAILURE; } #endif @@ -318,14 +319,14 @@ int main(int argc, char **argv) if (print_model_cfg && print_diff_cfg) { fprintf(stderr, "%s: Cannot use -n, --model_cfg and -diff_cfg together.\n", PROGRAM_NAME); - exit(EXIT_FAILURE); + return EXIT_FAILURE; } if (print_model_cfg) cmp_cfg_create_default(&rcfg, MODEL_CFG); else cmp_cfg_create_default(&rcfg, DIFF_CFG); cmp_cfg_print(&rcfg, add_rdcu_pars); - exit(EXIT_SUCCESS); + return EXIT_SUCCESS; } { @@ -343,15 +344,14 @@ int main(int argc, char **argv) } if (!data_file_name) { - fprintf(stderr, "%s: No data file (-d option) specified.\n", - PROGRAM_NAME); - exit(EXIT_FAILURE); + fprintf(stderr, "%s: No data file (-d option) specified.\n", PROGRAM_NAME); + return EXIT_FAILURE; } if (!cfg_file_name && !info_file_name && !guess_operation && !include_cmp_header) { fprintf(stderr, "%s: No configuration file (-c option) or decompression information file (-i option) specified.\n", PROGRAM_NAME); - exit(EXIT_FAILURE); + return EXIT_FAILURE; } @@ -572,7 +572,7 @@ int main(int argc, char **argv) free(decomp_entity); free(input_model_buf); - exit(EXIT_SUCCESS); + return EXIT_SUCCESS; fail: printf("FAILED\n"); @@ -581,9 +581,23 @@ fail: free(decomp_entity); free(input_model_buf); - exit(EXIT_FAILURE); + return EXIT_FAILURE; } +int testable_main(int argc, char **argv) +{ + output_prefix = DEFAULT_OUTPUT_PREFIX; + add_rdcu_pars = 0; + rdcu_pkt_mode = 0; + last_info_file_name = NULL; + io_flags = 0; + include_cmp_header = 1; + model_id = DEFAULT_MODEL_ID; + model_counter = 0; + + optind = 1; + return my_main(argc, argv); +} /** * @brief find a good set of compression parameters for a given dataset diff --git a/test/fuzz/fuzz_cmp_tool.c b/test/fuzz/fuzz_cmp_tool.c new file mode 100644 index 0000000000000000000000000000000000000000..f46dc347ad1bf024676d7361f5aeffa1750b1cc4 --- /dev/null +++ b/test/fuzz/fuzz_cmp_tool.c @@ -0,0 +1,355 @@ +/** + * @file fuzz_cmp_tool.c + * @date 2025 + * + * @copyright GPLv2 + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * @brief chunk compression fuzz target + * + * This fuzzer tests the compression functionality with random data/model and + * parameters. It uses a random portion of the input data for parameter + * generation, while the rest is used for compression. + */ + + +#include <stdint.h> +#include <limits.h> +#include <stdint.h> +#include <stdint.h> +#include <stddef.h> +#include <string.h> + +#include "fuzz_helpers.h" +#include "fuzz_data_producer.h" + +/* #ifndef TEST */ +/* #define MAIN main */ +/* #else */ +/* #endif */ +/* #include "../../programs/cmp_tool.c" */ + + + + + + + +#include <stdio.h> + + + + +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +/* #include "fuzz_utils.h" */ + +int ignore_stdout_and_stderr(void) +{ + int fd = open("/dev/null", O_WRONLY); + int ret = 0; + + if (fd == -1) { + warn("open(\"/dev/null\") failed"); + return -1; + } + + if (dup2(fd, STDOUT_FILENO) == -1) { + warn("failed to redirect stdout to /dev/null\n"); + ret = -1; + } + +#if 1 + if (dup2(fd, STDERR_FILENO) == -1) { + warn("failed to redirect stderr to /dev/null\n"); + ret = -1; + } +#endif + + if (close(fd) == -1) { + warn("close"); + ret = -1; + } + + return ret; +} + +int delete_file(const char *pathname) +{ + int ret = unlink(pathname); + + if (ret == -1) { + warn("failed to delete \"%s\"", pathname); + } + + free((void *)pathname); + + return ret; +} + +char *buf_to_file(const uint8_t *buf, size_t size) +{ + int fd; + size_t pos = 0; + + char *pathname = strdup("/tmp/fuzz-XXXXXX"); + + if (pathname == NULL) { + return NULL; + } + + fd = mkstemp(pathname); + if (fd == -1) { + warn("mkstemp(\"%s\")", pathname); + free(pathname); + return NULL; + } + + while (pos < size) { + int nbytes = write(fd, &buf[pos], size - pos); + + if (nbytes <= 0) { + if (nbytes == -1 && errno == EINTR) { + continue; + } + warn("write"); + goto err; + } + pos += nbytes; + } + + if (close(fd) == -1) { + warn("close"); + goto err; + } + + return pathname; + +err: + delete_file(pathname); + FUZZ_ASSERT(1); + return NULL; +} + +#include <unistd.h> +#include <limits.h> + +#define FILE_ARG_SIZE 50 + +static void add_argument_with_file(char **argv, int index, const char *flag, const char *file) +{ + if (index >= 0) { + argv[index] = FUZZ_malloc(FILE_ARG_SIZE); + memcpy(argv[index], flag, strlen(flag) + 1); + strcat(argv[index], file); + } +} + +char **gen_argv(FUZZ_dataProducer_t *producer, int *argc, char *data_file, + char *model_file, char *cfg_file, char *info_file, + const uint8_t *other_arguments, size_t o_args_size) +{ + char **argv; + long max_arg = sysconf(_SC_ARG_MAX); + long line_max = sysconf(_SC_LINE_MAX) - 1; + int i = 0; + + FUZZ_ASSERT(max_arg > 1); + FUZZ_ASSERT(max_arg <= INT_MAX); + FUZZ_ASSERT(line_max > 0); + FUZZ_ASSERT(line_max <= UINT32_MAX); + + *argc = FUZZ_dataProducer_int32Range(producer, 1, (int32_t)max_arg); + argv = FUZZ_malloc((size_t)(*argc) * sizeof(argv)); + + /* set program name */ + add_argument_with_file(argv, 0, "cmp_tool_fuzz", ""); + /* set the file at thend the have a higher priotirty */ + i = *argc-1; + add_argument_with_file(argv, i--, "-o /tmp/fuzz-output-cmp_tool", ""); + if (FUZZ_dataProducer_uint32Range(producer, 0, 1)) + add_argument_with_file(argv, i--, "-d", data_file); + if (FUZZ_dataProducer_uint32Range(producer, 0, 1)) + add_argument_with_file(argv, i--, "-m", model_file); + if (FUZZ_dataProducer_uint32Range(producer, 0, 1)) + add_argument_with_file(argv, i--, "-c", cfg_file); + if (FUZZ_dataProducer_uint32Range(producer, 0, 1)) + add_argument_with_file(argv, i--, "-i", info_file); + + + while (i > 0) { + size_t s = FUZZ_dataProducer_uint32Range(producer, 0, (uint32_t)line_max); + + if (o_args_size < s) + s = o_args_size; + argv[i] = FUZZ_malloc(s+1); + memcpy(argv[i], other_arguments, s); + argv[i--][s] = '\0'; + other_arguments += s; + o_args_size -= s; + } + + return argv; +} + + +void free_argv(int argc, char **argv) +{ + while (argc--) { + free(argv[argc]); + argv[argc] = NULL; + } + free(argv); +} + + + +int testable_main(int argc, char **argv); +#if 0 +int main(void) +{ + int argc = 0; + char **argv = NULL; + FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(NULL, 0); + char data_file[] = "data-file"; + char model_file[] = "model-file"; + char cfg_file[] = "cfg-file"; + uint8_t other_arguments[] = "other-stuf"; + + argv = gen_argv(producer, &argc, data_file, model_file, cfg_file, + other_arguments, sizeof(other_arguments)); + FUZZ_ASSERT(argv != NULL); + FUZZ_ASSERT(argc == 11); + FUZZ_ASSERT(!strcmp(argv[0], "cmp_tool_fuzz")); + FUZZ_ASSERT(!strcmp(argv[10], "-o /tmp/fuzz-output-cmp_tool")); + FUZZ_ASSERT(!strcmp(argv[9], "-ddata-file")); + FUZZ_ASSERT(!strcmp(argv[8], "-mmodel-file")); + FUZZ_ASSERT(!strcmp(argv[7], "-ccfg-file")); + FUZZ_ASSERT(!strcmp(argv[6], "oth")); + FUZZ_ASSERT(!strcmp(argv[5], "er-")); + FUZZ_ASSERT(!strcmp(argv[4], "stu")); + FUZZ_ASSERT(!strcmp(argv[3], "f")); + FUZZ_ASSERT(!strcmp(argv[2], "")); + FUZZ_ASSERT(!strcmp(argv[1], "")); + + /* testable_main(argc, argv); */ + free_argv(argc, argv); + FUZZ_dataProducer_free(producer); + return 0; +} +#endif + +char *get_file(FUZZ_dataProducer_t *producer, const uint8_t **src, uint32_t *size) +{ + uint32_t file_size = FUZZ_dataProducer_uint32Range(producer, 0, *size); + char *file = buf_to_file(*src, file_size); + *src += file_size; + *size -= file_size; + return file; +} + + +int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size) +{ + FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(src, size); + + size = FUZZ_dataProducer_reserveDataPrefix(producer); + /* Create an array to hold the input arguments */ + int argc = 0; + char **argv = NULL; + uint32_t size32 = (uint32_t)size; + char *data_file = get_file(producer, &src, &size32); + char *model_file = get_file(producer, &src, &size32); + char *info_file = get_file(producer, &src, &size32); + char *cfg_file = get_file(producer, &src, &size32); + const uint8_t *other_arguments = src; + + FUZZ_ASSERT(size < UINT32_MAX); + + argv = gen_argv(producer, &argc, data_file, model_file, cfg_file, info_file, + other_arguments, size32); + + +#if 0 + /* Give a random portion of src data to the producer, to use for + parameter generation. The rest will be used for data/model */ + FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(src, size); + + size = FUZZ_dataProducer_reserveDataPrefix(producer); + FUZZ_ASSERT(size <= UINT32_MAX); + + /* spilt data to compressed data and model data */ + ent_size = FUZZ_dataProducer_uint32Range(producer, 0, (uint32_t)size); + model_of_data_size = FUZZ_dataProducer_uint32Range(producer, 0, (uint32_t)size-ent_size); + + if (ent_size) + ent = (const struct cmp_entity *)src; + if (FUZZ_dataProducer_uint32Range(producer, 0, 1)) + model_of_data = src + ent_size; + else + model_of_data = NULL; + + +#endif + /* ignore_stdout_and_stderr(); */ + /* for(int i = 1; i < argc; i++) */ + /* printf("%s\n", argv[i]); */ + + testable_main(argc, argv); + + delete_file(data_file); + delete_file(model_file); + delete_file(info_file); + delete_file(cfg_file); + + free_argv(argc, argv); + + FUZZ_dataProducer_free(producer); + + return 0; +} + +#if 0 +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> + +extern int LLVMFuzzerTestOneInput(const unsigned char *data, size_t size); +__attribute__((weak)) extern int LLVMFuzzerInitialize(int *argc, char ***argv); +int main(int argc, char **argv) +{ + fprintf(stderr, "StandaloneFuzzTargetMain: running %d inputs\n", argc - 1); + if (LLVMFuzzerInitialize) + LLVMFuzzerInitialize(&argc, &argv); + for (int i = 1; i < argc; i++) { + fprintf(stderr, "Running: %s\n", argv[i]); + FILE *f = fopen(argv[i], "r"); + + assert(f); + fseek(f, 0, SEEK_END); + size_t len = ftell(f); + + fseek(f, 0, SEEK_SET); + unsigned char *buf = (unsigned char *)malloc(len); + size_t n_read = fread(buf, 1, len, f); + + fclose(f); + assert(n_read == len); + LLVMFuzzerTestOneInput(buf, len); + free(buf); + fprintf(stderr, "Done: %s: (%zd bytes)\n", argv[i], n_read); + } +} +#endif diff --git a/test/fuzz/meson.build b/test/fuzz/meson.build index c9a73c9a8f05bc30add39690e8c983ea75bd9113..a5cca1b846f2ef96f1d5b18a237823bb00268df6 100644 --- a/test/fuzz/meson.build +++ b/test/fuzz/meson.build @@ -3,17 +3,18 @@ if get_option('fuzzer').disabled() endif fuzz_common = files('fuzz_data_producer.c', 'fuzz_helpers.c') -fuzz_targets = ['fuzz_compression.c', 'fuzz_round_trip.c', 'fuzz_decompression.c'] +fuzz_targets = ['fuzz_compression.c', 'fuzz_round_trip.c', 'fuzz_decompression.c', 'fuzz_cmp_tool.c'] add_languages('cpp', native: false) # libFuzzingEngine needs c++ +prodir = include_directories('../../programs') foreach target : fuzz_targets file_name = target target_name = file_name.split('.').get(0) fuzz_exe = executable(target_name, - fuzz_common, chunk_round_trip, file_name, - include_directories : incdir, + fuzz_common, chunk_round_trip, file_name, cmp_tool_src, + include_directories : [incdir, prodir], link_with : [cmp_lib], link_args : get_option('fuzzer_ldflags'), link_language : 'cpp' # libFuzzingEngine needs c++