mirror of
https://github.com/Druthulu/BFM-decomp
synced 2026-09-26 13:33:34 -04:00
fix(gate_main): refuse a verbatim-asm draft at slate load
I converted 9 main SDK functions from §265 verbatim bodies to INCLUDE_ASM stubs so they could be decompiled, then 'banked' all 9 from stored drafts that were those same verbatim asm blocks. match_one printed closeness 0 nine times and the whole-binary gate went BYTE-IDENTICAL — both truthfully, since a raw asm blob assembles to the bytes it was copied from. Nothing was decompiled. progress.py caught it by not moving: REAL 882, VERBATIM 164, INCLUDE_ASM 37, identical before and after. The banks are reverted. The cookbook's closing paragraph, written last session, describes this exact trap. I read it and hit it anyway ~4 hours later, because the rule was addressed to 'any burst over this class' and I was hand-picking stored drafts, and because 'no byte gate can catch it' reads as unpreventable. The byte CHECK cannot; a slate-load refusal can. draft_prechecks.is_verbatim_asm_draft: a file-scope __asm__ naming the fn via .ent/.globl/label AND no C definition of it. Both spellings of .ent handled (inside a C string it is a backslash-t, not a tab — five censuses of this class disagreed until that was fixed). gate_main refuses such a slate beside its existing INCLUDE_ASM no-op refusal (R43). Census of the draft store: 1,099 of 704,375 .c files are verbatim-asm drafts under ordinary <fn>.c names. Negative control: 0 false positives across 45,898 drafts carrying both a C definition and an inline __asm__ (R39).
This commit is contained in:
@@ -35133,3 +35133,48 @@ its own source by construction**. The adversarial verifier refuted it on the rul
|
||||
containing `__asm__` or `INCLUDE_ASM` is a no-op that passes for free. Any burst over this class MUST
|
||||
carry that check: the trivially-passing draft is not a hypothetical here, it is the *default* thing to
|
||||
produce, and a byte gate cannot tell the difference.
|
||||
|
||||
#### ADDENDUM to §265 (P31 S76) — THE PROSE GUARD DID NOT HOLD. IT IS A GATE REFUSAL NOW.
|
||||
|
||||
**The paragraph immediately above this one was written in S75 and is correct. I tripped over the
|
||||
exact trap it describes about four hours later, in the next session, having read it.** That is the
|
||||
finding worth keeping — not the trap, which was already known, but the fact that knowing it in
|
||||
prose did not prevent it.
|
||||
|
||||
**What happened.** The 9 remaining `DECOMPILE-NOW` SDK functions in `src/800c3.c` / `src/800c2_2.c`
|
||||
were converted from §265 verbatim bodies to `INCLUDE_ASM` stubs *specifically so they could be
|
||||
decompiled*. I then searched the draft store for stored drafts, scored 195 candidates with
|
||||
`match_one`, and got **closeness 0 on all nine**. Slate, gate, `BANKED 9 main functions —
|
||||
143dbb89 BYTE-IDENTICAL`, 58 seconds. Every one of those nine "drafts" was the function's own
|
||||
assembly, emitted by `tools/asm_verbatim.py` into `<fn>.c` in the same directories as real drafts.
|
||||
I had converted verbatim → stub → verbatim. A perfect round trip that decompiled nothing.
|
||||
|
||||
**What caught it: `progress.py` did not move.** REAL 882, VERBATIM 164, INCLUDE_ASM 37 — identical
|
||||
before and after "banking nine functions". The instrument was right and the claim was wrong
|
||||
(`check-against-a-known-true-case`: the count you already know is the cheapest oracle you own).
|
||||
|
||||
**Why the prose could not hold.** S75's rule was addressed to a *burst over this class* — "any
|
||||
burst over this class MUST carry that check". I was not running a burst. I was hand-picking stored
|
||||
drafts one function at a time, which the rule did not name, and the conditional in a reader's head
|
||||
("does this apply to me?") is exactly where a prose guard fails. S75 also concluded "a byte gate
|
||||
cannot tell the difference", which is true and which reads as *unpreventable*. It is not: the byte
|
||||
CHECK cannot tell, but a **slate-load refusal** can, because the verbatim form is trivially
|
||||
decidable from the text.
|
||||
|
||||
**The guard, where it can actually fire.** `draft_prechecks.is_verbatim_asm_draft(text, fn)` — a
|
||||
file-scope `__asm__` naming this fn via `.ent`/`.globl`/label, AND no C definition of it. Both
|
||||
halves matter: a real draft may carry a small inline `__asm__`, and a verbatim body may omit
|
||||
`.globl` for a static. Match BOTH spellings — `".ent\tNAME"` inside a C string is a *backslash-t*,
|
||||
not a tab; five S75/S76 censuses of this class disagreed with each other until both were handled.
|
||||
`gate_main` now refuses such a slate at load, beside its existing `INCLUDE_ASM` no-op refusal (R43).
|
||||
|
||||
**The scale of the landmine.** A census of the draft store: **1,099 of 704,375 `.c` files are
|
||||
verbatim-asm drafts**, sitting under ordinary `<fn>.c` names in ordinary wave directories. Negative
|
||||
control: **0 false positives across 45,898** drafts that carry both a real C definition and an
|
||||
inline `__asm__` (R39). Any future "search the store for a stored draft" pass — and that pass is now
|
||||
a standard move, since S75 banked 20 functions from drafts already on disk — is drawing from a pool
|
||||
with 1,099 of these in it.
|
||||
|
||||
**The general law.** *A lesson that is only prose will be re-learned. If a check is decidable, the
|
||||
knowledge base is where you explain it and the pipeline is where you enforce it* — the same
|
||||
relationship R32 sets between "assert your coverage" and a scanner that actually does.
|
||||
|
||||
@@ -116,3 +116,41 @@ def undefined_data(binary, dest_text, syms, self_name=None, body=""):
|
||||
continue
|
||||
out.append(s)
|
||||
return out
|
||||
|
||||
|
||||
def is_verbatim_asm_draft(text, fn):
|
||||
"""True if `text` is the target's own assembly, not a decompile of it (P31 S76).
|
||||
|
||||
THE DEFECT THIS CATCHES, and why no byte gate can. `tools/asm_verbatim.py` emits a §265
|
||||
verbatim body -- the function's own .s pasted into a file-scope `__asm__` string. Those files
|
||||
sit in the same draft directories as real C drafts and are named `<fn>.c` like everything else.
|
||||
Score one with match_one and it prints MATCH, truthfully: a raw asm blob assembles to the bytes
|
||||
it was copied from. Substitute one and the whole-binary gate goes GREEN, also truthfully. The
|
||||
function is then reported BANKED while nothing whatsoever has been decompiled.
|
||||
|
||||
S75 hit this once (an agent submitted the verbatim block as its own "decompile"; only an
|
||||
adversarial reader caught it) and recorded "No byte gate can" catch it. That is true of the
|
||||
BYTE check and false of a slate-load refusal, which is why this lives here: the verbatim form
|
||||
is trivially decidable from the text (R43 -- refuse the input, never mishandle it).
|
||||
|
||||
S76 hit it again, from the other direction and at scale: nine functions were converted from
|
||||
verbatim bodies to stubs precisely so they could be decompiled, then "banked" from stored
|
||||
drafts that were the same verbatim blocks -- a round trip through the gate that moved
|
||||
progress.py by exactly zero and read as 9 of 9 MATCH. The instrument was right and the claim
|
||||
was wrong.
|
||||
|
||||
A draft is verbatim iff a file-scope `__asm__` names this function as a .ent/.globl/label AND
|
||||
no C definition of it exists. Both halves matter: a real draft may legitimately carry a small
|
||||
inline `__asm__`, and a verbatim body may omit .globl for a static."""
|
||||
if '__asm__' not in text:
|
||||
return False
|
||||
f = re.escape(fn)
|
||||
# The escaped forms are what the emitters write INTO a C string: `.ent\tfoo\n` is backslash-t,
|
||||
# not a tab. Match both the escaped and the literal spellings -- five S76 censuses of this
|
||||
# class disagreed with each other until both were handled.
|
||||
asm_names = re.search(rf'\.(?:ent|globl)(?:\\t|[ \t])+{f}\b', text) or \
|
||||
re.search(rf'"\s*{f}:\s*(?:\\n|$)', text)
|
||||
if not asm_names:
|
||||
return False
|
||||
c_def = re.search(rf'^[A-Za-z_][\w \*]*\b{f}\s*\([^;]*\)\s*(?:/\*.*?\*/\s*)?\{{', text, re.M | re.S)
|
||||
return not c_def
|
||||
|
||||
@@ -39,6 +39,7 @@ import hashlib
|
||||
import time, collections, fcntl, functools, glob, json, os, re, subprocess, sys
|
||||
sys.path.insert(0, 'tools')
|
||||
import corpus
|
||||
import draft_prechecks as DP
|
||||
|
||||
# stdout is BUFFERED when redirected to a file -- a long run then looks hung with an
|
||||
# empty log (measured: 16 min of silence during a bisect). Always flush.
|
||||
@@ -932,6 +933,24 @@ def main():
|
||||
|
||||
'passes for free: %s' % (len(_noop), ', '.join(_noop)))
|
||||
|
||||
# THE SAME NO-OP, WEARING C's CLOTHES (P31 S76). A §265 verbatim body is the function's own
|
||||
# assembly in a file-scope `__asm__` string; `tools/asm_verbatim.py` writes them as `<fn>.c`
|
||||
# into the same draft directories as real drafts. Substituting one assembles the bytes it was
|
||||
# copied from, so match_one prints MATCH and this gate goes GREEN -- both truthfully -- while
|
||||
# nothing has been decompiled. S75 saw it once from an agent and concluded "no byte gate can"
|
||||
# catch it; that is true of the BYTE check and false of a slate-load refusal. S76 then did it
|
||||
# at scale: 9 functions converted from verbatim bodies to stubs *so they could be decompiled*,
|
||||
# then "banked" from stored drafts that were those same verbatim blocks. 9 of 9 MATCH, and
|
||||
# progress.py moved by exactly zero. Refuse at load, like the INCLUDE_ASM no-op above (R43).
|
||||
_verb = [e['fn'] for e in slate
|
||||
if os.path.exists(e.get('draft', ''))
|
||||
and DP.is_verbatim_asm_draft(open(e['draft'], errors='replace').read(), e['fn'])]
|
||||
if _verb:
|
||||
raise SystemExit("gate_main: REFUSED — %d draft(s) are the target's own assembly in a "
|
||||
"file-scope __asm__ (a §265 verbatim body), not a decompile. They would "
|
||||
"pass this gate for free and bank nothing: %s"
|
||||
% (len(_verb), ', '.join(_verb)))
|
||||
|
||||
kept, dropped = resolve_conflicts(slate)
|
||||
print(f"slate {len(slate)} -> {len(kept)} compatible, {len(dropped)} dropped for in-TU decl conflict")
|
||||
for d in dropped:
|
||||
|
||||
Reference in New Issue
Block a user