DBD-Oracle
DBD-Oracle copied to clipboard
Indefinite block on exit of forked client (Library version 19.20 only)
Hi,
I was running 1.80 (installed through CPAN) with Oracle Client Library 18.5. Everything worked perfectly with this setup.
I then upgraded Oracle Client Library to 19.20, and did 'cpan -f DBD::Oracle' to upgrade that. This installed version 1.83.
After that, whenever a forked client (which opens its own db handle) exits, the process blocks forever on:
#0 0x00007f49995998d9 in pthread_cond_destroy@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
#1 0x00007f498c8c5ea2 in sltspcdestroy () from /opt/oracle/instantclient_19_20/libclntshcore.so.19.1
#2 0x00007f498dce8f6b in kpucpstopthr () from /opt/oracle/instantclient_19_20/libclntsh.so.19.1
#3 0x00007f4990ac5ba7 in kpufhndl0 () from /opt/oracle/instantclient_19_20/libclntsh.so.19.1
#4 0x00007f49919fee91 in ora_db_destroy (dbh=dbh@entry=0x1c9e780, imp_dbh=imp_dbh@entry=0x1c806f0)
at dbdimp.c:1262
#5 0x00007f49919f680b in XS_DBD__Oracle__db_DESTROY (my_perl=0x1776010, cv=<optimized out>)
at ./Oracle.xsi:387
I manually re-installed version 1.80 (still with 19.20) and had exactly the same result.
As a temporary workaround, I have edited dbdimp.c around line 1266:
} else if ( (imp_dbh->envhp == imp_drh->envhp) && (SvTRUE(perl_get_sv("DBI::PERL_ENDING",0))) ) {
//OCIHandleFree_log_stat(imp_dbh, imp_dbh->envhp, OCI_HTYPE_ENV, status);
//if ( status == OCI_SUCCESS ) {
imp_dbh->envhp = NULL;
imp_drh->envhp = NULL;
//}
}
To comment out the final environment free call.
With the above change, forked children exit correctly - but there is a potential memory leak (not sure though, as this seems to only be on the final exit path, so OS should clean it up anyway?)
Thanks, Justin
I have now tested with client library 21.11, and it has the same issue.
To aid in replicating, this is the offending snippet:
my $i = fork();
if(!defined $i) { ... ; return 0; }
if($i == 0) {
LOG(10, "child started");
# child must not close master dbh on exit
$mdbh->{InactiveDestroy} = 1;
# No signal handler for the child?
$SIG{CHLD} = 'DEFAULT';
$req->{'child'} = $$;
# get child db handle
$req->{'dbh'} = DBI->connect(..., { RaiseError => 0, AutoCommit => 1});
if(!$req->{'dbh'}) { ...; exit -1; }
... child code here ...
$req->{'dbh'}->disconnect;
delete $req->{'dbh'};
LOG(10, "Child done ($ret): " . Dumper($req));
exit $ret;
}
The final 'Child done' is logged, and the 'exit $ret' blocks indefinitely.
More information. Got this SEGFAULT today:
kpedbg_dmp_stack()+396<-kpeDbgCrash()+204<-kpeDbgSignalHandler()+113<-skgesig_sigactionHandler()+258<-__sighandler()<-Perl_csighandler()+34<-__sighandler()<-pthread_cond_timedwait()+306<-sltspctimewait()+131<-kpucpincrtime()+113<-start_thread()+197
Not sure if it has anything to do with the above hackaround though.
The program + DBD::Oracle has been running flawlessly for more than 10 years on client library 11 and then 18. Something is deeply fubar with 19 and on though.