[gjs] arg: Warn on lossy conversion from (u)int64



commit 048fceed7b8501f23d06bbdb109aa235767be4a1
Author: Philip Chimento <philip chimento gmail com>
Date:   Thu Feb 23 22:52:51 2017 -0800

    arg: Warn on lossy conversion from (u)int64
    
    Previously, a conversion from 64-bit integer that could not be stored
    exactly in a double, would trip an assertion in debug mode SpiderMonkey.
    This new behaviour in SpiderMonkey 38 would cause code like
    "GLib.MAXINT64" to crash.
    
    Instead, we check for that situation, log a warning for the developer,
    and proceed with the lossy value.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=778705

 gi/arg.cpp                                |   17 +++++++++++++++--
 installed-tests/js/testEverythingBasic.js |   12 ++++++++++++
 2 files changed, 27 insertions(+), 2 deletions(-)
---
diff --git a/gi/arg.cpp b/gi/arg.cpp
index b867ab8..d1194ef 100644
--- a/gi/arg.cpp
+++ b/gi/arg.cpp
@@ -2572,6 +2572,13 @@ gjs_object_from_g_hash (JSContext             *context,
     return result;
 }
 
+template<typename T>
+static bool
+is_safe_to_store_in_double(T number)
+{
+    return static_cast<T>(static_cast<double>(number)) == number;
+}
+
 bool
 gjs_value_from_g_argument (JSContext             *context,
                            JS::MutableHandleValue value_p,
@@ -2607,11 +2614,17 @@ gjs_value_from_g_argument (JSContext             *context,
         break;
 
     case GI_TYPE_TAG_INT64:
-        value_p.set(JS::NumberValue(arg->v_int64));
+        if (!is_safe_to_store_in_double(arg->v_int64))
+            g_warning("Value %" G_GINT64_FORMAT " cannot be safely stored in "
+                      "a JS Number and will be rounded", arg->v_int64);
+        value_p.setNumber(static_cast<double>(arg->v_int64));
         break;
 
     case GI_TYPE_TAG_UINT64:
-        value_p.set(JS::NumberValue(arg->v_uint64));
+        if (!is_safe_to_store_in_double(arg->v_uint64))
+            g_warning("Value %" G_GUINT64_FORMAT " cannot be safely stored in "
+                      "a JS Number and will be rounded", arg->v_uint64);
+        value_p.setNumber(static_cast<double>(arg->v_uint64));
         break;
 
     case GI_TYPE_TAG_UINT16:
diff --git a/installed-tests/js/testEverythingBasic.js b/installed-tests/js/testEverythingBasic.js
index 8e6d953..fda1204 100644
--- a/installed-tests/js/testEverythingBasic.js
+++ b/installed-tests/js/testEverythingBasic.js
@@ -101,6 +101,18 @@ describe('Life, the Universe and Everything', function () {
                 run_test(bytes, 'MAX', 'test_int');
             });
         });
+
+        it('warns when conversion is lossy', function () {
+            GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_WARNING,
+                "*cannot be safely stored*");
+            GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_WARNING,
+                "*cannot be safely stored*");
+            void GLib.MAXINT64;
+            void GLib.MAXUINT64;
+            GLib.test_assert_expected_messages_internal('Gjs',
+                'testEverythingBasic.js', 0,
+                'Limits warns when conversion is lossy');
+        });
     });
 
     describe('No implicit conversion to unsigned', function () {


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]