Skip to content

Unsound classification of lazy expressions under excessive unboxed constructor nesting #13928

Description

@lthls

I found a bug while looking at #13919 around the compilation of lazy expressions involving unboxed types nested excessively.
Here is a repro:

module type T = sig type t val mk : unit -> t end
module F (X : T) = struct type t = { x : X.t } [@@unboxed] let mk () = { x = X.mk () } end
module F10 (X : T) = F(F(F(F(F(F(F(F(F(F(X))))))))))
module F100 (X : T) = F10(F10(F10(F10(F10(F10(F10(F10(F10(F10(X))))))))))

module B = struct type t = float let mk () = 0. end
module M = F(F100(B))

let x = M.mk ()
let y = lazy x
let a = Array.make 10 y
let z = Lazy.force a.(0)

The issue is that when trying to see if lazy x can be compiled as x or needs to be a (makeforward x), we look at the runtime representation of x given by its type, which has to expand unboxed types. Since it is possible to create recursive unboxed types, this process might not terminate, so we limit the amount of expansions to a very large but finite amount (100 in practice). But when this expansion fails, instead of propagating this all the way to let the classification treat the value as an unknown type, we revert to the initial (unboxed) type and pretend it behaves as a regular (boxed) variant or record type. In the example this means that we assume that x cannot have a lazy or float tag, allowing us to represent it as x. But since it is actually a float, creating an array from it yields a flat float array and reading the values as regular values (as they are supposed to be, given that the type of the elements is something Lazy.t) fails at runtime.

Activity

  1. lthls commented on Apr 10, 2025

    @lthls
    ContributorAuthor

    Fixed by #13944.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions