iterTarArchive:: Monad m=> (forall a. TarHeader -> Pipes.Consumer BS.ByteString m a)
This is a mistake in my implementation of `onException`. It should release the finalizer promptly in the event of an exception and not delay it until the end of the `SafeT` block.-> TarArchive m -> m ()
--
You received this message because you are subscribed to the Google Groups "Haskell Pipes" group.
To unsubscribe from this group and stop receiving emails from it, send an email to haskell-pipe...@googlegroups.com.
To post to this group, send email to haskel...@googlegroups.com.
Let me clarify that I will implement my suggested fix. I just need to make sure there are no problems with it first.
--
Your `iterTarArchive` type was cutoff, so for the benefit of others I'm pasting the full type here:
This is a mistake in my implementation of `onException`. It should release the finalizer promptly in the event of an exception and not delay it until the end of the `SafeT` block.
The origin of this mistake is that I initially had this for `onException`:
m1 `onException` io = do
key <- register (io >> return ())
r <- m1 `C.onException` liftBase io
release key
return r
However, that was a double-free bug because the `C.onException` did not release the finalizer. In the following commit I "fixed" it by removing `C.onException` completely, but that accidentally caused the problem you observed: late finalization:
https://github.com/Gabriel439/Haskell-Pipes-Safe-Library/commit/a8746f4800745a3bc24b1b42f4a4c298d19bab03
The correct fix is to begin from the old version I had and instead correctly fix it by having the `C.onException` release the ReleaseKey to prevent double-frees while still preserving prompt finalization.
Yeah, you're right. I don't think there is a way to implement this using your current `iterTarArchive`. However, what's wrong with just using `iterT` on `TarArchive` directly? That is much more flexible and allows one to use `runSafeP` and it still prevents misuse.
Also, side note: What is the purpose behind the `TarEntryProducer` constructor of the `TarEntry` type?
On 10/19/2013 06:08 PM, Gabriel Gonzalez wrote:
iterT allows the user to call back into the parser multiple times, which would lead to corruption of the parser state. If the functor contains a Producer that must be ran to get the next action, this should be ran exactly once - no more, no less. Writing my own iterator meant I could get that guarantee.Yeah, you're right. I don't think there is a way to implement this using your current `iterTarArchive`. However, what's wrong with just using `iterT` on `TarArchive` directly? That is much more flexible and allows one to use `runSafeP` and it still prevents misuse.
On 10/19/2013 11:17 AM, Oliver Charles wrote:
On 10/19/2013 06:08 PM, Gabriel Gonzalez wrote:
iterT allows the user to call back into the parser multiple times, which would lead to corruption of the parser state. If the functor contains a Producer that must be ran to get the next action, this should be ran exactly once - no more, no less. Writing my own iterator meant I could get that guarantee.Yeah, you're right. I don't think there is a way to implement this using your current `iterTarArchive`. However, what's wrong with just using `iterT` on `TarArchive` directly? That is much more flexible and allows one to use `runSafeP` and it still prevents misuse.
I think trying to enforce this stronger property is much more trouble than its worth.
For example, consider this code:
import Pipes
import qualified Pipes.Prelude as P
p = P.stdinLn >-> P.take 10
Nothing prevents me from reading more than 10 lines by just restarting `p`. Getting this right requires linear types (which Haskell does not have).
Taking your idea to its logical conclusion would basically require replacing every `Producer` in the `pipes` ecosystem with something like this:
stdinLn2 :: (String -> IO ()) -> IO ()
This `stdinLn2` example has the same problems as your `iterTarArchive`. For example, there is no way to limit `stdinLn2` to only print the first 10 lines of input, just like you can't limit `iterTarArchive` to only process 10 tar entries.
This whole `pipes-safe` problem is just the tip of the iceberg for the issues you are going to encounter, the kind of issues I was trying to solve when I came up with `pipes`. For example, using `iterTarArchive` there is no way to `hoist lift` the `Producer` if its base monad does not match the `Consumer`.