Refactor hex_interpret to improve token management; ensure tokens are freed after processing to prevent memory leaks.
h3rald h3rald@h3rald.com
Thu, 11 Sep 2025 10:23:04 +0200
2 files changed,
28 insertions(+),
4 deletions(-)
M
src/hex.c
→
src/hex.c
@@ -3393,13 +3393,17 @@
while (token != NULL && token->type != HEX_TOKEN_INVALID) { int result = 0; + int token_consumed = 0; // Track whether the token was consumed by a function + if (token->type == HEX_TOKEN_INTEGER) { result = hex_push_integer(ctx, hex_parse_integer(token->value)); + // Token is not consumed by hex_push_integer, we need to free it } else if (token->type == HEX_TOKEN_STRING) { result = hex_push_string(ctx, token->value); + // Token is not consumed by hex_push_string, we need to free it } else if (token->type == HEX_TOKEN_SYMBOL) {@@ -3412,11 +3416,14 @@ }
token->position->filename = strdup(filename); } result = hex_push_symbol(ctx, token); + // hex_push_symbol now copies the token (from Patch 2), so we should free the original + // Token is not consumed, we need to free it } else if (token->type == HEX_TOKEN_QUOTATION_END) { hex_error(ctx, "(%d,%d) Unexpected end of quotation", position.line, position.column); result = 1; + // Token is not consumed, we need to free it } else if (token->type == HEX_TOKEN_QUOTATION_START) {@@ -3425,18 +3432,21 @@ if (!quotationItem)
{ hex_error(ctx, "(%d,%d) Failed to allocate memory for quotation", position.line, position.column); result = 1; + // Token is not consumed, we need to free it } else if (hex_parse_quotation(ctx, &input, quotationItem, &position) != 0) { hex_error(ctx, "(%d,%d) Failed to parse quotation", position.line, position.column); free(quotationItem); result = 1; + // Token is not consumed, we need to free it } else { result = hex_push_quotation(ctx, quotationItem->data.quotation_value, quotationItem->quotation_size); // Don't free quotationItem here as its content is now owned by the stack free(quotationItem); // Only free the wrapper, not the contents + // Token is not consumed, we need to free it } }@@ -3448,8 +3458,9 @@ print_stack_trace(ctx);
return result; } - // Free the token after successful processing (unless it's been stored somewhere) - if (token->type != HEX_TOKEN_SYMBOL && token->type != HEX_TOKEN_QUOTATION_START) + // Always free the token after processing since none of the above functions consume it + // With Patch 2, hex_push_symbol now copies tokens, so we always own the original + if (!token_consumed) { hex_free_token(token); }@@ -3461,6 +3472,7 @@ {
token->position->filename = strdup(filename); add_to_stack_trace(ctx, token); print_stack_trace(ctx); + hex_free_token(token); // Make sure to free the invalid token too return 1; } return 0;
M
src/interpreter.c
→
src/interpreter.c
@@ -76,13 +76,17 @@
while (token != NULL && token->type != HEX_TOKEN_INVALID) { int result = 0; + int token_consumed = 0; // Track whether the token was consumed by a function + if (token->type == HEX_TOKEN_INTEGER) { result = hex_push_integer(ctx, hex_parse_integer(token->value)); + // Token is not consumed by hex_push_integer, we need to free it } else if (token->type == HEX_TOKEN_STRING) { result = hex_push_string(ctx, token->value); + // Token is not consumed by hex_push_string, we need to free it } else if (token->type == HEX_TOKEN_SYMBOL) {@@ -95,11 +99,14 @@ }
token->position->filename = strdup(filename); } result = hex_push_symbol(ctx, token); + // hex_push_symbol now copies the token (from Patch 2), so we should free the original + // Token is not consumed, we need to free it } else if (token->type == HEX_TOKEN_QUOTATION_END) { hex_error(ctx, "(%d,%d) Unexpected end of quotation", position.line, position.column); result = 1; + // Token is not consumed, we need to free it } else if (token->type == HEX_TOKEN_QUOTATION_START) {@@ -108,18 +115,21 @@ if (!quotationItem)
{ hex_error(ctx, "(%d,%d) Failed to allocate memory for quotation", position.line, position.column); result = 1; + // Token is not consumed, we need to free it } else if (hex_parse_quotation(ctx, &input, quotationItem, &position) != 0) { hex_error(ctx, "(%d,%d) Failed to parse quotation", position.line, position.column); free(quotationItem); result = 1; + // Token is not consumed, we need to free it } else { result = hex_push_quotation(ctx, quotationItem->data.quotation_value, quotationItem->quotation_size); // Don't free quotationItem here as its content is now owned by the stack free(quotationItem); // Only free the wrapper, not the contents + // Token is not consumed, we need to free it } }@@ -131,8 +141,9 @@ print_stack_trace(ctx);
return result; } - // Free the token after successful processing (unless it's been stored somewhere) - if (token->type != HEX_TOKEN_SYMBOL && token->type != HEX_TOKEN_QUOTATION_START) + // Always free the token after processing since none of the above functions consume it + // With Patch 2, hex_push_symbol now copies tokens, so we always own the original + if (!token_consumed) { hex_free_token(token); }@@ -144,6 +155,7 @@ {
token->position->filename = strdup(filename); add_to_stack_trace(ctx, token); print_stack_trace(ctx); + hex_free_token(token); // Make sure to free the invalid token too return 1; } return 0;