on master help sign in
Add array boundary checks during serialization
commit31a679a7d912a30b70e5d69ed874823d658a0f14 authorHarendra Kumar <harendra@composewell.com> dateWed 16 Aug 2023, 12:01 (3 years ago) parentf7f42e0
2 files changed+33−8
core/src/Streamly/Internal/Data/Serialize.hs+32−6 core/src/Streamly/Internal/Data/Unbox.hs+1−2
core/src/Streamly/Internal/Data/Serialize.hs+32−6
@@ -20,6 +20,11 @@ module Streamly.Internal.Data.Serialize
2020
2121#include "assert.hs"
2222
23+#ifdef DEBUG
24+import Control.Exception (assert)
25+import Streamly.Internal.Data.Unbox (Unbox(..), sizeOfMutableByteArray)
26+#endif
27+
2328import Control.Monad (void)
2429import Data.List (foldl')
2530import Data.Proxy (Proxy (..))
@@ -105,20 +110,41 @@ class Serialize a where
105110-- Instances
106111--------------------------------------------------------------------------------
107112
113+{-# INLINE checkBounds #-}
114+checkBounds :: String -> Int -> MutableByteArray -> IO ()
115+checkBounds _label _off _arr = do
116+#ifdef DEBUG
117+ sz <- sizeOfMutableByteArray _arr
118+ if (_off > sz)
119+ then error
120+ $ _label
121+ ++ ": accessing array at offset = "
122+ ++ show (_off - 1)
123+ ++ " max valid offset = " ++ show (sz - 1)
124+ else return ()
125+#else
126+ return ()
127+#endif
128+
108129#define DERIVE_SERIALIZE_FROM_UNBOX(_type) \
109130instance Serialize _type where \
110131; {-# INLINE size #-} \
111132; size = Size (\acc _ -> acc + Unbox.sizeOf (Proxy :: Proxy _type)) \
112133; {-# INLINE deserialize #-} \
113134; deserialize off arr = \
114− Unbox.peekByteIndex off arr >>= \
115− \val -> let sz = Unbox.sizeOf (Proxy :: Proxy _type) \
116− in pure (off + sz, val) \
135+ let next = off + Unbox.sizeOf (Proxy :: Proxy _type) \
136+ in do { \
137+ checkBounds "deserialize" next arr; \
138+ Unbox.peekByteIndex off arr >>= \val -> pure (next, val); \
139+ } \
117140; {-# INLINE serialize #-} \
118141; serialize off arr val = \
119− Unbox.pokeByteIndex off arr val \
120− >> let sz = Unbox.sizeOf (Proxy :: Proxy _type) \
121− in pure (off + sz)
142+ let next = off + Unbox.sizeOf (Proxy :: Proxy _type) \
143+ in do { \
144+ checkBounds "serialize" next arr; \
145+ Unbox.pokeByteIndex off arr val; \
146+ pure next \
147+ }
122148
123149DERIVE_SERIALIZE_FROM_UNBOX(Bool)
124150DERIVE_SERIALIZE_FROM_UNBOX(Char)
core/src/Streamly/Internal/Data/Unbox.hs+1−2
@@ -17,6 +17,7 @@ module Streamly.Internal.Data.Unbox
1717 , MutableByteArray(..)
1818 , touch
1919 , getMutableByteArray#
20+ , sizeOfMutableByteArray
2021 , isPinned
2122 , pin
2223 , unpin
@@ -100,7 +101,6 @@ touch :: MutableByteArray -> IO ()
100101touch (MutableByteArray contents) =
101102 IO $ \s -> case touch# contents s of s' -> (# s', () #)
102103
103−{-
104104-- | Return the size of the array in bytes.
105105{-# INLINE sizeOfMutableByteArray #-}
106106sizeOfMutableByteArray :: MutableByteArray -> IO Int
@@ -108,7 +108,6 @@ sizeOfMutableByteArray (MutableByteArray arr) =
108108 IO $ \s ->
109109 case getSizeofMutableByteArray# arr s of
110110 (# s1, i #) -> (# s1, I# i #)
111−-}
112111
113112--------------------------------------------------------------------------------
114113-- Creation