DBD::mysql version
4.052
MySQL client version
8.0.45
Server version
8.0.45-0ubuntu0.22.04.1
Operating system version
Ubuntu 24.04.4 LTS
What happened?
We run a reasonably popular website with Apache+mod_perl & MySQL. Since upgrading a few things[1], we've been experiencing segfaults in apache processes several times a day: 35 yesterday, 12 the day before, 24 the day before that... Analysing core dumps showed the culprit being a function pointer call at the bottom of MySQL's mysql_real_connect() function.
The function pointer (and indeed much of the rest of the MYSQL struct) was uninitialised, hence the segfault. Looking at where that info is supposed to come from, it should be set in mysql_init(). However, it's possible (in cases of specific memory pressure) for mysql_init() to fail, in which case it will return nullptr.
This error case isn't checked by DBD::mysql, so if this occurs, DBD::mysql will continue freely setting options (which works, because the MYSQL struct itself is allocated, it's just not totally filled-out). Eventually it ends up in mysql_real_connect(), where the first actual access to an uninitialised field is the culprit function pointer call, and there's our segfault.
Fixing this is just a matter of ensuring that DBD::mysql checks for mysql_init() failures and reasonably exits, rather than continuing until something explodes.
I've written a patch on my local machine, but haven't really tested it, as running manually-compiled DBD will require compiling MySQL & Perl, which will require compiling other modules, and so on ad infinitum. The patch is pretty trivial though, and it compiles OK, so I'm hoping it just works.
diff --git a/dbdimp.c b/dbdimp.c
index 39db033..7a00e94 100644
--- a/dbdimp.c
+++ b/dbdimp.c
@@ -1207,7 +1207,8 @@ MYSQL *mysql_dr_connect(
client_flag = CLIENT_FOUND_ROWS;
#endif
mysql_library_init(0, NULL, NULL);
- mysql_init(sock);
+ if (!mysql_init(sock))
+ return NULL;
if (imp_dbh)
{
[1] I suspect the upgrade just caused the specific memory pressure pattern for this problem to start occuring, rather than it being a flaw in the particular versions of things that we upgraded to.
Other information
No response
DBD::mysql version
4.052
MySQL client version
8.0.45
Server version
8.0.45-0ubuntu0.22.04.1
Operating system version
Ubuntu 24.04.4 LTS
What happened?
We run a reasonably popular website with Apache+mod_perl & MySQL. Since upgrading a few things[1], we've been experiencing segfaults in apache processes several times a day: 35 yesterday, 12 the day before, 24 the day before that... Analysing core dumps showed the culprit being a function pointer call at the bottom of MySQL's
mysql_real_connect()function.The function pointer (and indeed much of the rest of the
MYSQLstruct) was uninitialised, hence the segfault. Looking at where that info is supposed to come from, it should be set inmysql_init(). However, it's possible (in cases of specific memory pressure) formysql_init()to fail, in which case it will returnnullptr.This error case isn't checked by
DBD::mysql, so if this occurs,DBD::mysqlwill continue freely setting options (which works, because theMYSQLstruct itself is allocated, it's just not totally filled-out). Eventually it ends up inmysql_real_connect(), where the first actual access to an uninitialised field is the culprit function pointer call, and there's our segfault.Fixing this is just a matter of ensuring that
DBD::mysqlchecks formysql_init()failures and reasonably exits, rather than continuing until something explodes.I've written a patch on my local machine, but haven't really tested it, as running manually-compiled DBD will require compiling MySQL & Perl, which will require compiling other modules, and so on ad infinitum. The patch is pretty trivial though, and it compiles OK, so I'm hoping it just works.
[1] I suspect the upgrade just caused the specific memory pressure pattern for this problem to start occuring, rather than it being a flaw in the particular versions of things that we upgraded to.
Other information
No response