From d09468cc6b82c15cbbcfdaaf910d28104e94090c Mon Sep 17 00:00:00 2001 From: samsonium Date: Mon, 19 Oct 2026 17:50:31 +0300 Subject: [PATCH 1/5] fix: critical fixes for newer compiler versions - Add token check before parsing statement or program - Fix program freeing --- CMakeLists.txt | 2 +- src/compiler/fzl_parser.c | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f25345b..db0aab3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 4.3) +cmake_minimum_required(VERSION 3.16) project(fz-lang LANGUAGES C) diff --git a/src/compiler/fzl_parser.c b/src/compiler/fzl_parser.c index 5e403c0..b7c9b9f 100644 --- a/src/compiler/fzl_parser.c +++ b/src/compiler/fzl_parser.c @@ -959,6 +959,9 @@ fzl_node_t *parse_block(fzl_parser_t *parser) // Statement parsing fzl_node_t *parse_statement(fzl_parser_t *parser) { + if (!peek(parser)) + return NULL; + fzl_node_t *res = NULL; if (is(parser, FZL_TOKTYPE_CLASS)) @@ -990,6 +993,9 @@ fzl_node_t *parse_statement(fzl_parser_t *parser) // Internal parsing entry point fzl_node_t *parse_program(fzl_parser_t *parser) { + if (!peek(parser)) + return NULL; + fzl_node_t *first = NULL; fzl_node_t *last = NULL; fzl_node_t *node = NULL; @@ -1023,6 +1029,8 @@ fzl_node_t *parse_program(fzl_parser_t *parser) // Parse tokens and build AST int fzl_parse(fzl_parser_t *parser) { + last_known_tok = NULL; + fzl_node_t *ast = parse_program(parser); if (!ast) return -1; @@ -1121,8 +1129,9 @@ void fzl_freeast(fzl_node_t *root) fzl_freenode(root->memb.parent); } - root = root->next; + fzl_node_t *next = root->next; free(root); + root = root->next; } } From 04b367e7a027f237199b20f243c62ac4339adc88 Mon Sep 17 00:00:00 2001 From: samsonium Date: Mon, 19 Oct 2026 18:39:40 +0300 Subject: [PATCH 2/5] fix: warnings fix (after -Wall -Wextra) --- CMakeLists.txt | 6 +++ include/compiler/utils/fzl_const_pool.h | 8 ++-- src/compiler/fzl_debug.c | 1 - src/compiler/fzl_parser.c | 28 ++++++-------- src/compiler/fzl_reader.c | 2 +- src/compiler/fzl_walker.c | 9 ++--- src/compiler/utils/fzl_const_pool.c | 50 ++++++++++++------------- src/compiler/utils/fzl_linked.c | 4 +- src/compiler/utils/fzl_options.c | 4 +- src/vm/fzl_vm.c | 11 +++++- src/vm/fzl_vm_env.c | 2 - src/vm/main.c | 2 +- 12 files changed, 66 insertions(+), 61 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index db0aab3..f5a00e5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,12 @@ project(fz-lang LANGUAGES C) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +add_compile_options(-Wall -Wextra -Werror=implicit-function-declaration) + +if (CMAKE_BUILD_TYPE STREQUAL "Debug") + add_compile_options(-fsanitize=address,undefined -g) + add_link_options(-fsanitize=address,undefined) +endif() include_directories(include) diff --git a/include/compiler/utils/fzl_const_pool.h b/include/compiler/utils/fzl_const_pool.h index 0d1b128..f2f3b99 100644 --- a/include/compiler/utils/fzl_const_pool.h +++ b/include/compiler/utils/fzl_const_pool.h @@ -4,12 +4,12 @@ #include #include #include +#include // Constant types typedef enum { FZL_CONSTTYPE_STRING, - FZL_CONSTTYPE_NUMBER } fzl_consttype_t; // Constant descriptor @@ -34,7 +34,7 @@ typedef struct typedef struct { - size_t pool_index; + ssize_t pool_index; } fzl_const_hash_slot_t; // Constant pool descriptor @@ -53,13 +53,13 @@ typedef struct bool fzl_consts_equal(fzl_const_t a, fzl_const_t b); // Get hash of specified constant -static uint32_t fzl_hash_const(fzl_const_t c); +uint32_t fzl_hash_const(fzl_const_t c); // Allocate constants hash pool fzl_const_hash_pool_t *fzl_mkconstpool(); // Resize the hash table -static void fzl_consts_pool_resize_hash(fzl_const_hash_pool_t *pool); +void fzl_consts_pool_resize_hash(fzl_const_hash_pool_t *pool); // Push constant. Returns unique index size_t fzl_consts_pool_add(fzl_const_hash_pool_t *pool, fzl_const_t c); diff --git a/src/compiler/fzl_debug.c b/src/compiler/fzl_debug.c index 2a78659..cbab185 100644 --- a/src/compiler/fzl_debug.c +++ b/src/compiler/fzl_debug.c @@ -27,7 +27,6 @@ void print_node(fzl_node_t *node, int level) if (!node) return; - size_t lvllen = print_level(levelbuf, level); strcpy(printbuf, levelbuf); switch (node->type) diff --git a/src/compiler/fzl_parser.c b/src/compiler/fzl_parser.c index b7c9b9f..5ce31bc 100644 --- a/src/compiler/fzl_parser.c +++ b/src/compiler/fzl_parser.c @@ -56,19 +56,6 @@ static fzl_token_t *peek(fzl_parser_t *parser) return parser->cursor->token; } -// Get token at (cursor + 1) -static fzl_token_t *next(fzl_parser_t *parser) -{ - if (!parser || !parser->cursor) - return NULL; - - fzl_reader_ll_t *next = parser->cursor->next; - if (!next) - return NULL; - - return next->token; -} - // Consume token at cursor and move to the next static fzl_token_t *consume(fzl_parser_t *parser) { @@ -204,8 +191,7 @@ fzl_node_t *parse_postfix(fzl_parser_t *parser) if (!parser) return NULL; - fzl_node_t *left = parse_primary(parser); - fzl_node_t *right = NULL; + fzl_node_t *left = parse_primary(parser); if (!left) { @@ -766,7 +752,15 @@ fzl_node_t *parse_function(fzl_parser_t *parser) if (!parser) return NULL; - fzl_token_t *fn = consume(parser); + fzl_token_t *fn = consume(parser); + if (fn->type != FZL_TOKTYPE_FUNCTION) + { + snprintf(plast_err, sizeof(plast_err), + "'%s': expected keyword 'fn' at %ld:%ld", last_known_tok->filename, + last_known_tok->ln, last_known_tok->cn); + return NULL; + } + fzl_token_t *name = consume(parser); if (!name || name->type != FZL_TOKTYPE_NAME) { @@ -1131,7 +1125,7 @@ void fzl_freeast(fzl_node_t *root) fzl_node_t *next = root->next; free(root); - root = root->next; + root = next; } } diff --git a/src/compiler/fzl_reader.c b/src/compiler/fzl_reader.c index 683fb3f..9f5cc70 100644 --- a/src/compiler/fzl_reader.c +++ b/src/compiler/fzl_reader.c @@ -313,7 +313,7 @@ int fzl_read(fzl_reader_t *reader) token = add_single(reader, FZL_TOKTYPE_PERCENT); else if (curr == '=') token = add_single(reader, FZL_TOKTYPE_EQ); - else if (curr >= 'A' && curr <= 'Z' || curr >= 'a' && curr <= 'z' || + else if ((curr >= 'A' && curr <= 'Z') || (curr >= 'a' && curr <= 'z') || curr == '_') token = parse_name(reader); else if (curr >= '0' && curr <= '9') diff --git a/src/compiler/fzl_walker.c b/src/compiler/fzl_walker.c index a99af45..0875399 100644 --- a/src/compiler/fzl_walker.c +++ b/src/compiler/fzl_walker.c @@ -64,7 +64,7 @@ fzl_walker_t *fzl_mkwalker(fzl_node_t *root) // --- Walking zone --- // Convert type token to `fzl_type_t` -const fzl_type_t tok_to_type(fzl_token_t *tok) +fzl_type_t tok_to_type(fzl_token_t *tok) { if (tok->type == FZL_TOKTYPE_NAME) return FZL_TYPE_OBJECT; @@ -403,7 +403,7 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node) } // NOTE: add sym_top limit check - size_t lvl = walker->sym_top; + ssize_t lvl = walker->sym_top; walker->syms[walker->sym_top++] = fzl_mksymt(); fzl_walk_ctx_t *newctx = nest_ctx(walker, FZL_WALK_CTX_TYPE_FN); @@ -939,7 +939,6 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node) } else if (node->token->type == FZL_TOKTYPE_NULL_LITERAL) { - fzl_token_t *tok = node->token; push_op(walker, FZL_OPCODE_PUSHNUM); push_word(walker, 0); push_op(walker, FZL_OPCODE_DEREFERENCE); @@ -1145,7 +1144,7 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node) if (obj_res.error) return obj_res; - fzl_ctable_t *ct; + fzl_ctable_t *ct = NULL; for (size_t i = 0; i < walker->classes_count; i++) { if (strcmp(obj_res.classname, walker->classes[i]->name) == 0) @@ -1164,7 +1163,7 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node) return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; } - fzl_ctable_field_t *ctf; + fzl_ctable_field_t *ctf = NULL; for (size_t i = 0; i < ct->fields_count; i++) { if (strcmp(field_node->memb.field->token->value, diff --git a/src/compiler/utils/fzl_const_pool.c b/src/compiler/utils/fzl_const_pool.c index 39c4c28..e2dbbe6 100644 --- a/src/compiler/utils/fzl_const_pool.c +++ b/src/compiler/utils/fzl_const_pool.c @@ -11,31 +11,31 @@ bool fzl_consts_equal(fzl_const_t a, fzl_const_t b) switch (a.type) { - case FZL_CONSTTYPE_STRING: - { - if (a.as.string.length != b.as.string.length) - return false; + case FZL_CONSTTYPE_STRING: + { + if (a.as.string.length != b.as.string.length) + return false; - return memcmp(a.as.string.chars, b.as.string.chars, a.as.string.length) == - 0; - } + return memcmp(a.as.string.chars, b.as.string.chars, a.as.string.length) == + 0; + } } return false; } -static uint32_t fzl_hash_const(fzl_const_t c) +uint32_t fzl_hash_const(fzl_const_t c) { - uint32_t hash = 2166136261u; + uint32_t hash = 2166136261u; const uint8_t *data = NULL; - size_t size = 0; + size_t size = 0; switch (c.type) { - case FZL_CONSTTYPE_STRING: - data = (const uint8_t *)c.as.string.chars; - size = c.as.string.length; - break; + case FZL_CONSTTYPE_STRING: + data = (const uint8_t *)c.as.string.chars; + size = c.as.string.length; + break; } for (size_t i = 0; i < size; i++) @@ -51,27 +51,27 @@ fzl_const_hash_pool_t *fzl_mkconstpool() { fzl_const_hash_pool_t *pool = malloc(sizeof(fzl_const_hash_pool_t)); - pool->size = 0; + pool->size = 0; pool->capacity = 8; - pool->array = malloc(pool->capacity * sizeof(fzl_const_t)); + pool->array = malloc(pool->capacity * sizeof(fzl_const_t)); - pool->slots_count = 0; + pool->slots_count = 0; pool->slots_capacity = 16; pool->slots = malloc(pool->slots_capacity * sizeof(fzl_const_hash_slot_t)); - for (int i = 0; i < pool->slots_capacity; i++) + for (size_t i = 0; i < pool->slots_capacity; i++) pool->slots[i].pool_index = -1; return pool; } -static void fzl_consts_pool_resize_hash(fzl_const_hash_pool_t *pool) +void fzl_consts_pool_resize_hash(fzl_const_hash_pool_t *pool) { - int old_capacity = pool->slots_capacity; + int old_capacity = pool->slots_capacity; fzl_const_hash_slot_t *old_slots = pool->slots; pool->slots_capacity = old_capacity * 2; pool->slots = malloc(pool->slots_capacity * sizeof(fzl_const_hash_slot_t)); - for (int i = 0; i < pool->slots_capacity; i++) + for (size_t i = 0; i < pool->slots_capacity; i++) pool->slots[i].pool_index = -1; pool->slots_count = 0; @@ -81,8 +81,8 @@ static void fzl_consts_pool_resize_hash(fzl_const_hash_pool_t *pool) continue; int index_in_pool = old_slots[i].pool_index; - fzl_const_t c = pool->array[index_in_pool]; - uint32_t hash = fzl_hash_const(c); + fzl_const_t c = pool->array[index_in_pool]; + uint32_t hash = fzl_hash_const(c); uint32_t bucket = hash & (pool->slots_capacity - 1); while (pool->slots[bucket].pool_index != -1) @@ -100,7 +100,7 @@ size_t fzl_consts_pool_add(fzl_const_hash_pool_t *pool, fzl_const_t c) if (pool->slots_count * 4 >= pool->slots_capacity * 3) fzl_consts_pool_resize_hash(pool); - uint32_t hash = fzl_hash_const(c); + uint32_t hash = fzl_hash_const(c); uint32_t bucket = hash & (pool->slots_capacity - 1); while (pool->slots[bucket].pool_index != -1) @@ -119,7 +119,7 @@ size_t fzl_consts_pool_add(fzl_const_hash_pool_t *pool, fzl_const_t c) pool->capacity * sizeof(fzl_const_t)); } - size_t new_index = pool->size; + size_t new_index = pool->size; pool->array[new_index] = c; pool->size++; diff --git a/src/compiler/utils/fzl_linked.c b/src/compiler/utils/fzl_linked.c index f7414eb..feb2887 100644 --- a/src/compiler/utils/fzl_linked.c +++ b/src/compiler/utils/fzl_linked.c @@ -72,9 +72,9 @@ bool fzl_linked_add_files(fzl_linked_t *l, char **files, size_t files_count) .end = current_start + file_sz - 1}; if (!l->source) - l->source = malloc(file_sz); + l->source = malloc(file_sz + 1); else - l->source = realloc(l->source, current_start + file_sz); + l->source = realloc(l->source, current_start + file_sz + 1); if (!l->source) { diff --git a/src/compiler/utils/fzl_options.c b/src/compiler/utils/fzl_options.c index 4060189..e91ab29 100644 --- a/src/compiler/utils/fzl_options.c +++ b/src/compiler/utils/fzl_options.c @@ -35,7 +35,7 @@ fzl_options_t *fzl_mkoptions(int argc, char **argv) return opts; } - size_t i; + int i; for (i = 1; i < argc; i++) { if (argv[i][0] != '-') @@ -108,7 +108,7 @@ fzl_options_t *fzl_mkoptions(int argc, char **argv) { printf("%sError%s: flags should go before source files list.\n", FZL_CERROR, FZL_CRST); - printf("Remain %zu arguments are not handled.\n", argc - 1 - i); + printf("Remain %d arguments are not handled.\n", argc - 1 - i); free(files); free(opts); diff --git a/src/vm/fzl_vm.c b/src/vm/fzl_vm.c index 3b13ee7..4dcce34 100644 --- a/src/vm/fzl_vm.c +++ b/src/vm/fzl_vm.c @@ -650,8 +650,17 @@ int fzl_vm_run(fzl_vm_t *vm) break; case FZL_OPCODE_JMP: - vm->ip = vm->ops[++vm->ip] - 1; + { + if (vm->ops_count >= vm->ip) + { + snprintf(last_err, sizeof(last_err), + "runtime error - expected JMP addr"); + return -1; + } + uint64_t jmp_ip = vm->ops[++vm->ip]; + vm->ip = jmp_ip - 1; break; + } case FZL_OPCODE_AND: if (vm->dtop < 2) diff --git a/src/vm/fzl_vm_env.c b/src/vm/fzl_vm_env.c index a7c98e6..533dc4b 100644 --- a/src/vm/fzl_vm_env.c +++ b/src/vm/fzl_vm_env.c @@ -7,8 +7,6 @@ #include #include -static const fzl_value_t null = {.type = FZL_TYPE_NULL}; - fzl_vm_env_t *fzl_mkenv() { fzl_vm_env_t *env = malloc(sizeof(fzl_vm_env_t)); diff --git a/src/vm/main.c b/src/vm/main.c index 55c85d4..cb357c0 100644 --- a/src/vm/main.c +++ b/src/vm/main.c @@ -33,7 +33,7 @@ run_args_t *parse_args(int argc, char **argv) args->help = false; args->debug = false; - for (size_t i = 0; i < argc; i++) + for (int i = 0; i < argc; i++) { if (argv[i][0] != '-') continue; From 1289f6c1508f5162e26d7f438d15d16706814c55 Mon Sep 17 00:00:00 2001 From: samsonium Date: Mon, 19 Oct 2026 19:41:39 +0300 Subject: [PATCH 3/5] fix: sanitizer checks fix (iteration 1) --- src/compiler/fzl_parser.c | 192 ++++++++++++++++++++------------ src/compiler/fzl_reader.c | 13 ++- src/compiler/fzl_token.c | 13 ++- src/compiler/fzl_walker.c | 3 + src/compiler/utils/fzl_linked.c | 1 + src/vm/fzl_vm.c | 19 +++- src/vm/main.c | 11 +- 7 files changed, 167 insertions(+), 85 deletions(-) diff --git a/src/compiler/fzl_parser.c b/src/compiler/fzl_parser.c index 5ce31bc..9bf96c5 100644 --- a/src/compiler/fzl_parser.c +++ b/src/compiler/fzl_parser.c @@ -9,6 +9,16 @@ char plast_err[256]; fzl_token_t *last_known_tok = NULL; +fzl_token_t null_tok = { + .type = FZL_TOKTYPE_TYPE, + .filename = "", + .ln = 0, + .cn = 0, + .store_value = true, + .value = "null", + .value_sz = 4, +}; + fzl_parser_t *fzl_mkparser(fzl_reader_ll_t *first) { if (!first) @@ -35,6 +45,7 @@ fzl_parser_t *fzl_mkparser(fzl_reader_ll_t *first) fzl_node_t *fzl_mknode(fzl_nodetype_t type, fzl_token_t *token) { fzl_node_t *node = malloc(sizeof(fzl_node_t)); + memset(node, 0, sizeof(fzl_node_t)); if (!node) return NULL; @@ -226,7 +237,7 @@ fzl_node_t *parse_postfix(fzl_parser_t *parser) if (args_capacity <= args_count) { args_capacity *= 2; - args = realloc(args, args_capacity * sizeof(fzl_node_t)); + args = realloc(args, args_capacity * sizeof(fzl_node_t *)); } args[args_count] = arg; @@ -700,9 +711,19 @@ fzl_node_t *parse_class(fzl_parser_t *parser) } } - fzl_node_t **new_args = realloc(node->fn.args, ++node->fn.args_count); - memcpy(&new_args[1], new_args, - (node->fn.args_count - 1) * sizeof(fzl_node_t *)); + fzl_node_t **new_args = realloc(node->fn.args, (++node->fn.args_count) * + sizeof(fzl_node_t *)); + if (!new_args) + { + snprintf(plast_err, sizeof(plast_err), + "failed to reallocate method args list"); + free(fields); + return NULL; + } + + if (node->fn.args_count > 1) + memmove(&new_args[1], new_args, + (node->fn.args_count - 1) * sizeof(fzl_node_t *)); fzl_token_t *this_tok = fzl_mktoken(FZL_TOKTYPE_NAME, node->fn.name->ln, node->fn.name->cn, @@ -713,6 +734,7 @@ fzl_node_t *parse_class(fzl_parser_t *parser) this_dec->var.identifier = this_id; new_args[0] = this_dec; + node->fn.args = new_args; methods[mcount++] = node; } else @@ -814,8 +836,7 @@ fzl_node_t *parse_function(fzl_parser_t *parser) type = consume(parser); if (!type) - type = fzl_mktoken(FZL_TOKTYPE_TYPE, last_known_tok->ln, last_known_tok->cn, - "null", 4, last_known_tok->filename); + type = &null_tok; if (!is(parser, FZL_TOKTYPE_LBRACE)) { @@ -1051,80 +1072,105 @@ void fzl_freeast(fzl_node_t *root) while (root) { - if (root->type == FZL_NODETYPE_BLOCK) + switch (root->type) { - if (root->list.entries) - { - for (size_t i = 0; i < root->list.entry_count; i++) - if (root->list.entries[i]) - fzl_freeast(root->list.entries[i]); + case FZL_NODETYPE_IDENTIFIER: + case FZL_NODETYPE_LITERAL: + break; - free(root->list.entries); - } - } - else if (root->type == FZL_NODETYPE_CALL) - { - if (root->call.args_count) - { - for (size_t i = 0; i < root->call.args_count; i++) - if (root->call.args[i]) - fzl_freeast(root->call.args[i]); + case FZL_NODETYPE_BLOCK: + if (root->list.entries) + { + for (size_t i = 0; i < root->list.entry_count; i++) + if (root->list.entries[i]) + fzl_freeast(root->list.entries[i]); - free(root->call.args); - } - } - else if (root->type == FZL_NODETYPE_ADD || root->type == FZL_NODETYPE_SUB || - root->type == FZL_NODETYPE_MUL || root->type == FZL_NODETYPE_DIV || - root->type == FZL_NODETYPE_POW || root->type == FZL_NODETYPE_MOD) - { - if (root->binary_op.left) - fzl_freeast(root->binary_op.left); - if (root->binary_op.right) - fzl_freeast(root->binary_op.right); - } - else if (root->type == FZL_NODETYPE_UNARY_PLUS || - root->type == FZL_NODETYPE_UNARY_MINUS) - { - if (root->unary_op.operand) - fzl_freeast(root->unary_op.operand); - } - else if (root->type == FZL_NODETYPE_FUNCTION) - { - if (root->fn.args_count) - for (size_t i = 0; i < root->fn.args_count; i++) - fzl_freenode(root->fn.args[i]); - free(root->fn.args); - fzl_freenode(root->fn.body); - } - else if (root->type == FZL_NODETYPE_RETURN) - { - if (root->ret.value) - fzl_freenode(root->ret.value); - } - else if (root->type == FZL_NODETYPE_CLASS) - { - if (root->class.fields_count) - for (size_t i = 0; i < root->class.fields_count; i++) - fzl_freenode(root->class.fields[i]); - free(root->class.fields); + free(root->list.entries); + } + break; - if (root->class.methods_count) - for (size_t i = 0; i < root->class.methods_count; i++) - fzl_freenode(root->class.methods[i]); - free(root->class.methods); - } - else if (root->type == FZL_NODETYPE_CONSTRUCT) - { - fzl_freenode(root->construct.name); - } - else if (root->type == FZL_NODETYPE_FIELD) - { - fzl_freenode(root->memb.field); - fzl_freenode(root->memb.parent); + case FZL_NODETYPE_CALL: + if (root->call.args_count) + { + for (size_t i = 0; i < root->call.args_count; i++) + if (root->call.args[i]) + fzl_freeast(root->call.args[i]); + + free(root->call.args); + } + break; + + case FZL_NODETYPE_ADD: + case FZL_NODETYPE_SUB: + case FZL_NODETYPE_MUL: + case FZL_NODETYPE_DIV: + case FZL_NODETYPE_POW: + case FZL_NODETYPE_MOD: + case FZL_NODETYPE_CONDITIONAL: + case FZL_NODETYPE_OR: + case FZL_NODETYPE_AND: + case FZL_NODETYPE_EQUAL: + case FZL_NODETYPE_NEQUAL: + case FZL_NODETYPE_LESS: + case FZL_NODETYPE_LESS_EQUAL: + case FZL_NODETYPE_GREATER: + case FZL_NODETYPE_GREATER_EQUAL: + case FZL_NODETYPE_ASSIGN: + if (root->binary_op.left) + fzl_freeast(root->binary_op.left); + if (root->binary_op.right) + fzl_freeast(root->binary_op.right); + break; + + case FZL_NODETYPE_UNARY_PLUS: + case FZL_NODETYPE_UNARY_MINUS: + case FZL_NODETYPE_NOT: + if (root->unary_op.operand) + fzl_freeast(root->unary_op.operand); + break; + + case FZL_NODETYPE_FUNCTION: + if (root->fn.args_count) + for (size_t i = 0; i < root->fn.args_count; i++) + fzl_freeast(root->fn.args[i]); + free(root->fn.args); + fzl_freeast(root->fn.body); + break; + + case FZL_NODETYPE_RETURN: + if (root->ret.value) + fzl_freeast(root->ret.value); + break; + + case FZL_NODETYPE_CLASS: + if (root->class.fields_count) + for (size_t i = 0; i < root->class.fields_count; i++) + fzl_freeast(root->class.fields[i]); + free(root->class.fields); + + if (root->class.methods_count) + for (size_t i = 0; i < root->class.methods_count; i++) + fzl_freeast(root->class.methods[i]); + free(root->class.methods); + break; + + case FZL_NODETYPE_CONSTRUCT: + fzl_freeast(root->construct.name); + break; + + case FZL_NODETYPE_FIELD: + fzl_freeast(root->memb.field); + fzl_freeast(root->memb.parent); + break; + + case FZL_NODETYPE_DECLARATION: + if (root->var.identifier) + fzl_freeast(root->var.identifier); + break; } fzl_node_t *next = root->next; - free(root); + fzl_freenode(root); root = next; } } diff --git a/src/compiler/fzl_reader.c b/src/compiler/fzl_reader.c index 9f5cc70..540d29c 100644 --- a/src/compiler/fzl_reader.c +++ b/src/compiler/fzl_reader.c @@ -204,31 +204,31 @@ fzl_token_t *parse_number(fzl_reader_t *reader) // Add single-char token fzl_token_t *add_single(fzl_reader_t *reader, fzl_toktype_t type) { - size_t p = move(reader, 1); fzl_file_loc l; - bool ok = fzl_linked_getpos(reader->linked, p, &l); + bool ok = fzl_linked_getpos(reader->linked, reader->position, &l); if (!ok) { snprintf(last_err, sizeof(last_err), "failed to locate line:col"); return NULL; } - return fzl_mktoken(type, l.line, l.col, NULL, 0, l.filename); + move(reader, 1); + return fzl_mktoken(type, l.line, l.col, "", 0, l.filename); } // Add double-char token fzl_token_t *add_double(fzl_reader_t *reader, fzl_toktype_t type) { - size_t p = move(reader, 2); fzl_file_loc l; - bool ok = fzl_linked_getpos(reader->linked, p, &l); + bool ok = fzl_linked_getpos(reader->linked, reader->position, &l); if (!ok) { snprintf(last_err, sizeof(last_err), "failed to locate line:col"); return NULL; } - return fzl_mktoken(type, l.line, l.col, NULL, 0, l.filename); + move(reader, 2); + return fzl_mktoken(type, l.line, l.col, "", 0, l.filename); } // Skip symbols until '\n' or EOF @@ -353,6 +353,7 @@ int fzl_read(fzl_reader_t *reader) } fzl_reader_ll_t *tok_node = malloc(sizeof(fzl_reader_ll_t)); + tok_node->next = NULL; tok_node->token = token; reader->last->next = tok_node; diff --git a/src/compiler/fzl_token.c b/src/compiler/fzl_token.c index 8ba49a7..dc62955 100644 --- a/src/compiler/fzl_token.c +++ b/src/compiler/fzl_token.c @@ -6,15 +6,20 @@ fzl_token_t *fzl_mktoken(const fzl_toktype_t type, size_t line, size_t col, void *value, size_t value_len, char *filename) { - char *valholder = malloc(value_len + 1); - memcpy(valholder, value, value_len); - valholder[value_len] = '\0'; + char *valholder = NULL; + + if (value && value_len > 0) + { + valholder = malloc(value_len + 1); + memcpy(valholder, value, value_len); + valholder[value_len] = '\0'; + } fzl_token_t *token = malloc(sizeof(fzl_token_t)); token->type = type; token->ln = line; token->cn = col; - token->store_value = value_len > 0; + token->store_value = (valholder != NULL); token->value = valholder; token->value_sz = value_len; token->filename = filename; diff --git a/src/compiler/fzl_walker.c b/src/compiler/fzl_walker.c index 0875399..d4442f9 100644 --- a/src/compiler/fzl_walker.c +++ b/src/compiler/fzl_walker.c @@ -246,6 +246,9 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node) strcpy((method_name + classname_len + 1), fn->fn.name->value); method_name[classname_len + fnname_len + 1] = 0; + if (fn->fn.name->value) + free(fn->fn.name->value); + fn->fn.name->value = method_name; fzl_walk_res_t fnres = walk(walker, fn); if (fnres.error) diff --git a/src/compiler/utils/fzl_linked.c b/src/compiler/utils/fzl_linked.c index feb2887..409455b 100644 --- a/src/compiler/utils/fzl_linked.c +++ b/src/compiler/utils/fzl_linked.c @@ -86,6 +86,7 @@ bool fzl_linked_add_files(fzl_linked_t *l, char **files, size_t files_count) } strcpy(l->source + current_start, source); + free(source); current_start += file_sz; } diff --git a/src/vm/fzl_vm.c b/src/vm/fzl_vm.c index 4dcce34..9cc73c3 100644 --- a/src/vm/fzl_vm.c +++ b/src/vm/fzl_vm.c @@ -42,6 +42,7 @@ fzl_vm_t *fzl_mkvm(const char *filepath) if (!fd) { snprintf(last_err, sizeof(last_err), "failed to open file '%s'", filepath); + free(vm); return NULL; } @@ -50,6 +51,8 @@ fzl_vm_t *fzl_mkvm(const char *filepath) if (memcmp(hdr, expect_hdr, 5) != 0) { snprintf(last_err, sizeof(last_err), "magic check error"); + fclose(fd); + free(vm); return NULL; } @@ -60,6 +63,8 @@ fzl_vm_t *fzl_mkvm(const char *filepath) if (ops_count < 1) { snprintf(last_err, sizeof(last_err), "there is nothing to do (0 ops)"); + fclose(fd); + free(vm); return NULL; } @@ -89,6 +94,9 @@ fzl_vm_t *fzl_mkvm(const char *filepath) } else { + fclose(fd); + free(vm->consts); + free(vm); snprintf(last_err, sizeof(last_err), "unknown const type at index %ld", i); return NULL; @@ -104,6 +112,7 @@ fzl_vm_t *fzl_mkvm(const char *filepath) fread(&op, sizeof(uint64_t), 1, fd); vm->ops[i] = op; } + fclose(fd); return vm; } @@ -732,6 +741,14 @@ int fzl_vm_run(fzl_vm_t *vm) } } + if (wrlvl <= -1) + { + snprintf(last_err, sizeof(last_err), + "runtime error - name '%s' not found in this scope", wrname); + print_err_data(vm); + return -1; + } + fzl_vm_env_wresult_t wresult = fzl_env_writevalue(vm->estack[wrlvl], (char *)wrname, value); if (wresult != FZL_VM_ENV_WRESULT_OK) @@ -825,7 +842,7 @@ int fzl_vm_run(fzl_vm_t *vm) else if (fn_id == FZL_BUILTIN_EXIT) { fzl_value_t arg = vm->dstack[--vm->dtop]; - exit(arg.as.i); + return arg.as.i; } else { diff --git a/src/vm/main.c b/src/vm/main.c index cb357c0..7551e1c 100644 --- a/src/vm/main.c +++ b/src/vm/main.c @@ -49,6 +49,7 @@ run_args_t *parse_args(int argc, char **argv) { printf("Error: unknown flag '%s'.\n", argv[i]); printf("Use 'fz --help' to read the usage\n"); + free(args); return NULL; } } @@ -57,6 +58,7 @@ run_args_t *parse_args(int argc, char **argv) { printf("Error: last argument MUST be a file path\n"); printf("Use 'fz --help' for help\n"); + free(args); return NULL; } @@ -73,6 +75,7 @@ int main(int argc, char **argv) else if (args->help) { print_hint(); + free(args); return 0; } @@ -80,6 +83,7 @@ int main(int argc, char **argv) if (!vm) { printf("Error: %s\n", fzl_vm_geterror()); + free(args); return -1; } @@ -90,7 +94,12 @@ int main(int argc, char **argv) int result = fzl_vm_run(vm); if (result != 0) { - printf("Error: %s\n", fzl_vm_geterror()); + char *err = fzl_vm_geterror(); + if (err && err[0]) + printf("Error: %s\n", err); + + free(args); + fzl_freevm(vm); return -1; } } From 3f2f03f931512dc6533750da99120a00a31f5e95 Mon Sep 17 00:00:00 2001 From: samsonium Date: Mon, 19 Oct 2026 19:54:11 +0300 Subject: [PATCH 4/5] fix: sanitizer checks fix (iteration 2) --- src/compiler/fzl_parser.c | 34 ++++++++++++++++++++++++++-------- src/vm/fzl_vm.c | 5 ++++- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/compiler/fzl_parser.c b/src/compiler/fzl_parser.c index 9bf96c5..e2d93b9 100644 --- a/src/compiler/fzl_parser.c +++ b/src/compiler/fzl_parser.c @@ -14,11 +14,19 @@ fzl_token_t null_tok = { .filename = "", .ln = 0, .cn = 0, - .store_value = true, + .store_value = false, .value = "null", .value_sz = 4, }; +fzl_token_t this_tok = {.type = FZL_TOKTYPE_NAME, + .filename = "", + .ln = 0, + .cn = 0, + .store_value = false, + .value = "this", + .value_sz = 4}; + fzl_parser_t *fzl_mkparser(fzl_reader_ll_t *first) { if (!first) @@ -725,10 +733,7 @@ fzl_node_t *parse_class(fzl_parser_t *parser) memmove(&new_args[1], new_args, (node->fn.args_count - 1) * sizeof(fzl_node_t *)); - fzl_token_t *this_tok = - fzl_mktoken(FZL_TOKTYPE_NAME, node->fn.name->ln, node->fn.name->cn, - "this", 4, node->fn.name->filename); - fzl_node_t *this_id = fzl_mknode(FZL_NODETYPE_IDENTIFIER, this_tok); + fzl_node_t *this_id = fzl_mknode(FZL_NODETYPE_IDENTIFIER, &this_tok); fzl_node_t *this_dec = fzl_mknode(FZL_NODETYPE_DECLARATION, name); this_dec->var.type = name; this_dec->var.identifier = this_id; @@ -1090,14 +1095,28 @@ void fzl_freeast(fzl_node_t *root) break; case FZL_NODETYPE_CALL: + if (root->call.callee) + fzl_freeast(root->call.callee); + if (root->call.args_count) { for (size_t i = 0; i < root->call.args_count; i++) if (root->call.args[i]) fzl_freeast(root->call.args[i]); - - free(root->call.args); } + if (root->call.args) + free(root->call.args); + break; + + case FZL_NODETYPE_CONDITIONAL: + if (root->cond.condition) + fzl_freeast(root->cond.condition); + + if (root->cond.true_block) + fzl_freeast(root->cond.true_block); + + if (root->cond.else_block) + fzl_freeast(root->cond.else_block); break; case FZL_NODETYPE_ADD: @@ -1106,7 +1125,6 @@ void fzl_freeast(fzl_node_t *root) case FZL_NODETYPE_DIV: case FZL_NODETYPE_POW: case FZL_NODETYPE_MOD: - case FZL_NODETYPE_CONDITIONAL: case FZL_NODETYPE_OR: case FZL_NODETYPE_AND: case FZL_NODETYPE_EQUAL: diff --git a/src/vm/fzl_vm.c b/src/vm/fzl_vm.c index 9cc73c3..07827f8 100644 --- a/src/vm/fzl_vm.c +++ b/src/vm/fzl_vm.c @@ -660,7 +660,7 @@ int fzl_vm_run(fzl_vm_t *vm) case FZL_OPCODE_JMP: { - if (vm->ops_count >= vm->ip) + if (vm->ops_count <= vm->ip) { snprintf(last_err, sizeof(last_err), "runtime error - expected JMP addr"); @@ -1011,6 +1011,9 @@ void fzl_freevm(fzl_vm_t *vm) if (!vm) return; + while (vm->etop > 0) + fzl_freeenv(vm->estack[--vm->etop]); + for (size_t i = 0; i < vm->consts_count; i++) { if (vm->consts[i].type == FZL_CONSTTYPE_STRING) From 1e518c4c82211613b8752e92d41eca8205e8fe29 Mon Sep 17 00:00:00 2001 From: samsonium Date: Mon, 19 Oct 2026 20:11:48 +0300 Subject: [PATCH 5/5] fix: sanitizer checks fix (iteration 3 - final) --- src/compiler/main.c | 28 ++++++++++++++++++++++++++++ src/vm/fzl_vm.c | 4 ++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/compiler/main.c b/src/compiler/main.c index 305a83c..d6b534b 100644 --- a/src/compiler/main.c +++ b/src/compiler/main.c @@ -15,9 +15,15 @@ int main(int argc, char **argv) { fzl_options_t *opts = fzl_mkoptions(argc, argv); if (!opts) + { + fzl_freeoptions(opts); return -1; + } else if (!opts->should_continue) + { + fzl_freeoptions(opts); return 0; + } if (opts->verbose) printf("%s> analyze\n-> reading file...%s", FZL_CDEBUG, FZL_CRST); @@ -28,6 +34,8 @@ int main(int argc, char **argv) char *lasterr = fzl_linked_geterror(); if (lasterr[0]) printf("%sError%s: %s\n", FZL_CERROR, FZL_CRST, lasterr); + fzl_freeoptions(opts); + fzl_freelinked(linked); return -1; } @@ -38,6 +46,8 @@ int main(int argc, char **argv) char *lasterr = fzl_linked_geterror(); if (lasterr[0]) printf("%sError%s: %s\n", FZL_CERROR, FZL_CRST, lasterr); + fzl_freeoptions(opts); + fzl_freelinked(linked); return -1; } @@ -53,6 +63,9 @@ int main(int argc, char **argv) if (result != 0) { printf("%sError%s: %s\n", FZL_CERROR, FZL_CRST, fzl_reader_geterror()); + fzl_freeoptions(opts); + fzl_freelinked(linked); + fzl_freereader(rd); return -1; } @@ -87,6 +100,10 @@ int main(int argc, char **argv) if (result != 0) { printf("%sError%s: %s\n", FZL_CERROR, FZL_CRST, fzl_parser_geterror()); + fzl_freeoptions(opts); + fzl_freeparser(parser); + fzl_freereader(rd); + fzl_freelinked(linked); return -1; } @@ -103,6 +120,11 @@ int main(int argc, char **argv) if (result != 0) { printf("%sError%s: %s\n", FZL_CERROR, FZL_CRST, fzl_walker_geterror()); + fzl_freeoptions(opts); + fzl_freewalker(walker); + fzl_freeparser(parser); + fzl_freereader(rd); + fzl_freelinked(linked); return -1; } @@ -144,6 +166,12 @@ int main(int argc, char **argv) if (result != 0) { printf("%sError%s: %s\n", FZL_CERROR, FZL_CRST, fzl_writer_geterror()); + fzl_freeoptions(opts); + fzl_freewriter(writer); + fzl_freewalker(walker); + fzl_freeparser(parser); + fzl_freereader(rd); + fzl_freelinked(linked); return -1; } diff --git a/src/vm/fzl_vm.c b/src/vm/fzl_vm.c index 07827f8..ce026e1 100644 --- a/src/vm/fzl_vm.c +++ b/src/vm/fzl_vm.c @@ -193,7 +193,7 @@ void print_object(fzl_vm_object_t *obj) else if (arg.type == FZL_TYPE_UINT) printf("uint(%lu)", arg.as.u); else if (arg.type == FZL_TYPE_BOOL) - printf("bool(%b)", arg.as.b); + printf("bool(%s)", arg.as.b ? "true" : "false"); else if (arg.type == FZL_TYPE_NULL) printf(""); else if (arg.type == FZL_TYPE_OBJECT) @@ -833,7 +833,7 @@ int fzl_vm_run(fzl_vm_t *vm) else if (arg.type == FZL_TYPE_UINT) printf("%lu\n", arg.as.u); else if (arg.type == FZL_TYPE_BOOL) - printf("%b\n", arg.as.b); + printf("%s\n", arg.as.b ? "true" : "false"); else if (arg.type == FZL_TYPE_NULL) printf("\n"); else if (arg.type == FZL_TYPE_OBJECT)