Skip to content

[AUTOMATED] Cast pointer values assigned to integer frame members - #1241

Merged
mahaloz merged 7 commits into
Noelo-Lab:mainfrom
thotypous:fix/declared-pointer-slot-casts
Oct 22, 2026
Merged

mahaloz merged 7 commits into
Noelo-Lab:mainfrom
thotypous:fix/declared-pointer-slot-casts

Conversation

@thotypous

Copy link
Copy Markdown
Contributor

A declared pointer copied into an integer frame member can print as frame[0] = value;, which Clang rejects. On x86-64 Linux, run from the repository root:

cat > /var/tmp/slot.c <<'C'
#include <stdint.h>
__attribute__((naked)) unsigned emit(unsigned char *value) {
 __asm__("sub $24,%rsp;mov %rdi,%rax;mov %rax,(%rsp);mov %rsp,%rdi;call consume;add $24,%rsp;ret");
}
__attribute__((aligned(32))) unsigned consume(void *p) {
 uintptr_t v;__builtin_memcpy(&v,p,sizeof(v));return *(unsigned char*)v;
}
C
clang -O2 -shared -fPIC -nostdlib -fcf-protection=none \
  -Wl,-Bsymbolic,--section-start,.text=0x1000 /var/tmp/slot.c -o /var/tmp/slot.so
decompiler/target/release/decomp_dbg -s specs <<'COMMANDS'
load file /var/tmp/slot.so
read symbols
option ctypes on
map prototype 0x1000 unsigned int emit(unsigned char *value)
map prototype 0x1020 unsigned int consume(void *slot)
load addr 0x1000
map address s0xffffffffffffffe8 unsigned long frame[2]
type varnode %RAX(0x1004) unsigned char *address
decompile
print C
quit
COMMANDS
  • Use the destination's rendered member type when an asserted pointer is copied into same-width integer storage.
  • Emit frame[0] = (unsigned long)value;; preserve numeric conversions, nocasts, and other output languages.

Six focused Clang PE32/ELF64 array/record cases pass, including stackviews on/off and O0/O2 recompilation. ELF64 cases each compare 4,096 native/recompiled calls per optimization. The three ELF cases fail before the fix. make check-spec passes; full suites are left to CI.

mahaloz and others added 3 commits October 22, 2026 18:41
The PE32 cases compiled the sample for i686-w64-windows-gnu with
`#include <stdint.h>`, which needs a MinGW sysroot; on a host whose clang
has no such headers the three PE32 tests failed instead of exercising
kuna. Use the compiler's builtin `__UINTPTR_TYPE__` so the freestanding
sample needs no target headers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BEr111CDLJsQMzY3YSyWXD
…NULL as 0

A pointer addition or member address assigned to integer storage still
printed without a cast (`frame[0] = &value[1];`), which gcc 15 and clang
reject. Treat PTRADD and PTRSUB statements like pointer copies.

A copied variable whose own declaration is an integer gained a redundant
cast (`cout = (unsigned long)cstart;` with `unsigned long cstart`); skip
it when the source variable is declared as a non-pointer. A null pointer
constant copied into integer storage now prints as `0` instead of
`(long)NULL`.

Adds two derived-pointer round-trip cases to the pointer-slot test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BEr111CDLJsQMzY3YSyWXD
@mahaloz

mahaloz commented Oct 22, 2026

Copy link
Copy Markdown
Contributor

[AUTOMATED] Pushed three commits on top of this branch:

  • 5af3324ff: the sample in pointer_slot_casts.rs uses __UINTPTR_TYPE__ rather than <stdint.h>. On a host whose clang has no MinGW headers, the PE32 cases were failing before kuna ran at all.
  • f1d15187f: a pointer addition or member address assigned to integer storage still printed without a cast (frame[0] = &value[1];, which gcc 15 rejects). PTRADD/PTRSUB statements now get the same cast. A copied variable that is itself declared as an integer no longer gets a redundant cast (cout = (unsigned long)cstart;). A copied null pointer now prints as 0 rather than (long)NULL. Two derived-pointer round-trip cases are added, and the spec paragraph is updated.
  • 6ef62a525: merged origin/main (resolved the tests/integration.rs module list).

mahaloz added a commit to thotypous/kuna that referenced this pull request Oct 22, 2026
…headers from the test

The fallback member lookup preferred the high's mapped Symbol type for every
variable. For a scalar local or global that type can differ from the type its
declaration prints (tar _help declares `unsigned long v50` but its Symbol is
`hol *`; a named global is declared at the type its accesses print), so the
pointer cast that Noelo-Lab#1241 added (`v50 = (unsigned long)v22;`,
`current_block = (long)v6;`) was dropped again and the C stopped compiling.
Use the Symbol type only when it is a structure, array or union, where the
declaration representative covers just the field.

The printer test now uses __UINTPTR_TYPE__ instead of <stdint.h>, so the
PE32 compile does not need a mingw sysroot.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BEr111CDLJsQMzY3YSyWXD
mahaloz added a commit to thotypous/kuna that referenced this pull request Oct 22, 2026
…to fix/integer-to-pointer-slots

Resolve kuna_pointerstorecast.rs: match COPY, CAST, PTRADD and PTRSUB; keep
this branch's CAST result type, widened source filter and two-way tail; keep
Noelo-Lab#1241's early return for a COPY whose input is declared a non-pointer, but
only when the source is a pointer, so it does not block the integer-to-pointer
COPY case.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BEr111CDLJsQMzY3YSyWXD
mahaloz and others added 2 commits October 22, 2026 21:00
The declared-non-pointer skip dropped the cast whenever the copied
variable's declaration was not a pointer. A source declared as a record
prints as the pointer member it reads, so `long x = (long)w.p;` with a
`W w` parameter printed `x = w.p;`, which gcc 15 rejects. Skip the cast
only when the source is declared as a same-width integer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BEr111CDLJsQMzY3YSyWXD
@mahaloz

mahaloz commented Oct 22, 2026

Copy link
Copy Markdown
Contributor

[AUTOMATED] Pushed c009e52 (plus a merge of origin/main, 8863f8f, which resolves the kuna-cli/tests/integration.rs module list).

The f1d1518 skip of the cast for a source variable declared as a non-pointer also dropped it for a source declared as a record. Such a source prints as the pointer member it reads, so long load(W w) { long x = (long)w.p; ... } (with W = struct { unsigned char *p; }, gcc -O2 -g) printed x = w.p;, which gcc 15 rejects. The cast is now skipped only for a source declared as an integer of the same width. The commit adds pointer_slot_casts::record_declared_source_keeps_cast. On the 99-binary corpus, the output is byte-identical to the previous head.

@mahaloz
mahaloz merged commit 090de68 into Noelo-Lab:main Oct 22, 2026
2 checks passed
mahaloz added a commit to thotypous/kuna that referenced this pull request Oct 22, 2026
Noelo-Lab#1241 landed as a squash; this re-applies only Noelo-Lab#1249's own changes on top
of main.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BEr111CDLJsQMzY3YSyWXD
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants