[GH-ISSUE #6823] [Bug] CUBIN register conflicts retain complete payload and target coverage #4169

Closed
opened 2026-10-31 00:47:22 +00:00 by bsakaguchi · 0 comments
Owner

Originally created by @coygeek on GitHub (Oct 23, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/6823

Before submitting

  • I searched the open and closed issues for a related report.
  • I removed credentials, tokens, private paths, and sensitive target data.

Area

Native analysis or decompilation

Observed behavior

The production GpuCodeObjectsService and GpuCodeObjectsProvider, followed by the production target-page projector, return contradictory coverage for a synthetic CUBIN whose text-section register declaration is 11 and whose global nv.info register declaration is 10. The reader detects the conflict, returns registers.physical: null, and adds Conflicting CUDA register declarations; physical count remains unknown, but the object inspection, report payload coverage, and target kernel_coverage all remain complete.

The control with both declarations equal to 10 returns physical count 10 and the same complete coverage. This reproduces through real file reads and the shared production service, without a mocked provider. It was not exercised through CLI/MCP transport or a CUDA compiler.

Reproduction

Use source revision 7fd722e15bea35255f5eadbd406948e28538d25f with its locked dependencies installed and Node.js 26.12.1. Save the following script as /tmp/rea-repro/cubin-register-coverage.mts. The fixture builder is already in that checkout; it writes inert ELF metadata, not executable test code.

import assert from 'node:assert/strict';
import { writeFile } from 'node:fs/promises';
import { resolve, join } from 'node:path';
import { pathToFileURL } from 'node:url';

const root = resolve(process.argv[2] ?? './rea');
const here = resolve(process.argv[3] ?? '.');
const load = (path: string) => import(pathToFileURL(join(root, path)).href);
const { cubinFixture } = await load('tests/fixtures/gpu/codeObjects.ts');
const { GpuCodeObjectsProvider } = await load('src/gpu/GpuCodeObjectsProvider.ts');
const { GpuCodeObjectsService } = await load('src/application/gpu/GpuCodeObjectsService.ts');
const { projectGpuCodeObjectsView } = await load('src/domain/analysisView/gpuCodeObjectsView.ts');

for (const [name, textRegisters] of [['control', 10], ['conflict', 11]] as const) {
  const path = join(here, `${name}.cubin`);
  await writeFile(path, cubinFixture({ textRegisters, globalRegisters: 10 }));
  const service = new GpuCodeObjectsService(new GpuCodeObjectsProvider());
  try {
    const result = await service.inspect({ path, analysis: 'kernels', detail: 'complete' });
    assert.equal(result.ok, true);
    if (!result.ok) throw result.error;
    const evidence = result.value;
    const report = evidence.normalized_result;
    const parent = {
      evidenceId: evidence.evidence_id,
      operation: evidence.operation,
      normalizedResult: report,
      limitations: evidence.limitations,
      subject: evidence.subject,
    };
    const targets = projectGpuCodeObjectsView(parent, {
      kind: 'gpu-code-objects', collection: 'targets', offset: 0, limit: 32,
    });
    assert.equal(targets.ok, true);
    console.log(JSON.stringify({
      name, text_registers: textRegisters, global_registers: 10,
      physical: report.kernels[0].registers.physical,
      kernel_limitations: report.kernels[0].limitations,
      object_inspection: report.objects[0].inspection,
      source_coverage: report.coverage,
      target_items: targets.ok ? targets.value.items : null,
    }, null, 2));
    assert.equal(report.coverage.payloads, 'complete');
    assert.equal(report.objects[0].inspection, 'complete');
    assert.equal(report.kernels[0].registers.physical, name === 'control' ? 10 : null);
    if (name === 'conflict') assert.match(report.kernels[0].limitations.join(' '), /Conflicting CUDA register declarations/);
  } finally { await service.close(); }
}

Run this command, with the checkout located at /tmp/rea-repro/rea:

node /tmp/rea-repro/rea/node_modules/tsx/dist/cli.mjs /tmp/rea-repro/cubin-register-coverage.mts /tmp/rea-repro/rea /tmp/rea-repro

Both cases were executed once, in one invocation. All assertions passed. Paths above replace the disposable research directory; the script and invocation otherwise match the executed proof.

Expected behavior

Preserve the known metadata, unknown register count, and conflict explanation, while propagating partial decoding coverage to the CUBIN object, report, and target page. A target page must not hide a detected resource conflict behind kernel_coverage: complete.

The existing incomplete decoder coverage acceptance check requires partial object/report/target coverage for unresolved PTX resource declarations and other decoding gaps. The GPU guide likewise describes explicit partial coverage for unsupported register declarations and preservation of conflicting CUDA facts.

Impact and scope

Bounded metadata-reporting defect: a caller selecting only a target page sees complete kernel coverage even though the reader detected a register conflict. The target schema does not carry per-kernel limitations, so that page conceals the reason the physical count is unknown. Full reports retain the warning and provide a practical workaround.

Observed only with the inert synthetic conflict above. Whether a real NVIDIA toolchain emits these conflicting declarations, and the frequency in collected CUBINs, are unknown. This report does not claim incorrect GPU execution, an incorrect non-null register count, or a vulnerability.

REA version

rea-agents manifest 6.7.0; source 7fd722e15bea35255f5eadbd406948e28538d25f. Latest published release was confirmed as rea-agents-6.7.0 for this investigation. The published-package runtime was not tested; observations above concern the stated main-source revision.

Runtime and platform

Node.js v26.12.1; Linux x86_64; repository-locked tsx. No CUDA/ROCm, Hopper, Ghidra, or target execution was involved.

Target and artifact context

Two 800-byte synthetic ELF64 CUDA CUBIN files generated by the repository's existing cubinFixture: .symtab, executable text, global/per-kernel numeric nv.info, and NOBITS shared-memory declarations. Only the text-header register count changes between control and conflict.

Interface

Other

Earliest failure stage

Native analysis or reconstruction

Relevant output or evidence

The executed command above exited 0 and produced these key facts:

{
  "control": {
    "text_registers": 10,
    "global_registers": 10,
    "physical": 10,
    "object_inspection": "complete",
    "payloads": "complete",
    "kernel_coverage": "complete"
  },
  "conflict": {
    "text_registers": 11,
    "global_registers": 10,
    "physical": null,
    "kernel_limitations": [
      "Conflicting CUDA register declarations; physical count remains unknown"
    ],
    "object_inspection": "complete",
    "payloads": "complete",
    "kernel_coverage": "complete"
  }
}

This excerpt omits the common informational limitation and unrelated target fields; it does not alter the observed values. Proof used the actual service/provider and target projector, not simulated provider output. The stored proof script and full stdout were retained before drafting; public reproduction is included above so access to local research artifacts is unnecessary.

Typed outcome or recovery expected

Successful partial observation: retain the kernel with registers.physical: null and its conflict limitation, and return objects[0].inspection: partial, coverage.payloads: partial, and target kernel_coverage: partial.

Analysis or suspected cause

Source-derived cause: attachCudaResources detects conflicting register declarations and mutates the kernel, but returns void. Its caller's complete flag is changed for parameter limitations or missing parameter metadata, not for the register conflict. The provider derives payload coverage from the resulting object state, and the target projector uses that same state.

Three interpretations were considered: accepting one declaration as authoritative, reporting unknown while retaining complete coverage, or preserving uncertainty with partial coverage. The last best fits the current parser, which explicitly calls these declarations conflicting, and the existing partial-resource coverage contract. No change to resource precedence or CUDA ABI interpretation is required by this report.

Additional context

AI assistance disclosure: an OpenAI Codex research agent performed source review, generated the isolated proof, executed it, and prepared this report. No human review or independent reproduction is claimed. No source files, real user configuration, issue records, or external targets were modified. No last-known-good version was tested.

Open and closed issue searches for CUBIN/register conflicts, GPU coverage, and register declarations found no matching report. Related #6624 concerns V2 parameter records; #6626 and #6469 concern PTX register syntax. They do not report this detected CUBIN resource conflict. A fresh open-issue listing was checked immediately before submission.

Triage assessment

  • Impact level: P2
  • Assessment status: supported
  • Impact basis: A production-reader observation with a known register conflict is reported as complete on object, report, and target surfaces; target-only callers cannot see the retained kernel warning. The demonstrated consequence is bounded evidence coverage inaccuracy, with real-compiler prevalence unknown.
  • Workaround status: available
  • Workaround basis: The same executed full report retains the null physical count and explicit per-kernel conflict warning. Inspect full kernel facts and limitations instead of relying only on target coverage.
Originally created by @coygeek on GitHub (Oct 23, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/6823 ## Before submitting - [x] I searched the open and closed issues for a related report. - [x] I removed credentials, tokens, private paths, and sensitive target data. ## Area Native analysis or decompilation ## Observed behavior The production `GpuCodeObjectsService` and `GpuCodeObjectsProvider`, followed by the production target-page projector, return contradictory coverage for a synthetic CUBIN whose text-section register declaration is 11 and whose global `nv.info` register declaration is 10. The reader detects the conflict, returns `registers.physical: null`, and adds `Conflicting CUDA register declarations; physical count remains unknown`, but the object inspection, report payload coverage, and target `kernel_coverage` all remain `complete`. The control with both declarations equal to 10 returns physical count 10 and the same complete coverage. This reproduces through real file reads and the shared production service, without a mocked provider. It was not exercised through CLI/MCP transport or a CUDA compiler. ## Reproduction Use source revision `7fd722e15bea35255f5eadbd406948e28538d25f` with its locked dependencies installed and Node.js 26.12.1. Save the following script as `/tmp/rea-repro/cubin-register-coverage.mts`. The fixture builder is already in that checkout; it writes inert ELF metadata, not executable test code. ```ts import assert from 'node:assert/strict'; import { writeFile } from 'node:fs/promises'; import { resolve, join } from 'node:path'; import { pathToFileURL } from 'node:url'; const root = resolve(process.argv[2] ?? './rea'); const here = resolve(process.argv[3] ?? '.'); const load = (path: string) => import(pathToFileURL(join(root, path)).href); const { cubinFixture } = await load('tests/fixtures/gpu/codeObjects.ts'); const { GpuCodeObjectsProvider } = await load('src/gpu/GpuCodeObjectsProvider.ts'); const { GpuCodeObjectsService } = await load('src/application/gpu/GpuCodeObjectsService.ts'); const { projectGpuCodeObjectsView } = await load('src/domain/analysisView/gpuCodeObjectsView.ts'); for (const [name, textRegisters] of [['control', 10], ['conflict', 11]] as const) { const path = join(here, `${name}.cubin`); await writeFile(path, cubinFixture({ textRegisters, globalRegisters: 10 })); const service = new GpuCodeObjectsService(new GpuCodeObjectsProvider()); try { const result = await service.inspect({ path, analysis: 'kernels', detail: 'complete' }); assert.equal(result.ok, true); if (!result.ok) throw result.error; const evidence = result.value; const report = evidence.normalized_result; const parent = { evidenceId: evidence.evidence_id, operation: evidence.operation, normalizedResult: report, limitations: evidence.limitations, subject: evidence.subject, }; const targets = projectGpuCodeObjectsView(parent, { kind: 'gpu-code-objects', collection: 'targets', offset: 0, limit: 32, }); assert.equal(targets.ok, true); console.log(JSON.stringify({ name, text_registers: textRegisters, global_registers: 10, physical: report.kernels[0].registers.physical, kernel_limitations: report.kernels[0].limitations, object_inspection: report.objects[0].inspection, source_coverage: report.coverage, target_items: targets.ok ? targets.value.items : null, }, null, 2)); assert.equal(report.coverage.payloads, 'complete'); assert.equal(report.objects[0].inspection, 'complete'); assert.equal(report.kernels[0].registers.physical, name === 'control' ? 10 : null); if (name === 'conflict') assert.match(report.kernels[0].limitations.join(' '), /Conflicting CUDA register declarations/); } finally { await service.close(); } } ``` Run this command, with the checkout located at `/tmp/rea-repro/rea`: ```sh node /tmp/rea-repro/rea/node_modules/tsx/dist/cli.mjs /tmp/rea-repro/cubin-register-coverage.mts /tmp/rea-repro/rea /tmp/rea-repro ``` Both cases were executed once, in one invocation. All assertions passed. Paths above replace the disposable research directory; the script and invocation otherwise match the executed proof. ## Expected behavior Preserve the known metadata, unknown register count, and conflict explanation, while propagating partial decoding coverage to the CUBIN object, report, and target page. A target page must not hide a detected resource conflict behind `kernel_coverage: complete`. The existing [incomplete decoder coverage acceptance check](https://github.com/morluto/rea/blob/7fd722e15bea35255f5eadbd406948e28538d25f/tests/acceptance/gpuCodeObjectsCli.test.ts#L695) requires partial object/report/target coverage for unresolved PTX resource declarations and other decoding gaps. The [GPU guide](https://github.com/morluto/rea/blob/7fd722e15bea35255f5eadbd406948e28538d25f/docs/gpu-code-objects.md) likewise describes explicit partial coverage for unsupported register declarations and preservation of conflicting CUDA facts. ## Impact and scope Bounded metadata-reporting defect: a caller selecting only a target page sees complete kernel coverage even though the reader detected a register conflict. The target schema does not carry per-kernel limitations, so that page conceals the reason the physical count is unknown. Full reports retain the warning and provide a practical workaround. Observed only with the inert synthetic conflict above. Whether a real NVIDIA toolchain emits these conflicting declarations, and the frequency in collected CUBINs, are unknown. This report does not claim incorrect GPU execution, an incorrect non-null register count, or a vulnerability. ## REA version `rea-agents` manifest 6.7.0; source `7fd722e15bea35255f5eadbd406948e28538d25f`. Latest published release was confirmed as `rea-agents-6.7.0` for this investigation. The published-package runtime was not tested; observations above concern the stated main-source revision. ## Runtime and platform Node.js v26.12.1; Linux x86_64; repository-locked `tsx`. No CUDA/ROCm, Hopper, Ghidra, or target execution was involved. ## Target and artifact context Two 800-byte synthetic ELF64 CUDA CUBIN files generated by the repository's existing `cubinFixture`: `.symtab`, executable text, global/per-kernel numeric `nv.info`, and NOBITS shared-memory declarations. Only the text-header register count changes between control and conflict. ## Interface Other ## Earliest failure stage Native analysis or reconstruction ## Relevant output or evidence The executed command above exited 0 and produced these key facts: ```json { "control": { "text_registers": 10, "global_registers": 10, "physical": 10, "object_inspection": "complete", "payloads": "complete", "kernel_coverage": "complete" }, "conflict": { "text_registers": 11, "global_registers": 10, "physical": null, "kernel_limitations": [ "Conflicting CUDA register declarations; physical count remains unknown" ], "object_inspection": "complete", "payloads": "complete", "kernel_coverage": "complete" } } ``` This excerpt omits the common informational limitation and unrelated target fields; it does not alter the observed values. Proof used the actual service/provider and target projector, not simulated provider output. The stored proof script and full stdout were retained before drafting; public reproduction is included above so access to local research artifacts is unnecessary. ## Typed outcome or recovery expected Successful partial observation: retain the kernel with `registers.physical: null` and its conflict limitation, and return `objects[0].inspection: partial`, `coverage.payloads: partial`, and target `kernel_coverage: partial`. ## Analysis or suspected cause Source-derived cause: [`attachCudaResources`](https://github.com/morluto/rea/blob/7fd722e15bea35255f5eadbd406948e28538d25f/src/gpu/GpuElfKernels.ts#L196) detects conflicting register declarations and mutates the kernel, but returns `void`. Its caller's `complete` flag is changed for parameter limitations or missing parameter metadata, [not for the register conflict](https://github.com/morluto/rea/blob/7fd722e15bea35255f5eadbd406948e28538d25f/src/gpu/GpuElfKernels.ts#L333). The [provider](https://github.com/morluto/rea/blob/7fd722e15bea35255f5eadbd406948e28538d25f/src/gpu/GpuCodeObjectsProvider.ts#L315) derives payload coverage from the resulting object state, and the [target projector](https://github.com/morluto/rea/blob/7fd722e15bea35255f5eadbd406948e28538d25f/src/domain/analysisView/gpuCodeObjectsView.ts#L146) uses that same state. Three interpretations were considered: accepting one declaration as authoritative, reporting unknown while retaining complete coverage, or preserving uncertainty with partial coverage. The last best fits the current parser, which explicitly calls these declarations conflicting, and the existing partial-resource coverage contract. No change to resource precedence or CUDA ABI interpretation is required by this report. ## Additional context AI assistance disclosure: an OpenAI Codex research agent performed source review, generated the isolated proof, executed it, and prepared this report. No human review or independent reproduction is claimed. No source files, real user configuration, issue records, or external targets were modified. No last-known-good version was tested. Open and closed issue searches for CUBIN/register conflicts, GPU coverage, and register declarations found no matching report. Related #6624 concerns V2 parameter records; #6626 and #6469 concern PTX register syntax. They do not report this detected CUBIN resource conflict. A fresh open-issue listing was checked immediately before submission. ## Triage assessment - Impact level: P2 - Assessment status: supported - Impact basis: A production-reader observation with a known register conflict is reported as complete on object, report, and target surfaces; target-only callers cannot see the retained kernel warning. The demonstrated consequence is bounded evidence coverage inaccuracy, with real-compiler prevalence unknown. - Workaround status: available - Workaround basis: The same executed full report retains the null physical count and explicit per-kernel conflict warning. Inspect full kernel facts and limitations instead of relying only on target coverage.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#4169
No description provided.