Bug 196935 - Add an overflow check to HashTable
Summary: Add an overflow check to HashTable
Status: NEW
Alias: None
Product: WebKit
Classification: Unclassified
Component: Web Template Framework (show other bugs)
Version: WebKit Nightly Build
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Ryosuke Niwa
URL:
Keywords: InRadar
Depends on: 197000
Blocks:
  Show dependency treegraph
 
Reported: 2019-04-15 14:30 PDT by Ryosuke Niwa
Modified: 2019-04-16 22:23 PDT (History)
12 users (show)

See Also:


Attachments
Fixes the bug (11.30 KB, patch)
2019-04-15 20:32 PDT, Ryosuke Niwa
ggaren: review+
Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Ryosuke Niwa 2019-04-15 14:30:16 PDT
We should check for an integer overflow when expanding HashTable.
Comment 1 Ryosuke Niwa 2019-04-15 20:32:15 PDT
Created attachment 367492 [details]
Fixes the bug
Comment 2 Radar WebKit Bug Importer 2019-04-15 20:33:01 PDT
<rdar://problem/49928688>
Comment 3 Geoffrey Garen 2019-04-15 21:17:20 PDT
Comment on attachment 367492 [details]
Fixes the bug

View in context: https://bugs.webkit.org/attachment.cgi?id=367492&action=review

r=me

> Source/WTF/wtf/HashTable.h:1206
> +        Checked<unsigned, CrashOnOverflow> bestTableSize = WTF::roundUpToPowerOfTwo(keyCount);
> +        if (bestTableSize.unsafeGet() < keyCount)
> +            bestTableSize.overflowed();
> +        bestTableSize *= 2;

If we needed a check here, I would recommend doing using Checked<T>.

But we don't need this less-than check. roundUpToPowerOfTwo(2^32) is 2^32. There's no overflow case.

I think I would write this as

    auto bestTableSize = Checked<unsigned, CrashOnOverflow>(WTF::roundUpToPowerOfTwo(keyCount)) * 2;
Comment 4 Ryosuke Niwa 2019-04-15 21:45:57 PDT
(In reply to Geoffrey Garen from comment #3)
> Comment on attachment 367492 [details]
> Fixes the bug
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=367492&action=review
> 
> r=me
> 
> > Source/WTF/wtf/HashTable.h:1206
> > +        Checked<unsigned, CrashOnOverflow> bestTableSize = WTF::roundUpToPowerOfTwo(keyCount);
> > +        if (bestTableSize.unsafeGet() < keyCount)
> > +            bestTableSize.overflowed();
> > +        bestTableSize *= 2;
> 
> If we needed a check here, I would recommend doing using Checked<T>.
> 
> But we don't need this less-than check. roundUpToPowerOfTwo(2^32) is 2^32.
> There's no overflow case.

Hm... roundUpToPowerOfTwo(0x8fffffff) is 0 though. Do we have some guarantee that 0x80000000 would be the maximum key count?
Comment 5 Geoffrey Garen 2019-04-16 10:55:41 PDT
> > If we needed a check here, I would recommend doing using Checked<T>.
> > 
> > But we don't need this less-than check. roundUpToPowerOfTwo(2^32) is 2^32.
> > There's no overflow case.
> 
> Hm... roundUpToPowerOfTwo(0x8fffffff) is 0 though. Do we have some guarantee
> that 0x80000000 would be the maximum key count?

Eep! I have immortalized in Bugzilla my inability to do binary arithmetic. Don't tell Gavin. :)

I think the problem input case is anything in the range (0x80000000, 0xffffffff], which is (2^31, 2^32-1]. In that case, the correct answer is 0x0000000100000000, which is not representable as uint32_t. And the implementation of roundUpToPowerOfTwo() will happen to return 0 (as you said).

Maybe the right solution is to templatize roundUpToPowerOfTwo() to accept uint32_t or Checked<uint32_t>, so it can naturally catch the overflow to zero on the final ++ operation?

I'm open to any solution that doesn't require an explicit check in the calling code. That's the primary benefit of Checked<T>.
Comment 6 Ryosuke Niwa 2019-04-16 21:03:35 PDT
Interesting, in the process of adding Checked<U, V> support to roundUpToPowerOfTwo, I found out that CachedTypes::malloc converts size_t to uint32_t that's probably a bug...