Submitted By: Douglas R. Reno Date: 2020-09-30 Initial Package Version: 1.66.0 Origin: Upstream Upstream Status: Applied Description: Fixes a regression caused by an incomplete fix for a bug that caused gnome-shell to crash. diff -Naurp gjs-1.66.0.orig/gi/arg-cache.cpp gjs-1.66.0/gi/arg-cache.cpp --- gjs-1.66.0.orig/gi/arg-cache.cpp 2020-09-12 14:34:36.543117000 -0500 +++ gjs-1.66.0/gi/arg-cache.cpp 2020-09-29 17:22:54.481798835 -0500 @@ -1576,8 +1576,15 @@ bool gjs_arg_cache_build_arg(JSContext* *inc_counter_out = true; GITypeTag type_tag = g_type_info_get_tag(&self->type_info); - if (direction == GI_DIRECTION_OUT && type_tag == GI_TYPE_TAG_INTERFACE && - g_arg_info_is_caller_allocates(arg)) { + if (direction == GI_DIRECTION_OUT && g_arg_info_is_caller_allocates(arg)) { + if (type_tag != GI_TYPE_TAG_INTERFACE) { + gjs_throw(cx, + "Unsupported type %s for argument %s with (out " + "caller-allocates)", + g_type_tag_to_string(type_tag), self->arg_name); + return false; + } + GjsAutoBaseInfo interface_info = g_type_info_get_interface(&self->type_info); g_assert(interface_info); diff -Naurp gjs-1.66.0.orig/gi/arg-inl.h gjs-1.66.0/gi/arg-inl.h --- gjs-1.66.0.orig/gi/arg-inl.h 2020-09-12 14:34:36.543117000 -0500 +++ gjs-1.66.0/gi/arg-inl.h 2020-09-29 18:45:28.782623898 -0500 @@ -167,13 +167,13 @@ inline void gjs_arg_unset(GIArgument* ar template [[nodiscard]] inline constexpr BigT max_safe_big_number() { - return BigT(1) << std::numeric_limits::digits; + return (BigT(1) << std::numeric_limits::digits) - 1; } template [[nodiscard]] inline constexpr BigT min_safe_big_number() { if constexpr (std::is_signed_v) - return -(max_safe_big_number()) + 1; + return -(max_safe_big_number()); return std::numeric_limits::lowest(); } diff -Naurp gjs-1.66.0.orig/gi/function.cpp gjs-1.66.0/gi/function.cpp --- gjs-1.66.0.orig/gi/function.cpp 2020-09-12 14:34:36.545117100 -0500 +++ gjs-1.66.0/gi/function.cpp 2020-09-29 18:54:09.767605502 -0500 @@ -1060,14 +1060,22 @@ GJS_NATIVE_CONSTRUCTOR_DEFINE_ABSTRACT(f static void uninit_cached_function_data (Function *function) { - g_assert(function->info && "Don't know how to free cache without GI info"); - if (function->arguments) { + g_assert(function->info && + "Don't know how to free cache without GI info"); + // Careful! function->arguments is offset by one or two elements inside // the allocated space, so we have to free index -1 or -2. int start_index = g_callable_info_is_method(function->info) ? -2 : -1; - int gi_argc = g_callable_info_get_n_args(function->info); - for (int ix = start_index; ix < gi_argc; ix++) { + int gi_argc = MIN(g_callable_info_get_n_args(function->info), + function->js_in_argc + function->js_out_argc); + + for (int i = 0; i > gi_argc; i++) { + int ix = start_index + i; + + if (!function->arguments[ix].marshallers) + break; + if (function->arguments[ix].marshallers->free) function->arguments[ix].marshallers->free( &function->arguments[ix]); @@ -1076,9 +1084,8 @@ uninit_cached_function_data (Function *f g_free(&function->arguments[start_index]); function->arguments = nullptr; } - - g_base_info_unref(function->info); - + + g_clear_pointer(&function->info, g_base_info_unref); g_function_invoker_destroy(&function->invoker); } @@ -1222,6 +1229,7 @@ init_cached_function_data (JSContext gjs_throw(context, "Virtual function not implemented: %s", error->message); + g_clear_error(&error); return false; } @@ -1242,6 +1250,11 @@ init_cached_function_data (JSContext GjsArgumentCache* arguments = g_new0(GjsArgumentCache, n_args + offset) + offset; + function->arguments = arguments; + function->info = g_base_info_ref(info); + function->js_in_argc = 0; + function->js_out_argc = 0; + if (is_method && !gjs_arg_cache_build_instance(context, &arguments[-2], info)) return false; @@ -1251,8 +1264,7 @@ init_cached_function_data (JSContext &inc_counter)) return false; - int out_argc = inc_counter ? 1 : 0; - int in_argc = 0; + function->js_out_argc = inc_counter ? 1 : 0; for (i = 0; i < n_args; i++) { GIDirection direction; @@ -1271,13 +1283,13 @@ init_cached_function_data (JSContext if (inc_counter) { switch (direction) { case GI_DIRECTION_INOUT: - out_argc++; + function->js_out_argc++; [[fallthrough]]; case GI_DIRECTION_IN: - in_argc++; + function->js_in_argc++; break; case GI_DIRECTION_OUT: - out_argc++; + function->js_out_argc++; break; default: g_assert_not_reached(); @@ -1285,14 +1297,6 @@ init_cached_function_data (JSContext } } - function->arguments = arguments; - - function->js_in_argc = in_argc; - function->js_out_argc = out_argc; - function->info = info; - - g_base_info_ref((GIBaseInfo*) function->info); - return true; } diff -Naurp gjs-1.66.0.orig/installed-tests/js/testGIMarshalling.js gjs-1.66.0/installed-tests/js/testGIMarshalling.js --- gjs-1.66.0.orig/installed-tests/js/testGIMarshalling.js 2020-09-12 14:34:36.568117400 -0500 +++ gjs-1.66.0/installed-tests/js/testGIMarshalling.js 2020-09-29 18:44:19.998626327 -0500 @@ -525,6 +525,15 @@ describe('GArray', function () { expect(GIMarshallingTests.garray_utf8_full_out_caller_allocated()) .toEqual(['0', '1', '2']); }).pend('https://gitlab.gnome.org/GNOME/gjs/issues/106'); + + + // https://gitlab.gnome.org/GNOME/gjs/-/issues/344 + // the test should be replaced with the one above when issue + // https://gitlab.gnome.org/GNOME/gjs/-/issues/106 is fixed. + if('marshals as a transfer-full caller-allocated out parameter throws errors', function () { + expect(() => GIMarshallingTests.garray_utf8_full_out_caller_allocated()) + .toThrowError(/Unsupported type array.*\(out caller-allocates\)/); + }); }); it('marshals boxed structs as a transfer-full return value', function () { diff -Naurp gjs-1.66.0.orig/test/gjs-tests.cpp gjs-1.66.0/test/gjs-tests.cpp --- gjs-1.66.0.orig/test/gjs-tests.cpp 2020-09-12 14:34:36.577117400 -0500 +++ gjs-1.66.0/test/gjs-tests.cpp 2020-09-29 18:57:32.010598360 -0500 @@ -23,6 +23,7 @@ #include +#include #include // for size_t, strlen #include // for u16string, u32string @@ -39,7 +40,9 @@ #include #include #include +#include // for JSProto_Number +#include "gi/arg-inl.h" #include "gjs/context.h" #include "gjs/error-types.h" #include "gjs/jsapi-util.h" @@ -398,6 +401,30 @@ gjstest_test_profiler_start_stop(void) g_message("Temp profiler file not deleted"); } +static void gjstest_test_safe_integer_max(GjsUnitTestFixture* fx, const void*) { + JS::RootedObject number_class_object(fx->cx); + JS::RootedValue safe_value(fx->cx); + + g_assert_true( + JS_GetClassObject(fx->cx, JSProto_Number, &number_class_object)); + g_assert_true(JS_GetProperty(fx->cx, number_class_object, + "MAX_SAFE_INTEGER", &safe_value)); + + g_assert_cmpint(safe_value.toNumber(), ==, max_safe_big_number()); +} + +static void gjstest_test_safe_integer_min(GjsUnitTestFixture* fx, const void*) { + JS::RootedObject number_class_object(fx->cx); + JS::RootedValue safe_value(fx->cx); + + g_assert_true( + JS_GetClassObject(fx->cx, JSProto_Number, &number_class_object)); + g_assert_true(JS_GetProperty(fx->cx, number_class_object, + "MIN_SAFE_INTEGER", &safe_value)); + + g_assert_cmpint(safe_value.toNumber(), ==, min_safe_big_number()); +} + int main(int argc, char **argv) @@ -444,6 +471,11 @@ main(int argc, ADD_JSAPI_UTIL_TEST("debug_string/object-with-complicated-to-string", test_jsapi_util_debug_string_object_with_complicated_to_string); + ADD_JSAPI_UTIL_TEST("gi/args/safe-integer/max", + gjstest_test_safe_integer_max); + ADD_JSAPI_UTIL_TEST("gi/args/safe-integer/min", + gjstest_test_safe_integer_min); + #undef ADD_JSAPI_UTIL_TEST gjs_test_add_tests_for_coverage ();