dbdata() broken? alignment error, overflow, Returns length+data, not just data.

Brian Bruns camber at ais.org
Sat Sep 9 08:46:51 EDT 2000

On Fri, 8 Sep 2000, Dennis Nicklaus wrote:

> Does anyone else use freetds's dbdata() function?
> How about with SYBVARBINARY data?
dbdata generally works but SYBVARBINARY is apparently broken.  Let me look
at the docs and see what it should do.
> I don't believe it functions correctly, at least with SYBVARBINARY.
> My understanding of dbdata is that it is supposed to return the buffer
> full of data that is read for the column.  However, for SYBVARBINARY, 
> it returns a (TDS_VARBINARY *), that is a pointer to a structure having its first 4
> bytes as the length of data, followed by the data of that length.
> >From other applications written by colleagues, I don't think that is
> correct.  See the function tds_process_row() in src/tds/token.c, the lines:
> } else if (curcol->column_type == SYBVARBINARY) {
> 	varbin = (TDS_VARBINARY *) &(info->current_row[curcol->column_offset]);
> 	varbin->len = colsize;
> 	tds_get_n(tds,varbin->array,colsize);
> which are processed during the dbnextrow() call.
> That, coupled with the src/dblib/dblib.c function dbdata which has this line:
> 	return &resinfo->current_row[colinfo->column_offset];
> Also, can someone explain the use of colinfo->column_offset here.
> It gets set to 1 with my SYBVARBINARY data. And I think that may be a mistake.
> All that seems to do is to cause some alignment run-time errors, 
> (which crashes the program under Sun-solaris).
> In particular, the assignment above:
> 	varbin->len = colsize;	
> crashes because varbin->len isn't word aligned, it is offset by
> that column_offset=1.
curcol->column_offset is the offset in the row buffer to the current
column.  It will start at (cols / 8) to store null indicator bits. Again
this appears to be a problem with only the SYBVARBINARY and Sparc
architecture.  I had thought we had caught all of those.  Although looking
at mem.c (line 97) it should be working.  Are you using 0.50 or the CVS

> In this SYBVARBINARY case, my 	
> 	res_info->row_size
> gets set to 1 in tds_alloc_results() from tds/mem.c during the dbresults()
> processing.
> My actual data rows have size: curcol->column_size=128 (from tds_process_col_info()).
> So tracing through tds_process_col_info() with SYBVARBINARY data, it
> will execute:
> 			curcol->column_offset = info->row_size;
> 			info->row_size += curcol->column_size + 1;
> so column_offset get set to 1 (old value of row_size),
> and then info->row_size gets increased to 130.
> Then, finally, since I have configured for tds 4.2, I execute:
> 	remainder = info->row_size % align; 
>  	if (remainder)
> 		info->row_size += (align - remainder);
> which increases row_size to 132.  Then it calls tds_alloc_row()
> which will malloc 132 bytes.  
> Now, when we call dbnextrow, look again at the code with the "varbin" variable
> in tds_process_row().  If I really have 128 bytes of data in this row, it
> is going to overflow the malloced area.
space in the row buffer is allocated fro the maximum size, if you have
varchar(255) and the data is 1 byte long you get 255 reserved in the row
> So, the big question I have:  Why is column_offset being set to 1 here?
> Should it be?  I don't have any idea what column_offset is for, so I don't
> feel good about fixing it one way or the other.
Again, NULL indicators are packed at the begining of the row buffer.

> Thanks!
> Dennis Nicklaus nicklaus at fnal.gov

More information about the FreeTDS mailing list