[gjs: 2/3] value: Fix regression converting Infinity and NaN to C integers
- From: Philip Chimento <pchimento src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gjs: 2/3] value: Fix regression converting Infinity and NaN to C integers
- Date: Sun, 13 Feb 2022 19:47:49 +0000 (UTC)
commit 4d8e71c6a651f484fa07857852aa41eeb4131c80
Author: Philip Chimento <philip chimento gmail com>
Date: Wed Feb 9 22:15:14 2022 -0800
value: Fix regression converting Infinity and NaN to C integers
This regression has been around somewhat longer, but JS::ToInt32,
JS::ToInt64, and friends all treat Infinity and NaN as 0 when converting
to APIs that expect an integer. GJS used to do this as well. Add tests so
it doesn't regress again.
Additionally add tests for float and double, to make sure that Infinity
and NaN are preserved when converting to C float and double.
gi/js-value-inl.h | 17 ++++++++++++++++-
installed-tests/js/testRegress.js | 25 +++++++++++++++++++++++++
2 files changed, 41 insertions(+), 1 deletion(-)
---
diff --git a/gi/js-value-inl.h b/gi/js-value-inl.h
index fe5be3c0f..debfe1527 100644
--- a/gi/js-value-inl.h
+++ b/gi/js-value-inl.h
@@ -248,6 +248,10 @@ GJS_JSAPI_RETURN_CONVENTION inline bool js_value_to_c_checked(
bi = value.toBigInt();
} else if (value.isNumber()) {
double number = value.toNumber();
+ if (!std::isfinite(number)) {
+ *out = 0;
+ return true;
+ }
number = std::trunc(number);
bi = JS::NumberToBigInt(cx, number);
if (!bi)
@@ -264,8 +268,10 @@ GJS_JSAPI_RETURN_CONVENTION inline bool js_value_to_c_checked(
if constexpr (std::is_same_v<WantedType, T>)
return js_value_to_c(cx, value, out);
+ // JS::ToIntNN() converts undefined, NaN, infinity to 0
if constexpr (std::is_integral_v<WantedType>) {
- if (value.isUndefined()) {
+ if (value.isUndefined() ||
+ (value.isDouble() && !std::isfinite(value.toDouble()))) {
*out = 0;
return true;
}
@@ -274,6 +280,15 @@ GJS_JSAPI_RETURN_CONVENTION inline bool js_value_to_c_checked(
if constexpr (std::is_arithmetic_v<T>) {
bool ret = js_value_to_c(cx, value, out);
if (out_of_range) {
+ // Infinity and NaN preserved between floating point types
+ if constexpr (std::is_floating_point_v<WantedType> &&
+ std::is_floating_point_v<T>) {
+ if (!std::isfinite(*out)) {
+ *out_of_range = false;
+ return ret;
+ }
+ }
+
*out_of_range =
(*out >
static_cast<T>(std::numeric_limits<WantedType>::max()) ||
diff --git a/installed-tests/js/testRegress.js b/installed-tests/js/testRegress.js
index f5935300a..36d062b28 100644
--- a/installed-tests/js/testRegress.js
+++ b/installed-tests/js/testRegress.js
@@ -124,6 +124,31 @@ describe('Life, the Universe and Everything', function () {
});
});
+ describe('Infinity and NaN', function () {
+ ['int8', 'int16', 'int32', 'int64', 'short', 'int', 'long', 'ssize'].forEach(type => {
+ it(`converts to 0 for ${type}`, function () {
+ expect(Regress[`test_${type}`](Infinity)).toBe(0);
+ expect(Regress[`test_${type}`](-Infinity)).toBe(0);
+ expect(Regress[`test_${type}`](NaN)).toBe(0);
+ });
+ });
+
+ ['uint8', 'uint16', 'uint32', 'uint64', 'ushort', 'uint', 'ulong', 'size'].forEach(type => {
+ it(`converts to 0 for ${type}`, function () {
+ expect(Regress[`test_${type}`](Infinity)).toBe(0);
+ expect(Regress[`test_${type}`](NaN)).toBe(0);
+ });
+ });
+
+ ['float', 'double'].forEach(type => {
+ it(`not for ${type}`, function () {
+ expect(Regress[`test_${type}`](Infinity)).toBe(Infinity);
+ expect(Regress[`test_${type}`](-Infinity)).toBe(-Infinity);
+ expect(Regress[`test_${type}`](NaN)).toBeNaN();
+ });
+ });
+ });
+
describe('(u)int64 numeric values', function () {
const minInt64 = -(2n ** 63n);
const maxInt64 = 2n ** 63n - 1n;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]