From 5e320e3de6b0541c5dd8703351f75a2301d05f56 Mon Sep 17 00:00:00 2001 From: Kai <450507+neko-kai@users.noreply.github.com> Date: Sat, 3 Oct 2020 08:27:27 +0100 Subject: [PATCH] Fix resource leak in `.toResourceZIO` that could happen just after ZManaged was acquired but before the finalizer was registered in Resource interpreter (https://github.com/typelevel/cats-effect/blob/bf1fa530bd651325c7b060389952d37b4852d5e5/core/shared/src/main/scala/cats/effect/Resource.scala#L133) (#234) --- .../main/scala/zio/interop/catszmanaged.scala | 43 +++++++++---------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/interop-cats/shared/src/main/scala/zio/interop/catszmanaged.scala b/interop-cats/shared/src/main/scala/zio/interop/catszmanaged.scala index 90c09786..cd4b3f23 100644 --- a/interop-cats/shared/src/main/scala/zio/interop/catszmanaged.scala +++ b/interop-cats/shared/src/main/scala/zio/interop/catszmanaged.scala @@ -17,12 +17,10 @@ package zio package interop -import cats.~> -import cats.arrow.FunctionK +import cats.arrow.{ ArrowChoice, FunctionK } import cats.effect.Resource.{ Allocate, Bind, Suspend } import cats.effect.{ Async, Effect, ExitCase, LiftIO, Resource, Sync, IO => CIO } -import cats.{ Bifunctor, Monad, MonadError, Monoid, Semigroup, SemigroupK } -import cats.arrow.ArrowChoice +import cats.{ ~>, Bifunctor, Monad, MonadError, Monoid, Semigroup, SemigroupK } import zio.ZManaged.ReleaseMap trait CatsZManagedSyntax { @@ -82,26 +80,25 @@ final class CatsIOResourceSyntax[F[_], A](private val resource: Resource[F, A]) final class ZManagedSyntax[R, E, A](private val managed: ZManaged[R, E, A]) extends AnyVal { def toResourceZIO: Resource[ZIO[R, E, ?], A] = - Resource.suspend { - ZManaged.ReleaseMap.make.bracketExit( - release = (releaseMap: ReleaseMap, exit: Exit[E, _]) => - exit match { - case Exit.Success(_) => UIO.unit - case Exit.Failure(_) => releaseMap.releaseAll(exit, ExecutionStrategy.Sequential) - }, - use = releaseMap => - managed.zio.provideSome[R]((_, releaseMap)).map { - case (_, a) => - Resource.applyCase(ZIO.succeedNow { - ( - a, - (exitCase: ExitCase[Throwable]) => - releaseMap.releaseAll(exitCaseToExit(exitCase), ExecutionStrategy.Sequential).unit - ) - }) - } + Resource + .applyCase[ZIO[R, E, ?], ReleaseMap]( + ZManaged.ReleaseMap.make.map( + releaseMap => + ( + releaseMap, + (exitCase: ExitCase[Throwable]) => + releaseMap.releaseAll(exitCaseToExit(exitCase), ExecutionStrategy.Sequential).unit + ) + ) + ) + .flatMap( + releaseMap => + Resource.suspend( + managed.zio.provideSome[R]((_, releaseMap)).map { a => + Resource.applyCase(ZIO.succeedNow((a._2, (_: ExitCase[Throwable]) => ZIO.unit))) + } + ) ) - } def toResource[F[_]](implicit F: Async[F], ev: Effect[ZIO[R, E, ?]]): Resource[F, A] = toResourceZIO.mapK(Lambda[FunctionK[ZIO[R, E, ?], F]](F liftIO ev.toIO(_)))