From 6e3aaa529b84a411e0e9669420877c87c87a53c4 Mon Sep 17 00:00:00 2001 From: Jakub Gonet Date: Thu, 26 Dec 2024 23:18:58 +0100 Subject: [PATCH 01/19] Reformat --- tools/packbeam/packbeam.c | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/tools/packbeam/packbeam.c b/tools/packbeam/packbeam.c index 3c8cf7f1e..bfc979192 100644 --- a/tools/packbeam/packbeam.c +++ b/tools/packbeam/packbeam.c @@ -29,8 +29,8 @@ #include #endif -#include "iff.c" #include "avmpack.h" +#include "iff.c" #include "mapped_file.h" #define LITT_UNCOMPRESSED_SIZE_OFFSET 8 @@ -41,9 +41,10 @@ #define BEAM_CODE_FLAG 2 #define BUF_SIZE 1024 -typedef struct FileData { +typedef struct FileData +{ uint8_t *data; - size_t size; + size_t size; } FileData; static void pad_and_align(FILE *f); @@ -54,7 +55,8 @@ static void pack_beam_file(FILE *pack, const uint8_t *data, size_t size, const c static int do_pack(int argc, char **argv, int is_archive, bool include_lines); static int do_list(int argc, char **argv); -static void usage3(FILE *out, const char *program, const char *msg) { +static void usage3(FILE *out, const char *program, const char *msg) +{ if (!IS_NULL_PTR(msg)) { fprintf(out, "%s\n", msg); } @@ -62,8 +64,7 @@ static void usage3(FILE *out, const char *program, const char *msg) { fprintf(out, " -h Print this help menu.\n"); fprintf(out, " -i Include file and line information.\n"); fprintf(out, " -l List the contents of an AVM file.\n"); - fprintf(out, " [-a] + Create an AVM file (archive if -a specified).\n" - ); + fprintf(out, " [-a] + Create an AVM file (archive if -a specified).\n"); } static void usage(const char *program) @@ -71,7 +72,6 @@ static void usage(const char *program) usage3(stdout, program, NULL); } - int main(int argc, char **argv) { int opt; @@ -80,7 +80,7 @@ int main(int argc, char **argv) int is_archive = 0; bool include_lines = false; while ((opt = getopt(argc, argv, "hail")) != -1) { - switch(opt) { + switch (opt) { case 'h': usage(argv[0]); return EXIT_SUCCESS; @@ -102,7 +102,7 @@ int main(int argc, char **argv) } } - int new_argc = argc - optind; + int new_argc = argc - optind; char **new_argv = argv + optind; if (new_argc < 1) { @@ -121,7 +121,7 @@ int main(int argc, char **argv) } } -static void assert_fread(void *buffer, size_t size, FILE* file) +static void assert_fread(void *buffer, size_t size, FILE *file) { size_t r = fread(buffer, sizeof(uint8_t), size, file); if (r != size) { @@ -130,7 +130,7 @@ static void assert_fread(void *buffer, size_t size, FILE* file) } } -static void assert_fwrite(const void *buffer, size_t size, FILE* file) +static void assert_fwrite(const void *buffer, size_t size, FILE *file) { size_t r = fwrite(buffer, 1, size, file); if (r != size) { @@ -148,7 +148,7 @@ static void *pack_beam_fun(void *accum, const void *section_ptr, uint32_t sectio return NULL; } - FILE *pack = (FILE *)accum; + FILE *pack = (FILE *) accum; size_t r = fwrite(section_ptr, sizeof(unsigned char), section_size, pack); if (r != section_size) { return NULL; @@ -191,9 +191,9 @@ static bool is_beam_file(FILE *file) return ret; } -static void validate_pack_options(int argc, char ** argv) +static void validate_pack_options(int argc, char **argv) { - for (int i = 0; i < argc; ++i) { + for (int i = 0; i < argc; ++i) { const char *filename = argv[i]; FILE *file = fopen(filename, "r"); if (i == 0) { @@ -231,8 +231,7 @@ static int do_pack(int argc, char **argv, int is_archive, bool include_lines) return EXIT_FAILURE; } - const unsigned char pack_header[24] = - { + const unsigned char pack_header[24] = { 0x23, 0x21, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x65, @@ -255,7 +254,6 @@ static int do_pack(int argc, char **argv, int is_archive, bool include_lines) size_t file_size = ftell(file); fseek(file, 0, SEEK_SET); - uint8_t *file_data = malloc(file_size); if (!file_data) { fprintf(stderr, "Unable to allocate %zu bytes\n", file_size); @@ -290,8 +288,7 @@ static void pack_beam_file(FILE *pack, const uint8_t *data, size_t size, const c } int written_beam_header_pos = ftell(pack); - const unsigned char beam_header[12] = - { + const unsigned char beam_header[12] = { 0x46, 0x4f, 0x52, 0x31, 0x00, 0x00, 0x00, 0x00, 0x42, 0x45, 0x41, 0x4d @@ -362,11 +359,10 @@ static void pack_beam_file(FILE *pack, const uint8_t *data, size_t size, const c int beam_written_size = end_of_module_pos - written_beam_header_pos; uint32_t beam_written_size_field = ENDIAN_SWAP_32(beam_written_size); fseek(pack, written_beam_header_pos + 4, SEEK_SET); - assert_fwrite(&beam_written_size_field , sizeof(uint32_t), pack); + assert_fwrite(&beam_written_size_field, sizeof(uint32_t), pack); fseek(pack, end_of_module_pos, SEEK_SET); } - static void *print_section(void *accum, const void *section_ptr, uint32_t section_size, const void *beam_ptr, uint32_t flags, const char *section_name) { UNUSED(section_ptr); From 6041a4b0f6da9f56221e9f02ad9f474d6b86b4e4 Mon Sep 17 00:00:00 2001 From: Jakub Gonet Date: Thu, 26 Dec 2024 23:19:43 +0100 Subject: [PATCH 02/19] Temporarily disable WITH_ZLIB --- tools/packbeam/packbeam.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/packbeam/packbeam.c b/tools/packbeam/packbeam.c index bfc979192..fc141d68c 100644 --- a/tools/packbeam/packbeam.c +++ b/tools/packbeam/packbeam.c @@ -25,9 +25,10 @@ #include #include -#ifdef WITH_ZLIB +// TODO: Remove this when the code is refactored +// #ifdef WITH_ZLIB #include -#endif +// #endif #include "avmpack.h" #include "iff.c" From 4626d2bfd0a1458fd09cfad2da466ffe65f6537c Mon Sep 17 00:00:00 2001 From: Jakub Gonet Date: Thu, 26 Dec 2024 23:53:23 +0100 Subject: [PATCH 03/19] Structure errors --- tools/packbeam/packbeam.c | 94 ++++++++++++++++++--------------------- 1 file changed, 43 insertions(+), 51 deletions(-) diff --git a/tools/packbeam/packbeam.c b/tools/packbeam/packbeam.c index fc141d68c..5d1a98bd7 100644 --- a/tools/packbeam/packbeam.c +++ b/tools/packbeam/packbeam.c @@ -56,21 +56,33 @@ static void pack_beam_file(FILE *pack, const uint8_t *data, size_t size, const c static int do_pack(int argc, char **argv, int is_archive, bool include_lines); static int do_list(int argc, char **argv); -static void usage3(FILE *out, const char *program, const char *msg) +#define program_error(...) error_with_usage(argv[0], __VA_ARGS__) +#define packbeam_error(...) error_with_usage("PackBeam", __VA_ARGS__) +#define packbeam_internal_error(...) internal_error("PackBeam", __VA_ARGS__) + +static void internal_error(const char *program, const char *format, ...) { - if (!IS_NULL_PTR(msg)) { - fprintf(out, "%s\n", msg); - } - fprintf(out, "Usage: %s [-h] [-l] []\n", program); - fprintf(out, " -h Print this help menu.\n"); - fprintf(out, " -i Include file and line information.\n"); - fprintf(out, " -l List the contents of an AVM file.\n"); - fprintf(out, " [-a] + Create an AVM file (archive if -a specified).\n"); + va_list format_args; + va_start(format_args, format); + fprintf(stderr, "%s: ", program); + fprintf(stderr, format, format_args); + fprintf(stderr, "\n"); + va_end(format_args); } -static void usage(const char *program) +static void error_with_usage(const char *program, const char *format, ...) { - usage3(stdout, program, NULL); + if (format != NULL) { + va_list format_args; + va_start(format_args, format); + internal_error(program, format, format_args); + va_end(format_args); + } + fprintf(stderr, "\nUsage: %s [-h] [-l] []\n", program); + fprintf(stderr, " -h Print this help menu.\n"); + fprintf(stderr, " -i Include file and line information.\n"); + fprintf(stderr, " -l List the contents of an AVM file.\n"); + fprintf(stderr, " [-a] + Create an AVM file (archive if -a specified).\n"); } int main(int argc, char **argv) @@ -83,7 +95,7 @@ int main(int argc, char **argv) while ((opt = getopt(argc, argv, "hail")) != -1) { switch (opt) { case 'h': - usage(argv[0]); + program_error(NULL); return EXIT_SUCCESS; case 'a': is_archive = 1; @@ -95,9 +107,7 @@ int main(int argc, char **argv) action = "list"; break; case '?': { - char buf[BUF_SIZE]; - snprintf(buf, BUF_SIZE, "Unknown option: %c", optopt); - usage3(stderr, argv[0], buf); + program_error("Unknown option: %c", optopt); return EXIT_FAILURE; } } @@ -107,13 +117,13 @@ int main(int argc, char **argv) char **new_argv = argv + optind; if (new_argc < 1) { - usage3(stderr, argv[0], "Missing avm file.\n"); + program_error("Missing avm file."); return EXIT_FAILURE; } if (!strcmp(action, "pack")) { if (new_argc < 2) { - usage3(stderr, argv[0], "Missing options for pack\n"); + program_error("Missing options for pack."); return EXIT_FAILURE; } return do_pack(new_argc, new_argv, is_archive, include_lines); @@ -126,7 +136,7 @@ static void assert_fread(void *buffer, size_t size, FILE *file) { size_t r = fread(buffer, sizeof(uint8_t), size, file); if (r != size) { - fprintf(stderr, "Unable to read, wanted to read %zu bytes, read %zu bytes\n", size, r); + packbeam_internal_error("Unable to read, wanted to read %zu bytes, read %zu bytes.", size, r); exit(EXIT_FAILURE); } } @@ -135,7 +145,7 @@ static void assert_fwrite(const void *buffer, size_t size, FILE *file) { size_t r = fwrite(buffer, 1, size, file); if (r != size) { - fprintf(stderr, "Unable to write, wanted to write %zu bytes, wrote %zu bytes\n", size, r); + packbeam_internal_error("Unable to write, wanted to write %zu bytes, wrote %zu bytes.", size, r); exit(EXIT_FAILURE); } } @@ -164,7 +174,7 @@ FileData read_file_data(FILE *file) fseek(file, 0, SEEK_SET); uint8_t *data = malloc(size); if (!data) { - fprintf(stderr, "Unable to allocate %zu bytes\n", size); + packbeam_internal_error("Unable to allocate %zu bytes.", size); exit(EXIT_FAILURE); } assert_fread(data, size, file); @@ -199,21 +209,15 @@ static void validate_pack_options(int argc, char **argv) FILE *file = fopen(filename, "r"); if (i == 0) { if (file && !is_avm_file(file)) { - char buf[BUF_SIZE]; - snprintf(buf, BUF_SIZE, "Invalid AVM file: %s", filename); - usage3(stderr, "PackBeam", buf); + packbeam_error("Invalid AVM file: %s.", filename); exit(EXIT_FAILURE); } } else { if (!file) { - char buf[BUF_SIZE]; - snprintf(buf, BUF_SIZE, "%s does not exist", filename); - usage3(stderr, "PackBeam", buf); + packbeam_error("%s does not exist.", filename); exit(EXIT_FAILURE); } else if (!is_avm_file(file) && !is_beam_file(file)) { - char buf[BUF_SIZE]; - snprintf(buf, BUF_SIZE, "Invalid AVM or BEAM file: %s", filename); - usage3(stderr, "PackBeam", buf); + packbeam_error("Invalid AVM or BEAM file: %s.", filename); exit(EXIT_FAILURE); } } @@ -226,9 +230,7 @@ static int do_pack(int argc, char **argv, int is_archive, bool include_lines) FILE *pack = fopen(argv[0], "w"); if (!pack) { - char buf[BUF_SIZE]; - snprintf(buf, BUF_SIZE, "Cannot open output file for writing %s", argv[0]); - perror(buf); + packbeam_internal_error("Cannot open output file for writing %s.", argv[0]); return EXIT_FAILURE; } @@ -245,9 +247,7 @@ static int do_pack(int argc, char **argv, int is_archive, bool include_lines) for (int i = 1; i < argc; i++) { FILE *file = fopen(argv[i], "r"); if (!file) { - char buf[BUF_SIZE]; - snprintf(buf, BUF_SIZE, "Cannot open file %s", argv[i]); - perror(buf); + packbeam_internal_error("Cannot open file %s.", argv[i]); return EXIT_FAILURE; } @@ -257,7 +257,7 @@ static int do_pack(int argc, char **argv, int is_archive, bool include_lines) uint8_t *file_data = malloc(file_size); if (!file_data) { - fprintf(stderr, "Unable to allocate %zu bytes\n", file_size); + packbeam_internal_error("Unable to allocate %zu bytes\n", file_size); return EXIT_FAILURE; } assert_fread(file_data, file_size, file); @@ -377,14 +377,10 @@ static void validate_list_options(const char *filename) { FILE *file = fopen(filename, "r"); if (!file) { - char buf[BUF_SIZE]; - snprintf(buf, BUF_SIZE, "%s does not exist", filename); - usage3(stderr, "PackBeam", buf); + packbeam_error("%s does not exist.", filename); exit(EXIT_FAILURE); } else if (!is_avm_file(file)) { - char buf[BUF_SIZE]; - snprintf(buf, BUF_SIZE, "Invalid AVM file: %s", filename); - usage3(stderr, "PackBeam", buf); + packbeam_error("Invalid AVM file: %s.", filename); exit(EXIT_FAILURE); } } @@ -396,9 +392,7 @@ static int do_list(int argc, char **argv) MappedFile *mapped_file = mapped_file_open_beam(argv[0]); if (IS_NULL_PTR(mapped_file)) { - char buf[BUF_SIZE]; - snprintf(buf, BUF_SIZE, "Cannot open AVM file %s", argv[0]); - perror(buf); + packbeam_internal_error("Cannot open AVM file %s.", argv[0]); return EXIT_FAILURE; } @@ -406,9 +400,7 @@ static int do_list(int argc, char **argv) if (avmpack_is_valid(mapped_file->mapped, mapped_file->size)) { avmpack_fold(NULL, mapped_file->mapped, print_section); } else { - char buf[BUF_SIZE]; - snprintf(buf, BUF_SIZE, "%s is not an AVM file.\n", argv[1]); - usage3(stderr, "PackBeam", buf); + packbeam_error("%s is not an AVM file.", argv[1]); ret = EXIT_FAILURE; } mapped_file_close(mapped_file); @@ -422,7 +414,7 @@ static void *uncompress_literals(const uint8_t *litT, int size, size_t *uncompre uint8_t *outBuf = malloc(required_buf_size); if (!outBuf) { - fprintf(stderr, "Cannot allocate temporary buffer (size = %u)", required_buf_size); + packbeam_internal_error("Cannot allocate temporary buffer of size %u.", required_buf_size); AVM_ABORT(); } @@ -437,12 +429,12 @@ static void *uncompress_literals(const uint8_t *litT, int size, size_t *uncompre int ret = inflateInit(&infstream); if (ret != Z_OK) { - fprintf(stderr, "Failed inflateInit\n"); + packbeam_internal_error("Failed inflateInit."); AVM_ABORT(); } ret = inflate(&infstream, Z_NO_FLUSH); if (ret != Z_OK) { - fprintf(stderr, "Failed inflate\n"); + packbeam_internal_error("Failed inflate."); AVM_ABORT(); } inflateEnd(&infstream); From 2d0aba767633632c71cfe313a1ef3763dfc7b70a Mon Sep 17 00:00:00 2001 From: Jakub Gonet Date: Fri, 27 Dec 2024 00:13:16 +0100 Subject: [PATCH 04/19] Change parameter passing --- tools/packbeam/packbeam.c | 102 ++++++++++++++++++++------------------ 1 file changed, 53 insertions(+), 49 deletions(-) diff --git a/tools/packbeam/packbeam.c b/tools/packbeam/packbeam.c index 5d1a98bd7..a1d1c08b5 100644 --- a/tools/packbeam/packbeam.c +++ b/tools/packbeam/packbeam.c @@ -53,8 +53,8 @@ static void *uncompress_literals(const uint8_t *litT, int size, size_t *uncompre static void add_module_header(FILE *f, const char *module_name, uint32_t flags); static void pack_beam_file(FILE *pack, const uint8_t *data, size_t size, const char *filename, int is_entrypoint, bool include_lines); -static int do_pack(int argc, char **argv, int is_archive, bool include_lines); -static int do_list(int argc, char **argv); +static int do_pack(char *output_avm_file, char **input_files, size_t files_n, int is_archive, bool include_lines); +static int do_list(const char *avm_path); #define program_error(...) error_with_usage(argv[0], __VA_ARGS__) #define packbeam_error(...) error_with_usage("PackBeam", __VA_ARGS__) @@ -87,24 +87,24 @@ static void error_with_usage(const char *program, const char *format, ...) int main(int argc, char **argv) { - int opt; - - const char *action = "pack"; - int is_archive = 0; + bool list_avm = false; + bool is_archive = false; bool include_lines = false; + + int opt; while ((opt = getopt(argc, argv, "hail")) != -1) { switch (opt) { case 'h': program_error(NULL); return EXIT_SUCCESS; case 'a': - is_archive = 1; + is_archive = true; break; case 'i': include_lines = true; break; case 'l': - action = "list"; + list_avm = true; break; case '?': { program_error("Unknown option: %c", optopt); @@ -116,20 +116,23 @@ int main(int argc, char **argv) int new_argc = argc - optind; char **new_argv = argv + optind; - if (new_argc < 1) { - program_error("Missing avm file."); - return EXIT_FAILURE; - } - - if (!strcmp(action, "pack")) { - if (new_argc < 2) { - program_error("Missing options for pack."); + if (list_avm) { + if (new_argc < 1) { + program_error("Listing needs an AVM file."); return EXIT_FAILURE; } - return do_pack(new_argc, new_argv, is_archive, include_lines); - } else { - return do_list(new_argc, new_argv); + const char *avm_file = new_argv[0]; + return do_list(avm_file); + } + + if (new_argc < 2) { + program_error("Pack needs output AVM file and at least one AVM or BEAM input file(s)."); + return EXIT_FAILURE; } + char *output_avm_file = new_argv[0]; + char **input_files = &new_argv[1]; + size_t n = new_argc - 1; + return do_pack(output_avm_file, input_files, n, is_archive, include_lines); } static void assert_fread(void *buffer, size_t size, FILE *file) @@ -202,35 +205,36 @@ static bool is_beam_file(FILE *file) return ret; } -static void validate_pack_options(int argc, char **argv) +static void validate_pack_options(char *output_file, char **input_files, size_t n) { - for (int i = 0; i < argc; ++i) { - const char *filename = argv[i]; + FILE *file = fopen(output_file, "r"); + if (file == NULL || !is_avm_file(file)) { + packbeam_error("Invalid AVM file: %s.", output_file); + exit(EXIT_FAILURE); + } + fclose(file); + + for (size_t i = 0; i < n; ++i) { + const char *filename = input_files[i]; FILE *file = fopen(filename, "r"); - if (i == 0) { - if (file && !is_avm_file(file)) { - packbeam_error("Invalid AVM file: %s.", filename); - exit(EXIT_FAILURE); - } - } else { - if (!file) { - packbeam_error("%s does not exist.", filename); - exit(EXIT_FAILURE); - } else if (!is_avm_file(file) && !is_beam_file(file)) { - packbeam_error("Invalid AVM or BEAM file: %s.", filename); - exit(EXIT_FAILURE); - } + if (!file) { + packbeam_error("%s does not exist.", filename); + exit(EXIT_FAILURE); + } else if (!is_avm_file(file) && !is_beam_file(file)) { + packbeam_error("Invalid AVM or BEAM file: %s.", filename); + exit(EXIT_FAILURE); } + fclose(file); } } -static int do_pack(int argc, char **argv, int is_archive, bool include_lines) +static int do_pack(char *output_avm_file, char **input_files, size_t files_n, int is_archive, bool include_lines) { - validate_pack_options(argc, argv); + validate_pack_options(output_avm_file, input_files, files_n); - FILE *pack = fopen(argv[0], "w"); + FILE *pack = fopen(output_avm_file, "w"); if (!pack) { - packbeam_internal_error("Cannot open output file for writing %s.", argv[0]); + packbeam_internal_error("Cannot open output file for writing %s.", output_avm_file); return EXIT_FAILURE; } @@ -244,10 +248,11 @@ static int do_pack(int argc, char **argv, int is_archive, bool include_lines) }; assert_fwrite(pack_header, 24, pack); - for (int i = 1; i < argc; i++) { - FILE *file = fopen(argv[i], "r"); + for (size_t i = 0; i < files_n; ++i) { + char *path = input_files[i]; + FILE *file = fopen(path, "r"); if (!file) { - packbeam_internal_error("Cannot open file %s.", argv[i]); + packbeam_internal_error("Cannot open file %s.", path); return EXIT_FAILURE; } @@ -267,7 +272,7 @@ static int do_pack(int argc, char **argv, int is_archive, bool include_lines) return EXIT_FAILURE; } } else { - char *filename = basename(argv[i]); + char *filename = basename(path); pack_beam_file(pack, file_data, file_size, filename, !is_archive && i == 1, include_lines); } } @@ -385,14 +390,13 @@ static void validate_list_options(const char *filename) } } -static int do_list(int argc, char **argv) +static int do_list(const char *avm_path) { - UNUSED(argc); - validate_list_options(argv[0]); + validate_list_options(avm_path); - MappedFile *mapped_file = mapped_file_open_beam(argv[0]); + MappedFile *mapped_file = mapped_file_open_beam(avm_path); if (IS_NULL_PTR(mapped_file)) { - packbeam_internal_error("Cannot open AVM file %s.", argv[0]); + packbeam_internal_error("Cannot open AVM file %s.", avm_path); return EXIT_FAILURE; } @@ -400,7 +404,7 @@ static int do_list(int argc, char **argv) if (avmpack_is_valid(mapped_file->mapped, mapped_file->size)) { avmpack_fold(NULL, mapped_file->mapped, print_section); } else { - packbeam_error("%s is not an AVM file.", argv[1]); + packbeam_error("%s is not an AVM file.", avm_path); ret = EXIT_FAILURE; } mapped_file_close(mapped_file); From c8df447bc0eaea655761eb1bc4b8586765798e63 Mon Sep 17 00:00:00 2001 From: Jakub Gonet Date: Fri, 27 Dec 2024 00:29:25 +0100 Subject: [PATCH 05/19] Move validate close to main --- tools/packbeam/packbeam.c | 70 ++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 34 deletions(-) diff --git a/tools/packbeam/packbeam.c b/tools/packbeam/packbeam.c index a1d1c08b5..fdd6515f0 100644 --- a/tools/packbeam/packbeam.c +++ b/tools/packbeam/packbeam.c @@ -53,6 +53,8 @@ static void *uncompress_literals(const uint8_t *litT, int size, size_t *uncompre static void add_module_header(FILE *f, const char *module_name, uint32_t flags); static void pack_beam_file(FILE *pack, const uint8_t *data, size_t size, const char *filename, int is_entrypoint, bool include_lines); +static void validate_list_options(const char *filename); + static int do_pack(char *output_avm_file, char **input_files, size_t files_n, int is_archive, bool include_lines); static int do_list(const char *avm_path); @@ -135,6 +137,40 @@ int main(int argc, char **argv) return do_pack(output_avm_file, input_files, n, is_archive, include_lines); } +static void validate_list_options(const char *filename) +{ + FILE *file = fopen(filename, "r"); + if (!file) { + packbeam_error("%s does not exist.", filename); + exit(EXIT_FAILURE); + } else if (!is_avm_file(file)) { + packbeam_error("Invalid AVM file: %s.", filename); + exit(EXIT_FAILURE); + } +} + +static int do_list(const char *avm_path) +{ + validate_list_options(avm_path); + + MappedFile *mapped_file = mapped_file_open_beam(avm_path); + if (IS_NULL_PTR(mapped_file)) { + packbeam_internal_error("Cannot open AVM file %s.", avm_path); + return EXIT_FAILURE; + } + + int ret = EXIT_SUCCESS; + if (avmpack_is_valid(mapped_file->mapped, mapped_file->size)) { + avmpack_fold(NULL, mapped_file->mapped, print_section); + } else { + packbeam_error("%s is not an AVM file.", avm_path); + ret = EXIT_FAILURE; + } + mapped_file_close(mapped_file); + + return ret; +} + static void assert_fread(void *buffer, size_t size, FILE *file) { size_t r = fread(buffer, sizeof(uint8_t), size, file); @@ -378,40 +414,6 @@ static void *print_section(void *accum, const void *section_ptr, uint32_t sectio return accum; } -static void validate_list_options(const char *filename) -{ - FILE *file = fopen(filename, "r"); - if (!file) { - packbeam_error("%s does not exist.", filename); - exit(EXIT_FAILURE); - } else if (!is_avm_file(file)) { - packbeam_error("Invalid AVM file: %s.", filename); - exit(EXIT_FAILURE); - } -} - -static int do_list(const char *avm_path) -{ - validate_list_options(avm_path); - - MappedFile *mapped_file = mapped_file_open_beam(avm_path); - if (IS_NULL_PTR(mapped_file)) { - packbeam_internal_error("Cannot open AVM file %s.", avm_path); - return EXIT_FAILURE; - } - - int ret = EXIT_SUCCESS; - if (avmpack_is_valid(mapped_file->mapped, mapped_file->size)) { - avmpack_fold(NULL, mapped_file->mapped, print_section); - } else { - packbeam_error("%s is not an AVM file.", avm_path); - ret = EXIT_FAILURE; - } - mapped_file_close(mapped_file); - - return ret; -} - static void *uncompress_literals(const uint8_t *litT, int size, size_t *uncompressedSize) { unsigned int required_buf_size = READ_32_ALIGNED(litT + LITT_UNCOMPRESSED_SIZE_OFFSET); From 28fb4c1a30f9dc71e08f0dbda555e25357afe199 Mon Sep 17 00:00:00 2001 From: Jakub Gonet Date: Fri, 27 Dec 2024 00:37:13 +0100 Subject: [PATCH 06/19] Refactor do_list() --- tools/packbeam/packbeam.c | 55 ++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 30 deletions(-) diff --git a/tools/packbeam/packbeam.c b/tools/packbeam/packbeam.c index fdd6515f0..c97062906 100644 --- a/tools/packbeam/packbeam.c +++ b/tools/packbeam/packbeam.c @@ -34,6 +34,11 @@ #include "iff.c" #include "mapped_file.h" +#define TRY(expr) \ + if (!(expr)) { \ + goto cleanup; \ + } + #define LITT_UNCOMPRESSED_SIZE_OFFSET 8 #define LITT_HEADER_SIZE 12 @@ -53,8 +58,6 @@ static void *uncompress_literals(const uint8_t *litT, int size, size_t *uncompre static void add_module_header(FILE *f, const char *module_name, uint32_t flags); static void pack_beam_file(FILE *pack, const uint8_t *data, size_t size, const char *filename, int is_entrypoint, bool include_lines); -static void validate_list_options(const char *filename); - static int do_pack(char *output_avm_file, char **input_files, size_t files_n, int is_archive, bool include_lines); static int do_list(const char *avm_path); @@ -137,37 +140,38 @@ int main(int argc, char **argv) return do_pack(output_avm_file, input_files, n, is_archive, include_lines); } -static void validate_list_options(const char *filename) +static void *print_section(void *accum, const void *section_ptr, uint32_t section_size, const void *beam_ptr, uint32_t flags, const char *section_name) { - FILE *file = fopen(filename, "r"); - if (!file) { - packbeam_error("%s does not exist.", filename); - exit(EXIT_FAILURE); - } else if (!is_avm_file(file)) { - packbeam_error("Invalid AVM file: %s.", filename); - exit(EXIT_FAILURE); - } + UNUSED(section_ptr); + UNUSED(section_size); + UNUSED(beam_ptr); + printf("%s %s\n", section_name, flags & BEAM_START_FLAG ? "*" : ""); + return accum; } static int do_list(const char *avm_path) { - validate_list_options(avm_path); + int ret = EXIT_SUCCESS; + // TODO: mapped_file_open_beam prints unnecessary warnings MappedFile *mapped_file = mapped_file_open_beam(avm_path); - if (IS_NULL_PTR(mapped_file)) { - packbeam_internal_error("Cannot open AVM file %s.", avm_path); - return EXIT_FAILURE; + if (mapped_file == NULL) { + packbeam_error("Cannot open AVM file %s", avm_path); + ret = EXIT_FAILURE; + goto cleanup; } - - int ret = EXIT_SUCCESS; - if (avmpack_is_valid(mapped_file->mapped, mapped_file->size)) { - avmpack_fold(NULL, mapped_file->mapped, print_section); - } else { + if (!avmpack_is_valid(mapped_file->mapped, mapped_file->size)) { packbeam_error("%s is not an AVM file.", avm_path); ret = EXIT_FAILURE; + goto cleanup; } - mapped_file_close(mapped_file); + avmpack_fold(NULL, mapped_file->mapped, print_section); + +cleanup: + if (mapped_file != NULL) { + mapped_file_close(mapped_file); + } return ret; } @@ -405,15 +409,6 @@ static void pack_beam_file(FILE *pack, const uint8_t *data, size_t size, const c fseek(pack, end_of_module_pos, SEEK_SET); } -static void *print_section(void *accum, const void *section_ptr, uint32_t section_size, const void *beam_ptr, uint32_t flags, const char *section_name) -{ - UNUSED(section_ptr); - UNUSED(section_size); - UNUSED(beam_ptr); - printf("%s %s\n", section_name, flags & BEAM_START_FLAG ? "*" : ""); - return accum; -} - static void *uncompress_literals(const uint8_t *litT, int size, size_t *uncompressedSize) { unsigned int required_buf_size = READ_32_ALIGNED(litT + LITT_UNCOMPRESSED_SIZE_OFFSET); From 06971455ef2d9f0adf1ba0294099e2e9a238aa65 Mon Sep 17 00:00:00 2001 From: Jakub Gonet Date: Fri, 27 Dec 2024 18:34:40 +0100 Subject: [PATCH 07/19] Rewrite validate_pack_files() --- tools/packbeam/packbeam.c | 162 +++++++++++++++++++++++++++----------- 1 file changed, 116 insertions(+), 46 deletions(-) diff --git a/tools/packbeam/packbeam.c b/tools/packbeam/packbeam.c index c97062906..4cf2d6b93 100644 --- a/tools/packbeam/packbeam.c +++ b/tools/packbeam/packbeam.c @@ -34,10 +34,12 @@ #include "iff.c" #include "mapped_file.h" -#define TRY(expr) \ - if (!(expr)) { \ - goto cleanup; \ - } +#define TRY(expr) \ + do { \ + if (!(expr)) { \ + goto cleanup; \ + } \ + } while (0) #define LITT_UNCOMPRESSED_SIZE_OFFSET 8 #define LITT_HEADER_SIZE 12 @@ -58,31 +60,40 @@ static void *uncompress_literals(const uint8_t *litT, int size, size_t *uncompre static void add_module_header(FILE *f, const char *module_name, uint32_t flags); static void pack_beam_file(FILE *pack, const uint8_t *data, size_t size, const char *filename, int is_entrypoint, bool include_lines); +static void free_file_data(FileData *data); +static bool safe_read_file(const char *filename, FileData *data); +static bool safe_fread(void *buffer, size_t size, FILE *file); +static bool has_iff_header(uint8_t *data, size_t size); + static int do_pack(char *output_avm_file, char **input_files, size_t files_n, int is_archive, bool include_lines); static int do_list(const char *avm_path); -#define program_error(...) error_with_usage(argv[0], __VA_ARGS__) -#define packbeam_error(...) error_with_usage("PackBeam", __VA_ARGS__) +#define program_error(...) \ + do { \ + internal_error(argv[0], __VA_ARGS__); \ + usage(argv[0]); \ + } while (false) +#define packbeam_error(...) \ + do { \ + internal_error("PackBeam", __VA_ARGS__); \ + usage("PackBeam"); \ + } while (false) #define packbeam_internal_error(...) internal_error("PackBeam", __VA_ARGS__) static void internal_error(const char *program, const char *format, ...) { va_list format_args; va_start(format_args, format); + fprintf(stderr, "%s: ", program); - fprintf(stderr, format, format_args); + vfprintf(stderr, format, format_args); fprintf(stderr, "\n"); + va_end(format_args); } -static void error_with_usage(const char *program, const char *format, ...) +static void usage(const char *program) { - if (format != NULL) { - va_list format_args; - va_start(format_args, format); - internal_error(program, format, format_args); - va_end(format_args); - } fprintf(stderr, "\nUsage: %s [-h] [-l] []\n", program); fprintf(stderr, " -h Print this help menu.\n"); fprintf(stderr, " -i Include file and line information.\n"); @@ -100,7 +111,7 @@ int main(int argc, char **argv) while ((opt = getopt(argc, argv, "hail")) != -1) { switch (opt) { case 'h': - program_error(NULL); + usage(argv[0]); return EXIT_SUCCESS; case 'a': is_archive = true; @@ -229,48 +240,42 @@ FileData read_file_data(FILE *file) return file_data; } -static bool is_avm_file(FILE *file) -{ - FileData file_data = read_file_data(file); - bool ret = avmpack_is_valid(file_data.data, file_data.size); - free(file_data.data); - return ret; -} - -static bool is_beam_file(FILE *file) +static bool validate_pack_files(char *output_file, char **input_files, size_t files_n) { - FileData file_data = read_file_data(file); - bool ret = iff_is_valid_beam(file_data.data); - free(file_data.data); - return ret; -} + FileData file_data = (FileData){ .data = NULL, .size = 0 }; -static void validate_pack_options(char *output_file, char **input_files, size_t n) -{ - FILE *file = fopen(output_file, "r"); - if (file == NULL || !is_avm_file(file)) { - packbeam_error("Invalid AVM file: %s.", output_file); - exit(EXIT_FAILURE); + TRY(safe_read_file(output_file, &file_data)); + if (!avmpack_is_valid(file_data.data, file_data.size)) { + packbeam_error("Invalid AVM file '%s'.", output_file); + goto cleanup; } - fclose(file); + free_file_data(&file_data); - for (size_t i = 0; i < n; ++i) { + for (size_t i = 0; i < files_n; ++i) { const char *filename = input_files[i]; - FILE *file = fopen(filename, "r"); - if (!file) { - packbeam_error("%s does not exist.", filename); - exit(EXIT_FAILURE); - } else if (!is_avm_file(file) && !is_beam_file(file)) { - packbeam_error("Invalid AVM or BEAM file: %s.", filename); - exit(EXIT_FAILURE); + TRY(safe_read_file(filename, &file_data)); + + bool is_valid_avm = avmpack_is_valid(file_data.data, file_data.size); + bool is_valid_beam = has_iff_header(file_data.data, file_data.size); + if (!(is_valid_avm || is_valid_beam)) { + printf("ZZZ: %i, %i\n", is_valid_avm, is_valid_beam); + packbeam_error("Invalid AVM or BEAM file '%s'.", filename); + goto cleanup; } - fclose(file); + + free_file_data(&file_data); } + + return true; + +cleanup: + free_file_data(&file_data); + return false; } static int do_pack(char *output_avm_file, char **input_files, size_t files_n, int is_archive, bool include_lines) { - validate_pack_options(output_avm_file, input_files, files_n); + validate_pack_files(output_avm_file, input_files, files_n); FILE *pack = fopen(output_avm_file, "w"); if (!pack) { @@ -463,3 +468,68 @@ static void add_module_header(FILE *f, const char *module_name, uint32_t flags) assert_fwrite(module_name, strlen(module_name) + 1, f); pad_and_align(f); } + +static bool has_iff_header(uint8_t *data, size_t size) +{ + return size >= 4 && iff_is_valid_beam(data); +} + +static void free_file_data(FileData *data) +{ + if (data->data != NULL) { + free(data->data); + } + data->data = NULL; + data->size = 0; +} + +static bool safe_fread(void *buffer, size_t size, FILE *file) +{ + size_t r = fread(buffer, sizeof(uint8_t), size, file); + if (r != size) { + packbeam_internal_error("Unable to read, wanted to read %zu bytes, read %zu bytes.", size, r); + return false; + } + return true; +} + +static bool safe_read_file(const char *filename, FileData *file_data) +{ + FILE *file = NULL; + uint8_t *data = NULL; + *file_data = (FileData){ .data = NULL, .size = 0 }; + + file = fopen(filename, "r"); + if (file == NULL) { + packbeam_internal_error("Cannot open file '%s'.", filename); + goto cleanup; + } + + TRY(fseek(file, 0, SEEK_END) == 0); + long size = ftell(file); + if (size == -1L) { + goto cleanup; + } + TRY(fseek(file, 0, SEEK_SET) == 0); + + data = malloc(size); + if (data == NULL) { + goto cleanup; + } + + TRY(safe_fread(data, size, file)); + TRY(fclose(file) == 0); + + *file_data = (FileData){ + .data = data, + .size = size + }; + return true; + +cleanup: + if (file != NULL) { + fclose(file); + } + free(data); + return false; +} \ No newline at end of file From 94857b9abc02bd7f07e6bd5f78d6018eb703ca07 Mon Sep 17 00:00:00 2001 From: Jakub Gonet Date: Fri, 27 Dec 2024 18:40:24 +0100 Subject: [PATCH 08/19] Do not use cleanup label for return value --- tools/packbeam/packbeam.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tools/packbeam/packbeam.c b/tools/packbeam/packbeam.c index 4cf2d6b93..a9284ca7f 100644 --- a/tools/packbeam/packbeam.c +++ b/tools/packbeam/packbeam.c @@ -162,28 +162,26 @@ static void *print_section(void *accum, const void *section_ptr, uint32_t sectio static int do_list(const char *avm_path) { - int ret = EXIT_SUCCESS; // TODO: mapped_file_open_beam prints unnecessary warnings MappedFile *mapped_file = mapped_file_open_beam(avm_path); if (mapped_file == NULL) { packbeam_error("Cannot open AVM file %s", avm_path); - ret = EXIT_FAILURE; goto cleanup; } if (!avmpack_is_valid(mapped_file->mapped, mapped_file->size)) { packbeam_error("%s is not an AVM file.", avm_path); - ret = EXIT_FAILURE; goto cleanup; } avmpack_fold(NULL, mapped_file->mapped, print_section); + return EXIT_SUCCESS; cleanup: if (mapped_file != NULL) { mapped_file_close(mapped_file); } - return ret; + return EXIT_FAILURE; } static void assert_fread(void *buffer, size_t size, FILE *file) From d791549994e113021fe0d5acf2d06ef58e7a2cc9 Mon Sep 17 00:00:00 2001 From: Jakub Gonet Date: Fri, 27 Dec 2024 18:41:27 +0100 Subject: [PATCH 09/19] Remove old read_file_data() --- tools/packbeam/packbeam.c | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/tools/packbeam/packbeam.c b/tools/packbeam/packbeam.c index a9284ca7f..02c3ad93e 100644 --- a/tools/packbeam/packbeam.c +++ b/tools/packbeam/packbeam.c @@ -219,25 +219,6 @@ static void *pack_beam_fun(void *accum, const void *section_ptr, uint32_t sectio return accum; } -FileData read_file_data(FILE *file) -{ - fseek(file, 0, SEEK_END); - size_t size = ftell(file); - fseek(file, 0, SEEK_SET); - uint8_t *data = malloc(size); - if (!data) { - packbeam_internal_error("Unable to allocate %zu bytes.", size); - exit(EXIT_FAILURE); - } - assert_fread(data, size, file); - - FileData file_data = { - .data = data, - .size = size - }; - return file_data; -} - static bool validate_pack_files(char *output_file, char **input_files, size_t files_n) { FileData file_data = (FileData){ .data = NULL, .size = 0 }; From 96326f94212b76848c40455b459a0e0e596d0a42 Mon Sep 17 00:00:00 2001 From: Jakub Gonet Date: Fri, 27 Dec 2024 19:07:22 +0100 Subject: [PATCH 10/19] Replace read file loop in do_file with safe_read_file() --- tools/packbeam/packbeam.c | 60 +++++++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 25 deletions(-) diff --git a/tools/packbeam/packbeam.c b/tools/packbeam/packbeam.c index 02c3ad93e..97b5adfc9 100644 --- a/tools/packbeam/packbeam.c +++ b/tools/packbeam/packbeam.c @@ -63,6 +63,7 @@ static void pack_beam_file(FILE *pack, const uint8_t *data, size_t size, const c static void free_file_data(FileData *data); static bool safe_read_file(const char *filename, FileData *data); static bool safe_fread(void *buffer, size_t size, FILE *file); +static bool safe_fwrite(const void *buffer, size_t size, FILE *file); static bool has_iff_header(uint8_t *data, size_t size); static int do_pack(char *output_avm_file, char **input_files, size_t files_n, int is_archive, bool include_lines); @@ -162,9 +163,10 @@ static void *print_section(void *accum, const void *section_ptr, uint32_t sectio static int do_list(const char *avm_path) { - + MappedFile *mapped_file = NULL; // TODO: mapped_file_open_beam prints unnecessary warnings - MappedFile *mapped_file = mapped_file_open_beam(avm_path); + mapped_file = mapped_file_open_beam(avm_path); + if (mapped_file == NULL) { packbeam_error("Cannot open AVM file %s", avm_path); goto cleanup; @@ -254,12 +256,16 @@ static bool validate_pack_files(char *output_file, char **input_files, size_t fi static int do_pack(char *output_avm_file, char **input_files, size_t files_n, int is_archive, bool include_lines) { - validate_pack_files(output_avm_file, input_files, files_n); + FILE *pack = NULL; + FileData file_data = (FileData){ .data = NULL, .size = 0 }; + + TRY(validate_pack_files(output_avm_file, input_files, files_n)); - FILE *pack = fopen(output_avm_file, "w"); - if (!pack) { + // TODO: having any error corrupts output file + pack = fopen(output_avm_file, "w"); + if (pack == NULL) { packbeam_internal_error("Cannot open output file for writing %s.", output_avm_file); - return EXIT_FAILURE; + goto cleanup; } const unsigned char pack_header[24] = { @@ -270,34 +276,20 @@ static int do_pack(char *output_avm_file, char **input_files, size_t files_n, in 0x74, 0x6f, 0x6d, 0x56, 0x4d, 0x0a, 0x00, 0x00 }; - assert_fwrite(pack_header, 24, pack); + TRY(safe_fwrite(pack_header, 24, pack)); for (size_t i = 0; i < files_n; ++i) { char *path = input_files[i]; - FILE *file = fopen(path, "r"); - if (!file) { - packbeam_internal_error("Cannot open file %s.", path); - return EXIT_FAILURE; - } - - fseek(file, 0, SEEK_END); - size_t file_size = ftell(file); - fseek(file, 0, SEEK_SET); + TRY(safe_read_file(path, &file_data)); - uint8_t *file_data = malloc(file_size); - if (!file_data) { - packbeam_internal_error("Unable to allocate %zu bytes\n", file_size); - return EXIT_FAILURE; - } - assert_fread(file_data, file_size, file); - if (avmpack_is_valid(file_data, file_size)) { - void *result = avmpack_fold(pack, file_data, pack_beam_fun); + if (avmpack_is_valid(file_data.data, file_data.size)) { + void *result = avmpack_fold(pack, file_data.data, pack_beam_fun); if (result == NULL) { return EXIT_FAILURE; } } else { char *filename = basename(path); - pack_beam_file(pack, file_data, file_size, filename, !is_archive && i == 1, include_lines); + pack_beam_file(pack, file_data.data, file_data.size, filename, !is_archive && i == 1, include_lines); } } @@ -305,6 +297,13 @@ static int do_pack(char *output_avm_file, char **input_files, size_t files_n, in fclose(pack); return EXIT_SUCCESS; + +cleanup: + if (pack != NULL) { + fclose(pack); + } + free_file_data(&file_data); + return EXIT_FAILURE; } static void pack_beam_file(FILE *pack, const uint8_t *data, size_t size, const char *section_name, int is_entrypoint, bool include_lines) @@ -472,10 +471,21 @@ static bool safe_fread(void *buffer, size_t size, FILE *file) return true; } +static bool safe_fwrite(const void *buffer, size_t size, FILE *file) +{ + size_t r = fwrite(buffer, 1, size, file); + if (r != size) { + packbeam_internal_error("Unable to write, wanted to write %zu bytes, wrote %zu bytes.", size, r); + return false; + } + return true; +} + static bool safe_read_file(const char *filename, FileData *file_data) { FILE *file = NULL; uint8_t *data = NULL; + *file_data = (FileData){ .data = NULL, .size = 0 }; file = fopen(filename, "r"); From 71862657a8c9d4962e11ae0194a5fc7f6a8fc5b0 Mon Sep 17 00:00:00 2001 From: Jakub Gonet Date: Fri, 27 Dec 2024 19:13:06 +0100 Subject: [PATCH 11/19] Simplify do_pack() --- tools/packbeam/packbeam.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/tools/packbeam/packbeam.c b/tools/packbeam/packbeam.c index 97b5adfc9..05ad81235 100644 --- a/tools/packbeam/packbeam.c +++ b/tools/packbeam/packbeam.c @@ -282,15 +282,18 @@ static int do_pack(char *output_avm_file, char **input_files, size_t files_n, in char *path = input_files[i]; TRY(safe_read_file(path, &file_data)); - if (avmpack_is_valid(file_data.data, file_data.size)) { - void *result = avmpack_fold(pack, file_data.data, pack_beam_fun); - if (result == NULL) { - return EXIT_FAILURE; - } + // TODO: redundant, we have this information in validate_pack_files + bool is_avm = avmpack_is_valid(file_data.data, file_data.size); + + if (is_avm) { + TRY(avmpack_fold(pack, file_data.data, pack_beam_fun) != NULL); } else { + bool is_first = i == 0; + bool is_entrypoint = !is_archive && is_first; char *filename = basename(path); - pack_beam_file(pack, file_data.data, file_data.size, filename, !is_archive && i == 1, include_lines); + pack_beam_file(pack, file_data.data, file_data.size, filename, is_entrypoint, include_lines); } + free_file_data(&file_data); } add_module_header(pack, "end", END_OF_FILE); From c0655598e932a05c7db0adf32a992decd62becc5 Mon Sep 17 00:00:00 2001 From: Jakub Gonet Date: Fri, 27 Dec 2024 19:13:23 +0100 Subject: [PATCH 12/19] Remove assert_fread() --- tools/packbeam/packbeam.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/tools/packbeam/packbeam.c b/tools/packbeam/packbeam.c index 05ad81235..c6eb6fe75 100644 --- a/tools/packbeam/packbeam.c +++ b/tools/packbeam/packbeam.c @@ -186,15 +186,6 @@ static int do_list(const char *avm_path) return EXIT_FAILURE; } -static void assert_fread(void *buffer, size_t size, FILE *file) -{ - size_t r = fread(buffer, sizeof(uint8_t), size, file); - if (r != size) { - packbeam_internal_error("Unable to read, wanted to read %zu bytes, read %zu bytes.", size, r); - exit(EXIT_FAILURE); - } -} - static void assert_fwrite(const void *buffer, size_t size, FILE *file) { size_t r = fwrite(buffer, 1, size, file); From 1745571a736f90aa42b65c8d395d48dfdf5c8e9f Mon Sep 17 00:00:00 2001 From: Jakub Gonet Date: Fri, 27 Dec 2024 19:20:44 +0100 Subject: [PATCH 13/19] Rewrite pack_beam_file() --- tools/packbeam/packbeam.c | 70 ++++++++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 26 deletions(-) diff --git a/tools/packbeam/packbeam.c b/tools/packbeam/packbeam.c index c6eb6fe75..be37bf9a3 100644 --- a/tools/packbeam/packbeam.c +++ b/tools/packbeam/packbeam.c @@ -58,7 +58,7 @@ typedef struct FileData static void pad_and_align(FILE *f); static void *uncompress_literals(const uint8_t *litT, int size, size_t *uncompressedSize); static void add_module_header(FILE *f, const char *module_name, uint32_t flags); -static void pack_beam_file(FILE *pack, const uint8_t *data, size_t size, const char *filename, int is_entrypoint, bool include_lines); +static bool pack_beam_file(FILE *pack, const uint8_t *data, size_t size, const char *filename, int is_entrypoint, bool include_lines); static void free_file_data(FileData *data); static bool safe_read_file(const char *filename, FileData *data); @@ -282,7 +282,7 @@ static int do_pack(char *output_avm_file, char **input_files, size_t files_n, in bool is_first = i == 0; bool is_entrypoint = !is_archive && is_first; char *filename = basename(path); - pack_beam_file(pack, file_data.data, file_data.size, filename, is_entrypoint, include_lines); + TRY(pack_beam_file(pack, file_data.data, file_data.size, filename, is_entrypoint, include_lines)); } free_file_data(&file_data); } @@ -300,9 +300,14 @@ static int do_pack(char *output_avm_file, char **input_files, size_t files_n, in return EXIT_FAILURE; } -static void pack_beam_file(FILE *pack, const uint8_t *data, size_t size, const char *section_name, int is_entrypoint, bool include_lines) +static bool pack_beam_file(FILE *pack, const uint8_t *data, size_t size, const char *section_name, int is_entrypoint, bool include_lines) { - size_t zero_pos = ftell(pack); + void *deflated = NULL; + + long zero_pos = ftell(pack); + if (zero_pos == -1) { + goto cleanup; + } if (is_entrypoint) { add_module_header(pack, section_name, BEAM_CODE_FLAG | BEAM_START_FLAG); @@ -310,80 +315,93 @@ static void pack_beam_file(FILE *pack, const uint8_t *data, size_t size, const c add_module_header(pack, section_name, BEAM_CODE_FLAG); } - int written_beam_header_pos = ftell(pack); + long written_beam_header_pos = ftell(pack); + if (written_beam_header_pos == -1) { + goto cleanup; + } const unsigned char beam_header[12] = { 0x46, 0x4f, 0x52, 0x31, 0x00, 0x00, 0x00, 0x00, 0x42, 0x45, 0x41, 0x4d }; - assert_fwrite(beam_header, 12, pack); + TRY(safe_fwrite(beam_header, 12, pack)); unsigned long offsets[MAX_OFFS]; unsigned long sizes[MAX_SIZES]; scan_iff(data, size, offsets, sizes); if (offsets[AT8U]) { - assert_fwrite(data + offsets[AT8U], sizes[AT8U] + IFF_SECTION_HEADER_SIZE, pack); + TRY(safe_fwrite(data + offsets[AT8U], sizes[AT8U] + IFF_SECTION_HEADER_SIZE, pack)); pad_and_align(pack); } if (offsets[CODE]) { - assert_fwrite(data + offsets[CODE], sizes[CODE] + IFF_SECTION_HEADER_SIZE, pack); + TRY(safe_fwrite(data + offsets[CODE], sizes[CODE] + IFF_SECTION_HEADER_SIZE, pack)); pad_and_align(pack); } if (offsets[EXPT]) { - assert_fwrite(data + offsets[EXPT], sizes[EXPT] + IFF_SECTION_HEADER_SIZE, pack); + TRY(safe_fwrite(data + offsets[EXPT], sizes[EXPT] + IFF_SECTION_HEADER_SIZE, pack)); pad_and_align(pack); } if (offsets[LOCT]) { - assert_fwrite(data + offsets[LOCT], sizes[LOCT] + IFF_SECTION_HEADER_SIZE, pack); + TRY(safe_fwrite(data + offsets[LOCT], sizes[LOCT] + IFF_SECTION_HEADER_SIZE, pack)); pad_and_align(pack); } if (offsets[IMPT]) { - assert_fwrite(data + offsets[IMPT], sizes[IMPT] + IFF_SECTION_HEADER_SIZE, pack); + TRY(safe_fwrite(data + offsets[IMPT], sizes[IMPT] + IFF_SECTION_HEADER_SIZE, pack)); pad_and_align(pack); } if (offsets[LITU]) { - assert_fwrite(data + offsets[LITU], sizes[LITU] + IFF_SECTION_HEADER_SIZE, pack); + TRY(safe_fwrite(data + offsets[LITU], sizes[LITU] + IFF_SECTION_HEADER_SIZE, pack)); pad_and_align(pack); } if (offsets[FUNT]) { - assert_fwrite(data + offsets[FUNT], sizes[FUNT] + IFF_SECTION_HEADER_SIZE, pack); + TRY(safe_fwrite(data + offsets[FUNT], sizes[FUNT] + IFF_SECTION_HEADER_SIZE, pack)); pad_and_align(pack); } if (offsets[STRT]) { - assert_fwrite(data + offsets[STRT], sizes[STRT] + IFF_SECTION_HEADER_SIZE, pack); + TRY(safe_fwrite(data + offsets[STRT], sizes[STRT] + IFF_SECTION_HEADER_SIZE, pack)); pad_and_align(pack); } if (offsets[LINT] && include_lines) { - assert_fwrite(data + offsets[LINT], sizes[LINT] + IFF_SECTION_HEADER_SIZE, pack); + TRY(safe_fwrite(data + offsets[LINT], sizes[LINT] + IFF_SECTION_HEADER_SIZE, pack)); pad_and_align(pack); } if (offsets[LITT]) { size_t u_size; - void *deflated = uncompress_literals(data + offsets[LITT], sizes[LITT], &u_size); - assert_fwrite("LitU", 4, pack); + deflated = uncompress_literals(data + offsets[LITT], sizes[LITT], &u_size); + TRY(safe_fwrite("LitU", 4, pack)); uint32_t size_field = ENDIAN_SWAP_32(u_size); - assert_fwrite(&size_field, sizeof(size_field), pack); - assert_fwrite(deflated, u_size, pack); + TRY(safe_fwrite(&size_field, sizeof(size_field), pack)); + TRY(safe_fwrite(deflated, u_size, pack)); free(deflated); } pad_and_align(pack); - size_t end_of_module_pos = ftell(pack); + long end_of_module_pos = ftell(pack); + if (end_of_module_pos == -1) { + goto cleanup; + } size_t rsize = end_of_module_pos - zero_pos; uint32_t size_field = ENDIAN_SWAP_32(rsize); - fseek(pack, zero_pos, SEEK_SET); - assert_fwrite(&size_field, sizeof(uint32_t), pack); - fseek(pack, end_of_module_pos, SEEK_SET); + TRY(fseek(pack, zero_pos, SEEK_SET) != -1); + TRY(safe_fwrite(&size_field, sizeof(uint32_t), pack)); + TRY(fseek(pack, end_of_module_pos, SEEK_SET) != -1); int beam_written_size = end_of_module_pos - written_beam_header_pos; uint32_t beam_written_size_field = ENDIAN_SWAP_32(beam_written_size); - fseek(pack, written_beam_header_pos + 4, SEEK_SET); - assert_fwrite(&beam_written_size_field, sizeof(uint32_t), pack); - fseek(pack, end_of_module_pos, SEEK_SET); + TRY(fseek(pack, written_beam_header_pos + 4, SEEK_SET) != -1); + TRY(safe_fwrite(&beam_written_size_field, sizeof(uint32_t), pack)); + TRY(fseek(pack, end_of_module_pos, SEEK_SET) != -1); + + return true; + +cleanup: + free(deflated); + + return false; } static void *uncompress_literals(const uint8_t *litT, int size, size_t *uncompressedSize) From 94deadad20ee97ebafa01e7dc988cc49f644cf27 Mon Sep 17 00:00:00 2001 From: Jakub Gonet Date: Fri, 27 Dec 2024 19:23:36 +0100 Subject: [PATCH 14/19] Refator add_module_header() --- tools/packbeam/packbeam.c | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/tools/packbeam/packbeam.c b/tools/packbeam/packbeam.c index be37bf9a3..0e3f5b428 100644 --- a/tools/packbeam/packbeam.c +++ b/tools/packbeam/packbeam.c @@ -57,7 +57,7 @@ typedef struct FileData static void pad_and_align(FILE *f); static void *uncompress_literals(const uint8_t *litT, int size, size_t *uncompressedSize); -static void add_module_header(FILE *f, const char *module_name, uint32_t flags); +static bool add_module_header(FILE *f, const char *module_name, uint32_t flags); static bool pack_beam_file(FILE *pack, const uint8_t *data, size_t size, const char *filename, int is_entrypoint, bool include_lines); static void free_file_data(FileData *data); @@ -186,15 +186,6 @@ static int do_list(const char *avm_path) return EXIT_FAILURE; } -static void assert_fwrite(const void *buffer, size_t size, FILE *file) -{ - size_t r = fwrite(buffer, 1, size, file); - if (r != size) { - packbeam_internal_error("Unable to write, wanted to write %zu bytes, wrote %zu bytes.", size, r); - exit(EXIT_FAILURE); - } -} - static void *pack_beam_fun(void *accum, const void *section_ptr, uint32_t section_size, const void *beam_ptr, uint32_t flags, const char *section_name) { UNUSED(beam_ptr); @@ -287,7 +278,7 @@ static int do_pack(char *output_avm_file, char **input_files, size_t files_n, in free_file_data(&file_data); } - add_module_header(pack, "end", END_OF_FILE); + TRY(add_module_header(pack, "end", END_OF_FILE)); fclose(pack); return EXIT_SUCCESS; @@ -310,9 +301,9 @@ static bool pack_beam_file(FILE *pack, const uint8_t *data, size_t size, const c } if (is_entrypoint) { - add_module_header(pack, section_name, BEAM_CODE_FLAG | BEAM_START_FLAG); + TRY(add_module_header(pack, section_name, BEAM_CODE_FLAG | BEAM_START_FLAG)); } else { - add_module_header(pack, section_name, BEAM_CODE_FLAG); + TRY(add_module_header(pack, section_name, BEAM_CODE_FLAG)); } long written_beam_header_pos = ftell(pack); @@ -446,17 +437,22 @@ static void pad_and_align(FILE *f) } } -static void add_module_header(FILE *f, const char *module_name, uint32_t flags) +static bool add_module_header(FILE *f, const char *module_name, uint32_t flags) { uint32_t size_field = 0; uint32_t flags_field = ENDIAN_SWAP_32(flags); uint32_t reserved = 0; - assert_fwrite(&size_field, sizeof(uint32_t), f); - assert_fwrite(&flags_field, sizeof(uint32_t), f); - assert_fwrite(&reserved, sizeof(uint32_t), f); - assert_fwrite(module_name, strlen(module_name) + 1, f); + TRY(safe_fwrite(&size_field, sizeof(uint32_t), f)); + TRY(safe_fwrite(&flags_field, sizeof(uint32_t), f)); + TRY(safe_fwrite(&reserved, sizeof(uint32_t), f)); + TRY(safe_fwrite(module_name, strlen(module_name) + 1, f)); pad_and_align(f); + + return true; + +cleanup: + return false; } static bool has_iff_header(uint8_t *data, size_t size) From 4eb1b92b08e8725487f525a57056c2b056e63564 Mon Sep 17 00:00:00 2001 From: Jakub Gonet Date: Fri, 27 Dec 2024 19:24:11 +0100 Subject: [PATCH 15/19] Remove debug log --- tools/packbeam/packbeam.c | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/packbeam/packbeam.c b/tools/packbeam/packbeam.c index 0e3f5b428..b92fb7b38 100644 --- a/tools/packbeam/packbeam.c +++ b/tools/packbeam/packbeam.c @@ -221,7 +221,6 @@ static bool validate_pack_files(char *output_file, char **input_files, size_t fi bool is_valid_avm = avmpack_is_valid(file_data.data, file_data.size); bool is_valid_beam = has_iff_header(file_data.data, file_data.size); if (!(is_valid_avm || is_valid_beam)) { - printf("ZZZ: %i, %i\n", is_valid_avm, is_valid_beam); packbeam_error("Invalid AVM or BEAM file '%s'.", filename); goto cleanup; } From bda6cd4f3da164369c016165d5cf0b6440714e60 Mon Sep 17 00:00:00 2001 From: Jakub Gonet Date: Fri, 27 Dec 2024 19:35:03 +0100 Subject: [PATCH 16/19] Refactor uncompress_literals() --- tools/packbeam/packbeam.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/tools/packbeam/packbeam.c b/tools/packbeam/packbeam.c index b92fb7b38..373cb2686 100644 --- a/tools/packbeam/packbeam.c +++ b/tools/packbeam/packbeam.c @@ -318,6 +318,7 @@ static bool pack_beam_file(FILE *pack, const uint8_t *data, size_t size, const c unsigned long offsets[MAX_OFFS]; unsigned long sizes[MAX_SIZES]; + // TODO: add error handling in scan_iff scan_iff(data, size, offsets, sizes); if (offsets[AT8U]) { @@ -360,6 +361,9 @@ static bool pack_beam_file(FILE *pack, const uint8_t *data, size_t size, const c if (offsets[LITT]) { size_t u_size; deflated = uncompress_literals(data + offsets[LITT], sizes[LITT], &u_size); + if (deflated == NULL) { + goto cleanup; + } TRY(safe_fwrite("LitU", 4, pack)); uint32_t size_field = ENDIAN_SWAP_32(u_size); TRY(safe_fwrite(&size_field, sizeof(size_field), pack)); @@ -396,37 +400,47 @@ static bool pack_beam_file(FILE *pack, const uint8_t *data, size_t size, const c static void *uncompress_literals(const uint8_t *litT, int size, size_t *uncompressedSize) { + uint8_t *outbuf = NULL; + z_stream infstream; + + *uncompressedSize = 0; + unsigned int required_buf_size = READ_32_ALIGNED(litT + LITT_UNCOMPRESSED_SIZE_OFFSET); - uint8_t *outBuf = malloc(required_buf_size); - if (!outBuf) { + outbuf = malloc(required_buf_size); + if (outbuf == NULL) { packbeam_internal_error("Cannot allocate temporary buffer of size %u.", required_buf_size); - AVM_ABORT(); + goto cleanup; } - z_stream infstream; infstream.zalloc = Z_NULL; infstream.zfree = Z_NULL; infstream.opaque = Z_NULL; infstream.avail_in = (uInt) (size - IFF_SECTION_HEADER_SIZE); infstream.next_in = (Bytef *) (litT + LITT_HEADER_SIZE); infstream.avail_out = (uInt) required_buf_size; - infstream.next_out = (Bytef *) outBuf; + infstream.next_out = (Bytef *) outbuf; int ret = inflateInit(&infstream); if (ret != Z_OK) { packbeam_internal_error("Failed inflateInit."); - AVM_ABORT(); + goto cleanup; } ret = inflate(&infstream, Z_NO_FLUSH); if (ret != Z_OK) { packbeam_internal_error("Failed inflate."); - AVM_ABORT(); + goto cleanup; } inflateEnd(&infstream); *uncompressedSize = required_buf_size; - return outBuf; + return outbuf; + +cleanup: + free(outbuf); + inflateEnd(&infstream); + + return NULL; } static void pad_and_align(FILE *f) From 353d8dbc85bc50b4f8409e0dd29ab99316c7125d Mon Sep 17 00:00:00 2001 From: Jakub Gonet Date: Fri, 27 Dec 2024 19:39:55 +0100 Subject: [PATCH 17/19] Rewrite pad_and_align() --- tools/packbeam/packbeam.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/tools/packbeam/packbeam.c b/tools/packbeam/packbeam.c index 373cb2686..aa9e0d289 100644 --- a/tools/packbeam/packbeam.c +++ b/tools/packbeam/packbeam.c @@ -55,7 +55,7 @@ typedef struct FileData size_t size; } FileData; -static void pad_and_align(FILE *f); +static bool pad_and_align(FILE *f); static void *uncompress_literals(const uint8_t *litT, int size, size_t *uncompressedSize); static bool add_module_header(FILE *f, const char *module_name, uint32_t flags); static bool pack_beam_file(FILE *pack, const uint8_t *data, size_t size, const char *filename, int is_entrypoint, bool include_lines); @@ -443,11 +443,25 @@ static void *uncompress_literals(const uint8_t *litT, int size, size_t *uncompre return NULL; } -static void pad_and_align(FILE *f) +static bool pad_and_align(FILE *f) { - while ((ftell(f) % 4) != 0) { - fputc(0, f); + while (true) { + long pos = ftell(f); + if (pos == -1L) { + goto cleanup; + } + + bool aligned = pos % 4 == 0; + if (aligned) { + break; + } + + TRY(fputc(0, f) != EOF); } + return true; + +cleanup: + return false; } static bool add_module_header(FILE *f, const char *module_name, uint32_t flags) From 1462e0c892fb06b8bc00c4ed0700dc02a8435d48 Mon Sep 17 00:00:00 2001 From: Jakub Gonet Date: Fri, 27 Dec 2024 19:42:30 +0100 Subject: [PATCH 18/19] Use safe pad_and_align() and deinit zstream --- tools/packbeam/packbeam.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/tools/packbeam/packbeam.c b/tools/packbeam/packbeam.c index aa9e0d289..0288f6fb3 100644 --- a/tools/packbeam/packbeam.c +++ b/tools/packbeam/packbeam.c @@ -323,39 +323,39 @@ static bool pack_beam_file(FILE *pack, const uint8_t *data, size_t size, const c if (offsets[AT8U]) { TRY(safe_fwrite(data + offsets[AT8U], sizes[AT8U] + IFF_SECTION_HEADER_SIZE, pack)); - pad_and_align(pack); + TRY(pad_and_align(pack)); } if (offsets[CODE]) { TRY(safe_fwrite(data + offsets[CODE], sizes[CODE] + IFF_SECTION_HEADER_SIZE, pack)); - pad_and_align(pack); + TRY(pad_and_align(pack)); } if (offsets[EXPT]) { TRY(safe_fwrite(data + offsets[EXPT], sizes[EXPT] + IFF_SECTION_HEADER_SIZE, pack)); - pad_and_align(pack); + TRY(pad_and_align(pack)); } if (offsets[LOCT]) { TRY(safe_fwrite(data + offsets[LOCT], sizes[LOCT] + IFF_SECTION_HEADER_SIZE, pack)); - pad_and_align(pack); + TRY(pad_and_align(pack)); } if (offsets[IMPT]) { TRY(safe_fwrite(data + offsets[IMPT], sizes[IMPT] + IFF_SECTION_HEADER_SIZE, pack)); - pad_and_align(pack); + TRY(pad_and_align(pack)); } if (offsets[LITU]) { TRY(safe_fwrite(data + offsets[LITU], sizes[LITU] + IFF_SECTION_HEADER_SIZE, pack)); - pad_and_align(pack); + TRY(pad_and_align(pack)); } if (offsets[FUNT]) { TRY(safe_fwrite(data + offsets[FUNT], sizes[FUNT] + IFF_SECTION_HEADER_SIZE, pack)); - pad_and_align(pack); + TRY(pad_and_align(pack)); } if (offsets[STRT]) { TRY(safe_fwrite(data + offsets[STRT], sizes[STRT] + IFF_SECTION_HEADER_SIZE, pack)); - pad_and_align(pack); + TRY(pad_and_align(pack)); } if (offsets[LINT] && include_lines) { TRY(safe_fwrite(data + offsets[LINT], sizes[LINT] + IFF_SECTION_HEADER_SIZE, pack)); - pad_and_align(pack); + TRY(pad_and_align(pack)); } if (offsets[LITT]) { @@ -371,7 +371,7 @@ static bool pack_beam_file(FILE *pack, const uint8_t *data, size_t size, const c free(deflated); } - pad_and_align(pack); + TRY(pad_and_align(pack)); long end_of_module_pos = ftell(pack); if (end_of_module_pos == -1) { @@ -401,6 +401,7 @@ static bool pack_beam_file(FILE *pack, const uint8_t *data, size_t size, const c static void *uncompress_literals(const uint8_t *litT, int size, size_t *uncompressedSize) { uint8_t *outbuf = NULL; + bool stream_init = false; z_stream infstream; *uncompressedSize = 0; @@ -426,6 +427,7 @@ static void *uncompress_literals(const uint8_t *litT, int size, size_t *uncompre packbeam_internal_error("Failed inflateInit."); goto cleanup; } + stream_init = true; ret = inflate(&infstream, Z_NO_FLUSH); if (ret != Z_OK) { packbeam_internal_error("Failed inflate."); @@ -438,7 +440,9 @@ static void *uncompress_literals(const uint8_t *litT, int size, size_t *uncompre cleanup: free(outbuf); - inflateEnd(&infstream); + if (stream_init) { + inflateEnd(&infstream); + } return NULL; } @@ -474,7 +478,7 @@ static bool add_module_header(FILE *f, const char *module_name, uint32_t flags) TRY(safe_fwrite(&flags_field, sizeof(uint32_t), f)); TRY(safe_fwrite(&reserved, sizeof(uint32_t), f)); TRY(safe_fwrite(module_name, strlen(module_name) + 1, f)); - pad_and_align(f); + TRY(pad_and_align(f)); return true; From afd99e29fa506a5ef2bf21782acc72e4c961a079 Mon Sep 17 00:00:00 2001 From: Jakub Gonet Date: Fri, 27 Dec 2024 19:48:08 +0100 Subject: [PATCH 19/19] Reorganize imports, readd WITH_ZLIB --- tools/packbeam/packbeam.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/tools/packbeam/packbeam.c b/tools/packbeam/packbeam.c index 0288f6fb3..52c2b10a2 100644 --- a/tools/packbeam/packbeam.c +++ b/tools/packbeam/packbeam.c @@ -25,10 +25,9 @@ #include #include -// TODO: Remove this when the code is refactored -// #ifdef WITH_ZLIB +#ifdef WITH_ZLIB #include -// #endif +#endif #include "avmpack.h" #include "iff.c" @@ -58,13 +57,13 @@ typedef struct FileData static bool pad_and_align(FILE *f); static void *uncompress_literals(const uint8_t *litT, int size, size_t *uncompressedSize); static bool add_module_header(FILE *f, const char *module_name, uint32_t flags); -static bool pack_beam_file(FILE *pack, const uint8_t *data, size_t size, const char *filename, int is_entrypoint, bool include_lines); - -static void free_file_data(FileData *data); -static bool safe_read_file(const char *filename, FileData *data); +static bool pack_beam_file(FILE *pack, const uint8_t *data, size_t size, const char *section_name, int is_entrypoint, bool include_lines); +static bool has_iff_header(uint8_t *data, size_t size); static bool safe_fread(void *buffer, size_t size, FILE *file); static bool safe_fwrite(const void *buffer, size_t size, FILE *file); -static bool has_iff_header(uint8_t *data, size_t size); + +static bool safe_read_file(const char *filename, FileData *file_data); +static void free_file_data(FileData *data); static int do_pack(char *output_avm_file, char **input_files, size_t files_n, int is_archive, bool include_lines); static int do_list(const char *avm_path); @@ -397,7 +396,7 @@ static bool pack_beam_file(FILE *pack, const uint8_t *data, size_t size, const c return false; } - +#ifdef WITH_ZLIB static void *uncompress_literals(const uint8_t *litT, int size, size_t *uncompressedSize) { uint8_t *outbuf = NULL; @@ -446,6 +445,17 @@ static void *uncompress_literals(const uint8_t *litT, int size, size_t *uncompre return NULL; } +#else +static void *uncompress_literals(const uint8_t *litT, int size, size_t *uncompressedSize) +{ + UNUSED(litT); + UNUSED(size); + UNUSED(uncompressedSize); + packbeam_internal_error("ZLIB not available."); + return NULL; +} + +#endif // WITH_ZLIB static bool pad_and_align(FILE *f) {