From 62025d4a2738a36ea5f1a7cebef08b22b5eef613 Mon Sep 17 00:00:00 2001 From: Evan Welsh Date: Fri, 24 Sep 2021 22:17:04 +0000 Subject: [PATCH] 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..49f36d76 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) + return true; + + // Otherwise, throw an error to prevent a segfault. + if (!arg) { + 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++; -- GitLab