perl5-dbi / DBD-Oracle

Oracle database driver for the DBI module
http://search.cpan.org/dist/DBD-Oracle
18 stars 25 forks source link

panic: memory wrap #105

Open mjegh opened 5 years ago

mjegh commented 5 years ago

This is very similar to issue 15 (which was RT 94232) and was causes by the fix to RT91698 but far worse:

use strict;
use warnings;
use DBI;
use DBD::Oracle qw(:ora_types);
use Data::Dumper;

print "perl=$]  DBI=$DBI::VERSION  DBD::Oracle=$DBD::Oracle::VERSION\n";

my $dbh = DBI->connect(
    "dbi:Oracle:blahblah',
    "username",
    "password",
    {RaiseError => 1}
);

my $sth = $dbh->prepare(qq{
    BEGIN
        :out := '1';
    END;
});
$sth->bind_param_inout(':out', \my $result, 1
        , {ora_type => ORA_CHAR}
);
$sth->execute();
print Dumper($result);

$sth->execute();
print Dumper($result);

$dbh->disconnect;

Which outputs:

perl=5.022000  DBI=1.639  DBD::Oracle=1.791
$VAR1 = '1  ';
panic: memory wrap at rt94232_gh_15.pl line 27.
djzort commented 4 years ago

Im guessing this is still an issue?

tonycoz commented 4 years ago

@djzort asked me to have a look at this, but I've run into limits on my knowledge (and time) on how this is meant to work:

The base issue is this code:

                 SvGROW(phs->sv,(STRLEN) (unsigned int)phs->maxlen-1);

is called when phs->maxlen is 0, subtracting 1 returns 0xffffffffffffffff:

Breakpoint 1, Perl_croak_memory_wrap () at util.c:1776
1776        Perl_croak_nocontext("%s",PL_memory_wrap);
(gdb) bt
#0  Perl_croak_memory_wrap () at util.c:1776
#1  0x00005555556fbb1c in Perl_sv_grow (my_perl=0x5555559ae260, 
    sv=0x555555e488b8, newlen=18446744073709551615) at sv.c:1607
#2  0x00007ffff7b90fbb in dbd_rebind_ph_char (imp_sth=0x555555a53cc0, 
    phs=0x555555f6ee20) at dbdimp.c:2789
#3  0x00007ffff7b92a73 in dbd_rebind_ph (sth=0x555555c95ba8, 
    imp_sth=0x555555a53cc0, phs=0x555555f6ee20) at dbdimp.c:3204
#4  0x00007ffff7b950e8 in ora_st_execute (sth=0x555555c95ba8, 
    imp_sth=0x555555a53cc0) at dbdimp.c:3689
#5  0x00007ffff7b7b4f5 in XS_DBD__Oracle__st_execute (my_perl=0x5555559ae260, 
    cv=0x555555de2ce0) at ./Oracle.xsi:623
#6  0x00007ffff7bd4cda in XS_DBI_dispatch (my_perl=0x5555559ae260, 
    cv=0x555555d43dd8) at DBI.xs:3783
#7  0x00005555556f5f99 in Perl_pp_entersub (my_perl=0x5555559ae260)
    at pp_hot.c:5277
#8  0x00005555556e2fe0 in Perl_runops_standard (my_perl=0x5555559ae260)
    at run.c:41
#9  0x00005555555d67eb in S_run_body (my_perl=0x5555559ae260, oldscope=1)
    at perl.c:2761
#10 0x00005555555d61ea in perl_run (my_perl=0x5555559ae260) at perl.c:2684
#11 0x000055555559c20a in main (argc=3, argv=0x7fffffffebb8, 
    env=0x7fffffffebd8) at perlmain.c:127
(gdb) up 2
#2  0x00007ffff7b90fbb in dbd_rebind_ph_char (imp_sth=0x555555a53cc0, 
    phs=0x555555f6ee20) at dbdimp.c:2789
2789                    SvGROW(phs->sv,(STRLEN) (unsigned int)phs->maxlen-1);
(gdb) p phs->maxlen
$1 = 0

How does it get that value? Initially it's set to the maxlen supplied to bind_param_inout:

3507        phs->maxlen = maxlen;       /* 0 if not inout       */
(gdb) p maxlen
$2 = 1

but later it's modified:

(gdb) watch -l phs->maxlen
Hardware watchpoint 3: -location phs->maxlen
(gdb) c
Continuing.

Hardware watchpoint 3: -location phs->maxlen

Old value = 1
New value = 0
dbd_rebind_ph_char (imp_sth=0x555555a53810, phs=0x555555f6fb10)
    at dbdimp.c:2846
2846        if (phs->maxlen < 0)        /* can happen with nulls    */
(gdb) l 2845 
2840            }
2841            phs->maxlen  = ((IV)SvLEN(phs->sv)); /* avail buffer space (64bit safe) Logicaly maxlen should never change but it does why I know not - MJE because SvGROW can allocate more than you ask for - anyway - I fixed that and it doesn't grow anymore */
2842    
2843        }

Since $result is undef at this point, SvLEN() is 0 and phs->maxlen isn't modified again until the panic.

Hopefully someone with a better knowledge of DBD::Oracle will understand what's going on here.

djzort commented 4 years ago

thanks @tonycoz

djzort commented 4 years ago

@mjegh can we arrange to look at this? maybe chat via irc or something