addForeignPtrFinalizer - finalizers run in FIFO or LIFO order?

The doc of base-4.5:Foreign.ForeignPtr.addForeignPtrFinalizer states: "This function adds a finalizer to the given foreign object. The finalizer will run before all other finalizers for the same object which have already been registered." I do addForeignPtrFinalizer finalize1 fp addForeignPtrFinalizer finalize2 fp and let the finalizers print something when they are started. I get the output: finalizer1 finalizer2 This indicates that the newly added finalizer is run _after_ the finalizers that are already registered. Is this a documentation bug or a bug in the base library?

On Fri, 17 Aug 2012, Henning Thielemann wrote:
The doc of base-4.5:Foreign.ForeignPtr.addForeignPtrFinalizer states: "This function adds a finalizer to the given foreign object. The finalizer will run before all other finalizers for the same object which have already been registered."
I do
addForeignPtrFinalizer finalize1 fp addForeignPtrFinalizer finalize2 fp
and let the finalizers print something when they are started. I get the output:
finalizer1 finalizer2
This indicates that the newly added finalizer is run _after_ the finalizers that are already registered. Is this a documentation bug or a bug in the base library?
Hm, it seems to depend on the context. In some situations I get the correct (reversed) order finalizer2 finalizer1 and in others I get finalizer1 first and then finalizer2. Any hint what can change the order of finalizers?

On Fri, 17 Aug 2012, Henning Thielemann wrote:
On Fri, 17 Aug 2012, Henning Thielemann wrote:
The doc of base-4.5:Foreign.ForeignPtr.addForeignPtrFinalizer states: "This function adds a finalizer to the given foreign object. The finalizer will run before all other finalizers for the same object which have already been registered."
I do
addForeignPtrFinalizer finalize1 fp addForeignPtrFinalizer finalize2 fp
and let the finalizers print something when they are started. I get the output:
finalizer1 finalizer2
This indicates that the newly added finalizer is run _after_ the finalizers that are already registered. Is this a documentation bug or a bug in the base library?
Hm, it seems to depend on the context. In some situations I get the correct (reversed) order
finalizer2 finalizer1
and in others I get finalizer1 first and then finalizer2. Any hint what can change the order of finalizers?
continuing my monologue ... It seems that a simple modification like turning a not directly related allocaBytes into a mallocBytes reverses the order from incorrect to correct (reversed). Maybe adding the finalizers is not the problem but running them. Maybe there are different ways to run the finalizers and allocaBytes causes an invalid execution of finalizers whereas mallocBytes leaves the correct way.

No. 1 question: do you have a reproduceable test case of both behaviors? Edward Excerpts from Henning Thielemann's message of Fri Aug 17 08:10:02 -0400 2012:
The doc of base-4.5:Foreign.ForeignPtr.addForeignPtrFinalizer states: "This function adds a finalizer to the given foreign object. The finalizer will run before all other finalizers for the same object which have already been registered."
I do
addForeignPtrFinalizer finalize1 fp addForeignPtrFinalizer finalize2 fp
and let the finalizers print something when they are started. I get the output:
finalizer1 finalizer2
This indicates that the newly added finalizer is run _after_ the finalizers that are already registered. Is this a documentation bug or a bug in the base library?

On Fri, 17 Aug 2012, Edward Z. Yang wrote:
No. 1 question: do you have a reproduceable test case of both behaviors?
Unfortunately I was not able to reduce it to a small test. Below a certain complexity the problem vanishes. Currently my example has many dependencies on external libraries (libav etc.) :-( Thus I hoped I could approach the problem from a different direction. If there are different ways to run the finalizers of a ForeignPtr then I could check them. I could not find something suspicious in base:GHC.ForeignPtr, though.

Henning Thielemann wrote:
and let the finalizers print something when they are started. I get the output:
finalizer1 finalizer2
Funny bug, I can reproduce it. (And it is a bug; the code in question violates a documented invariant.) What happens is, in essence, that the list of finalizers is reversed during garbage collection. See http://hackage.haskell.org/trac/ghc/ticket/7160 for an example program. Best regards, Bertram

Hi Bertram, On Sat, 18 Aug 2012, Bertram Felgenhauer wrote:
Henning Thielemann wrote:
and let the finalizers print something when they are started. I get the output:
finalizer1 finalizer2
Funny bug, I can reproduce it. (And it is a bug; the code in question violates a documented invariant.) What happens is, in essence, that the list of finalizers is reversed during garbage collection.
See http://hackage.haskell.org/trac/ghc/ticket/7160 for an example program.
Thank you a lot for working out the example! It could have required ages for me to reduce my problem to such a compact example.
participants (3)
-
Bertram Felgenhauer
-
Edward Z. Yang
-
Henning Thielemann