Blame SOURCES/disable-destoyed-object-criticals.patch

f96290
From a44c356190f44f1532208f1a0612a878bbafce27 Mon Sep 17 00:00:00 2001
f96290
From: Ray Strode <rstrode@redhat.com>
f96290
Date: Fri, 16 Feb 2018 10:51:37 -0500
f96290
Subject: [PATCH] object: only print stacktraces when debugging enabled
f96290
f96290
We have a bunch of corruption right now spamming the
f96290
log.
f96290
f96290
This commit gets rid of the spam unless G_MESSAGES_DEBUG
f96290
is set.
f96290
---
f96290
 gi/object.cpp | 86 +++++++++++++++++++++++++++++++--------------------
f96290
 1 file changed, 52 insertions(+), 34 deletions(-)
f96290
f96290
diff --git a/gi/object.cpp b/gi/object.cpp
f96290
index fe381ec3..bd09a75c 100644
f96290
--- a/gi/object.cpp
f96290
+++ b/gi/object.cpp
f96290
@@ -127,60 +127,83 @@ struct ObjectInstance {
f96290
        prototypes) */
f96290
     GTypeClass *klass;
f96290
 
f96290
     GjsListLink instance_link;
f96290
 
f96290
     unsigned js_object_finalized : 1;
f96290
     unsigned g_object_finalized  : 1;
f96290
 
f96290
     /* True if this object has visible JS state, and thus its lifecycle is
f96290
      * managed using toggle references. False if this object just keeps a
f96290
      * hard ref on the underlying GObject, and may be finalized at will. */
f96290
     bool uses_toggle_ref : 1;
f96290
 };
f96290
 
f96290
 static std::stack<JS::PersistentRootedObject> object_init_list;
f96290
 
f96290
 using ParamRef = std::unique_ptr<GParamSpec, decltype(&g_param_spec_unref)>;
f96290
 using ParamRefArray = std::vector<ParamRef>;
f96290
 static std::unordered_map<GType, ParamRefArray> class_init_properties;
f96290
 
f96290
 static bool context_weak_pointer_callback = false;
f96290
 static bool weak_pointer_callback = false;
f96290
 ObjectInstance *wrapped_gobject_list;
f96290
 
f96290
 extern struct JSClass gjs_object_instance_class;
f96290
 GJS_DEFINE_PRIV_FROM_JS(ObjectInstance, gjs_object_instance_class)
f96290
 
f96290
 static void            disassociate_js_gobject (GObject *gobj);
f96290
 static void ensure_uses_toggle_ref(JSContext *cx, ObjectInstance *priv);
f96290
 
f96290
+static void
f96290
+gjs_log_stacktrace(const char *format,
f96290
+                   ...)
f96290
+{
f96290
+    const char *domain;
f96290
+    va_list     args;
f96290
+
f96290
+    domain = g_getenv("G_MESSAGES_DEBUG");
f96290
+
f96290
+    if (!domain)
f96290
+        return;
f96290
+
f96290
+    if (!g_str_equal(domain, "all") &&
f96290
+        !strstr(domain, G_LOG_DOMAIN))
f96290
+        return;
f96290
+
f96290
+    va_start(args, format);
f96290
+    g_logv(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, format, args);
f96290
+    va_end(args);
f96290
+
f96290
+    gjs_dumpstack();
f96290
+}
f96290
+
f96290
 typedef enum {
f96290
     SOME_ERROR_OCCURRED = false,
f96290
     NO_SUCH_G_PROPERTY,
f96290
     VALUE_WAS_SET
f96290
 } ValueFromPropertyResult;
f96290
 
f96290
 static GQuark
f96290
 gjs_is_custom_type_quark (void)
f96290
 {
f96290
     static GQuark val = 0;
f96290
     if (!val)
f96290
         val = g_quark_from_static_string ("gjs::custom-type");
f96290
 
f96290
     return val;
f96290
 }
f96290
 
f96290
 static GQuark
f96290
 gjs_is_custom_property_quark (void)
f96290
 {
f96290
     static GQuark val = 0;
f96290
     if (!val)
f96290
         val = g_quark_from_static_string ("gjs::custom-property");
f96290
 
f96290
     return val;
f96290
 }
f96290
 
f96290
 static GQuark
f96290
 gjs_object_priv_quark (void)
