Skip to content

Commit 26a1c33

Browse files
authored
Fix space leak in Lazy.fromListWith (#386)
Fixes #382
1 parent a40fcc7 commit 26a1c33

File tree

2 files changed

+24
-5
lines changed

2 files changed

+24
-5
lines changed

Data/HashMap/Internal.hs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1026,11 +1026,11 @@ insertModifyingArr x f k0 ary0 = go k0 ary0 0 (A.length ary0)
10261026
unsafeInsertWith :: forall k v. (Eq k, Hashable k)
10271027
=> (v -> v -> v) -> k -> v -> HashMap k v
10281028
-> HashMap k v
1029-
unsafeInsertWith f k0 v0 m0 = unsafeInsertWithKey (const f) k0 v0 m0
1029+
unsafeInsertWith f k0 v0 m0 = unsafeInsertWithKey (\_ a b -> (# f a b #)) k0 v0 m0
10301030
{-# INLINABLE unsafeInsertWith #-}
10311031

10321032
unsafeInsertWithKey :: forall k v. (Eq k, Hashable k)
1033-
=> (k -> v -> v -> v) -> k -> v -> HashMap k v
1033+
=> (k -> v -> v -> (# v #)) -> k -> v -> HashMap k v
10341034
-> HashMap k v
10351035
unsafeInsertWithKey f k0 v0 m0 = runST (go h0 k0 v0 0 m0)
10361036
where
@@ -1039,7 +1039,8 @@ unsafeInsertWithKey f k0 v0 m0 = runST (go h0 k0 v0 0 m0)
10391039
go !h !k x !_ Empty = return $! Leaf h (L k x)
10401040
go h k x s t@(Leaf hy l@(L ky y))
10411041
| hy == h = if ky == k
1042-
then return $! Leaf h (L k (f k x y))
1042+
then case f k x y of
1043+
(# v #) -> return $! Leaf h (L k v)
10431044
else return $! collision h l (L k x)
10441045
| otherwise = two s h k x hy t
10451046
go h k x s t@(BitmapIndexed b ary)
@@ -1060,7 +1061,7 @@ unsafeInsertWithKey f k0 v0 m0 = runST (go h0 k0 v0 0 m0)
10601061
return t
10611062
where i = index h s
10621063
go h k x s t@(Collision hy v)
1063-
| h == hy = return $! Collision h (updateOrSnocWithKey (\key a b -> (# f key a b #) ) k x v)
1064+
| h == hy = return $! Collision h (updateOrSnocWithKey f k x v)
10641065
| otherwise = go h k x s $ BitmapIndexed (mask hy s) (A.singleton t)
10651066
{-# INLINABLE unsafeInsertWithKey #-}
10661067

@@ -2104,7 +2105,7 @@ fromListWith f = List.foldl' (\ m (k, v) -> unsafeInsertWith f k v m) empty
21042105
--
21052106
-- @since 0.2.11
21062107
fromListWithKey :: (Eq k, Hashable k) => (k -> v -> v -> v) -> [(k, v)] -> HashMap k v
2107-
fromListWithKey f = List.foldl' (\ m (k, v) -> unsafeInsertWithKey f k v m) empty
2108+
fromListWithKey f = List.foldl' (\ m (k, v) -> unsafeInsertWithKey (\k' a b -> (# f k' a b #)) k v m) empty
21082109
{-# INLINE fromListWithKey #-}
21092110

21102111
------------------------------------------------------------------------

tests/Regressions.hs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,23 @@ issue381mapMaybeWithKey = do
208208

209209
#endif
210210

211+
------------------------------------------------------------------------
212+
-- Issue #382
213+
214+
issue382 :: Assertion
215+
issue382 = do
216+
i :: Int <- randomIO
217+
let k = SC (show i)
218+
weakK <- mkWeakPtr k Nothing -- add the ability to test whether k is alive
219+
let f :: Int -> Int -> Int
220+
f x = error ("Should not be evaluated " ++ show x)
221+
let m = HML.fromListWith f [(k, 1), (k, 2)]
222+
Just v <- evaluate $ HML.lookup k m
223+
performGC
224+
res <- deRefWeak weakK -- gives Just if k is still alive
225+
touch v -- makes sure that we didn't GC away the combined value
226+
assert $ isNothing res
227+
211228
------------------------------------------------------------------------
212229
-- * Test list
213230

@@ -233,4 +250,5 @@ tests = testGroup "Regression tests"
233250
, testCase "mapMaybeWithKey" issue381mapMaybeWithKey
234251
]
235252
#endif
253+
, testCase "issue382" issue382
236254
]

0 commit comments

Comments
 (0)