The following program segfaults:
let f x =
let rec l =
let v = lazy x in
Gc.minor ();
v
in
l
let lazy_one = f 1
What happens is that lazy x is compiled as (makeforward x), as f could be called with float or lazy arguments (otherwise we would get x directly).
This lures Value_rec_check and Value_rec_compiler into thinking that l will always be a block of size 1 with tag Forward_tag.
However, if a GC runs between the moment the value is allocated and the moment it is used to update the dummy value used for compiling recursive bindings, then if the value turns out to be neither a float nor a lazy the GC will shortcut it, and then we will try to update the dummy block using the integer 1.
I don't have a good idea of how to fix that. I think that we could update the environments used in Value_rec_check and Value_rec_compiler to either not consider forward blocks as having a static size (easier to do but may introduce regressions), or to clear the static sizes of forward blocks whenever a non-trivial expression is encountered.
As I said in #13919, I also think that we could completely remove the lazy optimisations from this part of the compiler, making Value_rec_check and Value_rec_compiler simpler, and instead implement them in the backends (or in Simplif, if we don't want to duplicate the implementation).
The following program segfaults:
What happens is that
lazy xis compiled as(makeforward x), asfcould be called with float or lazy arguments (otherwise we would getxdirectly).This lures
Value_rec_checkandValue_rec_compilerinto thinking thatlwill always be a block of size 1 with tagForward_tag.However, if a GC runs between the moment the value is allocated and the moment it is used to update the dummy value used for compiling recursive bindings, then if the value turns out to be neither a float nor a lazy the GC will shortcut it, and then we will try to update the dummy block using the integer 1.
I don't have a good idea of how to fix that. I think that we could update the environments used in
Value_rec_checkandValue_rec_compilerto either not consider forward blocks as having a static size (easier to do but may introduce regressions), or to clear the static sizes of forward blocks whenever a non-trivial expression is encountered.As I said in #13919, I also think that we could completely remove the lazy optimisations from this part of the compiler, making
Value_rec_checkandValue_rec_compilersimpler, and instead implement them in the backends (or inSimplif, if we don't want to duplicate the implementation).