Description
In Data.Array.Accelerate.Array.Remote.Table, there is a function called insertUnmanaged which I believe is necessary for handing off pre-existing CUDA buffers to Accelerate. There is an assumed invariant here, namely that the remoteFinalizer attached to a Weak reference is run before deRefWeak can return Nothing in clean. This is not actually always true, and deRefWeak can return Nothing before remoteFinalizer runs and thus clean will see a buffer in the table and it will be "unreferenced" and so it will invoke freeStable on it, thus you could accidentally free a buffer provided by insertUnmanaged.
Steps to reproduce
I have not seen this in the wild but this appears real from reading Data.Array.Accelerate.Array.Remote.Table. I have confirmed that this order-of-operations of deRefWeak and the finalizer logic are inconsistent in the way described above, with an example Haskell program.
Description
In
Data.Array.Accelerate.Array.Remote.Table, there is a function calledinsertUnmanagedwhich I believe is necessary for handing off pre-existing CUDA buffers to Accelerate. There is an assumed invariant here, namely that theremoteFinalizerattached to aWeakreference is run beforedeRefWeakcan returnNothinginclean. This is not actually always true, anddeRefWeakcan returnNothingbeforeremoteFinalizerruns and thuscleanwill see a buffer in the table and it will be "unreferenced" and so it will invokefreeStableon it, thus you could accidentally free a buffer provided byinsertUnmanaged.Steps to reproduce
I have not seen this in the wild but this appears real from reading
Data.Array.Accelerate.Array.Remote.Table. I have confirmed that this order-of-operations ofdeRefWeakand the finalizer logic are inconsistent in the way described above, with an example Haskell program.