MySQL driver segfaulting under mod_perl - where to look for issue - mysql

I have a webapp that segfaults when the database in restarted and it tries to use the old connections. Running it under gdb --args apache -X leads to the following output:
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread -1212868928 (LWP 16098)]
0xb7471c20 in mysql_send_query () from /usr/lib/libmysqlclient.so.15
I've checked that the drivers and database are all up to date (DBD::mysql 4.0008, MySQL 5.0.32-Debian_7etch6-log).
Annoyingly I can't reproduce this with a trivial script:
use DBI;
use Test::More tests => 2;
my $dbh = DBI->connect( "dbi:mysql:test", 'root' );
sub test_db {
my ($number) = $dbh->selectrow_array("select 1 ");
return $number;
}
is test_db, 1, "connected to db";
warn "restart db now";
getc;
is test_db, 1, "connected to db";
Which gives the following:
ok 1 - connected to db
restart db now at dbd-mysql-test.pl line 23.
DBD::mysql::db selectrow_array failed: MySQL server has gone away at dbd-mysql-test.pl line 17.
not ok 2 - connected to db
# Failed test 'connected to db'
# at dbd-mysql-test.pl line 26.
# got: undef
# expected: '1'
This behaves correctly, telling me why the request failed.
What stumps me is that it is segfaulting, which it shouldn't do. As it only appears to happen when the whole app is running (which uses DBIx::Class) it is hard to reduce it to a test case.
Where should I start to look to debug this? Has anyone else seen this?
UPDATE: further prodding showed that it being under mod_perl was a red herring. Having reduced it to a simple test script I've now posted to the DBI mailing list. Thanks for your answers.

What this probably means is that there's a difference between your mod_perl environment and the one you were testing via your script. Some things to check:
Was your mod_perl compiled with the same version of Perl
Are the #INC's the same for both
Are you using threads in your mod_perl setup? I don't believe DBD::mysql is completely thread-safe.

I've seen this problem, but I'm not sure it had the same cause as yours. Are you by chance using a certain module for sending mails (forgot the name, sorry) from your application? When we had the problem in a project, after days of debugging we found that this mail module was doing strange things with open file descriptors, then forked off another process which called the console tool sendmail, which again did strange things with file descriptors. I guess one of the file descriptors it messed around with was the connection to the database, but I'm still not sure about that. The problem disappeared when we switched to another module for sending mails. Maybe it's worth a look for you too.

If you're getting a segfault, do you have a core file greated? If not, check ulimit -c. If that returns 0, your system won't create core files and you'll have to change that. If you do have a core file, you can use gdb or similar tools to debug it. It's not particularly fun, but it's possible. The start of the command will look something like:
gbd /usr/bin/httpd core
There are plenty of tutorials for debugging core files scattered about the Web.
Update: Just found a reference for ensuring you get core dumps from mod_perl. That should help.

This is a known problem in old DBD::mysql. Upgrade it (4.008 is not up to date).
There's a simple test script attached to https://rt.cpan.org/Public/Bug/Display.html?id=37027
that will trigger this bug.

Related

Perl gives "gzip: stdout: Broken pipe" error when opening gzipped files, but only if connecting to a DB

