;;;; The allocation registry — NEXT.md, "a dev-build allocation registry". ;;;; ;;;; A Flan struct is exactly its C layout with no header and no tag word, so ;;;; nothing at run time can say what is at an address. The registry sidesteps ;;;; that: the allocator's *caller* knew the type, and a dev build writes it ;;;; down. What is asserted here is the consequence a program can see without ;;;; an inspector — whether an address is still live — and the two ways ;;;; storage dies underneath one. ;;;; ;;;; This program is deliberately readable in a release build too, and prints ;;;; a different and equally correct answer there: nothing is recorded, so ;;;; every question about an address comes back 0. The two expectations sit ;;;; side by side in the acceptance table, which is the honest way to assert ;;;; "a release build carries none of it". (declare-c reg-on [] i32 "flan_dev_reg_enabled") (declare-c reg-live [p (Ptr i32)] i32 "flan_dev_reg_live") (declare-c reg-count [live i32] i64 "flan_dev_reg_count") (defvar frame Allocator) (defn main [] i32 ;; Armed by a constructor in a dev build and never in a release one. (println (reg-on)) ;; 1. The heap tier. A pointer into a Vec's storage is live while the Vec is, ;; and the free that releases it is seen — which is the whole of "use ;; after free that names what died", minus the naming, which needs the ;; inspector to read it back. (let [v (vec-new i32)] (push v 7) (push v 8) (let [p (addr (at v 1))] (println (reg-live p)) ; dev: 1 (free v) (println (reg-live p)))) ; 0 either way ;; 2. The arena tier, and the hole test_valgrind.ml measures. free-all is ;; retain-capacity: the pages stay mapped and the bytes stay readable, so ;; memcheck is never told anything died and a later read of stale bytes ;; goes unnoticed. This does not tell memcheck. It tells the registry, so ;; that the same read is at least *answerable*. (set frame (arena-new 4096)) (let [w (vec-new i32 frame)] (push w 3) (let [q (addr (at w 0))] (println (reg-live q)) ; dev: 1 (free-all frame) (println (reg-live q)))) ; 0 either way ;; Nothing is live by now except whatever the arena's own destroy leaves, so ;; the count is a statement about the table rather than about one address. (arena-destroy frame) (println (reg-count 1)) ; 0 either way 0)