destruction ordering in DBI

[email protected] (Nicholas Clark) Wed, 3 Nov 2004 18:34:39 +0000
Newsgroups perl.ponie.dev
Message-ID <[email protected]>
Whilst this might seem an inappropriate place to mail this, I believe that
Tim Bunce is subscribed, so I'm going to fire away.

I can get segfaults in DBI from the regression tests for DBD-SQLite (0.31)

It comes down to a destruction ordering problem (I believe). valgrind
reports:

==14963== Invalid read of size 4
==14963==    at 0x3DD1CB33: XS_DBI_dispatch (DBI.xs:2507)
==14963==    by 0x8139261: Perl_pp_entersub (pp_hot.c:2798)
==14963==    by 0x80BA4B0: S_call_body (perl.c:2167)
==14963==    by 0x80BA143: Perl_call_sv (perl.c:2088)
==14963==    by 0x8148BD1: Perl_sv_clear (sv.c:5733)
==14963==    by 0x8149BE7: Perl_sv_free2 (sv.c:6010)
==14963==    by 0x8149484: Perl_sv_clear (sv.c:5837)
==14963==    by 0x8149BE7: Perl_sv_free2 (sv.c:6010)
==14963==    by 0x8125CE6: Perl_hv_free_ent (hv.c:1434)
==14963==    by 0x81264E0: S_hfreeentries (hv.c:1608)
==14963==    by 0x812656A: Perl_hv_undef (hv.c:1634)
==14963==    by 0x814920C: Perl_sv_clear (sv.c:5802)
==14963==    by 0x8149BE7: Perl_sv_free2 (sv.c:6010)
==14963==    by 0x813AB58: do_clean_objs (sv.c:331)
==14963==    by 0x813A8B1: S_ptr_table_visit (sv.c:263)
==14963==    by 0x813A908: S_visit (sv.c:282)
==14963==    by 0x813AF70: Perl_sv_clean_objs (sv.c:370)
==14963==    by 0x80B5AB4: perl_destruct (perl.c:446)
==14963==  Address 0x3E55B7F0 is 60 bytes inside a block of size 85 free'd
==14963==    at 0x3C01E72D: free (vg_replace_malloc.c:127)
==14963==    by 0x8112284: Perl_safesysfree (util.c:145)
==14963==    by 0x81494F1: Perl_sv_clear (sv.c:5859)
==14963==    by 0x8149BE7: Perl_sv_free2 (sv.c:6010)
==14963==    by 0x811A6F2: Perl_mg_free (mg.c:405)
==14963==    by 0x8149012: Perl_sv_clear (sv.c:5774)
==14963==    by 0x8149BE7: Perl_sv_free2 (sv.c:6010)
==14963==    by 0x813AB58: do_clean_objs (sv.c:331)
==14963==    by 0x813A8B1: S_ptr_table_visit (sv.c:263)
==14963==    by 0x813A908: S_visit (sv.c:282)
==14963==    by 0x813AF70: Perl_sv_clean_objs (sv.c:370)
==14963==    by 0x80B5AB4: perl_destruct (perl.c:446)
==14963==    by 0x80B3F0D: main (perlmain.c:88)
==14963==
==14963== ---- Attach to debugger ? --- [Return/N/n/Y/y/C/c] ---- y

Line 2507 is the last one of these:

    /* record this inner handle for use by DBI::var::FETCH	*/
    if (is_DESTROY) {

	if (DBIc_TYPE(imp_xxh) <= DBIt_DB ) {	/* is dbh or drh */
	    imp_xxh_t *parent_imp;

	    if (SvOK(DBIc_ERR(imp_xxh)) && (parent_imp = DBIc_PARENT_COM(imp_xxh)) ) {
		/* copy err/errstr/state values to $DBI::err etc still work */
		sv_setsv(DBIc_ERR(parent_imp),    DBIc_ERR(imp_xxh));
		sv_setsv(DBIc_ERRSTR(parent_imp), DBIc_ERRSTR(imp_xxh));
		sv_setsv(DBIc_STATE(parent_imp),  DBIc_STATE(imp_xxh));


Which is the lookup of the SV Err in this structure:

typedef struct dbih_com_attr_st {
    /* These are copies of the Hash values (ref.cnt.inc'd)	*/
    /* Many of the hash values are themselves references	*/
    SV *TraceLevel;
    SV *State;		/* Standard SQLSTATE, 5 char string	*/
    SV *Err;		/* Native engine error code		*/
    SV *Errstr;		/* Native engine error message		*/
    UV ErrCount;
    U32  LongReadLen;	/* auto read length for long/blob types	*/
    SV *FetchHashKeyName;	/* for fetchrow_hashref		*/
    /* (NEW FIELDS?... DON'T FORGET TO UPDATE dbih_clearcom()!)	*/
} dbih_com_attr_t;


in the parent. (parent_imp)

The problem is that parent_imp has already been free()d, and it seems that
the child has no way of knowing this. It's probably a real DBI bug, but it's
hard to make it show up reliably on ponie, let alone conventional perl 5.
However, it might not be (quite) a real DBI bug, as currently ponie's SV
structure isn't totally like perl5's - SvRV() and SvPVX() aren't pointing to
the same piece of memory.

Nicholas Clark