Skip to content

kernel-contract: window_rows prompt fixture computes modulo zero for empty prefixes #1316

Closed

Description

@Maxrio9

The CUDA kernel-contract runner terminates before its final summary when it reaches the first window_rows prompt registration. Its fixture prepares decode-only positions even for prompts; a valid empty-prefix prompt has shape.k == 0, so the position loop evaluates modulo zero.

Environment: tested source 67cc8fbce879e2d0dd74b94ebb8848b134478ee4, native version 1.1.4, Zig 0.17.0, Linux x86_64, RTX PRO 4500 Blackwell (SM120), CUDA compiler 13.0.88. Model/checkpoint: none; synthetic contract inputs only. Relevant zig/ source is unchanged through release 1.1.5 at 84e0d560.

The documented full reproduction is:

zig build kernel-contract -Dnvcc=/path/to/nvcc -Dsm=120

The full run exited 136 after 2,297 seconds, before its one-hour bound, with no SUMMARY. Its last completed registration was window_rows decode-256. The kernel log recorded a divide-error trap; mapping its instruction address in the tested executable identifies contract_window_rows.Rows.prepare, line 183.

The next registered configuration is the P32/image-row prompt. Its first served shape has zero prior tokens. Gate 1 clamps its rows to eight and calls prepare(..., .nonfinite, ...). At i == 0 the position expression evaluates i % min(40, shape.k), hence % 0. Decode positions are unused by prompt Call.at, which derives positions from p0 + r instead.

A small diagnostic wrapper selecting that original registration, with the original fixture, runtime, seed and fatbins unchanged, reproduced exit 136 in two separate admitted runs (about two seconds each). Both reached the zero-prefix prompt's nonfinite gate and terminated before the kernel checks could run. These are isolated wrapper reproductions, not two complete full-suite reruns.

A CPU-only copy of the position expression also traps with FPE on x86_64 in ReleaseFast. In ReleaseFast the same diagnostic prints zero for its first row on aarch64, but Debug reports division by zero on both architectures. The apparent ARM success does not make modulo zero valid, and does not validate the full CUDA fixture on ARM. Save this as repro.zig and run zig test repro.zig -O ReleaseFast:

const std = @import("std");
test "zero-prefix fixture position" {
    var inputs = [_]usize{ 0, 8, 0 };
    const ptr: *volatile [3]usize = &inputs;
    const k = ptr.*[0];
    const n = ptr.*[1];
    const i = ptr.*[2];
    const position = if (i == n - 1) k -| 1
        else if (i % 4 == 0) i % @min(40, k)
        else (i * 7919) % k;
    std.debug.print("{d}\n", .{position});
}

Expected: valid zero-prefix prompts reach the contract gates and the runner emits its final summary. The sibling contract_window.zig already guards the same expression for prompts. The window_rows fixture can similarly use at + i for prompt positions, consistent with its p0, while preserving existing decode-position coverage. A fix should test zero and nonzero prompt prefixes and rerun the affected prompt registrations and their corruption controls without changing kernels or tolerances.

This is a test-fixture failure; it does not establish incorrect Gemma model output or incorrect window_rows GPU arithmetic. It is separate from #1309 / #1315, whose six affected registrations completed their gates before this crash and whose reference file is not used by this fixture.

Logs available on request. Investigated with AI coding assistants (Codex, Claude).

Activity

  1. Maxrio9 commented on Oct 25, 2026

    @Maxrio9
    ContributorAuthor

    /atc claim

  2. ashhart commented on Oct 25, 2026

    @ashhart
    Owner

    Thanks for the precise diagnosis. Fixed on the next landing batch: prompt rows in the window_rows fixture now sit at p0 + i, as Call.at reads them and as contract_window.zig already does, so an empty prefix takes no modulo of zero. A test covers empty and long prefixes. Decode positions, kernels and tolerances are unchanged. It also lands with your #1315 (signed-zero endpoints) and #1308.

    - Synthema, Ash's AI Assistant.

  3. Maxrio9 commented on Oct 25, 2026

    @Maxrio9
    ContributorAuthor

    /atc release

  4. ashhart commented on Oct 25, 2026

    @ashhart
    Owner

    Fixed on main (84e0d56..24072ec) by 3cb8cb5: window_rows prompt rows sit at p0 + i, as Call.at reads them, with a test for empty and long prefixes. Kernels and tolerances unchanged. Thanks again for the diagnosis.

    - Synthema, Ash's AI Assistant.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions