RESOLVED FIXED 96798
[V8] Binding: Implement EnforceRange IDL Attribute for long long conversions
https://bugs.webkit.org/show_bug.cgi?id=96798
Summary [V8] Binding: Implement EnforceRange IDL Attribute for long long conversions
Joshua Bell
Reported 2012-09-14 09:34:45 PDT
From the WebIDL spec: http://dev.w3.org/2006/webapi/WebIDL/#es-long-long 1. If x is NaN, +∞, or −∞, then throw a TypeError. 2. Set x to sign(x) * floor(abs(x)). 3. If x < −(2^53 − 1) or x > 2^53 − 1, then throw a TypeError. 4. Return the IDL long long value that represents the same numeric value as x. Note that there are similar cases for unsigned long long. The binding code generator says: return "toInt64($value)" if $type eq "unsigned long long" or $type eq "long long"; and toInt64 defined in bindings/v8/V8Binding.h is: inline long long toInt64(v8::Local<v8::Value> value) { return static_cast<long long>(value->IntegerValue()); } ... so there are no guard checks. This causes IndexedDB to fail the test http://w3c-test.org/webapps/IndexedDB/tests/submissions/Ms2ger/idbfactory_open9.htm We could special case this in the IDB code, or change toInt64 to incorporate the checks from WebIDL and call throwTypeError().
Attachments
Patch (24.41 KB, patch)
2012-09-20 15:09 PDT, Joshua Bell
no flags
Patch (62.86 KB, patch)
2012-12-27 14:40 PST, Joshua Bell
no flags
Patch (94.74 KB, patch)
2013-01-08 14:25 PST, Joshua Bell
no flags
Patch (124.43 KB, patch)
2013-02-12 16:42 PST, Joshua Bell
no flags
Patch (71.06 KB, patch)
2013-02-13 14:34 PST, Joshua Bell
no flags
Patch (71.47 KB, patch)
2013-02-13 17:11 PST, Joshua Bell
no flags
Patch for landing (73.64 KB, patch)
2013-02-25 11:23 PST, Joshua Bell
no flags
Patch for landing (75.46 KB, patch)
2013-02-26 09:19 PST, Joshua Bell
no flags
Patch (109.04 KB, patch)
2013-03-08 11:49 PST, Joshua Bell
no flags
Patch (118.78 KB, patch)
2013-03-08 12:16 PST, Joshua Bell
no flags
Patch (127.19 KB, patch)
2013-03-11 12:15 PDT, Joshua Bell
no flags
Patch (127.63 KB, patch)
2013-03-12 12:07 PDT, Joshua Bell
no flags
Patch for landing (127.37 KB, patch)
2013-03-15 11:00 PDT, Joshua Bell
no flags
David Grogan
Comment 1 2012-09-14 13:58:12 PDT
Adding negative sign
Joshua Bell
Comment 2 2012-09-20 10:21:02 PDT
Note that this should only apply if the IDL has [EnforceRange] extended attribute.
Joshua Bell
Comment 3 2012-09-20 11:11:43 PDT
Debugging through this, NaN, Infinity and -Infinity are being coerced to -0x8000000000000000 via V8's IntegerValue(). It's IndexedDB that's generating the type error for those. So basically we need to implement all these tests.
Joshua Bell
Comment 4 2012-09-20 13:59:30 PDT
Huh, I'm a bit stumped. This should be a matter of dumping the appropriate tests into V8Binding.h's toInt64 (and then refactoring), and having toInt64() call throwTypeError(). However, when this is done the exception is not caught/rethrown by the v8::TryCatch block in EXCEPTION_BLOCK, so the script never sees the exception. Maybe v8 change r11894 is to blame? Calling throwTypeError() winds its way into api.cc's ThrowException which calls Isolate::ScheduleThrow(). That method calls into Isolate::Throw(), then immediately moves the exception from "pending" to "scheduled" and clears the pending exception. Tracing through, nothing causes the "scheduled" exception to be "promoted" back to pending before the TryCatch block concludes. v8 r11894 monkeys with the contents of Isolate::ScheduleThrow, removing a call to PropagatePendingExceptionToExternalTryCatch() which seems to be needed. If I undo that change then throwTypeError() works as expected.
Joshua Bell
Comment 5 2012-09-20 15:09:06 PDT
Joshua Bell
Comment 6 2012-09-20 15:11:34 PDT
(In reply to comment #5) > Created an attachment (id=164990) [details] > Patch Uploaded a patch, but it won't work until we sort out the V8 issue. (If I revert http://code.google.com/p/v8/source/diff?spec=svn11894&old=11882&r=11894&format=unidiff&path=%2Ftrunk%2Fsrc%2Fisolate.cc locally it works!) Also: * Doesn't implement EnforceRange for "long" types, just "long long" * The logic should probably move from V8Binding.h to V8Binding.cpp * I didn't touch JSC at all
Joshua Bell
Comment 7 2012-09-20 16:29:54 PDT
(In reply to comment #4) > This should be a matter of dumping the appropriate tests into V8Binding.h's toInt64 (and then refactoring), and having toInt64() call throwTypeError(). However, when this is done the exception is not caught/rethrown by the v8::TryCatch block in EXCEPTION_BLOCK, so the script never sees the exception. haraken@ points out this is http://code.google.com/p/v8/issues/detail?id=2166 - in summary, TryCatch is not nestable.
Joshua Bell
Comment 8 2012-12-04 08:59:32 PST
(In reply to comment #7) > (In reply to comment #4) > > This should be a matter of dumping the appropriate tests into V8Binding.h's toInt64 (and then refactoring), and having toInt64() call throwTypeError(). However, when this is done the exception is not caught/rethrown by the v8::TryCatch block in EXCEPTION_BLOCK, so the script never sees the exception. > > haraken@ points out this is http://code.google.com/p/v8/issues/detail?id=2166 - in summary, TryCatch is not nestable. Once Chromium rolls v8 to r13130 this should be unblocked on the v8 side.
Erik Arvidsson
Comment 9 2012-12-04 09:39:32 PST
(In reply to comment #8) > (In reply to comment #7) > > (In reply to comment #4) > > > This should be a matter of dumping the appropriate tests into V8Binding.h's toInt64 (and then refactoring), and having toInt64() call throwTypeError(). However, when this is done the exception is not caught/rethrown by the v8::TryCatch block in EXCEPTION_BLOCK, so the script never sees the exception. > > > > haraken@ points out this is http://code.google.com/p/v8/issues/detail?id=2166 - in summary, TryCatch is not nestable. > > Once Chromium rolls v8 to r13130 this should be unblocked on the v8 side. I don't understand why we need V8 changes for this. See bug 101783 for a WIP patch that worked (to some extent). Maybe it is cleaner to wait for V8 to allow anything to throw but we can keep track of the success state as we do the conversions.
Joshua Bell
Comment 10 2012-12-04 09:53:48 PST
(In reply to comment #9) > I don't understand why we need V8 changes for this. See bug 101783 for a WIP patch that worked (to some extent). Maybe it is cleaner to wait for V8 to allow anything to throw but we can keep track of the success state as we do the conversions. That's true, it's not technically blocked. I was favoring having the toIntXXX() methods throw for readability but passing in an bool& obviously works as well. The throwing approach works, apart from a v8 bug which has now been resolved, so we can choose either approach. I wasn't aware of the bug when I started this patch and as it wasn't urgent and the v8 fix seemed imminent I left it blocked rather than exploring other approaches.
Erik Arvidsson
Comment 11 2012-12-04 10:00:35 PST
(In reply to comment #10) > (In reply to comment #9) > > I don't understand why we need V8 changes for this. See bug 101783 for a WIP patch that worked (to some extent). Maybe it is cleaner to wait for V8 to allow anything to throw but we can keep track of the success state as we do the conversions. > > That's true, it's not technically blocked. I was favoring having the toIntXXX() methods throw for readability but passing in an bool& obviously works as well. I'm not sure which approach is better. Today, where we do not handle any type conversion failures, I think using a throw is less invasive, but given that we really should handle all type conversion failures I'm not sure throw is a better solution?
Joshua Bell
Comment 12 2012-12-04 10:19:17 PST
(In reply to comment #11) > I'm not sure which approach is better. Today, where we do not handle any type conversion failures, I think using a throw is less invasive, but given that we really should handle all type conversion failures I'm not sure throw is a better solution? I was imagining we'd end up with a repeated pattern like this anyway in the API: XXX toXXX(x, options..., bool& ok); XXX toXXXMaybeThrow(x, options...) { bool ok; XXX r = toXXX(x, ok); if (!ok) throwTypeError(); return r; } So eliminating the toXXXMaybeThrow and relying on the generated code to throw seems like it will result in less code overall.
Kentaro Hara
Comment 13 2012-12-04 15:52:38 PST
(In reply to comment #9) > > > haraken@ points out this is http://code.google.com/p/v8/issues/detail?id=2166 - in summary, TryCatch is not nestable. BTW, this bug is going to be fixed shortly.
Joshua Bell
Comment 14 2012-12-27 14:40:22 PST
Joshua Bell
Comment 15 2012-12-27 14:44:04 PST
Latest patch drops dependency on nested v8 try/catch blocks and implements this in the style of bug 101783 - thanks arv@! To match the IDL it is more lenient for u/int32 conversions in some cases when [EnforceRange] is not specified. This does NOT YET implement the JSC version, only the V8 version, so it's not ready for landing but I wanted to see what the bots think and get feedback.
WebKit Review Bot
Comment 16 2012-12-27 18:42:56 PST
Comment on attachment 180821 [details] Patch Attachment 180821 [details] did not pass chromium-ews (chromium-xvfb): Output: http://queues.webkit.org/results/15549644 New failing tests: fast/js/select-options-add.html fast/dom/non-numeric-values-numeric-parameters.html
Erik Arvidsson
Comment 17 2013-01-02 08:07:21 PST
Comment on attachment 180821 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=180821&action=review > Source/WebCore/bindings/v8/V8Binding.cpp:136 > + x = (x < 0 ? -1 : 1) * floor(fabs(x)); Can't this just be (int) x? > Source/WebCore/bindings/v8/V8Binding.cpp:147 > + if (isnan(numberValue) || isinf(numberValue)) I'm concerned about this change. Why do we silently want to treat NaN and Infinity as 0?
Joshua Bell
Comment 18 2013-01-02 09:04:45 PST
Comment on attachment 180821 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=180821&action=review >> Source/WebCore/bindings/v8/V8Binding.cpp:136 >> + x = (x < 0 ? -1 : 1) * floor(fabs(x)); > > Can't this just be (int) x? After reviewing the C standard: yes. "When a value of floating type is converted to integral type, the fractional part is discarded." (Unsurprising, as WebIDL is likely just specifying existing behavior of implementations.) >> Source/WebCore/bindings/v8/V8Binding.cpp:147 >> + if (isnan(numberValue) || isinf(numberValue)) > > I'm concerned about this change. Why do we silently want to treat NaN and Infinity as 0? WebIDL does not specify that an exception should be raised in non-finite cases if [EnforceRange] is not specified. That's the point of the attribute - to allow interfaces to turn on throwing behavior. I agree that this is the scariest part of the patch, as it changes the behavior of existing binding code. I will look more carefully at where toIntXX(value, ok) is called explicitly, since I think generated code never uses that form unless [EnforceRange] is specified.
Erik Arvidsson
Comment 19 2013-01-02 09:22:05 PST
(In reply to comment #18) > WebIDL does not specify that an exception should be raised in non-finite cases if [EnforceRange] is not specified. That's the point of the attribute - to allow interfaces to turn on throwing behavior. My assumption was wrong. I just double checked. I wonder if we could test these behaviors? One idea would be to have add an object to testRunner where we have all of these. I'll file a bug.
Joshua Bell
Comment 20 2013-01-02 10:42:20 PST
(In reply to comment #18) > (From update of attachment 180821 [details]) > View in context: https://bugs.webkit.org/attachment.cgi?id=180821&action=review > > >> Source/WebCore/bindings/v8/V8Binding.cpp:136 > >> + x = (x < 0 ? -1 : 1) * floor(fabs(x)); > > > > Can't this just be (int) x? > > After reviewing the C standard: yes. "When a value of floating type is converted to integral type, the fractional part is discarded." Hrm, well, trickier than that as the subsequent tests look for values outside the range of the destination type. The C++ standard says "The behavior is undefined if the truncated value cannot be represented in the destination type". So... I'm not sure we can take a shortcut here.
Joshua Bell
Comment 21 2013-01-02 11:43:33 PST
Details on the two test failures: * fast/dom/non-numeric-values-numeric-parameters.html * fast/js/select-options-add.html Both are probing the behavior around: document.createElement('select').options.add(document.createElement('option'), x); ... for various values of X. x = Infinity ==> Chrome 23 throws, Safari 6 throws, FF17 throws, IE10 throws. x = -Infinity ==> Chrome 23 throws, Safari 6 throws, FF17 throws, IE10 throws. x = NaN ==> Chrome 23 throws, Safari 6 throws, FF17 ok, IE10 throws. x = -2 ==> Chrome 23 throws, Safari 6 throws, FF17 ok, IE10 throws. x = -1 ==> Chrome 23 ok, Safari 6 ok, FF17 ok, IE10 ok. x = 100 ==> Chrome 23 ok, Safari 6 ok, FF17 ok, IE10 ok. The HTML spec has: void add((HTMLOptionElement or HTMLOptGroupElement) element, optional (HTMLElement or long)? before = null); ... and the prose reads: "If before is omitted, null, or a number out of range, then element will be added at the end of the list" - therefore, I would not expect the throwing behavior in any of these cases. ... The fast/dom/non-numeric-values-numeric-parameters.html test actually has a bug in the test where it is setting NaNAllowed but testing nanAllowed, so it is not correctly probing NaN support for this method, which may explain the divergence between WebKit and Gecko.
Joshua Bell
Comment 22 2013-01-02 14:36:07 PST
Per discussion w/ Moz folks on #whatwg, this bit of Gecko code has crufty old custom binding code not based on the IDL, so the behavior there is not intentional. jwalden agrees that per-spec none of these should throw.
Joshua Bell
Comment 23 2013-01-02 14:55:10 PST
Joshua Bell
Comment 24 2013-01-08 14:25:04 PST
Joshua Bell
Comment 25 2013-01-08 14:27:44 PST
(In reply to comment #24) > Created an attachment (id=181764) [details] > Patch Updated patch still a WIP. Handles attribute setters via another macro (since return type is void). Adds more attributes to the TypeConversions object and corresponding tests. Still V8 only.
Joshua Bell
Comment 26 2013-02-12 16:42:02 PST
Joshua Bell
Comment 27 2013-02-12 16:43:36 PST
Rebased. Still V8 only. * Passes throwTypeError() the required isolate argument. * Introduces a ConversionAttributes enum of flags in V8Binding.h so that eventually [Clamp] can be supported without adding yet another boolean arg. I think this is good-to-go on the V8 side, but the JSC side needs some luv.
Adam Barth
Comment 28 2013-02-13 12:05:48 PST
Would you like me to review your patch?
Joshua Bell
Comment 29 2013-02-13 12:07:45 PST
Comment on attachment 187960 [details] Patch abarth@ - Sure, feedback at this point is welcome. r?
Adam Barth
Comment 30 2013-02-13 12:18:12 PST
Comment on attachment 187960 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=187960&action=review > Source/WebCore/bindings/scripts/test/V8/V8TestObj.cpp:202 > - int v = toInt32(value); > + V8TRYCATCH_FOR_TYPECHECK_VOID(int, v, toInt32(value, false, ok)); It looks like we're now always creating a try-catch block. Is that necessary? Does that impact performance when the [EnforceRange] attribute isn't specified?
Joshua Bell
Comment 31 2013-02-13 12:25:44 PST
Comment on attachment 187960 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=187960&action=review > Source/WebCore/bindings/v8/V8BindingMacros.h:77 > + throwTypeError(0, info.GetIsolate()); \ This should just be |isolate|
Joshua Bell
Comment 32 2013-02-13 12:29:20 PST
Comment on attachment 187960 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=187960&action=review >> Source/WebCore/bindings/scripts/test/V8/V8TestObj.cpp:202 >> + V8TRYCATCH_FOR_TYPECHECK_VOID(int, v, toInt32(value, false, ok)); > > It looks like we're now always creating a try-catch block. Is that necessary? Does that impact performance when the [EnforceRange] attribute isn't specified? Thanks - no, shouldn't be necessary; probably residue from earlier iterations. In the ...TYPECHECK_VOID case there shouldn't need to be a try-catch block. This can reduce to a TYPECHECK macro.
Build Bot
Comment 33 2013-02-13 13:35:09 PST
Comment on attachment 187960 [details] Patch Attachment 187960 [details] did not pass mac-wk2-ews (mac-wk2): Output: http://queues.webkit.org/results/16547013 New failing tests: fast/dom/non-numeric-values-numeric-parameters.html fast/js/webidl-type-mapping.html
Build Bot
Comment 34 2013-02-13 14:17:42 PST
Comment on attachment 187960 [details] Patch Attachment 187960 [details] did not pass mac-wk2-ews (mac-wk2): Output: http://queues.webkit.org/results/16563012 New failing tests: fast/dom/non-numeric-values-numeric-parameters.html fast/js/webidl-type-mapping.html
Joshua Bell
Comment 35 2013-02-13 14:34:04 PST
Joshua Bell
Comment 36 2013-02-13 14:38:04 PST
Let's give that another whirl: * Minimized code generator output differences - callers to JSValueToNative call a helper to determine if type checking is necessary and only use type checking macro wrappers if necessary. Ugly, but safer. * Only need TYPECHECK_VOID and V8TRYCATCH_WITH_TYPECHECK macros. With more extensive refactoring could probably compose those. Alternately, these could be inlined but I think these will eventually end up being used in 1-2 more places (e.g. Dictionary value access) * Actually ran the tests, which turned up stupid logic bugs with the flags. Derp. * Updated the test for HTMLOptionsCollection to match the HTML spec, which matches the new behavior of the code (see comment #21)
Kentaro Hara
Comment 37 2013-02-13 16:06:12 PST
Comment on attachment 188184 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=188184&action=review > Source/WebCore/bindings/scripts/CodeGeneratorV8.pm:3928 > +sub ConversionThrowsTypeError Will this method be useful for other purpose? Otherwise, I would hard-code $signature->extendedAttributes->{"EnforceRange"} in call sites and remove the method. > Source/WebCore/bindings/v8/V8Binding.cpp:115 > v8::Local<v8::Number> numberObject = value->ToNumber(); This can throw. You need a try-catch block. > Source/WebCore/bindings/v8/V8Binding.cpp:121 > + if (attributes & FEnforceRange) { [EnforgeRange] must not be in conjunction with [Clamp]: http://www.w3.org/TR/WebIDL/#EnforceRange So it would be useless to use a bit-masking approach. > Source/WebCore/bindings/v8/V8Binding.cpp:128 > + if (x < -0x8000000 || x > 0x7fffffff) { Nit: Shall we use a constant variable for these magic numbers? > Source/WebCore/bindings/v8/V8Binding.cpp:166 > + if (attributes & FEnforceRange) { Ditto. > Source/WebCore/bindings/v8/V8Binding.cpp:173 > + if (x < 0 || x > 0xffffffff) { Nit: Use a constant variable for the magic number. > Source/WebCore/bindings/v8/V8Binding.cpp:198 > + v8::Local<v8::Number> numberObject = value->ToNumber(); This can throw. You need a try-catch block. > Source/WebCore/bindings/v8/V8Binding.cpp:206 > + if (attributes & FEnforceRange) { Ditto. > Source/WebCore/bindings/v8/V8Binding.cpp:237 > + if (result >= 0) > + return result; Can we also add a fast path for result < 0 ? > Source/WebCore/bindings/v8/V8Binding.cpp:241 > + v8::Local<v8::Number> numberObject = value->ToNumber(); This can throw. You need a try-catch block. > Source/WebCore/bindings/v8/V8Binding.cpp:249 > + if (attributes & FEnforceRange) { Ditto. > Source/WebCore/bindings/v8/V8Binding.h:348 > + enum ConversionAttributes { Nit: IntergerConversionConfiguration? > Source/WebCore/bindings/v8/V8Binding.h:351 > + FNone = 0x0000, > + FEnforceRange = 0x0001, > + // FIXME: Implement FClamp = 0x0002 Nit: Are these hard-coded values (e.g. 0x0001) meaningful? Otherwise, we can drop them. Nit: Also is "FEnforceRange" a speced name somewhere? Otherwise, we can simply say "EnforceRange". > Source/WebCore/bindings/v8/V8BindingMacros.h:46 > + bool ok = true; \ > + var = (value); \ > + if (UNLIKELY(!ok)) { \ Where is |ok| updated? > Source/WebCore/bindings/v8/V8BindingMacros.h:71 > + if (UNLIKELY(!ok)) \ Ditto.
Kentaro Hara
Comment 38 2013-02-13 16:07:49 PST
Comment on attachment 188184 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=188184&action=review > LayoutTests/fast/js/webidl-type-mapping.html:45 > +function testNonNumericToNumericEnforceRange(attribute) You might want to add more test cases for non numeric values, especially a case where an exception is thrown during value conversion.
Joshua Bell
Comment 39 2013-02-13 16:41:45 PST
(In reply to comment #37) > (From update of attachment 188184 [details]) > View in context: https://bugs.webkit.org/attachment.cgi?id=188184&action=review > > > Source/WebCore/bindings/scripts/CodeGeneratorV8.pm:3928 > > +sub ConversionThrowsTypeError > > Will this method be useful for other purpose? Otherwise, I would hard-code $signature->extendedAttributes->{"EnforceRange"} in call sites and remove the method. I was imagining that it would be, but I also wasn't really paying attention to what [Clamp] meant. I can inline it. > > Source/WebCore/bindings/v8/V8Binding.cpp:115 > > v8::Local<v8::Number> numberObject = value->ToNumber(); > > This can throw. You need a try-catch block. Bleah. This is also in the existing code, which means existing conversions are buggy. To abarth@'s earlier point this probably means all numeric conversions will need to get wrapped in try-catch blocks, not just those with [EnforceRange] specified. > > > Source/WebCore/bindings/v8/V8Binding.cpp:121 > > + if (attributes & FEnforceRange) { > > [EnforgeRange] must not be in conjunction with [Clamp]: > http://www.w3.org/TR/WebIDL/#EnforceRange > > So it would be useless to use a bit-masking approach. Thanks. I should have looked more closely at [Clamp]. That simplifies things. > > > Source/WebCore/bindings/v8/V8Binding.cpp:128 > > + if (x < -0x8000000 || x > 0x7fffffff) { > > Nit: Shall we use a constant variable for these magic numbers? Sure. kMinInt32, kMaxUint32, etc? > > Source/WebCore/bindings/v8/V8Binding.cpp:237 > > + if (result >= 0) > > + return result; > > Can we also add a fast path for result < 0 ? Yep. Will depend on the attributes so will have multiple cases, but probably worth it. > > Source/WebCore/bindings/v8/V8Binding.h:348 > > + enum ConversionAttributes { > > Nit: IntergerConversionConfiguration? Sure. > > Source/WebCore/bindings/v8/V8Binding.h:351 > > + FNone = 0x0000, > > + FEnforceRange = 0x0001, > > + // FIXME: Implement FClamp = 0x0002 > > Nit: Are these hard-coded values (e.g. 0x0001) meaningful? Otherwise, we can drop them. > > Nit: Also is "FEnforceRange" a speced name somewhere? Otherwise, we can simply say "EnforceRange". Since [Clamp] and [EnforceRange] are exclusive, the values and 'F' prefixes can definitely be dropped. Thanks again, I should have looked more closely at the spec for [Clamp]. > > Source/WebCore/bindings/v8/V8BindingMacros.h:46 > > + bool ok = true; \ > > + var = (value); \ > > + if (UNLIKELY(!ok)) { \ > > Where is |ok| updated? In the cases where these macros are used, the expression generated by JSValueToNative() passes ok into the ToIntXX functions, that expression is what ends up as the |value| macro parameter. (This was arv@'s suggestion.)
Kentaro Hara
Comment 40 2013-02-13 16:50:18 PST
> > > Source/WebCore/bindings/v8/V8Binding.cpp:115 > > > v8::Local<v8::Number> numberObject = value->ToNumber(); > > > > This can throw. You need a try-catch block. > > Bleah. This is also in the existing code, which means existing conversions are buggy. To abarth@'s earlier point this probably means all numeric conversions will need to get wrapped in try-catch blocks, not just those with [EnforceRange] specified. Yeah, I think you can fix it in a separate patch. (Actually we have similar bugs in a lot of places in custom bindings... not only integer conversion but also string conversions.) > > Nit: Shall we use a constant variable for these magic numbers? > > Sure. kMinInt32, kMaxUint32, etc? Sounds good!
Joshua Bell
Comment 41 2013-02-13 17:11:32 PST
Kentaro Hara
Comment 42 2013-02-13 17:31:02 PST
Comment on attachment 188229 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=188229&action=review LGTM. > Source/WebCore/bindings/scripts/CodeGeneratorV8.pm:1252 > + my $value = JSValueToNative($attribute->signature, "value", "info.GetIsolate()", 1); 1 is unclear. Let's pass a string "canThrowException".
Kentaro Hara
Comment 43 2013-02-13 17:32:27 PST
(In reply to comment #40) > Yeah, I think you can fix it in a separate patch. (Actually we have similar bugs in a lot of places in custom bindings... not only integer conversion but also string conversions.) Please add more test cases for non numeric values (exception cases) when you work on the follow-up patch.
Joshua Bell
Comment 44 2013-02-14 09:29:29 PST
(In reply to comment #42) > > 1 is unclear. Let's pass a string "canThrowException". Done. (We should do this for the other methods that take optional bools, too.) So... thoughts on the JSC side here? Tackle it now, handle it with TestExpectations, ...?
Joshua Bell
Comment 45 2013-02-25 11:23:04 PST
Created attachment 190095 [details] Patch for landing
WebKit Review Bot
Comment 46 2013-02-25 17:09:35 PST
Comment on attachment 190095 [details] Patch for landing Rejecting attachment 190095 [details] from commit-queue. Failed to run "['/mnt/git/webkit-commit-queue/Tools/Scripts/webkit-patch', '--status-host=queues.webkit.org', '--bot-id=gce-cq-02', 'apply-attachment', '--no-update', '--non-interactive', 190095, '--port=chromium-xvfb']" exit_code: 2 cwd: /mnt/git/webkit-commit-queue Last 500 characters of output: LayoutTests/fast/dom/script-tests/non-numeric-values-numeric-parameters.js patching file LayoutTests/fast/js/webidl-type-mapping-expected.txt patching file LayoutTests/fast/js/webidl-type-mapping.html patching file LayoutTests/storage/indexeddb/intversion-bad-parameters-expected.txt patching file LayoutTests/storage/indexeddb/resources/intversion-bad-parameters.js Failed to run "[u'/mnt/git/webkit-commit-queue/Tools/Scripts/svn-apply', '--force']" exit_code: 1 cwd: /mnt/git/webkit-commit-queue Full output: http://queues.webkit.org/results/16760403
Joshua Bell
Comment 47 2013-02-26 09:19:29 PST
Created attachment 190301 [details] Patch for landing
Build Bot
Comment 48 2013-02-26 14:33:02 PST
Comment on attachment 190301 [details] Patch for landing Attachment 190301 [details] did not pass mac-wk2-ews (mac-wk2): Output: http://webkit-commit-queue.appspot.com/results/16769502 New failing tests: fast/dom/non-numeric-values-numeric-parameters.html
WebKit Review Bot
Comment 49 2013-02-26 14:58:52 PST
Comment on attachment 190301 [details] Patch for landing Attachment 190301 [details] did not pass chromium-ews (chromium-xvfb): Output: http://webkit-commit-queue.appspot.com/results/16781400 New failing tests: fast/js/select-options-add.html fast/js/webidl-type-mapping.html
Build Bot
Comment 50 2013-02-27 03:18:10 PST
Comment on attachment 190301 [details] Patch for landing Attachment 190301 [details] did not pass mac-ews (mac): Output: http://webkit-commit-queue.appspot.com/results/16831130 New failing tests: fast/dom/non-numeric-values-numeric-parameters.html
Peter Beverloo (cr-android ews)
Comment 51 2013-02-27 18:57:27 PST
Comment on attachment 190301 [details] Patch for landing Attachment 190301 [details] did not pass cr-android-ews (chromium-android): Output: http://webkit-commit-queue.appspot.com/results/16797184
Joshua Bell
Comment 52 2013-03-08 11:49:32 PST
Joshua Bell
Comment 53 2013-03-08 12:16:04 PST
Peter Beverloo (cr-android ews)
Comment 54 2013-03-08 12:45:10 PST
Comment on attachment 192267 [details] Patch Attachment 192267 [details] did not pass cr-android-ews (chromium-android): Output: http://webkit-commit-queue.appspot.com/results/17016293
WebKit Review Bot
Comment 55 2013-03-08 14:37:44 PST
Comment on attachment 192267 [details] Patch Attachment 192267 [details] did not pass chromium-ews (chromium-xvfb): Output: http://webkit-commit-queue.appspot.com/results/17110231 New failing tests: fast/dom/non-numeric-values-numeric-parameters.html
WebKit Review Bot
Comment 56 2013-03-08 15:25:43 PST
Comment on attachment 192267 [details] Patch Attachment 192267 [details] did not pass chromium-ews (chromium-xvfb): Output: http://webkit-commit-queue.appspot.com/results/17016336 New failing tests: fast/dom/non-numeric-values-numeric-parameters.html
Joshua Bell
Comment 57 2013-03-11 12:15:07 PDT
Joshua Bell
Comment 58 2013-03-11 12:19:17 PDT
Needed the passing expectation for chromium on that test. ... Sorry about the patch churn. It's all about the previously mentioned case: document.createElement('select').options.add(document.createElement('option'), x); ... which per spec (and Firefox) shouldn't throw for non-finite x, but previously did. This patch will make it not throw in V8, but it will continue to throw in JSC. Therefore, I've updated the tests to match the spec, which leaves them with FAIL expectations in JSC and requires different expectations in V8. Do any JSC experts want to weigh in before landing? haraken@ - can you give it one last look?
Peter Beverloo (cr-android ews)
Comment 59 2013-03-11 14:07:09 PDT
Comment on attachment 192526 [details] Patch Attachment 192526 [details] did not pass cr-android-ews (chromium-android): Output: http://webkit-commit-queue.appspot.com/results/17011690
Kentaro Hara
Comment 60 2013-03-11 18:07:24 PDT
Comment on attachment 192526 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=192526&action=review Getting closer! > Source/WebCore/bindings/scripts/CodeGeneratorV8.pm:3994 > + my $intConversion = $signature->extendedAttributes->{"EnforceRange"} ? "EnforceRange" : "NormalConversion"; > + die "Can't handle [EnforceRange] unless called from context that handles failures." if $intConversion eq "EnforceRange" and !$mayFail; Maybe you can simply remove $mayFail because you want to throw anyway if $signature->extendedAttributes->{"EnforceRange"} is true. If you remove $mayFail, call sites of JSValueToNative() become much simpler. > Source/WebCore/bindings/v8/V8Binding.cpp:267 > + if (x < 0 || x > (kJSMaxInteger - 1)) { Is this correct? c.f. You are doing 'if (x < -(kJSMaxInteger - 1) || x > (kJSMaxInteger - 1))' in toInt64(). > Source/WebCore/bindings/v8/V8Binding.h:59 > + const long long kJSMaxInteger = 0x20000000000000LL; You can put it in V8Binding.cpp. Also this should be 0x1fffffffffffffLL. (Then you can remove '- 1' from V8Binding.cpp.) > Source/WebCore/bindings/v8/V8BindingMacros.h:45 > +#define TYPECHECK_VOID(type, var, value, isolate) \ > + type var; \ > + { \ > + bool ok = true; \ > + var = (value); \ > + if (UNLIKELY(!ok)) { \ > + throwTypeError(0, isolate); \ > + return; \ > + } \ > + } 'var = (value)' can throw, so you need to protect it with a TryCatch block. You can rename the macro to V8TRYCATCH_WITH_TYPECHECK_VOID().
Joshua Bell
Comment 61 2013-03-12 11:38:22 PDT
(In reply to comment #60) > Maybe you can simply remove $mayFail because you want to throw anyway if $signature->extendedAttributes->{"EnforceRange"} is true. If you remove $mayFail, call sites of JSValueToNative() become much simpler. This was added to ensure that callers of JSValueToNative() were "opting in" to the new behavior and would then use the correct macro wrappers around the conversion. But I agree it's not required, so will remove it. > > Source/WebCore/bindings/v8/V8Binding.cpp:267 > > + if (x < 0 || x > (kJSMaxInteger - 1)) { > > Is this correct? > > c.f. You are doing 'if (x < -(kJSMaxInteger - 1) || x > (kJSMaxInteger - 1))' in toInt64(). Yes. Unless there's a typo I'm not seeing. Spec has, for unsigned long long: If x < 0 or x > 2^53 − 1, then throw a TypeError. Spec has, for long long: If x < −(2^53 − 1) or x > 2^53 − 1, then throw a TypeError. Are you asking because it seems unusual for the upper bounds to be the same for both int64 and uint64 conversion? If so, the reason is that the maximum integer value exactly representable (due to the limited mantissa range) in an ECMAScript Number (a.k.a. a 64-bit IEEE754 float) is 2^53-1, which is less than either 2^64-1 (max uint64) or 2^63-1 (max int64). So the WebIDL conversion logic is not "is this number in the int64/uint64 range?" but "if I put the floor of this exact number into an int64/uint64 will I get the same number out again?" If you're asking for another reason then I'm probably missing something, so please point it out! > > Source/WebCore/bindings/v8/V8Binding.h:59 > > + const long long kJSMaxInteger = 0x20000000000000LL; > > You can put it in V8Binding.cpp. Also this should be 0x1fffffffffffffLL. (Then you can remove '- 1' from V8Binding.cpp.) Done. The WebIDL spec uses "2^53 - 1" hence that style, but I'll move it and clarify the constant. > > Source/WebCore/bindings/v8/V8BindingMacros.h:45 > > +#define TYPECHECK_VOID(type, var, value, isolate) \ > > + type var; \ > > + { \ > > + bool ok = true; \ > > + var = (value); \ > > + if (UNLIKELY(!ok)) { \ > > + throwTypeError(0, isolate); \ > > + return; \ > > + } \ > > + } > > 'var = (value)' can throw, so you need to protect it with a TryCatch block. You can rename the macro to V8TRYCATCH_WITH_TYPECHECK_VOID(). That's actually what I had prior to comment #30 from abarth@. But now that the call sites inspect EnforceRange I can revert - thanks!
Joshua Bell
Comment 62 2013-03-12 12:07:02 PDT
Joshua Bell
Comment 63 2013-03-12 12:10:10 PDT
(In reply to comment #60) > > 'var = (value)' can throw, so you need to protect it with a TryCatch block. You can rename the macro to V8TRYCATCH_WITH_TYPECHECK_VOID(). Fixing this macro also revealed a flaw in the previous patch where conversions that threw (e.g. { valueOf: function() { throw new Error('foo'); }) were eating the thrown error and throwing a TypeError instead. Updated the tests to double-check that the error thrown during "var = (value)" are what makes it out.
Kentaro Hara
Comment 64 2013-03-12 17:41:08 PDT
Thanks for all the fixes! (In reply to comment #61) > Spec has, for unsigned long long: If x < 0 or x > 2^53 − 1, then throw a TypeError. > Spec has, for long long: If x < −(2^53 − 1) or x > 2^53 − 1, then throw a TypeError. > > Are you asking because it seems unusual for the upper bounds to be the same for both int64 and uint64 conversion? Yes, I was asking for the reason. Thanks for the detailed clarification.
Kentaro Hara
Comment 65 2013-03-12 17:41:27 PDT
Comment on attachment 192784 [details] Patch LGTM
Erik Arvidsson
Comment 66 2013-03-13 11:10:03 PDT
Comment on attachment 192784 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=192784&action=review This looks great > Source/WebCore/bindings/scripts/CodeGeneratorV8.pm:1904 > + if ($parameter->extendedAttributes->{"EnforceRange"}) { > + my $value = JSValueToNative($parameter, $optional && $optional eq "DefaultIsNullString" ? "argumentOrNull(args, $paramIndex)" : "args[$paramIndex]", "args.GetIsolate()"); > + $parameterCheckString .= " V8TRYCATCH_WITH_TYPECHECK($nativeType, $parameterName, $value, args.GetIsolate());\n"; > + } else { > + my $value = JSValueToNative($parameter, $optional && $optional eq "DefaultIsNullString" ? "argumentOrNull(args, $paramIndex)" : "args[$paramIndex]", "args.GetIsolate()"); > + $parameterCheckString .= " V8TRYCATCH($nativeType, $parameterName, $value);\n"; > + } Can you move the "my $value = ..." line out of the if to reduce code duplication?
Joshua Bell
Comment 67 2013-03-15 10:56:48 PDT
(In reply to comment #66) > Can you move the "my $value = ..." line out of the if to reduce code duplication? Nice catch, done.
Joshua Bell
Comment 68 2013-03-15 11:00:31 PDT
Created attachment 193338 [details] Patch for landing
WebKit Review Bot
Comment 69 2013-03-15 12:00:22 PDT
Comment on attachment 193338 [details] Patch for landing Clearing flags on attachment: 193338 Committed r145929: <http://trac.webkit.org/changeset/145929>
WebKit Review Bot
Comment 70 2013-03-15 12:00:31 PDT
All reviewed patches have been landed. Closing bug.
Kenneth Russell
Comment 71 2013-03-15 20:32:34 PDT
FYI: this caused a build failure on Windows which was fixed in http://trac.webkit.org/changeset/145975 .
Joshua Bell
Comment 72 2013-03-18 09:09:24 PDT
(In reply to comment #71) > FYI: this caused a build failure on Windows which was fixed in http://trac.webkit.org/changeset/145975 . Thanks for the fix, sorry about the breakage.
Note You need to log in before you can comment on or make changes to this bug.