[Haskell-cafe] dangerous inlinePerformIO in Data.Binary(?)

Udo Stenzel u.stenzel at web.de
Thu Jun 14 19:03:10 EDT 2007


I was trying to understand the magic inside Data.Binary, and found two
somewhat suspicious uses of inlinePerformIO, which imho has a far too
innocuous name:

| toLazyByteString :: Builder -> L.ByteString
| toLazyByteString m = S.LPS $ inlinePerformIO $ do
|     buf <- newBuffer defaultSize
|     return (runBuilder (m `append` flush) (const []) buf)

Why is this safe?  Considering the GHC implementation of IO, isn't there
a real danger that 'newBuffer defaultSize' is floated out and therefore
every invocation of 'toLazyByteString' starts out with the same buffer?
Isn't that exactly the reason why unsafePerformIO and runST are declared

The other occurence is:

| unsafeLiftIO :: (Buffer -> IO Buffer) -> Builder
| unsafeLiftIO f =  Builder $ \ k buf -> inlinePerformIO $ do
|     buf' <- f buf
|     return (k buf')

which might be safe, since 'f buf' cannot float out of the lambda which
binds 'buf', but still, all this stuff is inlined, something constant
might get plugged in the place of buf and the result might be floated
out to give us an even harder to find Heisenbug.

Am I missing something and this is actually safe?  If not, what can be
done to avoid such errors?  I'd really hate to find building blocks that
crumble under pressure in standard libraries...


-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: Digital signature
Url : http://www.haskell.org/pipermail/haskell-cafe/attachments/20070615/f9d5ea22/attachment.bin

More information about the Haskell-Cafe mailing list