Skip Menu |

This queue is for tickets about the DBD-Sybase CPAN distribution.

Report information
The Basics
Id: 105810
Status: open
Priority: 0/
Queue: DBD-Sybase

People
Owner: Nobody in particular
Requestors: ZHENYZ [...] cpan.org
Cc:
AdminCc:

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



Subject: main.t crashes after 31 "execute compute" on fetching compute results
Perl 5.20.1, ASE 15.7, gcc 4.8 main.t gets over "ok 31 - execute compute" and crashes on fetching compute results. The test log is like ok 30 - Prepare compute ok 31 - execute compute Failed 5/36 subtests I looked at this issue with valgrind, it shows that the segfault happens at line 4092 of dbdimp.c. ==5230== syb_st_fetch() -> 2/0/0 ==5230== Invalid read of size 4 ==5230== at 0x40A86A0: syb_st_fetch (dbdimp.c:4092) ==5230== by 0x4098CD8: XS_DBD__Sybase__st_fetchrow_arrayref (Sybase.xsi:630) Corresponding source of dbdimp.c: 4073 for (i = 0; i < num_fields; ++i) { 4074 SV *sv = AvARRAY(av)[i]; /* Note: we (re)use the SV in the AV */ 4075 len = 0; 4076 4077 if (DBIc_DBISTATE(imp_dbh)->debug >= 5) { 4078 /*char *text = neatsvpv(phs->sv,0);*/ 4079 PerlIO_printf(DBIc_LOGPIO(imp_dbh), 4080 " syb_st_fetch() -> %d/%d/%d\n", i, 4081 imp_sth->coldata[i].valuelen, imp_sth->coldata[i].type); 4082 } 4083 /* If we're beyond the number of items in this result set 4084 or: the data is null 4085 or: noBindBlob is set and the data type is IMAGE or TEXT 4086 then: set sv to undef */ 4087 if (i >= imp_sth->numCols || imp_sth->coldata[i].indicator 4088 == CS_NULLDATA || (imp_sth->noBindBlob 4089 && (imp_sth->datafmt[i].datatype == CS_TEXT_TYPE 4090 || imp_sth->datafmt[i].datatype == CS_IMAGE_TYPE))) { 4091 /* NULL data */ 4092 (void) SvOK_off(sv); 4093 } else { There is a loop to go through the columns. And the problem is that the loop index i goes out of bound of array av, which comes from below assignment. 4059 av = DBIc_DBISTATE(imp_dbh)->get_fbav(imp_sth); Before the rows for compute results, a data row has 4 columns. When the data rows end, it saw compute rows of 2 columns and reallocs to shrink the av array for 2 columns. Below log was dumped with env variable DBI_TRACE=5 to indicate the realloc. syb_st_fetch() -> ct_fetch() = -204 (0 rows, 4 cols) st_next_result() -> ct_results(4045) == 1 ct_res_info() returns 2 columns STORE DBI::st=HASH(0xa784410) 'NUM_OF_FIELDS' => 2 dbih_setup_fbav realloc from 4 to 2 fields But the variable num_fields at dbdimp.c line 4073 is not changed and remains 4. This causes loop index i to go out of the array bound. I also tried another Perl we have, that is 5.14.2 (compiler is gcc 3.4), it also goes out of the bound here, but it does not have segfault, and main.t can pass. Below DBIC_TRACE=5 log shows that it can run to i=3 for the loop index. syb_st_fetch() -> 2/0/0 syb_st_fetch() -> 3/0/0 ... For 5.20, we cannot see that line of "syb_st_fetch() -> 3/0/0" in log, as segfault happens right after that 2/0/0 line.
Subject: [PATCH] main.t crashes after 31 "execute compute" on fetching compute results
On Sat Jul 11 08:36:39 2015, ZHENYZ wrote: Show quoted text
> Perl 5.20.1, ASE 15.7, gcc 4.8 > > main.t gets over "ok 31 - execute compute" and crashes on fetching > compute results. > The test log is like > > ok 30 - Prepare compute > ok 31 - execute compute > Failed 5/36 subtests > > I looked at this issue with valgrind, it shows that the segfault > happens at line 4092 of dbdimp.c. > > ==5230== > syb_st_fetch() -> 2/0/0 > ==5230== Invalid read of size 4 > ==5230== at 0x40A86A0: syb_st_fetch (dbdimp.c:4092) > ==5230== by 0x4098CD8: XS_DBD__Sybase__st_fetchrow_arrayref > (Sybase.xsi:630) > > Corresponding source of dbdimp.c: > > 4073 for (i = 0; i < num_fields; ++i) { > 4074 SV *sv = AvARRAY(av)[i]; /* Note: we (re)use the SV > in the AV */ > 4075 len = 0; > 4076 > 4077 if (DBIc_DBISTATE(imp_dbh)->debug >= 5) { > 4078 /*char *text = neatsvpv(phs->sv,0);*/ > 4079 PerlIO_printf(DBIc_LOGPIO(imp_dbh), > 4080 " syb_st_fetch() -> %d/%d/%d\n", i, > 4081 imp_sth->coldata[i].valuelen, imp_sth-
> >coldata[i].type);
> 4082 } > 4083 /* If we're beyond the number of items in this result > set > 4084 or: the data is null > 4085 or: noBindBlob is set and the data type is IMAGE or > TEXT > 4086 then: set sv to undef */ > 4087 if (i >= imp_sth->numCols || imp_sth-
> >coldata[i].indicator
> 4088 == CS_NULLDATA || (imp_sth->noBindBlob > 4089 && (imp_sth->datafmt[i].datatype == > CS_TEXT_TYPE > 4090 || imp_sth->datafmt[i].datatype == > CS_IMAGE_TYPE))) { > 4091 /* NULL data */ > 4092 (void) SvOK_off(sv); > 4093 } else { > > There is a loop to go through the columns. And the problem is that the > loop index i goes out of bound of array av, which comes from below > assignment. > > 4059 av = DBIc_DBISTATE(imp_dbh)->get_fbav(imp_sth); > > Before the rows for compute results, a data row has 4 columns. When > the data rows end, it saw compute rows of 2 columns and reallocs to > shrink the av array for 2 columns. Below log was dumped with env > variable DBI_TRACE=5 to indicate the realloc. > > syb_st_fetch() -> ct_fetch() = -204 (0 rows, 4 cols) > st_next_result() -> ct_results(4045) == 1 > ct_res_info() returns 2 columns > STORE DBI::st=HASH(0xa784410) 'NUM_OF_FIELDS' => 2 > dbih_setup_fbav realloc from 4 to 2 fields > > But the variable num_fields at dbdimp.c line 4073 is not changed and > remains 4. This causes loop index i to go out of the array bound. > > I also tried another Perl we have, that is 5.14.2 (compiler is gcc > 3.4), it also goes out of the bound here, but it does not have > segfault, and main.t can pass. Below DBIC_TRACE=5 log shows that it > can run to i=3 for the loop index. > > syb_st_fetch() -> 2/0/0 > syb_st_fetch() -> 3/0/0 > ... > > For 5.20, we cannot see that line of "syb_st_fetch() -> 3/0/0" in log, > as segfault happens right after that 2/0/0 line.
The same thing happens in 5.22. I've performed some more analysis. The following code snippets are from DBD::Sybase 1.16. When the regular rows are done, the next call to syb_st_fetch() will result in 4059 4060 TryAgain: retcode = ct_fetch(cmd, CS_UNUSED, CS_UNUSED, CS_UNUSED, 4061 &rows_read); 4062 setting retcode = CS_END_DATA. This is then processed here: 4206 case CS_END_DATA: /* we've seen all the data for this result 4207 set. So see if this is the end of the 4208 result sets */ 4209 4210 restype = st_next_result(sth, imp_sth); 4211 if (DBIc_DBISTATE(imp_dbh)->debug >= 3) 4212 PerlIO_printf(DBIc_LOGPIO(imp_dbh), 4213 " syb_st_fetch() -> st_next_results() == %d\n", restype); 4214 4215 if (restype == CS_CMD_DONE || restype == CS_CMD_FAIL) { 4216 return Nullav; 4217 } else { /* XXX What to do here??? */ 4218 /* if(fix_fbav(imp_sth, num_fields, av)) 4219 clear_cache(sth, imp_sth);*/ 4220 4221 if (restype == CS_COMPUTE_RESULT) { 4222 goto TryAgain; 4223 } 4224 4225 imp_sth->moreResults = 1; 4226 } 4227 return Nullav; 4228 break; The call to st_next_result at line 4210 is what leads to the reallocation of av. In st_next_result, 3343 while ((retcode = ct_results(cmd, &restype)) == CS_SUCCEED) { 3344 if (DBIc_DBISTATE(imp_dbh)->debug >= 3) 3345 PerlIO_printf(DBIc_LOGPIO(imp_dbh), 3346 " st_next_result() -> ct_results(%d) == %d\n", restype, 3347 retcode); 3348 3349 if (restype == CS_CMD_FAIL) 3350 failFlag = 1; 3351 if ((restype == CS_CMD_DONE || restype == CS_CMD_SUCCEED) && !failFlag) { 3352 ct_res_info(cmd, CS_ROW_COUNT, &imp_sth->numRows, CS_UNUSED, NULL); 3353 } 3354 switch (restype) { 3355 case CS_ROW_RESULT: 3356 case CS_PARAM_RESULT: 3357 case CS_STATUS_RESULT: 3358 case CS_CURSOR_RESULT: 3359 case CS_COMPUTE_RESULT: 3360 if (imp_sth->done_desc) { 3361 cleanUp(imp_sth); 3362 clear_cache(sth, imp_sth); 3363 } 3364 retcode = describe(sth, imp_sth, restype); the call to ct_results at line 3343 sets restype to CS_COMPUTE_RESULT. The switch( restype) at 3354 leads to the invocation of describe() at line 3364. And in describe(), 3064 /* According to Tim Bunce I shouldn't need the code below. 3065 However, if I remove it DBD::Sybase segfaults in some situations 3066 with DBI < 1.53, and there are still problems with COMPUTE BY 3067 statements with DBI >= 1.54. */ 3068 /* Adjust NUM_OF_FIELDS - which also adjusts the row buffer size */ 3069 DBIc_NUM_FIELDS(imp_sth) = 0; /* for DBI <= 1.53 */ 3070 DBIc_DBISTATE(imp_sth)->set_attr_k(sth, sv_2mortal( 3071 newSVpvn("NUM_OF_FIELDS", 13)), 0, sv_2mortal(newSViv(numCols))); 3072 And now we need to switch distributions, to DBI (version 1.637). In DBI.xs, in the set_attr_k function, 2246 else if (htype==DBIt_ST && strEQ(key, "NUM_OF_FIELDS")) { 2247 D_imp_sth(h); 2248 int new_num_fields = (SvOK(valuesv)) ? SvIV(valuesv) : -1; 2249 DBIc_NUM_FIELDS(imp_sth) = new_num_fields; 2250 if (DBIc_FIELDS_AV(imp_sth)) { /* modify existing fbav */ 2251 dbih_setup_fbav(imp_sth); 2252 } the changed number of fields is noted, and dbih_setup_fbav() (same file) performs the reallocation: 1803 if (av) { 1804 if (av_len(av)+1 == i) /* is existing array the right size? */ 1805 return av; 1806 /* we need to adjust the size of the array */ 1807 if (DBIc_TRACE_LEVEL(imp_sth) >= 2) 1808 PerlIO_printf(DBIc_LOGPIO(imp_sth)," dbih_setup_fbav realloc from %ld to %ld fields\n", (long)(av_len(av)+1), (long)i); 1809 SvREADONLY_off(av); 1810 if (i < av_len(av)+1) /* trim to size if too big */ 1811 av_fill(av, i-1); 1812 } Eventually (!) the control flow returns to syb_st_fetch, line 4211. 4210 restype = st_next_result(sth, imp_sth); 4211 if (DBIc_DBISTATE(imp_dbh)->debug >= 3) 4212 PerlIO_printf(DBIc_LOGPIO(imp_dbh), 4213 " syb_st_fetch() -> st_next_results() == %d\n", restype); 4214 4215 if (restype == CS_CMD_DONE || restype == CS_CMD_FAIL) { 4216 return Nullav; We pick up the story again at line 4217. Note that the author expresses concern about what to do, and the fix_fbav() function, which is commented out was an attempt to perform some sort of a fix. 4217 } else { /* XXX What to do here??? */ 4218 /* if(fix_fbav(imp_sth, num_fields, av)) 4219 clear_cache(sth, imp_sth);*/ 4220 4221 if (restype == CS_COMPUTE_RESULT) { 4222 goto TryAgain; 4223 } 4224 4225 imp_sth->moreResults = 1; 4226 } 4227 return Nullav; 4228 break; Regardless, at line 4222 we jump back to TryAgain (line 4060), with num_fields now no longer tracking the revised size of av. Here's my incredibly simple-minded fix (attached), based upon the following logic. In the describe() function, which the new number of columns is determined from ct_res_info: 3049 if ((retcode = ct_res_info(imp_sth->cmd, CS_NUMDATA, &numCols, CS_UNUSED, 3050 NULL)) != CS_SUCCEED) { in the same way that num_fields is determined in syb_st_fetch: 4050 ** Find out how many columns there are in this result set. 4051 */ 4052 retcode = ct_res_info(cmd, CS_NUMDATA, &num_fields, CS_UNUSED, NULL); describe() later stores this in imp_sth->numCols: 3085 3086 imp_sth->numCols = numCols; 3087 So, since the number of columns is determined in the same way, rather than calling ct_res_info again, I simply set num_fields to imp_sth->numCols prior to the jump to TryAgain: 4221 if (restype == CS_COMPUTE_RESULT) { 4222 num_fields = imp_sth->numCols; 4223 goto TryAgain; 4224 } 4225 and the tests pass.
Subject: DBD-Sybase-1.16.patch
# This is a patch for DBD-Sybase-1.16.orig to update it to DBD-Sybase-1.16 # # To apply this patch: # STEP 1: Chdir to the source directory. # STEP 2: Run the 'applypatch' program with this patch file as input. # # If you do not have 'applypatch', it is part of the 'makepatch' package # that you can fetch from the Comprehensive Perl Archive Network: # http://www.perl.com/CPAN/authors/Johan_Vromans/makepatch-x.y.tar.gz # In the above URL, 'x' should be 2 or higher. # # To apply this patch without the use of 'applypatch': # STEP 1: Chdir to the source directory. # STEP 2: Run the 'patch' program with this file as input. # #### End of Preamble #### #### Patch data follows #### diff -c 'DBD-Sybase-1.16.orig/dbdimp.c' 'DBD-Sybase-1.16/dbdimp.c' Index: ./dbdimp.c Prereq: 1.116 *** ./dbdimp.c Sun Sep 10 10:31:45 2017 --- ./dbdimp.c Tue Oct 17 17:22:36 2017 *************** *** 4219,4224 **** --- 4219,4225 ---- clear_cache(sth, imp_sth);*/ if (restype == CS_COMPUTE_RESULT) { + num_fields = imp_sth->numCols; goto TryAgain; } #### End of Patch data #### #### ApplyPatch data follows #### # Data version : 1.0 # Date generated : Tue Oct 17 17:28:38 2017 # Generated by : makepatch 2.05 # Recurse directories : Yes # Excluded files : (\A|/).*\~\Z # (\A|/).*\.a\Z # (\A|/).*\.bak\Z # (\A|/).*\.BAK\Z # (\A|/).*\.elc\Z # (\A|/).*\.exe\Z # (\A|/).*\.gz\Z # (\A|/).*\.ln\Z # (\A|/).*\.o\Z # (\A|/).*\.obj\Z # (\A|/).*\.olb\Z # (\A|/).*\.old\Z # (\A|/).*\.orig\Z # (\A|/).*\.rej\Z # (\A|/).*\.so\Z # (\A|/).*\.Z\Z # (\A|/)\.del\-.*\Z # (\A|/)\.make\.state\Z # (\A|/)\.nse_depinfo\Z # (\A|/)core\Z # (\A|/)tags\Z # (\A|/)TAGS\Z # p 'dbdimp.c' 163974 1508275356 0100644 #### End of ApplyPatch data #### #### End of Patch kit [created: Tue Oct 17 17:28:38 2017] #### #### Patch checksum: 49 1658 29427 #### #### Checksum: 67 2354 21339 ####