[GH-ISSUE #6606] [Bug] retain declared names of pointer-qualified PTX parameters #3992

Closed
opened 2026-10-31 00:45:51 +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/6606

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 public inspect-gpu-code-objects command returns name: null for the first parameter in .entry k(.param .u64 .ptr .global .align 4 ptr_arg, .param .u32 count). The kernel, scalar type and second parameter name survive, and the original retained PTX still contains ptr_arg. The object and payload coverage are partial, with a limitation about unknown parameter layout.

Removing only the pointer qualifiers restores name: "ptr_arg", size 8, offset 0 and complete coverage. A separate unsupported-layout control, .param .u64 dyn_arg[], retains dyn_arg while reporting unknown size/offset and partial coverage. Partial layout coverage therefore does not consistently prevent name retention.

Reproduction

Run from the source checkout identified below with its required Node toolchain, locked dependencies and compiled runtime already prepared. Python 3 is used only to create disposable fixtures, isolate the child environment and summarize JSON. The block below was executed successfully once per input; earlier independent runs of the qualified, plain and unsupported-layout cases each gave the same result twice. All inspection calls exited 0 with empty stderr.

PATH=/opt/homebrew/opt/node@24/bin:$PATH python3 - <<'PY'
import json, os, pathlib, shutil, subprocess, tempfile
repo = pathlib.Path.cwd()
node = shutil.which('node')
header = '.version 8.8\n.target sm_80\n.address_size 64\n'
with tempfile.TemporaryDirectory(prefix='ptx-parameter-check-') as directory:
    work = pathlib.Path(directory)
    env = {'PATH': os.environ['PATH']}
    for key, name in {'HOME':'home', 'USERPROFILE':'home', 'XDG_CONFIG_HOME':'config', 'XDG_CACHE_HOME':'cache', 'XDG_DATA_HOME':'data', 'XDG_STATE_HOME':'state', 'XDG_RUNTIME_DIR':'run', 'TMPDIR':'temp'}.items():
        path = work / name
        path.mkdir(mode=0o700, exist_ok=True)
        env[key] = str(path)
    cases = {
        'qualified': '.param .u64 .ptr .global .align 4 ptr_arg',
        'plain': '.param .u64 ptr_arg',
        'unsupported': '.param .u64 dyn_arg[]',
    }
    for name, parameter in cases.items():
        fixture = work / (name + '.ptx')
        text = header + '.visible .entry k(' + parameter + ', .param .u32 count) { ret; }\n'
        fixture.write_text(text)
        command = [node, str(repo / 'scripts/rea.mjs'), 'inspect-gpu-code-objects', str(fixture), '--analysis', 'kernels', '--detail', 'complete', '--json']
        result = subprocess.run(command, cwd=work, env=env, text=True, capture_output=True, timeout=50)
        if result.returncode != 0:
            raise RuntimeError(result.stdout + result.stderr)
        evidence = json.loads(result.stdout)['normalized_result']
        kernel = evidence['kernels'][0]
        print(json.dumps({'case': name, 'exit': result.returncode, 'stderr': result.stderr, 'payloads': evidence['coverage']['payloads'], 'parameter_bytes': kernel['parameter_bytes'], 'parameters': kernel['parameters'], 'retained_text_matches': evidence['ptx_artifacts'][0]['text'] == text}))
print('Disposable fixture and environment directories removed.')
PY

The header and entry built by the block make the qualified input exactly:

.version 8.8
.target sm_80
.address_size 64
.visible .entry k(.param .u64 .ptr .global .align 4 ptr_arg, .param .u32 count) { ret; }

Expected behavior

Keep ptr_arg in the structured parameter row. REA's documented treatment of unsupported parameter layouts retains known facts and explicit limitations. The declared identifier is known independently of layout interpretation. It is acceptable for sizes, offsets and total bytes to remain unknown with partial coverage; calculating qualified-pointer layout is not necessary to satisfy this report.

Impact and scope

The affected output loses a meaningful identifier from structured kernel facts for the tested qualified declarations. An analyst can recover it from the retained original text, but must interpret the declaration manually. The observed loss is bounded, and REA reports partial coverage rather than asserting complete decoding. Both qualified pointer parameters in one independently compiled kernel also lost their names. This sample establishes that a real producer emits affected declarations; it does not establish prevalence among CUDA or HIP workloads. Embedded containers and MCP were not executed. No security boundary crossing was identified.

REA version

Source revision bcd1f95e688a2ac020a9d13f9c85e0ce321cb6b6; the prepared source launcher's --version prints 6.7.0. The latest published release tag is rea-agents-6.7.0, but its source tree has no GPU reader or GPU command files. The affected parser and documentation were added after that tag. This report establishes the source-build failure; no published-package runtime failure is claimed.

Runtime and platform

Node.js v24.22.1; macOS 27.0.1 arm64. Public CLI execution used isolated HOME, USERPROFILE, XDG and temporary directories with no inherited REA or provider overrides. No GPU, CUDA toolkit, Hopper or Ghidra was needed. The optional producer check used the available Homebrew Clang 23.1.1 NVPTX backend.

Target and artifact context

The primary fixture is 133 bytes of standalone UTF-8 PTX 8.8 targeting sm_80 with a 64-bit address size and one two-parameter kernel. The plain fixture differs only by removal of .ptr .global .align 4. The dynamic-array case is an unsupported-layout parser control, not a claim that its kernel ABI was independently validated by an assembler.

Interface

CLI

Earliest failure stage

Native analysis or reconstruction

Relevant output or evidence

  • Expected source: docs/gpu-code-objects.md:81-88 promises preservation of known facts for unsupported parameter layouts; NVIDIA's PTX ISA 8.8 section 5.1.6.3 specifies the exact qualifier position and optional state space/alignment, including joined qualifier spellings. The pointer-memory alignment qualifier does not make the identifier unknown.
  • Failure source: The independently executed public CLI reproduction above; src/gpu/PtxKernels.ts:124-130 chooses the token immediately after the scalar type as its name candidate, :150-158 returns the unsupported declaration facts, and :337-341 emits the layout limitation. src/cli/gpuCommands.ts:98-117 and src/gpu/GpuInventory.ts:228-252,335-375 establish the public route to that parser.
  • Evidence provenance: observed
  • Local verification: reproduced
  • Reproduction completeness: complete

Selected observed results, with unrelated fields omitted:

qualified:   first name=null, size=null, offset=null; count name retained; total=null; payloads=partial
plain:       first name=ptr_arg, size=8, offset=0; count size=4, offset=8; total=12; payloads=complete
unsupported: first name=dyn_arg, size=null, offset=null; count name retained; total=null; payloads=partial
All three: exit=0; stderr empty; retained_text_matches=true

The qualified kernel's additional limitation was:

Unsupported PTX parameter declarations or overflowing layouts leave parameter sizes/offsets and the total byte count unknown.

The public inspect-analysis-view command was also executed with inline Evidence from the qualified result and view { "kind": "gpu-code-objects", "collection": "ptx", "object_id": "file@0", "offset": 0, "limit": 4096 }. It exited 0 with empty stderr and returned the exact original text, including ptr_arg, with exhausted page coverage. This verifies that the original identifier remains available as a manual workaround. A kernels view explicitly selecting fields: ["name", "parameters"] also exited 0 and returned the null first parameter name, so paging the structured facts does not recover it. A separate execution of the unchanged source parser produced the same parameter results as the compiled CLI. The existing focused PTX parser test file passed all 11 tests; those passing tests do not establish coverage of this case.

Typed outcome or recovery expected

Return the declared identifier in the ordinary GPU kernel parameter row. Preserve explicit unknown layout facts and partial coverage when the layout remains unsupported. No new error type is required by the name-preservation contract.

Analysis or suspected cause

Source-derived: the parser treats the first token after .u64 as the name candidate. For the failing input that token is .ptr, which fails its identifier predicate. The actual identifier later in the declaration is never selected. The unsupported branch then retains the resulting null name, while the corresponding branch for the array control retains the identifier it already found. This explains the observed difference without requiring a change to layout support.

Additional context

A local producer check compiled this source as device-only CUDA:

extern "C" __attribute__((global)) void increment(float *out, const float *in, unsigned count) {
  if (count != 0) out[0] = in[0] + 1.0f;
}

The executed compiler command, using the recorded Clang version, was:

clang -x cuda --cuda-device-only -nocudalib -nocudainc --cuda-gpu-arch=sm_80 -S -O1 producer.cu -o producer.ptx

It exited 0 and emitted PTX 7.0 with .param .u64 .ptr .align 1 increment_param_0, the same form for increment_param_1, and unqualified .param .u32 increment_param_2. Running the same public REA command on that generated file exited 0 and returned parameter names [null, null, "increment_param_2"] with partial coverage. The generated PTX was inspected statically; no assembly or GPU execution was performed.

Open and closed issue searches found no matching pointer-parameter name report. Related reports concern an omitted optional entry parameter list, register declaration length, and target-alias admission; their triggers and restoration signals differ from this case. The completed GPU inventory feature is the implemented capability this report exercises. NOT_ENOUGH_INFO: the last source revision that retained these qualified names is unknown; no regression window was established.

Restoration check

Rerun the original qualified input without rewriting its bytes. Its first structured parameter name must be ptr_arg, and the sibling name must remain count. Size/offset and total bytes may remain null with explicit partial coverage, or become known if qualified layouts are supported; name preservation is required either way. The plain control must retain its observed names, sizes, offsets and complete coverage. The unsupported-layout control must retain dyn_arg and honest unknown layout facts. The independently generated kernel must retain both declared pointer-parameter names. Original retained PTX must still match each input exactly.

Triage assessment

  • Impact level: P2
  • Assessment status: supported
  • Impact basis: Valid qualified declarations lose identifiers from machine-readable kernel facts through the public CLI, including two parameters emitted by an actual compiler; the loss is bounded and the result remains explicitly partial.
  • Workaround status: available
  • Workaround basis: Complete Evidence retains the exact PTX, and the executed PTX analysis view returned the original declaration and identifier. An analyst can read that text without changing artifact identity, although this does not restore the missing structured field.
Originally created by @coygeek on GitHub (Oct 23, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/6606 ## 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 public `inspect-gpu-code-objects` command returns `name: null` for the first parameter in `.entry k(.param .u64 .ptr .global .align 4 ptr_arg, .param .u32 count)`. The kernel, scalar type and second parameter name survive, and the original retained PTX still contains `ptr_arg`. The object and payload coverage are partial, with a limitation about unknown parameter layout. Removing only the pointer qualifiers restores `name: "ptr_arg"`, size 8, offset 0 and complete coverage. A separate unsupported-layout control, `.param .u64 dyn_arg[]`, retains `dyn_arg` while reporting unknown size/offset and partial coverage. Partial layout coverage therefore does not consistently prevent name retention. ## Reproduction Run from the source checkout identified below with its required Node toolchain, locked dependencies and compiled runtime already prepared. Python 3 is used only to create disposable fixtures, isolate the child environment and summarize JSON. The block below was executed successfully once per input; earlier independent runs of the qualified, plain and unsupported-layout cases each gave the same result twice. All inspection calls exited 0 with empty stderr. ```sh PATH=/opt/homebrew/opt/node@24/bin:$PATH python3 - <<'PY' import json, os, pathlib, shutil, subprocess, tempfile repo = pathlib.Path.cwd() node = shutil.which('node') header = '.version 8.8\n.target sm_80\n.address_size 64\n' with tempfile.TemporaryDirectory(prefix='ptx-parameter-check-') as directory: work = pathlib.Path(directory) env = {'PATH': os.environ['PATH']} for key, name in {'HOME':'home', 'USERPROFILE':'home', 'XDG_CONFIG_HOME':'config', 'XDG_CACHE_HOME':'cache', 'XDG_DATA_HOME':'data', 'XDG_STATE_HOME':'state', 'XDG_RUNTIME_DIR':'run', 'TMPDIR':'temp'}.items(): path = work / name path.mkdir(mode=0o700, exist_ok=True) env[key] = str(path) cases = { 'qualified': '.param .u64 .ptr .global .align 4 ptr_arg', 'plain': '.param .u64 ptr_arg', 'unsupported': '.param .u64 dyn_arg[]', } for name, parameter in cases.items(): fixture = work / (name + '.ptx') text = header + '.visible .entry k(' + parameter + ', .param .u32 count) { ret; }\n' fixture.write_text(text) command = [node, str(repo / 'scripts/rea.mjs'), 'inspect-gpu-code-objects', str(fixture), '--analysis', 'kernels', '--detail', 'complete', '--json'] result = subprocess.run(command, cwd=work, env=env, text=True, capture_output=True, timeout=50) if result.returncode != 0: raise RuntimeError(result.stdout + result.stderr) evidence = json.loads(result.stdout)['normalized_result'] kernel = evidence['kernels'][0] print(json.dumps({'case': name, 'exit': result.returncode, 'stderr': result.stderr, 'payloads': evidence['coverage']['payloads'], 'parameter_bytes': kernel['parameter_bytes'], 'parameters': kernel['parameters'], 'retained_text_matches': evidence['ptx_artifacts'][0]['text'] == text})) print('Disposable fixture and environment directories removed.') PY ``` The header and entry built by the block make the qualified input exactly: ```ptx .version 8.8 .target sm_80 .address_size 64 .visible .entry k(.param .u64 .ptr .global .align 4 ptr_arg, .param .u32 count) { ret; } ``` ## Expected behavior Keep `ptr_arg` in the structured parameter row. REA's documented treatment of unsupported parameter layouts retains known facts and explicit limitations. The declared identifier is known independently of layout interpretation. It is acceptable for sizes, offsets and total bytes to remain unknown with partial coverage; calculating qualified-pointer layout is not necessary to satisfy this report. ## Impact and scope The affected output loses a meaningful identifier from structured kernel facts for the tested qualified declarations. An analyst can recover it from the retained original text, but must interpret the declaration manually. The observed loss is bounded, and REA reports partial coverage rather than asserting complete decoding. Both qualified pointer parameters in one independently compiled kernel also lost their names. This sample establishes that a real producer emits affected declarations; it does not establish prevalence among CUDA or HIP workloads. Embedded containers and MCP were not executed. No security boundary crossing was identified. ## REA version Source revision `bcd1f95e688a2ac020a9d13f9c85e0ce321cb6b6`; the prepared source launcher's `--version` prints `6.7.0`. The latest published release tag is `rea-agents-6.7.0`, but its source tree has no GPU reader or GPU command files. The affected parser and documentation were added after that tag. This report establishes the source-build failure; no published-package runtime failure is claimed. ## Runtime and platform Node.js v24.22.1; macOS 27.0.1 arm64. Public CLI execution used isolated HOME, USERPROFILE, XDG and temporary directories with no inherited REA or provider overrides. No GPU, CUDA toolkit, Hopper or Ghidra was needed. The optional producer check used the available Homebrew Clang 23.1.1 NVPTX backend. ## Target and artifact context The primary fixture is 133 bytes of standalone UTF-8 PTX 8.8 targeting sm_80 with a 64-bit address size and one two-parameter kernel. The plain fixture differs only by removal of `.ptr .global .align 4`. The dynamic-array case is an unsupported-layout parser control, not a claim that its kernel ABI was independently validated by an assembler. ## Interface CLI ## Earliest failure stage Native analysis or reconstruction ## Relevant output or evidence - Expected source: `docs/gpu-code-objects.md:81-88` promises preservation of known facts for unsupported parameter layouts; NVIDIA's [PTX ISA 8.8 section 5.1.6.3](https://docs.nvidia.com/cuda/archive/12.9.1/parallel-thread-execution/index.html#kernel-parameter-attribute-ptr) specifies the exact qualifier position and optional state space/alignment, including joined qualifier spellings. The pointer-memory alignment qualifier does not make the identifier unknown. - Failure source: The independently executed public CLI reproduction above; `src/gpu/PtxKernels.ts:124-130` chooses the token immediately after the scalar type as its name candidate, `:150-158` returns the unsupported declaration facts, and `:337-341` emits the layout limitation. `src/cli/gpuCommands.ts:98-117` and `src/gpu/GpuInventory.ts:228-252,335-375` establish the public route to that parser. - Evidence provenance: observed - Local verification: reproduced - Reproduction completeness: complete Selected observed results, with unrelated fields omitted: ```text qualified: first name=null, size=null, offset=null; count name retained; total=null; payloads=partial plain: first name=ptr_arg, size=8, offset=0; count size=4, offset=8; total=12; payloads=complete unsupported: first name=dyn_arg, size=null, offset=null; count name retained; total=null; payloads=partial All three: exit=0; stderr empty; retained_text_matches=true ``` The qualified kernel's additional limitation was: ```text Unsupported PTX parameter declarations or overflowing layouts leave parameter sizes/offsets and the total byte count unknown. ``` The public `inspect-analysis-view` command was also executed with inline Evidence from the qualified result and view `{ "kind": "gpu-code-objects", "collection": "ptx", "object_id": "file@0", "offset": 0, "limit": 4096 }`. It exited 0 with empty stderr and returned the exact original text, including `ptr_arg`, with exhausted page coverage. This verifies that the original identifier remains available as a manual workaround. A kernels view explicitly selecting `fields: ["name", "parameters"]` also exited 0 and returned the null first parameter name, so paging the structured facts does not recover it. A separate execution of the unchanged source parser produced the same parameter results as the compiled CLI. The existing focused PTX parser test file passed all 11 tests; those passing tests do not establish coverage of this case. ## Typed outcome or recovery expected Return the declared identifier in the ordinary GPU kernel parameter row. Preserve explicit unknown layout facts and partial coverage when the layout remains unsupported. No new error type is required by the name-preservation contract. ## Analysis or suspected cause Source-derived: the parser treats the first token after `.u64` as the name candidate. For the failing input that token is `.ptr`, which fails its identifier predicate. The actual identifier later in the declaration is never selected. The unsupported branch then retains the resulting null name, while the corresponding branch for the array control retains the identifier it already found. This explains the observed difference without requiring a change to layout support. ## Additional context A local producer check compiled this source as device-only CUDA: ```cpp extern "C" __attribute__((global)) void increment(float *out, const float *in, unsigned count) { if (count != 0) out[0] = in[0] + 1.0f; } ``` The executed compiler command, using the recorded Clang version, was: ```sh clang -x cuda --cuda-device-only -nocudalib -nocudainc --cuda-gpu-arch=sm_80 -S -O1 producer.cu -o producer.ptx ``` It exited 0 and emitted PTX 7.0 with `.param .u64 .ptr .align 1 increment_param_0`, the same form for `increment_param_1`, and unqualified `.param .u32 increment_param_2`. Running the same public REA command on that generated file exited 0 and returned parameter names `[null, null, "increment_param_2"]` with partial coverage. The generated PTX was inspected statically; no assembly or GPU execution was performed. Open and closed issue searches found no matching pointer-parameter name report. Related reports concern an omitted optional entry parameter list, register declaration length, and target-alias admission; their triggers and restoration signals differ from this case. The completed GPU inventory feature is the implemented capability this report exercises. NOT_ENOUGH_INFO: the last source revision that retained these qualified names is unknown; no regression window was established. ## Restoration check Rerun the original qualified input without rewriting its bytes. Its first structured parameter name must be `ptr_arg`, and the sibling name must remain `count`. Size/offset and total bytes may remain null with explicit partial coverage, or become known if qualified layouts are supported; name preservation is required either way. The plain control must retain its observed names, sizes, offsets and complete coverage. The unsupported-layout control must retain `dyn_arg` and honest unknown layout facts. The independently generated kernel must retain both declared pointer-parameter names. Original retained PTX must still match each input exactly. ## Triage assessment - Impact level: P2 - Assessment status: supported - Impact basis: Valid qualified declarations lose identifiers from machine-readable kernel facts through the public CLI, including two parameters emitted by an actual compiler; the loss is bounded and the result remains explicitly partial. - Workaround status: available - Workaround basis: Complete Evidence retains the exact PTX, and the executed PTX analysis view returned the original declaration and identifier. An analyst can read that text without changing artifact identity, although this does not restore the missing structured field.
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#3992
No description provided.