| Summary: | Akonadi server triggers assert() in libmysql 5.7.34 | ||
|---|---|---|---|
| Product: | [Frameworks and Libraries] Akonadi | Reporter: | groot |
| Component: | server | Assignee: | kdepim bugs <pim-bugs-null> |
| Status: | RESOLVED UPSTREAM | ||
| Severity: | normal | ||
| Priority: | NOR | ||
| Version First Reported In: | 5.17.3 | ||
| Target Milestone: | --- | ||
| Platform: | Other | ||
| OS: | FreeBSD | ||
| Latest Commit: | Version Fixed/Implemented In: | ||
| Sentry Crash Report: | |||
|
Description
groot
2021-07-10 19:50:18 UTC
With some additional debugging added, and a mutex lock on QueryBuilder::exec() so it is singlethreaded, I get this output (as an indication what Akonadi is building up):
```
org.kde.pim.akonadiserver: Prepared new query for "SELECT PartTable.id, PartTable.pimItemId, PartTable.partTypeId, PartTable.data, PartTable.datasize, PartTable.version, PartTable.storage FROM PartTable WHERE ( PartTable.partTypeId = :0 AND storage = :1 AND data IS NOT NULL )"
org.kde.pim.akonadiserver: Bound 0 QVariant(qlonglong, 1)
org.kde.pim.akonadiserver: Bound 1 QVariant(qlonglong, 1)
Assertion failed: (param->buffer_length != 0), function setup_one_fetch_function, file /wrkdirs/usr/ports/databases/mysql57-client/work/mysql-5.7.34/libmysql/libmysql.c, line 4112.
```
and this slightly-more-detailed backtrace:
```
#0 thr_kill () at thr_kill.S:4
#1 0x0000000800ff71b4 in __raise (s=s@entry=6)
at /usr/src/src/lib/libc/gen/raise.c:52
#2 0x00000008010ac129 in abort () at /usr/src/src/lib/libc/stdlib/abort.c:67
#3 0x0000000800fda0c1 in __assert (func=<optimized out>, file=<optimized out>,
line=<optimized out>, failedexpr=<optimized out>)
at /usr/src/src/lib/libc/gen/assert.c:51
#4 0x0000000805efeb77 in ?? () from /usr/local/lib/mysql/libmysqlclient.so.20
#5 0x0000000805efe5ce in mysql_stmt_bind_result ()
from /usr/local/lib/mysql/libmysqlclient.so.20
#6 0x000000080325fe6f in ?? ()
from /usr/local/lib/qt5/plugins/sqldrivers/libqsqlmysql.so
#7 0x0000000800756da7 in QSqlQuery::exec() ()
from /usr/local/lib/qt5/libQt5Sql.so.5
#8 0x00000000003b9745 in Akonadi::Server::QueryBuilder::exec (
this=<optimized out>)
at /zbigone/src/kde/invent/akonadi/src/server/storage/querybuilder.cpp:418
#9 0x00000000003b4d86 in Akonadi::Server::PartHelper::remove (column=...,
value=...)
at /zbigone/src/kde/invent/akonadi/src/server/storage/parthelper.cpp:108
#10 0x0000000000359fbb in Akonadi::Server::DataStore::unhideAllPimItems (
this=<optimized out>)
at /zbigone/src/kde/invent/akonadi/src/server/storage/datastore.cpp:1177
#11 0x00000000002749f1 in Akonadi::Server::AkonadiServer::init (
this=0x7fffffffd158)
at /zbigone/src/kde/invent/akonadi/src/server/akonadi.cpp:152
```
Relevant code change between 5.7.33 and 5.7.34 is in libmysql.c, line 4112:
=== 5.7.33
case MYSQL_TYPE_BLOB:
case MYSQL_TYPE_BIT:
DBUG_ASSERT(param->buffer_length != 0);
=== 5.7.34
case MYSQL_TYPE_BLOB:
case MYSQL_TYPE_BIT:
assert(param->buffer_length != 0);
As you can see the DBUG_ASSERT has turned into a "real" assert.
By modifying the Qt MySQL drivers, e.g. void QMYSQLResultPrivate::bindBlobs() I can get the Qt layer to confirm that the value being passed in is 0. Apparently max_length for the field that is causing problems here, is indeed 0. By nudging that to 1, like so:
```
if (!bind->buffer_length) { bind->buffer_length=1;
qWarning("QMYSQLResultPrivate::bindBlobs: field max_length was 0");
}
```
Akonadi works again (because of the patch in Qt). I'm just not convinced that's a good fix: why is there a BLOB field of length 0, anyway?
I ended up patching the mysql driver in Qt as follows:
```
- if (qIsBlob(inBinds[i].buffer_type) && meta && fieldInfo) {
+ if (qIsBlob(inBinds[i].buffer_type) && meta && fieldInfo && fieldInfo->max_length) {
```
It **seems** to do the trick for akonadi, at least.
Closing because - the problem seems to live somewhere other than Akonadi itself (even if Akonadi triggers it) - as "upstream" because the issue is in the Qt MySQL plugin - the problem is patched downstream. |