Attaching a finalizer to a regular data type like that is a bit of a hazard prone process. If GHC unpack your Socket in another data constructor it will get "freed" and then your socket can get finalized while you still have access to the CInt! 

data MySockets = MySockets {-# unpack #-} !Socket {-# unpack #-} !Socket

will happily 'eat' your data constructor wrapper and if there are no references remaining to a copy of it on the heap, their finalizers will fire. Worker-wrapper transforms can do this even without any "containing" data type if you just increase your optimization level!

It would be much, much safer to attach the finalizer to something that has a "presence" all its own, like Weak# () as is done in ForeignPtr. This would result in something like:

data Socket = Socket !CInt (Weak# ())

Then when it gets unpacked into another data constructor, then the Weak# () still exists. This isn't free, it comes at the cost that your sockets take a couple of words each (plus finalizer space), but the approach you are taking now isn't free either as it isn't really sound. ;)

tl;dr don't attach finalizers to regular Haskell data types if you can help it

-Edward

On Tue, Jan 30, 2018 at 12:18 AM, Kazu Yamamoto <kazu@iij.ad.jp> wrote:
Hi,

I registered this issue to network:

        https://github.com/haskell/network/issues/302

Viktor, thank you!

--Kazu

>> On Jan 29, 2018, at 10:25 PM, Kazu Yamamoto (山本和彦) <kazu@iij.ad.jp> wrote:
>>
>>    socket family stype protocol = do
>>       fd <- c_socket ...
>>       ...
>>       let s = Socket fd
>>       addFinalizer s $ close s
>>       ruturn s
>
> For the record, I think I've convinced Kazu Yamamoto that this is
> an anti-pattern.  Such a finalizer would easily end up closing
> already closed sockets, whose file-descriptors may already be
> associated with other open files or sockets.  That way lie all
> sorts of difficult to isolate race-condition bugs.  To make this
> safe, the close function would need to mutate the socket,
> invalidating the enclosed file-descriptor, and would then need to
> be a NOP or just raise an exception if the socket is closed again
> (the finalizer should invoke a close variant that just returns
> without raising exceptions if the socket is already closed).
>
> There is, AFAIK still an unresolved bug along these lines somewhere
> in http-client and its dependencies.  So far no reproducing cases have
> been provided.  No very recent reports either, perhaps it went away,
> or people have just been more lucky lately:
>
>    https://github.com/snoyberg/http-client/issues/252
>    https://github.com/vincenthz/hs-tls/issues/179
>
> All that said, the original question about addFinalizer vs. GHC 7.10
> may still be worth exploring, even if its use-case for Sockets goes
> away.  So, please don't take this poset to mean that the original
> question should be ignored.
>
> --
>       Viktor.
>
> _______________________________________________
> Haskell-Cafe mailing list
> To (un)subscribe, modify options or view archives go to:
> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
> Only members subscribed via the mailman list are allowed to post.
_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.