Hello community, here is the log from the commit of package cjs for openSUSE:Factory checked in at 2017-08-22 11:10:46 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/cjs (Old) and /work/SRC/openSUSE:Factory/.cjs.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "cjs" Tue Aug 22 11:10:46 2017 rev:8 rq:518008 version:3.4.4 Changes: -------- --- /work/SRC/openSUSE:Factory/cjs/cjs.changes 2017-08-10 14:11:33.173102107 +0200 +++ /work/SRC/openSUSE:Factory/.cjs.new/cjs.changes 2017-08-22 11:10:49.330291437 +0200 @@ -1,0 +2,12 @@ +Sun Aug 20 16:09:40 UTC 2017 - [email protected] + +- Update to version 3.4.4: + * object.cpp: Follow-up to 503fa20 - handler ID's must be managed + from start to finish - they should be initialised to 0, and + re-set to 0 whenever they're finished being used. + * arg: Don't crash when asked to convert a null strv to an array. + * object: Don't invalidate closure if already invalid. + * closure: Remove a pointer to runtime. + * closure: Prevent use-after-free in closures. + +------------------------------------------------------------------- Old: ---- cjs-3.4.3.tar.gz New: ---- cjs-3.4.4.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ cjs.spec ++++++ --- /var/tmp/diff_new_pack.4V3DGx/_old 2017-08-22 11:10:50.234164166 +0200 +++ /var/tmp/diff_new_pack.4V3DGx/_new 2017-08-22 11:10:50.234164166 +0200 @@ -20,7 +20,7 @@ %define sover 0 %define typelib typelib-1_0-CjsPrivate-1_0 Name: cjs -Version: 3.4.3 +Version: 3.4.4 Release: 0 Summary: JavaScript module used by Cinnamon License: MIT AND (MPL-1.1 OR GPL-2.0+ OR LGPL-2.1+) ++++++ cjs-3.4.3.tar.gz -> cjs-3.4.4.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cjs-3.4.3/configure.ac new/cjs-3.4.4/configure.ac --- old/cjs-3.4.3/configure.ac 2017-07-06 11:11:13.000000000 +0200 +++ new/cjs-3.4.4/configure.ac 2017-08-09 12:43:55.000000000 +0200 @@ -3,7 +3,7 @@ m4_define(pkg_major_version, 3) m4_define(pkg_minor_version, 4) -m4_define(pkg_micro_version, 3) +m4_define(pkg_micro_version, 4) m4_define(pkg_version, pkg_major_version.pkg_minor_version.pkg_micro_version) m4_define(pkg_int_version, (pkg_major_version * 100 + pkg_minor_version) * 100 + pkg_micro_version) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cjs-3.4.3/debian/changelog new/cjs-3.4.4/debian/changelog --- old/cjs-3.4.3/debian/changelog 2017-07-06 11:11:13.000000000 +0200 +++ new/cjs-3.4.4/debian/changelog 2017-08-09 12:43:55.000000000 +0200 @@ -1,3 +1,17 @@ +cjs (3.4.4) sonya; urgency=medium + + [ leigh123linux ] + * object: Keep proper track of pending closure invalidations + * revert b66d7c2965f20c2cf51628840682c404a01bf408 + + [ Michael Webster ] + * Add a debug package. + + [ Jason Hicks ] + * object: Zero out new ConnectData + + -- Clement Lefebvre <[email protected]> Wed, 09 Aug 2017 12:43:19 +0200 + cjs (3.4.3) sonya; urgency=medium [ Michael Webster ] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cjs-3.4.3/debian/control new/cjs-3.4.4/debian/control --- old/cjs-3.4.3/debian/control 2017-07-06 11:11:13.000000000 +0200 +++ new/cjs-3.4.4/debian/control 2017-08-09 12:43:55.000000000 +0200 @@ -67,3 +67,17 @@ . This package contains the development files applications need to build against. + +Package: libcjs-dbg +Section: debug +Architecture: any +Priority: extra +Depends: libcjs0f (= ${binary:Version}), + ${misc:Depends} +Description: Mozilla-based javascript bindings for the Cinnamon platform + Makes it possible for applications to use all of Cinnamon's platform + libraries using the JavaScript language. It's mainly based on the + Mozilla JavaScript engine and the GObject introspection framework. + . + This development package contains unstripped binaries compiled with + debugging symbols needed by gdb. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cjs-3.4.3/debian/control.in new/cjs-3.4.4/debian/control.in --- old/cjs-3.4.3/debian/control.in 2017-07-06 11:11:13.000000000 +0200 +++ new/cjs-3.4.4/debian/control.in 2017-08-09 12:43:55.000000000 +0200 @@ -63,3 +63,17 @@ . This package contains the development files applications need to build against. + +Package: libcjs-dbg +Section: debug +Architecture: any +Priority: extra +Depends: libcjs0f (= ${binary:Version}), + ${misc:Depends} +Description: Mozilla-based javascript bindings for the Cinnamon platform + Makes it possible for applications to use all of Cinnamon's platform + libraries using the JavaScript language. It's mainly based on the + Mozilla JavaScript engine and the GObject introspection framework. + . + This development package contains unstripped binaries compiled with + debugging symbols needed by gdb. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cjs-3.4.3/debian/rules new/cjs-3.4.4/debian/rules --- old/cjs-3.4.3/debian/rules 2017-07-06 11:11:13.000000000 +0200 +++ new/cjs-3.4.4/debian/rules 2017-08-09 12:43:55.000000000 +0200 @@ -27,6 +27,9 @@ override_dh_auto_test: dh_auto_test || true +override_dh_strip: + dh_strip --dbg-package=libcjs-dbg + override_dh_makeshlibs: dh_makeshlibs -Xusr/lib/cjs-1.0/ -V'libcjs0f (>= $(DEB_UPSTREAM_VERSION)), libcjs0-$(LIBMOZJS)' -- -c4 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cjs-3.4.3/gi/object.cpp new/cjs-3.4.4/gi/object.cpp --- old/cjs-3.4.3/gi/object.cpp 2017-07-06 11:11:13.000000000 +0200 +++ new/cjs-3.4.4/gi/object.cpp 2017-08-09 12:43:55.000000000 +0200 @@ -24,6 +24,7 @@ #include <config.h> #include <deque> +#include <map> #include <memory> #include <set> #include <stack> @@ -65,6 +66,7 @@ /* a list of all signal connections, used when tracing */ std::set<ConnectData *> signals; + std::map<ConnectData *, unsigned> pending_invalidations; /* the GObjectClass wrapped by this JS Object (only used for prototypes) */ @@ -79,7 +81,6 @@ struct _ConnectData { ObjectInstance *obj; GClosure *closure; - unsigned idle_invalidate_id; }; static std::stack<JS::PersistentRootedObject> object_init_list; @@ -1416,8 +1417,8 @@ signal_connection_invalidate_idle(void *user_data) { auto cd = static_cast<ConnectData *>(user_data); + cd->obj->pending_invalidations.erase(cd); cd->obj->signals.erase(cd); - cd->idle_invalidate_id = 0; g_slice_free(ConnectData, cd); return G_SOURCE_REMOVE; } @@ -1427,7 +1428,41 @@ GClosure *closure) { auto cd = static_cast<ConnectData *>(data); - cd->idle_invalidate_id = g_idle_add(signal_connection_invalidate_idle, cd); + std::map<ConnectData *, unsigned>& pending = cd->obj->pending_invalidations; + g_assert(pending.count(cd) == 0); + pending[cd] = g_idle_add(signal_connection_invalidate_idle, cd); +} + +/* This is basically the same as invalidate_all_signals(), but does not defer + * the invalidation to an idle handler. */ +static void +invalidate_all_signals_now(ObjectInstance *priv) +{ + for (auto& iter : priv->pending_invalidations) { + ConnectData *cd = iter.first; + g_source_remove(iter.second); + g_slice_free(ConnectData, cd); + /* Erase element if not already erased */ + priv->signals.erase(cd); + } + priv->pending_invalidations.clear(); + + /* Can't loop directly through the items, since invalidating an item's + * closure might have the effect of removing the item from the set in the + * invalidate notifier. */ + while (!priv->signals.empty()) { + ConnectData *cd = *priv->signals.begin(); + + /* We have to remove the invalidate notifier, which would + * otherwise schedule a new pending invalidation. */ + g_closure_remove_invalidate_notifier(cd->closure, cd, + signal_connection_invalidated); + g_closure_invalidate(cd->closure); + + g_slice_free(ConnectData, cd); + /* Erase element if not already erased */ + priv->signals.erase(cd); + } } static void @@ -1449,39 +1484,22 @@ priv->info ? g_base_info_get_namespace((GIBaseInfo*) priv->info) : "_gjs_private", priv->info ? g_base_info_get_name((GIBaseInfo*) priv->info) : g_type_name(priv->gtype))); + /* We must invalidate all signal connections now, instead of in an idle + * handler, because the object will not exist anymore when we get around to + * the idle function. We originally needed to defer these invalidations to + * an idle function since the object needs to continue tracing its signal + * connections while GC is going on. However, once the object is finalized, + * it will not be tracing them any longer anyway, so it's safe to do them + * now. + * This applies only to instances, not prototypes, but it's possible that + * an instance's GObject is already freed at this point. */ + invalidate_all_signals_now(priv); + + /* Object is instance, not prototype, AND GObject is not already freed */ if (priv->gobj) { bool had_toggle_up; bool had_toggle_down; - /* We must invalidate all signal connections now, instead of in an idle - * handler, because the object will not exist anymore when we get - * around to the idle function. We originally needed to defer these - * invalidations to an idle function since the object needs to continue - * tracing its signal connections while GC is going on. However, once - * the object is finalized, it will not be tracing them any longer - * anyway, so it's safe to do them now. - * - * This is basically the same as invalidate_all_signals(), but does not - * defer the invalidation to an idle handler. - */ - for (ConnectData *cd : priv->signals) { - /* First remove any pending invalidation, we are doing it now. */ - if (cd->idle_invalidate_id > 0) { - g_source_remove(cd->idle_invalidate_id); - cd->idle_invalidate_id = 0; - } else { - /* We also have to remove the invalidate notifier, which would - * otherwise schedule a new pending invalidation. */ - g_closure_remove_invalidate_notifier(cd->closure, cd, - signal_connection_invalidated); - - g_closure_invalidate(cd->closure); - } - - g_slice_free(ConnectData, cd); - } - priv->signals.clear(); - if (G_UNLIKELY (priv->gobj->ref_count <= 0)) { g_error("Finalizing proxy for an already freed object of type: %s.%s\n", priv->info ? g_base_info_get_namespace((GIBaseInfo*) priv->info) : "", @@ -1666,10 +1684,9 @@ if (closure == NULL) goto out; - connect_data = g_slice_new(ConnectData); + connect_data = g_slice_new0(ConnectData); priv->signals.insert(connect_data); connect_data->obj = priv; - connect_data->idle_invalidate_id = 0; /* This is a weak reference, and will be cleared when the closure is invalidated */ connect_data->closure = closure; g_closure_add_invalidate_notifier(closure, connect_data, signal_connection_invalidated); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cjs-3.4.3/installed-tests/js/testEverythingEncapsulated.js new/cjs-3.4.4/installed-tests/js/testEverythingEncapsulated.js --- old/cjs-3.4.3/installed-tests/js/testEverythingEncapsulated.js 2017-07-06 11:11:13.000000000 +0200 +++ new/cjs-3.4.4/installed-tests/js/testEverythingEncapsulated.js 2017-08-09 12:43:55.000000000 +0200 @@ -1,4 +1,6 @@ +const GLib = imports.gi.GLib; const Regress = imports.gi.Regress; +const System = imports.system; describe('Introspected structs', function () { let struct; @@ -261,3 +263,18 @@ expect(Regress.TestObj.new_callback.length).toEqual(1); }); }); + +describe('Garbage collection of introspected objects', function () { + // This tests a regression that would very rarely crash, but + // when run under valgrind this code would show use-after-free. + it('collects objects properly with signals connected', function (done) { + function orphanObject() { + let obj = new Regress.TestObj(); + obj.connect('notify', () => {}); + } + + orphanObject(); + System.gc(); + GLib.idle_add(GLib.PRIORITY_LOW, () => done()); + }); +});
