Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Strict.alterFEager too lazy when inserting new key #383

Closed
sjakobi opened this issue Mar 19, 2022 · 1 comment · Fixed by #384
Closed

Strict.alterFEager too lazy when inserting new key #383

sjakobi opened this issue Mar 19, 2022 · 1 comment · Fixed by #384
Assignees
Labels

Comments

@sjakobi
Copy link
Member

sjakobi commented Mar 19, 2022

-- | This is the default version of alterF that we use in most non-trivial
-- cases. It's called "eager" because it looks up the given key in the map
-- eagerly, whether or not the given function requires that information.
alterFEager :: (Functor f, Eq k, Hashable k)
=> (Maybe v -> f (Maybe v)) -> k -> HashMap k v -> f (HashMap k v)
alterFEager f !k !m = (<$> f mv) $ \fres ->
case fres of
------------------------------
-- Delete the key from the map.
Nothing -> case lookupRes of
-- Key did not exist in the map to begin with, no-op
Absent -> m
-- Key did exist, no collision
Present _ collPos -> deleteKeyExists collPos h k m
------------------------------
-- Update value
Just v' -> case lookupRes of
-- Key did not exist before, insert v' under a new key
Absent -> insertNewKey h k v' m
-- Key existed before, no hash collision
Present v collPos -> v' `seq`
if v `ptrEq` v'
-- If the value is identical, no-op
then m
-- If the value changed, update the value.
else insertKeyExists collPos h k v' m
where !h = hash k
!lookupRes = lookupRecordCollision h k m
!mv = case lookupRes of
Absent -> Nothing
Present v _ -> Just v
{-# INLINABLE alterFEager #-}

The problem is in lines 404–407: v' is never forced.

I wonder whether confusion about the strictness of insertNewKey may have led to this bug. Although this function doesn't have a module prefix, it is imported from Data.HashMap.Internal. The code author may have thought that they were using a local, strict version of insertNewKey.

@sjakobi sjakobi added the bug label Mar 19, 2022
sjakobi added a commit that referenced this issue Mar 20, 2022
sjakobi added a commit that referenced this issue Mar 20, 2022
@sjakobi
Copy link
Member Author

sjakobi commented Mar 20, 2022

Judging by the commit message of 85e11c7, the strictness properties of this code already seemed dubious when it was introduced:

Open questions/follow-ups:

  • [...]
  • Verify that strictness is enforced properly in Data.HashMap.Strict.alterF.

It's pretty disappointing that no one even bothered to record this task on the issue tracker. :(

@sjakobi sjakobi self-assigned this Mar 20, 2022
sjakobi added a commit that referenced this issue Mar 21, 2022
sjakobi added a commit that referenced this issue Mar 21, 2022
sjakobi added a commit that referenced this issue Mar 21, 2022
sjakobi added a commit that referenced this issue Mar 23, 2022
sjakobi added a commit that referenced this issue Mar 23, 2022
sjakobi added a commit that referenced this issue Mar 23, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant