From 83be441d3fd776dc23d6fba820f1b75d43d8cb12 Mon Sep 17 00:00:00 2001 From: Stefano Zacchiroli Date: Mon, 30 Mar 2015 16:10:58 +0200 Subject: [PATCH] Cudf_parser.from_file: prevent transient in_channel leaks 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 --- cudf_parser.ml | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/cudf_parser.ml b/cudf_parser.ml index 48d7ecd..5b4e966 100644 --- a/cudf_parser.ml +++ b/cudf_parser.ml @@ -1,6 +1,6 @@ (*****************************************************************************) (* libCUDF - CUDF (Common Upgrade Description Format) manipulation library *) -(* Copyright (C) 2009-2012 Stefano Zacchiroli *) +(* Copyright (C) 2009-2015 Stefano Zacchiroli *) (* *) (* This library is free software: you can redistribute it and/or modify *) (* it under the terms of the GNU Lesser General Public License as *) @@ -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 @@ -31,6 +35,7 @@ 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 = @@ -38,18 +43,24 @@ let from_IO_in_channel ?(typedecl=Cudf_conf.stanza_typedecl) ic = { 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