Zig 0.16 - #14
Conversation
Winarm64 cross runtime check
优化 Zig 0.16 文件句柄流复制路径
Walkthrough本PR更新Zig版本要求从0.15.2至0.16.0,完善CI流程以支持Windows ARM64交叉编译,改进流运行时与Windows兼容性,调整汇编堆栈管理策略,并修订相关测试。 Changes
Sequence DiagramsequenceDiagram
participant Go as Go 测试/应用
participant ZigRT as Zig 运行时<br/>go2zig_runtime.zig
participant Platform as 平台层<br/>(Windows/POSIX)
Go->>ZigRT: copy_stream(reader, writer)
ZigRT->>ZigRT: streamFile(reader_handle)
alt 有效文件句柄
ZigRT->>ZigRT: copy_stream_file_handles()
alt Windows 平台
ZigRT->>Platform: std.Io.File 流式读/写
Platform-->>ZigRT: 数据/错误
else 非 Windows 平台
ZigRT->>Platform: std.posix.read/write
Platform-->>ZigRT: 字节计数/错误
end
ZigRT-->>Go: 复制字节数
else 无文件句柄
ZigRT->>ZigRT: 缓冲读/写循环
ZigRT-->>Go: 复制字节数
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Code Review
This pull request updates the project to Zig 0.16.0 across documentation, CI configurations, and source code. Key changes include the implementation of stack alignment in amd64 assembly macros and a refactor of the stream I/O logic to utilize std.Io.Threaded for better Windows compatibility. Review feedback focuses on ensuring thread safety when the Zig runtime is invoked from Go's multi-threaded environment, specifically recommending the use of std.Io.Threaded.global instead of single-threaded instances. Additionally, it is suggested to simplify the manual POSIX write loops by leveraging the improved std.posix.write wrapper available in Zig 0.16.0.
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
docs/en/ci.md (1)
13-20:⚠️ Potential issue | 🟡 MinorKeep the Windows ARM64 exception reflected here.
This says every matrix entry installs Zig, but the workflow skips Zig setup for
windows/arm64tests and uses the downloaded prebuiltbasic.dllinstead. Please document that exception.Suggested wording
- - Install Zig `0.16.0` + - Install Zig `0.16.0`, except for the `windows/arm64` test job, which uses a prebuilt downloaded `basic.dll`🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/en/ci.md` around lines 13 - 20, Update the CI docs to reflect the Windows ARM64 exception: in docs/en/ci.md add a brief note after the matrix bullet list explaining that the workflow does not install Zig for the windows/arm64 job but instead skips Zig setup and uses a prebuilt examples/basic/basic.dll artifact; reference the job/platform as "windows/arm64" and mention that other matrix entries still install Zig 0.16.0 and regenerate examples/basic before testing.docs/ci.md (1)
13-20:⚠️ Potential issue | 🟡 Minor同步 Windows ARM64 的 CI 描述。
这里写成“每个矩阵条目都会安装 Zig”,但工作流里
windows/arm64测试项是setup_zig: false,改为下载预构建basic.dll。建议把这条改成例外描述,避免本地复现或排查 CI 时误判。建议调整
- - 安装 Zig `0.16.0` + - 除 `windows/arm64` 测试 job 外安装 Zig `0.16.0`;`windows/arm64` 使用预构建并下载的 `basic.dll`🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/ci.md` around lines 13 - 20, 把文档中通用说明“安装 Zig `0.16.0`”改为对 windows/arm64 的例外说明:在说明列表中保留一条通用行为“安装 Zig `0.16.0`”,并在同一段或紧随其后的句子里明确标注当测试矩阵项为 `windows/arm64`(workflow 中 `setup_zig: false`)时不会安装 Zig 而是下载预构建的 `basic.dll`,以便读者和 CI 排查时不会误以为该平台也做本地 Zig 安装或编译。examples/stream/stream_test.go (1)
183-229:⚠️ Potential issue | 🟡 Minor
TestCopyStreamHandlesPartialWrites依赖对生成代码的字符串替换,耦合脆弱Line 186-187 对
go2zig_runtime.zig源做字面字符串替换来注入"每次最多写 17 字节"的逻辑。只要生成器或静态样例中那段代码的空白 / 换行 / 分号有任何微调,strings.Replace(..., 1)会静默命中 0 次、然后用"未改过的运行时"去测试,测试仍然会通过(因为逻辑上等价),失去了"验证分片写入"的覆盖意义。建议要么:
- 在替换后立即断言
runtimeSource与原文不同(if runtimeSource == original { t.Fatalf(...) });或- 将"人为限制最大写"这一行为抽成 runtime 中可参数化的开关(如
extern const stream_write_cap),避免测试依赖字面匹配。🛡️ 建议增加替换生效的前置断言
runtimeSource := strings.Replace( string(readStreamExampleFile(t, "go2zig_runtime.zig")), "if (buffer.len > available) return error.StreamWriteFailed;\n const dst = `@as`([*]u8, `@ptrCast`(state.ptr.?))[state.len..][0..buffer.len];\n `@memcpy`(dst, buffer);\n state.len += buffer.len;\n return buffer.len;", "const limit = `@min`(buffer.len, `@as`(usize, 17));\n if (limit > available) return error.StreamWriteFailed;\n const dst = `@as`([*]u8, `@ptrCast`(state.ptr.?))[state.len..][0..limit];\n `@memcpy`(dst, buffer[0..limit]);\n state.len += limit;\n return limit;", 1, ) + if !strings.Contains(runtimeSource, "const limit = `@min`(buffer.len, `@as`(usize, 17));") { + t.Fatalf("runtime source replacement did not take effect; update the anchor string") + } libPath := buildCustomStreamRuntime(t, "", runtimeSource)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@examples/stream/stream_test.go` around lines 183 - 229, The test TestCopyStreamHandlesPartialWrites mutates the runtime by calling strings.Replace on the string returned by readStreamExampleFile to inject a 17-byte write limit but doesn't verify the replacement succeeded; add an immediate assertion after creating runtimeSource (using the original string from readStreamExampleFile or by checking runtimeSource contains the expected "const limit" snippet) and call t.Fatalf if the replacement didn't change runtimeSource so the test fails fast when strings.Replace matched 0 occurrences; reference runtimeSource, readStreamExampleFile, strings.Replace and buildCustomStreamRuntime when adding this check.
🧹 Nitpick comments (5)
asmcall/amd64.s (1)
5-17: 移除不可达的 Windows 条件分支。文件 Line 1 限定
//go:build amd64 && !windows,因此 Line 5 的#ifdef GOOS_windows分支在此文件中永远不会被编译。Windows 的 ABI 处理已在独立的asmcall/amd64_windows.s中实现。在不可达分支中添加RTMP0定义容易误导维护者。♻️ 可选简化
-#ifdef GOOS_windows -#define RARG0 CX -#define RARG1 DX -#define RARG2 R8 -#define RRET AX -#define RTMP0 R9 -#else `#define` RARG0 DI `#define` RARG1 SI `#define` RARG2 DX `#define` RRET AX `#define` RTMP0 CX -#endif🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@asmcall/amd64.s` around lines 5 - 17, Remove the unreachable Windows conditional block guarded by `#ifdef GOOS_windows` and keep only the non-Windows macro definitions so the file matches the `//go:build amd64 && !windows` restriction; specifically delete the entire `#ifdef GOOS_windows ... `#else`` branch and ensure the remaining definitions set RARG0=DI, RARG1=SI, RARG2=DX, RRET=AX and RTMP0=CX (the symbols to look for are the macros RARG0, RARG1, RARG2, RRET, RTMP0 and the `#ifdef GOOS_windows`/`#else`/`#endif` conditional).internal/generator/generator.go (1)
305-324:streamFile仅剔除了低位标志,未过滤 direct reader/writer 标志之外的情形
streamFile通过(value & stream_handle_mask) != 0拒绝所有带低 2 位标志的句柄(包括 direct_reader=0x1、direct_writer=0x2),仅放行标志为 0 的"编码过的 fd"路径,与streamRead/streamWrite中对 direct tag 的处理保持互补,整体一致。不过此处有一个隐藏前提:
streamFileFromEncoded会直接计算(value >> 2) - 1。若value恰为某个"编码为 0"的合法值(编码规则(handle + 1) << 2,当handle == usize_max >> 2 - 1时),外层已经由_go2zigEncodeFileHandle的maxEncodedFileHandle检查在 Go 侧拦截(见 Line 759–761 生成片段)。但streamFile本身并没有做这层自校验——只依赖调用方传入的是合法编码。作为面向公共 API 的pub inline fn(被examples/stream/lib.zig:6-7直接使用),建议补充对(value >> 2) == 0的防御性return null,避免下溢触发未定义行为。♻️ 建议增加下溢防御
pub inline fn streamFile(value: usize) ?std.Io.File { if (value == 0) return null; if ((value & stream_handle_mask) != 0) return null; + if ((value >> 2) == 0) return null; return streamFileFromEncoded(value); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@internal/generator/generator.go` around lines 305 - 324, streamFile currently only masks low bits and then calls streamFileFromEncoded which computes (value >> 2) - 1, risking underflow if value encodes to 0; add a defensive check in pub inline fn streamFile(value: usize) ?std.Io.File to return null when (value >> 2) == 0 before calling streamFileFromEncoded. Update streamFile to perform both the existing low-bit mask check and this new zero-after-shift check so streamFileFromEncoded/streamHandleFromEncoded never see a value that would underflow.internal/generator/generator_test.go (1)
325-325: 单行过长的 checks 列表降低可读性
TestRenderStreamsWithExperimentalFlag的 checks 切片被全部塞进一行(Line 325),包含 20+ 条字符串断言。这类"黄金字符串"测试在跨行格式时通常更易维护(diff 也更局部化)。建议拆分为多行字面量:♻️ 建议拆分为多行以便 diff 与评审
- for _, check := range []string{"const builtin = `@import`(\"builtin\");", "inline fn streamHandleFromUsize(value: usize) std.Io.File.Handle", /* …many items… */, "return streamWriteCompat(streamHandleFromEncoded(writer), buffer) catch { return error.StreamWriteFailed; };"} { + for _, check := range []string{ + "const builtin = `@import`(\"builtin\");", + "inline fn streamHandleFromUsize(value: usize) std.Io.File.Handle", + "inline fn streamHandleFromEncoded(value: usize) std.Io.File.Handle", + "inline fn streamFileFromEncoded(value: usize) std.Io.File", + "pub inline fn streamFile(value: usize) ?std.Io.File", + "if ((value & stream_handle_mask) != 0) return null;", + "const stream_handle_direct_reader: usize = 0x1;", + "const DirectReaderState = extern struct", + "const DirectWriterState = extern struct", + "const stream_is_windows = builtin.os.tag == .windows;", + "inline fn streamReadCompat(handle: std.Io.File.Handle, buffer: []u8) anyerror!usize", + "const io = std.Io.Threaded.global_single_threaded.io();", + "return file.readStreaming(io, &.{buffer}) catch |err| switch (err) {", + "error.EndOfStream => 0,", + "std.posix.read(handle, buffer)", + "inline fn streamWriteCompat(handle: std.Io.File.Handle, buffer: []const u8) anyerror!usize", + "return file.writeStreaming(io, &.{}, &.{buffer}, 1);", + "std.posix.system.write(handle, buffer.ptr, buffer.len)", + "std.posix.errno(rc)", + "pub fn streamRead(reader: usize, buffer: []u8)", + "pub fn streamWrite(writer: usize, buffer: []const u8)", + "const n = streamReadCompat(streamHandleFromEncoded(reader), buffer) catch { return error.StreamReadFailed; };", + "if (n == 0) return error.EndOfStream;", + "return streamWriteCompat(streamHandleFromEncoded(writer), buffer) catch { return error.StreamWriteFailed; };", + } {另外建议补充一条断言覆盖
streamWriteCompat在非 Windows 分支的 errno case(例如".PIPE => return error.BrokenPipe,"),保证 errno→error 映射表被测试显式锁定,避免未来误删。🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@internal/generator/generator_test.go` at line 325, The checks slice in TestRenderStreamsWithExperimentalFlag is a single very long line which harms readability; split the []string literal across multiple lines so each expected string (e.g. "const builtin = `@import`(\"builtin\");", "inline fn streamHandleFromUsize(value: usize) std.Io.File.Handle", "inline fn streamWriteCompat(handle: std.Io.File.Handle, buffer: []const u8) anyerror!usize", "pub fn streamRead(reader: usize, buffer: []u8)", etc.) is on its own line to make diffs smaller and reviews easier, and while editing add one more assertion covering the non-Windows errno→error mapping for streamWriteCompat (for example an entry for ".PIPE => return error.BrokenPipe,") so the errno mapping logic for streamWriteCompat is explicitly tested; update the checks used in TestRenderStreamsWithExperimentalFlag accordingly.examples/stream/stream_test.go (1)
88-114: 三处client/rt/lib关闭 cleanup 完全重复,建议抽取辅助函数
TestCopyStreamFileHandles、TestCopyStreamFileHandlesRepeated、TestCopyStreamDoesNotPanicOnWriterCloseError(以及部分TestCopyStreamHandlesPartialWrites)都重复了同一个 client 构造+Load+Cleanup 的 5 行模板。可提炼一个 helper:♻️ 建议抽取 `newLoadedClient` helper
+func newLoadedClient(t *testing.T, path string) *Go2ZigClient { + t.Helper() + client := NewGo2ZigClient(path) + if err := client.Load(); err != nil { + t.Fatalf("Load() error = %v", err) + } + t.Cleanup(func() { + if client != nil && client.rt != nil && client.rt.lib != nil { + _ = client.rt.lib.Close() + } + }) + return client +} func TestCopyStreamFileHandles(t *testing.T) { - prepareStreamRuntime(t) - client := NewGo2ZigClient(prepareRuntimePath) - if err := client.Load(); err != nil { - t.Fatalf("Load() error = %v", err) - } - t.Cleanup(func() { - if client != nil && client.rt != nil && client.rt.lib != nil { - _ = client.rt.lib.Close() - } - }) + prepareStreamRuntime(t) + client := newLoadedClient(t, prepareRuntimePath) payload := bytes.Repeat([]byte("go2zig-stream-copy-"), 1024) copyStreamFileHandlesOnce(t, client, payload) }Also applies to: 195-241
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@examples/stream/stream_test.go` around lines 88 - 114, Several tests repeat the same client setup and cleanup (prepareStreamRuntime, NewGo2ZigClient(prepareRuntimePath), client.Load() and the t.Cleanup that closes client.rt.lib) — extract a helper like newLoadedClient(t *testing.T) that calls prepareStreamRuntime, constructs NewGo2ZigClient(prepareRuntimePath), checks client.Load() and registers a single t.Cleanup that safely closes client.rt.lib (checking nils) and return the loaded client; update TestCopyStreamFileHandles, TestCopyStreamFileHandlesRepeated, TestCopyStreamDoesNotPanicOnWriterCloseError and TestCopyStreamHandlesPartialWrites to use newLoadedClient instead of duplicating the five-line setup/cleanup.examples/stream/lib.zig (1)
9-14: 每次调用都新建std.Io.Threaded实例,与 runtime 的global_single_threaded不一致此处使用
.init_single_threaded在栈上创建一次性实例,而go2zig_runtime.zig中的streamReadCompat/streamWriteCompat使用的是std.Io.Threaded.global_single_threaded.io()。两者都不支持真正的多线程并发,但行为细节存在差异:
init_single_threaded是栈上的局部实例,生命周期与本函数一致,scope 退出即回收;global_single_threaded是进程级全局单例,根据 Zig 0.16 release notes,它与-fsingle-threaded配合使用时不支持任务级并发与取消。若
copy_stream_file_handles在 Go 多 goroutine 并发调用下被触发(FFI 场景常见),sendFileAll内部可能借助 io 实例持有瞬态资源,各实例相互独立是安全的;但如果未来切换为global_single_threaded以保持一致性,则需要重新评估并发安全。建议保留当前写法并添加一行注释说明"为并发安全而刻意每次新建",或用其他手段明确两处选择的差异。🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@examples/stream/lib.zig` around lines 9 - 14, The current code creates a new std.Io.Threaded via .init_single_threaded for each call (variables reader_buf/writer_buf, src.readerStreaming and dst.writerStreaming), which differs from the runtime's std.Io.Threaded.global_single_threaded used by streamReadCompat/streamWriteCompat; either explicitly document why we create per-call instances for concurrency safety (e.g., when copy_stream_file_handles or sendFileAll may be called concurrently from FFI) or switch both call sites to use the same global_single_threaded strategy—add a concise comment next to the .init_single_threaded instantiation explaining the deliberate choice (or replace with global_single_threaded and ensure concurrency implications are re-evaluated).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/workflows/ci.yml:
- Around line 13-30: The build-winarm64-runtime job compiles
examples/basic/go2zig_build_root.zig before the repository's "Prepare basic
example" step runs, so the artifact can be built from stale generated sources;
modify the job to regenerate the basic example first (e.g., add the same
"Prepare basic example" step or run the generator script) prior to invoking zig,
ensuring the job name build-winarm64-runtime runs the prepare step that produces
examples/basic/go2zig_build_root.zig (or depends on the job that does) so the
produced basic.dll reflects the latest generator/runtime changes.
In `@examples/basic/testlib_test.go`:
- Around line 33-37: 当前用 os.Stat 只检查了路径存在但没拒绝目录:在对 basicRuntimePathEnv
做存在性检查后(在现在设置 prepareRuntimeErr 的分支中或紧接其后),调用 os.Stat(...) 返回的 FileInfo 并用
fi.IsDir() 判断是否为目录;如果是目录则设置 prepareRuntimeErr 为类似 "override path %s is a
directory" 的错误并返回,确保不要把目录赋给
prepareRuntimePath。引用符号:basicRuntimePathEnv、prepareRuntimeErr、prepareRuntimePath、os.Stat、FileInfo.IsDir。
In `@examples/stream/lib.zig`:
- Around line 5-22: The function copy_stream_file_handles currently returns the
byte count from dst_writer.interface.sendFileAll (copied) before calling
dst_writer.flush, which means a later flush failure invalidates the reported
"written" bytes; change the flow in copy_stream_file_handles to call
dst_writer.flush() immediately after sendFileAll succeeds and only then return
`@intCast`(copied); keep the existing error mapping for sendFileAll
(error.ReadFailed / error.WriteFailed) and make flush failures return
error.StreamWriteFailed as before so the returned integer always represents
bytes that have been flushed/persisted; update references to sendFileAll,
dst_writer.flush, and copied accordingly.
In `@internal/generator/generator.go`:
- Around line 346-376: The non-Windows branch of streamWriteCompat reimplements
errno-to-error mapping manually (including mapping BADF to error.Unexpected)
which is asymmetric with streamReadCompat and risks incorrect/ incomplete
mappings; change streamWriteCompat to call std.posix.write directly (like
streamReadCompat) so the stdlib handles EINTR/retries and full errno
translation, and if you still need special-casing replace the BADF =>
error.Unexpected mapping with a clear intented error (e.g.
error.NotOpenForWriting or error.InvalidHandle) only after calling
std.posix.write and inspecting the returned error.
---
Outside diff comments:
In `@docs/ci.md`:
- Around line 13-20: 把文档中通用说明“安装 Zig `0.16.0`”改为对 windows/arm64
的例外说明:在说明列表中保留一条通用行为“安装 Zig `0.16.0`”,并在同一段或紧随其后的句子里明确标注当测试矩阵项为
`windows/arm64`(workflow 中 `setup_zig: false`)时不会安装 Zig 而是下载预构建的
`basic.dll`,以便读者和 CI 排查时不会误以为该平台也做本地 Zig 安装或编译。
In `@docs/en/ci.md`:
- Around line 13-20: Update the CI docs to reflect the Windows ARM64 exception:
in docs/en/ci.md add a brief note after the matrix bullet list explaining that
the workflow does not install Zig for the windows/arm64 job but instead skips
Zig setup and uses a prebuilt examples/basic/basic.dll artifact; reference the
job/platform as "windows/arm64" and mention that other matrix entries still
install Zig 0.16.0 and regenerate examples/basic before testing.
In `@examples/stream/stream_test.go`:
- Around line 183-229: The test TestCopyStreamHandlesPartialWrites mutates the
runtime by calling strings.Replace on the string returned by
readStreamExampleFile to inject a 17-byte write limit but doesn't verify the
replacement succeeded; add an immediate assertion after creating runtimeSource
(using the original string from readStreamExampleFile or by checking
runtimeSource contains the expected "const limit" snippet) and call t.Fatalf if
the replacement didn't change runtimeSource so the test fails fast when
strings.Replace matched 0 occurrences; reference runtimeSource,
readStreamExampleFile, strings.Replace and buildCustomStreamRuntime when adding
this check.
---
Nitpick comments:
In `@asmcall/amd64.s`:
- Around line 5-17: Remove the unreachable Windows conditional block guarded by
`#ifdef GOOS_windows` and keep only the non-Windows macro definitions so the
file matches the `//go:build amd64 && !windows` restriction; specifically delete
the entire `#ifdef GOOS_windows ... `#else`` branch and ensure the remaining
definitions set RARG0=DI, RARG1=SI, RARG2=DX, RRET=AX and RTMP0=CX (the symbols
to look for are the macros RARG0, RARG1, RARG2, RRET, RTMP0 and the `#ifdef
GOOS_windows`/`#else`/`#endif` conditional).
In `@examples/stream/lib.zig`:
- Around line 9-14: The current code creates a new std.Io.Threaded via
.init_single_threaded for each call (variables reader_buf/writer_buf,
src.readerStreaming and dst.writerStreaming), which differs from the runtime's
std.Io.Threaded.global_single_threaded used by
streamReadCompat/streamWriteCompat; either explicitly document why we create
per-call instances for concurrency safety (e.g., when copy_stream_file_handles
or sendFileAll may be called concurrently from FFI) or switch both call sites to
use the same global_single_threaded strategy—add a concise comment next to the
.init_single_threaded instantiation explaining the deliberate choice (or replace
with global_single_threaded and ensure concurrency implications are
re-evaluated).
In `@examples/stream/stream_test.go`:
- Around line 88-114: Several tests repeat the same client setup and cleanup
(prepareStreamRuntime, NewGo2ZigClient(prepareRuntimePath), client.Load() and
the t.Cleanup that closes client.rt.lib) — extract a helper like
newLoadedClient(t *testing.T) that calls prepareStreamRuntime, constructs
NewGo2ZigClient(prepareRuntimePath), checks client.Load() and registers a single
t.Cleanup that safely closes client.rt.lib (checking nils) and return the loaded
client; update TestCopyStreamFileHandles, TestCopyStreamFileHandlesRepeated,
TestCopyStreamDoesNotPanicOnWriterCloseError and
TestCopyStreamHandlesPartialWrites to use newLoadedClient instead of duplicating
the five-line setup/cleanup.
In `@internal/generator/generator_test.go`:
- Line 325: The checks slice in TestRenderStreamsWithExperimentalFlag is a
single very long line which harms readability; split the []string literal across
multiple lines so each expected string (e.g. "const builtin =
`@import`(\"builtin\");", "inline fn streamHandleFromUsize(value: usize)
std.Io.File.Handle", "inline fn streamWriteCompat(handle: std.Io.File.Handle,
buffer: []const u8) anyerror!usize", "pub fn streamRead(reader: usize, buffer:
[]u8)", etc.) is on its own line to make diffs smaller and reviews easier, and
while editing add one more assertion covering the non-Windows errno→error
mapping for streamWriteCompat (for example an entry for ".PIPE => return
error.BrokenPipe,") so the errno mapping logic for streamWriteCompat is
explicitly tested; update the checks used in
TestRenderStreamsWithExperimentalFlag accordingly.
In `@internal/generator/generator.go`:
- Around line 305-324: streamFile currently only masks low bits and then calls
streamFileFromEncoded which computes (value >> 2) - 1, risking underflow if
value encodes to 0; add a defensive check in pub inline fn streamFile(value:
usize) ?std.Io.File to return null when (value >> 2) == 0 before calling
streamFileFromEncoded. Update streamFile to perform both the existing low-bit
mask check and this new zero-after-shift check so
streamFileFromEncoded/streamHandleFromEncoded never see a value that would
underflow.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 7bd105cf-69d1-4a04-b515-e902fda25063
📒 Files selected for processing (23)
.github/workflows/ci.ymlREADME.mdREADME_ja.mdREADME_zh.mdasmcall/amd64.sasmcall/amd64_windows.sdocs/ci.en.mddocs/ci.mddocs/en/ci.mddocs/en/usage.mddocs/ja/ci.mddocs/ja/usage.mddocs/usage.en.mddocs/usage.mddocs/zh/ci.mddocs/zh/usage.mdexamples/basic/testlib_test.goexamples/stream/bench_test.goexamples/stream/go2zig_runtime.zigexamples/stream/lib.zigexamples/stream/stream_test.gointernal/generator/generator.gointernal/generator/generator_test.go
💤 Files with no reviewable changes (1)
- examples/stream/bench_test.go
Summary by CodeRabbit
发行说明
新功能
文档
基础设施