fix: prevent memory leaks in module parser

This commit is contained in:
Fernando Araoz 2024-12-16 07:10:06 -05:00
parent 81e38ab8a8
commit 5337ba48a4
2 changed files with 19 additions and 12 deletions

View File

@ -17,36 +17,32 @@ pub const Module = struct {
pub fn init(target: *@This(), tokens: *const TokenStream, pos: usize, allocator: std.mem.Allocator) ParseError!void {
var arrl = std.ArrayList(*statement.Statement).init(allocator);
errdefer arrl.deinit();
errdefer for (arrl.items) |i| {
i.deinit();
allocator.destroy(i);
};
const input_len = tokens.items.len;
var current_pos = pos;
// parse many statements
while (current_pos < input_len) {
// FIXME: if a statement was added to the array list,
// and then one of these fails,
// will all previous statements leak memory?
var stmt = try allocator.create(statement.Statement);
errdefer allocator.destroy(stmt);
const next_pos = try stmt.init(tokens, current_pos, allocator);
current_pos = next_pos;
arrl.append(stmt) catch {
// TODO: free stmt if this fails
return ParseError.Error;
};
try arrl.append(stmt);
}
target.* = .{
// FIXME: is this copying the whole arraylist? should use a pointer?
.statements = arrl,
.alloc = allocator,
};
}
pub fn deinit(self: @This()) void {
// FIXME: should deinit all elements inside the arraylist no? otherwise
// they will leak no?
for (self.statements.items) |stmt| {
stmt.deinit();
self.alloc.destroy(stmt);
@ -69,3 +65,15 @@ test "should parse a single statement" {
defer module.deinit();
}
test "should clean memory if a statement parsing fails after one item has been inserted" {
const input = "var my_variable = 322 unrelated()";
const tokens = try lexic.tokenize(input, std.testing.allocator);
defer tokens.deinit();
var module: Module = undefined;
_ = module.init(&tokens, 0, std.testing.allocator) catch {
return;
};
defer module.deinit();
}

View File

@ -43,7 +43,6 @@ pub const VariableBinding = struct {
// parse expression
if (pos + 3 >= tokens.items.len) return ParseError.Error;
// TODO: allocate on the stack
const exp = allocator.create(expression.Expression) catch {
return ParseError.OutOfMemory;
};
@ -103,7 +102,7 @@ test "should fail is it doesnt start with var" {
try std.testing.expect(false);
}
test "should fail if the idenfier is missing" {
test "should fail if the identifier is missing" {
const input = "var ";
const tokens = try lexic.tokenize(input, std.testing.allocator);
defer tokens.deinit();