|
24 | 24 | # md-table-align no longer pads it to ~800 KB of whitespace. |
25 | 25 |
|
26 | 26 | 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" |
71 | 27 | - id: "D-586" |
72 | 28 | status: |- |
73 | 29 | open (2026-09-05, ADR-0195 trigger). UPSTREAM: zwasm/D-584. zwasm's JIT |
@@ -7583,6 +7539,17 @@ discharged: |
7583 | 7539 | refs: |- |
7584 | 7540 | 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). |
7585 | 7541 | 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" |
7586 | 7553 | conventions: |- |
7587 | 7554 | - 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. |
7588 | 7555 | - 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). |
|
0 commit comments