CC: | Eric Promislow <ericp [...] ActiveState.com>, Kevin Goess <cpan [...] goess.org> |
Subject: | "panic: attempt to copy freed scalar" upon commit() or rollback() |
Date: | Sun, 15 Mar 2015 16:50:15 -0400 |
To: | bug-DBI [...] rt.cpan.org |
From: | Frédéric Brière <fbriere [...] fbriere.net> |
[ This bug was already filed as Perl bug #113644; my thanks to Eric
Promislow and Kevin Goess for figuring out what triggers it. Merely
knowing that I was not alone was of great help to my sanity. <g> ]
This bug manifests itself when calling commit() or rollback() in a
non-null context:
$ perl bug.pl
panic: attempt to copy freed scalar 903a878 to 905bfd0 at bug.pl line 52.
The problem is in XS_DBI_dispatch(), lines 3889-3895, when calling STORE
to set AutoCommit to 0 if the driver hasn't already done so. At this
point, the return values are already on the stack, and sp has already
been rewound, so they get overwritten when pushing the arguments to the
STORE method.
(At least, that's my understanding, as a complete XS newbie.)
From what I've gathered after some playtime with gdb, this usually goes
unnoticed, because in the process of call_method(), it just so happens
that the last value that was pushed at the bottom of the stack was
&PL_sv_yes, which was probably the original return value anyway. But in
different circumstances (running under the debugger in the RT ticket, or
subclassing DBI and overwriting STORE in my case), this may no longer be
the case. This is also specific to drivers which don't turn off
AutoCommit (e.g. mysql), leaving any other unharmed (e.g. sqlite).
In any case, I have had success with incrementing/decrementing sp by
outitems around this block, but I have no idea if this is the right
solution, given my lack of knowledge in the matter. I trust you will
know better. :)
If this can help, I'm attaching a simple script that triggers this bug.
However, since this requires a connection to a real MySQL server (which
seemed to be a hindrance according to the comments in the RT ticket),
I'm also attaching a stripped-to-the-bones hackish driver spanwed from
DBD::mysql (named DBD::nysql -- I was out of imagination) with only the
barest minimum needed to trigger the bug, with no outside requirements.
I trust you will be able to turn this mess into a proper test case. :)
--
# look for dup words
perl -0777 -ne 'print "$.: doubled $_\n" while /\b(\w+)\b\s+\b\1\b/gi'
Message body is not shown because sender requested not to inline it.
Message body not shown because it is not plain text.