summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordavidot <davidot@serenityos.org>2022-08-16 18:25:20 +0200
committerLinus Groh <mail@linusgroh.de>2022-08-17 23:56:24 +0100
commit0f9434a02cb8d3be1d02eacf386839f0ac06cfda (patch)
tree3478907fa297d5b1e5bc6a6fd785a3e673f53523
parent9d05ca7b20e30454b9751e00a8765feebac58a53 (diff)
downloadserenity-0f9434a02cb8d3be1d02eacf386839f0ac06cfda.zip
LibJS: Make StringToNumber case sensitive when falling back to strtod
We use strtod to convert a string to number after checking whether the string is [+-]Infinity, however strtod also checks for either 'inf' or 'infinity' in a case-insensitive. There are still valid cases for strtod to return infinity like 10e100000 so we just check if the "number" contains 'i' or 'I' in which case the strtod infinity is not valid.
-rw-r--r--Userland/Libraries/LibJS/Runtime/Value.cpp5
-rw-r--r--Userland/Libraries/LibJS/Tests/builtins/Number/Number.js14
2 files changed, 19 insertions, 0 deletions
diff --git a/Userland/Libraries/LibJS/Runtime/Value.cpp b/Userland/Libraries/LibJS/Runtime/Value.cpp
index 77fc975649..7c3f9445d5 100644
--- a/Userland/Libraries/LibJS/Runtime/Value.cpp
+++ b/Userland/Libraries/LibJS/Runtime/Value.cpp
@@ -500,6 +500,11 @@ ThrowCompletionOr<Value> Value::to_number(GlobalObject& global_object) const
auto parsed_double = strtod(string.characters(), &endptr);
if (*endptr)
return js_nan();
+ // NOTE: Per the spec only exactly [+-]Infinity should result in infinity
+ // but strtod gives infinity for any case-insensitive 'infinity' or 'inf' string.
+ if (isinf(parsed_double) && string.contains('i', AK::CaseSensitivity::CaseInsensitive))
+ return js_nan();
+
return Value(parsed_double);
}
case SYMBOL_TAG:
diff --git a/Userland/Libraries/LibJS/Tests/builtins/Number/Number.js b/Userland/Libraries/LibJS/Tests/builtins/Number/Number.js
index 7ee0f557a9..7a237dd21b 100644
--- a/Userland/Libraries/LibJS/Tests/builtins/Number/Number.js
+++ b/Userland/Libraries/LibJS/Tests/builtins/Number/Number.js
@@ -17,11 +17,18 @@ test("constructor without new", () => {
expect(Number("Infinity")).toBe(Infinity);
expect(Number("+Infinity")).toBe(Infinity);
expect(Number("-Infinity")).toBe(-Infinity);
+ expect(Number("infinity")).toBeNaN();
+ expect(Number("-infinity")).toBeNaN();
+ expect(Number("INFINITY")).toBeNaN();
+ expect(Number("-INFINITY")).toBeNaN();
+ expect(Number("inf")).toBeNaN();
expect(Number(undefined)).toBeNaN();
expect(Number({})).toBeNaN();
expect(Number({ a: 1 })).toBeNaN();
expect(Number([1, 2, 3])).toBeNaN();
expect(Number("foo")).toBeNaN();
+ expect(Number("10e10000")).toBe(Infinity);
+ expect(Number("-10e10000")).toBe(-Infinity);
});
test("constructor with new", () => {
@@ -38,9 +45,16 @@ test("constructor with new", () => {
expect(new Number("Infinity").valueOf()).toBe(Infinity);
expect(new Number("+Infinity").valueOf()).toBe(Infinity);
expect(new Number("-Infinity").valueOf()).toBe(-Infinity);
+ expect(new Number("infinity").valueOf()).toBeNaN();
+ expect(new Number("-infinity").valueOf()).toBeNaN();
+ expect(new Number("INFINITY").valueOf()).toBeNaN();
+ expect(new Number("-INFINITY").valueOf()).toBeNaN();
+ expect(new Number("inf").valueOf()).toBeNaN();
expect(new Number(undefined).valueOf()).toBeNaN();
expect(new Number({}).valueOf()).toBeNaN();
expect(new Number({ a: 1 }).valueOf()).toBeNaN();
expect(new Number([1, 2, 3]).valueOf()).toBeNaN();
expect(new Number("foo").valueOf()).toBeNaN();
+ expect(new Number("10e10000").valueOf()).toBe(Infinity);
+ expect(new Number("-10e10000").valueOf()).toBe(-Infinity);
});