on master help sign in
Make bounds checking safer
d84a2ecBryan O'Sullivan
Data/Text.hs+27−12
@@ -174,7 +174,7 @@ import Prelude (Char, Bool(..), Functor(..), Int, Maybe(..), String,
174 Eq(..), Ord(..), Ordering(..), (++),
174 Eq(..), Ord(..), Ordering(..), (++),
175 Read(..), Show(..),
175 Read(..), Show(..),
176 (&&), (||), (+), (-), (.), ($), ($!), (>>), (*),
176 (&&), (||), (+), (-), (.), ($), ($!), (>>), (*),
177− div, error, not, return, otherwise)
177+ div, maxBound, not, return, otherwise)
178#if defined(HAVE_DEEPSEQ)
178#if defined(HAVE_DEEPSEQ)
179import Control.DeepSeq (NFData)
179import Control.DeepSeq (NFData)
180#endif
180#endif
@@ -294,8 +294,8 @@ instance NFData Text
294
294
295instance Data Text where
295instance Data Text where
296 gfoldl f z txt = z pack `f` (unpack txt)
296 gfoldl f z txt = z pack `f` (unpack txt)
297− toConstr _ = error "Data.Text.Text.toConstr"
297+ toConstr _ = P.error "Data.Text.Text.toConstr"
298− gunfold _ _ = error "Data.Text.Text.gunfold"
298+ gunfold _ _ = P.error "Data.Text.Text.gunfold"
299#if __GLASGOW_HASKELL__ >= 612
299#if __GLASGOW_HASKELL__ >= 612
300 dataTypeOf _ = mkNoRepType "Data.Text.Text"
300 dataTypeOf _ = mkNoRepType "Data.Text.Text"
301#else
301#else
@@ -340,7 +340,11 @@ snoc t c = unstream (S.snoc (stream t) c)
340-- | /O(n)/ Appends one 'Text' to the other by copying both of them
340-- | /O(n)/ Appends one 'Text' to the other by copying both of them
341-- into a new 'Text'. Subject to fusion.
341-- into a new 'Text'. Subject to fusion.
342append :: Text -> Text -> Text
342append :: Text -> Text -> Text
343−append (Text arr1 off1 len1) (Text arr2 off2 len2) = Text (A.run x) 0 len
343+append a@(Text arr1 off1 len1) b@(Text arr2 off2 len2)
344+ | len1 == 0 = b
345+ | len2 == 0 = a
346+ | len > 0 = Text (A.run x) 0 len
347+ | otherwise = overflowError "append"
344 where
348 where
345 len = len1+len2
349 len = len1+len2
346 x = do
350 x = do
@@ -706,7 +710,7 @@ concat ts = case ts' of
706 _ -> Text (A.run go) 0 len
710 _ -> Text (A.run go) 0 len
707 where
711 where
708 ts' = L.filter (not . null) ts
712 ts' = L.filter (not . null) ts
709− len = L.sum $ L.map lengthWord16 ts'
713+ len = sumP "concat" $ L.map lengthWord16 ts'
710 go = do
714 go = do
711 arr <- A.new len
715 arr <- A.new len
712 let step i (Text a o l) =
716 let step i (Text a o l) =
@@ -804,12 +808,11 @@ mapAccumR f z0 = second reverse . S.mapAccumL f z0 . reverseStream
804-- @t@ repeated @n@ times.
808-- @t@ repeated @n@ times.
805replicate :: Int -> Text -> Text
809replicate :: Int -> Text -> Text
806replicate n t@(Text a o l)
810replicate n t@(Text a o l)
807− | n <= 0 || l <= 0 = empty
811+ | n <= 0 || l <= 0 = empty
808− | n == 1 = t
812+ | n == 1 = t
809− | isSingleton t = replicateChar n (unsafeHead t)
813+ | isSingleton t = replicateChar n (unsafeHead t)
810− | len < n = error $ "Data.Text.replicate: invalid length " ++
811− show n -- multiplication overflow
812− | otherwise = Text (A.run x) 0 len
814+ | n <= maxBound `div` l = Text (A.run x) 0 len
815+ | otherwise = overflowError "replicate"
813 where
816 where
814 len = l * n
817 len = l * n
815 x = do
818 x = do
@@ -1440,5 +1443,17 @@ stripSuffix p@(Text _arr _off plen) t@(Text arr off len)
1440 | p `isSuffixOf` t = Just $! textP arr off (len-plen)
1443 | p `isSuffixOf` t = Just $! textP arr off (len-plen)
1441 | otherwise = Nothing
1444 | otherwise = Nothing
1442
1445
1446+-- | Add a list of non-negative numbers. Errors out on overflow.
1447+sumP :: String -> [Int] -> Int
1448+sumP fun = go 0
1449+ where go !a (x:xs)
1450+ | ax >= 0 = go ax xs
1451+ | otherwise = overflowError fun
1452+ where ax = a + x
1453+ go a _ = a
1454+
1443emptyError :: String -> a
1455emptyError :: String -> a
1444−emptyError fun = P.error ("Data.Text." ++ fun ++ ": empty input")
1456+emptyError fun = P.error $ "Data.Text." ++ fun ++ ": empty input"
1457+
1458+overflowError :: String -> a
1459+overflowError fun = P.error $ "Data.Text." ++ fun ++ ": size overflow"
Data/Text/Array.hs+4−3
@@ -59,7 +59,7 @@ if (_k_) < 0 || (_k_) >= (_len_) then error ("Data.Text.Array." ++ (_func_) ++ "
59#if defined(ASSERTS)
59#if defined(ASSERTS)
60import Control.Exception (assert)
60import Control.Exception (assert)
61#endif
61#endif
62−import Data.Bits ((.&.))
62+import Data.Bits ((.&.), xor)
63import Data.Text.UnsafeShift (shiftL, shiftR)
63import Data.Text.UnsafeShift (shiftL, shiftR)
64import GHC.Base (ByteArray#, MutableByteArray#, Int(..),
64import GHC.Base (ByteArray#, MutableByteArray#, Int(..),
65 indexWord16Array#, indexWordArray#, newByteArray#,
65 indexWord16Array#, indexWordArray#, newByteArray#,
@@ -103,7 +103,7 @@ instance IArray (MArray s) where
103-- | Create an uninitialized mutable array.
103-- | Create an uninitialized mutable array.
104new :: forall s. Int -> ST s (MArray s)
104new :: forall s. Int -> ST s (MArray s)
105new n
105new n
106− | len < n = error $ "Data.Text.Array.unsafeNew: invalid length " ++ show n
106+ | n < 0 || n .&. highBit /= 0 = error $ "Data.Text.Array.new: size overflow"
107 | otherwise = ST $ \s1# ->
107 | otherwise = ST $ \s1# ->
108 case newByteArray# len# s1# of
108 case newByteArray# len# s1# of
109 (# s2#, marr# #) -> (# s2#, MArray marr#
109 (# s2#, marr# #) -> (# s2#, MArray marr#
@@ -111,7 +111,8 @@ new n
111 n
111 n
112#endif
112#endif
113 #)
113 #)
114− where !len@(I# len#) = bytesInArray n
114+ where !(I# len#) = bytesInArray n
115+ highBit = maxBound `xor` (maxBound `shiftR` 1)
115{-# INLINE new #-}
116{-# INLINE new #-}
116
117
117-- | Freeze a mutable array. Do not mutate the 'MArray' afterwards!
118-- | Freeze a mutable array. Do not mutate the 'MArray' afterwards!