diff --git a/Changelog.md b/Changelog.md
--- a/Changelog.md
+++ b/Changelog.md
@@ -1,5 +1,10 @@
 # Changelog
 
+## 0.2.3 (Feb 2025)
+
+* Fix breakOn/lines in the Array module.
+* Support GHC 9.12
+
 ## 0.2.2 (Jan 2024)
 
 * Add fixities `infixr 5` for `cons` and `consM` functions.
diff --git a/configure b/configure
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.71 for streamly-core 0.2.2.
+# Generated by GNU Autoconf 2.71 for streamly-core 0.2.3.
 #
 # Report bugs to <streamly@composewell.com>.
 #
@@ -610,8 +610,8 @@
 # Identity of this package.
 PACKAGE_NAME='streamly-core'
 PACKAGE_TARNAME='streamly-core'
-PACKAGE_VERSION='0.2.2'
-PACKAGE_STRING='streamly-core 0.2.2'
+PACKAGE_VERSION='0.2.3'
+PACKAGE_STRING='streamly-core 0.2.3'
 PACKAGE_BUGREPORT='streamly@composewell.com'
 PACKAGE_URL='https://streamly.composewell.com'
 
@@ -1256,7 +1256,7 @@
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures streamly-core 0.2.2 to adapt to many kinds of systems.
+\`configure' configures streamly-core 0.2.3 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1318,7 +1318,7 @@
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of streamly-core 0.2.2:";;
+     short | recursive ) echo "Configuration of streamly-core 0.2.3:";;
    esac
   cat <<\_ACEOF
 
@@ -1404,7 +1404,7 @@
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-streamly-core configure 0.2.2
+streamly-core configure 0.2.3
 generated by GNU Autoconf 2.71
 
 Copyright (C) 2021 Free Software Foundation, Inc.
@@ -1622,7 +1622,7 @@
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by streamly-core $as_me 0.2.2, which was
+It was created by streamly-core $as_me 0.2.3, which was
 generated by GNU Autoconf 2.71.  Invocation command line was
 
   $ $0$ac_configure_args_raw
@@ -3832,7 +3832,7 @@
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by streamly-core $as_me 0.2.2, which was
+This file was extended by streamly-core $as_me 0.2.3, which was
 generated by GNU Autoconf 2.71.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -3888,7 +3888,7 @@
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config='$ac_cs_config_escaped'
 ac_cs_version="\\
-streamly-core config.status 0.2.2
+streamly-core config.status 0.2.3
 configured by $0, generated by GNU Autoconf 2.71,
   with options \\"\$ac_cs_config\\"
 
diff --git a/configure.ac b/configure.ac
--- a/configure.ac
+++ b/configure.ac
@@ -3,7 +3,7 @@
 # See https://www.gnu.org/software/autoconf/manual/autoconf.html for help on
 # the macros used in this file.
 
-AC_INIT([streamly-core], [0.2.2], [streamly@composewell.com], [streamly-core], [https://streamly.composewell.com])
+AC_INIT([streamly-core], [0.2.3], [streamly@composewell.com], [streamly-core], [https://streamly.composewell.com])
 
 # To suppress "WARNING: unrecognized options: --with-compiler"
 AC_ARG_WITH([compiler], [GHC])
diff --git a/docs/ApiChangelogs/0.2.2-0.2.3.txt b/docs/ApiChangelogs/0.2.2-0.2.3.txt
new file mode 100644
--- /dev/null
+++ b/docs/ApiChangelogs/0.2.2-0.2.3.txt
@@ -0,0 +1,28 @@
+---------------------------------
+API Annotations
+---------------------------------
+
+[A] : Added
+[R] : Removed
+[C] : Changed
+[O] : Old definition
+[N] : New definition
+[D] : Deprecated
+
+---------------------------------
+API diff
+---------------------------------
+
+
+
+---------------------------------
+Internal API diff
+---------------------------------
+
+[C] Streamly.Internal.Data.MutByteArray
+    [D] unsafePinnedAsPtr :: MonadIO m => MutByteArray -> (Ptr a -> m b) -> m b
+[C] Streamly.Internal.Data.MutArray
+    [D] unsafePinnedAsPtr :: MonadIO m => MutArray a -> (Ptr a -> m b) -> m b
+    [D] memcpy :: Ptr Word8 -> Ptr Word8 -> Int -> IO ()
+    [D] memcmp :: Ptr Word8 -> Ptr Word8 -> Int -> IO Bool
+    [D] c_memchr :: Ptr Word8 -> Word8 -> CSize -> IO (Ptr Word8)
diff --git a/docs/Changelog.md b/docs/Changelog.md
--- a/docs/Changelog.md
+++ b/docs/Changelog.md
@@ -1,5 +1,10 @@
 # Changelog
 
+## 0.2.3 (Feb 2025)
+
+* Fix breakOn/lines in the Array module.
+* Support GHC 9.12
+
 ## 0.2.2 (Jan 2024)
 
 * Add fixities `infixr 5` for `cons` and `consM` functions.
diff --git a/src/Streamly/Internal/Data/Array/Type.hs b/src/Streamly/Internal/Data/Array/Type.hs
--- a/src/Streamly/Internal/Data/Array/Type.hs
+++ b/src/Streamly/Internal/Data/Array/Type.hs
@@ -247,7 +247,10 @@
 --
 {-# INLINE unsafePinnedAsPtr #-}
 unsafePinnedAsPtr :: MonadIO m => Array a -> (Ptr a -> m b) -> m b
-unsafePinnedAsPtr arr = MA.unsafePinnedAsPtr (unsafeThaw arr)
+unsafePinnedAsPtr arr f = do
+    let marr = unsafeThaw arr
+    pinned <- liftIO $ MA.pin marr
+    MA.unsafeAsPtr pinned f
 
 {-# DEPRECATED asPtrUnsafe "Please use unsafePinnedAsPtr instead." #-}
 {-# INLINE asPtrUnsafe #-}
diff --git a/src/Streamly/Internal/Data/MutArray/Lib.c b/src/Streamly/Internal/Data/MutArray/Lib.c
new file mode 100644
--- /dev/null
+++ b/src/Streamly/Internal/Data/MutArray/Lib.c
@@ -0,0 +1,15 @@
+#include <string.h>
+
+// Find the char "c" starting from "dst+off" and up to "len" chars from
+// it, returns the index of the character found, considering dst + off
+// as the base pointer. If index is greater than or equal to len the
+// char is not found.
+size_t memchr_index(const void *dst, size_t off, int c, size_t len) {
+    void *p = memchr ((char *)dst + off, c, len);
+
+    if (p) {
+        return (size_t) (p - dst - off);
+    } else {
+        return len;
+    }
+}
diff --git a/src/Streamly/Internal/Data/MutArray/Type.hs b/src/Streamly/Internal/Data/MutArray/Type.hs
--- a/src/Streamly/Internal/Data/MutArray/Type.hs
+++ b/src/Streamly/Internal/Data/MutArray/Type.hs
@@ -1,5 +1,6 @@
 {-# LANGUAGE CPP #-}
 {-# LANGUAGE UnboxedTuples #-}
+{-# LANGUAGE UnliftedFFITypes #-}
 -- |
 -- Module      : Streamly.Internal.Data.MutArray.Type
 -- Copyright   : (c) 2020 Composewell Technologies
@@ -313,8 +314,9 @@
 import Data.Functor.Identity (Identity(..))
 import Data.Proxy (Proxy(..))
 import Data.Word (Word8)
-import Foreign.C.Types (CSize(..), CInt(..))
-import Foreign.Ptr (plusPtr, minusPtr, nullPtr)
+import Foreign.C.Types (CSize(..))
+import Foreign.Ptr (plusPtr)
+import Foreign.C.Types (CInt(..))
 import Streamly.Internal.Data.MutByteArray.Type
     ( MutByteArray(..)
     , PinnedState(..)
@@ -329,7 +331,7 @@
     , copyMutableByteArray#
     )
 import GHC.Base (noinline)
-import GHC.Exts (unsafeCoerce#, Addr#)
+import GHC.Exts (unsafeCoerce#, Addr#, MutableByteArray#, RealWorld)
 import GHC.Ptr (Ptr(..))
 
 import Streamly.Internal.Data.Fold.Type (Fold(..))
@@ -362,17 +364,14 @@
 -------------------------------------------------------------------------------
 
 -- NOTE: Have to be "ccall unsafe" so that we can pass unpinned memory to these
-foreign import ccall unsafe "string.h memcpy" c_memcpy
-    :: Ptr Word8 -> Ptr Word8 -> CSize -> IO (Ptr Word8)
-
-foreign import ccall unsafe "string.h memchr" c_memchr
-    :: Ptr Word8 -> Word8 -> CSize -> IO (Ptr Word8)
+foreign import ccall unsafe "string.h memcpy" c_memcpy_pinned_src
+    :: MutableByteArray# RealWorld -> Ptr Word8 -> CSize -> IO (Ptr Word8)
 
-foreign import ccall unsafe "string.h memcmp" c_memcmp
-    :: Ptr Word8 -> Ptr Word8 -> CSize -> IO CInt
+foreign import ccall unsafe "memchr_index" c_memchr_index
+    :: MutableByteArray# RealWorld -> CSize -> Word8 -> CSize -> IO CSize
 
-foreign import ccall unsafe "string.h strlen" c_strlen
-    :: Ptr Word8 -> IO CSize
+foreign import ccall unsafe "string.h strlen" c_strlen_pinned
+    :: Addr# -> IO CSize
 
 -- | Given an 'Unboxed' type (unused first arg) and a number of bytes, return
 -- how many elements of that type will completely fit in those bytes.
@@ -381,18 +380,6 @@
 bytesToElemCount :: forall a. Unbox a => a -> Int -> Int
 bytesToElemCount _ n = n `div` SIZE_OF(a)
 
--- XXX we are converting Int to CSize
-memcpy :: Ptr Word8 -> Ptr Word8 -> Int -> IO ()
-memcpy dst src len = void (c_memcpy dst src (fromIntegral len))
-
--- XXX we are converting Int to CSize
--- return True if the memory locations have identical contents
-{-# INLINE memcmp #-}
-memcmp :: Ptr Word8 -> Ptr Word8 -> Int -> IO Bool
-memcmp p1 p2 len = do
-    r <- c_memcmp p1 p2 (fromIntegral len)
-    return $ r == 0
-
 -------------------------------------------------------------------------------
 -- MutArray Data Type
 -------------------------------------------------------------------------------
@@ -2439,10 +2426,10 @@
     -- memcpy is better than stream copy when the size is known.
     -- XXX We can implement a stream copy in a similar way by streaming Word64
     -- first and then remaining Word8.
-    arr <- new len
-    _ <- unsafeAsPtr arr
-            (\ptr -> liftIO $ c_memcpy ptr addr (fromIntegral len))
-    return (arr {arrEnd = len})
+    (arr :: MutArray Word8) <- emptyOf len
+    let mbarr = getMutableByteArray# (arrContents arr)
+    _ <- liftIO $ c_memcpy_pinned_src mbarr addr (fromIntegral len)
+    pure (arr { arrEnd = len })
 
 {-# INLINABLE fromByteStr# #-}
 fromByteStr# :: MonadIO m => Addr# -> m (MutArray Word8)
@@ -2453,11 +2440,8 @@
     -- version. https://github.com/bminor/glibc/blob/master/string/strlen.c
     -- XXX We can possibly use a stream of Word64 to do the same.
     -- fromByteStr# addr = fromPureStream (D.fromByteStr# addr)
-    len <- liftIO $ c_strlen (Ptr addr)
-    let lenInt = fromIntegral len
-    arr <- new lenInt
-    _ <- unsafeAsPtr arr (\ptr -> liftIO $ c_memcpy ptr (Ptr addr) len)
-    return (arr {arrEnd = lenInt})
+    len <- liftIO $ c_strlen_pinned addr
+    fromPtrN (fromIntegral len) (Ptr addr)
 
 -------------------------------------------------------------------------------
 -- convert a stream of arrays to a single array by reallocating and copying
@@ -2744,24 +2728,26 @@
 {-# INLINE breakOn #-}
 breakOn :: MonadIO m
     => Word8 -> MutArray Word8 -> m (MutArray Word8, Maybe (MutArray Word8))
-breakOn sep arr@MutArray{..} = unsafeAsPtr arr $ \p -> liftIO $ do
+breakOn sep arr@MutArray{..} = liftIO $ do
     -- XXX We do not need memchr here, we can use a Haskell equivalent.
     -- Need efficient stream based primitives that work on Word64.
-    loc <- c_memchr p sep (fromIntegral $ byteLength arr)
-    let sepIndex = loc `minusPtr` p
+    let marr = getMutableByteArray# arrContents
+        len = fromIntegral (arrEnd - arrStart)
+    sepIndex <- c_memchr_index marr (fromIntegral arrStart) sep len
+    let intIndex = fromIntegral sepIndex
     return $
-        if loc == nullPtr
+        if sepIndex >= len
         then (arr, Nothing)
         else
             ( MutArray
                 { arrContents = arrContents
                 , arrStart = arrStart
-                , arrEnd = arrStart + sepIndex -- exclude the separator
-                , arrBound = arrStart + sepIndex
+                , arrEnd = arrStart + intIndex -- exclude the separator
+                , arrBound = arrStart + intIndex
                 }
             , Just $ MutArray
                     { arrContents = arrContents
-                    , arrStart = arrStart + (sepIndex + 1)
+                    , arrStart = arrStart + (intIndex + 1)
                     , arrEnd = arrEnd
                     , arrBound = arrBound
                     }
@@ -2859,33 +2845,31 @@
 -- available e.g. a null terminated C string. However, we can create another
 -- flavor of the API e.g. asPtrN.
 
--- | Use a @MutArray a@ as @Ptr a@. This is useful when we want to pass an
--- array as a pointer to some operating system call or to a "safe" FFI call.
---
--- If the array is not pinned it is copied to pinned memory before passing it
--- to the monadic action.
---
--- /Performance Notes:/ Forces a copy if the array is not pinned. It is advised
--- that the programmer keeps this in mind and creates a pinned array
--- opportunistically before this operation occurs, to avoid the cost of a copy
--- if possible.
---
--- /Unsafe/ because of direct pointer operations. The user must ensure that
--- they are writing within the legal bounds of the array.
---
--- /Pre-release/
---
+-- | NOTE: this is deprecated because it can lead to accidental problems if the
+-- user tries to use it to mutate the array because it does not return the new
+-- array after pinning.
+{-# DEPRECATED unsafePinnedAsPtr "Pin the array and then use unsafeAsPtr." #-}
 {-# INLINE unsafePinnedAsPtr #-}
 unsafePinnedAsPtr :: MonadIO m => MutArray a -> (Ptr a -> m b) -> m b
-unsafePinnedAsPtr arr f =
-    Unboxed.unsafePinnedAsPtr
-        (arrContents arr) (\ptr -> f (ptr `plusPtr` arrStart arr))
+unsafePinnedAsPtr arr f = do
+    arr1 <- liftIO $ Unboxed.pin (arrContents arr)
+    Unboxed.unsafeAsPtr arr1 (\ptr -> f (ptr `plusPtr` arrStart arr))
 
-{-# DEPRECATED asPtrUnsafe "Please use unsafePinnedAsPtr instead." #-}
+{-# DEPRECATED asPtrUnsafe "Pin the array and then use unsafeAsPtr." #-}
 {-# INLINE asPtrUnsafe #-}
 asPtrUnsafe :: MonadIO m => MutArray a -> (Ptr a -> m b) -> m b
 asPtrUnsafe = unsafePinnedAsPtr
 
+-- | @unsafeAsPtr arr f@, f is a function used as @f ptr len@ where @ptr@ is a
+-- pointer to the beginning of array and @len@ is the length of the array.
+--
+-- /Unsafe/ WARNING:
+--
+-- 1. The array must be pinned, otherwise it will lead to memory corruption.
+-- 2. The user must not use the pointer beyond the supplied length.
+--
+-- /Pre-release/
+--
 {-# INLINE unsafeAsPtr #-}
 unsafeAsPtr :: MonadIO m => MutArray a -> (Ptr a -> m b) -> m b
 unsafeAsPtr arr f =
@@ -3316,3 +3300,28 @@
                         go x (i - 1)
                     _ -> putIndexUnsafe (i + 1) arr x
             else putIndexUnsafe (i + 1) arr x
+
+--------------------------------------------------------------------------------
+-- Deprecated Foreign APIs
+--------------------------------------------------------------------------------
+
+foreign import ccall unsafe "string.h memcpy" c_memcpy
+    :: Ptr Word8 -> Ptr Word8 -> CSize -> IO (Ptr Word8)
+
+{-# DEPRECATED c_memchr "c_memchr is now deprecated." #-}
+foreign import ccall unsafe "string.h memchr" c_memchr
+    :: Ptr Word8 -> Word8 -> CSize -> IO (Ptr Word8)
+
+foreign import ccall unsafe "string.h memcmp" c_memcmp
+    :: Ptr Word8 -> Ptr Word8 -> CSize -> IO CInt
+
+{-# DEPRECATED memcpy "Use copyMutableByteArray# instead." #-}
+memcpy :: Ptr Word8 -> Ptr Word8 -> Int -> IO ()
+memcpy dst src len = void (c_memcpy dst src (fromIntegral len))
+
+{-# DEPRECATED memcmp "Use byteCmp instead." #-}
+{-# INLINE memcmp #-}
+memcmp :: Ptr Word8 -> Ptr Word8 -> Int -> IO Bool
+memcmp p1 p2 len = do
+    r <- c_memcmp p1 p2 (fromIntegral len)
+    return $ r == 0
diff --git a/src/Streamly/Internal/Data/MutByteArray/Type.hs b/src/Streamly/Internal/Data/MutByteArray/Type.hs
--- a/src/Streamly/Internal/Data/MutByteArray/Type.hs
+++ b/src/Streamly/Internal/Data/MutByteArray/Type.hs
@@ -12,7 +12,6 @@
     (
     -- ** MutByteArray
       MutByteArray(..)
-    , MutableByteArray
     , getMutableByteArray# -- XXX getMutByteArray#
 
     -- ** Pinning
@@ -38,13 +37,14 @@
     , unsafeAsPtr
 
     -- ** Deprecated
+    , MutableByteArray
     , asPtrUnsafe
     , nil
     ) where
 
 import Control.Monad.IO.Class (MonadIO(..))
-#ifdef DEBUG
 import Control.Monad (when)
+#ifdef DEBUG
 import Debug.Trace (trace)
 #endif
 import GHC.Base (IO(..))
@@ -102,31 +102,15 @@
 -- guarantees that unsafe calls will be performed in the calling thread. Making
 -- it safe to pass heap-allocated objects to unsafe functions.
 
--- | Use a @MutByteArray@ as @Ptr a@. This is useful when we want to pass
--- an array as a pointer to some operating system call or to a "safe" FFI call.
---
--- If the array is not pinned it is copied to pinned memory before passing it
--- to the monadic action.
---
--- /Performance Notes:/ Forces a copy if the array is not pinned. It is advised
--- that the programmer keeps this in mind and creates a pinned array
--- opportunistically before this operation occurs, to avoid the cost of a copy
--- if possible.
---
--- /Unsafe/ because of direct pointer operations. The user must ensure that
--- they are writing within the legal bounds of the array.
---
--- /Pre-release/
---
+-- | NOTE: this is deprecated because it can lead to accidental problems if the
+-- user tries to use it to mutate the array because it does not return the new
+-- array after pinning.
+{-# DEPRECATED unsafePinnedAsPtr "Pin the array and then use unsafeAsPtr." #-}
 {-# INLINE unsafePinnedAsPtr #-}
 unsafePinnedAsPtr :: MonadIO m => MutByteArray -> (Ptr a -> m b) -> m b
 unsafePinnedAsPtr arr f = do
-  contents <- liftIO $ pin arr
-  let !ptr = Ptr (byteArrayContents#
-                     (unsafeCoerce# (getMutableByteArray# contents)))
-  r <- f ptr
-  liftIO $ touch contents
-  return r
+    arr1 <- liftIO $ pin arr
+    unsafeAsPtr arr1 f
 
 {-# DEPRECATED asPtrUnsafe "Please use unsafePinnedAsPtr instead." #-}
 {-# INLINE asPtrUnsafe #-}
@@ -137,11 +121,15 @@
 {-# INLINE unsafeAsPtr #-}
 unsafeAsPtr :: MonadIO m => MutByteArray -> (Ptr a -> m b) -> m b
 unsafeAsPtr arr f = do
-  let !ptr = Ptr (byteArrayContents#
+    when (not (isPinned arr))
+        $ error "unsafeAsPtr requires the array to be pinned"
+    let !ptr = Ptr (byteArrayContents#
                      (unsafeCoerce# (getMutableByteArray# arr)))
-  r <- f ptr
-  liftIO $ touch arr
-  return r
+    r <- f ptr
+    -- While f is using the bare pointer, the MutByteArray may be garbage
+    -- collected by the GC, tell the GC that we are still using it.
+    liftIO $ touch arr
+    return r
 
 --------------------------------------------------------------------------------
 -- Creation
diff --git a/src/Streamly/Internal/Data/Serialize/TH.hs b/src/Streamly/Internal/Data/Serialize/TH.hs
--- a/src/Streamly/Internal/Data/Serialize/TH.hs
+++ b/src/Streamly/Internal/Data/Serialize/TH.hs
@@ -28,6 +28,7 @@
 
 import Data.List (foldl')
 import Data.Word (Word16, Word32, Word64, Word8)
+import Data.Foldable (length)
 
 import Language.Haskell.TH
 import Language.Haskell.TH.Syntax
@@ -44,6 +45,7 @@
 import Streamly.Internal.Data.Serialize.TH.Bottom
 import Streamly.Internal.Data.Serialize.TH.Common
 import Streamly.Internal.Data.Serialize.TH.RecHeader
+import Prelude hiding (Foldable(..))
 
 --------------------------------------------------------------------------------
 -- Domain specific helpers
diff --git a/src/Streamly/Internal/Data/Serialize/TH/Bottom.hs b/src/Streamly/Internal/Data/Serialize/TH/Bottom.hs
--- a/src/Streamly/Internal/Data/Serialize/TH/Bottom.hs
+++ b/src/Streamly/Internal/Data/Serialize/TH/Bottom.hs
@@ -57,6 +57,7 @@
 import Data.Maybe (isJust)
 import Data.Char (chr, ord)
 import Data.List (foldl')
+import Data.Foldable (length)
 import Data.Word (Word16, Word32, Word64, Word8)
 import Data.Bits (Bits, (.|.), shiftL, zeroBits, xor)
 import Streamly.Internal.System.IO (unsafeInlineIO)
@@ -69,6 +70,7 @@
 import qualified Streamly.Internal.Data.Unbox as Unbox
 
 import Streamly.Internal.Data.Unbox.TH (DataCon(..))
+import Prelude hiding (Foldable(..))
 
 --------------------------------------------------------------------------------
 -- Config
diff --git a/src/Streamly/Internal/Data/Serialize/TH/RecHeader.hs b/src/Streamly/Internal/Data/Serialize/TH/RecHeader.hs
--- a/src/Streamly/Internal/Data/Serialize/TH/RecHeader.hs
+++ b/src/Streamly/Internal/Data/Serialize/TH/RecHeader.hs
@@ -22,6 +22,7 @@
 
 import Control.Monad (void)
 import Data.List (foldl')
+import Data.Foldable (length, sum)
 import Data.Word (Word32, Word8)
 import Data.Maybe (fromJust)
 import Language.Haskell.TH
@@ -34,6 +35,7 @@
 
 import Streamly.Internal.Data.Serialize.TH.Bottom
 import Streamly.Internal.Data.Serialize.TH.Common
+import Prelude hiding (Foldable(..))
 
 --------------------------------------------------------------------------------
 -- Notes
@@ -353,7 +355,7 @@
                      ([], dataOff)
                      keys
              $(varP finalRec) <-
-                 $(foldl
+                 $(foldl'
                        (\acc i ->
                             [|$(acc) <*>
                               $(deserializeFieldExpr i)|])
diff --git a/src/Streamly/Internal/Data/Serialize/Type.hs b/src/Streamly/Internal/Data/Serialize/Type.hs
--- a/src/Streamly/Internal/Data/Serialize/Type.hs
+++ b/src/Streamly/Internal/Data/Serialize/Type.hs
@@ -31,6 +31,7 @@
 import qualified Streamly.Internal.Data.MutArray as MutArray
 
 import GHC.Exts
+import Prelude hiding (Foldable(..))
 
 --------------------------------------------------------------------------------
 -- Developer Note
diff --git a/src/Streamly/Internal/Data/Unbox.hs b/src/Streamly/Internal/Data/Unbox.hs
--- a/src/Streamly/Internal/Data/Unbox.hs
+++ b/src/Streamly/Internal/Data/Unbox.hs
@@ -54,7 +54,9 @@
 import GHC.Real (Ratio(..))
 import GHC.Stable (StablePtr(..))
 import GHC.Word (Word16(..), Word32(..), Word64(..), Word8(..))
-#if MIN_VERSION_base(4,15,0)
+#if MIN_VERSION_base(4,21,0)
+import GHC.IO.SubSystem (IoSubSystem (..))
+#elif MIN_VERSION_base(4,15,0)
 import GHC.RTS.Flags (IoSubSystem(..))
 #endif
 import Streamly.Internal.Data.Builder (Builder (..))
diff --git a/src/Streamly/Internal/FileSystem/Handle.hs b/src/Streamly/Internal/FileSystem/Handle.hs
--- a/src/Streamly/Internal/FileSystem/Handle.hs
+++ b/src/Streamly/Internal/FileSystem/Handle.hs
@@ -179,7 +179,8 @@
 getChunk size h = liftIO $ do
     arr :: MArray.MutArray Word8 <- MArray.pinnedEmptyOf size
     -- ptr <- mallocPlainForeignPtrAlignedBytes size (alignment (undefined :: Word8))
-    MArray.unsafePinnedAsPtr arr $ \p -> do
+    -- Since the array is pinned (pinnedEmptyOf) we can safely use unsafeAsPtr
+    MArray.unsafeAsPtr arr $ \p -> do
         n <- hGetBufSome h p size
         -- XXX shrink only if the diff is significant
         return $
diff --git a/streamly-core.cabal b/streamly-core.cabal
--- a/streamly-core.cabal
+++ b/streamly-core.cabal
@@ -1,6 +1,6 @@
 cabal-version:      2.2
 name:               streamly-core
-version:            0.2.2
+version:            0.2.3
 synopsis:           Streaming, parsers, arrays, serialization and more
 description:
   For upgrading to streamly-0.9.0+ please read the
@@ -69,6 +69,8 @@
                    , GHC==9.4.7
                    , GHC==9.6.3
                    , GHC==9.8.1
+                   , GHC==9.10.1
+                   , GHC==9.12.1
 author:              Composewell Technologies
 maintainer:          streamly@composewell.com
 copyright:           2017 Composewell Technologies
@@ -117,6 +119,7 @@
     docs/ApiChangelogs/0.1.0.txt
     docs/ApiChangelogs/0.1.0-0.2.0.txt
     docs/ApiChangelogs/0.2.0-0.2.2.txt
+    docs/ApiChangelogs/0.2.2-0.2.3.txt
 
 source-repository head
     type: git
@@ -294,6 +297,8 @@
         , src/Streamly/Internal/Data/Array
         , src/Streamly/Internal/Data/Stream
 
+    c-sources: src/Streamly/Internal/Data/MutArray/Lib.c
+
     if os(windows)
       c-sources:     src/Streamly/Internal/Data/Time/Clock/Windows.c
 
@@ -499,15 +504,15 @@
                     -- packages depending on the "ghc" package (packages
                     -- depending on doctest is a common example) can
                     -- depend on streamly.
-                       ghc-prim          >= 0.5.3 && < 0.12
+                       ghc-prim          >= 0.5.3 && < 0.14
                      , fusion-plugin-types >= 0.1 && < 0.2
-                     , base              >= 4.12  && < 4.20
+                     , base              >= 4.12  && < 4.22
                      , exceptions        >= 0.8.0 && < 0.11
                      , transformers      >= 0.5.5 && < 0.7
                      , filepath          >= 1.4.2 && < 1.6
 
                     -- streamly-unicode-core
-                     , template-haskell  >= 2.14  && < 2.22
+                     , template-haskell  >= 2.14  && < 2.24
 
                      -- streamly-filesystem-core
                      , directory         >= 1.3.3 && < 1.4