f96290
 {
f96290
     static GQuark val = 0;
f96290
@@ -433,66 +456,65 @@ out:
f96290
 /* a hook on getting a property; set value_p to override property's value.
f96290
  * Return value is false on OOM/exception.
f96290
  */
f96290
 static bool
f96290
 object_instance_get_prop(JSContext              *context,
f96290
                          JS::HandleObject        obj,
f96290
                          JS::HandleId            id,
f96290
                          JS::MutableHandleValue  value_p)
f96290
 {
f96290
     ObjectInstance *priv;
f96290
     GjsAutoJSChar name;
f96290
 
f96290
     if (!gjs_get_string_id(context, id, &name))
f96290
         return true; /* not resolved, but no error */
f96290
 
f96290
     priv = priv_from_js(context, obj);
f96290
     gjs_debug_jsprop(GJS_DEBUG_GOBJECT,
f96290
                      "Get prop '%s' hook obj %p priv %p",
f96290
                      name.get(), obj.get(), priv);
f96290
 
f96290
     if (priv == nullptr)
f96290
         /* If we reach this point, either object_instance_new_resolve
f96290
          * did not throw (so name == "_init"), or the property actually
f96290
          * exists and it's not something we should be concerned with */
f96290
         return true;
f96290
 
f96290
     if (priv->gobj == NULL) /* prototype, not an instance. */
f96290
         return true;
f96290
 
f96290
     if (priv->g_object_finalized) {
f96290
-        g_critical("Object %s.%s (%p), has been already finalized. "
f96290
-                   "Impossible to get any property from it.",
f96290
-                   priv->info ? g_base_info_get_namespace( (GIBaseInfo*) priv->info) : "",
f96290
-                   priv->info ? g_base_info_get_name( (GIBaseInfo*) priv->info) : g_type_name(priv->gtype),
f96290
-                   priv->gobj);
f96290
-        gjs_dumpstack();
f96290
+        gjs_log_stacktrace("Object %s.%s (%p), has been already finalized. "
f96290
+                           "Impossible to get any property from it.",
f96290
+                           priv->info ? g_base_info_get_namespace( (GIBaseInfo*) priv->info) : "",
f96290
+                           priv->info ? g_base_info_get_name( (GIBaseInfo*) priv->info) : g_type_name(priv->gtype),
f96290
+                           priv->gobj);
f96290
         return true;
f96290
     }
f96290
 
f96290
     if (!get_prop_from_g_param(context, obj, priv, name, value_p))
f96290
         return false;
f96290
 
f96290
     if (!value_p.isUndefined())
f96290
         return true;
f96290
 
f96290
     /* Fall back to fields */
f96290
     return get_prop_from_field(context, obj, priv, name, value_p);
f96290
 }
f96290
 
f96290
 static bool
f96290
 set_g_param_from_prop(JSContext          *context,
f96290
                       ObjectInstance     *priv,
f96290
                       const char         *name,
f96290
                       bool&               was_set,
f96290
                       JS::HandleValue     value_p,
f96290
                       JS::ObjectOpResult& result)
f96290
 {
f96290
     GParameter param = { NULL, { 0, }};
f96290
     was_set = false;
f96290
 
f96290
     switch (init_g_param_from_property(context, name,
f96290
                                        value_p,
f96290
                                        G_TYPE_FROM_INSTANCE(priv->gobj),
f96290
                                        &param,
f96290
                                        false /* constructing */)) {
f96290
     case SOME_ERROR_OCCURRED:
f96290
@@ -549,66 +571,65 @@ check_set_field_from_prop(JSContext             *cx,
f96290
     value_p.setUndefined();
f96290
 out:
f96290
     g_base_info_unref((GIBaseInfo *) field);
f96290
     return retval;
f96290
 }
f96290
 
f96290
 /* a hook on setting a property; set value_p to override property value to
f96290
  * be set. Return value is false on OOM/exception.
f96290
  */
f96290
 static bool
f96290
 object_instance_set_prop(JSContext              *context,
f96290
                          JS::HandleObject        obj,
f96290
                          JS::HandleId            id,
f96290
                          JS::MutableHandleValue  value_p,
f96290
                          JS::ObjectOpResult&     result)
f96290
 {
f96290
     ObjectInstance *priv;
f96290
     GjsAutoJSChar name;
f96290
     bool ret = true;
f96290
     bool g_param_was_set = false;
f96290
 
f96290
     priv = priv_from_js(context, obj);
f96290
     if (priv == nullptr)
f96290
         /* see the comment in object_instance_get_prop() on this */
f96290
         return result.succeed();
f96290
 
f96290
     if (priv->gobj == NULL) /* prototype, not an instance. */
f96290
         return result.succeed();
f96290
 
f96290
     if (priv->g_object_finalized) {
f96290
-        g_critical("Object %s.%s (%p), has been already finalized. "
f96290
-                   "Impossible to set any property to it.",
f96290
-                   priv->info ? g_base_info_get_namespace( (GIBaseInfo*) priv->info) : "",
f96290
-                   priv->info ? g_base_info_get_name( (GIBaseInfo*) priv->info) : g_type_name(priv->gtype),
f96290
-                   priv->gobj);
f96290
-        gjs_dumpstack();
f96290
+        gjs_log_stacktrace("Object %s.%s (%p), has been already finalized. "
f96290
+                           "Impossible to set any property to it.",
f96290
+                           priv->info ? g_base_info_get_namespace( (GIBaseInfo*) priv->info) : "",
f96290
+                           priv->info ? g_base_info_get_name( (GIBaseInfo*) priv->info) : g_type_name(priv->gtype),
f96290
+                           priv->gobj);
f96290
         return result.succeed();
f96290
     }
f96290
 
f96290
     if (!gjs_get_string_id(context, id, &name)) {
f96290
         /* We need to keep the wrapper alive in order not to lose custom
f96290
          * "expando" properties. In this case if gjs_get_string_id() is false
f96290
          * then a number or symbol property was probably set. */
f96290
         ensure_uses_toggle_ref(context, priv);
f96290
         return result.succeed();  /* not resolved, but no error */
f96290
     }
f96290
 
f96290
     gjs_debug_jsprop(GJS_DEBUG_GOBJECT,
f96290
                      "Set prop '%s' hook obj %p priv %p",
f96290
                      name.get(), obj.get(), priv);
f96290
 
f96290
     ret = set_g_param_from_prop(context, priv, name, g_param_was_set, value_p, result);
f96290
     if (g_param_was_set || !ret)
f96290
         return ret;
f96290
 
f96290
     /* note that the prop will also have been set in JS, which I think
f96290
      * is OK, since we hook get and set so will always override that
f96290
      * value. We could also use JS_DefineProperty though and specify a
f96290
      * getter/setter maybe, don't know if that is better.
f96290
      */
f96290
     return check_set_field_from_prop(context, priv, name, value_p, result);
f96290
 }
f96290
 
f96290
 static bool
f96290
 is_vfunc_unchanged(GIVFuncInfo *info,
f96290
                    GType        gtype)
f96290
@@ -1780,67 +1801,66 @@ do_associate_closure(ObjectInstance *priv,
f96290
      * invalidated */
f96290
     priv->closures.insert(closure);
f96290
     g_closure_add_invalidate_notifier(closure, priv, closure_invalidated);
f96290
 }
f96290
 
f96290
 static bool
f96290
 real_connect_func(JSContext *context,
f96290
                   unsigned   argc,
f96290
                   JS::Value *vp,
f96290
                   bool       after)
f96290
 {
f96290
     GJS_GET_PRIV(context, argc, vp, argv, obj, ObjectInstance, priv);
f96290
     GClosure *closure;
f96290
     gulong id;
f96290
     guint signal_id;
f96290
     GQuark signal_detail;
f96290
 
f96290
     gjs_debug_gsignal("connect obj %p priv %p argc %d", obj.get(), priv, argc);
f96290
     if (priv == NULL) {
f96290
         throw_priv_is_null_error(context);
f96290
         return false; /* wrong class passed in */
f96290
     }
f96290
     if (priv->gobj == NULL) {
f96290
         /* prototype, not an instance. */
f96290
         gjs_throw(context, "Can't connect to signals on %s.%s.prototype; only on instances",
f96290
                   priv->info ? g_base_info_get_namespace( (GIBaseInfo*) priv->info) : "",
f96290
                   priv->info ? g_base_info_get_name( (GIBaseInfo*) priv->info) : g_type_name(priv->gtype));
f96290
         return false;
f96290
     }
f96290
     if (priv->g_object_finalized) {
f96290
-        g_critical("Object %s.%s (%p), has been already deallocated - impossible to connect to signal. "
f96290
-                   "This might be caused by the fact that the object has been destroyed from C "
f96290
-                   "code using something such as destroy(), dispose(), or remove() vfuncs",
f96290
-                   priv->info ? g_base_info_get_namespace( (GIBaseInfo*) priv->info) : "",
f96290
-                   priv->info ? g_base_info_get_name( (GIBaseInfo*) priv->info) : g_type_name(priv->gtype),
f96290
-                   priv->gobj);
f96290
-        gjs_dumpstack();
f96290
+        gjs_log_stacktrace("Object %s.%s (%p), has been already deallocated - impossible to connect to signal. "
f96290
+                           "This might be caused by the fact that the object has been destroyed from C "
f96290
+                           "code using something such as destroy(), dispose(), or remove() vfuncs",
f96290
+                           priv->info ? g_base_info_get_namespace( (GIBaseInfo*) priv->info) : "",
f96290
+                           priv->info ? g_base_info_get_name( (GIBaseInfo*) priv->info) : g_type_name(priv->gtype),
f96290
+                           priv->gobj);
f96290
         return true;
f96290
     }
f96290
 
f96290
     ensure_uses_toggle_ref(context, priv);
f96290
 
f96290
     if (argc != 2 || !argv[0].isString() || !JS::IsCallable(&argv[1].toObject())) {
f96290
         gjs_throw(context, "connect() takes two args, the signal name and the callback");
f96290
         return false;
f96290
     }
f96290
 
f96290
     JS::RootedString signal_str(context, argv[0].toString());
f96290
     GjsAutoJSChar signal_name = JS_EncodeStringToUTF8(context, signal_str);
f96290
     if (!signal_name)
f96290
         return false;
f96290
 
f96290
     if (!g_signal_parse_name(signal_name,
f96290
                              G_OBJECT_TYPE(priv->gobj),
f96290
                              &signal_id,
f96290
                              &signal_detail,
f96290
                              true)) {
f96290
         gjs_throw(context, "No signal '%s' on object '%s'",
f96290
                   signal_name.get(),
f96290
                   g_type_name(G_OBJECT_TYPE(priv->gobj)));
f96290
         return false;
f96290
     }
f96290
 
f96290
     closure = gjs_closure_new_for_signal(context, &argv[1].toObject(), "signal callback", signal_id);
f96290
     if (closure == NULL)
f96290
         return false;
f96290
     do_associate_closure(priv, closure);
f96290
@@ -1875,67 +1895,66 @@ connect_func(JSContext *context,
f96290
 static bool
f96290
 emit_func(JSContext *context,
f96290
           unsigned   argc,
f96290
           JS::Value *vp)
f96290
 {
f96290
     GJS_GET_PRIV(context, argc, vp, argv, obj, ObjectInstance, priv);
f96290
     guint signal_id;
f96290
     GQuark signal_detail;
f96290
     GSignalQuery signal_query;
f96290
     GValue *instance_and_args;
f96290
     GValue rvalue = G_VALUE_INIT;
f96290
     unsigned int i;
f96290
     bool failed;
f96290
 
f96290
     gjs_debug_gsignal("emit obj %p priv %p argc %d", obj.get(), priv, argc);
f96290
 
f96290
     if (priv == NULL) {
f96290
         throw_priv_is_null_error(context);
f96290
         return false; /* wrong class passed in */
f96290
     }
f96290
 
f96290
     if (priv->gobj == NULL) {
f96290
         /* prototype, not an instance. */
f96290
         gjs_throw(context, "Can't emit signal on %s.%s.prototype; only on instances",
f96290
                   priv->info ? g_base_info_get_namespace( (GIBaseInfo*) priv->info) : "",
f96290
                   priv->info ? g_base_info_get_name( (GIBaseInfo*) priv->info) : g_type_name(priv->gtype));
f96290
         return false;
f96290
     }
f96290
 
f96290
     if (priv->g_object_finalized) {
f96290
-        g_critical("Object %s.%s (%p), has been already deallocated - impossible to emit signal. "
f96290
-                   "This might be caused by the fact that the object has been destroyed from C "
f96290
-                   "code using something such as destroy(), dispose(), or remove() vfuncs",
f96290
-                   priv->info ? g_base_info_get_namespace( (GIBaseInfo*) priv->info) : "",
f96290
-                   priv->info ? g_base_info_get_name( (GIBaseInfo*) priv->info) : g_type_name(priv->gtype),
f96290
-                   priv->gobj);
f96290
-        gjs_dumpstack();
f96290
+        gjs_log_stacktrace("Object %s.%s (%p), has been already deallocated - impossible to emit signal. "
f96290
+                           "This might be caused by the fact that the object has been destroyed from C "
f96290
+                           "code using something such as destroy(), dispose(), or remove() vfuncs",
f96290
+                           priv->info ? g_base_info_get_namespace( (GIBaseInfo*) priv->info) : "",
f96290
+                           priv->info ? g_base_info_get_name( (GIBaseInfo*) priv->info) : g_type_name(priv->gtype),
f96290
+                           priv->gobj);
f96290
         return true;
f96290
     }
f96290
 
f96290
     if (argc < 1 || !argv[0].isString()) {
f96290
         gjs_throw(context, "emit() first arg is the signal name");
f96290
         return false;
f96290
     }
f96290
 
f96290
     JS::RootedString signal_str(context, argv[0].toString());
f96290
     GjsAutoJSChar signal_name = JS_EncodeStringToUTF8(context, signal_str);
f96290
     if (!signal_name)
f96290
         return false;
f96290
 
f96290
     if (!g_signal_parse_name(signal_name,
f96290
                              G_OBJECT_TYPE(priv->gobj),
f96290
                              &signal_id,
f96290
                              &signal_detail,
f96290
                              false)) {
f96290
         gjs_throw(context, "No signal '%s' on object '%s'",
f96290
                   signal_name.get(),
f96290
                   g_type_name(G_OBJECT_TYPE(priv->gobj)));
f96290
         return false;
f96290
     }
f96290
 
f96290
     g_signal_query(signal_id, &signal_query);
f96290
 
f96290
     if ((argc - 1) != signal_query.n_params) {
f96290
         gjs_throw(context, "Signal '%s' on %s requires %d args got %d",
f96290
                   signal_name.get(),
f96290
                   g_type_name(G_OBJECT_TYPE(priv->gobj)),
f96290
@@ -2250,68 +2269,67 @@ gjs_object_from_g_object(JSContext    *context,
f96290
             return nullptr;
f96290
 
f96290
         JS::RootedObject obj(context,
f96290
             JS_NewObjectWithGivenProto(context, JS_GetClass(proto), proto));
f96290
         if (!obj)
f96290
             return nullptr;
f96290
 
f96290
         priv = init_object_private(context, obj);
f96290
 
f96290
         g_object_ref_sink(gobj);
f96290
         associate_js_gobject(context, obj, gobj);
f96290
 
f96290
         g_assert(priv->keep_alive == obj.get());
f96290
     }
f96290
 
f96290
     return priv->keep_alive;
f96290
 }
f96290
 
f96290
 GObject*
f96290
 gjs_g_object_from_object(JSContext       *context,
f96290
                          JS::HandleObject obj)
f96290
 {
f96290
     ObjectInstance *priv;
f96290
 
f96290
     if (!obj)
f96290
         return NULL;
f96290
 
f96290
     priv = priv_from_js(context, obj);
f96290
 
f96290
     if (priv->g_object_finalized) {
f96290
-        g_critical("Object %s.%s (%p), has been already deallocated - "
f96290
-                   "impossible to access it. This might be caused by the "
f96290
-                   "object having been destroyed from C code using something "
f96290
-                   "such as destroy(), dispose(), or remove() vfuncs",
f96290
-                   priv->info ? g_base_info_get_namespace(priv->info) : "",
f96290
-                   priv->info ? g_base_info_get_name(priv->info) : g_type_name(priv->gtype),
f96290
-                   priv->gobj);
f96290
-        gjs_dumpstack();
f96290
+        gjs_log_stacktrace ("Object %s.%s (%p), has been already deallocated - "
f96290
+                            "impossible to access it. This might be caused by the "
f96290
+                            "object having been destroyed from C code using something "
f96290
+                            "such as destroy(), dispose(), or remove() vfuncs",
f96290
+                            priv->info ? g_base_info_get_namespace(priv->info) : "",
f96290
+                            priv->info ? g_base_info_get_name(priv->info) : g_type_name(priv->gtype),
f96290
+                            priv->gobj);
f96290
         return nullptr;
f96290
     }
f96290
 
f96290
     return priv->gobj;
f96290
 }
f96290
 
f96290
 bool
f96290
 gjs_typecheck_is_object(JSContext       *context,
f96290
                         JS::HandleObject object,
f96290
                         bool             throw_error)
f96290
 {
f96290
     return do_base_typecheck(context, object, throw_error);
f96290
 }
f96290
 
f96290
 bool
f96290
 gjs_typecheck_object(JSContext       *context,
f96290
                      JS::HandleObject object,
f96290
                      GType            expected_type,
f96290
                      bool             throw_error)
f96290
 {
f96290
     ObjectInstance *priv;
f96290
     bool result;
f96290
 
f96290
     if (!do_base_typecheck(context, object, throw_error))
f96290
         return false;
f96290
 
f96290
     priv = priv_from_js(context, object);
f96290
 
f96290
     if (priv == NULL) {
f96290
         if (throw_error) {
f96290
-- 
f96290
2.17.1
f96290