I can’t “retrieve” the content of a slice after reallocation using a temporary backup varariable.
Non working exemple
In this exemple I use the zig tokenizer to count the number of keywords “for” in a string.
But assuming I don’t know in advance that number at runtime I use an allocator to store the “for” tokens and check if it is full (i.e. allocation size reached), then I use a temporary variable to “save” the elements contained in the allocated memory. After I reallocate with a bigger allocation size and try to retrieve the firsts elements contained in the temporary variable.
However I got the following error:
$ zig test test.zig
Source: You are the one for me, for me, for me, formidable'
Segmentation fault at address 0x107fdb000
/Users/[..]/src/test.zig:46:31: 0x107d78e46 in test.test count for keywords (test)
for (temp,0..) |tmp,j| {
^
???:?:?: 0x107e6fab7 in ??? (???)
Unwind information for `???:0x107e6fab7` was not available, trace may be incomplete
error: the following test command crashed:
/Users/[..]/.zig-cache/o/c674d5dee9354dbee1a6fbc3bf9690f2/test --seed=0x1e70405c
Full code
const std = @import("std");
pub const My_token = struct {
loc: Loc,
pub const Loc = struct {
start: usize,
end: usize,
};
};
test "test count for keywords" {
const source:[:0]const u8 = "You are the one for me, for me, for me, formidable";
std.debug.print("Source: {s}'\n", .{source});
var alloc_size:usize = 2;
var for_tokens = try std.testing.allocator.alloc(My_token, alloc_size);
defer std.testing.allocator.free(for_tokens);
var tok = std.zig.Tokenizer.init(source);
var tag_name:[]const u8 = undefined;
var i:usize = 0;
var count_for_keywords:u8 = 0;
var token:@TypeOf(tok.next()) = undefined;
var temp:[]My_token = undefined;
while (true) : (i += 1) {
token = tok.next();
tag_name = @tagName(token.tag);
if (std.mem.eql(u8,tag_name,"keyword_for")) {
for_tokens[count_for_keywords].loc.start = token.loc.start;
for_tokens[count_for_keywords].loc.end = token.loc.end;
count_for_keywords += 1;
if (count_for_keywords == alloc_size) {
temp = for_tokens[0..count_for_keywords];
alloc_size *= 2;
for_tokens = try std.testing.allocator.realloc(for_tokens, alloc_size);
for (temp,0..) |tmp,j| {
for_tokens[j].loc.start = tmp.loc.start;
for_tokens[j].loc.end = tmp.loc.end;
}
}
}
if (std.mem.eql(u8, tag_name, "eof")) {
break;
}
}
const expected:u8 = 3;
const actual = count_for_keywords;
try std.testing.expectEqual(expected, actual);
}
To me, it looks like the variable temp
lost its content after the realloc
, because for_tokens
is then empty. But, the temp
has been assigned before the reallocation so I don’t understand…
Questions
- How to fix the above code in order to remove the error?
- Is there a “better” way to do such a thing, i.e. restore the content of reallocated variable?