From ae1343a82c91e61ed6c7272c9fcd755d5b84dda7 Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Fri, 17 Jul 2026 20:15:30 +0100 Subject: [PATCH] fix(ffi): remove redundant @ptrCast from cartridge shims (CWE-704) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sweeps all 114 vendored copies of cartridge_shim.zig in boj-server — including the canonical shared source ffi/zig/src/cartridge_shim.zig — to the blessed post-#146 idiom: std.mem.sliceTo(tool_name, 0) with [*c]const u8 test locals and no @ptrCast. Mirrors PR #89 in boj-server-cartridges, which is the split-out of these cartridges. Why the casts were redundant, not unsafe: a [*:0]const u8 sentinel pointer coerces implicitly to the [*c]const u8 that toolIs/invokeArgsNull accept, so @ptrCast(name) was a no-op widening — but a C-oriented scanner (Hypatia code_safety/zig_ptr_cast, CWE-704) still flags it as an unchecked pointer type conversion. Typing the local as [*c]const u8 up front removes the finding rather than suppressing it. Also folds in ffi/zig/src/abi_verify.zig (ABI-conformance tests C.6/C.7), which called shim.toolIs/invokeArgsNull via @ptrCast. NOTE: that file was modified in the shared working tree by a concurrent agent; it is included here because it is the identical CWE-704 fix — flag if it should land separately. Verification (zig 0.15.2, the CI-pinned version): - every cartridge_shim.zig compiles and passes `zig test` standalone; - the edited abi_verify C.6/C.7 idiom verified in isolation against the real shim (8/8), since the full `zig build test` graph does not compile under 0.15.2 for reasons unrelated to this change (see below). Out of scope, reported separately: (1) .github/workflows/zig-test.yml has been startup_failure (0s) on main since >=2026-07-09, so this repo's Zig CI validates nothing and this PR's zig-test check cannot pass on any branch; (2) catalogue/guardian/loader/coprocessor/sdp reference the removed std.atomic.Mutex and do not compile under the pinned 0.15.2. Co-Authored-By: Claude Opus 4.8 --- .../ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/aerie-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../affinescript-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/agent-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../airtable-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/arango-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/aws-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/bofig-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/browser-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/bsp-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../bug-filing-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../buildkite-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../burble-admin-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../circleci-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../civic-connect-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../ffi/cartridge_shim.zig | 26 ++++++++++++------- .../claude-ai-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../clickhouse-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/cloud-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../cloudflare-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/coderag-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../codeseeker-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/comms-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/conflow-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../container-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/crates-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/dap-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../database-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../digitalocean-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/discord-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../dns-shield-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../docker-hub-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/duckdb-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/ephapax-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../feedback-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../fireflag-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/fleet-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/fly-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../game-admin-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/gcp-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/git-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../github-actions-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../github-api-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../gitlab-api-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../google-docs-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../google-drive-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../google-sheets-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../gossamer-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/grafana-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/hackage-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/hesiod-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/hetzner-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/hex-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/hypatia-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/iac-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../idaptik-admin-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/jira-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/k8s-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/k9iser-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../kategoria-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/laminar-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/lang-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/linear-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/linode-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../local-memory-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/lsp-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/matrix-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/ml-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../model-router-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/mongodb-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/neo4j-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/neon-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/nesy-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../notifyhub-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/notion-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../npm-registry-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/observe-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../obsidian-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/opam-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../opendata-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/opsm-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/origene-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../panic-attack-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/pmpl-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../postgresql-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../prometheus-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/proof-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/pypi-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/queues-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/railway-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/redis-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/render-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../reposystem-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../research-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/rokur-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../sanctify-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/secrets-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/sentry-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/slack-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/ssg-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/stapeln-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../supabase-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../telegram-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/todoist-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../toolchain-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/turso-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../typed-wasm-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/ums-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/vault-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- .../verisimdb-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/vext-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/vordr-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- cartridges/zotero-mcp/ffi/cartridge_shim.zig | 26 ++++++++++++------- ffi/zig/src/abi_verify.zig | 18 ++++++------- ffi/zig/src/cartridge_shim.zig | 26 ++++++++++++------- 115 files changed, 1833 insertions(+), 1149 deletions(-) diff --git a/cartridges/academic-workflow-mcp/ffi/cartridge_shim.zig b/cartridges/academic-workflow-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/academic-workflow-mcp/ffi/cartridge_shim.zig +++ b/cartridges/academic-workflow-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/aerie-mcp/ffi/cartridge_shim.zig b/cartridges/aerie-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/aerie-mcp/ffi/cartridge_shim.zig +++ b/cartridges/aerie-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/affinescript-mcp/ffi/cartridge_shim.zig b/cartridges/affinescript-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/affinescript-mcp/ffi/cartridge_shim.zig +++ b/cartridges/affinescript-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/agent-mcp/ffi/cartridge_shim.zig b/cartridges/agent-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/agent-mcp/ffi/cartridge_shim.zig +++ b/cartridges/agent-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/airtable-mcp/ffi/cartridge_shim.zig b/cartridges/airtable-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/airtable-mcp/ffi/cartridge_shim.zig +++ b/cartridges/airtable-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/arango-mcp/ffi/cartridge_shim.zig b/cartridges/arango-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/arango-mcp/ffi/cartridge_shim.zig +++ b/cartridges/arango-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/aws-mcp/ffi/cartridge_shim.zig b/cartridges/aws-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/aws-mcp/ffi/cartridge_shim.zig +++ b/cartridges/aws-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/bofig-mcp/ffi/cartridge_shim.zig b/cartridges/bofig-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/bofig-mcp/ffi/cartridge_shim.zig +++ b/cartridges/bofig-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/browser-mcp/ffi/cartridge_shim.zig b/cartridges/browser-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/browser-mcp/ffi/cartridge_shim.zig +++ b/cartridges/browser-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/bsp-mcp/ffi/cartridge_shim.zig b/cartridges/bsp-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/bsp-mcp/ffi/cartridge_shim.zig +++ b/cartridges/bsp-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/bug-filing-mcp/ffi/cartridge_shim.zig b/cartridges/bug-filing-mcp/ffi/cartridge_shim.zig index 0e399dbb..5b0fac88 100644 --- a/cartridges/bug-filing-mcp/ffi/cartridge_shim.zig +++ b/cartridges/bug-filing-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/buildkite-mcp/ffi/cartridge_shim.zig b/cartridges/buildkite-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/buildkite-mcp/ffi/cartridge_shim.zig +++ b/cartridges/buildkite-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/burble-admin-mcp/ffi/cartridge_shim.zig b/cartridges/burble-admin-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/burble-admin-mcp/ffi/cartridge_shim.zig +++ b/cartridges/burble-admin-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/circleci-mcp/ffi/cartridge_shim.zig b/cartridges/circleci-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/circleci-mcp/ffi/cartridge_shim.zig +++ b/cartridges/circleci-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/civic-connect-mcp/ffi/cartridge_shim.zig b/cartridges/civic-connect-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/civic-connect-mcp/ffi/cartridge_shim.zig +++ b/cartridges/civic-connect-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/claude-agents-power-mcp/ffi/cartridge_shim.zig b/cartridges/claude-agents-power-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/claude-agents-power-mcp/ffi/cartridge_shim.zig +++ b/cartridges/claude-agents-power-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/claude-ai-mcp/ffi/cartridge_shim.zig b/cartridges/claude-ai-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/claude-ai-mcp/ffi/cartridge_shim.zig +++ b/cartridges/claude-ai-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/clickhouse-mcp/ffi/cartridge_shim.zig b/cartridges/clickhouse-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/clickhouse-mcp/ffi/cartridge_shim.zig +++ b/cartridges/clickhouse-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/cloud-mcp/ffi/cartridge_shim.zig b/cartridges/cloud-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/cloud-mcp/ffi/cartridge_shim.zig +++ b/cartridges/cloud-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/cloudflare-mcp/ffi/cartridge_shim.zig b/cartridges/cloudflare-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/cloudflare-mcp/ffi/cartridge_shim.zig +++ b/cartridges/cloudflare-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/coderag-mcp/ffi/cartridge_shim.zig b/cartridges/coderag-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/coderag-mcp/ffi/cartridge_shim.zig +++ b/cartridges/coderag-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/codeseeker-mcp/ffi/cartridge_shim.zig b/cartridges/codeseeker-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/codeseeker-mcp/ffi/cartridge_shim.zig +++ b/cartridges/codeseeker-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/comms-mcp/ffi/cartridge_shim.zig b/cartridges/comms-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/comms-mcp/ffi/cartridge_shim.zig +++ b/cartridges/comms-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/conflow-mcp/ffi/cartridge_shim.zig b/cartridges/conflow-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/conflow-mcp/ffi/cartridge_shim.zig +++ b/cartridges/conflow-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/container-mcp/ffi/cartridge_shim.zig b/cartridges/container-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/container-mcp/ffi/cartridge_shim.zig +++ b/cartridges/container-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/crates-mcp/ffi/cartridge_shim.zig b/cartridges/crates-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/crates-mcp/ffi/cartridge_shim.zig +++ b/cartridges/crates-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/dap-mcp/ffi/cartridge_shim.zig b/cartridges/dap-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/dap-mcp/ffi/cartridge_shim.zig +++ b/cartridges/dap-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/database-mcp/ffi/cartridge_shim.zig b/cartridges/database-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/database-mcp/ffi/cartridge_shim.zig +++ b/cartridges/database-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/digitalocean-mcp/ffi/cartridge_shim.zig b/cartridges/digitalocean-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/digitalocean-mcp/ffi/cartridge_shim.zig +++ b/cartridges/digitalocean-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/discord-mcp/ffi/cartridge_shim.zig b/cartridges/discord-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/discord-mcp/ffi/cartridge_shim.zig +++ b/cartridges/discord-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/dns-shield-mcp/ffi/cartridge_shim.zig b/cartridges/dns-shield-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/dns-shield-mcp/ffi/cartridge_shim.zig +++ b/cartridges/dns-shield-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/docker-hub-mcp/ffi/cartridge_shim.zig b/cartridges/docker-hub-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/docker-hub-mcp/ffi/cartridge_shim.zig +++ b/cartridges/docker-hub-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/duckdb-mcp/ffi/cartridge_shim.zig b/cartridges/duckdb-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/duckdb-mcp/ffi/cartridge_shim.zig +++ b/cartridges/duckdb-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/ephapax-mcp/ffi/cartridge_shim.zig b/cartridges/ephapax-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/ephapax-mcp/ffi/cartridge_shim.zig +++ b/cartridges/ephapax-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/feedback-mcp/ffi/cartridge_shim.zig b/cartridges/feedback-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/feedback-mcp/ffi/cartridge_shim.zig +++ b/cartridges/feedback-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/fireflag-mcp/ffi/cartridge_shim.zig b/cartridges/fireflag-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/fireflag-mcp/ffi/cartridge_shim.zig +++ b/cartridges/fireflag-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/fleet-mcp/ffi/cartridge_shim.zig b/cartridges/fleet-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/fleet-mcp/ffi/cartridge_shim.zig +++ b/cartridges/fleet-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/fly-mcp/ffi/cartridge_shim.zig b/cartridges/fly-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/fly-mcp/ffi/cartridge_shim.zig +++ b/cartridges/fly-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/game-admin-mcp/ffi/cartridge_shim.zig b/cartridges/game-admin-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/game-admin-mcp/ffi/cartridge_shim.zig +++ b/cartridges/game-admin-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/gcp-mcp/ffi/cartridge_shim.zig b/cartridges/gcp-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/gcp-mcp/ffi/cartridge_shim.zig +++ b/cartridges/gcp-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/git-mcp/ffi/cartridge_shim.zig b/cartridges/git-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/git-mcp/ffi/cartridge_shim.zig +++ b/cartridges/git-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/github-actions-mcp/ffi/cartridge_shim.zig b/cartridges/github-actions-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/github-actions-mcp/ffi/cartridge_shim.zig +++ b/cartridges/github-actions-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/github-api-mcp/ffi/cartridge_shim.zig b/cartridges/github-api-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/github-api-mcp/ffi/cartridge_shim.zig +++ b/cartridges/github-api-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/gitlab-api-mcp/ffi/cartridge_shim.zig b/cartridges/gitlab-api-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/gitlab-api-mcp/ffi/cartridge_shim.zig +++ b/cartridges/gitlab-api-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/google-docs-mcp/ffi/cartridge_shim.zig b/cartridges/google-docs-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/google-docs-mcp/ffi/cartridge_shim.zig +++ b/cartridges/google-docs-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/google-drive-mcp/ffi/cartridge_shim.zig b/cartridges/google-drive-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/google-drive-mcp/ffi/cartridge_shim.zig +++ b/cartridges/google-drive-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/google-sheets-mcp/ffi/cartridge_shim.zig b/cartridges/google-sheets-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/google-sheets-mcp/ffi/cartridge_shim.zig +++ b/cartridges/google-sheets-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/gossamer-mcp/ffi/cartridge_shim.zig b/cartridges/gossamer-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/gossamer-mcp/ffi/cartridge_shim.zig +++ b/cartridges/gossamer-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/grafana-mcp/ffi/cartridge_shim.zig b/cartridges/grafana-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/grafana-mcp/ffi/cartridge_shim.zig +++ b/cartridges/grafana-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/hackage-mcp/ffi/cartridge_shim.zig b/cartridges/hackage-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/hackage-mcp/ffi/cartridge_shim.zig +++ b/cartridges/hackage-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/hesiod-mcp/ffi/cartridge_shim.zig b/cartridges/hesiod-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/hesiod-mcp/ffi/cartridge_shim.zig +++ b/cartridges/hesiod-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/hetzner-mcp/ffi/cartridge_shim.zig b/cartridges/hetzner-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/hetzner-mcp/ffi/cartridge_shim.zig +++ b/cartridges/hetzner-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/hex-mcp/ffi/cartridge_shim.zig b/cartridges/hex-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/hex-mcp/ffi/cartridge_shim.zig +++ b/cartridges/hex-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/hypatia-mcp/ffi/cartridge_shim.zig b/cartridges/hypatia-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/hypatia-mcp/ffi/cartridge_shim.zig +++ b/cartridges/hypatia-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/iac-mcp/ffi/cartridge_shim.zig b/cartridges/iac-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/iac-mcp/ffi/cartridge_shim.zig +++ b/cartridges/iac-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/idaptik-admin-mcp/ffi/cartridge_shim.zig b/cartridges/idaptik-admin-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/idaptik-admin-mcp/ffi/cartridge_shim.zig +++ b/cartridges/idaptik-admin-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/jira-mcp/ffi/cartridge_shim.zig b/cartridges/jira-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/jira-mcp/ffi/cartridge_shim.zig +++ b/cartridges/jira-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/k8s-mcp/ffi/cartridge_shim.zig b/cartridges/k8s-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/k8s-mcp/ffi/cartridge_shim.zig +++ b/cartridges/k8s-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/k9iser-mcp/ffi/cartridge_shim.zig b/cartridges/k9iser-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/k9iser-mcp/ffi/cartridge_shim.zig +++ b/cartridges/k9iser-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/kategoria-mcp/ffi/cartridge_shim.zig b/cartridges/kategoria-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/kategoria-mcp/ffi/cartridge_shim.zig +++ b/cartridges/kategoria-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/laminar-mcp/ffi/cartridge_shim.zig b/cartridges/laminar-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/laminar-mcp/ffi/cartridge_shim.zig +++ b/cartridges/laminar-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/lang-mcp/ffi/cartridge_shim.zig b/cartridges/lang-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/lang-mcp/ffi/cartridge_shim.zig +++ b/cartridges/lang-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/linear-mcp/ffi/cartridge_shim.zig b/cartridges/linear-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/linear-mcp/ffi/cartridge_shim.zig +++ b/cartridges/linear-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/linode-mcp/ffi/cartridge_shim.zig b/cartridges/linode-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/linode-mcp/ffi/cartridge_shim.zig +++ b/cartridges/linode-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/local-memory-mcp/ffi/cartridge_shim.zig b/cartridges/local-memory-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/local-memory-mcp/ffi/cartridge_shim.zig +++ b/cartridges/local-memory-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/lsp-mcp/ffi/cartridge_shim.zig b/cartridges/lsp-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/lsp-mcp/ffi/cartridge_shim.zig +++ b/cartridges/lsp-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/matrix-mcp/ffi/cartridge_shim.zig b/cartridges/matrix-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/matrix-mcp/ffi/cartridge_shim.zig +++ b/cartridges/matrix-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/ml-mcp/ffi/cartridge_shim.zig b/cartridges/ml-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/ml-mcp/ffi/cartridge_shim.zig +++ b/cartridges/ml-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/model-router-mcp/ffi/cartridge_shim.zig b/cartridges/model-router-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/model-router-mcp/ffi/cartridge_shim.zig +++ b/cartridges/model-router-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/mongodb-mcp/ffi/cartridge_shim.zig b/cartridges/mongodb-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/mongodb-mcp/ffi/cartridge_shim.zig +++ b/cartridges/mongodb-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/neo4j-mcp/ffi/cartridge_shim.zig b/cartridges/neo4j-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/neo4j-mcp/ffi/cartridge_shim.zig +++ b/cartridges/neo4j-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/neon-mcp/ffi/cartridge_shim.zig b/cartridges/neon-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/neon-mcp/ffi/cartridge_shim.zig +++ b/cartridges/neon-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/nesy-mcp/ffi/cartridge_shim.zig b/cartridges/nesy-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/nesy-mcp/ffi/cartridge_shim.zig +++ b/cartridges/nesy-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/notifyhub-mcp/ffi/cartridge_shim.zig b/cartridges/notifyhub-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/notifyhub-mcp/ffi/cartridge_shim.zig +++ b/cartridges/notifyhub-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/notion-mcp/ffi/cartridge_shim.zig b/cartridges/notion-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/notion-mcp/ffi/cartridge_shim.zig +++ b/cartridges/notion-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/npm-registry-mcp/ffi/cartridge_shim.zig b/cartridges/npm-registry-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/npm-registry-mcp/ffi/cartridge_shim.zig +++ b/cartridges/npm-registry-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/observe-mcp/ffi/cartridge_shim.zig b/cartridges/observe-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/observe-mcp/ffi/cartridge_shim.zig +++ b/cartridges/observe-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/obsidian-mcp/ffi/cartridge_shim.zig b/cartridges/obsidian-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/obsidian-mcp/ffi/cartridge_shim.zig +++ b/cartridges/obsidian-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/opam-mcp/ffi/cartridge_shim.zig b/cartridges/opam-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/opam-mcp/ffi/cartridge_shim.zig +++ b/cartridges/opam-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/opendata-mcp/ffi/cartridge_shim.zig b/cartridges/opendata-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/opendata-mcp/ffi/cartridge_shim.zig +++ b/cartridges/opendata-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/opsm-mcp/ffi/cartridge_shim.zig b/cartridges/opsm-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/opsm-mcp/ffi/cartridge_shim.zig +++ b/cartridges/opsm-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/origene-mcp/ffi/cartridge_shim.zig b/cartridges/origene-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/origene-mcp/ffi/cartridge_shim.zig +++ b/cartridges/origene-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/panic-attack-mcp/ffi/cartridge_shim.zig b/cartridges/panic-attack-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/panic-attack-mcp/ffi/cartridge_shim.zig +++ b/cartridges/panic-attack-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/pmpl-mcp/ffi/cartridge_shim.zig b/cartridges/pmpl-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/pmpl-mcp/ffi/cartridge_shim.zig +++ b/cartridges/pmpl-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/postgresql-mcp/ffi/cartridge_shim.zig b/cartridges/postgresql-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/postgresql-mcp/ffi/cartridge_shim.zig +++ b/cartridges/postgresql-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/prometheus-mcp/ffi/cartridge_shim.zig b/cartridges/prometheus-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/prometheus-mcp/ffi/cartridge_shim.zig +++ b/cartridges/prometheus-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/proof-mcp/ffi/cartridge_shim.zig b/cartridges/proof-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/proof-mcp/ffi/cartridge_shim.zig +++ b/cartridges/proof-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/pypi-mcp/ffi/cartridge_shim.zig b/cartridges/pypi-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/pypi-mcp/ffi/cartridge_shim.zig +++ b/cartridges/pypi-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/queues-mcp/ffi/cartridge_shim.zig b/cartridges/queues-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/queues-mcp/ffi/cartridge_shim.zig +++ b/cartridges/queues-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/railway-mcp/ffi/cartridge_shim.zig b/cartridges/railway-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/railway-mcp/ffi/cartridge_shim.zig +++ b/cartridges/railway-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/redis-mcp/ffi/cartridge_shim.zig b/cartridges/redis-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/redis-mcp/ffi/cartridge_shim.zig +++ b/cartridges/redis-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/render-mcp/ffi/cartridge_shim.zig b/cartridges/render-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/render-mcp/ffi/cartridge_shim.zig +++ b/cartridges/render-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/reposystem-mcp/ffi/cartridge_shim.zig b/cartridges/reposystem-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/reposystem-mcp/ffi/cartridge_shim.zig +++ b/cartridges/reposystem-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/research-mcp/ffi/cartridge_shim.zig b/cartridges/research-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/research-mcp/ffi/cartridge_shim.zig +++ b/cartridges/research-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/rokur-mcp/ffi/cartridge_shim.zig b/cartridges/rokur-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/rokur-mcp/ffi/cartridge_shim.zig +++ b/cartridges/rokur-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/sanctify-mcp/ffi/cartridge_shim.zig b/cartridges/sanctify-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/sanctify-mcp/ffi/cartridge_shim.zig +++ b/cartridges/sanctify-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/secrets-mcp/ffi/cartridge_shim.zig b/cartridges/secrets-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/secrets-mcp/ffi/cartridge_shim.zig +++ b/cartridges/secrets-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/sentry-mcp/ffi/cartridge_shim.zig b/cartridges/sentry-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/sentry-mcp/ffi/cartridge_shim.zig +++ b/cartridges/sentry-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/slack-mcp/ffi/cartridge_shim.zig b/cartridges/slack-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/slack-mcp/ffi/cartridge_shim.zig +++ b/cartridges/slack-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/ssg-mcp/ffi/cartridge_shim.zig b/cartridges/ssg-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/ssg-mcp/ffi/cartridge_shim.zig +++ b/cartridges/ssg-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/stapeln-mcp/ffi/cartridge_shim.zig b/cartridges/stapeln-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/stapeln-mcp/ffi/cartridge_shim.zig +++ b/cartridges/stapeln-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/supabase-mcp/ffi/cartridge_shim.zig b/cartridges/supabase-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/supabase-mcp/ffi/cartridge_shim.zig +++ b/cartridges/supabase-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/telegram-mcp/ffi/cartridge_shim.zig b/cartridges/telegram-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/telegram-mcp/ffi/cartridge_shim.zig +++ b/cartridges/telegram-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/todoist-mcp/ffi/cartridge_shim.zig b/cartridges/todoist-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/todoist-mcp/ffi/cartridge_shim.zig +++ b/cartridges/todoist-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/toolchain-mcp/ffi/cartridge_shim.zig b/cartridges/toolchain-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/toolchain-mcp/ffi/cartridge_shim.zig +++ b/cartridges/toolchain-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/turso-mcp/ffi/cartridge_shim.zig b/cartridges/turso-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/turso-mcp/ffi/cartridge_shim.zig +++ b/cartridges/turso-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/typed-wasm-mcp/ffi/cartridge_shim.zig b/cartridges/typed-wasm-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/typed-wasm-mcp/ffi/cartridge_shim.zig +++ b/cartridges/typed-wasm-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/ums-mcp/ffi/cartridge_shim.zig b/cartridges/ums-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/ums-mcp/ffi/cartridge_shim.zig +++ b/cartridges/ums-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/vault-mcp/ffi/cartridge_shim.zig b/cartridges/vault-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/vault-mcp/ffi/cartridge_shim.zig +++ b/cartridges/vault-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/verisimdb-mcp/ffi/cartridge_shim.zig b/cartridges/verisimdb-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/verisimdb-mcp/ffi/cartridge_shim.zig +++ b/cartridges/verisimdb-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/vext-mcp/ffi/cartridge_shim.zig b/cartridges/vext-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/vext-mcp/ffi/cartridge_shim.zig +++ b/cartridges/vext-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/vordr-mcp/ffi/cartridge_shim.zig b/cartridges/vordr-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/vordr-mcp/ffi/cartridge_shim.zig +++ b/cartridges/vordr-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/cartridges/zotero-mcp/ffi/cartridge_shim.zig b/cartridges/zotero-mcp/ffi/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/cartridges/zotero-mcp/ffi/cartridge_shim.zig +++ b/cartridges/zotero-mcp/ffi/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); } diff --git a/ffi/zig/src/abi_verify.zig b/ffi/zig/src/abi_verify.zig index 0058ce59..a42964c5 100644 --- a/ffi/zig/src/abi_verify.zig +++ b/ffi/zig/src/abi_verify.zig @@ -473,21 +473,21 @@ test "C.5: [BOUNDARY] writeResult — zero-capacity buffer, non-empty body, RC_B } test "C.6: toolIs — exact match and non-match" { - const name: [*:0]const u8 = "list-databases"; - try std.testing.expect(shim.toolIs(@ptrCast(name), "list-databases")); - try std.testing.expect(!shim.toolIs(@ptrCast(name), "list-database")); - try std.testing.expect(!shim.toolIs(@ptrCast(name), "list-databasess")); - try std.testing.expect(!shim.toolIs(@ptrCast(name), "")); + const name: [*c]const u8 = "list-databases"; + try std.testing.expect(shim.toolIs(name, "list-databases")); + try std.testing.expect(!shim.toolIs(name, "list-database")); + try std.testing.expect(!shim.toolIs(name, "list-databasess")); + try std.testing.expect(!shim.toolIs(name, "")); } test "C.7: invokeArgsNull — each null slot detected independently" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!shim.invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!shim.invokeArgsNull(name, &buf, &len)); try std.testing.expect(shim.invokeArgsNull(null, &buf, &len)); - try std.testing.expect(shim.invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(shim.invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(shim.invokeArgsNull(name, null, &len)); + try std.testing.expect(shim.invokeArgsNull(name, &buf, null)); } test "C.8: RC_BUFFER_TOO_SMALL hint enables two-phase caller pattern" { diff --git a/ffi/zig/src/cartridge_shim.zig b/ffi/zig/src/cartridge_shim.zig index 473c6009..cd83b44b 100644 --- a/ffi/zig/src/cartridge_shim.zig +++ b/ffi/zig/src/cartridge_shim.zig @@ -58,8 +58,14 @@ pub fn invokeArgsNull( /// Compare a C-NUL-terminated tool-name pointer against a Zig string /// literal. Caller must have already verified `tool_name` is non-null /// (usually via `invokeArgsNull`). +/// +/// Implementation note (CWE-704 fix, post-#146): uses +/// `std.mem.sliceTo(ptr, 0)` which scans the C string up to the first +/// NUL — no `@ptrCast` and no `[*:0]` re-typing. The earlier +/// `std.mem.spanZ` call was removed in Zig 0.14+ and would not +/// compile under the 0.15.1 CI pin. pub fn toolIs(tool_name: [*c]const u8, expected: []const u8) bool { - const s = std.mem.span(@as([*:0]const u8, @ptrCast(tool_name))); + const s = std.mem.sliceTo(tool_name, 0); return std.mem.eql(u8, s, expected); } @@ -124,19 +130,19 @@ test "writeResult: empty body" { } test "toolIs: matches and rejects" { - const name: [*:0]const u8 = "foo"; - try std.testing.expect(toolIs(@ptrCast(name), "foo")); - try std.testing.expect(!toolIs(@ptrCast(name), "bar")); - try std.testing.expect(!toolIs(@ptrCast(name), "foobar")); - try std.testing.expect(!toolIs(@ptrCast(name), "fo")); + const name: [*c]const u8 = "foo"; + try std.testing.expect(toolIs(name, "foo")); + try std.testing.expect(!toolIs(name, "bar")); + try std.testing.expect(!toolIs(name, "foobar")); + try std.testing.expect(!toolIs(name, "fo")); } test "invokeArgsNull: detects each null slot" { var buf: [4]u8 = undefined; var len: usize = 4; - const name: [*:0]const u8 = "x"; - try std.testing.expect(!invokeArgsNull(@ptrCast(name), &buf, &len)); + const name: [*c]const u8 = "x"; + try std.testing.expect(!invokeArgsNull(name, &buf, &len)); try std.testing.expect(invokeArgsNull(null, &buf, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), null, &len)); - try std.testing.expect(invokeArgsNull(@ptrCast(name), &buf, null)); + try std.testing.expect(invokeArgsNull(name, null, &len)); + try std.testing.expect(invokeArgsNull(name, &buf, null)); }