Bug 164007 - JSGenericTypedArrayView::set() should check for exceptions.
Summary: JSGenericTypedArrayView::set() should check for exceptions.
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: JavaScriptCore (show other bugs)
Version: WebKit Local Build
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Mark Lam
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2016-10-26 00:11 PDT by Mark Lam
Modified: 2016-10-26 12:27 PDT (History)
8 users (show)

See Also:


Attachments
proposed patch. (4.38 KB, patch)
2016-10-26 00:36 PDT, Mark Lam
fpizlo: review+
Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Mark Lam 2016-10-26 00:11:48 PDT
Patch coming.
Comment 1 Mark Lam 2016-10-26 00:20:24 PDT
<rdar://problem/28853775>
Comment 2 Mark Lam 2016-10-26 00:36:50 PDT
Created attachment 292882 [details]
proposed patch.
Comment 3 JF Bastien 2016-10-26 09:35:31 PDT
Comment on attachment 292882 [details]
proposed patch.

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

> JSTests/stress/typed-array-view-set-should-not-crash-on-exception.js:14
> +    get: Date.prototype.getSeconds,

Ew, this is horrible :-)

> Source/JavaScriptCore/runtime/JSGenericTypedArrayViewInlines.h:252
>          length = std::min(length, other->length());

This is weird because other->length() is uint32_t and length is unsigned. Realistically unsigned is also uint32_t but if it weren't then it would potentially truncate (or if other->length()'s type were changed) which could lead to OOB things happening below (in the code you're changing, validating ranges of truncated things can get weird). It may be good to static_assert here that sizeof and sign are the same?

> Source/JavaScriptCore/runtime/JSGenericTypedArrayViewInlines.h:256
> +        ASSERT(!scope.exception() == success);

I don't understand what this assertion is checking. Success is the same as scope having raised an exception? Why? Exceptions can only occur if the range was borked?
Comment 4 Mark Lam 2016-10-26 09:43:17 PDT
Comment on attachment 292882 [details]
proposed patch.

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

>> Source/JavaScriptCore/runtime/JSGenericTypedArrayViewInlines.h:252
>>          length = std::min(length, other->length());
> 
> This is weird because other->length() is uint32_t and length is unsigned. Realistically unsigned is also uint32_t but if it weren't then it would potentially truncate (or if other->length()'s type were changed) which could lead to OOB things happening below (in the code you're changing, validating ranges of truncated things can get weird). It may be good to static_assert here that sizeof and sign are the same?

This is pre-existing code.  In my understanding, our codebase pretty much uses unsigned and uint32_t interchangeably.  If that premise every becomes untrue, then all shorts of things will fail.  Do we really want to start putting thee static_asserts every where?

>> Source/JavaScriptCore/runtime/JSGenericTypedArrayViewInlines.h:256
>> +        ASSERT(!scope.exception() == success);
> 
> I don't understand what this assertion is checking. Success is the same as scope having raised an exception? Why? Exceptions can only occur if the range was borked?

Calling scope.exception(0 has side effects of satisfying a check for the exception scope verification process.  This is how we do it (satisfy that check) when we want to check an alternate value (i.e. success in this case).
Comment 5 Mark Lam 2016-10-26 09:43:59 PDT
(In reply to comment #4)
> Calling scope.exception(0 has ...

/scope.exception(0/scope.exception()/
Comment 6 Geoffrey Garen 2016-10-26 10:01:38 PDT
Comment on attachment 292882 [details]
proposed patch.

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

>>> Source/JavaScriptCore/runtime/JSGenericTypedArrayViewInlines.h:252
>>>          length = std::min(length, other->length());
>> 
>> This is weird because other->length() is uint32_t and length is unsigned. Realistically unsigned is also uint32_t but if it weren't then it would potentially truncate (or if other->length()'s type were changed) which could lead to OOB things happening below (in the code you're changing, validating ranges of truncated things can get weird). It may be good to static_assert here that sizeof and sign are the same?
> 
> This is pre-existing code.  In my understanding, our codebase pretty much uses unsigned and uint32_t interchangeably.  If that premise every becomes untrue, then all shorts of things will fail.  Do we really want to start putting thee static_asserts every where?

If there were a type mismatch between "length" and "other->length()", the call to min would fail to compile due to ambiguity, no?

For example:

scratch.cc:

int main()
{
    uint32_t x = 0;
    uint16_t y = 0;
    std::min(x, y);
}

clang++ -o scratch scratch.cc:

scratch.cc:16:5: error: no matching function for call to 'min'
    std::min(x, y);
    ^~~~~~~~
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/algorithm:2589:1: note: candidate template ignored: deduced conflicting types for parameter '_Tp'
      ('unsigned int' vs. 'unsigned short')
min(const _Tp& __a, const _Tp& __b)
Comment 7 JF Bastien 2016-10-26 10:13:38 PDT
(In reply to comment #6)
> Comment on attachment 292882 [details]
> proposed patch.
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=292882&action=review
> 
> >>> Source/JavaScriptCore/runtime/JSGenericTypedArrayViewInlines.h:252
> >>>          length = std::min(length, other->length());
> >> 
> >> This is weird because other->length() is uint32_t and length is unsigned. Realistically unsigned is also uint32_t but if it weren't then it would potentially truncate (or if other->length()'s type were changed) which could lead to OOB things happening below (in the code you're changing, validating ranges of truncated things can get weird). It may be good to static_assert here that sizeof and sign are the same?
> > 
> > This is pre-existing code.  In my understanding, our codebase pretty much uses unsigned and uint32_t interchangeably.  If that premise every becomes untrue, then all shorts of things will fail.  Do we really want to start putting thee static_asserts every where?
> 
> If there were a type mismatch between "length" and "other->length()", the
> call to min would fail to compile due to ambiguity, no?
> 
> For example:
> 
> scratch.cc:
> 
> int main()
> {
>     uint32_t x = 0;
>     uint16_t y = 0;
>     std::min(x, y);
> }
> 
> clang++ -o scratch scratch.cc:
> 
> scratch.cc:16:5: error: no matching function for call to 'min'
>     std::min(x, y);
>     ^~~~~~~~
> /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.
> xctoolchain/usr/bin/../include/c++/v1/algorithm:2589:1: note: candidate
> template ignored: deduced conflicting types for parameter '_Tp'
>       ('unsigned int' vs. 'unsigned short')
> min(const _Tp& __a, const _Tp& __b)

Oh yeah you're totally right! Ignore me :-)
Comment 8 Mark Lam 2016-10-26 12:27:35 PDT
Thanks for the review.  Landed in r207906: <http://trac.webkit.org/r207906>.