Date: | Wed, 09 Oct 2019 09:38:39 -0600 |
To: | undisclosed-recipients:; |
From: | chazmcgarvey [...] brokenzipper.com |
From e81047b90678ab7053f93e870b7249f5bfb77b9c Mon Sep 17 00:00:00 2001
From: Charles McGarvey <chazmcgarvey@brokenzipper.com>
Date: Thu, 26 Sep 2019 22:19:28 -0600
Subject: [PATCH] Fix a segfault related to async statements
To: bug-DBD-Pg@rt.cpan.org
Hi friends,
After upgrading to DBD::Pg 3.10.0, my async app now dies on "Segmentation
fault" or "double free or corruption". The exact place it dies is
inconsistent, but capturing various backtraces reveals it's always in PQclear.
So it seems like we're attempting to free a result more than once.
It crashes consistently in my complex app, but I haven't yet succeeded in
reproducing it in a test file. :-(
Here's a sample backtrace:
#0 0x00007fe110a45a90 in free () from /lib64/libc.so.6
#1 0x00007fe10d30f9fe in PQclear () from /usr/lib64/postgresql-11/lib64/libpq.so.5
#2 0x00007fe10d358089 in _result () from .../lib/perl5/x86_64-linux/auto/DBD/Pg/Pg.so
#3 0x00007fe10d35994c in pg_st_deallocate_statement.isra () from .../lib/perl5/x86_64-linux/auto/DBD/Pg/Pg.so
#4 0x00007fe10d365023 in pg_st_destroy () from .../lib/perl5/x86_64-linux/auto/DBD/Pg/Pg.so
#5 0x00007fe10d352ea6 in XS_DBD__Pg__st_DESTROY () from .../lib/perl5/x86_64-linux/auto/DBD/Pg/Pg.so
#6 0x00007fe10d3939b8 in XS_DBI_dispatch () from .../lib/perl5/x86_64-linux/auto/DBI/DBI.so
#7 0x000055c2a3321179 in Perl_pp_entersub ()
...
I bisected to b312efb (made prior to 3.9.0).
I took a stab at fixing the problem and came to this solution. This does
alleviate the segfaults for me, though I'd need someone more familiar with
this code to verify it's the right solution. And that it doesn't introduce
memory leaks.
Pull request: https://github.com/bucardo/dbdpg/pull/60
Regards,
Charles M.
---
dbdimp.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/dbdimp.c b/dbdimp.c
index c88321f..73a6712 100644
--- a/dbdimp.c
+++ b/dbdimp.c
@@ -684,6 +684,8 @@ void dbd_db_destroy (SV * dbh, imp_dbh_t * imp_dbh)
if (imp_dbh->async_sth->result) {
TRACE_PQCLEAR;
PQclear(imp_dbh->async_sth->result);
+ if (imp_dbh->last_result == imp_dbh->async_sth->result)
+ imp_dbh->last_result = NULL;
}
imp_dbh->async_sth = NULL;
}
@@ -5169,8 +5171,13 @@ long pg_db_result (SV *h, imp_dbh_t *imp_dbh)
if (imp_dbh->async_sth) {
if (imp_dbh->async_sth->result) { /* For potential multi-result sets */
- TRACE_PQCLEAR;
- PQclear(imp_dbh->async_sth->result);
+ if (imp_dbh->sth_result_owner == (long int)imp_dbh->async_sth) {
+ imp_dbh->sth_result_owner = 0;
+ }
+ else {
+ TRACE_PQCLEAR;
+ PQclear(imp_dbh->async_sth->result);
+ }
}
imp_dbh->async_sth->result = result;
}
--
2.21.0