diff --git a/snappy-c.cabal b/snappy-c.cabal
--- a/snappy-c.cabal
+++ b/snappy-c.cabal
@@ -1,6 +1,6 @@
 cabal-version:      3.0
 name:               snappy-c
-version:            0.1.0
+version:            0.1.1
 synopsis:           Bindings to Google's Snappy: A fast compression library
 description:        [Snappy](https://github.com/google/snappy) is a fast
                     (de)compression library. It is written in C++, but a basic
@@ -17,10 +17,11 @@
 build-type:         Simple
 extra-source-files: README.md
 extra-doc-files:    CHANGELOG.md
-tested-with:        GHC==9.2.8
+tested-with:        GHC==8.10.7
+                  , GHC==9.2.8
                   , GHC==9.4.8
                   , GHC==9.6.4
-                  , GHC==9.8.1
+                  , GHC==9.8.2
 
 source-repository head
   type:     git
@@ -33,7 +34,7 @@
       -Wprepositive-qualified-module
       -Widentities
   build-depends:
-      base >= 4.16 && < 4.20
+      base >= 4.14 && < 4.20
   default-language:
       Haskell2010
   default-extensions:
@@ -76,7 +77,7 @@
       Codec.Compression.SnappyC.Internal.FrameFormat
       Codec.Compression.SnappyC.Internal.Util
   build-depends:
-    , bytestring   >= 0.11  && < 0.13
+    , bytestring   >= 0.10  && < 0.13
     , data-default >= 0.7   && < 0.8
     , digest       >= 0.0.2 && < 0.0.3
     , mtl          >= 2.2.2 && < 2.4
@@ -93,7 +94,7 @@
   build-depends:
       snappy-c
 
-    , bytestring           >= 0.11  && < 0.13
+    , bytestring           >= 0.10  && < 0.13
     , conduit              >= 1.3.5 && < 1.4
     , data-default         >= 0.7   && < 0.8
     , optparse-applicative >= 0.18  && < 0.19
@@ -101,7 +102,6 @@
       -threaded
       -rtsopts
 
--- TODO bounds here
 test-suite test-snappy-c
   import:
       lang
@@ -119,7 +119,7 @@
     , snappy-c
   build-depends:
       -- External dependencies
-    , bytestring       >= 0.11 && < 0.13
+    , bytestring       >= 0.10 && < 0.13
     , tasty            >= 1.5  && < 1.6
     , tasty-hunit      >= 0.10 && < 0.11
     , tasty-quickcheck >= 0.10 && < 0.11
@@ -139,7 +139,7 @@
     , snappy-c
 
     -- external
-    , bytestring  >= 0.11  && < 0.13
+    , bytestring  >= 0.10  && < 0.13
     , criterion   >= 1.6.3 && < 1.7
     , deepseq     >= 1.4   && < 1.6
     , random      >= 1.2.1 && < 1.3
diff --git a/src/Codec/Compression/SnappyC/Raw.hs b/src/Codec/Compression/SnappyC/Raw.hs
--- a/src/Codec/Compression/SnappyC/Raw.hs
+++ b/src/Codec/Compression/SnappyC/Raw.hs
@@ -21,80 +21,76 @@
 import Data.ByteString.Internal (ByteString(..))
 import Foreign
 import System.IO.Unsafe
+import Data.ByteString.Unsafe
 
 -- | Compress the input using [Snappy](https://github.com/google/snappy/).
 --
 -- The result is in Snappy raw format, /not/ the framing format.
 compress :: ByteString -> ByteString
-compress (BS sfp slen) =
-    unsafePerformIO $ do
+compress bs = unsafePerformIO $ do
+    unsafeUseAsCStringLen bs $ \(sptr, slen) -> do
       let dlen = C.snappy_max_compressed_length (fromIntegral slen)
-      dfp <- mallocForeignPtrBytes (fromIntegral dlen)
-      withForeignPtr sfp $ \sptr ->
-        withForeignPtr dfp $ \dptr ->
-          with dlen $ \dlen_ptr ->
-            case
-              C.snappy_compress
-                (castPtr sptr)
-                (fromIntegral slen)
-                (castPtr dptr)
-                dlen_ptr
-            of
-              0 ->
-                BS dfp . fromIntegral <$> peek dlen_ptr
-              1 ->
-                error "impossible: there is no invalid input for compression"
-              2 ->
-                error "impossible: the buffer size is always set correctly"
-              status ->
-                error $
-                  "impossible: unexpected status from snappy_compress: " ++
-                  show status
+      dptr <- mallocBytes (fromIntegral dlen)
+      with dlen $ \dlen_ptr ->
+        case
+          C.snappy_compress
+            (castPtr sptr)
+            (fromIntegral slen)
+            (castPtr dptr)
+            dlen_ptr
+        of
+          0 -> do
+            len <- fromIntegral <$> peek dlen_ptr
+            unsafePackMallocCStringLen (dptr, len)
+          1 ->
+            error "impossible: there is no invalid input for compression"
+          2 ->
+            error "impossible: the buffer size is always set correctly"
+          status ->
+            error $
+              "impossible: unexpected status from snappy_compress: " ++
+              show status
 
 -- | Decompress the input using [Snappy](https://github.com/google/snappy/).
 --
 -- Returns 'Nothing' if the input is not in Snappy raw format or
 -- otherwise ill-formed.
 decompress :: ByteString -> Maybe ByteString
-decompress (BS sfp slen) =
-    unsafePerformIO $ do
-      withForeignPtr sfp $
-        \sptr ->
-          alloca $
-            \dlen_ptr ->
-              case
-                C.snappy_uncompressed_length
+decompress bs = unsafePerformIO $ do
+    unsafeUseAsCStringLen bs $ \(sptr, slen) ->
+      alloca $ \dlen_ptr ->
+        case
+          C.snappy_uncompressed_length
+            (castPtr sptr)
+            (fromIntegral slen)
+            dlen_ptr
+        of
+          0 -> do
+            dlen <- fromIntegral <$> peek dlen_ptr
+            dptr <- mallocBytes dlen
+            case
+                C.snappy_uncompress
                   (castPtr sptr)
                   (fromIntegral slen)
+                  (castPtr dptr)
                   dlen_ptr
-              of
-                0 -> do
-                  dlen <- fromIntegral <$> peek dlen_ptr
-                  dfp <- mallocForeignPtrBytes dlen
-                  withForeignPtr dfp $
-                    \dptr ->
-                      case
-                          C.snappy_uncompress
-                            (castPtr sptr)
-                            (fromIntegral slen)
-                            (castPtr dptr)
-                            dlen_ptr
-                      of
-                        0 ->
-                          Just . BS dfp . fromIntegral <$> peek dlen_ptr
-                        1 ->
-                          -- Invalid input. Successful result from
-                          -- snappy_uncompressed_length does *not* mean the
-                          -- input is completely valid
-                          return Nothing
-                        status ->
-                          error $
-                            "impossible: decompression failed with status " ++
-                            show status
-                1 ->
-                  return Nothing
-                status ->
-                  error $
-                    "impossible: snappy_uncompressed_length failed with " ++
-                    "status" ++ show status
+             of
+              0 -> do
+                len <- fromIntegral <$> peek dlen_ptr
+                Just <$> unsafePackMallocCStringLen (dptr, len)
+              1 ->
+                -- Invalid input. Successful result from
+                -- snappy_uncompressed_length does *not* mean the
+                -- input is completely valid
+                return Nothing
+              status ->
+                error $
+                  "impossible: decompression failed with status " ++
+                  show status
+          1 ->
+            return Nothing
+          status ->
+            error $
+              "impossible: snappy_uncompressed_length failed with " ++
+              "status" ++ show status
 
