
I'm afraid I still don't fully understand why Haskell finalisers are unsafe or why (if) calling Haskell from a C finaliser (which then called C land again) would be any safer.
The FFI standard doesn't say that calling C finalizers is unsafe (which would imply that the finalizers potentially do something naughty). Rather, the standard says that finalizers are called in a restricted context in which they are not allowed to call back into Haskell. The reason that finalizers must be written in C and cannot call into Haskell is that it requires pretty much all the machinery needed to implement preemptive concurrency (multiple C stacks, context switches, etc.) which was felt to be an excessively high burden on a Haskell implementation just to let you call C functions. (Of course, GHC already has this machinery which is why they provide enhanced functionality.) Why does it require most of the machinery of preemptive concurrency? Suppose that a finalizer requires the value of something that is currently being evaluated by the main thread. (This is very common and pretty much impossible to reason about in Haskell. For example, it could be a dictionary object or the thunk '(==) dict_Int'.) The correct thing to do if this happens is to block the finalizer, run the main thread until the shared thunk is updated with a value, and then restart the finalizer. To block a thread in this way, we have to switch C stacks, perform a context switch, etc. QED. -- Alastair Reid haskell-consulting.com