Skip Menu |

This queue is for tickets about the DBI CPAN distribution.

Report information
The Basics
Id: 32309
Status: resolved
Priority: 0/
Queue: DBI

People
Owner: Nobody in particular
Requestors: vandry [...] TZoNE.ORG
Cc:
AdminCc:

Bug Information
Severity: Important
Broken in: 1.601
Fixed in: (no value)



Subject: "DBIS" macro defined incorrectly
The DBIS macro is declared in the "DBIXS.h" header file and used by the various DBD::xx modules to fetch the state information published by the DBI module. The definition of this as follows: # define DBIS (*(INT2PTR(dbistate_t**, &SvIVX(DBISTATE_ADDRSV)))) (DBIXH.h line 458) This definition is incorrect. This bug requires the following preconditions in order to occur: - Perl built with threads (MULTIPLICITY is defined). Without this, a different definition for the DBIS macro is used, and that definition does not exhibit a problem. - Integers and pointers are not the same size. If integers and pointers are the same size then the macro becomes a no-op and is harmless. - Big endian platform. On little endian, everything just works out. NOTE regarding the severity level I have attached to this ticket: although most Perl users will not be affected by this bug because they do not have systems that meet the preconditions above, DBI is completely unusable due to this bug on those platforms that do meet the preconditions, so it should be regarded as a critical bug. Why is this macro wrong? First we fetch the state variable using DBISTATE_ADDRSV, then we get its integer value using SvIVX. Now we take a pointer to this integer (using &). The resulting type is (IV *) but INT2PTR casts it to a (dbistate_t**). This cast doesn't make any sense: this value is not at all a pointer to a pointer to a structure of type dbistate_t, it's a pointer to an integer whose value is the same as the address of a structure of type dbistate_t. Here is an example for platform "sun4-solaris-thread-multi-64int" where the integers are 8 bytes and the pointers are 4 bytes. SvIVX returns an [8-byte] integer. Now we take a pointer to this integer and cast it to a (dbistate_t**). Then we dereference that double pointer. This causes us to look at the first four bytes of the integer and interpret them as a pointer. Since these are the most significant 4 bytes of the original integer, the result is incorrect (we are actually trying to get at the least significant 4 bytes of the integer). We are left with a result of type (dbistate_t *) which is a NULL pointer. I do not understand why the definition of this macro is so complicated. It seems to me that what we are trying to do is actually just this: #define DBIS (INT2PTR(dbistate_t*, SvIVX(DBISTATE_ADDRSV))) That is, take the result of SvIVX (which is of type IV) and cast it to a pointer of type (dbistate_t*). Because of the different sizes of the two types, this cast causes the most significant bytes of the value to be discarded on platforms where integers are bigger than pointers, which is what we want. The resulting (dbistate_t*) is returned directly. I am mystified as to why the original macro creates an extra indirection of the pointer only to dereference it again at the end. It is both simpler and more correct to not do that. I mention my interrogation on this point only in case there is some reason for the more complicated definition that eludes me. TO REPRODUCE: - Install DBI normally on platform sun4-solaris-thread-multi-64int. - Unpack, configure, and make the latest version of DBD::mysql. - make test will fail TO PROVE MY ALTERNATE DEFINITON OF DBIS WORKS: - Edit the mysql.xs file that is part of the DBD::mysql distribution. - Right after the includes at the top of the file, override the definition of the DBIS macro by inserting these lines: #undef DBIS #define DBIS (INT2PTR(dbistate_t*, SvIVX(DBISTATE_ADDRSV))) - rerun make - make test now passes RECOMMENDATION FOR FIX: Change the definition of the DBIS macro in the DBIXS.h file to the one I suggest. Change also the dbis macro 2 lines below. -Phil
The macro is complex because (as I recall) it was setup to be an lvalue. ActiveState supplied the patch many years ago when they added PERL_OBJECT. The tricky question is: do some drivers still need it to be an lvalue? I think the answer is no but I'm not sure. Would you be willing to test alternative fixes?
Subject: Re: [rt.cpan.org #32309] "DBIS" macro defined incorrectly
Date: Fri, 21 Mar 2008 20:25:45 -0400
To: Tim_Bunce via RT <bug-DBI [...] rt.cpan.org>
From: Phil Vandry <vandry [...] TZoNE.ORG>
On Fri, Mar 21, 2008 at 08:11:21PM -0400, Tim_Bunce via RT wrote: Show quoted text
> The macro is complex because (as I recall) it was setup to be an lvalue.
Ah, that would explain it! Show quoted text
> Would you be willing to test alternative fixes?
Yes, I can easily test using the same SPARC on which I originally encountered the problem. -Phil
I've not been able to find time to work on this. Could you? Meanwhile I've downgraded this from Critical to Important as you're still the only one to have raised the issue.
From: ranjmis [...] gmail.com
Perl Gurus, I have banged into the same problem on solaris-sparc multi-threaded perl build - for good reasons i guess. I have been figuring the issue out with DBD-SQLite-1.14 on sparc. (Raised a bug also there http://rt.cpan.org/Public/Bug/Display.html?id=35972 but actually it belongs to DBI) After wrestling for couple of days with XS and SQLite.c interface I too found DBIS is what is causing the problem. I could fix the problem partially by redefining D_imp_* macros where instead of doing a & then ** and * in INT2PTR, directly worked on the integer casted pointer. I did : #ifdef D_imp_dbh #undef D_imp_dbh #undef D_imp_drh #undef D_imp_sth #define D_imp_dbh(dbh) imp_dbh_t * imp_dbh = ( imp_dbh_t * ) ( ( ( ( ( dbistate_t * ) ( unsigned long) ( ( ( XPVIV * ) ( ( (SV*)Perl_get_sv ( ( ( PerlInterpreter * ) pthread_getspecific ( ( * Perl_Gthr_key_ptr ( (void *)0 ) ) ) ) , "DBI::_dbistate " , 0x05 ) ) ) -> sv_any) -> xiv_iv ) ) ) -> getcom ( dbh ) ) ) #define D_imp_drh(drh) imp_drh_t * imp_drh = ( imp_drh_t * ) ( ( ( ( ( dbistate_t * ) ( unsigned long ) ( ( ( XPVIV * ) ( ( (SV*)Perl_get_sv ( ( ( PerlInterpreter * ) pthread_getspecific ( ( * Perl_Gthr_key_ptr ( 0 ) ) ) ) , "DBI::_dbistate" , 0x0 5 ) ) ) -> sv_any ) -> xiv_iv ) ) ) -> getcom ( drh ) ) ); #define D_imp_sth(sth) imp_sth_t * imp_sth = ( imp_sth_t * ) ( ( ( ( ( dbistate_t * ) ( unsigned long ) ( ( ( XPVIV * ) ( ( (SV*)Perl_get_sv ( ( ( PerlInterpreter * ) pthread_getspecific ( ( * Perl_Gthr_key_ptr ( 0 ) ) ) ) , "DBI::_dbistate" , 0x05 ) ) ) -> sv_any ) -> xiv_iv ) ) ) -> getcom ( sth ) ) ) #endif but stuck when I defined DBIS as it is acting as a lvalue at many places like dbdimp.c for SQLite: void sqlite_init(dbistate_t *dbistate) { dTHR; DBIS = dbistate; } so we need & and ** and * there. (Although I could figure out the problem but PVANDRY has beautifully explained the issue making it crystal clear. Many thanks.) If there is any patch lying around for this lvalue or any quick fix would be very helpful. On Fri Mar 21 20:08:00 2008, TIMB wrote: Show quoted text
> The macro is complex because (as I recall) it was setup to be an lvalue. > ActiveState supplied the patch many years ago when they added PERL_OBJECT. > The tricky question is: do some drivers still need it to be an lvalue? > I think the answer is no but I'm not sure. > Would you be willing to test alternative fixes? >
From: ranjmis [...] gmail.com
Hi, Problem fixed as: In SQLiteXS.h #undef DBIS #define DBIS (INT2PTR(dbistate_t*, SvIVX(DBISTATE_ADDRSV))) #define DBISV SvIVX(DBISTATE_ADDRSV) DBISV is ment to be used as lvalue. So in dbdimp.c void sqlite_init(dbistate_t *dbistate) { dTHR; DBISV = dbistate; } ( Updated http://rt.cpan.org/Public/Bug/Display.html?id=35972 ) On Thu May 22 14:20:57 2008, ranjmis wrote: Show quoted text
> Perl Gurus, > > I have banged into the same problem on solaris-sparc multi-threaded perl > build - for good reasons i guess. > I have been figuring the issue out with DBD-SQLite-1.14 on sparc. > (Raised a bug also there > http://rt.cpan.org/Public/Bug/Display.html?id=35972 but actually it > belongs to DBI) > After wrestling for couple of days with XS and SQLite.c interface I too > found DBIS is what is causing the problem. I could fix the problem > partially by redefining D_imp_* macros where instead of doing a & then > ** and * in INT2PTR, directly worked on the integer casted pointer. > > I did : > > #ifdef D_imp_dbh > #undef D_imp_dbh > #undef D_imp_drh > #undef D_imp_sth > #define D_imp_dbh(dbh) imp_dbh_t * imp_dbh = ( imp_dbh_t * ) ( ( ( ( ( > dbistate_t * ) ( unsigned long) ( ( ( XPVIV * ) ( ( > (SV*)Perl_get_sv ( ( ( PerlInterpreter * ) pthread_getspecific ( ( * > Perl_Gthr_key_ptr ( (void *)0 ) ) ) ) , "DBI::_dbistate > " , 0x05 ) ) ) -> sv_any) -> xiv_iv ) ) ) -> getcom ( dbh ) ) ) > #define D_imp_drh(drh) imp_drh_t * imp_drh = ( imp_drh_t * ) ( ( ( ( ( > dbistate_t * ) ( unsigned long ) ( ( ( XPVIV * ) ( > ( (SV*)Perl_get_sv ( ( ( PerlInterpreter * ) pthread_getspecific ( ( * > Perl_Gthr_key_ptr ( 0 ) ) ) ) , "DBI::_dbistate" , 0x0 > 5 ) ) ) -> sv_any ) -> xiv_iv ) ) ) -> getcom ( drh ) ) ); > #define D_imp_sth(sth) imp_sth_t * imp_sth = ( imp_sth_t * ) ( ( ( ( > ( dbistate_t * ) ( unsigned long ) ( ( ( XPVIV * ) > ( ( (SV*)Perl_get_sv ( ( ( PerlInterpreter * ) pthread_getspecific ( ( > * Perl_Gthr_key_ptr ( 0 ) ) ) ) , "DBI::_dbistate" , > 0x05 ) ) ) -> sv_any ) -> xiv_iv ) ) ) -> getcom ( sth ) ) ) > #endif > > but stuck when I defined DBIS as it is acting as a lvalue at many places > like dbdimp.c for SQLite: > > void > sqlite_init(dbistate_t *dbistate) > { > dTHR; > DBIS = dbistate; > } > > so we need & and ** and * there. > (Although I could figure out the problem but PVANDRY has beautifully > explained the issue making it crystal clear. Many thanks.) > If there is any patch lying around for this lvalue or any quick fix > would be very helpful. > > On Fri Mar 21 20:08:00 2008, TIMB wrote:
> > The macro is complex because (as I recall) it was setup to be an lvalue. > > ActiveState supplied the patch many years ago when they added
PERL_OBJECT. Show quoted text
> > The tricky question is: do some drivers still need it to be an lvalue? > > I think the answer is no but I'm not sure. > > Would you be willing to test alternative fixes? > >
> >
I think I have fixed this now, as of revision 11329. I'd be grateful if someone could test it using the version in the repository. See http://search.cpan.org/~timb/DBI/DBI.pm#CONTRIBUTING