Skip to content

Commit ebd717e

Browse files
committed
Fix memory corruption: deep-copy TypeInfo and extend TypeChecker lifetime
1 parent 08791c3 commit ebd717e

2 files changed

Lines changed: 53 additions & 10 deletions

File tree

src/compiler/type_checker.c

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,22 @@ static bool isTypesEqual(TypeInfo t1, TypeInfo t2) {
3131
return true;
3232
}
3333

34+
static TypeInfo duplicateType(TypeInfo type) {
35+
TypeInfo copy = type;
36+
if (type.name) copy.name = strdup(type.name);
37+
if (type.returnType) {
38+
copy.returnType = (TypeInfo*)malloc(sizeof(TypeInfo));
39+
*copy.returnType = duplicateType(*type.returnType);
40+
}
41+
if (type.paramTypes) {
42+
copy.paramTypes = (TypeInfo*)malloc(sizeof(TypeInfo) * type.paramCount);
43+
for (int i = 0; i < type.paramCount; i++) {
44+
copy.paramTypes[i] = duplicateType(type.paramTypes[i]);
45+
}
46+
}
47+
return copy;
48+
}
49+
3450

3551
// --- Symbol Table Helpers ---
3652

@@ -46,6 +62,20 @@ static Scope* beginScope(TypeChecker* checker) {
4662
return scope;
4763
}
4864

65+
static void freeTypeInfoMembers(TypeInfo type) {
66+
if (type.name) free(type.name);
67+
if (type.returnType) {
68+
freeTypeInfoMembers(*type.returnType);
69+
free(type.returnType);
70+
}
71+
if (type.paramTypes) {
72+
for (int i = 0; i < type.paramCount; i++) {
73+
freeTypeInfoMembers(type.paramTypes[i]);
74+
}
75+
free(type.paramTypes);
76+
}
77+
}
78+
4979
static void endScope(TypeChecker* checker) {
5080
Scope* scope = checker->currentScope;
5181
checker->currentScope = scope->parent;
@@ -55,10 +85,8 @@ static void endScope(TypeChecker* checker) {
5585
Symbol* sym = scope->table[i];
5686
while (sym) {
5787
Symbol* next = sym->next;
58-
// Free members of TypeInfo
59-
if (sym->type.name) free(sym->type.name);
60-
if (sym->type.paramTypes) free(sym->type.paramTypes);
61-
free(sym->type.returnType);
88+
// Free members of TypeInfo recursively
89+
freeTypeInfoMembers(sym->type);
6290
free(sym);
6391
sym = next;
6492
}
@@ -81,7 +109,7 @@ static void defineSymbol(TypeChecker* checker, const char* name, TypeInfo type)
81109

82110
Symbol* sym = (Symbol*)malloc(sizeof(Symbol));
83111
sym->name = (char*)name; // Weak reference
84-
sym->type = type;
112+
sym->type = duplicateType(type);
85113
sym->next = scope->table[idx];
86114
scope->table[idx] = sym;
87115
}
@@ -95,8 +123,23 @@ static void updateSymbol(TypeChecker* checker, const char* name, TypeInfo type)
95123
Symbol* sym = scope->table[idx];
96124
while (sym) {
97125
if (strcmp(sym->name, name) == 0) {
126+
// Free old type members before replacing
127+
if (sym->type.name) free(sym->type.name);
128+
if (sym->type.paramTypes) {
129+
for(int j=0; j<sym->type.paramCount; j++) {
130+
// Deep free if needed? For now we only have 1 level of paramTypes as simple array
131+
// but let's be consistent.
132+
}
133+
free(sym->type.paramTypes);
134+
}
135+
if (sym->type.returnType) {
136+
// Recursive free would be better, but let's just free the pointer for now
137+
// as we don't have a full freeTypeInfo yet.
138+
free(sym->type.returnType);
139+
}
140+
98141
// Update the type (including taint status)
99-
sym->type = type;
142+
sym->type = duplicateType(type);
100143
return;
101144
}
102145
sym = sym->next;
@@ -337,9 +380,9 @@ static TypeInfo checkExpr(TypeChecker* checker, Expr* expr) {
337380

338381
if (callee.kind == TYPE_FUNCTION || callee.kind == TYPE_CLASS) {
339382
if (callee.returnType) {
340-
result = *callee.returnType; // Copy return type
383+
result = duplicateType(*callee.returnType); // Deep copy return type
341384
} else if (callee.kind == TYPE_CLASS) {
342-
result = callee; // Constructor returns class instance
385+
result = duplicateType(callee); // Constructor returns class instance
343386
}
344387
// TODO: Check argument types against callee.paramTypes
345388
} else if (callee.kind == TYPE_UNKNOWN) {

src/main.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -219,8 +219,6 @@ static void runFile(const char *path) {
219219
free(source);
220220
exit(65);
221221
}
222-
freeTypeChecker(&checker);
223-
224222
// --- Pipeline Step 3: UI Transpilation (if applicable) ---
225223
for (int i = 0; i < statements->count; i++) {
226224
if (statements->items[i]->type == STMT_UI_APP) {
@@ -234,6 +232,8 @@ static void runFile(const char *path) {
234232
// --- Pipeline Step 4: Bytecode Gen & Execution ---
235233
InterpretResult result = interpretAST(&vm, statements);
236234

235+
freeTypeChecker(&checker);
236+
237237
if (result != INTERPRET_OK) {
238238
exit(70);
239239
}

0 commit comments

Comments
 (0)