;;;; stale-region.flan's trap, reached through arena-destroy rather than ;;;; free-all. The difference is what the check reads: free-all keeps the ;;;; allocator and bumps its epoch, while arena-destroy hands the arena back, ;;;; and a container made from it still points at the allocator to read the ;;;; epoch from. The allocator therefore outlives its arena, so that read is of ;;;; memory that is still there and the trap names the site. ;;;; ;;;; Argument 1 is the other use of a destroyed arena: a new container made ;;;; from it, which has no stale epoch to catch and reaches the allocator ;;;; itself. ;;;; ;;;; Argument 2 is a destroyed allocator taken back by the next arena-new. The ;;;; container made before the destroy still traps, because the epoch on a ;;;; header only ever rises. ;;;; ;;;; Arguments 4, 5 and 6 use the destroyed Allocator value itself after the ;;;; next arena-new took its record back — for a new container, through ;;;; with-allocator, and in a second destroy. The value carries the incarnation ;;;; it was made for, so each traps instead of reaching the new arena. ;;;; ;;;; Argument 3 makes and destroys arenas in a loop, as many times as the ;;;; second argument says. A retired allocator is reused rather than kept, so ;;;; the loop's memory stays flat however long it runs. (defn main [args [str]] i32 (let [which (if (> (length args) 1) (i32 (bytes->i64 (bytes-view (at args 1)))) 0) a (arena-new 4096)] (cond (= which 1) (do (arena-destroy a) (let [w (vec-new i32 a)] (push w 1) (println (length w)))) (= which 2) (let [v (vec-new i32 a)] (push v 1) (arena-destroy a) (let [b (arena-new 4096) w (vec-new i32 b)] (push w 5) (println (at w 0)) (println (at v 0)))) ;; The Allocator value itself, kept past its destroy, after arena-new ;; took its record back: b works, and a traps rather than naming b's ;; arena. Argument 5 is the same through with-allocator, and 6 through ;; a second arena-destroy. (>= which 4) (do (arena-destroy a) (let [b (arena-new 4096) w (vec-new i32 b)] (push w 5) (println (at w 0)) (cond (= which 4) (let [x (vec-new i32 a)] (push x 1)) (= which 5) (with-allocator a (let [x (vec-new i32)] (push x 1))) :else (arena-destroy a)) (println "unreachable"))) (= which 3) (let [n (bytes->i64 (bytes-view (at args 2)))] (arena-destroy a) (dotimes [i (i32 n)] (let [b (arena-new 64)] (arena-destroy b))) (println "done")) :else (let [v (vec-new i32 a)] (push v 1) (push v 2) (println (at v 1)) (arena-destroy a) (println (at v 1))))) 0)