#265 asdf load-system crashes mid-load of alexandria (functions→lists boundary): 'not a function' / SIGSEGV
closedAfter explicit (asdf::load-asd alexandria.asd) + (asdf:load-system "alexandria"), asdf's perform path DOES load alexandria's component files in serial order (package, definitions, … functions) — CURRY/RCURRY/NAMED-LAMBDA all process — then crashes at the functions.lisp→lists.lisp boundary.
- Instrumented binary: ; Error: attempt to call an object that is not a function | in: LOAD-SYSTEM
- Clean binary: SIGSEGV (same bug — funcall on a garbage/non-function pointer; sometimes caught, sometimes crashes)
Note: alexandria loads CLEAN via compat/alexandria/load-all.lisp (plain load, per project memory). So the delta is asdf's perform/operate wrapper, not alexandria's source. lists.lisp opens with in-package, declaim inline, defun safe-endp (endp), alist-plist (dolist/push/nreverse), then a big macrolet with define-setf-expander/with-unique-names/get-setf-expansion.
Next: gdb backtrace of the SIGSEGV (JIT .eh_frame walkable), or bisect which form under asdf perform funcalls a non-function. Likely an asdf hook / mini-clos generic (perform / around-compile) resolving to a non-function between files.
Comments (4)
PROGRESS (2026-07-09) — partial fix landed in working tree; error count 36→24; alexandria now FUNCTIONALLY loads+runs.
FIX #1 (verified, in tree, compat/alexandria/types.lisp): the frob macrolet's (setf (values negative-extremum …) (ecase …)) rewritten to an equivalent (multiple-value-bind (…) (ecase …) …). (setf (values …)) routed to a nonexistent SETF-VALUES place → frob's expander bailed to the tree-walker (format-symbol garbage names). After the rewrite: frob stays on the hosted path (0 MACROEVAL-PASSTHRU in types), the type PREDICATES now generate (find-symbol NEGATIVE-FIXNUM-P ALEXANDRIA => T), and F1-7+types.lisp loads 100% CLEAN (0 errors). Portable, semantics-preserving (vars assigned once then only read). VERIFY: full load-all 36→24 errors; (alexandria:flatten '(1 (2 3) 4))=>(1 2 3 4), (iota 4)=>(0 1 2 3), (lastcar '(7 8 9))=>9 all correct.
REMAINING 24 errors = a SECOND, distinct bug (deferring):
- 12 in %DEFTYPE-REGISTER, ~12 in DEFUN, all for the real/rational/float subtypes frob generates (NEGATIVE-REAL etc.). fixnum/integer subtypes succeed.
- STATE-DEPENDENT: F1-7+types = 0 errors; F1-11+types = 24 errors. The ONLY delta is loading hash-tables/control-flow/functions/lists (files 8-11) BEFORE types. Same frob, same format-symbol names.
- NOT GC: F1-11+types with an 8GiB no-GC window ((gc-stress 8589934592)) = identical 24. NOT a tree-walker bail: 0 MACROEVAL-PASSTHRU in types. NOT asdf.
- So it is accumulated-compiler-state corruption of the deftype/defun NAME path that only bites once files 8-11 have grown the state — a scale-triggered 'not a byte-vector' in the symbol-name/quote-pool/fn-table machinery (cave#260-adjacent but GC-ruled-out). RED HERRING ruled out: format-symbol/format-nil return a non-byte-vector in BOTH F1-7 and F1-11 (funcl strings simply aren't byte-vectors), so that is not the discriminator. NEXT: watchpoint/bisect the state-dependent corruption — what files 8-11 push into the compiler alists that later makes a types.lisp deftype/defun NAME read as a non-bv. Also independent: 53 benign %SETF-SYMBOL hosted-bails (setf-on-user-place macros) — tree-walker handles them fine (0 errors from them); a %SETF-SYMBOL runtime twin (defun %setf-symbol (s) (ag-make-setf-symbol s)) would remove them but is unproven (needs build+fixture gate) and does NOT address the 24.
MAJOR UPDATE (2026-07-09): alexandria now LOADS AND RUNS correctly via funcl. The 24 remaining errors are NON-FATAL.
With the mvb fix (types.lisp frob), full (load compat/alexandria/load-all.lisp) then a 10-function battery ALL return correct results:
- flatten '(1 (2 3) 4) => (1 2 3 4); iota 4 => (0 1 2 3); lastcar => 9
- (funcall (curry #'+ 10) 5) => 15; hash-table-keys => (1); ensure-list 5 => (5)
- mappend #'list '(1 2) '(3 4) => (1 3 2 4)
- the frob-GENERATED type predicates work: positive-fixnum-p 3 => T, negative-real-p -1.5 => T So the 24 'not a byte-vector' errors during load are redundant/duplicate deftype/defun registrations — they error but do NOT prevent the working definitions.
REMAINING BUG (24 non-fatal errors) — precisely characterized, deferred as a distinct funcl COMPILER bug:
- Trigger: a function that frob's make-docstring flet CALLS (ensure-car) being DEFINED so the call RESOLVES. F1-10+types=0 errors; add (defun ensure-car …)=24. A same-body defun with a NAME frob doesn't call (zzz-dummy-fn) => 0 (frob's ensure-car call stays unresolved). Inlining the call to use car/consp primitives ALSO => 24 (any resolved call from that expander site corrupts).
- So: a RESOLVED function call from frob's hosted-compiled expander (at the make-docstring site, after the name bvs are built) corrupts ~24 of the 36 generated deftype/defun NAME bvs → 'not a byte-vector' at their DEFUN/%DEFTYPE-REGISTER.
- RULED OUT: GC (8GiB no-GC window identical), tree-walker bail (0 MACROEVAL-PASSTHRU), format buffer-sharing ((format nil) returns distinct eq=NIL strings), name-collision with a funcl-internal (none), fn-table size/threshold (dummy defun at same point = 0).
- Likely locus: ag-compile-lambda-impl quote-pool emission / patch-apply interaction — emitting a resolved CALL patch in an expander whose quote pool holds freshly-built name bvs overwrites some of those bvs. Needs a watchpoint on a doomed name-bv address across the expander's ag-emit-quote-pool/ag-patches-apply. NEXT: this compiler bug (own investigation). For the north-star, alexandria is functionally usable now; re-verify the asdf:load-system path (types fix should help it too).
FIXED — root cause was cave#281 (capturing closures were conses; asdf's ensure-function misdispatched every session thunk). Evidence 2026-07-11: (push asdf:central-registry) + (asdf:load-system "alexandria") completes a REAL multi-file component load on build/funcl; (alexandria:flatten '(1 (2) 3)) => (1 2 3); 8/8 breadth probes incl. closure-returning curry/compose. Fix chain: ADR-0028 closure records e17d39b + eql specializers 822a554 + macro-aware eval 0f0eed8 + REPL robustness 21f15f2.
ROOT CAUSE FOUND — and it is NOT asdf and NOT GC. Reframing this issue.
REPRODUCES WITHOUT ASDF: plain (load "compat/alexandria/load-all.lisp") fails identically with 'the value is not a byte-vector | in: DEFUN' (×36). So asdf's perform wrapper is exonerated — the alexandria-scale failure is a compiler bug in loading types.lisp.
GC EXONERATED (cave#260 theory disproven for THIS symptom): loading F1-7 + types.lisp with an 8GiB no-GC window ((gc-stress 8589934592), window never fills so no collection) yields EXACTLY 36 errors — identical to the default-GC run. GC window size makes zero difference. Deterministic, not heap-state-dependent at root (downstream crash LOCATION varies once state is corrupted, but the trigger is deterministic).
DETERMINISTIC MINIMAL REPRO: load alexandria package,definitions,binding,strings,conditions,symbols,macros then types.lisp => 36× 'not a byte-vector in DEFUN'.
MECHANISM: types.lisp:17-105 is a (macrolet ((frob (type ...) ...)) ...) invoked once per numeric type (fixnum integer rational real float short/single/double/long-float = 9 types). Each frob expansion generates 4 predicate defuns (negative-P non-positive-P non-negative-P positive-P) whose NAMES are built by format-symbol (make-subtype-name/make-predicate-name, lines 21-30). 9×4 = 36 = the error count. The frob expander BAILS to the closed tree-walker (360 'MACROEVAL-PASSTHRU NEGATIVE/POSITIVE' on stderr — the cave#161 bail predicate). In the tree-walker, format-symbol yields a non-byte-vector (garbage / format's SIMPLE-VECTOR scratch, cave#253 family), so each generated (defun ...) has a non-bv name => 'not a byte-vector in DEFUN'. The 36 predicate defuns never get defined; downstream files referencing them then fail/crash/hang (the varying secondary symptom).
This is the hosted-vs-tree-walker macro-expansion fault line (funcl 'two macro-expansion paths'): frob is a sophisticated format-symbol code generator the closed tree-walker can't run. FIX OPTIONS: (1) fix the cave#161 bail predicate so frob's expander COMPILES instead of bailing; (2) make format-symbol return a real SIMPLE-STRING/bv in the tree-walker path; (3) #+funcl port hunk rewriting types.lisp's frob to avoid the bail. Renaming this issue's scope to the types.lisp frob bail.