Skip to content

Commit 7309673

Browse files
committed
Runtime: fix memory leak wrt channels
1 parent 950b56a commit 7309673

File tree

5 files changed

+71
-30
lines changed

5 files changed

+71
-30
lines changed

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
## Bug fixes
1010
* Fix small bug in global data flow analysis (#1768)
11+
* Runtime: no longer leak channels
1112

1213
# 5.9.1 (02-12-2024) - Lille
1314

dune-project

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
(depends
2121
(ocaml (and (>= 4.08) (< 5.4)))
2222
(num :with-test)
23-
(ppx_expect (and (>= v0.14.2) :with-test))
23+
(ppx_expect (and (>= v0.16.1) :with-test))
2424
(ppxlib (>= 0.15.0))
2525
(re :with-test)
2626
(cmdliner (>= 1.1.0))

js_of_ocaml-compiler.opam

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ depends: [
1515
"dune" {>= "3.17"}
1616
"ocaml" {>= "4.08" & < "5.4"}
1717
"num" {with-test}
18-
"ppx_expect" {>= "v0.14.2" & with-test}
18+
"ppx_expect" {>= "v0.16.1" & with-test}
1919
"ppxlib" {>= "0.15.0"}
2020
"re" {with-test}
2121
"cmdliner" {>= "1.1.0"}

runtime/js/io.js

Lines changed: 66 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,19 @@ var caml_sys_fds = new Array(3);
2525
//Provides: caml_sys_close
2626
//Requires: caml_sys_fds
2727
function caml_sys_close(fd) {
28-
var file = caml_sys_fds[fd];
29-
if (file) file.close();
30-
delete caml_sys_fds[fd];
28+
var x = caml_sys_fds[fd];
29+
if (x) {
30+
x.file.close();
31+
delete caml_sys_fds[fd];
32+
}
3133
return 0;
3234
}
3335

36+
//Provides: MlChanid
37+
function MlChanid(id) {
38+
this.id = id;
39+
}
40+
3441
//Provides: caml_sys_open
3542
//Requires: caml_raise_sys_error
3643
//Requires: MlFakeFd_out
@@ -39,11 +46,16 @@ function caml_sys_close(fd) {
3946
//Requires: fs_node_supported
4047
//Requires: caml_sys_fds
4148
//Requires: caml_sys_open_for_node
49+
//Requires: MlChanid
4250
function caml_sys_open_internal(file, idx) {
51+
var chanid;
4352
if (idx === undefined) {
4453
idx = caml_sys_fds.length;
45-
}
46-
caml_sys_fds[idx] = file;
54+
chanid = new MlChanid(idx);
55+
} else if (caml_sys_fds[idx]) {
56+
chanid = caml_sys_fds[idx].chanid;
57+
} else chanid = new MlChanid(idx);
58+
caml_sys_fds[idx] = { file: file, chanid: chanid };
4759
return idx | 0;
4860
}
4961
function caml_sys_open(name, flags, _perms) {
@@ -125,41 +137,58 @@ function caml_ml_set_channel_name(chanid, name) {
125137
}
126138

127139
//Provides: caml_ml_channels
128-
var caml_ml_channels = new Array();
140+
//Requires: MlChanid
141+
function caml_ml_channels_state() {
142+
this.map = new globalThis.WeakMap();
143+
this.opened = new globalThis.Set();
144+
}
145+
caml_ml_channels_state.prototype.close = function (chanid) {
146+
this.opened.delete(chanid);
147+
};
148+
caml_ml_channels_state.prototype.get = function (chanid) {
149+
return this.map.get(chanid);
150+
};
151+
caml_ml_channels_state.prototype.set = function (chanid, val) {
152+
if (val.opened) this.opened.add(chanid);
153+
return this.map.set(chanid, val);
154+
};
155+
caml_ml_channels_state.prototype.all = function () {
156+
return this.opened.values();
157+
};
158+
159+
var caml_ml_channels = new caml_ml_channels_state();
160+
161+
//Provides: caml_ml_channel_get
162+
//Requires: caml_ml_channels
163+
function caml_ml_channel_get(id) {
164+
return caml_ml_channels.get(id);
165+
}
129166

130167
//Provides: caml_ml_channel_redirect
131168
//Requires: caml_ml_channel_get, caml_ml_channels
132169
function caml_ml_channel_redirect(captured, into) {
133170
var to_restore = caml_ml_channel_get(captured);
134171
var new_ = caml_ml_channel_get(into);
135-
caml_ml_channels[captured] = new_; // XXX
172+
caml_ml_channels.set(captured, new_);
136173
return to_restore;
137174
}
138175

139176
//Provides: caml_ml_channel_restore
140177
//Requires: caml_ml_channels
141178
function caml_ml_channel_restore(captured, to_restore) {
142-
caml_ml_channels[captured] = to_restore; // XXX
179+
caml_ml_channels.set(captured, to_restore);
143180
return 0;
144181
}
145182

146-
//Provides: caml_ml_channel_get
147-
//Requires: caml_ml_channels
148-
function caml_ml_channel_get(id) {
149-
return caml_ml_channels[id]; // XXX
150-
}
151-
152183
//Provides: caml_ml_out_channels_list
153184
//Requires: caml_ml_channels
185+
//Requires: caml_ml_channel_get
154186
function caml_ml_out_channels_list() {
155187
var l = 0;
156-
for (var c = 0; c < caml_ml_channels.length; c++) {
157-
if (
158-
caml_ml_channels[c] &&
159-
caml_ml_channels[c].opened &&
160-
caml_ml_channels[c].out
161-
)
162-
l = [0, caml_ml_channels[c].fd, l];
188+
var keys = caml_ml_channels.all();
189+
for (var k of keys) {
190+
var chan = caml_ml_channel_get(k);
191+
if (chan.opened && chan.out) l = [0, k, l];
163192
}
164193
return l;
165194
}
@@ -169,7 +198,11 @@ function caml_ml_out_channels_list() {
169198
//Requires: caml_raise_sys_error
170199
//Requires: caml_sys_open
171200
function caml_ml_open_descriptor_out(fd) {
172-
var file = caml_sys_fds[fd];
201+
var fd_desc = caml_sys_fds[fd];
202+
if (fd_desc === undefined)
203+
caml_raise_sys_error("fd " + fd + " doesn't exist");
204+
var file = fd_desc.file;
205+
var chanid = fd_desc.chanid;
173206
if (file.flags.rdonly) caml_raise_sys_error("fd " + fd + " is readonly");
174207
var buffered = file.flags.buffered !== undefined ? file.flags.buffered : 1;
175208
var channel = {
@@ -182,16 +215,20 @@ function caml_ml_open_descriptor_out(fd) {
182215
buffer: new Uint8Array(65536),
183216
buffered: buffered,
184217
};
185-
caml_ml_channels[channel.fd] = channel;
186-
return channel.fd;
218+
caml_ml_channels.set(chanid, channel);
219+
return chanid;
187220
}
188221

189222
//Provides: caml_ml_open_descriptor_in
190223
//Requires: caml_ml_channels, caml_sys_fds
191224
//Requires: caml_raise_sys_error
192225
//Requires: caml_sys_open
193226
function caml_ml_open_descriptor_in(fd) {
194-
var file = caml_sys_fds[fd];
227+
var fd_desc = caml_sys_fds[fd];
228+
if (fd_desc === undefined)
229+
caml_raise_sys_error("fd " + fd + " doesn't exist");
230+
var file = fd_desc.file;
231+
var chanid = fd_desc.chanid;
195232
if (file.flags.wronly) caml_raise_sys_error("fd " + fd + " is writeonly");
196233
var refill = null;
197234
var channel = {
@@ -205,8 +242,8 @@ function caml_ml_open_descriptor_in(fd) {
205242
buffer: new Uint8Array(65536),
206243
refill: refill,
207244
};
208-
caml_ml_channels[channel.fd] = channel;
209-
return channel.fd;
245+
caml_ml_channels.set(chanid, channel);
246+
return chanid;
210247
}
211248

212249
//Provides: caml_ml_open_descriptor_in_with_flags
@@ -253,10 +290,12 @@ function caml_ml_is_binary_mode(chanid) {
253290
//Provides: caml_ml_close_channel
254291
//Requires: caml_ml_flush, caml_ml_channel_get
255292
//Requires: caml_sys_close
293+
//Requires: caml_ml_channels
256294
function caml_ml_close_channel(chanid) {
257295
var chan = caml_ml_channel_get(chanid);
258296
if (chan.opened) {
259297
chan.opened = false;
298+
caml_ml_channels.close(chanid);
260299
caml_sys_close(chan.fd);
261300
chan.fd = -1;
262301
chan.buffer = new Uint8Array(0);

runtime/js/parsing.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ var caml_parser_trace = 0;
2424
//Requires: caml_lex_array, caml_parser_trace,caml_jsstring_of_string
2525
//Requires: caml_ml_output, caml_ml_string_length, caml_string_of_jsbytes
2626
//Requires: caml_jsbytes_of_string, MlBytes
27+
//Requires: caml_sys_fds
2728
function caml_parse_engine(tables, env, cmd, arg) {
2829
var ERRCODE = 256;
2930

@@ -82,7 +83,7 @@ function caml_parse_engine(tables, env, cmd, arg) {
8283

8384
function log(x) {
8485
var s = caml_string_of_jsbytes(x + "\n");
85-
caml_ml_output(2, s, 0, caml_ml_string_length(s));
86+
caml_ml_output(caml_sys_fds[2].chanid, s, 0, caml_ml_string_length(s));
8687
}
8788

8889
function token_name(names, number) {

0 commit comments

Comments
 (0)