Skip to content

Commit 849dea9

Browse files
committed
Plug compiler generated space leaks in Bundle
The lifetime of bindings referenced by a closure in OCaml may be incorrectly extended as a reference to the closure record is kept alive for too long. These changes work around that compiler bug by calling a non-inlined function at the start of the closure, which forces the compiler to generate code to extract all the bindings from the closure record and turn them into ordinary bindings.
1 parent a5e27af commit 849dea9

File tree

1 file changed

+15
-31
lines changed

1 file changed

+15
-31
lines changed

lib/picos_std.structured/bundle.ml

Lines changed: 15 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,11 @@ let[@inline never] returned value child t canceler =
150150
Computation.return child value;
151151
finish t canceler
152152

153+
let[@inline never] plug t thunk child canceler =
154+
match thunk () with
155+
| value -> returned value child t canceler
156+
| exception exn -> raised exn child t canceler
157+
153158
let fork_as_promise_pass (type a) (Bundle r as t : t) thunk (pass : a pass) =
154159
(* The sequence of operations below ensures that nothing is leaked. *)
155160
incr t Backoff.default;
@@ -160,19 +165,10 @@ let fork_as_promise_pass (type a) (Bundle r as t : t) thunk (pass : a pass) =
160165
let canceler = Computation.attach_canceler ~from:bundle ~into:child in
161166
let main =
162167
match pass with
163-
| FLS -> begin
168+
| FLS ->
164169
Fiber.FLS.set fiber flock_key t;
165-
fun fiber ->
166-
match thunk () with
167-
| value -> returned value child (get_flock fiber) canceler
168-
| exception exn -> raised exn child (get_flock fiber) canceler
169-
end
170-
| Arg -> begin
171-
fun _ ->
172-
match thunk () with
173-
| value -> returned value child t canceler
174-
| exception exn -> raised exn child t canceler
175-
end
170+
fun fiber -> plug (get_flock fiber) thunk child canceler
171+
| Arg -> fun _ -> plug t thunk child canceler
176172
in
177173
Fiber.spawn fiber main;
178174
child
@@ -183,36 +179,24 @@ let fork_as_promise_pass (type a) (Bundle r as t : t) thunk (pass : a pass) =
183179
decr t;
184180
raise canceled_exn
185181

186-
let[@inline never] raised_flock exn fiber =
187-
let t = get_flock fiber in
188-
let bt = Printexc.get_raw_backtrace () in
189-
error t exn bt;
190-
decr t
191-
192-
let[@inline never] raised_bundle exn t =
182+
let[@inline never] raised exn t =
193183
error t exn (Printexc.get_raw_backtrace ());
194184
decr t
195185

186+
let[@inline never] plug t thunk =
187+
match thunk () with () -> decr t | exception exn -> raised exn t
188+
196189
let fork_pass (type a) (Bundle r as t : t) thunk (pass : a pass) =
197190
(* The sequence of operations below ensures that nothing is leaked. *)
198191
incr t Backoff.default;
199192
try
200193
let fiber = Fiber.create_packed ~forbid:false r.bundle in
201194
let main =
202195
match pass with
203-
| FLS -> begin
196+
| FLS ->
204197
Fiber.FLS.set fiber flock_key t;
205-
fun fiber ->
206-
match thunk () with
207-
| () -> decr (get_flock fiber)
208-
| exception exn -> raised_flock exn fiber
209-
end
210-
| Arg -> begin
211-
fun _ ->
212-
match thunk () with
213-
| () -> decr t
214-
| exception exn -> raised_bundle exn t
215-
end
198+
fun fiber -> plug (get_flock fiber) thunk
199+
| Arg -> fun _ -> plug t thunk
216200
in
217201
Fiber.spawn fiber main
218202
with canceled_exn ->

0 commit comments

Comments
 (0)