[Haskell-cafe] addFinalizer in GHC 7.10

Edward Kmett ekmett at gmail.com
Tue Jan 30 21:50:36 UTC 2018


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 at 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 at 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.
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/haskell-cafe/attachments/20180130/899b90cb/attachment.html>


More information about the Haskell-Cafe mailing list