Skip to content

Commit 0eb16b8

Browse files
committed
fix(zig): repair broken CWE-704 fix using std.mem.sliceTo (was spanZ)
The previous CWE-704 fix in e72eae0 replaced @ptrCast with `std.mem.spanZ`, which was removed from Zig stdlib in 0.14 — under the 0.15.1 CI pin the Zig FFI tests will not even compile. The other site (`local_coord_ffi.zig:3291`) also used invalid syntax: if (json_args != null) |ja| std.mem.spanZ(ja) else "{}" [*c] pointers are null-checked with `== null`; the `|payload|` capture form is for optionals, not C-compat pointers. Switch to `std.mem.sliceTo(ptr, 0)`, which: * exists in Zig 0.15.x; * accepts `[*c]const u8` directly with no `@ptrCast`; * scans up to the first NUL and returns a `[]const u8`; * fully addresses the CWE-704 finding (no unchecked pointer type conversion remains in the modified call sites). Files: * cartridges/local-coord-mcp/ffi/cartridge_shim.zig — toolIs() * cartridges/local-coord-mcp/ffi/local_coord_ffi.zig — boj_cartridge_invoke() tool + args extraction. This unblocks the failing "Zig FFI Tests" check on PR #146 and lets the dependent "E2E — Full REST + MCP Bridge" and "Emit manifest + verify FFI" jobs run against a compilable library.
1 parent e72eae0 commit 0eb16b8

2 files changed

Lines changed: 14 additions & 3 deletions

File tree

cartridges/local-coord-mcp/ffi/cartridge_shim.zig

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,14 @@ pub fn invokeArgsNull(
5858
/// Compare a C-NUL-terminated tool-name pointer against a Zig string
5959
/// literal. Caller must have already verified `tool_name` is non-null
6060
/// (usually via `invokeArgsNull`).
61+
///
62+
/// Implementation note (CWE-704 fix, post-#146): uses
63+
/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first
64+
/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier
65+
/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not
66+
/// compile under the 0.15.1 CI pin.
6167
pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool {
62-
const s = std.mem.spanZ(tool_name);
68+
const s = std.mem.sliceTo(tool_name, 0);
6369
return std.mem.eql(u8, s, expected);
6470
}
6571

cartridges/local-coord-mcp/ffi/local_coord_ffi.zig

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3287,8 +3287,13 @@ export fn boj_cartridge_invoke(
32873287
in_out_len.* = 64; // hint a minimum useful size
32883288
return shim.RC_BUFFER_TOO_SMALL;
32893289
}
3290-
const tool = std.mem.spanZ(tool_name);
3291-
const args: []const u8 = if (json_args != null) |ja| std.mem.spanZ(ja) else "{}";
3290+
// CWE-704 fix (post-#146): std.mem.sliceTo(ptr, 0) reads the C string
3291+
// up to the first NUL without an `@ptrCast` and without the
3292+
// `std.mem.spanZ` that no longer exists in Zig 0.14+. The optional-payload
3293+
// capture `if (json_args != null) |ja|` was also invalid for [*c]
3294+
// pointers — those are null-checked with `== null`, not unwrapped.
3295+
const tool = std.mem.sliceTo(tool_name, 0);
3296+
const args: []const u8 = if (json_args == null) "{}" else std.mem.sliceTo(json_args, 0);
32923297
const result = ci_dispatch(tool, args, out_buf[0..cap], std.heap.page_allocator);
32933298
in_out_len.* = result.written;
32943299
return result.rc;

0 commit comments

Comments
 (0)