Consider the following program, running on a Linux machine, which opens a gzipped input file:
#!/usr/bin/env perl
open (my $fileHandle, "-|", "/bin/zcat $ARGV[0]");
my $ff = <$fileHandle>;
close($fileHandle);
That works as expected (it does nothing, but prints no error):
$ bar.pl file.gz
$
Now, if I use the same code but previously connect to a MySQL database, gzip will complain (you can run the code directly, this is an open DB and the credentials will work):
#!/usr/bin/env perl
use DBI;
use strict;
use warnings;
my $dsn = "DBI:mysql:database=hg19;host=genome-mysql.cse.ucsc.edu";
my $db = DBI->connect($dsn, 'genomep', 'password');
my $dbResults = $db->prepare("show tables");
my $ret = $dbResults->execute();
$dbResults->finish();
$db->disconnect();
open (my $fileHandle, "-|", "/bin/zcat $ARGV[0]");
my $ff = <$fileHandle>;
close($ff);
Running the above gives:
$ foo.pl file.gz
gzip: stdout: Broken pipe
This is obviously part of a much more complicated program, but I've managed to trim it down to this silly snippet that reproduces the issue.
What's going on? Why does connecting to a DB affect how gzip behaves? Note that everything seems to work (in the actual program, I do something useful with the gzipped data) but why am I getting that error message?
It turns out this behavior is specific to (slightly) older versions of Perl and/or DBI. On the machines where it failed, I have:
Ubuntu
Perl 5, version 22, subversion 1 (v5.22.1) built for x86_64-linux-gnu-thread-multi
DBI 1.634
DBD 4.033
gzip 1.6
However, on another two machines it did work. These had:
Ubuntu
Perl 5, version 26, subversion 1 (v5.26.1) built for x86_64-linux-gnu-thread-multi
DBI 1.640
DBD 4.033
gzip 1.6
And
Arch Linux
Perl 5, version 30, subversion 0 (v5.30.0) built for x86_64-linux-thread-multi
DBI 1.642
DBD 4.050
gzip 1.10
At least here, it appears that the MySQL libraries (probably) are masking (ignoring) SIGPIPE, and that's what you're seeing. Comparing strace outputs, I see a line like this in the MySQL run:
rt_sigaction(SIGPIPE, {sa_handler=SIG_IGN, sa_mask=[PIPE], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7f78bdf16840}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
And it turns out you can duplicate the behavior easily w/o MySQL:
$SIG{PIPE} = 'IGNORE';
open (my $fileHandle, "-|", "/bin/zcat $ARGV[0]");
my $ff = <$fileHandle>;
close($ff);
Or, alternatively, you can reset the signal to the default handler to make the message go away, even after connecting to MySQL by setting it to DEFAULT instead of IGNORE.
This is, by the way, documented behavior of the MySQL library:
To avoid aborting the program when a connection terminates, MySQL blocks SIGPIPE on the first call to mysql_library_init(), mysql_init(), or mysql_connect().
(It may also depend on the gzip version; maybe some versions of gzip set up signal handlers on init.)
Ultimately, what you're seeing is that if gzip gets a SIGPIPE, it just exits. If it gets an error back from write (because SIGPIPE is ignored), it prints an error message.
Most probably the following is happening:
gzip tries to write to the pipe, the program on your side is not reading up to eof, the closes the pipe. Gzip then receives a SIGPIPE, and dies with this error message. Can you confirm that this is taking place?

Symfony 4 framework session handler error

I'm using symfony 4, What does error stands for ?
Warning: SessionHandler::read(): open(/var/lib/php/sessions/sess_634q91mh896b6aa4jpjvlihmar, O_RDWR) failed: Permission denied (13)
When a user logs into a Symfony application, session information is stored on the web server. By default Symfony uses the native PHP session mechanism, storing session info in a file in /var/lib/php/sessions/ on Linux systems. Your error message is output by PHP and means it got a permissions error creating or re-opening a session file.
The error appears only intermittently because PHP removes old session files randomly about every 1/100th or 1/1000th page load. (On some Linux variants, old session files are removed by a cron job instead.)
https://symfony.com/doc/current/session.html says:
"some session expiration related options may not work as expected if other applications that write to the same directory have short max lifetime settings."
Try to avoid having multiple processes writing to the same sessions directory. I think I got the error message because both an Apache web server and php bin/console server:start were running at the same time. One process may have removed the other process's session file.
See PHP manual and Symfony manual for how to configure writing to separate directories. For example, I changed {Symfony directory}/config/packages/framework.yaml:
# Enables session support. Note that the session will ONLY be started if you read or write from it.
# Remove or comment this section to explicitly disable session support.
session:
# handler_id: ~
cookie_secure: auto
cookie_samesite: lax
handler_id: 'session.handler.native_file'
save_path: '%kernel.project_dir%/var/sessions/%kernel.environment%'
gc_probability: 100 # Run garbage collection always for
gc_divisor: 100 # investigating this problem only.
Another possibility is a problem in your Symfony code can cause the error message. The Symfony documentation says not to call the PHP session functions like session_start() directly since Symfony classes call them. A bug in my code caused an exception which I speculate caused the error message.
Related stack overflow questions: cleanup-php-session-files and how-does-php-know-when-to-delete-a-session
For those familiar with C code, see the PHP interpreter source code line that prints the error here
Hope this helps!
Not related to symfony 4, but you have to fix permissions in your /var/lib/php/sessions/ directory

How to connect to local MySQL Server 8.0 with DBIish in Perl6

I'm working on a Perl6 project, but having difficulty connecting to MySQL. Even when using the DBIish (or perl6.org tutorial) example code, the connection fails. Any suggestions or advice is appreciated! User credentials have been confirmed accurate too.
I'm running this on Windows 10 with MySQL Server 8.0 and standard Perl6 with Rakudo Star. I have tried modifying the connection string in numerous ways like :$password :password<> :password() etc. but can't get a connection established. Also should note that I have the ODBC, C, C++, and.Net connectors installed.
#!/usr/bin/perl6
use v6.c;
use lib 'lib';
use DBIish;
use Register::User;
# Windows support
%*ENV<DBIISH_MYSQL_LIB> = "C:/Program Files/MySQL/MySQL Server 8.0/liblibmysql.dll"
if $*DISTRO.is-win;
my $dbh = DBIish.connect('mysql', :host<localhost>, :port(3306), :database<dbNameHere>, :user<usernameHere>, :password<pwdIsHere>) or die "couldn't connect to database";
my $sth = $dbh.prepare(q:to/STATEMENT/);
SELECT *
FROM users
STATEMENT
$sth.execute();
my #rows = $sth.allrows();
for #rows { .print }
say #rows.elems;
$sth.finish;
$dbh.dispose;
This should be connecting to the DB. Then the app runs a query, followed by printing out each resulting row. What actually happens is the application hits the 'die' message every time.
This is more of a work around, but being unable to use use a DB is crippling. So even when trying to use the NativeLibs I couldn't get a connection via DBIish. Instead I have opted to using DB::MySQL which is proving to be quite helpful. With a few lines of code this module has your DB needs covered:
use DB::MySQL;
my $mysql = DB::MySQL.new(:database<databaseName>, :user<userName>, :password<passwordHere>);
my #users = $mysql.query('select * from users').arrays;
for #users { say "user #$_[0]: $_[1] $_[2]"; }
#Results would be:
#user #1: FirstName LastName
#user #2: FirstName LastName
#etc...
This will print out a line for each user formatted as shown above. It's not as familiar as DBIish, but this module gets the job done as needed. There's plenty more you can do with it to, so I highly recommend reading the docs.
According to this github DBIish issue 127
The environmental variable DBIISH_MYSQL_LIB was removed. I don't know if anyone brought it back.
However if you add the library's path, and the file is named mysql.dll, it will work. Not a good result for the scientific method.
So more testing is needed - and perhaps
C:\Program Files\MySQL\MySQL Server 8.0\lib>mklink mysql.dll .\libmysql.dll
Oviously you can create your own lib directory and add that to your path and then add this symlink to that directory.
Hope this helps. I've spent hours..
EDIT: Still spending time - accounting later.
Something very transitory is going on. I reset the machine (perhaps always do this from now on), and still got the missing mysql.dll errors. Tried going into the MySQL lib directory to execute raku from there.. worked. changed directories.. didn't work.
Launched administrator cmd - from home directory, tried the raku command. Worked. Ok - not good, but perhaps consistent. Launched non admin cmd, tried it from the MySQL lib directory, worked. And just for giggles, tried it outside of that directory.. worked.
Now I can't get it not to work. Will explore NativeLibs::Searcher as Valle Lukas suggested!
Maybe the example in the dbiish repository is not valid anymore.
The DBIISH_MYSQL_LIB Env seems to be replaced by NativeLibs::Searcher with commit 9bc4191
Looking at NativeLibs::Searcher may help to find the root cause of the problem.

redis.conf include: "Bad directive or wrong number of arguments"

I've created this config for redis [/etc/redis/map.conf]:
include /etc/redis/ideal.conf
port 11235
pidfile /var/run/redis-map.pid
logfile /var/log/redis/map.log
dbfilename map.rdb
As you can see, it includes /etc/redis/ideal.conf; this file actually exists and we have read permissions.
Also there is another file, slightly different; consider [/etc/redis/storage.conf]:
include /etc/redis/ideal.conf
pidfile /var/run/redis-storage.pid
port 8000
bind 192.168.0.3
logfile /var/log/redis/storage.log
dbfilename dump_storage.rdb
My problem is: I can launch redis-server with storage.conf (and everything works fine), but map.conf leads to the following error:
Reading the configuration file, at line 1
>>> 'include /etc/redis/ideal.conf'
Bad directive or wrong number of arguments
failed
Version of redis is 2.2.
Where did I go wrong?
Sorry guys.
I was using different instances of Redis.
Instance for storage.conf was launched by /usr/local/bin/redis-server, but map.conf launched by /usr/bin/redis-server; second one is broken.
Thank you anyway.

Is there a way to handle catch exception in MSI install wizard?

I am facing some odd situation that when I select/deselect the features in the feature customization wizard, it sometimes crashes the window. It does not give any clue at all. It also not happens consistently.
Do you have any idea or faced such kind of issue? I am able to even trace the root cause using install log.
You may be able to get closer to isolating the problem if you turn on the Debug policy. Do this by setting HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\Installer's Debug value to (dword) 7 in as described on the Windows Installer team blog. You will then need to use a tool like DebugView to view the extra output that Windows Installer will generate. Note you may have to restart the "msiserver" service for the policy to take effect. Best luck making sense of what it shows; often it's just a lot of SQL query dumps.
You can sometimes grab MSI exceptions from out of the event log, but they won't always tell you much.
Instead what you can do is turn on logging of the MSI, this can be done either via the registry, or via the command line. To find out about the registry option, visit this MS Support article. To do it from the command line you can use the same switches, but they obviously will only last for that one install. This is a snapshot as gathered from msiexec:
Logging Options
/l[i|w|e|a|r|u|c|m|o|p|v|x|+|!|*] <LogFile>
i - Status messages
w - Nonfatal warnings
e - All error messages
a - Start up of actions
r - Action-specific records
u - User requests
c - Initial UI parameters
m - Out-of-memory or fatal exit information
o - Out-of-disk-space messages
p - Terminal properties
v - Verbose output
x - Extra debugging information
+ - Append to existing log file
! - Flush each line to the log
* - Log all information, except for v and x options
/log <LogFile>
Equivalent of /l* <LogFile>
To take advantage of these options, use msiexec directly:
msiexec.exe [path to your msi] /l [your options]