I’m sort of at a loss as to how to ask this question. I’m building up a tree data structure to test. I wrote a function shortTreeMock()
to construct a simple version of the tree.
After building the tree in main(), and when I go to read what’s inside, I find it panics on a corrupted tag on the 52nd node.
Weird thing is, if inside of shortTreeMock()
, there is code to loop through all nodes to read and display them, the loop inside of main will not find a corrupted tag on the 52nd node. But if I remove the code to loop through all nodes to read and display them, it will
It seems like the memory would be corrupted unless I read it inside of shortTreeMock()
first. This doesn’t make sense. I’m guessing it’s something else. What could be the culprit? How could I find out?
Details below.
Here is the output of zig build run
Leaf Node 49: { 10702, 0, 0, 0, 0, 0, 0, 0 }
Leaf Node 50: { 11047, 0, 0, 0, 0, 0, 0, 0 }
break here
Leaf Node 51: { 11167, 0, 0, 0, 0, 0, 0, 0 }
thread 9979832 panic: switch on corrupt value
/Users/iamwil/projects/code/fruitful_town/database/src/main.zig:20:17: 0x10288b4ff in main (database)
switch (node) {
^
/Users/iamwil/.zvm/0.13.0/lib/std/start.zig:524:37: 0x10288c44b in main (database)
const result = root.main() catch |err| {
^
???:?:?: 0x18651e0df in ??? (???)
???:?:?: 0x1f62ffffffffffff in ??? (???)
run
└─ run database failure
error: the following command terminated unexpectedly:
/Users/iamwil/projects/code/fruitful_town/database/zig-out/bin/database
Build Summary: 5/7 steps succeeded; 1 failed (disable with --summary none)
This is in test_helpers to build the tree
pub fn shortTreeMock(allocator: std.mem.Allocator) !prolly.OrderedMap(u32, u32) {
const randArr = try randomSortedUniqueArray(allocator, u32, 64, 0, 16384);
defer allocator.free(randArr);
const groups = try partition(allocator, u32, randArr, prolly.MAX_NODE_SIZE, prolly.MAX_NODE_SIZE);
defer allocator.free(groups);
// create all the child nodes.
// leave room at [0] for the root.
var branchNodes: [prolly.MAX_NODE_SIZE + 1]prolly.BranchNode(u32) = undefined;
for (groups, 0..) |group, groupIndex| {
var pivots: [prolly.MAX_NODE_SIZE]u32 = undefined;
// fill in pivots
for (group, 0..) |elem, idx| {
pivots[idx] = elem;
}
// create branch node
const branchNode = prolly.BranchNode(u32).initWithPivots(pivots);
try testing.expect(branchNode.pivots[0] == group[0]);
try testing.expect(branchNode.pivots[branchNode.pivots.len - 1] == group[branchNode.pivots.len - 1]);
branchNodes[groupIndex + 1] = branchNode;
}
// root pivots are the the min pivot for all child nodes
var pivots: [prolly.MAX_NODE_SIZE]u32 = undefined;
for (0..prolly.MAX_NODE_SIZE) |i| {
pivots[i] = branchNodes[i + 1].pivots[0];
}
branchNodes[0] = prolly.BranchNode(u32).initWithPivots(pivots);
// create all leaf nodes
var leafNodes: [prolly.MAX_NODE_SIZE * prolly.MAX_NODE_SIZE]prolly.LeafNode(u32, usize) = undefined;
for (branchNodes[1..], 1..) |childNode, branchIdx| {
for (childNode.pivots, 0..) |currPivot, pivotIdx| {
const leafIdx = (branchIdx - 1) * prolly.MAX_NODE_SIZE + pivotIdx;
// Currently, only a single key in the leaf, because figuring out
// the next pivot as max for random array is too much work at the moment.
const keys: [prolly.MAX_NODE_SIZE]u32 = .{ currPivot, 0, 0, 0, 0, 0, 0, 0 };
const valueIndexes: [prolly.MAX_NODE_SIZE]usize = .{ 0, 0, 0, 0, 0, 0, 0, 0 };
leafNodes[leafIdx] = prolly.LeafNode(u32, usize)
.initWithKeyIndexes(keys, valueIndexes);
std.debug.print("new leaf {}: {any}\n", .{ leafIdx + 9, leafNodes[leafIdx].keys });
}
}
const numNodes = 1 + prolly.MAX_NODE_SIZE + prolly.MAX_NODE_SIZE * prolly.MAX_NODE_SIZE;
std.debug.print("allocating {} nodes\n", .{numNodes});
var allNodes: [numNodes]prolly.Node(u32, usize) = undefined;
var idx: u32 = 0;
for (0..branchNodes.len) |branchIdx| {
allNodes[idx] = prolly.Node(u32, usize){ .Branch = branchNodes[branchIdx] };
idx += 1;
}
for (0..leafNodes.len) |leafIdx| {
allNodes[idx] = prolly.Node(u32, usize){ .Leaf = leafNodes[leafIdx] };
idx += 1;
}
// RIGHT HERE If this code to display the nodes isn't here, the display code in main errors out.
// for (allNodes, 0..) |node, i| {
// switch (node) {
// .Branch => |branchNode| {
// std.debug.print("p Branch Node {}: ", .{i});
// std.debug.print("{any}\n", .{branchNode.pivots});
// },
// .Leaf => |leafNode| {
// std.debug.print("p Leaf Node {}: ", .{i});
// std.debug.print("{any}\n", .{leafNode.keys});
// },
// }
// }
const seg = prolly.Segment(u32, u32, prolly.MAX_NODE_SIZE).init();
var segments: [1]prolly.Segment(u32, u32, prolly.MAX_NODE_SIZE) = .{seg};
const orderedMap = prolly.OrderedMap(u32, u32).initWithNodes(allocator, allNodes[0..], segments[0..]);
return orderedMap;
}
This is main that uses the tree. The loop to look in the tree is what errors out at the 52nd node.
pub fn main() !void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const allocator = arena.allocator();
const orderedMap = try test_helper.shortTreeMock(allocator);
std.debug.print("number of nodes: {}\n", .{orderedMap.nodes.len});
for (orderedMap.nodes, 0..) |node, i| {
if (i == 51) {
std.debug.print("break here\n", .{});
}
switch (node) {
.Branch => |branchNode| {
std.debug.print("Branch Node {}: ", .{i});
std.debug.print("{any}\n", .{branchNode.pivots});
},
.Leaf => |leafNode| {
std.debug.print("Leaf Node {}: ", .{i});
std.debug.print("{any}\n", .{leafNode.keys});
},
}
}
}