A defer is in the typed IR twice -- spliced into the body for the normal path, and again in fdefers for the path a transfer leaves through -- so a dyn temporary inside one is emitted twice. dyn_roots counted only the body's, and the second copy went into slots nothing had rooted. Nothing failed, and that is the whole reason this is worth a commit of its own. dyn_tmp falls back to a plain slot rather than unbalancing the stack, so the pushes and the pops still matched, the program ran and printed the right answer, and the values were simply invisible. Against a stub that never collects there is no symptom to find -- no leak, no crash, no wrong number. It would have become a symptom the week the real collector landed, in a defer reached only on a handled condition, which is close to the worst place to start looking. What found it was the IR: a rooted slot is spelled %dr and the fallback %dx, and the assertion is that no dyn program in the corpus emits one of the latter. That is now a test over all five dyn programs, and it is the only check in the lane that can see a missing root while there is still nothing to lose one by. When the collector arrives it is the thing to extend rather than replace. Also checked, both clean: flan dev --llvm builds and runs a dyn program, which is the route the x86 refusal sends people to and would have been a link error in the worst possible place; and the daemon's own refusal already names the flag.
29 lines
1.1 KiB
Plaintext
29 lines
1.1 KiB
Plaintext
;;;; A dyn value produced inside a defer, on a function a transfer leaves
|
|
;;;; through rather than returns from.
|
|
;;;;
|
|
;;;; This is here for the root count and not for the arithmetic. A defer appears
|
|
;;;; twice in the typed IR — spliced into the body for the normal path, and
|
|
;;;; again in fdefers for the path a handled condition unwinds along — so the
|
|
;;;; emitter produces two copies of every dyn temporary inside one. Counting
|
|
;;;; only the body left the second copy's temporaries in slots the collector had
|
|
;;;; never been told about: the pushes and the pops still balanced, so nothing
|
|
;;;; failed, and the values were simply invisible.
|
|
;;;;
|
|
;;;; Nothing the stub does can show that, because it never collects. What shows
|
|
;;;; it is the emitted IR — a fallback slot is spelled %dx and a rooted one %dr,
|
|
;;;; and the fix is the absence of the former.
|
|
|
|
(defstruct Boom [n i64])
|
|
|
|
(defn inner [x] dyn
|
|
(defer (print (+ x 1000)) (print "\n"))
|
|
(restart-case
|
|
(error (Boom {.n 1}))
|
|
(give [] 0))
|
|
(+ x 1))
|
|
|
|
(defn main [] ()
|
|
(handler-bind [(Boom [b] (invoke-restart 'give))]
|
|
(print (inner 5))
|
|
(print "\n")))
|