https://bugs.webkit.org/show_bug.cgi?id=181182
Reviewed by Darin Adler.
JSTests:
* stress/big-int-prototype-to-string-cast-overflow.js: Added.
* stress/big-int-prototype-to-string-exception.js: Added.
* stress/big-int-prototype-to-string-wrong-values.js: Added.
* stress/number-prototype-to-string-cast-overflow.js: Added.
* stress/number-prototype-to-string-exception.js: Added.
* stress/number-prototype-to-string-wrong-values.js: Added.
Source/JavaScriptCore:
Casting double to integer is undefined behavior when the truncation
results into a value that doesn't fit into integer size,
according C++ spec[1]. Thus, we are changing bigIntProtoFuncToString and
numberProtoFuncToString to remove these source of undefined
behavior.
[1] - http://en.cppreference.com/w/cpp/language/implicit_conversion
* runtime/BigIntPrototype.cpp:
(JSC::bigIntProtoFuncToString):
* runtime/NumberPrototype.cpp:
(JSC::numberProtoFuncToString):
(JSC::extractToStringRadixArgument):
(JSC::extractRadixFromArgs): Deleted.
* runtime/NumberPrototype.h:
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@227271
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2018-01-20 Caio Lima <ticaiolima@gmail.com>
+
+ [JSC] NumberPrototype::extractRadixFromArgs incorrectly cast double to int32_t
+ https://bugs.webkit.org/show_bug.cgi?id=181182
+
+ Reviewed by Darin Adler.
+
+ * stress/big-int-prototype-to-string-cast-overflow.js: Added.
+ * stress/big-int-prototype-to-string-exception.js: Added.
+ * stress/big-int-prototype-to-string-wrong-values.js: Added.
+ * stress/number-prototype-to-string-cast-overflow.js: Added.
+ * stress/number-prototype-to-string-exception.js: Added.
+ * stress/number-prototype-to-string-wrong-values.js: Added.
+
2018-01-19 Ryan Haddad <ryanhaddad@apple.com>
Disable Atomics when SharedArrayBuffer isn’t enabled
--- /dev/null
+//@ runBigIntEnabled
+
+function assert(a) {
+ if (!a)
+ throw new Error("Bad assertion");
+}
+
+function assertThrowRangeError(input) {
+ try {
+ let number = 3n;
+ number.toString(input);
+ assert(false);
+ } catch (e) {
+ assert(e instanceof RangeError);
+ }
+}
+
+assertThrowRangeError(1e100);
+assertThrowRangeError(-1e101);
+
--- /dev/null
+//@ runBigIntEnabled
+
+function assert(a) {
+ if (!a)
+ throw new Error("Bad assertion");
+}
+
+let o = {
+ valueOf: () => {
+ throw new Error("Bad");
+ return 2;
+ }
+}
+
+let a = 20n;
+try {
+ a.toString(o);
+ assert(false);
+} catch (e) {
+ assert(e.message == "Bad");
+}
+
--- /dev/null
+//@ runBigIntEnabled
+
+function assert(a) {
+ if (!a)
+ throw new Error("Bad assertion");
+}
+
+function assertRangeError(v) {
+ let a = 456n;
+ try {
+ a.toString(v);
+ assert(false);
+ } catch (e) {
+ assert(e instanceof RangeError);
+ }
+}
+
+assertRangeError(1);
+assertRangeError(37);
+assertRangeError(37.1);
+assertRangeError(37.2);
+assertRangeError(0);
+assertRangeError(-1);
+assertRangeError(1.999999);
+assertRangeError(37.00000000000000001);
+assertRangeError(NaN);
+assertRangeError(null);
+assertRangeError(+Infinity);
+assertRangeError(-Infinity);
+assertRangeError(-0);
+
--- /dev/null
+function assert(a) {
+ if (!a)
+ throw new Error("Bad assertion");
+}
+
+function assertThrowRangeError(input) {
+ try {
+ let number = 3;
+ number.toString(input);
+ assert(false);
+ } catch (e) {
+ assert(e instanceof RangeError);
+ }
+}
+
+assertThrowRangeError(1e100);
+assertThrowRangeError(-1e101);
+
--- /dev/null
+function assert(a) {
+ if (!a)
+ throw new Error("Bad assertion");
+}
+
+let o = {
+ valueOf: () => {
+ throw new Error("Bad");
+ return 2;
+ }
+}
+
+let a = 2;
+try {
+ a.toString(o);
+ assert(false);
+} catch (e) {
+ assert(e.message == "Bad");
+}
+
--- /dev/null
+function assert(a) {
+ if (!a)
+ throw new Error("Bad assertion");
+}
+
+function assertRangeError(v) {
+ let a = 2;
+ try {
+ a.toString(v);
+ assert(false);
+ } catch (e) {
+ assert(e instanceof RangeError);
+ }
+}
+
+assertRangeError(1);
+assertRangeError(37);
+assertRangeError(37.1);
+assertRangeError(37.2);
+assertRangeError(0);
+assertRangeError(-1);
+assertRangeError(1.999999);
+assertRangeError(37.00000000000000001);
+assertRangeError(NaN);
+assertRangeError(null);
+assertRangeError(+Infinity);
+assertRangeError(-Infinity);
+assertRangeError(-0);
+
+2018-01-20 Caio Lima <ticaiolima@gmail.com>
+
+ [JSC] NumberPrototype::extractRadixFromArgs incorrectly cast double to int32_t
+ https://bugs.webkit.org/show_bug.cgi?id=181182
+
+ Reviewed by Darin Adler.
+
+ Casting double to integer is undefined behavior when the truncation
+ results into a value that doesn't fit into integer size,
+ according C++ spec[1]. Thus, we are changing bigIntProtoFuncToString and
+ numberProtoFuncToString to remove these source of undefined
+ behavior.
+
+ [1] - http://en.cppreference.com/w/cpp/language/implicit_conversion
+
+ * runtime/BigIntPrototype.cpp:
+ (JSC::bigIntProtoFuncToString):
+ * runtime/NumberPrototype.cpp:
+ (JSC::numberProtoFuncToString):
+ (JSC::extractToStringRadixArgument):
+ (JSC::extractRadixFromArgs): Deleted.
+ * runtime/NumberPrototype.h:
+
2018-01-19 Saam Barati <sbarati@apple.com>
Kill ArithNegate's ArithProfile assert inside BytecodeParser
#include "JSFunction.h"
#include "JSGlobalObject.h"
#include "JSString.h"
+#include "NumberPrototype.h"
#include <wtf/Assertions.h>
namespace JSC {
ASSERT(value);
- int64_t radix;
- JSValue radixValue = state->argument(0);
- if (radixValue.isInt32())
- radix = radixValue.asInt32();
- else if (radixValue.isUndefined())
- radix = 10;
- else {
- radix = static_cast<int64_t>(radixValue.toInteger(state));
- RETURN_IF_EXCEPTION(scope, encodedJSValue());
- }
-
- if (radix < 2 || radix > 36)
- return throwVMError(state, scope, createRangeError(state, ASCIILiteral("toString() radix argument must be between 2 and 36")));
+ int32_t radix = extractToStringRadixArgument(state, state->argument(0), scope);
+ RETURN_IF_EXCEPTION(scope, encodedJSValue());
- String resultString = value->toString(*state, static_cast<int32_t>(radix));
+ String resultString = value->toString(*state, radix);
RETURN_IF_EXCEPTION(scope, encodedJSValue());
+ scope.release();
if (resultString.length() == 1)
return JSValue::encode(vm.smallStrings.singleCharacterString(resultString[0]));
- scope.release();
return JSValue::encode(jsNontrivialString(&vm, resultString));
}
return JSValue::encode(jsString(exec, String(numberToFixedPrecisionString(x, significantFigures, buffer))));
}
-static inline int32_t extractRadixFromArgs(ExecState* exec)
-{
- JSValue radixValue = exec->argument(0);
- int32_t radix;
- if (radixValue.isInt32())
- radix = radixValue.asInt32();
- else if (radixValue.isUndefined())
- radix = 10;
- else
- radix = static_cast<int32_t>(radixValue.toInteger(exec)); // nan -> 0
-
- return radix;
-}
-
static ALWAYS_INLINE JSString* int32ToStringInternal(VM& vm, int32_t value, int32_t radix)
{
ASSERT(!(radix < 2 || radix > 36));
return numberToStringInternal(vm, doubleValue, radix);
}
-EncodedJSValue JSC_HOST_CALL numberProtoFuncToString(ExecState* exec)
+EncodedJSValue JSC_HOST_CALL numberProtoFuncToString(ExecState* state)
{
- VM& vm = exec->vm();
+ VM& vm = state->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
double doubleValue;
- if (!toThisNumber(exec->thisValue(), doubleValue))
- return throwVMTypeError(exec, scope);
+ if (!toThisNumber(state->thisValue(), doubleValue))
+ return throwVMTypeError(state, scope);
- int32_t radix = extractRadixFromArgs(exec);
+ auto radix = extractToStringRadixArgument(state, state->argument(0), scope);
RETURN_IF_EXCEPTION(scope, encodedJSValue());
- if (radix < 2 || radix > 36)
- return throwVMError(exec, scope, createRangeError(exec, ASCIILiteral("toString() radix argument must be between 2 and 36")));
- scope.release();
return JSValue::encode(numberToStringInternal(vm, doubleValue, radix));
}
return JSValue::encode(jsNumber(x));
}
+int32_t extractToStringRadixArgument(ExecState* state, JSValue radixValue, ThrowScope& throwScope)
+{
+ if (radixValue.isUndefined())
+ return 10;
+
+ if (radixValue.isInt32()) {
+ int32_t radix = radixValue.asInt32();
+ if (radix >= 2 && radix <= 36)
+ return radix;
+ } else {
+ double radixDouble = radixValue.toInteger(state);
+ RETURN_IF_EXCEPTION(throwScope, 0);
+ if (radixDouble >= 2 && radixDouble <= 36)
+ return static_cast<int32_t>(radixDouble);
+ }
+
+ throwRangeError(state, throwScope, ASCIILiteral("toString() radix argument must be between 2 and 36"));
+ return 0;
+}
+
} // namespace JSC
JSString* int52ToString(VM&, int64_t value, int32_t radix);
JSString* numberToString(VM&, double value, int32_t radix);
String toStringWithRadix(double doubleValue, int32_t radix);
+int32_t extractToStringRadixArgument(ExecState*, JSValue radixValue, ThrowScope&);
} // namespace JSC