Skip to content

Commit 8621cd0

Browse files
authored
Merge pull request #18 from BuddhiLW/main
v1.15.1: wasm/exports, dot interop over wasm exports, zwasm fork main, README rewrite
2 parents 72920fd + 9adabd2 commit 8621cd0

33 files changed

Lines changed: 1624 additions & 492 deletions

‎.dev/debt.yaml‎

Lines changed: 11 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -24,50 +24,6 @@
2424
# md-table-align no longer pads it to ~800 KB of whitespace.
2525

2626
active:
27-
- id: "D-587"
28-
status: |-
29-
open (2026-09-09). USE-AFTER-FREE, user-reachable panic. Re-registering a
30-
deftype/defrecord name frees a TypeDescriptor that live instances still
31-
point at. `type_descriptor.zig registerType` keys `rt.types` by the SIMPLE
32-
name, and on re-registration does `fetchRemove(name)` then frees the old
33-
descriptor (each field_layout entry name, the layout slice, fqcn,
34-
defining_ns, method_table entries, protocol_impls, then
35-
`gpa.destroy(old.value)`). Every constructed instance holds
36-
`inst.descriptor` as a raw pointer to it, so `print.zig
37-
printTypedInstance` then reads `field_layout` out of freed memory: the
38-
symptom is `thread panic: integer overflow` (a garbage field index or
39-
layout length), the defect is the free.
40-
Repro (ReleaseSafe v1.14.3): `(ns aaa) (defrecord Point [x y]) (def a
41-
(->Point 1 2)) (ns bbb) (defrecord Point [x y]) (def b (->Point 1 2))
42-
(prn (pr-str aaa/a))` panics; printing `bbb/b` is fine. Variants: two ns
43-
with DIFFERENT names is fine; two ns SAME name panics; SAME ns redefining
44-
the same name panics (this is the ordinary REPL / `require :reload` path
45-
`dev/user.clj` depends on); same name with a different field count panics;
46-
the deftype form raises `WriteFailed` instead, same root.
47-
TWO separable defects: (1) the registry is keyed by simple name, so
48-
`aaa/Point` and `bbb/Point` collide with no redefinition at all (clj gives
49-
each ns its own class); (2) re-registration frees a descriptor live
50-
instances reference.
51-
ADR-0019 forbids a panic on a user-reachable path, and this one is reached
52-
by re-evaluating a defrecord form. It also caps the native-suite migration:
53-
`test/clj/suites/` shares ONE image, so no two suites may define the same
54-
type name (worked around 2026-09-09 by renaming defrecord_test's record to
55-
DPoint; 45 type definitions across 103 suites, no other duplicate today).
56-
Found while migrating phase7_defrecord.sh to a native suite.
57-
Card `[CLJW-TD-UAF]` 20260909211032-6471bc49.
58-
category: "correctness"
59-
quality_floor: "correctness: a user-reachable panic from an ordinary redefine"
60-
barrier: |-
61-
Needs an ADR: the free is deliberate (comments cite row 7.7 cycle 5 and
62-
D-190 / ADR-0068) and exists to avoid leaking on redefine, so removing it
63-
trades the leak back. Candidate shapes: key `rt.types` by the qualified
64-
name when `defining_ns` is present and RETIRE rather than free a replaced
65-
descriptor (a leak bounded by redefinition count, which is what clj does
66-
with the old class), or make descriptors GC-managed so a descriptor dies
67-
only when no instance references it. Devil's-advocate fork is mandatory at
68-
this depth. Not blocked on anything external: the repro is one file and the
69-
owning function is ~70 lines.
70-
last_reviewed: "2026-09-09"
7127
- id: "D-586"
7228
status: |-
7329
open (2026-09-05, ADR-0195 trigger). UPSTREAM: zwasm/D-584. zwasm's JIT
@@ -7583,6 +7539,17 @@ discharged:
75837539
refs: |-
75847540
src/runtime/collection/literal.zig (the one literal construction); src/eval/analyzer/analyzer.zig (the constant fold); src/eval/backend/vm/compiler.zig and vm.zig (the extend opcodes); docs/spec/formats/chunk-v12.edn (bytecode format v12).
75857541
discharged_at: "2026-10-02"
7542+
- id: "D-587"
7543+
status: |-
7544+
DISCHARGED 2026-10-14 by ADR-0198 plus ADR-0201. Both defects the row named are fixed. (1) rt.types is keyed by <defining_ns>.<Name>, so aaa.Point and bbb.Point are two classes (ADR-0198), and a bare constructor binds the class of the namespace its form was analyzed in ([CLJW-CTOR-ANALYZE-TIME]: a ctor site carries definer_ns, bytecode v13), so `aaa/->Point` builds aaa.Point even after bbb registered a namesake. (2) A displaced descriptor is retired, never freed, until Runtime.deinit (ADR-0198; ADR-0201 Part B makes that the one lifetime rule for every user descriptor). ADR-0201 also made membership descriptor identity: instance?, .isInstance, isa? and multimethod dispatch agree with (= (class x) C) for a redefined record, a namesake in another namespace and a reify class. The original repro prints both records and the narrowed redefine on both backends.
7545+
Was: open (2026-09-09), USE-AFTER-FREE, user-reachable panic. Re-registering a deftype/defrecord name freed a TypeDescriptor that live instances still pointed at, and the registry was keyed by the simple name, so two namespaces defining Point collided with no redefinition at all. Symptom `thread panic: integer overflow` from printTypedInstance, or `WriteFailed` for a deftype.
7546+
category: "correctness"
7547+
barrier: |-
7548+
none, discharged. Pinned by test/clj/suites/type_redefine_test.clj (the six scenarios of the former type_descriptor_redefinition e2e, incl. 3000 redefinitions interleaved with reify under a forced collection and the defining-namespace ctor binding), test/clj/suites/user_class_identity_test.clj, the type_redefinition diff corpus, and the class_name.zig / analyzer.zig unit tests. Still open and separate: rt.types_by_simple still exists for the bare-name paths that are not ctor sites (card 20260909231443-1ba4303c), and D-574 (reify mints a descriptor per evaluation).
7549+
last_reviewed: "2026-10-14"
7550+
refs: |-
7551+
ADR-0198, ADR-0201; src/runtime/type_descriptor.zig (registerType retires), src/runtime/class_name.zig (isInstanceOfClass, classIsaOf, descriptorIsa), src/eval/analyzer/special_forms.zig (constructInstance definer_ns lookup), docs/spec/formats/chunk-v13.edn.
7552+
discharged_at: "2026-10-14"
75867553
conventions: |-
75877554
- Category vocabulary is a closed set (guarded by scripts/check_debt_category.sh; synonyms were normalized 2026-10-08: structural->structure, tests/test->testing, numerics->numeric, performance->perf). Allowed: app backend bench bootstrap build clj-parity concurrency correctness debt-hygiene demo discipline distribution docs docs-onboarding ecosystem error-system eval eval-semantics feature gc governance host-surface infra interop isolation license macro meta-reorg missing-ns namespace numeric perf polymorphism process project-flow reader refactor regex robustness runtime scope security structure testing tooling wasm. A new category is added here first, in the same commit as the row that needs it.
75887555
- Structure: two top-level lists — `active:` and `discharged:`. Active entries carry id / status / category / barrier (+ optional quality_floor / last_reviewed); discharged entries carry id / discharged_at / resolution. Edit as YAML (no Markdown table to align).

