Bug 216501 - Segfault in WebCore::IDBKey::createBinary
Summary: Segfault in WebCore::IDBKey::createBinary
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: WebCore JavaScript (show other bugs)
Version: WebKit Nightly Build
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Michael Saboff
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2020-09-14 16:19 PDT by Michael Saboff
Modified: 2020-10-01 08:02 PDT (History)
10 users (show)

See Also:


Attachments
Patch (4.57 KB, patch)
2020-09-15 15:47 PDT, Michael Saboff
no flags Details | Formatted Diff | Diff
Updated Patch (4.49 KB, patch)
2020-09-17 09:49 PDT, Michael Saboff
youennf: review+
Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Michael Saboff 2020-09-14 16:19:10 PDT
The script below crashes due to code IDBKey::createBinary(JSC::JSArrayBufferView&) not handling the case where we can't get a buffer view due to running out of memory.

-- test.html --
<script>
const a = [];
a.length = 2**30
a.__proto__ = {};
Object.defineProperty(a, 0, { get: foo });
function foo() {
  new Uint8Array(a);
}

try {
  foo();
} catch {}

try {
  while(1) {
    new ArrayBuffer(2**20);
  }
} catch {}

let u8 = new Uint8Array();
IDBKeyRange.only(u8);
</script>

Steps To Reproduce:

DYLD_FRAMEWORK_PATH=<WEBKIT_PATH>/WebKitBuild/Debug <WEBKIT_PATH>/WebKitBuild/Debug/WebKitTestRunner test.html

Results:

Crashed Thread:        0  Dispatch queue: com.apple.main-thread

Exception Type:        EXC_BAD_ACCESS (SIGSEGV)
Exception Codes:       KERN_INVALID_ADDRESS at 0x0000000000000020
Exception Note:        EXC_CORPSE_NOTIFY


Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0   com.apple.WebCore                   0x00000004a14631fa WebCore::IDBKey::createBinary(JSC::JSArrayBufferView&) + 42
1   com.apple.WebCore                   0x00000004a19abe62 WebCore::createIDBKeyFromValue(JSC::JSGlobalObject&, JSC::JSValue, WTF::Vector<JSC::JSArray*, 0ul, WTF::CrashOnOverflow, 16ul, WTF::FastMalloc>&) + 2178
2   com.apple.WebCore                   0x00000004a197ee62 WebCore::scriptValueToIDBKey(JSC::JSGlobalObject&, JSC::JSValue) + 34
3   com.apple.WebCore                   0x00000004a147098a WebCore::IDBKeyRange::only(JSC::JSGlobalObject&, JSC::JSValue) + 122
4   com.apple.WebCore                   0x00000004a097090f WebCore::jsIDBKeyRangeConstructorFunctionOnly(JSC::JSGlobalObject*, JSC::CallFrame*) + 287
5   ???                                 0x0000251383201178 0 + 40765734523256
6   com.apple.JavaScriptCore            0x00000004a9a451b1 llint_entry + 120103
Comment 1 Michael Saboff 2020-09-14 16:19:37 PDT
<rdar://problem/68498785>
Comment 2 Michael Saboff 2020-09-15 15:47:40 PDT
Created attachment 408869 [details]
Patch
Comment 3 Yusuke Suzuki 2020-09-15 19:00:39 PDT
Comment on attachment 408869 [details]
Patch

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

> LayoutTests/storage/indexeddb/IDBKey-create-array-buffer-view-oom.html:44
> +shouldBeTrue("exceptionString == undefined || exceptionString === 'DataError: Provided data is inadequate.'");

