[gjs/gnome-3-34] arg: Allow empty flat arrays of structs



commit 3b56f18af68ad176bd2a30d25b5ca89a569beeda
Author: Philip Chimento <philip chimento gmail com>
Date:   Mon Nov 25 09:53:20 2019 -0800

    arg: Allow empty flat arrays of structs
    
    We should be able to pass null or [] to a parameter expecting a flat
    array of structs even if passing anything else would crash. This case
    was inadvertently broken when we prevented the crash as part of #44.
    
    Closes: #289

 gi/arg.cpp                              | 43 +++++++++++++++++++++++++--------
 installed-tests/js/testIntrospection.js | 19 +++++++++++++++
 2 files changed, 52 insertions(+), 10 deletions(-)
---
diff --git a/gi/arg.cpp b/gi/arg.cpp
index 3e6aae5c..f1bb87b4 100644
--- a/gi/arg.cpp
+++ b/gi/arg.cpp
@@ -1052,14 +1052,32 @@ is_gvalue_flat_array(GITypeInfo *param_info,
 }
 
 GJS_JSAPI_RETURN_CONVENTION
-static bool
-gjs_array_to_array(JSContext   *context,
-                   JS::Value    array_value,
-                   gsize        length,
-                   GITransfer   transfer,
-                   GITypeInfo  *param_info,
-                   void       **arr_p)
-{
+static bool is_empty(JSContext* cx, JS::HandleValue array_value, bool* empty) {
+    if (array_value.isNull()) {
+        *empty = true;
+        return true;
+    }
+
+    bool is_array;
+    if (!JS_IsArrayObject(cx, array_value, &is_array))
+        return false;
+    if (!is_array) {
+        *empty = false;
+        return true;
+    }
+
+    JS::RootedObject array_object(cx, &array_value.toObject());
+    uint32_t length;
+    if (!JS_GetArrayLength(cx, array_object, &length))
+        return false;
+    *empty = (length == 0);
+    return true;
+}
+
+GJS_JSAPI_RETURN_CONVENTION
+static bool gjs_array_to_array(JSContext* context, JS::HandleValue array_value,
+                               size_t length, GITransfer transfer,
+                               GITypeInfo* param_info, void** arr_p) {
     enum { UNSIGNED=false, SIGNED=true };
     GITypeTag element_type;
 
@@ -1127,8 +1145,13 @@ gjs_array_to_array(JSContext   *context,
             GjsAutoBaseInfo interface_info =
                 g_type_info_get_interface(param_info);
             GIInfoType info_type = g_base_info_get_type(interface_info);
-            if (info_type == GI_INFO_TYPE_STRUCT ||
-                info_type == GI_INFO_TYPE_UNION) {
+
+            bool array_is_empty;
+            if (!is_empty(context, array_value, &array_is_empty))
+                return false;
+
+            if (!array_is_empty && (info_type == GI_INFO_TYPE_STRUCT ||
+                                    info_type == GI_INFO_TYPE_UNION)) {
                 gjs_throw(context,
                       "Flat array of type %s is not currently supported",
                       interface_info.name());
diff --git a/installed-tests/js/testIntrospection.js b/installed-tests/js/testIntrospection.js
index 814beb27..f81751b0 100644
--- a/installed-tests/js/testIntrospection.js
+++ b/installed-tests/js/testIntrospection.js
@@ -28,6 +28,25 @@ describe('Unsafe integer marshalling', function () {
     });
 });
 
+describe('Marshalling empty flat arrays of structs', function () {
+    let widget;
+    beforeAll(function () {
+        Gtk.init(null);
+    });
+
+    beforeEach(function () {
+        widget = new Gtk.Label();
+    });
+
+    it('accepts null', function () {
+        widget.drag_dest_set(0, null, Gdk.DragAction.COPY);
+    });
+
+    it('accepts an empty array', function () {
+        widget.drag_dest_set(0, [], Gdk.DragAction.COPY);
+    });
+});
+
 describe('Constructor', function () {
     it('throws when constructor called without new', function () {
         expect(() => Gio.AppLaunchContext())


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