‎CHANGELOG.md‎

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,51 @@ first stable `1.0.0` tag; pre-1.0 `alpha` / `rc` tags may still change surfaces.
77

88
## [Unreleased]
99

10+
## [1.15.1] - 2026-10-21
11+
12+
### Added
13+
14+
- **`wasm/exports` lists a core module's exports.** `(wasm/exports m)` returns
15+
a vector in export order: a function as `{:name "sum_f64" :kind :func
16+
:params [:i32 :i32] :results [:f64]}`, a memory, global or table as
17+
`{:name "memory" :kind :memory}`. Signatures come from the same runtime probe
18+
`wasm/call` uses (ADR-0203).
19+
20+
- **Dot interop on a Wasm module handle.** `(.sum_f64 m buf 4)`,
21+
`(. m sum_f64 buf 4)` and `(. m (sum_f64 buf 4))` call the export named by
22+
the method symbol, verbatim, through `wasm/call`'s own path, so results,
23+
fuel and errors are identical. A C function compiled to Wasm is called like a
24+
host method (ADR-0203).
25+
26+
### Changed
27+
28+
- **zwasm pinned to the fork's `main` (d74e63b4, upstream main of
29+
2026-10-21).** Upstream now carries the component re-export, wasip2
30+
`metadata-hash` and `PreparedWasi` fixes the fork's `cljw` branch existed
31+
for.
32+
33+
- **A shorter README** led by calling C from Clojure, with the architecture,
34+
size and startup charts kept.
35+
36+
### Fixed
37+
38+
- **Redefining a deftype or defrecord is safe, and a user class is matched by
39+
identity, not by name.** Re-registering a type no longer frees a descriptor
40+
live instances still use (the `thread panic: integer overflow` on printing
41+
an old instance is gone). `aaa.Point` and `bbb.Point` are two classes, and
42+
`instance?`, `.isInstance`, class `isa?` and multimethod dispatch agree with
43+
`(= (class x) C)` for a redefined record, a namesake in another namespace
44+
and a reify class. A bare `(Point. x y)` or `->Point` builds the class of the
45+
namespace the form was written in, even after another namespace registered a
46+
namesake of a different shape. Compiled chunks move to format v13.
47+
48+
- **The VM reports errors at their form.** `set!` on an unbound var, an
49+
unresolved or unsupported `.member` call, a static method call, a
50+
constructor arity failure, `import` and `require`/`refer` failures raised on
51+
the VM with no source position (`0:0`) while TreeWalk reported line and
52+
column. Both backends now report the same position, and the dual-backend
53+
test oracle checks it for every failing case.
54+
1055
## [1.15.0] - 2026-10-13
1156

1257
### Added

0 commit comments

Comments
 (0)