summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Keller <skeller@gnome.org>2023-03-16 22:35:49 +0100
committerSebastian Keller <skeller@gnome.org>2023-04-06 02:11:01 +0200
commitc925d91e5d018f38b0f66d0ac592274d4b007efb (patch)
treee0f9a8e4767bcf7873dfcca5c8b7f5cd3046475c
parent5b1e0a3ccdcf394cf746ef4e75b7b69f1535a710 (diff)
downloadgjs-c925d91e5d018f38b0f66d0ac592274d4b007efb.tar.gz
function: Always initialize callback return value
When callback_closure() exits early, for example due to being called during GC, the return value would not be initialized. This value is often non-zero. If the callback is a source func of an idle or a timeout this would then get interpreted as G_SOURCE_CONTINUE and the same would repeat in the next iteration. If this happens fast enough, this results in the entire process being seemingly frozen while spamming the log with error messages. To fix this always initialize the return value to 0 or a comparable neutral value. Related: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/1868
-rw-r--r--gi/function.cpp18
1 files changed, 8 insertions, 10 deletions
diff --git a/gi/function.cpp b/gi/function.cpp
index cf94b39e..3fb87939 100644
--- a/gi/function.cpp
+++ b/gi/function.cpp
@@ -297,6 +297,14 @@ void GjsCallbackTrampoline::warn_about_illegal_js_callback(const char* when,
void GjsCallbackTrampoline::callback_closure(GIArgument** args, void* result) {
GITypeInfo ret_type;
+ // Fill in the result with some hopefully neutral value
+ g_callable_info_load_return_type(m_info, &ret_type);
+ if (g_type_info_get_tag(&ret_type) != GI_TYPE_TAG_VOID) {
+ GIArgument argument = {};
+ gjs_gi_argument_init_default(&ret_type, &argument);
+ set_return_ffi_arg_from_giargument(&ret_type, result, &argument);
+ }
+
if (G_UNLIKELY(!is_valid())) {
warn_about_illegal_js_callback(
"during shutdown",
@@ -375,8 +383,6 @@ void GjsCallbackTrampoline::callback_closure(GIArgument** args, void* result) {
JS::RootedValue rval(context);
- g_callable_info_load_return_type(m_info, &ret_type);
-
if (!callback_closure_inner(context, this_object, gobj, &rval, args,
&ret_type, n_args, c_args_offset, result)) {
if (!JS_IsExceptionPending(context)) {
@@ -399,14 +405,6 @@ void GjsCallbackTrampoline::callback_closure(GIArgument** args, void* result) {
descr.c_str(), m_info.ns(), m_info.name());
}
- // Fill in the result with some hopefully neutral value
- if (g_type_info_get_tag(&ret_type) != GI_TYPE_TAG_VOID) {
- GIArgument argument = {};
- g_callable_info_load_return_type(m_info, &ret_type);
- gjs_gi_argument_init_default(&ret_type, &argument);
- set_return_ffi_arg_from_giargument(&ret_type, result, &argument);
- }
-
// If the callback has a GError** argument, then make a GError from the
// value that was thrown. Otherwise, log it as "uncaught" (critical
// instead of warning)