Skip to content

Commit f2c5a85

Browse files
committed
Bugfix for Comballoc with local allocations. (oxcaml#41)
It is incorrect to combine two local allocations that straddle a heap allocation, as the GC traverses the local allocations looking for roots and must not see uninitialised local data.
1 parent 83bcd09 commit f2c5a85

3 files changed

Lines changed: 51 additions & 32 deletions

File tree

asmcomp/comballoc.ml

Lines changed: 22 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -20,64 +20,54 @@ open Mach
2020
type pending_alloc =
2121
{ reg: Reg.t; (* register holding the result of the last allocation *)
2222
dbginfos: Debuginfo.alloc_dbginfo; (* debug info for each pending alloc *)
23-
totalsz: int } (* amount to be allocated in this block *)
23+
totalsz: int; (* amount to be allocated in this block *)
24+
mode: Lambda.alloc_mode } (* heap or stack allocation *)
2425

25-
type mode_allocation_state =
26+
type allocation_state =
2627
No_alloc
2728
| Pending_alloc of pending_alloc
2829

29-
type allocation_state =
30-
{ heap: mode_allocation_state; local: mode_allocation_state }
31-
32-
let get_mode (m : Lambda.alloc_mode) s =
33-
match m with
34-
| Alloc_heap -> s.heap
35-
| Alloc_local -> s.local
36-
37-
let set_mode (m : Lambda.alloc_mode) s x =
38-
match m with
39-
| Alloc_heap -> { s with heap = x }
40-
| Alloc_local -> { s with local = x }
41-
4230
let rec combine i allocstate =
4331
match i.desc with
4432
Iend | Ireturn | Iexit _ | Iraise _ ->
4533
(i, allocstate)
4634
| Iop(Ialloc { bytes = sz; dbginfo; mode }) ->
4735
assert (List.length dbginfo = 1);
48-
begin match get_mode mode allocstate with
49-
| Pending_alloc {reg; dbginfos; totalsz}
50-
when (totalsz + sz <= (Config.max_young_wosize + 1) * Arch.size_addr)
51-
|| mode = Lambda.Alloc_local ->
36+
begin match allocstate with
37+
| Pending_alloc {reg; dbginfos; totalsz; mode = prev_mode}
38+
when (mode = prev_mode) &&
39+
((totalsz + sz <= (Config.max_young_wosize + 1) * Arch.size_addr)
40+
|| mode = Lambda.Alloc_local) ->
5241
let (next, state) =
5342
combine i.next
54-
(set_mode mode allocstate
55-
(Pending_alloc { reg = i.res.(0);
56-
dbginfos = dbginfo @ dbginfos;
57-
totalsz = totalsz + sz })) in
43+
(Pending_alloc { reg = i.res.(0);
44+
dbginfos = dbginfo @ dbginfos;
45+
totalsz = totalsz + sz;
46+
mode }) in
5847
(instr_cons_debug (Iop(Iintop_imm(Iadd, -sz)))
5948
[| reg |] i.res i.dbg next,
6049
state)
6150
| No_alloc | Pending_alloc _ ->
6251
let (next, state) =
6352
combine i.next
64-
(set_mode mode allocstate
65-
(Pending_alloc { reg = i.res.(0);
66-
dbginfos = dbginfo;
67-
totalsz = sz })) in
53+
(Pending_alloc { reg = i.res.(0);
54+
dbginfos = dbginfo;
55+
totalsz = sz;
56+
mode }) in
6857
let totalsz, dbginfo =
69-
match get_mode mode state with
58+
match state with
7059
| No_alloc -> assert false
71-
| Pending_alloc { totalsz; dbginfos; _ } -> totalsz, dbginfos in
60+
| Pending_alloc { totalsz; dbginfos; mode = m; _ } ->
61+
assert (m = mode);
62+
totalsz, dbginfos in
7263
let next =
7364
let offset = totalsz - sz in
7465
if offset = 0 then next
7566
else instr_cons_debug (Iop(Iintop_imm(Iadd, offset))) i.res
7667
i.res i.dbg next
7768
in
78-
let rstate = set_mode mode state (get_mode mode allocstate) in
7969
(instr_cons_debug (Iop(Ialloc {bytes = totalsz; dbginfo; mode}))
80-
i.arg i.res i.dbg next, rstate)
70+
i.arg i.res i.dbg next, allocstate)
8171
end
8272
| Iop(Icall_ind | Icall_imm _ | Iextcall _ |
8373
Itailcall_ind | Itailcall_imm _) ->
@@ -112,7 +102,7 @@ let rec combine i allocstate =
112102
(instr_cons (Itrywith(newbody, newhandler)) i.arg i.res newnext, s')
113103

114104
and combine_restart i =
115-
let (newi, _) = combine i {local=No_alloc; heap=No_alloc} in newi
105+
let (newi, _) = combine i No_alloc in newi
116106

117107
let fundecl f =
118108
{f with fun_body = combine_restart f.fun_body}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
(* TEST *)
2+
let glob = ref []
3+
4+
let[@inline never] f g n =
5+
let a = local_ [n] in
6+
let b = [n+1] in
7+
let c = local_ [n+2] in
8+
glob := b;
9+
g a c;
10+
()
11+
12+
type junk = { a : float; b : float; c : float; d : float; e : float; f : float }
13+
let[@inline never] clear g n =
14+
let junk = local_ {a=n;b=n;c=n;d=n;e=n;f=n} in
15+
g junk;
16+
()
17+
18+
(* As a header, this looks like tag 0 and marked,
19+
while as a value it's (probably) an invalid pointer *)
20+
let ones = Int64.float_of_bits 0x3FFF_FF00_FFFF_FF00L
21+
let () =
22+
for i = 1 to 1_000_000 do
23+
clear (fun _ -> ()) ones;
24+
f (fun _ _ -> ()) 42
25+
done;
26+
print_endline "ok"
27+
28+
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ok

0 commit comments

Comments
 (0)