I actually work with bayruds, and we were sharing this code
snippet, but I'm having a slightly different problem with
this. The deep recursion is only showing up in Perl-5.8.0.
Previous versions do not have this problem.
Secondly, we're using the Filter::Handle module to split
STDERR to both a logfile and to the terminal. For
this I have been using (until switching to Perl-5.8.0) the
following code snippet:
use Filter::Handle qw/subs/;
## $LOG_FH is a FileHandle reference...
Filter \*STDERR,
sub { local $_ = @_;
if (defined $LOG_FH) {print $LOG_FH "STDERR: $_";}
$_
};
## Need a signal handler to capture warnings from carp
## and warn which are not captured by Filter::Handle
## (but by capturing ourselves and printing to STDERR,
## they do get picked up by Filter::Handle)...
$SIG{__WARN__} = sub
{ local $_ = "@_";
print STDERR $_;
};
I don't want to just tie STDERR to the $LOG_FH filehandle,
I want to print to both STDERR and the filehandle.
Beginning with Perl-5.8.0, any output to STDERR, either
explicitly or from Perl (e.g. uninitialized variable) results
in a deep recursion error.
Any thoughts about this?? Why is this happening only in Perl-5.8.0?
thanks,
-Cadphile
| [reply] [d/l] |
Okay. Here's what I think is going on, based upon my observations and some reading. I say what comes next with a great deal of trepidation because not only is the author of Filter::Handle well respected, but in the bottom of the pod for the module he thanks no less a list of PM luminaries as tilly, chromatic and merlyn!
There seems to be a fundemental design flaw in Filter::Handle.
What the module does is to tie the handle supplied (through whichever of its 3 interfaces) to itself. Then, whenever print or printf is called on the tied handle, the tie magic ensures that the PRINT or PRINTF routines within then module get called. It then calls the sub you pass in when you intialise the filtering, and passing you the arguments that would have been passed to print or printf and gives you the opportunity to modify them before returning them. It then calls print or printf on the tie'd handle passing the modified arguments.
The problem is, that the handle it is using is the same one as you did, which is still tied, and so it recursively calls itself and then calls you and then calls print or printf on the same tied handle which means it recurses into itself again....ad nauseum.
I cannot explain why this didn't happen in 5.6. By my logic, it should, but if it had, then the module would never have made it onto CPAN as is.
At first, I thought that this was to do with you $SIG{__WARN__} handler. I remembered from the perl58delta that as of 5,8, signals were now "safe", and to quote the docs,
Perl used to be fragile in that signals arriving at inopportune moment
+s could corrupt Perl's internal state. Now Perl postpones handling of
+ signals until it's safe (between opcodes).
This change may have surprising side effects because signals no longer
+ interrupt Perl instantly. Perl will now first finish whatever it was
+ doing, like finishing an internal operation (like sort()) or an exte
+rnal operation (like an I/O operation), and only then look at any arr
+ived signals (and before starting the next operation)
but this was a red-herring easily dismissed by removing the WARN handler. The recursion still occurs under 5.8.
However, there were also some fairly extensive changes made to the IO in 5.8, not least of which was the move to PerlIO by default.
My gut feeling is that Filter::Handle only worked in 5.6 because of a bug that has either been fixed or bypassed in the move to 5.8. I don;t like drawing the conclusion because I can't think of any easy way to prove it. Perhaps if someone has a build of 5.6(.1) that was built with PerlIO, they could try it and see if that also goes into recursion. My best 'evidence' for my conclusion is just the logic of the thing.
If I tie a handle, and intercept prints to that handle, and then invoke print on that same handle from within the PRINT handler itself, how could I NOT end up recursing back into myself?
Nothing has changed between the call to print on the tied handle and when I call print on that same tied handle from within the handler. Unless perl has some additional magic to temporarially untie a tied handle whilst in the handler?
Of course, this doesn't explain why it doesn't go into recursion under 5.6...but my only explaination for that is a bug in 5.6 that allowed it to 'work'!
Sorry I cannot suggest an immediate workaround for your problem.
BrowserUk currently sitting here feeling the presence of the Sword of Damocles hanging above me:)
Examine what is said, not who speaks.
"Efficiency is intelligent laziness." -David Dunham
"When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller
| [reply] [d/l] |