summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 0995310)
raw | patch | inline | side by side (parent: 0995310)
author | Sebastian Harl <sh@tokkee.org> | |
Wed, 23 Jan 2013 08:26:48 +0000 (09:26 +0100) | ||
committer | Sebastian Harl <sh@tokkee.org> | |
Wed, 23 Jan 2013 08:26:48 +0000 (09:26 +0100) |
D'oh! This is the most stupidest bug: all database connection objects are
stored in a plugin-global array and a pointer to each object was passed around
to the worker functions. This array used to be an array of objects (rather
than pointers) and was realloc'ed every time a new connection was added. Now,
the realloc caused the old pointer to not be valid any more, thus, any but the
last database connection were later accessing memory out of range. This caused
the plugin to segfault if more than one database connection was used.
Thanks to Greg Swift for reporting this!
Fixes Github issue #238.
stored in a plugin-global array and a pointer to each object was passed around
to the worker functions. This array used to be an array of objects (rather
than pointers) and was realloc'ed every time a new connection was added. Now,
the realloc caused the old pointer to not be valid any more, thus, any but the
last database connection were later accessing memory out of range. This caused
the plugin to segfault if more than one database connection was used.
Thanks to Greg Swift for reporting this!
Fixes Github issue #238.
src/postgresql.c | patch | blob | history |
diff --git a/src/postgresql.c b/src/postgresql.c
index 6c9ab44e8b3379aff58dd9b0b7a4295e6b74876c..e7b247e77e8fa983d131012d1149c869c24e5ff9 100644 (file)
--- a/src/postgresql.c
+++ b/src/postgresql.c
};
static int def_queries_num = STATIC_ARRAY_SIZE (def_queries);
-static c_psql_database_t *databases = NULL;
-static size_t databases_num = 0;
+static c_psql_database_t **databases = NULL;
+static size_t databases_num = 0;
-static udb_query_t **queries = NULL;
-static size_t queries_num = 0;
+static udb_query_t **queries = NULL;
+static size_t queries_num = 0;
-static c_psql_writer_t *writers = NULL;
-static size_t writers_num = 0;
+static c_psql_writer_t *writers = NULL;
+static size_t writers_num = 0;
static int c_psql_begin (c_psql_database_t *db)
{
static c_psql_database_t *c_psql_database_new (const char *name)
{
- c_psql_database_t *db;
+ c_psql_database_t **tmp;
+ c_psql_database_t *db;
- db = (c_psql_database_t *)realloc (databases,
- (databases_num + 1) * sizeof (*db));
+ db = (c_psql_database_t *)malloc (sizeof(*db));
if (NULL == db) {
log_err ("Out of memory.");
return NULL;
}
- databases = db;
- db = databases + databases_num;
+ tmp = (c_psql_database_t **)realloc (databases,
+ (databases_num + 1) * sizeof (*databases));
+ if (NULL == tmp) {
+ log_err ("Out of memory.");
+ sfree (db);
+ return NULL;
+ }
+
+ databases = tmp;
+ databases[databases_num] = db;
++databases_num;
db->conn = NULL;
sfree (db->service);
/* don't care about freeing or reordering the 'databases' array
- * this is done in 'shutdown' */
+ * this is done in 'shutdown'; also, don't free the database instance
+ * object just to make sure that in case anybody accesses it before
+ * shutdown won't segfault */
return;
} /* c_psql_database_delete */
__attribute__((unused)) const char *ident,
user_data_t *ud)
{
- c_psql_database_t *dbs = databases;
+ c_psql_database_t **dbs = databases;
size_t dbs_num = databases_num;
size_t i;
if ((ud != NULL) && (ud->data != NULL)) {
- dbs = ud->data;
+ dbs = (c_psql_database_t **)&ud->data;
dbs_num = 1;
}
for (i = 0; i < dbs_num; ++i) {
- c_psql_database_t *db = dbs + i;
+ c_psql_database_t *db = dbs[i];
/* don't commit if the timeout is larger than the regular commit
* interval as in that case all requested data has already been
plugin_unregister_read_group ("postgresql");
for (i = 0; i < databases_num; ++i) {
- c_psql_database_t *db = databases + i;
+ c_psql_database_t *db = databases[i];
if (db->writers_num > 0) {
char cb_name[DATA_MAX_NAME_LEN];
plugin_unregister_flush (cb_name);
plugin_unregister_write (cb_name);
}
+
+ sfree (db);
}
udb_query_free (queries, queries_num);