Add patch to fix AppIndicator extension crash
This commit is contained in:
parent
82841de5b8
commit
2398b179cd
258
gjs-1.71.1-promise-rejection.patch
Normal file
258
gjs-1.71.1-promise-rejection.patch
Normal file
@ -0,0 +1,258 @@
|
|||||||
|
From 3f0c615a802e196f5e14a9819a81e7c74fb6b988 Mon Sep 17 00:00:00 2001
|
||||||
|
From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= <mail@3v1n0.net>
|
||||||
|
Date: Mon, 21 Feb 2022 17:17:10 +0100
|
||||||
|
Subject: [PATCH 1/2] context: Only warn about unhandled promises when the job
|
||||||
|
queue is flushed
|
||||||
|
|
||||||
|
A promise rejection may be reported as not handled even though it's
|
||||||
|
going to be handled by a later added promise. In such case we were
|
||||||
|
correctly be informed about this via
|
||||||
|
unregister_unhandled_promise_rejection(), but given that since commit
|
||||||
|
4446ee7f we promptly warn about unhandled promise rejections our
|
||||||
|
unhandled rejections stack trace list was cleared earlier than we'd got
|
||||||
|
an unregistration event.
|
||||||
|
|
||||||
|
To avoid this, let's just wait for the job queue to be fully processed,
|
||||||
|
so that we won't accidentally clear the unhandled rejections list, until
|
||||||
|
those have been fully processed.
|
||||||
|
|
||||||
|
By doing this we are both avoiding misbehaving on the said case, and we
|
||||||
|
don't regress by keeping the exit-warns handled by #417 still valid.
|
||||||
|
|
||||||
|
Added tests to cover both a normal rejection case and the one that was
|
||||||
|
previously leading to a crash (assertion error).
|
||||||
|
|
||||||
|
Fixes: #466
|
||||||
|
---
|
||||||
|
gi/closure.cpp | 4 +-
|
||||||
|
gi/function.cpp | 6 +-
|
||||||
|
gjs/context.cpp | 6 +-
|
||||||
|
installed-tests/js/meson.build | 1 +
|
||||||
|
installed-tests/js/testPromise.js | 106 ++++++++++++++++++++++++++++++
|
||||||
|
5 files changed, 115 insertions(+), 8 deletions(-)
|
||||||
|
create mode 100644 installed-tests/js/testPromise.js
|
||||||
|
|
||||||
|
diff --git a/gi/closure.cpp b/gi/closure.cpp
|
||||||
|
index 15b6a5fe7..288550a05 100644
|
||||||
|
--- a/gi/closure.cpp
|
||||||
|
+++ b/gi/closure.cpp
|
||||||
|
@@ -183,7 +183,9 @@ bool Closure::invoke(JS::HandleObject this_obj,
|
||||||
|
JS::RootedFunction func(m_cx, m_func);
|
||||||
|
bool ok = JS::Call(m_cx, this_obj, func, args, retval);
|
||||||
|
GjsContextPrivate* gjs = GjsContextPrivate::from_cx(m_cx);
|
||||||
|
- gjs->warn_about_unhandled_promise_rejections();
|
||||||
|
+
|
||||||
|
+ if (gjs->should_exit(nullptr))
|
||||||
|
+ gjs->warn_about_unhandled_promise_rejections();
|
||||||
|
if (!ok) {
|
||||||
|
/* Exception thrown... */
|
||||||
|
gjs_debug_closure(
|
||||||
|
diff --git a/gi/function.cpp b/gi/function.cpp
|
||||||
|
index f39dc1727..716acc8ec 100644
|
||||||
|
--- a/gi/function.cpp
|
||||||
|
+++ b/gi/function.cpp
|
||||||
|
@@ -379,11 +379,11 @@ void GjsCallbackTrampoline::callback_closure(GIArgument** args, void* result) {
|
||||||
|
// main loop, or maybe not, but there's no way to tell, so we have
|
||||||
|
// to exit here instead of propagating the exception back to the
|
||||||
|
// original calling JS code.
|
||||||
|
- gjs->warn_about_unhandled_promise_rejections();
|
||||||
|
-
|
||||||
|
uint8_t code;
|
||||||
|
- if (gjs->should_exit(&code))
|
||||||
|
+ if (gjs->should_exit(&code)) {
|
||||||
|
+ gjs->warn_about_unhandled_promise_rejections();
|
||||||
|
exit(code);
|
||||||
|
+ }
|
||||||
|
|
||||||
|
// Some other uncatchable exception, e.g. out of memory
|
||||||
|
JSFunction* fn = callable();
|
||||||
|
diff --git a/gjs/context.cpp b/gjs/context.cpp
|
||||||
|
index 7a6eba6e7..0ba6b250a 100644
|
||||||
|
--- a/gjs/context.cpp
|
||||||
|
+++ b/gjs/context.cpp
|
||||||
|
@@ -1080,10 +1080,7 @@ bool GjsContextPrivate::run_jobs_fallible(GCancellable* cancellable) {
|
||||||
|
JSAutoRealm ar(m_cx, job);
|
||||||
|
gjs_debug(GJS_DEBUG_CONTEXT, "handling job %s",
|
||||||
|
gjs_debug_object(job).c_str());
|
||||||
|
- bool ok =
|
||||||
|
- JS::Call(m_cx, JS::UndefinedHandleValue, job, args, &rval);
|
||||||
|
- warn_about_unhandled_promise_rejections();
|
||||||
|
- if (!ok) {
|
||||||
|
+ if (!JS::Call(m_cx, JS::UndefinedHandleValue, job, args, &rval)) {
|
||||||
|
/* Uncatchable exception - return false so that
|
||||||
|
* System.exit() works in the interactive shell and when
|
||||||
|
* exiting the interpreter. */
|
||||||
|
@@ -1104,6 +1101,7 @@ bool GjsContextPrivate::run_jobs_fallible(GCancellable* cancellable) {
|
||||||
|
|
||||||
|
m_draining_job_queue = false;
|
||||||
|
m_job_queue.clear();
|
||||||
|
+ warn_about_unhandled_promise_rejections();
|
||||||
|
JS::JobQueueIsEmpty(m_cx);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
diff --git a/installed-tests/js/meson.build b/installed-tests/js/meson.build
|
||||||
|
index f531fd356..567e5cc7c 100644
|
||||||
|
--- a/installed-tests/js/meson.build
|
||||||
|
+++ b/installed-tests/js/meson.build
|
||||||
|
@@ -137,6 +137,7 @@ jasmine_tests = [
|
||||||
|
'Package',
|
||||||
|
'ParamSpec',
|
||||||
|
'Print',
|
||||||
|
+ 'Promise',
|
||||||
|
'Regress',
|
||||||
|
'Signals',
|
||||||
|
'System',
|
||||||
|
diff --git a/installed-tests/js/testPromise.js b/installed-tests/js/testPromise.js
|
||||||
|
new file mode 100644
|
||||||
|
index 000000000..df302bac2
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/installed-tests/js/testPromise.js
|
||||||
|
@@ -0,0 +1,106 @@
|
||||||
|
+// -*- mode: js; indent-tabs-mode: nil -*-
|
||||||
|
+// SPDX-License-Identifier: MIT OR LGPL-2.0-or-later
|
||||||
|
+// SPDX-FileContributor: Authored by: Marco Trevisan <marco.trevisan@canonical.com>
|
||||||
|
+// SPDX-FileCopyrightText: 2022 Canonical, Ltd.
|
||||||
|
+
|
||||||
|
+const {GLib} = imports.gi;
|
||||||
|
+
|
||||||
|
+class SubPromise extends Promise {
|
||||||
|
+ constructor(executor) {
|
||||||
|
+ super((resolve, reject) => {
|
||||||
|
+ executor(resolve, reject);
|
||||||
|
+ });
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+const PromiseResult = {
|
||||||
|
+ RESOLVED: 0,
|
||||||
|
+ FAILED: 1,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+describe('Promise', function () {
|
||||||
|
+ let loop;
|
||||||
|
+
|
||||||
|
+ beforeEach(function () {
|
||||||
|
+ loop = GLib.MainLoop.new(null, false);
|
||||||
|
+ });
|
||||||
|
+
|
||||||
|
+ function executePromise(promise) {
|
||||||
|
+ const promiseResult = {};
|
||||||
|
+
|
||||||
|
+ promise.then(value => {
|
||||||
|
+ promiseResult.result = PromiseResult.RESOLVED;
|
||||||
|
+ promiseResult.value = value;
|
||||||
|
+ }).catch(e => {
|
||||||
|
+ promiseResult.result = PromiseResult.FAILED;
|
||||||
|
+ promiseResult.error = e;
|
||||||
|
+ });
|
||||||
|
+
|
||||||
|
+ while (promiseResult.result === undefined)
|
||||||
|
+ loop.get_context().iteration(true);
|
||||||
|
+
|
||||||
|
+ return promiseResult;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ it('waits for all promises before handling unhandled, when handled', function () {
|
||||||
|
+ let error;
|
||||||
|
+ let resolved;
|
||||||
|
+
|
||||||
|
+ const promise = async () => {
|
||||||
|
+ await new SubPromise(resolve => resolve('success'));
|
||||||
|
+ const rejecting = new SubPromise((_resolve, reject) => reject('got error'));
|
||||||
|
+ try {
|
||||||
|
+ await rejecting;
|
||||||
|
+ } catch (e) {
|
||||||
|
+ error = e;
|
||||||
|
+ } finally {
|
||||||
|
+ resolved = true;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ expect(resolved).toBeTrue();
|
||||||
|
+ expect(error).toBe('got error');
|
||||||
|
+
|
||||||
|
+ return 'parent-returned';
|
||||||
|
+ };
|
||||||
|
+
|
||||||
|
+ expect(executePromise(promise())).toEqual({
|
||||||
|
+ result: PromiseResult.RESOLVED,
|
||||||
|
+ value: 'parent-returned',
|
||||||
|
+ });
|
||||||
|
+ });
|
||||||
|
+
|
||||||
|
+ it('waits for all promises before handling unhandled, when unhandled', function () {
|
||||||
|
+ const thenHandler = jasmine.createSpy('thenHandler');
|
||||||
|
+
|
||||||
|
+ const promise = async () => {
|
||||||
|
+ await new Promise(resolve => resolve('success'));
|
||||||
|
+ await new Promise((_resolve, reject) => reject(new Error('got error')));
|
||||||
|
+ return 'parent-returned';
|
||||||
|
+ };
|
||||||
|
+
|
||||||
|
+ promise().then(thenHandler).catch();
|
||||||
|
+ expect(thenHandler).not.toHaveBeenCalled();
|
||||||
|
+
|
||||||
|
+ GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, () => loop.quit());
|
||||||
|
+ GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_WARNING,
|
||||||
|
+ 'Unhandled promise rejection.*');
|
||||||
|
+ loop.run();
|
||||||
|
+ GLib.test_assert_expected_messages_internal('Gjs', 'testPromise.js', 0,
|
||||||
|
+ 'warnsIfRejected');
|
||||||
|
+ });
|
||||||
|
+
|
||||||
|
+ it('do not lead to high-priority IDLE starvation', function () {
|
||||||
|
+ const promise = new Promise(resolve => {
|
||||||
|
+ const id = GLib.idle_add(GLib.PRIORITY_HIGH, () => {
|
||||||
|
+ resolve();
|
||||||
|
+ return GLib.SOURCE_REMOVE;
|
||||||
|
+ });
|
||||||
|
+ GLib.Source.set_name_by_id(id, `Test Idle source ${id}`);
|
||||||
|
+ });
|
||||||
|
+
|
||||||
|
+ expect(executePromise(promise)).toEqual({
|
||||||
|
+ result: PromiseResult.RESOLVED,
|
||||||
|
+ value: undefined,
|
||||||
|
+ });
|
||||||
|
+ });
|
||||||
|
+});
|
||||||
|
--
|
||||||
|
GitLab
|
||||||
|
|
||||||
|
|
||||||
|
From 865d2ae27b853848157215cc60e4888575f13200 Mon Sep 17 00:00:00 2001
|
||||||
|
From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= <mail@3v1n0.net>
|
||||||
|
Date: Tue, 22 Feb 2022 04:18:40 +0100
|
||||||
|
Subject: [PATCH 2/2] context: Only show a critical error if unregistering an
|
||||||
|
unknown promise
|
||||||
|
|
||||||
|
In case a promise handled is removed too early or never added we may
|
||||||
|
have a bug, but not enough critical to crash.
|
||||||
|
---
|
||||||
|
gjs/context.cpp | 12 ++++++++----
|
||||||
|
1 file changed, 8 insertions(+), 4 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/gjs/context.cpp b/gjs/context.cpp
|
||||||
|
index 0ba6b250a..12eb0921c 100644
|
||||||
|
--- a/gjs/context.cpp
|
||||||
|
+++ b/gjs/context.cpp
|
||||||
|
@@ -1150,10 +1150,14 @@ void GjsContextPrivate::register_unhandled_promise_rejection(
|
||||||
|
}
|
||||||
|
|
||||||
|
void GjsContextPrivate::unregister_unhandled_promise_rejection(uint64_t id) {
|
||||||
|
- // Return value unused in G_DISABLE_ASSERT case
|
||||||
|
- [[maybe_unused]] size_t erased = m_unhandled_rejection_stacks.erase(id);
|
||||||
|
- g_assert(((void)"Handler attached to rejected promise that wasn't "
|
||||||
|
- "previously marked as unhandled", erased == 1));
|
||||||
|
+ size_t erased = m_unhandled_rejection_stacks.erase(id);
|
||||||
|
+ if (erased != 1) {
|
||||||
|
+ g_critical("Promise %" G_GUINT64_FORMAT
|
||||||
|
+ " Handler attached to rejected promise that wasn't "
|
||||||
|
+ "previously marked as unhandled or that we wrongly reported "
|
||||||
|
+ "as unhandled",
|
||||||
|
+ id);
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
void GjsContextPrivate::async_closure_enqueue_for_gc(Gjs::Closure* trampoline) {
|
||||||
|
--
|
||||||
|
GitLab
|
||||||
|
|
7
gjs.spec
7
gjs.spec
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
Name: gjs
|
Name: gjs
|
||||||
Version: 1.71.1
|
Version: 1.71.1
|
||||||
Release: 3%{?dist}
|
Release: 4%{?dist}
|
||||||
Summary: Javascript Bindings for GNOME
|
Summary: Javascript Bindings for GNOME
|
||||||
|
|
||||||
# The following files contain code from Mozilla which
|
# The following files contain code from Mozilla which
|
||||||
@ -18,6 +18,8 @@ Source0: https://download.gnome.org/sources/%{name}/1.71/%{name}-%{versio
|
|||||||
Patch0: gjs-1.71.1-cairo-textextents-test.patch
|
Patch0: gjs-1.71.1-cairo-textextents-test.patch
|
||||||
# https://gitlab.gnome.org/GNOME/gjs/-/issues/462
|
# https://gitlab.gnome.org/GNOME/gjs/-/issues/462
|
||||||
Patch1: gjs-1.71.1-bigint-32bit-test.patch
|
Patch1: gjs-1.71.1-bigint-32bit-test.patch
|
||||||
|
# https://gitlab.gnome.org/GNOME/gjs/-/merge_requests/729
|
||||||
|
Patch2: gjs-1.71.1-promise-rejection.patch
|
||||||
|
|
||||||
BuildRequires: gcc-c++
|
BuildRequires: gcc-c++
|
||||||
BuildRequires: meson
|
BuildRequires: meson
|
||||||
@ -101,6 +103,9 @@ sed -i -e "/'Gtk4'/d" installed-tests/js/meson.build
|
|||||||
%{_datadir}/installed-tests/
|
%{_datadir}/installed-tests/
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Wed Feb 23 2022 David King <amigadave@amigadave.com> - 1.71.1-4
|
||||||
|
- Add patch to fix AppIndicator extension crash
|
||||||
|
|
||||||
* Mon Feb 21 2022 David King <amigadave@amigadave.com> - 1.71.1-3
|
* Mon Feb 21 2022 David King <amigadave@amigadave.com> - 1.71.1-3
|
||||||
- Fix 32-bit GI marshalling test
|
- Fix 32-bit GI marshalling test
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user