Skip to content

Commit 620652e

Browse files
author
TheDevConnor
committed
Fix: Only track pointer returns from #returns_ownership functions
Static analyzer was incorrectly treating struct returns as heap allocations. Now only tracks pointer return types, fixing false positive memory leaks for structs with pointer fields.
1 parent 0c2d3d4 commit 620652e

2 files changed

Lines changed: 21 additions & 7 deletions

File tree

src/typechecker/stmt.c

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,6 @@ bool typecheck_var_decl(AstNode *node, Scope *scope, ArenaAllocator *arena) {
132132
bool is_public = node->stmt.var_decl.is_public;
133133
bool is_mutable = node->stmt.var_decl.is_mutable;
134134

135-
// Track memory allocation
136135
// Track memory allocation
137136
if (initializer && contains_alloc_expression(initializer)) {
138137
StaticMemoryAnalyzer *analyzer = get_static_analyzer(scope);
@@ -178,6 +177,7 @@ bool typecheck_var_decl(AstNode *node, Scope *scope, ArenaAllocator *arena) {
178177
}
179178

180179
// Track ownership transfer from function return values
180+
// CRITICAL FIX: Only track if the returned type is a POINTER
181181
if (initializer && initializer->type == AST_EXPR_CALL) {
182182
AstNode *callee = initializer->expr.call.callee;
183183
Symbol *func_symbol = NULL;
@@ -194,14 +194,27 @@ bool typecheck_var_decl(AstNode *node, Scope *scope, ArenaAllocator *arena) {
194194
}
195195

196196
// If function returns ownership, track as allocation
197+
// BUT ONLY if the return type is actually a pointer
197198
if (func_symbol && func_symbol->returns_ownership) {
198-
StaticMemoryAnalyzer *analyzer = get_static_analyzer(scope);
199-
if (analyzer) {
200-
const char *func_name = get_current_function_name(scope);
201-
static_memory_track_alloc(analyzer, node->line, node->column, name,
202-
func_name, g_tokens, g_token_count,
203-
g_file_path);
199+
// Get the actual return type
200+
AstNode *return_type = NULL;
201+
if (func_symbol->type && func_symbol->type->type == AST_TYPE_FUNCTION) {
202+
return_type = func_symbol->type->type_data.function.return_type;
203+
}
204+
205+
// CRITICAL: Only track if return type is a pointer
206+
if (return_type && is_pointer_type(return_type)) {
207+
StaticMemoryAnalyzer *analyzer = get_static_analyzer(scope);
208+
if (analyzer) {
209+
const char *func_name = get_current_function_name(scope);
210+
static_memory_track_alloc(analyzer, node->line, node->column, name,
211+
func_name, g_tokens, g_token_count,
212+
g_file_path);
213+
}
204214
}
215+
// If return type is a struct with pointer fields, we DON'T track the
216+
// struct itself The struct is a value type, not a heap allocation Only
217+
// the pointer FIELDS need to be freed (which the user handles with defer)
205218
}
206219
}
207220

std/string.lx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@ pub const atio -> fn (value: *byte) int {
219219
return num;
220220
}
221221

222+
#returns_ownership
222223
pub const string_add -> fn (num1: *byte, num2: *byte) *byte {
223224
let len1: int = strlen(num1);
224225
let len2: int = strlen(num2);

0 commit comments

Comments
 (0)