Skip Menu |

This queue is for tickets about the Moose CPAN distribution.

Report information
The Basics
Id: 49722
Status: rejected
Priority: 0/
Queue: Moose

People
Owner: Nobody in particular
Requestors: zefram [...] fysh.org
Cc:
AdminCc:

Bug Information
Severity: (no value)
Broken in: (no value)
Fixed in: (no value)



Subject: Moose::Object DESTROY still needs to localise more
Date: Tue, 15 Sep 2009 21:17:20 +0100
To: bug-Moose [...] rt.cpan.org
From: Zefram <zefram [...] fysh.org>
Re bug #48271, I see that you're now explicitly localising $?, and Try::Tiny localises $@. Those are fine. But object destruction can still clobber $!, $^E, and $., and that's still a problem. Here's an example of how clobbering $! can lose: use warnings; use strict; { package TestObj; use Moose; sub DEMOLISH { open my $fh, "<", "/bar"; if($fh) { # hypothetically might do some I/O here } } } do { my $t = TestObj->new; mkdir("/foo") } or die "mkdir failed: $!\n"; Assuming you're not root, the mkdir will fail with EACCES (Permission denied). The die attempts to put this status into an exception message. Between the mkdir and the die, though, $t gets destroyed, and its attempt at I/O fails with ENOENT (No such file or directory). It clobbers $!, and the program ends up showing the wrong error message. This is a reasonable coding pattern, and for it to work the destructor needs to localise $! to avoid clobbering it. The localisation can either go in every individual DEMOLISH method that has a chance of clobbering it, or go in Moose::Object::DESTROY. I recommend that the framework should do it. The use case for $^E is identical, because it's an auxiliary OS error code and is set in the same situations as $!. It doesn't do anything on Unix, though, so it's a little harder to demonstrate. Also more likely to be forgotten if every DEMOLISH author is responsible for localising it. $. gets changed by I/O. More specifically, the aspect of $. that behaves as a local status indicator is not the value visible in it (which is actually persistent state of some filehandle) but *which* filehandle it points at. This gets changed whenever input is performed with a different filehandle. It could be clobbered by a destructor quite similar to the one in the example I gave above. The same issues apply as with $!, $?, and the rest, but $. is even more likely to be overlooked by individual destructor authors. -zefram
Subject: Re: [rt.cpan.org #49722] Moose::Object DESTROY still needs to localise more
Date: Thu, 17 Sep 2009 15:58:10 +0300
To: bug-Moose [...] rt.cpan.org
From: Yuval Kogman <nuffin [...] cpan.org>
We decided not to do that because $@ and to some extend $? are much more volatile in object destruction (due to stack unwinding and global destruction) but all other variables don't correlate with destruction at all. The reason we do localize these two values because destructors often called between the point in time when $@ is set and $@ is read, but this does not apply to $!, $^E, $. etc since they do not intrinsically correlate with control flow (and therefore garbage collection). Show quoted text
>        do { my $t = TestObj->new; mkdir("/foo") } >                or die "mkdir failed: $!\n";
The problem is that in this code $! is not collected soon enough. This is a flaw in Perl that Moose cannot solve. Liewise, if TestObj::DESTROY calls a system call and $! was actually meant to be collected later then that in turn will be broken since the value is lost irrecoverably. The correct fix here would be to wrap mkdir in something like autodie which would collect all the values of the error value from global storage into something else *immediately* after the system call, as no other way is correct. FWIW, Even that is flawed, since in many programs system calls might be made at arbitrary points in the program: $SIG{CHLD} = sub { ... } wait() might set $! then the value of $! could be clobbered anywhere and at any time. This is the same limitation that errno has in C. Destructors and localization cannot guarantee in any way that the people are collecting the value of $! when they should be. Even $@ and $? are questionable, and with the current behavior they may lose meaningful values. For instance: eval { die "foo" }; handle($@); sub Foo::DESTROY { die "blah" } my $obj = Foo->new(); undef $obj; or using RAII patterns to set $? at destruction in case resource cleanup did not go well. In both of these instances, which are perfectly valid, the user would have to override Moose::Object::DESTROY to provide something that is less defensive. As for $., localizing would be even worse because if a destructor and "normal code" both read from the same filehandle (intentionally), this causes skews instead of clobbered values, which are harder to detect. The real fix would be for Perl to localize these values implicitly like it does with the regexp capture variables, or of course to provide a facility other than program globals to access this information, but that's not really going to happen...
not a bug.