DBD-Oracle icon indicating copy to clipboard operation
DBD-Oracle copied to clipboard

Indefinite block on exit of forked client (Library version 19.20 only)

Open justinschoeman opened this issue 2 years ago • 3 comments

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

justinschoeman avatar Oct 10 '23 13:10 justinschoeman

I have now tested with client library 21.11, and it has the same issue.

justinschoeman avatar Oct 12 '23 11:10 justinschoeman

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.

justinschoeman avatar Oct 13 '23 08:10 justinschoeman

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.

justinschoeman avatar Oct 20 '23 11:10 justinschoeman