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

Dennis Nicklaus nicklaus at crusher.fnal.gov
Fri Sep 8 18:04:57 EDT 2000

Does anyone else use freetds's dbdata() function?
How about with SYBVARBINARY data?

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;

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.

In this SYBVARBINARY case, my 	
gets set to 1 in tds_alloc_results() from tds/mem.c during the dbresults()

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.

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.

Dennis Nicklaus nicklaus at fnal.gov

More information about the FreeTDS mailing list