Skip to content

fn-literal labels: unforgeable separator, unique named-literal keys; certify pins its oracle JDK - #1082

Merged
yogthos merged 2 commits into
mainfrom
fix/munge-followups
Sep 21, 2026
Merged

yogthos merged 2 commits into
mainfrom
fix/munge-followups

Conversation

@yogthos

@yogthos yogthos commented Sep 21, 2026

Copy link
Copy Markdown
Member

Follow-up to #1080, closing the two beads left from it.

jfn$ labels. The anon-fn label used $ as its separator, and the munge spells escapes with $, so ns a$ + def c and ns a + def $c both registered as jfn$a$$$c$0. Same forgery #1080 closed for jv$; same fix — the label is jfn$<ns>/<def>$<n> over munge-chars, and / cannot come from an escape or a name.

Probing that found two real collisions in the fn-form registry (the image writer's source map):

  • a named inner literal was keyed <name>$jf<n> with the counter per def — (fn mapi …) in two defs, or in two namespaces, both registered as mapi$jf0 and an image restore of the first came back with the second's source;
  • on the runtime eval path a named inner literal took the ns/name binding and was never registered at all, so a closure over a letfn-bound fn dumped from a build and refused from a jolt run session.

A named literal is jfn$<ns>/<def>$<n>/<name> on both paths; ns/name stays the def's direct init only. Backtraces show it as ns/def/name (was ns/name, which reads as a var). Not image surface: restore uses the name only in error text.

certify. profile.edn pins :oracle-jdk 21; certify.clj refuses any other JDK (26 changed java.util.zip's exceptions and reported 11 rows as NEW divergences), and make certify finds the pinned JDK for JAVA_CMD when it is unset. make ci is green locally with no env var.

Both seeds reminted; make ci 141 targets green, selfhost at fixpoint. Filed jolt-ebie for a loaderconf case-13 race seen once under -j8 load, unrelated to this change.

Yogthos added 2 commits September 21, 2026 11:21
…/<name>

The anon-fn label joined munge-name(ns) $ munge-name(def) $ n, and the
munge itself spells escapes with $, so ns "a$" + def "c" and ns "a" +
def "$c" both registered as jfn$a$$$c$0 and the second registration
replaced the first — the same forgery #1080 closed for jv$ names. The
separator is / now: munge-chars never emits one and the reader never
lets one into a namespace or def name.

Probing that turned up two more registry collisions. A named inner
literal was keyed <name>$jf<n> with the counter per def, so `mapi` in
two defs, or in two namespaces, both registered as mapi$jf0, and an
image restore of the first closure came back with the second's source.
And on the runtime eval path the qualified ns/name branch won for every
named fn, not only the def's direct init, and that branch never
registered: a closure over a letfn-bound fn dumped from a build and
refused from a `jolt run` session. A named literal is now
jfn$<ns>/<def>$<n>/<name> on both paths; ns/name stays the direct
init's binding, which is what the source registry keys on. A backtrace
shows the literal as ns/def/name, the way clojure.stacktrace demunges
user$f$mapi__12 (was ns/name, which reads as a var the namespace does
not have). *known-procs* maps a name to the site its frame carries so a
:local call site records the same name as the callee's frame.

The label was never image surface: the restore side uses the record's
name only in error text; form, ns and free names travel in the record.
A corpus value is measured on one JDK, and a different one reports its
own java.* changes as jolt divergences: JDK 26 raises
IllegalStateException where 21 raises NullPointerException on a closed
Inflater and reworded the CEN messages, so a local `make ci` on a
machine whose clojure launcher found JDK 26 failed certify with 11 NEW
rows and nothing wrong. certify.clj only refused an older oracle.

profile.edn carries :oracle-jdk (--profile writes the JDK it ran on),
certify.clj refuses any other feature version, and make certify hands
the launcher the pinned JDK through JAVA_CMD when it is unset and one of
the usual installs has it (Homebrew openjdk@N, /usr/lib/jvm/java-N-*,
java_home). CI keeps setting JAVA_CMD itself.
@yogthos
yogthos merged commit e2489d3 into main Sep 21, 2026
10 checks passed
@yogthos
yogthos deleted the fix/munge-followups branch September 21, 2026 15:42
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.

1 participant