Finalizers strike back

George Russell ger at
Fri Oct 11 09:51:15 EDT 2002

Alastair Reid wrote:
> Please to not refer to that code out of context again.  I wrote that
> code _specifically_ to demonstrate where race conditions could arise.
> I clearly flagged it as code that "does nothing at all to guarantee
> atomicity of Haskell code that manipulates global variables" and in
> which "Some possible interleavings of the IO actions in these
> functions can result in an object not being added to or removed from
> the object list".
OK, I apologise for taking you out of context.  But in that case, if all your
code demonstrates is that given Haskell98 + FFI + IORefs + no MVars + Haskell finalizers
+ an incompetent programmers, you may get race conditions, does that really demonstrate
very much?
> I think we are in full agreement that some form of locking is required
> if Haskell finalizers that manipulate shared Haskell state are
> allowed.
We are currently defining Haskell98 + FFI.  There is no shared internal Haskell state to 
manipulate in Haskell98 + FFI.  Therefore, in such circumstances, this statement is
vacuously true.

As I have already pointed out, in the absence of shared internal Haskell state there
may still be good reasons for permitting Haskell code to run inside finalizers, for
example if the outside world independently calls some (perhaps pure) Haskell function,
while a finalizer is running.  

I think the simplest solution, in these circumstances, is to say that the extensions 
required to implement mutable state are not our problem in this standard.  The FFI standard
is not responsible when the programmer obtains race conditions due to misuse of features
(such as choosing IORefs when MVars would be more appropriate) which are not even specified
in it.

Thus I do not think Alastair's argument for retaining this restriction in the standard holds.

We also seem to have got into details about what NHC and Hugs should do.  As I've already made
clear, I think it would be better for the standard not to include this restriction, so that
the NHC and Hugs documentation must explicitly (and clearly) say that they do not follow the
standard here, the reason being that this is a potentially serious problem leading to unreproducible
core-dumps and heaven knows what.  

However, although I am not a Hugs user, my personal opinion would be that Hugs should permit
Haskell finalizers, but only run them at the next scheduling point (or at the end of execution), if 
no better way can be found.   The user would still need to be warned to use yield periodically 
if necessary, but the consequences of not doing so would be not nearly as dire as the alternative.
I don't like memory leaks, but infinitely prefer them to unreproducible core-dumps occuring at
random points in the program.  Hugs would then keep to the letter of the standard.  If instant
finalizers are desired, there is of course no reason we should not also have an 
addUnsafeForeignFinalizer function with the existing behaviour.

What is the situation with NHC?

More information about the FFI mailing list