53 lines
1.9 KiB
Plaintext
53 lines
1.9 KiB
Plaintext
;;;; 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.
|
|
;;;;
|
|
;;;; 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 [string]] 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))))
|
|
(= 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)
|