fix: memory leaks on error handling

This commit is contained in:
Fernando Araoz 2024-12-28 07:23:38 -05:00
parent 3ac2f0202c
commit a371b10180
4 changed files with 16 additions and 0 deletions

View File

@ -67,6 +67,7 @@ fn prefixed(
if (end_position >= cap or !validator(input[end_position])) {
// populate error information
try err.init("Incomplete number", start, end_position, alloc);
try err.add_label("Expected a valid digit after the '" ++ [_]u8{prefix} ++ "'", start, end_position);
// throw error
return LexError.Incomplete;
@ -303,6 +304,7 @@ test "shouldnt parse incomplete hex number" {
defer std.testing.allocator.destroy(errdata);
const result = lex(input, input.len, 0, errdata, std.testing.allocator) catch |err| {
try std.testing.expect(err == token.LexError.Incomplete);
defer errdata.deinit();
return;
};
@ -322,6 +324,7 @@ test "shouldnt parse incomplete hex number 2" {
defer std.testing.allocator.destroy(errdata);
const result = lex(input, input.len, 0, errdata, std.testing.allocator) catch |err| {
try std.testing.expect(err == token.LexError.Incomplete);
defer errdata.deinit();
return;
};
@ -365,6 +368,7 @@ test "shouldnt parse incomplete octal number" {
defer std.testing.allocator.destroy(errdata);
const result = lex(input, input.len, 0, errdata, std.testing.allocator) catch |err| {
try std.testing.expect(err == token.LexError.Incomplete);
defer errdata.deinit();
return;
};
@ -396,6 +400,7 @@ test "shouldnt parse incomplete binary number" {
defer std.testing.allocator.destroy(errdata);
const result = lex(input, input.len, 0, errdata, std.testing.allocator) catch |err| {
try std.testing.expect(err == token.LexError.Incomplete);
defer errdata.deinit();
return;
};

View File

@ -214,6 +214,7 @@ test "should handle recoverable errors" {
const input = "322 0b 644";
var error_list = std.ArrayList(errors.ErrorData).init(std.testing.allocator);
defer error_list.deinit();
defer for (error_list.items) |*err| err.deinit();
const arrl = try tokenize(input, std.testing.allocator, &error_list);
defer arrl.deinit();

View File

@ -41,6 +41,7 @@ pub const LexError = error{
IncompleteScientificNumber,
IncompleteString,
CRLF,
OutOfMemory,
};
/// Contains the lexed token and the next position

View File

@ -10,6 +10,7 @@ pub const ErrorLabel = struct {
/// and pretty prints them.
pub const ErrorData = struct {
reason: []const u8,
help: ?[]const u8,
start_position: usize,
end_position: usize,
labels: std.ArrayList(ErrorLabel),
@ -27,6 +28,7 @@ pub const ErrorData = struct {
.start_position = start_position,
.end_position = end_position,
.labels = std.ArrayList(ErrorLabel).init(alloc),
.help = null,
.alloc = alloc,
};
}
@ -39,6 +41,11 @@ pub const ErrorData = struct {
});
}
/// Sets the help message of this error.
pub fn set_help(self: *@This(), help: []const u8) void {
self.help = help;
}
/// Generates an error string. `alloc` is used to create the string,
/// the caller should call `free` on the returning slice.
pub fn get_error_str(self: *@This(), source_code: []const u8, filename: []const u8, alloc: std.mem.Allocator) ![]u8 {
@ -238,6 +245,7 @@ test "should gen error message" {
const source = "print(ehh)";
var err = ErrorData{
.reason = "Invalid identifier",
.help = null,
.start_position = 6,
.end_position = 9,
.labels = std.ArrayList(ErrorLabel).init(std.testing.allocator),
@ -256,6 +264,7 @@ test "should gen error message with label (1)" {
const source = "print(ehh)";
var err = ErrorData{
.reason = "Invalid identifier",
.help = null,
.start_position = 6,
.end_position = 9,
.labels = std.ArrayList(ErrorLabel).init(std.testing.allocator),