Hello community,
here is the log from the commit of package cjs for openSUSE:Factory checked in at 2017-06-29 15:18:01 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/cjs (Old) and /work/SRC/openSUSE:Factory/.cjs.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "cjs"
Thu Jun 29 15:18:01 2017 rev:6 rq:506912 version:3.4.2
Changes: -------- --- /work/SRC/openSUSE:Factory/cjs/cjs.changes 2017-05-27 13:13:10.319555640 +0200 +++ /work/SRC/openSUSE:Factory/.cjs.new/cjs.changes 2017-06-29 15:18:19.265863430 +0200 @@ -1,0 +2,10 @@ +Wed Jun 28 19:20:44 UTC 2017 - sor.alexei@meowr.ru + +- Update to version 3.4.2: + * tweener: Add undefined property check. + * tweener.js: Silence some additional warnings due to + missing/unused properties. + * object: Prevent use-after-free in signal connections. + * util-root: Require GjsMaybeOwned callback to reset. + +-------------------------------------------------------------------
Old: ---- cjs-3.4.1.tar.gz
New: ---- cjs-3.4.2.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences: ------------------ ++++++ cjs.spec ++++++ --- /var/tmp/diff_new_pack.dF1nwc/_old 2017-06-29 15:18:21.137598845 +0200 +++ /var/tmp/diff_new_pack.dF1nwc/_new 2017-06-29 15:18:21.141598279 +0200 @@ -20,7 +20,7 @@ %define sover 0 %define typelib typelib-1_0-CjsPrivate-1_0 Name: cjs -Version: 3.4.1 +Version: 3.4.2 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.1.tar.gz -> cjs-3.4.2.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cjs-3.4.1/cjs/jsapi-util-root.h new/cjs-3.4.2/cjs/jsapi-util-root.h --- old/cjs-3.4.1/cjs/jsapi-util-root.h 2017-05-23 16:29:10.000000000 +0200 +++ new/cjs-3.4.2/cjs/jsapi-util-root.h 2017-06-26 12:19:31.000000000 +0200 @@ -170,11 +170,12 @@ * to remove it. */ m_has_weakref = false;
- /* The object is still live across this callback. */ + /* The object is still live entering this callback. The callback + * must reset() this wrapper. */ if (m_notify) m_notify(handle(), m_data); - - reset(); + else + reset(); }
public: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cjs-3.4.1/configure.ac new/cjs-3.4.2/configure.ac --- old/cjs-3.4.1/configure.ac 2017-05-23 16:29:10.000000000 +0200 +++ new/cjs-3.4.2/configure.ac 2017-06-26 12:19:31.000000000 +0200 @@ -3,7 +3,7 @@
m4_define(pkg_major_version, 3) m4_define(pkg_minor_version, 4) -m4_define(pkg_micro_version, 1) +m4_define(pkg_micro_version, 2) 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.1/debian/changelog new/cjs-3.4.2/debian/changelog --- old/cjs-3.4.1/debian/changelog 2017-05-23 16:29:10.000000000 +0200 +++ new/cjs-3.4.2/debian/changelog 2017-06-26 12:19:31.000000000 +0200 @@ -1,3 +1,17 @@ +cjs (3.4.2) sonya; urgency=medium + + [ leigh123linux ] + * tweener: Add undefined property check (#45) + + [ Michael Webster ] + * tweener.js: silence some additional warnings due to missing/unused properties. + + [ leigh123linux ] + * object: Prevent use-after-free in signal connections + * util-root: Require GjsMaybeOwned callback to reset + + -- Clement Lefebvre root@linuxmint.com Mon, 26 Jun 2017 12:18:57 +0200 + cjs (3.4.1) sonya; urgency=medium
[ Clement Lefebvre ] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cjs-3.4.1/gi/object.cpp new/cjs-3.4.2/gi/object.cpp --- old/cjs-3.4.1/gi/object.cpp 2017-05-23 16:29:10.000000000 +0200 +++ new/cjs-3.4.2/gi/object.cpp 2017-06-26 12:19:31.000000000 +0200 @@ -55,6 +55,8 @@ #include <util/hash-x32.h> #include <girepository.h>
+typedef struct _ConnectData ConnectData; + struct ObjectInstance { GIObjectInfo *info; GObject *gobj; /* NULL if we are the prototype and not an instance */ @@ -62,7 +64,7 @@ GType gtype;
/* a list of all signal connections, used when tracing */ - GList *signals; + std::set<ConnectData *> signals;
/* the GObjectClass wrapped by this JS Object (only used for prototypes) */ @@ -74,11 +76,11 @@ unsigned js_object_finalized : 1; };
-typedef struct { +struct _ConnectData { ObjectInstance *obj; - GList *link; GClosure *closure; -} ConnectData; + unsigned idle_invalidate_id; +};
static std::stackJS::PersistentRootedObject object_init_list; static GHashTable *class_init_properties; @@ -93,7 +95,7 @@ GJS_DEFINE_PRIV_FROM_JS(ObjectInstance, gjs_object_instance_class)
static void disassociate_js_gobject (GObject *gobj); -static void invalidate_all_signals (ObjectInstance *priv); + typedef enum { SOME_ERROR_OCCURRED = false, NO_SUCH_G_PROPERTY, @@ -1220,6 +1222,21 @@ }
static void +invalidate_all_signals(ObjectInstance *priv) +{ + /* 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()) { + /* This will also free cd, through the closure invalidation mechanism */ + ConnectData *cd = *priv->signals.begin(); + g_closure_invalidate(cd->closure); + /* Erase element if not already erased */ + priv->signals.erase(cd); + } +} + +static void disassociate_js_gobject(GObject *gobj) { ObjectInstance *priv = get_object_qdata(gobj); @@ -1374,43 +1391,44 @@ }
static void -invalidate_all_signals(ObjectInstance *priv) -{ - GList *iter, *next; - - for (iter = priv->signals; iter; ) { - ConnectData *cd = (ConnectData*) iter->data; - next = iter->next; - - /* This will also free cd and iter, through - the closure invalidation mechanism */ - g_closure_invalidate(cd->closure); - - iter = next; - } -} - -static void object_instance_trace(JSTracer *tracer, JSObject *obj) { ObjectInstance *priv; - GList *iter;
priv = (ObjectInstance *) JS_GetPrivate(obj); if (priv == NULL) return;
- for (iter = priv->signals; iter; iter = iter->next) { - ConnectData *cd = (ConnectData *) iter->data; - + for (ConnectData *cd : priv->signals) gjs_closure_trace(cd->closure, tracer); - }
for (auto vfunc : priv->vfuncs) vfunc->js_function.trace(tracer, "ObjectInstance::vfunc"); }
+/* Removing the signal connection data from the list means that the object stops + * tracing the JS function objects belonging to the closures. Incremental GC + * does not allow that in the middle of a garbage collection. Therefore, we must + * do it in an idle handler. + */ +static gboolean +signal_connection_invalidate_idle(void *user_data) +{ + auto cd = static_cast<ConnectData *>(user_data); + cd->obj->signals.erase(cd); + g_slice_free(ConnectData, cd); + return G_SOURCE_REMOVE; +} + +static void +signal_connection_invalidated(void *data, + GClosure *closure) +{ + auto cd = static_cast<ConnectData *>(data); + cd->idle_invalidate_id = g_idle_add(signal_connection_invalidate_idle, cd); +} + static void object_instance_finalize(JSFreeOp *fop, JSObject *obj) @@ -1434,7 +1452,31 @@ bool had_toggle_up; bool had_toggle_down;
- invalidate_all_signals (priv); + /* 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); + + /* 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", @@ -1568,29 +1610,6 @@ return proto; }
-/* Removing the signal connection data from the list means that the object stops - * tracing the JS function objects belonging to the closures. Incremental GC - * does not allow that in the middle of a garbage collection. Therefore, we must - * do it in an idle handler. - */ -static gboolean -signal_connection_invalidate_idle(void *user_data) -{ - ConnectData *connect_data = (ConnectData *) user_data; - - connect_data->obj->signals = g_list_delete_link(connect_data->obj->signals, - connect_data->link); - g_slice_free(ConnectData, connect_data); - return G_SOURCE_REMOVE; -} - -static void -signal_connection_invalidated(void *data, - GClosure *closure) -{ - g_idle_add(signal_connection_invalidate_idle, data); -} - static bool real_connect_func(JSContext *context, unsigned argc, @@ -1644,9 +1663,8 @@ goto out;
connect_data = g_slice_new(ConnectData); - priv->signals = g_list_prepend(priv->signals, connect_data); + priv->signals.insert(connect_data); connect_data->obj = priv; - connect_data->link = priv->signals; /* 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.1/modules/tweener/tweener.js new/cjs-3.4.2/modules/tweener/tweener.js --- old/cjs-3.4.1/modules/tweener/tweener.js 2017-05-23 16:29:10.000000000 +0200 +++ new/cjs-3.4.2/modules/tweener/tweener.js 2017-06-26 12:19:31.000000000 +0200 @@ -508,6 +508,7 @@ if (scopes[i][istr] == undefined) log("The property " + istr + " doesn't seem to be a normal object property of " + scopes[i] + " or a registered special property"); } + properties[istr].isSpecialProperty = false; } } } @@ -542,11 +543,11 @@ copyProperties[istr] = new PropertyInfo(properties[istr].valueStart, properties[istr].valueComplete, properties[istr].valueComplete, - properties[istr].arrayIndex, + properties[istr].arrayIndex || 0, {}, properties[istr].isSpecialProperty, - properties[istr].modifierFunction, - properties[istr].modifierParameters); + properties[istr].modifierFunction || null, + properties[istr].modifierParameters || null); } }
@@ -555,7 +556,7 @@ _ticker.getTime() + (((delay * 1000) + (time * 1000)) / _timeScale), false, transition, - obj.transitionParams); + obj.transitionParams || null);
tween.properties = isCaller ? null : copyProperties; tween.onStart = obj.onStart; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cjs-3.4.1/test/gjs-test-rooting.cpp new/cjs-3.4.2/test/gjs-test-rooting.cpp --- old/cjs-3.4.1/test/gjs-test-rooting.cpp 2017-05-23 16:29:10.000000000 +0200 +++ new/cjs-3.4.2/test/gjs-test-rooting.cpp 2017-06-26 12:19:31.000000000 +0200 @@ -13,6 +13,8 @@
bool finalized; bool notify_called; + + GjsMaybeOwned<JSObject *> *obj; /* only used in callback test cases */ };
static void @@ -220,6 +222,7 @@ g_assert_false(fx->notify_called); g_assert_false(fx->finalized); fx->notify_called = true; + fx->obj->reset(); }
static void @@ -233,24 +236,24 @@ test_maybe_owned_notify_callback_called_on_context_destroy(GjsRootingFixture *fx, gconstpointer unused) { - auto obj = new GjsMaybeOwned<JSObject *>(); - obj->root(PARENT(fx)->cx, test_obj_new(fx), context_destroyed, fx); + fx->obj = new GjsMaybeOwned<JSObject *>(); + fx->obj->root(PARENT(fx)->cx, test_obj_new(fx), context_destroyed, fx);
gjs_unit_test_destroy_context(PARENT(fx)); g_assert_true(fx->notify_called); - delete obj; + delete fx->obj; }
static void test_maybe_owned_object_destroyed_after_notify(GjsRootingFixture *fx, gconstpointer unused) { - auto obj = new GjsMaybeOwned<JSObject *>(); - obj->root(PARENT(fx)->cx, test_obj_new(fx), context_destroyed, fx); + fx->obj = new GjsMaybeOwned<JSObject *>(); + fx->obj->root(PARENT(fx)->cx, test_obj_new(fx), context_destroyed, fx);
gjs_unit_test_destroy_context(PARENT(fx)); g_assert_true(fx->finalized); - delete obj; + delete fx->obj; }
void