Skip to content

Equivalent programs show different behaviour #508

Open
@pclayton

Description

@pclayton

I have an example where a finalizer is unexpectedly not being run. However, the finalizer is run if I transform the code to something (that I thought was) equivalent. This is using MLton 20210117.

A highly reduced example is attached which is built with the command make mlton. The code contains a function declaration

fun theFunction ({n, ...} : t) = ...

and two references to the function of the form theFunction self. When run, it produces the output

finalized a1
finalized obj1

so obj2 is not finalized. If the code is changed to declare

fun theFunction n =

and the two references to the function changed to theFunction (#n self), then it produces the output

finalized a1
finalized obj1
finalized obj2

so obj2 is finalized. Therefore, finalization of obj2 depends on whether the record component n is selected by pattern matching in the function declaration or in the argument of each call.

The reason that finalization does not occur in the original example is probably due to my alternative implementation of FINALIZABLE in the structure Finalizable (which is based on my Poly/ML implementation). At exit, the finalizers are cleaned up by code registered with both MLtonSignal.handleGC and OS.Process.atExit. There is no code that empties the list of pending finalizers at exit as the in the MLton implementation. Instead, data races are avoided by using the module SharedVar which protects access to a shared variable using MLton.Thread.atomically. It can be seen that this protection has an effect for the list of pending finalizers in this example: in the original example, changing

fun foldmap r f x = MLton.Thread.atomically (fn () => foldmap' r f x)

to

fun foldmap r f x = foldmap' r f x

i.e. removing the protection from the module SharedVar produces the output

finalized a1
finalized obj1
finalized a1
free(): double free detected in tcache 2
Aborted (core dumped)

Possibly I am misusing MLton.Thread.atomically or have done something wrong. Still, I am surprised that two seemingly equivalent programs can give different results.

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