From 6828cc5f1a1d303fa8dc4914491b8db1ec5520c7 Mon Sep 17 00:00:00 2001 From: William Bell Date: Thu, 26 Jun 2025 16:56:17 +0100 Subject: [PATCH] fix memory leak in declaration and function --- null_test.ar | 2 +- src/dynamic_array/darray.h | 2 +- src/main.c | 7 +- src/parser/assignable/call/call.c | 1 + src/parser/declaration/declaration.c | 22 ++-- src/parser/function/function.c | 9 +- src/parser/parser.c | 6 +- .../dynamic_array_armem/darray_armem.c | 113 ++++++++++++++++++ .../dynamic_array_armem/darray_armem.h | 37 ++++++ src/runtime/objects/functions/functions.c | 10 +- src/runtime/objects/object.h | 4 +- src/runtime/runtime.c | 25 ++-- 12 files changed, 196 insertions(+), 42 deletions(-) create mode 100644 src/runtime/internals/dynamic_array_armem/darray_armem.c create mode 100644 src/runtime/internals/dynamic_array_armem/darray_armem.h diff --git a/null_test.ar b/null_test.ar index c156d2e..57cad2c 100644 --- a/null_test.ar +++ b/null_test.ar @@ -1 +1 @@ -let x(hello,lol,world, WORLD,HELLOOOO,LOLLLLLL, WORLD)=let f(x)="bruh" \ No newline at end of file +let f(x)="bruh" \ No newline at end of file diff --git a/src/dynamic_array/darray.h b/src/dynamic_array/darray.h index f04aa65..a5554aa 100644 --- a/src/dynamic_array/darray.h +++ b/src/dynamic_array/darray.h @@ -4,7 +4,7 @@ #include #include // for size_t -#define CHUNK_SIZE 1024 +#define CHUNK_SIZE 16 typedef struct { void *data; diff --git a/src/main.c b/src/main.c index 4812697..96cf474 100644 --- a/src/main.c +++ b/src/main.c @@ -3,16 +3,16 @@ #include "lexer/token.h" #include "memory.h" #include "parser/parser.h" -#include "translator/translator.h" #include "runtime/runtime.h" +#include "translator/translator.h" #include -#include #include #include #include #include #include +#include #include const char FILE_IDENTIFIER[] = "ARBI"; @@ -62,7 +62,7 @@ int main(int argc, char *argv[]) { regCount = htole64(regCount); constantsSize = htole64(constantsSize); bytecodeSize = htole64(bytecodeSize); - + fwrite(&FILE_IDENTIFIER, sizeof(char), strlen(FILE_IDENTIFIER), file); fwrite(&version_number_htole64ed, sizeof(uint64_t), 1, file); fwrite(®Count, sizeof(uint64_t), 1, file); @@ -77,7 +77,6 @@ int main(int argc, char *argv[]) { generate_siphash_key(); init_types(); - runtime(translated); free_translator(&translated); diff --git a/src/parser/assignable/call/call.c b/src/parser/assignable/call/call.c index 02819cb..b26df81 100644 --- a/src/parser/assignable/call/call.c +++ b/src/parser/assignable/call/call.c @@ -49,5 +49,6 @@ void free_parse_call(void *ptr) { darray_free(&parsedCall->args, free_parsed); free_parsed(parsedCall->to_call); + free(parsedCall->to_call); free(parsedCall); } \ No newline at end of file diff --git a/src/parser/declaration/declaration.c b/src/parser/declaration/declaration.c index e9469f5..abd7c53 100644 --- a/src/parser/declaration/declaration.c +++ b/src/parser/declaration/declaration.c @@ -1,9 +1,9 @@ #include "declaration.h" #include "../../lexer/token.h" #include "../../memory.h" +#include "../function/function.h" #include "../literals/literals.h" #include "../parser.h" -#include "../function/function.h" #include #include #include @@ -23,7 +23,6 @@ ParsedValue *parse_declaration(char *file, DArray *tokens, size_t *index) { darray_push(declarations, &_declaration); ParsedSingleDeclaration *declaration = darray_get(declarations, declarations->size - 1); - bool isFunction = false; DArray parameters; declaration->from = parse_null(); @@ -40,7 +39,6 @@ ParsedValue *parse_declaration(char *file, DArray *tokens, size_t *index) { return parsedValue; token = darray_get(tokens, *index); if (token->type == TOKEN_LPAREN) { - isFunction = true; darray_init(¶meters, sizeof(char *)); (*index)++; error_if_finished(file, tokens, index); @@ -63,8 +61,8 @@ ParsedValue *parse_declaration(char *file, DArray *tokens, size_t *index) { file, token->line, token->column); exit(EXIT_FAILURE); } - char *parameter_name = - strcpy(checked_malloc(strlen(token->value) + 1), token->value); + char *parameter_name = checked_malloc(strlen(token->value) + 1); + strcpy(parameter_name, token->value); darray_push(¶meters, ¶meter_name); (*index)++; error_if_finished(file, tokens, index); @@ -99,13 +97,15 @@ ParsedValue *parse_declaration(char *file, DArray *tokens, size_t *index) { token->column); exit(EXIT_FAILURE); } - if (isFunction) { - declaration->from = create_parsed_function(declaration->name, parameters, declaration->from); - } - if ((*index) >= tokens->size) - break; - token = darray_get(tokens, *index); } + if (parameters.resizable) { + declaration->from = create_parsed_function(declaration->name, parameters, + declaration->from); + } + if ((*index) >= tokens->size) + break; + token = darray_get(tokens, *index); + size_t count = skip_newlines_and_indents(tokens, index); if ((*index) >= tokens->size) break; diff --git a/src/parser/function/function.c b/src/parser/function/function.c index fe93111..1fbb127 100644 --- a/src/parser/function/function.c +++ b/src/parser/function/function.c @@ -1,5 +1,6 @@ #include "function.h" #include "../../memory.h" +#include #include #include @@ -15,11 +16,17 @@ ParsedValue *create_parsed_function(char *name, DArray parameters, return parsedValue; } +void free_parameter(void *ptr) { + char** data = ptr; + free(*data); +} + void free_function(void *ptr) { ParsedValue *parsedValue = ptr; ParsedFunction *parsed = parsedValue->data; free_parsed(parsed->body); + free(parsed->body); free(parsed->name); - darray_free(&parsed->parameters, NULL); + darray_free(&parsed->parameters, free_parameter); free(parsed); } \ No newline at end of file diff --git a/src/parser/parser.c b/src/parser/parser.c index 79a3cc3..d6ff1c0 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -23,8 +23,8 @@ #include const char *ValueTypeNames[] = { - "string", "assign", "identifier", "number", "if statement", - "access", "call", "declaration", "null", "boolean", + "string", "assign", "identifier", "number", "if statement", + "access", "call", "declaration", "null", "boolean", "do wrap", "operations", "list", "dictionary", "function"}; void error_if_finished(char *file, DArray *tokens, size_t *index) { @@ -157,7 +157,7 @@ ParsedValue *parse_token_full(char *file, DArray *tokens, size_t *index, passed = true; } } - + return output; } diff --git a/src/runtime/internals/dynamic_array_armem/darray_armem.c b/src/runtime/internals/dynamic_array_armem/darray_armem.c new file mode 100644 index 0000000..4c1c9cf --- /dev/null +++ b/src/runtime/internals/dynamic_array_armem/darray_armem.c @@ -0,0 +1,113 @@ +#include "darray_armem.h" +#include "../../../memory.h" +#include +#include +#include +#include + +void darray_armem_init(darray_armem *arr, size_t element_size) { + arr->element_size = element_size; + arr->size = 0; + arr->capacity = CHUNK_SIZE; + arr->data = ar_alloc(CHUNK_SIZE * element_size); + arr->resizable = true; + if (!arr->data) { + fprintf(stderr, "darray_armem_init: allocation failed\n"); + exit(EXIT_FAILURE); + } +} + +void darray_armem_resize(darray_armem *arr, size_t new_size) { + if (!arr->resizable) { + fprintf(stderr, "darray_armem_resize: unresizable darray_armem\n"); + exit(EXIT_FAILURE); + } + size_t new_capacity = ((new_size + CHUNK_SIZE) / CHUNK_SIZE) * CHUNK_SIZE; + if (new_capacity != arr->capacity) { + void *new_data = ar_alloc(new_capacity * arr->element_size); + memccpy(new_data,arr->data, arr->element_size, arr->capacity); + if (!new_data) { + fprintf(stderr, "darray_armem_resize: reallocation failed\n"); + exit(EXIT_FAILURE); + } + arr->data = new_data; + arr->capacity = new_capacity; + } + + arr->size = new_size; +} + +void darray_armem_push(darray_armem *arr, void *element) { + if (!arr->resizable) { + fprintf(stderr, "darray_armem_resize: unresizable darray_armem\n"); + exit(EXIT_FAILURE); + } + if (arr->size >= arr->capacity) { + darray_armem_resize(arr, arr->size + 1); + } else { + arr->size++; + } + + void *target = (char *)arr->data + (arr->size - 1) * arr->element_size; + memcpy(target, element, arr->element_size); +} + +void darray_armem_pop(darray_armem *arr, void (*free_data)(void *)) { + if (!arr->resizable) { + fprintf(stderr, "darray_armem_resize: unresizable darray_armem\n"); + exit(EXIT_FAILURE); + } + if (arr->size == 0) + return; + + if (free_data) { + void *target = (char *)arr->data + (arr->size-1) * arr->element_size; + free_data(target); + } + + darray_armem_resize(arr, arr->size-1); +} + +void *darray_armem_get(darray_armem *arr, size_t index) { + if (index >= arr->size) { + fprintf(stderr, "darray_armem_get: index out of bounds\n"); + exit(EXIT_FAILURE); + } + return (char *)arr->data + index * arr->element_size; +} + +darray_armem darray_armem_slice(darray_armem *arr, size_t start, size_t end) { + if (start > end || end > arr->size) { + fprintf(stderr, "darray_armem_slice: invalid slice range\n"); + exit(EXIT_FAILURE); + } + + darray_armem slice; + + slice.data = (char *)arr->data + start * arr->element_size; + slice.size = (end - start); + slice.element_size = arr->element_size; + slice.capacity = ((slice.size + CHUNK_SIZE) / CHUNK_SIZE) * CHUNK_SIZE; + slice.resizable = false; + + return slice; +} + +void darray_armem_free(darray_armem *arr, void (*free_data)(void *)) { + if (!arr->resizable) { + // It's a view/slice — don't free + return; + } + if (free_data) { + for (size_t i = 0; i < arr->size; ++i) { + void *element = (char *)arr->data + i * arr->element_size; + free_data(element); + } + } + free(arr->data); + arr->data = NULL; + arr->size = 0; + arr->capacity = 0; + arr->element_size = 0; + arr->resizable = false; +} \ No newline at end of file diff --git a/src/runtime/internals/dynamic_array_armem/darray_armem.h b/src/runtime/internals/dynamic_array_armem/darray_armem.h new file mode 100644 index 0000000..2d2417c --- /dev/null +++ b/src/runtime/internals/dynamic_array_armem/darray_armem.h @@ -0,0 +1,37 @@ +#ifndef darray_armem_H +#define darray_armem_H + +#include +#include // for size_t + +#define CHUNK_SIZE 16 + +typedef struct { + void *data; + size_t element_size; + size_t size; + size_t capacity; + bool resizable; +} darray_armem; + +// Initializes the dynamic_array +void darray_armem_init(darray_armem *arr, size_t element_size); + +// Pushes an element onto the array +void darray_armem_push(darray_armem *arr, void *element); + +// Pops the last element, calling `free_data` if provided +void darray_armem_pop(darray_armem *arr, void (*free_data)(void *)); + +// Gets a pointer to an element at index +void *darray_armem_get(darray_armem *arr, size_t index); + +// Frees the entire array and optionally each element +void darray_armem_free(darray_armem *arr, void (*free_data)(void *)); + +// Resizes the array to a new size (internal use, but exposed) +void darray_armem_resize(darray_armem *arr, size_t new_size); + +darray_armem darray_armem_slice(darray_armem *arr, size_t start, size_t end); + +#endif // darray_armem_H diff --git a/src/runtime/objects/functions/functions.c b/src/runtime/objects/functions/functions.c index 86c0ed9..202e853 100644 --- a/src/runtime/objects/functions/functions.c +++ b/src/runtime/objects/functions/functions.c @@ -23,24 +23,18 @@ void load_argon_function(Translated *translated, RuntimeState *state, object->value.argon_fn.number_of_parameters = pop_bytecode(translated, state); object->value.argon_fn.parameters = ar_alloc(object->value.argon_fn.number_of_parameters * sizeof(char *)); - printf("%s(", object->name); for (size_t i = 0; i < object->value.argon_fn.number_of_parameters; i++) { - if(i!=0)printf(", "); offset = pop_bytecode(translated, state); length = pop_bytecode(translated, state); object->value.argon_fn.parameters[i] = ar_alloc_atomic(length + 1); memcpy(object->value.argon_fn.parameters[i], arena_get(&translated->constants, offset), length); object->value.argon_fn.parameters[i][length] = '\0'; - printf("%s", object->value.argon_fn.parameters[i]); } - printf(") = "); offset = pop_bytecode(translated, state); length = pop_bytecode(translated, state); - darray_init(&object->value.argon_fn.bytecode, sizeof(uint64_t)); - darray_resize(&object->value.argon_fn.bytecode, length/object->value.argon_fn.bytecode.element_size); + darray_armem_init(&object->value.argon_fn.bytecode, sizeof(uint64_t)); + darray_armem_resize(&object->value.argon_fn.bytecode, length/object->value.argon_fn.bytecode.element_size); memcpy(object->value.argon_fn.bytecode.data, arena_get(&translated->constants, offset), length); object->value.argon_fn.stack = stack; - fwrite(object->value.argon_fn.bytecode.data, object->value.argon_fn.bytecode.element_size, object->value.argon_fn.bytecode.size, stdout); - printf("\n"); state->registers[0]=object; } \ No newline at end of file diff --git a/src/runtime/objects/object.h b/src/runtime/objects/object.h index 2766e79..cd028e5 100644 --- a/src/runtime/objects/object.h +++ b/src/runtime/objects/object.h @@ -1,7 +1,7 @@ #ifndef OBJECT_H #define OBJECT_H #include "../internals/hashmap/hashmap.h" -#include "../../dynamic_array/darray.h" +#include "../internals/dynamic_array_armem/darray_armem.h" #include #include #include "../runtime.h" @@ -13,7 +13,7 @@ struct string_struct { size_t length; }; struct argon_function_struct { - DArray bytecode; + darray_armem bytecode; struct Stack stack; size_t number_of_parameters; char** parameters; diff --git a/src/runtime/runtime.c b/src/runtime/runtime.c index a28c961..552ef15 100644 --- a/src/runtime/runtime.c +++ b/src/runtime/runtime.c @@ -1,12 +1,13 @@ #include "runtime.h" #include "../translator/translator.h" #include "internals/siphash/siphash.h" +#include "objects/functions/functions.h" #include "objects/null/null.h" #include "objects/object.h" #include "objects/string/string.h" #include "objects/type/type.h" -#include "objects/functions/functions.h" #include +#include #include #include #include @@ -35,25 +36,26 @@ void load_const(Translated *translated, RuntimeState *state) { size_t length = pop_bytecode(translated, state); uint64_t offset = pop_bytecode(translated, state); - void*data = ar_alloc_atomic(length); - memcpy(data, arena_get(&translated->constants,offset), length); + void *data = ar_alloc_atomic(length); + memcpy(data, arena_get(&translated->constants, offset), length); ArgonObject *object = ARGON_NULL; switch (type) { - case TYPE_OP_STRING: - object = init_string_object(data, length); - break; + case TYPE_OP_STRING: + object = init_string_object(data, length); + break; } state->registers[to_register] = object; } -void run_instruction(Translated *translated, RuntimeState *state, struct Stack stack) { +void run_instruction(Translated *translated, RuntimeState *state, + struct Stack stack) { OperationType opcode = pop_bytecode(translated, state); switch (opcode) { case OP_LOAD_NULL: state->registers[pop_bytecode(translated, state)] = ARGON_NULL; break; case OP_LOAD_CONST: - load_const(translated,state); + load_const(translated, state); break; case OP_LOAD_FUNCTION: load_argon_function(translated, state, stack); @@ -65,9 +67,10 @@ void runtime(Translated translated) { RuntimeState state = { checked_malloc(translated.registerCount * sizeof(ArgonObject *)), 0}; struct Stack stack = {}; - - while (state.head < translated.bytecode.size) - run_instruction(&translated, &state,stack); + state.head = 0; + while (state.head < translated.bytecode.size) { + run_instruction(&translated, &state, stack); + } free(state.registers); }