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 {
|
pub fn init(target: *@This(), tokens: *const TokenStream, pos: usize, allocator: std.mem.Allocator) ParseError!void {
|
||||||
var arrl = std.ArrayList(*statement.Statement).init(allocator);
|
var arrl = std.ArrayList(*statement.Statement).init(allocator);
|
||||||
errdefer arrl.deinit();
|
errdefer arrl.deinit();
|
||||||
|
errdefer for (arrl.items) |i| {
|
||||||
|
i.deinit();
|
||||||
|
allocator.destroy(i);
|
||||||
|
};
|
||||||
|
|
||||||
const input_len = tokens.items.len;
|
const input_len = tokens.items.len;
|
||||||
var current_pos = pos;
|
var current_pos = pos;
|
||||||
|
|
||||||
// parse many statements
|
// parse many statements
|
||||||
while (current_pos < input_len) {
|
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);
|
var stmt = try allocator.create(statement.Statement);
|
||||||
errdefer allocator.destroy(stmt);
|
errdefer allocator.destroy(stmt);
|
||||||
|
|
||||||
const next_pos = try stmt.init(tokens, current_pos, allocator);
|
const next_pos = try stmt.init(tokens, current_pos, allocator);
|
||||||
current_pos = next_pos;
|
current_pos = next_pos;
|
||||||
|
|
||||||
arrl.append(stmt) catch {
|
try arrl.append(stmt);
|
||||||
// TODO: free stmt if this fails
|
|
||||||
return ParseError.Error;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
target.* = .{
|
target.* = .{
|
||||||
// FIXME: is this copying the whole arraylist? should use a pointer?
|
|
||||||
.statements = arrl,
|
.statements = arrl,
|
||||||
.alloc = allocator,
|
.alloc = allocator,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: @This()) void {
|
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| {
|
for (self.statements.items) |stmt| {
|
||||||
stmt.deinit();
|
stmt.deinit();
|
||||||
self.alloc.destroy(stmt);
|
self.alloc.destroy(stmt);
|
||||||
@ -69,3 +65,15 @@ test "should parse a single statement" {
|
|||||||
|
|
||||||
defer module.deinit();
|
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
|
// parse expression
|
||||||
if (pos + 3 >= tokens.items.len) return ParseError.Error;
|
if (pos + 3 >= tokens.items.len) return ParseError.Error;
|
||||||
|
|
||||||
// TODO: allocate on the stack
|
|
||||||
const exp = allocator.create(expression.Expression) catch {
|
const exp = allocator.create(expression.Expression) catch {
|
||||||
return ParseError.OutOfMemory;
|
return ParseError.OutOfMemory;
|
||||||
};
|
};
|
||||||
@ -103,7 +102,7 @@ test "should fail is it doesnt start with var" {
|
|||||||
try std.testing.expect(false);
|
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 input = "var ";
|
||||||
const tokens = try lexic.tokenize(input, std.testing.allocator);
|
const tokens = try lexic.tokenize(input, std.testing.allocator);
|
||||||
defer tokens.deinit();
|
defer tokens.deinit();
|
||||||
|
Loading…
Reference in New Issue
Block a user