If this happened, shouldn't we throw out-of-memory error instead of DataError?
Comment 4 Michael Saboff 2020-09-15 19:16:47 PDT
(In reply to Yusuke Suzuki from comment #3)
> Comment on attachment 408869 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=408869&action=review
> 
> > LayoutTests/storage/indexeddb/IDBKey-create-array-buffer-view-oom.html:44
> > +shouldBeTrue("exceptionString == undefined || exceptionString === 'DataError: Provided data is inadequate.'");
> 
> If this happened, shouldn't we throw out-of-memory error instead of
> DataError?

That error is existing when the key range source is invalid.  This fix uses that existing error path.  The test code catches and throws away two out-of-memory errors before getting to this point.

We could specifically throw out-of-memory, but I suspect that would be a riskier fix.
Comment 5 youenn fablet 2020-09-16 00:10:11 PDT
Comment on attachment 408869 [details]
Patch

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

> Source/WebCore/Modules/indexeddb/IDBKey.cpp:56
> +        return adoptRef(*new IDBKey());

Can we try returning nullptr here as a RefPtr<IDBKey>?
If we are low on memory, it seems best to not allocate a new object.
Might be a bigger change though.
Comment 6 Saam Barati 2020-09-16 10:30:44 PDT
Comment on attachment 408869 [details]
Patch

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

>> Source/WebCore/Modules/indexeddb/IDBKey.cpp:56
>> +        return adoptRef(*new IDBKey());
> 
> Can we try returning nullptr here as a RefPtr<IDBKey>?
> If we are low on memory, it seems best to not allocate a new object.
> Might be a bigger change though.

I agree this seems cleaner, given this now can fail. It's nicer to document things using nullability.
Comment 7 Michael Saboff 2020-09-16 18:09:39 PDT
(In reply to youenn fablet from comment #5)
> Comment on attachment 408869 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=408869&action=review
> 
> > Source/WebCore/Modules/indexeddb/IDBKey.cpp:56
> > +        return adoptRef(*new IDBKey());
> 
> Can we try returning nullptr here as a RefPtr<IDBKey>?
> If we are low on memory, it seems best to not allocate a new object.
> Might be a bigger change though.

Are you suggesting we change
    Ref<IDBKey> createBinary(JSC::JSArrayBufferView&)
to
    RefPtr<IDBKey> createBinary(JSC::JSArrayBufferView&)

If so, it seems weird to have two different return types for the overloaded createBinary(...) methods.

If not, there isn't a way to convert a RefPtr<IDBKey>(nullptr) into a Ref<IDBKey>.

This code is only being called by createIDBKeyFromValue() (via createIDBKeyFromValue()) which return IDBKey::createInvalid() aka adoptRef(*new IDBKey()) for a key with the value of RefPtr<IDBKey>(nullptr).  So we aren't avoiding the allocation, only delaying it.
Comment 8 youenn fablet 2020-09-16 23:21:48 PDT
Comment on attachment 408869 [details]
Patch

> Are you suggesting we change
>     Ref<IDBKey> createBinary(JSC::JSArrayBufferView&)
> to
>     RefPtr<IDBKey> createBinary(JSC::JSArrayBufferView&)
> 
> If so, it seems weird to have two different return types for the overloaded createBinary(...) methods.

We could introduce tryCreateBinary.
Or at least return IDBKey::createInvalid() which seems a bit clearer.
Comment 9 Michael Saboff 2020-09-17 08:51:59 PDT
(In reply to youenn fablet from comment #8)
> Comment on attachment 408869 [details]
> Patch
> 
> > Are you suggesting we change
> >     Ref<IDBKey> createBinary(JSC::JSArrayBufferView&)
> > to
> >     RefPtr<IDBKey> createBinary(JSC::JSArrayBufferView&)
> > 
> > If so, it seems weird to have two different return types for the overloaded createBinary(...) methods.
> 
> We could introduce tryCreateBinary.
> Or at least return IDBKey::createInvalid() which seems a bit clearer.

Let's go with IDBKey::createInvalid().
Comment 10 Michael Saboff 2020-09-17 09:49:12 PDT
Created attachment 409043 [details]
Updated Patch
Comment 11 Michael Saboff 2020-09-17 12:52:46 PDT
Committed r267205: <https://trac.webkit.org/changeset/267205>
Comment 12 Truitt Savell 2020-09-18 15:35:33 PDT
It looks like the new test
storage/indexeddb/IDBKey-create-array-buffer-view-oom.html

added in https://trac.webkit.org/changeset/267205/webkit

is a flaky timeout 
History:
https://results.webkit.org/?suite=layout-tests&test=storage%2Findexeddb%2FIDBKey-create-array-buffer-view-oom.html