Skip to content

Commit

Permalink
Cudf_parser.from_file: prevent transient in_channel leaks
Browse files Browse the repository at this point in the history
When from_file is used (differently from, e.g., from_in_channel), libcudf is in
charge of creating an in_channel for parsing reasons. Its disposal will be up
to the GC, non deterministically. Hence if from_file is used a lot, and if the
GC kicks in late, users might run out of file descriptors.

With this change Cudf_parser will store internally the in_channel it has open,
if any, and close it upon Cudf_parser.close()

Closes: #18789
Reference: https://gforge.inria.fr/tracker/?func=detail&atid=13811&aid=18789&group_id=4385
  • Loading branch information
zacchiro committed Mar 30, 2015
1 parent 446c5d0 commit 83be441
Showing 1 changed file with 14 additions and 3 deletions.
17 changes: 14 additions & 3 deletions cudf_parser.ml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
(*****************************************************************************)
(* libCUDF - CUDF (Common Upgrade Description Format) manipulation library *)
(* Copyright (C) 2009-2012 Stefano Zacchiroli <[email protected]> *)
(* Copyright (C) 2009-2015 Stefano Zacchiroli <[email protected]> *)
(* *)
(* This library is free software: you can redistribute it and/or modify *)
(* it under the terms of the GNU Lesser General Public License as *)
Expand All @@ -20,6 +20,10 @@ type cudf_parser = {
lexbuf: Lexing.lexbuf ;
fname: string ;
mutable typedecl: Cudf_conf.stanza_typedecl ;
priv_in_chan: in_channel option;
(* in_channel to be closed upon close() invocation, to avoid leaving up to
OCaml GC when to close it. Will be set only if it is Cudf_parser itself
who has created the in_channel, e.g., upon Cudf_parser.from_file *)
}

type loc_map = (string * loc) list
Expand All @@ -31,25 +35,32 @@ let from_in_channel ?(typedecl=Cudf_conf.stanza_typedecl) ic =
{ lexbuf = Lexing.from_channel ic ;
typedecl = typedecl ;
fname = "" ;
priv_in_chan = None ;
}

let from_IO_in_channel ?(typedecl=Cudf_conf.stanza_typedecl) ic =
let f s n = try IO.input ic s 0 n with IO.No_more_input -> 0 in
{ lexbuf = Lexing.from_function f;
typedecl = typedecl ;
fname = "" ;
priv_in_chan = None ;
}

let from_file ?(typedecl=Cudf_conf.stanza_typedecl) fname =
(* Syntax error with OCaml 3.10.2:
* { from_in_channel ?typedecl (open_in fname)
* with fname = fname } *)
{ lexbuf = Lexing.from_channel (open_in fname) ;
let ic = open_in fname in
{ lexbuf = Lexing.from_channel ic ;
typedecl = typedecl ;
fname = fname ;
priv_in_chan = Some ic ;
}

let close p = ()
let close p =
match p.priv_in_chan with
| None -> ()
| Some ic -> close_in ic

let parse_stanza p =
try
Expand Down

0 comments on commit 83be441

Please sign in to comment.