all repos — hex @ 71e4e53ac3a3650061c4c4cb8984afb1790c8af5

A tiny, minimalist, slightly-esoteric concatenative programming lannguage.

Enhance ownership contract documentation for hex_set_symbol; clarify memory management responsibilities and prevent double free risks.
h3rald h3rald@h3rald.com
Wed, 10 Sep 2025 17:31:11 +0200
commit

71e4e53ac3a3650061c4c4cb8984afb1790c8af5

parent

bc2cc707d4193e9affbd6f0b1164a4bdf90c92f4

2 files changed, 24 insertions(+), 4 deletions(-)

jump to
M src/hex.csrc/hex.c

@@ -1110,6 +1110,16 @@ }

return 1; } +/* + * hex_set_symbol + * Ownership contract: + * - Caller passes a heap-allocated hex_item_t* (value). + * - This function ALWAYS consumes (frees) the passed pointer, whether it succeeds or fails. + * - The registry stores its own deep copy (value_copy) and becomes sole owner. + * - Callers MUST NOT use or free the original pointer after calling. + * - Rationale: prevents aliasing between caller's pointer and registry entry, eliminating + * double free / accidental mutation risks. + */ int hex_set_symbol(hex_context_t *ctx, const char *key, hex_item_t *value, int native) { hex_registry_t *registry = ctx->registry;

@@ -1178,11 +1188,11 @@ func_item->token = malloc(sizeof(hex_token_t));

func_item->token->type = HEX_TOKEN_SYMBOL; func_item->token->value = strdup(name); func_item->token->position = NULL; - + // hex_set_symbol consumes func_item (success or failure); never free it here afterwards. if (hex_set_symbol(ctx, name, func_item, 1) != 0) { hex_error(ctx, "Error: Failed to register native symbol '%s'", name); - hex_free_item(ctx, func_item); + return; // func_item already freed inside hex_set_symbol } }
M src/registry.csrc/registry.c

@@ -141,6 +141,16 @@ }

return 1; } +/* + * hex_set_symbol + * Ownership contract: + * - Caller passes a heap-allocated hex_item_t* (value). + * - This function ALWAYS consumes (frees) the passed pointer, whether it succeeds or fails. + * - The registry stores its own deep copy (value_copy) and becomes sole owner. + * - Callers MUST NOT use or free the original pointer after calling. + * - Rationale: prevents aliasing between caller's pointer and registry entry, eliminating + * double free / accidental mutation risks. + */ int hex_set_symbol(hex_context_t *ctx, const char *key, hex_item_t *value, int native) { hex_registry_t *registry = ctx->registry;

@@ -209,11 +219,11 @@ func_item->token = malloc(sizeof(hex_token_t));

func_item->token->type = HEX_TOKEN_SYMBOL; func_item->token->value = strdup(name); func_item->token->position = NULL; - + // hex_set_symbol consumes func_item (success or failure); never free it here afterwards. if (hex_set_symbol(ctx, name, func_item, 1) != 0) { hex_error(ctx, "Error: Failed to register native symbol '%s'", name); - hex_free_item(ctx, func_item); + return; // func_item already freed inside hex_set_symbol } }