Mercurial > dovecot > original-hg > dovecot-1.2
changeset 8650:81fd92599c7f HEAD
pgsql: Don't write to freed memory if transaction is aborted while SQL commands are being executed.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Sat, 17 Jan 2009 17:21:29 -0500 |
parents | 67c08c386702 |
children | a498c440eef2 |
files | src/lib-sql/driver-pgsql.c |
diffstat | 1 files changed, 21 insertions(+), 4 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib-sql/driver-pgsql.c Sat Jan 17 13:56:24 2009 -0500 +++ b/src/lib-sql/driver-pgsql.c Sat Jan 17 17:21:29 2009 -0500 @@ -70,6 +70,7 @@ struct pgsql_transaction_context { struct sql_transaction_context ctx; + int refcount; sql_commit_callback_t *callback; void *context; @@ -845,10 +846,22 @@ ctx = i_new(struct pgsql_transaction_context, 1); ctx->ctx.db = db; + ctx->refcount = 1; return &ctx->ctx; } static void +driver_pgsql_transaction_unref(struct pgsql_transaction_context *ctx) +{ + i_assert(ctx->refcount > 0); + if (--ctx->refcount > 0) + return; + + i_free(ctx->first_update); + i_free(ctx); +} + +static void transaction_commit_callback(struct sql_result *result, void *context) { struct pgsql_transaction_context *ctx = @@ -871,13 +884,14 @@ callback(ctx->error, context); if (ctx->opened) sql_exec(_ctx->db, "ROLLBACK"); - i_free(ctx); + driver_pgsql_transaction_unref(ctx); return; } if (!ctx->opened) { /* nothing done */ ctx->callback(NULL, ctx->context); + driver_pgsql_transaction_unref(ctx); return; } @@ -897,6 +911,7 @@ struct sql_result *result; if (ctx->first_update != NULL) { + ctx->refcount++; sql_query(_ctx->db, ctx->first_update, transaction_update_callback, ctx); i_free_and_null(ctx->first_update); @@ -919,7 +934,7 @@ sql_result_free(result); } - i_free(ctx); + driver_pgsql_transaction_unref(ctx); return *error_r == NULL ? 0 : -1; } @@ -931,8 +946,7 @@ if (ctx->opened) sql_exec(_ctx->db, "ROLLBACK"); - i_free(ctx->first_update); - i_free(ctx); + driver_pgsql_transaction_unref(ctx); } static void @@ -944,6 +958,7 @@ ctx->failed = TRUE; ctx->error = sql_result_get_error(result); } + driver_pgsql_transaction_unref(ctx); } static void @@ -963,12 +978,14 @@ return; } ctx->opened = TRUE; + ctx->refcount += 2; sql_query(_ctx->db, "BEGIN", transaction_update_callback, ctx); sql_query(_ctx->db, ctx->first_update, transaction_update_callback, ctx); i_free_and_null(ctx->first_update); } + ctx->refcount++; driver_pgsql_query_full(_ctx->db, query, transaction_update_callback, ctx, FALSE); }