fix: prevent memory leaks in module parser
This commit is contained in:
parent
81e38ab8a8
commit
5337ba48a4
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user