I'm not exactly sure what is going on here. If you run zig test src/parse.zig in https://github.com/isaachier/zig-parser-generator the test crashes. I have used gdb to track this into the first insertion into the RuleSet hash map. The line it crashes on involves calling an arena allocator to allocate space for the map. The problem is, there is no error message here or much else to help me debug. Sorry to paste a link, but not sure what else to do here.
Seems like the allocFn for the HashMap's allocator isn't set to a valid address for some reason.
(lldb) p self->allocFn
(Error![]u8 (*)(Error![]u8 *, StackTrace *, Allocator *, unsigned long, unsigned int)) $3 = 0x0000000000000001
Backtrace for reference:
* thread #1, name = 'test', stop reason = signal SIGSEGV: invalid address (fault address: 0x1)
* frame #0: 0x0000000000000001
frame #1: 0x0000000000208563 test`Allocator_alignedAlloc at mem.zig:71
frame #2: 0x00000000002083e3 test`Allocator_alloc at mem.zig:63
frame #3: 0x0000000000207b49 test`HashMap(hm=0x00007fffffffde58)_initCapacity at hash_map.zig:167
frame #4: 0x00000000002067a8 test`HashMap(hm=0x00007fffffffde58)_put at hash_map.zig:94
frame #5: 0x0000000000206273 test`RuleSet_put(self=0x00007fffffffde18) at grammar.zig:52
frame #6: 0x0000000000205347 test`Parser_parseRule(self=0x00007fffffffdde8) at parse.zig:172
frame #7: 0x000000000020467b test`Parser_parse(self=0x00007fffffffdde8) at parse.zig:163
frame #8: 0x0000000000203b4a test`parseInputFile(allocator=0x0000000000241000) at parse.zig:19
frame #9: 0x000000000020367f test`parse input at parse.zig:178
frame #10: 0x0000000000224ef8 test`main at test_runner.zig:11
frame #11: 0x0000000000224cfb test`callMain at bootstrap.zig:102
frame #12: 0x0000000000224c69 test`callMainWithArgs(argc=1) at bootstrap.zig:76
frame #13: 0x0000000000224a68 test`posixCallMainAndExit at bootstrap.zig:70
frame #14: 0x0000000000224910 test`_start at bootstrap.zig:43
I noticed at one point the arena allocator had its freeFn function pointer set to 0x1. Is it possible that realloc triggers a free that is invalid in an arena?
A little digging didn't help too much, but the failure of a new assertion I added is a bit disturbing.
pub fn init(allocator: *Allocator) RuleSet {
var arena = ArenaAllocator.init(allocator);
return RuleSet{
.arena = arena,
.map = RuleMap.init(&arena.allocator),
};
}
pub fn deinit(self: *RuleSet) void {
self.arena.deinit();
}
pub fn put(self: *RuleSet, name: []const u8) !*Rule {
var rule = try Rule.init(&self.arena.allocator, name);
std.debug.warn("put: {}\n", rule.name.toSliceConst());
std.debug.assert(self.map.allocator == &self.arena.allocator);
...
The map allocator is changing somewhere between init and put, but I have no idea how.
@andrewrk, i think this is because arena is copied in the init function, so this will be solved by #287.
Yeah that's right. The problem is here:
var arena = ArenaAllocator.init(allocator); // memory for arena.allocator is in this stack frame
return RuleSet{
.arena = arena,
.map = RuleMap.init(&arena.allocator), // returning a pointer that is about to become invalid
};
After #287 and after we have the ability to mark a field as "fixed" this would be a compile error, and it would be resolved by using the no-copy semantics.
Most helpful comment
@andrewrk, i think this is because
arenais copied in theinitfunction, so this will be solved by #287.