遇到Zig编译器错误GenericPoison,求问题排查与解答
平台详情
- macOS(Apple Silicon)
- Zig版本(所有版本表现一致)
- 0.10.0 aarch64
- 0.11-dev824 aarch64
问题描述
我编写了基础可组合迭代器的代码:
pub fn RangeIterator(comptime NumberType: type) type { return struct { const This = @This(); const Item = NumberType; start: NumberType, step: NumberType, len: usize, _index: usize = 0, fn next(this: *This) !?Item { if (this._index >= this.len) { return null; } defer this._index += 1; return this.start + (this.step * @intCast(NumberType, this._index)); } }; } test "range iterator" { // 这些测试可以通过! var iterator = RangeIterator(u32){.start = 1, .step = 3, .len = 5}; try std.testing.expectEqual(iterator.next(), 1); try std.testing.expectEqual(iterator.next(), 4); try std.testing.expectEqual(iterator.next(), 7); try std.testing.expectEqual(iterator.next(), 10); try std.testing.expectEqual(iterator.next(), 13); try std.testing.expectEqual(iterator.next(), null); } // 基于Zig标准库中BufferedWriter的实现模式 pub fn IterWhile( comptime IteratorType: type, comptime ItemType: type, comptime include_last: bool, ) type { return struct { const This = @This(); const Item = ItemType; iterator: IteratorType, predicate: fn (ItemType) bool, _is_spent: bool = false, pub fn next(this: *This) ?ItemType { if (this._is_spent) { return null; } const result = try this.iterator.next(); if (result == null) { return null; } if (!this.predicate(result)) { this._is_spent = true; if (!include_last) return null; } return result; } }; } pub fn iterWhile( iterator: anytype, predicate: fn (anytype) bool, comptime include_last: bool, ) IterWhile( @TypeOf(iterator), @typeInfo(predicate).Fn.args[0].arg_type, include_last, ) { return .{ .iterator = iterator, .predicate = predicate }; } test "iter while" { // 这些测试会触发编译器错误 :S var range = RangeIterator(u32){.start = 1, .step = 3, .len = 5}; var iterator = iterWhile(range, TestUtils.isOneDigit, false); try std.testing.expectEqual(iterator.next(), 1); try std.testing.expectEqual(iterator.next(), 4); try std.testing.expectEqual(iterator.next(), 7); try std.testing.expectEqual(iterator.next(), null); } const TestUtils = struct { fn isOneDigit(value: u32) bool { return value < 10; } };
注释掉第二个测试块"iter while"时,测试可正常通过;但保留该测试块时,会触发以下错误:
thread 1531026 panic: zig compiler bug: GenericPoison Unable to dump stack trace: debug info stripped zsh: abort zig test src/utils/iterator.zig
疑问
- 能否帮忙排查代码问题?或者这是编译器自身的问题?
debug info stripped——为何会出现这种情况?我未传入任何发布构建参数,难道不是运行在调试模式吗?
问题排查与解答
1. 代码问题与编译器bug分析
你的代码存在两处问题,这些问题触发了编译器内部panic:
- 迭代器传递方式错误:
RangeIterator的next方法需要接收指针(*This),但调用iterWhile时直接传递了range的值而非指针,导致IterWhile内部无法调用需要指针的next方法。正确写法是传递指针:iterWhile(&range, TestUtils.isOneDigit, false)。 - 可选类型不匹配:
RangeIterator.next返回!?Item(错误联合包裹的可选值),try后得到?Item,但TestUtils.isOneDigit接收的是u32而非?u32。需要先解包可选值再传入断言函数,同时IterWhile.next也需要返回!?ItemType(因为内部调用了可能返回错误的迭代器方法)。
修改后的IterWhile.next示例:
pub fn next(this: *This) !?ItemType { if (this._is_spent) { return null; } const result = try this.iterator.next(); if (result == null) { return null; } const val = result.?; if (!this.predicate(val)) { this._is_spent = true; if (!include_last) return null; } return val; }
虽然代码存在问题,但编译器出现GenericPoison panic属于编译器自身bug,可在Zig官方仓库提交issue反馈。
2. debug info stripped 原因说明
这个提示指的是Zig编译器自身的二进制没有包含调试信息,不是你编写的代码问题。预编译的Zig发布版本通常会剥离调试信息以减小体积,因此编译器内部panic时无法生成自身的栈跟踪。如果需要查看编译器栈跟踪,需要从源码编译带调试信息的Zig版本,而非使用预编译的发布包。
内容的提问来源于stack exchange,提问作者CrepeGoat
相关产品推荐
相关产品推荐

