|
|
0718c1 |
From 0c39ba49a21b8861d9ffb4bee546bd9927cf0b3c Mon Sep 17 00:00:00 2001
|
|
|
0718c1 |
From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hr=C3=A1zk=C3=BD?= <lhrazky@redhat.com>
|
|
|
0718c1 |
Date: Mon, 7 Oct 2019 16:33:48 +0200
|
|
|
0718c1 |
Subject: [PATCH] Fix leaking log handlers in Sack (RhBug:1758737)
|
|
|
0718c1 |
|
|
|
0718c1 |
Stores the log handler ids in the sack and uses g_log_remove_handler()
|
|
|
0718c1 |
in the sack destructor to remove the handlers.
|
|
|
0718c1 |
|
|
|
0718c1 |
The mechanism is a bit complex and is explained in a code comment.
|
|
|
0718c1 |
|
|
|
0718c1 |
https://bugzilla.redhat.com/show_bug.cgi?id=1758737
|
|
|
0718c1 |
---
|
|
|
0718c1 |
python/hawkey/sack-py.cpp | 47 +++++++++++++++++++++++++++++++++------
|
|
|
0718c1 |
python/hawkey/sack-py.hpp | 1 -
|
|
|
0718c1 |
2 files changed, 40 insertions(+), 8 deletions(-)
|
|
|
0718c1 |
|
|
|
0718c1 |
diff --git a/python/hawkey/sack-py.cpp b/python/hawkey/sack-py.cpp
|
|
|
0718c1 |
index e9253463..66479309 100644
|
|
|
0718c1 |
--- a/python/hawkey/sack-py.cpp
|
|
|
0718c1 |
+++ b/python/hawkey/sack-py.cpp
|
|
|
0718c1 |
@@ -47,6 +47,22 @@ typedef struct {
|
|
|
0718c1 |
DnfSack *sack;
|
|
|
0718c1 |
PyObject *custom_package_class;
|
|
|
0718c1 |
PyObject *custom_package_val;
|
|
|
0718c1 |
+
|
|
|
0718c1 |
+ // g_log handler IDs
|
|
|
0718c1 |
+ // Multiple sacks can be created during a run of an application and each
|
|
|
0718c1 |
+ // sack opens a log file and registers two g_log handlers. To avoid dangling
|
|
|
0718c1 |
+ // handlers with invalid FILE pointers (we close them when destroying the
|
|
|
0718c1 |
+ // sack), we need to keep track of the handlers so that we can also remove
|
|
|
0718c1 |
+ // them.
|
|
|
0718c1 |
+ //
|
|
|
0718c1 |
+ // g_log is clever about adding log handlers. It does store all handlers
|
|
|
0718c1 |
+ // registered for a given domain, but only the one that was registered last
|
|
|
0718c1 |
+ // is used. If you remove the last registered one, the next in line will be
|
|
|
0718c1 |
+ // used. That means stacking sacks is ok, the handler from the last
|
|
|
0718c1 |
+ // undeleted sack will be the one that is used.
|
|
|
0718c1 |
+ guint default_log_handler_id;
|
|
|
0718c1 |
+ guint libdnf_log_handler_id;
|
|
|
0718c1 |
+
|
|
|
0718c1 |
FILE *log_out;
|
|
|
0718c1 |
} _SackObject;
|
|
|
0718c1 |
|
|
|
0718c1 |
@@ -121,8 +137,13 @@ sack_dealloc(_SackObject *o)
|
|
|
0718c1 |
Py_XDECREF(o->custom_package_val);
|
|
|
0718c1 |
if (o->sack)
|
|
|
0718c1 |
g_object_unref(o->sack);
|
|
|
0718c1 |
- if (o->log_out)
|
|
|
0718c1 |
+
|
|
|
0718c1 |
+ if (o->log_out) {
|
|
|
0718c1 |
+ g_log_remove_handler(nullptr, o->default_log_handler_id);
|
|
|
0718c1 |
+ g_log_remove_handler("libdnf", o->libdnf_log_handler_id);
|
|
|
0718c1 |
fclose(o->log_out);
|
|
|
0718c1 |
+ }
|
|
|
0718c1 |
+
|
|
|
0718c1 |
Py_TYPE(o)->tp_free(o);
|
|
|
0718c1 |
}
|
|
|
0718c1 |
|
|
|
0718c1 |
@@ -177,15 +198,27 @@ log_handler(const gchar *log_domain, GLogLevelFlags log_level, const gchar *mess
|
|
|
0718c1 |
g_free(msg);
|
|
|
0718c1 |
}
|
|
|
0718c1 |
|
|
|
0718c1 |
-gboolean
|
|
|
0718c1 |
-set_logfile(const gchar *path, FILE *log_out)
|
|
|
0718c1 |
+static void
|
|
|
0718c1 |
+log_handler_noop(const gchar *, GLogLevelFlags, const gchar *, gpointer)
|
|
|
0718c1 |
{
|
|
|
0718c1 |
- log_out = fopen(path, "a");
|
|
|
0718c1 |
+}
|
|
|
0718c1 |
+
|
|
|
0718c1 |
+static gboolean
|
|
|
0718c1 |
+sack_set_logfile(_SackObject *self, const gchar *path)
|
|
|
0718c1 |
+{
|
|
|
0718c1 |
+ self->log_out = fopen(path, "a");
|
|
|
0718c1 |
|
|
|
0718c1 |
- if (!log_out)
|
|
|
0718c1 |
+ if (!self->log_out)
|
|
|
0718c1 |
return FALSE;
|
|
|
0718c1 |
|
|
|
0718c1 |
- g_log_set_default_handler(log_handler, log_out);
|
|
|
0718c1 |
+ // The default log handler prints messages that weren't handled by any
|
|
|
0718c1 |
+ // other logger to stderr/stdout, we do not want that
|
|
|
0718c1 |
+ g_log_set_default_handler(log_handler_noop, nullptr);
|
|
|
0718c1 |
+
|
|
|
0718c1 |
+ // set the handler for the default domain as well as "libdnf"
|
|
|
0718c1 |
+ self->default_log_handler_id = g_log_set_handler(nullptr, G_LOG_LEVEL_MASK, log_handler, self->log_out);
|
|
|
0718c1 |
+ self->libdnf_log_handler_id = g_log_set_handler("libdnf", G_LOG_LEVEL_MASK, log_handler, self->log_out);
|
|
|
0718c1 |
+
|
|
|
0718c1 |
g_info("=== Started libdnf-%d.%d.%d ===", LIBDNF_MAJOR_VERSION,
|
|
|
0718c1 |
LIBDNF_MINOR_VERSION, LIBDNF_MICRO_VERSION);
|
|
|
0718c1 |
return TRUE;
|
|
|
0718c1 |
@@ -237,7 +270,7 @@ sack_init(_SackObject *self, PyObject *args, PyObject *kwds)
|
|
|
0718c1 |
PycompString logfile(logfile_py);
|
|
|
0718c1 |
if (!logfile.getCString())
|
|
|
0718c1 |
return -1;
|
|
|
0718c1 |
- if (!set_logfile(logfile.getCString(), self->log_out)) {
|
|
|
0718c1 |
+ if (!sack_set_logfile(self, logfile.getCString())) {
|
|
|
0718c1 |
PyErr_Format(PyExc_IOError, "Failed to open log file: %s", logfile.getCString());
|
|
|
0718c1 |
return -1;
|
|
|
0718c1 |
}
|
|
|
0718c1 |
diff --git a/python/hawkey/sack-py.hpp b/python/hawkey/sack-py.hpp
|
|
|
0718c1 |
index cba8accb..4ae77380 100644
|
|
|
0718c1 |
--- a/python/hawkey/sack-py.hpp
|
|
|
0718c1 |
+++ b/python/hawkey/sack-py.hpp
|
|
|
0718c1 |
@@ -35,7 +35,6 @@ DnfSack *sackFromPyObject(PyObject *o);
|
|
|
0718c1 |
int sack_converter(PyObject *o, DnfSack **sack_ptr);
|
|
|
0718c1 |
|
|
|
0718c1 |
PyObject *new_package(PyObject *sack, Id id);
|
|
|
0718c1 |
-gboolean set_logfile(const gchar *path, FILE *log_out);
|
|
|
0718c1 |
const char *log_level_name(int level);
|
|
|
0718c1 |
|
|
|
0718c1 |
#endif // SACK_PY_H
|
|
|
0718c1 |
--
|
|
|
0718c1 |
2.25.2
|
|
|
0718c1 |
|