|Anonymous | Login | Signup for a new account||2017-02-23 21:46 CET|
|Main | My View | View Issues | Change Log | Roadmap|
|View Issue Details|
|ID||Project||Category||View Status||Date Submitted||Last Update|
|0006119||OCaml||-OCaml general||public||2013-08-05 18:05||2015-12-11 19:26|
|Target Version||4.01.1+dev||Fixed in Version||4.02.0+dev|
|Summary||0006119: wrong sharing of data between closures in bytecode|
|Description||When two functions share a reference, but are in two different files, the serialization of the two closures through the Marshal library is ok in native code but give a wrong execution in bytecode!!!|
It seems that data sharing fails in bytecode, and that the virtual machine sees two separate references instead of one.
In the attached example, the first file defines:
let x = ref 0
let set = fun v -> x := v; printf "set x = %d@." !x
the second files defines:
let print = fun () -> printf "x = %d@." !x
and test the behavior of the two function before and afer marshalling :
type t = int ref * (int -> unit) * (unit -> unit)
let y:t = x, set, print
let test1 = print(); set 3; print ()
let test2 =
printf "after marshall/unmarshall@.";
let marshall = Marshal.to_string y [Marshal.Closures] in
let ((x, set, print) : t) = Marshal.from_string marshall 0 in
print (); set 42; print ()
Behavior of test1 and test2 should be identical. It is the case in native code, but not in bytecode, as if option Marshal.No_sharing was activated.
|Steps To Reproduce||- unzip attached file|
- "ocamlbuild bugMarshalClosure.native--" to check that execution is correct
- "ocamlbuild bugMarshalClosure.byte --" to see the bug : x = 3 instead of 42 when calling the unmarshalled set/print functions.
|Tags||No tags attached.|
|Attached Files||bugMarshalClosure.zip [^] (571 bytes) 2013-08-05 18:05|
edited on: 2013-08-06 12:40
I could reproduce the bug. It seems to be essential that [print] and [x] are defined in distinct modules. An [x] defined in the same module is marshalled correctly.
Acutally, I'm not sure whether this is a bug, but it's certainly an inconsistency.
I used plain ocamlc to build in order to exclude any influence of ocamlbuild.
edited on: 2013-10-14 17:54
Indeed, serialization of toplevel reference is unspecified. Changing this behaviour is probably a big change and I'm not sure it is worth.
What happens here, is that the closure representing 'set' in bytecode captures the references in its environment. While, the closure representing 'set' in native code and the 'print' closure in both byte- and native code make a direct access the global value in the BugClosure_lib module.
Hence, in bytecode, the unmarshalled 'x' value and 'set' function share the same reference (the marshalled one), while 'print' accesses the global value. In native code, the 'set' and 'print' access the global value, while the unmarshalled 'x' is copy of the global reference. Just add the following at the end of your example program to see the distinction:
printf "x = %d@." !BugClosure_lib.x;
printf "x = %d@." !x
Currently, in order to preserve consistency between bytecode and native code w.r.t to toplevel reference serialization, a workaround is to define toplevel references in a first module and define all functions using the reference on others modules. But this way, you will share the reference between the unmarshalled function and the original one.
If you really want to duplicate the reference, a workaround is to use local reference. That way you will always be consistent between byte- and native code:
let set, print =
let x = ref 0 in
let set = fun v -> x := v; printf "set x = %d@." !x
and print = fun () -> printf "x = %d@." !x in
To be certain that all the marshalled function share the same 'local' reference they all should be defined at once. Otherwise, I think the behaviour is also unspecified.
I'm not sure what to do to fix this bug report.
My wish would be that an error is raised in the Marshall library when such a case is encountered.
If it is not possible, at least, enhance the documentation of the Marshall library.
|The documentation for Marshal has been extended to explain this behavior (commit 14670 on trunk). Comments on the text are welcome.|
|2013-08-05 18:05||daweil||New Issue|
|2013-08-05 18:05||daweil||File Added: bugMarshalClosure.zip|
|2013-08-06 12:28||gerd||Note Added: 0010125|
|2013-08-06 12:40||gerd||Note Edited: 0010125||View Revisions|
|2013-08-19 17:13||doligez||Status||new => acknowledged|
|2013-08-19 17:13||doligez||Category||OCaml runtime system => OCaml general|
|2013-08-19 17:13||doligez||Target Version||=> 4.01.1+dev|
|2013-10-14 17:46||hnrgrgr||Note Added: 0010478|
|2013-10-14 17:54||hnrgrgr||Note Edited: 0010478||View Revisions|
|2013-10-14 20:33||daweil||Note Added: 0010482|
|2014-04-23 18:04||frisch||Note Added: 0011316|
|2014-04-23 18:04||frisch||Status||acknowledged => resolved|
|2014-04-23 18:04||frisch||Fixed in Version||=> 4.02.0+dev|
|2014-04-23 18:04||frisch||Resolution||open => fixed|
|2014-04-23 18:04||frisch||Assigned To||=> frisch|
|2015-12-11 19:26||xleroy||Status||resolved => closed|
|2017-02-23 16:36||doligez||Category||OCaml general => -OCaml general|
|Copyright © 2000 - 2011 MantisBT Group|