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)); }