diff --git a/library/PtrPoker/Compat/ByteString.hs b/library/PtrPoker/Compat/ByteString.hs
--- a/library/PtrPoker/Compat/ByteString.hs
+++ b/library/PtrPoker/Compat/ByteString.hs
@@ -1,27 +1,28 @@
 {-# LANGUAGE CPP #-}
 
-module PtrPoker.Compat.ByteString where
+module PtrPoker.Compat.ByteString (poke) where
 
-#if MIN_VERSION_bytestring(0,11,0)
 import Data.ByteString.Internal
-import PtrPoker.Prelude
+import qualified PtrPoker.Compat.ForeignPtr as ForeignPtr
+import PtrPoker.Prelude hiding (poke)
 
 {-# INLINE poke #-}
 poke :: ByteString -> Ptr Word8 -> IO (Ptr Word8)
+
+#if MIN_VERSION_bytestring(0,11,0)
+
 poke (BS fptr length) ptr =
   {-# SCC "poke" #-}
-  withForeignPtr fptr $ \ bytesPtr ->
+  ForeignPtr.unsafeWithForeignPtr fptr $ \ bytesPtr ->
     memcpy ptr bytesPtr length $>
     plusPtr ptr length
+
 #else
-import Data.ByteString.Internal
-import PtrPoker.Prelude
 
-{-# INLINE poke #-}
-poke :: ByteString -> Ptr Word8 -> IO (Ptr Word8)
 poke (PS fptr offset length) ptr =
   {-# SCC "poke" #-}
-  withForeignPtr fptr $ \ bytesPtr ->
+  ForeignPtr.unsafeWithForeignPtr fptr $ \ bytesPtr ->
     memcpy ptr (plusPtr bytesPtr offset) length $>
     plusPtr ptr length
+
 #endif
diff --git a/library/PtrPoker/Compat/ForeignPtr.hs b/library/PtrPoker/Compat/ForeignPtr.hs
new file mode 100644
--- /dev/null
+++ b/library/PtrPoker/Compat/ForeignPtr.hs
@@ -0,0 +1,33 @@
+{-# LANGUAGE CPP #-}
+
+module PtrPoker.Compat.ForeignPtr where
+
+import PtrPoker.Prelude
+
+#if MIN_VERSION_base(4,15,0)
+import qualified GHC.ForeignPtr
+#else
+import qualified Foreign.ForeignPtr
+#endif
+
+-- | 'unsafeWithForeignPtr' compatibility wrapper.
+--
+-- GHC 9.0 made 'withForeignPtr' sound at the cost of performance. If you want to
+-- use the faster unsafe implementation, it's now at 'unsafeWithForeignPtr', and
+-- GHC asks you to promise that your continuation does not diverge. All we do here
+-- is @memcpy@ bytestrings, so we gladly pinky swear. For more detail, see Ben
+-- Gamari's post:
+-- <https://www.haskell.org/ghc/blog/20210607-the-keepAlive-story.html>
+--
+-- Note that fumieval's mason uses 'unsafeWithForeignPtr' in the same way also to
+-- copy bytestrings.
+{-# INLINE unsafeWithForeignPtr #-}
+unsafeWithForeignPtr :: ForeignPtr a -> (Ptr a -> IO b) -> IO b
+#if MIN_VERSION_base(4,15,0)
+unsafeWithForeignPtr =
+    GHC.ForeignPtr.unsafeWithForeignPtr
+#else
+unsafeWithForeignPtr =
+    -- same implementation as new @unsafeWithForeignPtr@ (it was always unsafe)
+    Foreign.ForeignPtr.withForeignPtr
+#endif
diff --git a/library/PtrPoker/IO/Prim.hs b/library/PtrPoker/IO/Prim.hs
--- a/library/PtrPoker/IO/Prim.hs
+++ b/library/PtrPoker/IO/Prim.hs
@@ -5,7 +5,7 @@
 import PtrPoker.Prelude
 
 {-# INLINE pokeStorable #-}
-pokeStorable :: Storable a => Ptr Word8 -> a -> IO ()
+pokeStorable :: (Storable a) => Ptr Word8 -> a -> IO ()
 pokeStorable ptr value =
   {-# SCC "pokeStorable" #-}
   poke (castPtr ptr) value
diff --git a/library/PtrPoker/Poke.hs b/library/PtrPoker/Poke.hs
--- a/library/PtrPoker/Poke.hs
+++ b/library/PtrPoker/Poke.hs
@@ -40,7 +40,7 @@
 -- |
 -- Concatenate a foldable of pokes.
 {-# INLINE [1] concat #-}
-concat :: Foldable f => f Poke -> Poke
+concat :: (Foldable f) => f Poke -> Poke
 concat pokers =
   Poke (\p -> foldM (\p (Poke io) -> io p) p pokers)
 
diff --git a/library/PtrPoker/Prelude.hs b/library/PtrPoker/Prelude.hs
--- a/library/PtrPoker/Prelude.hs
+++ b/library/PtrPoker/Prelude.hs
@@ -76,5 +76,5 @@
 import Unsafe.Coerce as Exports
 import Prelude as Exports hiding (all, and, any, concat, concatMap, elem, fail, foldl, foldl1, foldr, foldr1, id, mapM, mapM_, maximum, minimum, notElem, or, product, sequence, sequence_, sum, (.))
 
-showAsText :: Show a => a -> Text
+showAsText :: (Show a) => a -> Text
 showAsText = show >>> fromString
diff --git a/library/PtrPoker/Write.hs b/library/PtrPoker/Write.hs
--- a/library/PtrPoker/Write.hs
+++ b/library/PtrPoker/Write.hs
@@ -50,7 +50,7 @@
 -- |
 -- Concatenate a foldable of writes.
 {-# INLINE concat #-}
-concat :: Foldable f => f Write -> Write
+concat :: (Foldable f) => f Write -> Write
 concat f =
   Write
     (foldl' (\a b -> a + writeSize b) 0 f)
diff --git a/ptr-poker.cabal b/ptr-poker.cabal
--- a/ptr-poker.cabal
+++ b/ptr-poker.cabal
@@ -1,6 +1,6 @@
 cabal-version: 3.0
 name:          ptr-poker
-version:       0.1.2.12
+version:       0.1.2.13
 synopsis:      Pointer poking action construction and composition toolkit
 homepage:      https://github.com/nikita-volkov/ptr-poker
 bug-reports:   https://github.com/nikita-volkov/ptr-poker/issues
@@ -68,6 +68,7 @@
   other-modules:
     PtrPoker.ByteString
     PtrPoker.Compat.ByteString
+    PtrPoker.Compat.ForeignPtr
     PtrPoker.Compat.Text
     PtrPoker.Ffi
     PtrPoker.IO.Prim
@@ -80,10 +81,10 @@
     cbits/text.c
 
   build-depends:
-    , base        >=4.11    && <5
-    , bytestring  >=0.10    && <0.12
-    , scientific  >=0.3.6.2 && <0.4
-    , text        >=1       && <3
+    , base >=4.11 && <5
+    , bytestring >=0.10 && <0.12
+    , scientific >=0.3.6.2 && <0.4
+    , text >=1 && <3
 
 test-suite test
   import:         base-settings
@@ -91,11 +92,11 @@
   hs-source-dirs: test
   main-is:        Main.hs
   build-depends:
-    , hedgehog           >=1.2     && <2
-    , isomorphism-class  >=0.1.0.8 && <0.2
-    , numeric-limits     >=0.1     && <0.2
+    , hedgehog >=1.2 && <2
+    , isomorphism-class >=0.1.0.8 && <0.2
+    , numeric-limits >=0.1 && <0.2
     , ptr-poker
-    , rerebase           >=1.16.1  && <2
+    , rerebase >=1.16.1 && <2
 
 benchmark bench
   import:         base-settings
@@ -104,6 +105,6 @@
   main-is:        Main.hs
   ghc-options:    -O2 -threaded -with-rtsopts=-N
   build-depends:
-    , criterion  >=1.6    && <2
+    , criterion >=1.6 && <2
     , ptr-poker
-    , rerebase   >=1.16.1 && <2
+    , rerebase >=1.16.1 && <2
