segfaults in mysql driver
Martin Pala
martinp at tildeslash.com
Wed Mar 19 22:52:05 CET 2008
Hi,
the problem seems to be in the ensureCapacity():
--8<--
static int ensureCapacity(T R, int i) {
if ((R->columns[i]->length > R->bind[i].buffer_length)) {
/* Assume truncation, resize and fetch column directly. */
unsigned long newSize = (sizeof *(R->columns[i]) + 1 +
R->columns[i]->field->length);
memset(&R->bind[i], 0, sizeof(MYSQL_BIND));
R->bind[i].buffer_type = R->columns[i]->field->type;
RESIZE(R->columns[i], newSize);
R->bind[i].buffer = R->columns[i]->buffer;
R->bind[i].buffer_length = R->columns[i]->field->length;
R->bind[i].is_null = &R->columns[i]->is_null;
R->bind[i].length = &R->columns[i]->length;
R->columns[i]->field =
mysql_fetch_field_direct(R->meta, i);
if (mysql_stmt_fetch_column(R->stmt, &R->bind[i], i, 0)) {
THROW(SQLException);
return false;
}
}
return true;
}
--8<--
the R->columns[1]->length is bigger then R->columns[1]->field->length
... which is 4GB (MySQL BLOB range)
(gdb) p R->columns[1]->length
$26 = 648
(gdb) p R->columns[1]->field->length
$27 = 4294967295
The newSize is unsigned long ... 4GB for ILP32 => the newSize overflows:
(gdb) p newSize
$28 = 268
The R->columns[i] is resized to newSize (wrong length) and the
R->bind[i].buffer_length is set to 4GB
The mysql_stmt_fetch_column() then corrupts the memory.
... the full *R->columns[1] structure (before reallocation):
(gdb) p *R->columns[1]
$15 = {is_null = 0 '\0', field = 0x807de00, length = 648,
buffer = "From nobody at pacific.net.sg Tue Dec 04 19:52:17
2007\nX-Envelope-From: <nobody at pacific.net.sg>\nReceived: from
[127.0.0.1] (port=49353 helo=test11)\n by centos.nowhere.com with
smtp (Exim 4.63)\n "...}
(gdb) p *R->columns[1]->field
$16 = {name = 0x807dea0 "data", org_name = 0x807dea8 "data", table =
0x807de90 "test",
org_table = 0x807de98 "test", db = 0x807de88 "test", catalog =
0x807de80 "def", def = 0x0, length = 4294967295,
max_length = 0, name_length = 4, org_name_length = 4, table_length =
4, org_table_length = 4, db_length = 4,
catalog_length = 3, def_length = 0, flags = 4241, decimals = 0,
charsetnr = 63, type = MYSQL_TYPE_BLOB}
Martin
Paul J Stevens wrote:
> Jan-Henrik Haukeland wrote:
>> On 19. mars. 2008, at 15.40, Paul J Stevens wrote:
>>
>>> Ok, I get it, I think.
>>>
>>> Reading the source I come to the conclusion that I should use
>>> ResetSet_readData
>>> for any column wider than STRLEN chars rather than _getString or
>>> _getBlob
>> No, _getString and _getBlob should of course work with any column
>> length data. This looks to be a number overflow bug of some sorts in
>> ensureCapacity() according to Martin, which we of course will fix. I'm
>> just stumped we haven't seen this before, ourselves. Must be that we
>> mainly work with small data and using SQLite.
>
> Glad to hear you guys are on it. I'm already quite seriously committed
> to using zdb. I'm still single threaded, but my database code is fully
> updated. I've begun putting some serious pressure on the postgres driver
> which is holding out great. That means I really need to deal with any
> surprises in the other drivers. But your code is a pleasure to work with
> so far.
>
> I was zooming in on ensureCapacity myself. Isn't mysql_stmt_store_result
> required to determine the width of a column? R->columns[i]->length
> appears to stay 0. I also can't see an obvious solution that avoids
> allocating rows*max_length for each MysqlResultSet. But I don't have any
> experience with the mysql_stmt api (yet).
>
> Anyway, curious to see what Martin comes up with.
>
More information about the libzdb-general
mailing list