Skip to content

Commit

Permalink
Runtime: fix memory leak wrt channels
Browse files Browse the repository at this point in the history
  • Loading branch information
hhugo committed Dec 11, 2024
1 parent 950b56a commit c6a9a8f
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 27 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
* Runtime: fix parsing of unsigned integers (0u2147483648) (#1633, #1666)
* Runtime: fix incorrect pos_in after unmarshalling
* Runtime: make float_of_string stricter (#1609)
* Runtime: no longer leak channels
* Toplevel: fix missing primitives with separate compilation
* Compiler: fix link of packed modules with separate compilation
* Compiler: Fixed the static evaluation of some equalities (#1659)
Expand Down
86 changes: 60 additions & 26 deletions runtime/js/io.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,17 @@ var caml_sys_fds = new Array(3);
//Provides: caml_sys_close
//Requires: caml_sys_fds
function caml_sys_close(fd) {
var file = caml_sys_fds[fd];
if (file) file.close();
var x = caml_sys_fds[fd];
if (x && x.file) x.file.close();
delete caml_sys_fds[fd];
return 0;
}

//Provides: MlChanid
function MlChanid(id) {
this.id = id;
}

//Provides: caml_sys_open
//Requires: caml_raise_sys_error
//Requires: MlFakeFd_out
Expand All @@ -39,11 +44,16 @@ function caml_sys_close(fd) {
//Requires: fs_node_supported
//Requires: caml_sys_fds
//Requires: caml_sys_open_for_node
//Requires: MlChanid
function caml_sys_open_internal(file, idx) {
var chanid;
if (idx === undefined) {
idx = caml_sys_fds.length;
}
caml_sys_fds[idx] = file;
chanid = new MlChanid(idx);
} else if (caml_sys_fds[idx]) {
chanid = caml_sys_fds[idx].chanid;
} else chanid = new MlChanid(idx);
caml_sys_fds[idx] = { file: file, chanid: chanid };
return idx | 0;
}
function caml_sys_open(name, flags, _perms) {
Expand Down Expand Up @@ -125,41 +135,59 @@ function caml_ml_set_channel_name(chanid, name) {
}

//Provides: caml_ml_channels
var caml_ml_channels = new Array();
//Requires: MlChanid
function caml_ml_channels_state() {
this.map = new globalThis.WeakMap();
this.opened = new globalThis.Set();
}
caml_ml_channels_state.prototype.close = function (chanid) {
this.opened.delete(chanid);
};
caml_ml_channels_state.prototype.get = function (chanid) {
return this.map.get(chanid);
};
caml_ml_channels_state.prototype.set = function (chanid, val) {
if (val.opened) this.opened.add(chanid);
return this.map.set(chanid, val);
};
caml_ml_channels_state.prototype.all = function () {
return this.opened.values();
};

var caml_ml_channels = new caml_ml_channels_state();

//Provides: caml_ml_channel_get
//Requires: caml_ml_channels
function caml_ml_channel_get(id) {
return caml_ml_channels.get(id);
}

//Provides: caml_ml_channel_redirect
//Requires: caml_ml_channel_get, caml_ml_channels
function caml_ml_channel_redirect(captured, into) {
var to_restore = caml_ml_channel_get(captured);
var new_ = caml_ml_channel_get(into);
caml_ml_channels[captured] = new_; // XXX
caml_ml_channels.set(captured, new_);
return to_restore;
}

//Provides: caml_ml_channel_restore
//Requires: caml_ml_channels
function caml_ml_channel_restore(captured, to_restore) {
caml_ml_channels[captured] = to_restore; // XXX
caml_ml_channels.set(captured, to_restore);
return 0;
}

//Provides: caml_ml_channel_get
//Requires: caml_ml_channels
function caml_ml_channel_get(id) {
return caml_ml_channels[id]; // XXX
}

//Provides: caml_ml_out_channels_list
//Requires: caml_ml_channels
//Requires: caml_ml_channel_get
//Requires: caml_sys_fds
function caml_ml_out_channels_list() {
var l = 0;
for (var c = 0; c < caml_ml_channels.length; c++) {
if (
caml_ml_channels[c] &&
caml_ml_channels[c].opened &&
caml_ml_channels[c].out
)
l = [0, caml_ml_channels[c].fd, l];
var keys = caml_ml_channels.all();
for (var k of keys) {
var chan = caml_ml_channel_get(k);
if (chan.opened && chan.out) l = [0, k, l];
}
return l;
}
Expand All @@ -169,7 +197,9 @@ function caml_ml_out_channels_list() {
//Requires: caml_raise_sys_error
//Requires: caml_sys_open
function caml_ml_open_descriptor_out(fd) {
var file = caml_sys_fds[fd];
var s = caml_sys_fds[fd],
file = s.file,
chanid = s.chanid;
if (file.flags.rdonly) caml_raise_sys_error("fd " + fd + " is readonly");
var buffered = file.flags.buffered !== undefined ? file.flags.buffered : 1;
var channel = {
Expand All @@ -182,16 +212,18 @@ function caml_ml_open_descriptor_out(fd) {
buffer: new Uint8Array(65536),
buffered: buffered,
};
caml_ml_channels[channel.fd] = channel;
return channel.fd;
caml_ml_channels.set(chanid, channel);
return chanid;
}

//Provides: caml_ml_open_descriptor_in
//Requires: caml_ml_channels, caml_sys_fds
//Requires: caml_raise_sys_error
//Requires: caml_sys_open
function caml_ml_open_descriptor_in(fd) {
var file = caml_sys_fds[fd];
var s = caml_sys_fds[fd],
file = s.file,
chanid = s.chanid;
if (file.flags.wronly) caml_raise_sys_error("fd " + fd + " is writeonly");
var refill = null;
var channel = {
Expand All @@ -205,8 +237,8 @@ function caml_ml_open_descriptor_in(fd) {
buffer: new Uint8Array(65536),
refill: refill,
};
caml_ml_channels[channel.fd] = channel;
return channel.fd;
caml_ml_channels.set(chanid, channel);
return chanid;
}

//Provides: caml_ml_open_descriptor_in_with_flags
Expand Down Expand Up @@ -253,10 +285,12 @@ function caml_ml_is_binary_mode(chanid) {
//Provides: caml_ml_close_channel
//Requires: caml_ml_flush, caml_ml_channel_get
//Requires: caml_sys_close
//Requires: caml_ml_channels
function caml_ml_close_channel(chanid) {
var chan = caml_ml_channel_get(chanid);
if (chan.opened) {
chan.opened = false;
caml_ml_channels.close(chanid);
caml_sys_close(chan.fd);
chan.fd = -1;
chan.buffer = new Uint8Array(0);
Expand Down
3 changes: 2 additions & 1 deletion runtime/js/parsing.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ var caml_parser_trace = 0;
//Requires: caml_lex_array, caml_parser_trace,caml_jsstring_of_string
//Requires: caml_ml_output, caml_ml_string_length, caml_string_of_jsbytes
//Requires: caml_jsbytes_of_string, MlBytes
//Requires: caml_sys_fds
function caml_parse_engine(tables, env, cmd, arg) {
var ERRCODE = 256;

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

function log(x) {
var s = caml_string_of_jsbytes(x + "\n");
caml_ml_output(2, s, 0, caml_ml_string_length(s));
caml_ml_output(caml_sys_fds[2].chanid, s, 0, caml_ml_string_length(s));
}

function token_name(names, number) {
Expand Down

0 comments on commit c6a9a8f

Please sign in to comment.