Skip to content

Commit

Permalink
Add a workaround for broken MariaDB clients which overwrite SIGPIPE h…
Browse files Browse the repository at this point in the history
…andler

MariaDB Connector/C 3.0.0 in function mysql_server_init() for non-Windows
systems started setting SIGPIPE handler to SIG_IGN. This breaks Perl
applications which installed its own SIGPIPE signal handler.

As a workaround use Perl rsignal_save() function to save existing SIGPIPE
handler before calling mysql_server_init() and after that restore saved
handler via Perl rsignal_restore() function.

Add a test which verifies that DBI->connect() which calls DBD::MariaDB's
mariadb_dr_connect() function and which calls mysql_server_init(), does not
overwrite $SIG{PIPE} handler set in Perl code.

Fixes: perl5-dbi#170
See: http://jira.mariadb.org/browse/CONC-591
  • Loading branch information
pali committed Sep 6, 2023
1 parent 0534b71 commit 8789e23
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 1 deletion.
1 change: 1 addition & 0 deletions MANIFEST
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ t/15reconnect.t
t/16dbi-get_info.t
t/17close_on_exec.t
t/18begin_work_without_raise_error.t
t/19sigpipe.t
t/20createdrop.t
t/25lockunlock.t
t/29warnings.t
Expand Down
25 changes: 24 additions & 1 deletion dbdimp.c
Original file line number Diff line number Diff line change
Expand Up @@ -1643,9 +1643,32 @@ static bool mariadb_dr_connect(
{
if (imp_drh->instances == 0 && !imp_drh->non_embedded_started)
{
int init_failed;

/*
* MariaDB Connector/C 3.0.0 in function mysql_server_init() for non-Windows systems started
* setting SIGPIPE handler to SIG_IGN. This breaks Perl applications which installed its own
* SIGPIPE signal handler. As a workaround use Perl rsignal_save() function to save existing
* SIGPIPE handler before calling mysql_server_init() and after that restore saved handler via
* Perl rsignal_restore() function. Note that Perl rsignal_save() function overwrites current
* handler (to our specified SIG_IGN), but this is not an issue as we always restored the
* saved handler. See reported issue: http://jira.mariadb.org/browse/CONC-591
*/
#if !defined(_WIN32) && defined(SIGPIPE) && defined(MARIADB_PACKAGE_VERSION) && defined(MARIADB_PACKAGE_VERSION_ID) && MARIADB_PACKAGE_VERSION_ID >= 30000
Sigsave_t pipehand;
int pipehand_failed = Perl_rsignal_save(aTHX_ SIGPIPE, (Sighandler_t)(void (*)())SIG_IGN, &pipehand);
#endif

/* negative value means to not start embedded server and just to initialize client library */
/* initializing client library is needed prior to any other mysql_* call from client library */
if (mysql_server_init(-1, NULL, NULL))
init_failed = mysql_server_init(-1, NULL, NULL);

#if !defined(_WIN32) && defined(SIGPIPE) && defined(MARIADB_PACKAGE_VERSION) && defined(MARIADB_PACKAGE_VERSION_ID) && MARIADB_PACKAGE_VERSION_ID >= 30000
if (!pipehand_failed)
Perl_rsignal_restore(aTHX_ SIGPIPE, &pipehand);
#endif

if (init_failed)
{
error_no_connection(dbh, "Connection error: Cannot initialize client library");
return FALSE;
Expand Down
22 changes: 22 additions & 0 deletions t/19sigpipe.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use strict;
use warnings;

use Test::More;
use DBI;

use vars qw($test_dsn $test_user $test_password);
use lib 't', '.';
require 'lib.pl';

plan skip_all => '$SIG{PIPE} is not supported' unless exists $SIG{PIPE};

plan tests => 1;

my $sigpipe_handler_called;
$SIG{PIPE} = sub { $sigpipe_handler_called = 1; };

DBI->connect($test_dsn, $test_user, $test_password, { RaiseError => 0, PrintError => 0, AutoCommit => 0 });

kill('PIPE', $$);

ok($sigpipe_handler_called, 'DBI->connect() does not overwrite $SIG{PIPE} handler');

0 comments on commit 8789e23

Please sign in to comment.