[gjs/ewlsh/callback-out-args] Handle optional out parameters in callbacks




commit edd3540ad4c17ae0fbed6c83dfc87fa98103ec87
Author: Evan Welsh <contact evanwelsh com>
Date:   Sun Sep 19 17:31:16 2021 -0700

    Handle optional out parameters in callbacks
    
    Fixes #439

 gi/arg.cpp      | 26 ++++++++++++++++++++------
 gi/arg.h        |  6 ++----
 gi/function.cpp | 14 ++++++++------
 3 files changed, 30 insertions(+), 16 deletions(-)
---
diff --git a/gi/arg.cpp b/gi/arg.cpp
index 0b8af141..16e564d4 100644
--- a/gi/arg.cpp
+++ b/gi/arg.cpp
@@ -1861,17 +1861,31 @@ void gjs_gi_argument_init_default(GITypeInfo* type_info, GIArgument* arg) {
     }
 }
 
-bool
-gjs_value_to_arg(JSContext      *context,
-                 JS::HandleValue value,
-                 GIArgInfo      *arg_info,
-                 GIArgument     *arg)
-{
+bool gjs_value_to_callback_out_arg(JSContext* context, JS::HandleValue value,
+                                   GIArgInfo* arg_info, GIArgument* arg) {
+    GIDirection direction [[maybe_unused]] = g_arg_info_get_direction(arg_info);
+    g_assert(
+        (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT) &&
+        "gjs_value_to_callback_out_arg does not handle in arguments.");
+
     GjsArgumentFlags flags = GjsArgumentFlags::NONE;
     GITypeInfo type_info;
 
     g_arg_info_load_type(arg_info, &type_info);
 
+    // If the argument is optional and we're passed nullptr,
+    // ignore the GJS value.
+    if (g_arg_info_is_optional(arg_info) && arg == nullptr)
+        return true;
+
+    // Otherwise, throw an error to prevent a segfault.
+    if (arg == nullptr) {
+        gjs_throw(context,
+                  "Return value %s is not optional but was passed NULL",
+                  g_base_info_get_name(arg_info));
+        return false;
+    }
+
     if (g_arg_info_may_be_null(arg_info))
         flags |= GjsArgumentFlags::MAY_BE_NULL;
     if (g_arg_info_is_caller_allocates(arg_info))
diff --git a/gi/arg.h b/gi/arg.h
index c81c2979..c5c81760 100644
--- a/gi/arg.h
+++ b/gi/arg.h
@@ -44,10 +44,8 @@ enum class GjsArgumentFlags : uint8_t {
                                               GjsArgumentType arg_type);
 
 GJS_JSAPI_RETURN_CONVENTION
-bool gjs_value_to_arg(JSContext      *context,
-                      JS::HandleValue value,
-                      GIArgInfo      *arg_info,
-                      GIArgument     *arg);
+bool gjs_value_to_callback_out_arg(JSContext* context, JS::HandleValue value,
+                                   GIArgInfo* arg_info, GIArgument* arg);
 
 GJS_JSAPI_RETURN_CONVENTION
 bool gjs_array_to_explicit_array(JSContext* cx, JS::HandleValue value,
diff --git a/gi/function.cpp b/gi/function.cpp
index 25fea26f..da060607 100644
--- a/gi/function.cpp
+++ b/gi/function.cpp
@@ -532,9 +532,10 @@ bool GjsCallbackTrampoline::callback_closure_inner(
             if (g_arg_info_get_direction(&arg_info) == GI_DIRECTION_IN)
                 continue;
 
-            if (!gjs_value_to_arg(context, rval, &arg_info,
-                                  get_argument_for_arg_info(&arg_info, args,
-                                                            i + c_args_offset)))
+            if (!gjs_value_to_callback_out_arg(
+                    context, rval, &arg_info,
+                    get_argument_for_arg_info(&arg_info, args,
+                                              i + c_args_offset)))
                 return false;
 
             break;
@@ -587,9 +588,10 @@ bool GjsCallbackTrampoline::callback_closure_inner(
             if (!JS_GetElement(context, out_array, elem_idx, &elem))
                 return false;
 
-            if (!gjs_value_to_arg(context, elem, &arg_info,
-                                  get_argument_for_arg_info(&arg_info, args,
-                                                            i + c_args_offset)))
+            if (!gjs_value_to_callback_out_arg(
+                    context, elem, &arg_info,
+                    get_argument_for_arg_info(&arg_info, args,
+                                              i + c_args_offset)))
                 return false;
 
             elem_idx++;


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