Why does Net::SFTP trigger my die handler when no errors?


U

usenet

Greetings. Kindly consider, if you please, this trivial sample script
which illustrates my question:

#!/usr/bin/perl
use warnings; use strict;
use Net::SFTP;

local $SIG{__DIE__} = sub {
print "Oh no - I'm dead!\n";
};

my ( $host, $user, $password, $local_file, $remote_file ) =
qw{ myhost myname mypasswrd junk.txt junk2.txt };

if (my $sftp = Net::SFTP->new($host, (user => $user,
password => $password,)
)
) {
$sftp -> put ($local_file, $remote_file)
|| warn $sftp->status();
}
print "I'm done - have a nice day.\n";

__END__

As you see, I have defined a custom "die" handler. For some reason,
when I run this script, I get three "die" messages from this handler,
even though the script successfully does the "put" and cleanly exits
with the polite message.

Why is Net::SFTP triggering my die handler when nothing seems to be
dying?

Thanks for any insights!
 
Ad

Advertisements

X

Xicheng

Greetings. Kindly consider, if you please, this trivial sample script
which illustrates my question:
#!/usr/bin/perl
use warnings; use strict;
use Net::SFTP;

local $SIG{__DIE__} = sub {
print "Oh no - I'm dead!\n";
};

my ( $host, $user, $password, $local_file, $remote_file ) =
qw{ myhost myname mypasswrd junk.txt junk2.txt };

if (my $sftp = Net::SFTP->new($host, (user => $user,
password => $password,)
)
) {
$sftp -> put ($local_file, $remote_file)
|| warn $sftp->status();
}
print "I'm done - have a nice day.\n";

__END__

As you see, I have defined a custom "die" handler. For some reason,
when I run this script, I get three "die" messages from this handler,
even though the script successfully does the "put" and cleanly exits
with the polite message.

Firstly, I knew nothing about this module, so my suggestions may be not
useful for you.

After I checked perldoc about this module, I guess you can take a look
at the following issues:

1) in the Net::SFTP->new(%host, %arg), there is a "warn" option in the
hash %arg, it shows:
warn: If given a sub ref, the sub is called with $self and any warning
message; if set to false, warnings are supressed; OTHERWISE they are
output with 'warn' (default).
so, you may get a default warning from this line if your failed in
creating a new instance.
Why is Net::SFTP triggering my die handler when nothing seems to be
dying?
2) $sftp->status
If a low-level protocol error or unexpected local error occurs, we DIE
with an error message.
so you may trigger your die handler here(just guess)

3) another error info may come directly from the "warn" clause..

IMHO, this module has embedded with independent error handling
mechanism so you dont have to do them all by yourself.

Good luck,
Xicheng
 
A

A. Sinan Unur

Greetings. Kindly consider, if you please, this trivial sample script
which illustrates my question:

#!/usr/bin/perl
use warnings; use strict;
use Net::SFTP;

local $SIG{__DIE__} = sub {
print "Oh no - I'm dead!\n";
};

my ( $host, $user, $password, $local_file, $remote_file ) =
qw{ myhost myname mypasswrd junk.txt junk2.txt };

if (my $sftp = Net::SFTP->new($host, (user => $user,
password => $password,)
)
) {
$sftp -> put ($local_file, $remote_file)
|| warn $sftp->status();
}
print "I'm done - have a nice day.\n";

__END__

Platform and Perl version?

I am on WinXP SP2 with perl 5.8.7 (815).
As you see, I have defined a custom "die" handler. For some reason,
when I run this script, I get three "die" messages from this handler,
even though the script successfully does the "put" and cleanly exits
with the polite message.

You are lucky then. With debugging turned on, I get:

D:\Home\asu1\UseNet\clpmisc> sftp.pl
Aardvark: Reading configuration data D:/Home/asu1/.ssh/config
Aardvark: Reading configuration data /etc/ssh_config
Oh no - I'm dead!
Aardvark: Connecting to xxx.example.com, port 22.
Aardvark: Remote protocol version 2.0, remote software version OpenSSH_3.8.1p1 FreeBSD-20040419
Oh no - I'm dead!
Oh no - I'm dead!
Oh no - I'm dead!
Oh no - I'm dead!
Oh no - I'm dead!
Oh no - I'm dead!
Aardvark: Net::SSH::perl Version 1.29, protocol version 2.0.
Aardvark: No compat match: OpenSSH_3.8.1p1 FreeBSD-20040419.
Oh no - I'm dead!
Can't set socket non-blocking: Bad file descriptor at C:/opt/Perl/site/lib/Net/SSH/Perl.pm line 212 said:
Why is Net::SFTP triggering my die handler when nothing seems to be
dying?

Thanks for any insights!

I tried single-stepping through the code (now, that's tedious).

Math::BigInt::CODE(0x281dd10)((eval 14)[C:/opt/Perl/lib/Math/BigInt.pm:2435]:1):

1: use Math::BigInt::GMP qw/Math::BigInt::GMP Pari FastCalc Calc/;
DB<1> s
main::CODE(0x182e1cc)(sftp.pl:6): print "Oh no - I'm dead!\n";
DB<1> s
Oh no - I'm dead!
main::CODE(0x182e1cc)(sftp.pl:6): print "Oh no - I'm dead!\n";
DB<1> s
Oh no - I'm dead!

....

Math::BigInt::CODE(0x28124b4)((eval 15)[C:/opt/Perl/lib/Math/BigInt.pm:2435]:1):

1: use Math::BigInt::pari qw/Math::BigInt::GMP Math::BigInt::pari FastCalc
Calc/;
DB<1> s
main::CODE(0x182e1cc)(sftp.pl:6): print "Oh no - I'm dead!\n";
DB<1> s
Oh no - I'm dead!
main::CODE(0x182e1cc)(sftp.pl:6): print "Oh no - I'm dead!\n";
DB<1> T
$ = main::__ANON__[sftp.pl:7]('Can\'t locate Math/BigInt/Pari.pm in @INC (@INC c
ontains: C:/opt/Perl/lib C:/opt/Perl/site/lib .) at (eval 15)[C:/opt/Perl/lib/Ma
th/BigInt.pm:2435] line 1, <GEN0> line 1.^JBEGIN failed--compilation aborted at
(eval 15)[C:/opt/Perl/lib/Math/BigInt.pm:2435] line 1, <GEN0> line 1.^J') called
from file `(eval 15)[C:/opt/Perl/lib/Math/BigInt.pm:2435]' line 1

Hmmm ... I had thought I all that was installed when I installed
Net::SFTP via ppm.

I installed Math::BigInt::GMP and Math::BigInt::Fast via ppm,
Math::BigInt::pari using Makefile.PL, and run into problems compiling
Math::BigInt::FastCalc (in case anyone knows what the to do, the
problem is "unresolved external symbol __ftol2"). Anyway, installing
what I was able to install reduced the number of "I'm dead" messages:

D:\Home\asu1\UseNet\clpmisc> sftp.pl
Oh no - I'm dead!
Oh no - I'm dead!
Can't set socket non-blocking: Bad file descriptor at C:/opt/Perl/site/lib/Net/S
SH/Perl.pm line 212, <GEN0> line 1.

I give up for now.

Sinan
 
A

A. Sinan Unur

problems compiling Math::BigInt::FastCalc (in case anyone knows
what the to do, the problem is "unresolved external symbol __ftol2").

If anyone is interested, adding /QIfist to CCFLAGS allowed me to compile
the module, and the module passed all the tests.

The script still emits "I'm dead" twice though.

Single-stepping reveals:

Net::SSH::perl::_current_user(C:/opt/Perl/site/lib/Net/SSH/Perl.pm:99):
99: eval { $user = scalar getpwuid $> };
DB<3> s
main::CODE(0x182e1cc)(sftp.pl:6): print "Oh no - I'm dead!\n";
DB<3> s
Oh no - I'm dead!

and then (after a lot of stepping):

Net::SSH::perl::_connect(C:/opt/Perl/site/lib/Net/SSH/Perl.pm:212):
212: defined($sock->blocking(0))
213: or die "Can't set socket non-blocking: $!";
DB<17> s
main::CODE(0x182e1cc)(sftp.pl:6): print "Oh no - I'm dead!\n";
DB<17> s
Oh no - I'm dead!
Can't set socket non-blocking: Bad file descriptor at
C:/opt/Perl/site/lib/Net/SSH/Perl.pm line 212, <GEN0> line 1.

Hmmmmm ...

Sinan
 
A

A. Sinan Unur

Net::SSH::perl::_connect(C:/opt/Perl/site/lib/Net/SSH/Perl.pm:212):
212: defined($sock->blocking(0))
213: or die "Can't set socket non-blocking: $!";
DB<17> s
main::CODE(0x182e1cc)(sftp.pl:6): print "Oh no - I'm dead!\n";
DB<17> s
Oh no - I'm dead!
Can't set socket non-blocking: Bad file descriptor at
C:/opt/Perl/site/lib/Net/SSH/Perl.pm line 212, <GEN0> line 1.

OK. I am now positively talking to myself.

This is listed as "resolved" at
http://rt.cpan.org/Public/Bug/Display.html?id=17127

Anyone know what the resolution is?

Sinan
 
X

xhoster

Greetings. Kindly consider, if you please, this trivial sample script
which illustrates my question:

#!/usr/bin/perl
use warnings; use strict;
use Net::SFTP;

local $SIG{__DIE__} = sub {
print "Oh no - I'm dead!\n";
};

I think it would be nice, at least for debugging purposes, if you had your
sub print out the error message it was called with. Then you would know
what it was.

....
As you see, I have defined a custom "die" handler. For some reason,
when I run this script, I get three "die" messages from this handler,
even though the script successfully does the "put" and cleanly exits
with the polite message.

Why is Net::SFTP triggering my die handler when nothing seems to be
dying?

You should ask Perl that, not us!

However, from perldoc perlvar:

Due to an implementation glitch, the $SIG{__DIE__} hook is
called even inside an eval(). Do not use this to rewrite a
pending exception in [email protected], or as a bizarre substitute for
over- riding CORE::GLOBAL::die(). This strange action at a
distance may be fixed in a future release so that
$SIG{__DIE__} is only called if your program is about to
exit, as was the original intent. Any other use is
deprecated.

So it would be my guess that Net::SFTP is dying from inside an eval, as
part of its normal course of business, and you are intercepting those dies.

But this lead me to ask a broader question. What are you trying to do, and
why are you using a SIG die handler, rather than eval{}, to do whatever it
is you are tyring to do?

Xho
 
Ad

Advertisements

A

A. Sinan Unur

I think it would be nice, at least for debugging purposes, if you had
your sub print out the error message it was called with. Then you
would know what it was.

Yeah ... I did it the long hard way ... It was dying in a bunch of
evals.
However, from perldoc perlvar:

Due to an implementation glitch, the $SIG{__DIE__} hook
is called even inside an eval(). Do not use this to
rewrite a pending exception in [email protected], or as a bizarre
substitute for over- riding CORE::GLOBAL::die(). This
strange action at a distance may be fixed in a future
release so that $SIG{__DIE__} is only called if your
program is about to exit, as was the original intent.
Any other use is deprecated.

Oooops ... I missed that and I wasted a lot of time.
So it would be my guess that Net::SFTP is dying from inside an eval,

That is true. In wasting my time on this, I realized that David's script
does not actually work on my machine because Net::SSH::perl dies:
Net::SSH::perl::_connect(C:/opt/Perl/site/lib/Net/SSH/Perl.pm:212):
212: defined($sock->blocking(0))
213: or die "Can't set socket non-blocking: $!";
DB<17> s
main::CODE(0x182e1cc)(sftp.pl:6): print "Oh no - I'm dead!\n";
DB<17> s
Oh no - I'm dead!
Can't set socket non-blocking: Bad file descriptor at
C:/opt/Perl/site/lib/Net/SSH/Perl.pm line 212, <GEN0> line 1.

This is listed as a resolved bug at
http://rt.cpan.org/Public/Bug/Display.html?id=17127

I hate to repeat myself, but I am kind of puzzled. I don't need SFTP
anytime soon, but does anyone know what the resolution is?

Sinan
 
U

usenet

I think it would be nice, at least for debugging purposes, if you had your
sub print out the error message it was called with. Then you would know
what it was.

Do you mean $! ? I wasn't sure $! would be reliable here. I actually
included $! as I was trying to figure out what was going on, and I got
a bunch of (seemingly) meaningless messages.
However, from perldoc perlvar:
<snip perldoc>
So it would be my guess that Net::SFTP is dying from inside an eval, as
part of its normal course of business, and you are intercepting those dies.

I'm glad you were able to translate that perldoc statement (which I
struggle to understand, with little success) into something that makes
sense! Thanks!
But this lead me to ask a broader question. What are you trying to do, and
why are you using a SIG die handler, rather than eval{}, to do whatever it
is you are tyring to do?
The die handler is designed to catch my own die() calls. I die within
my script under various dire circumstances, but I want to do some
housecleaning before I really leave (dispatching final logging methods,
closing databases cleanly, etc), so I use the handler. Maybe that's not
the best way to do it...

I didn't anticipate catching any die()s from Net::SFTP because the docs
for the module claim it die()s only in under fairly restrictive (and
unlikely) conditions. Your speculation about the module die()'ng inside
evals sounds plausable, and will make me re-think my exit strategy for
exception handling.

Thanks, Xho (and thanks, Sinan, for your amazing efforts to help also,
which were apparently thwarted by what seems to be a bug in Net::SSH on
Windows - but I'm a UN*X weenie).
 
Ad

Advertisements

X

xhoster

Do you mean $! ? I wasn't sure $! would be reliable here. I actually
included $! as I was trying to figure out what was going on, and I got
a bunch of (seemingly) meaningless messages.

Mind you, I've never actually used SIG die handlers, so this is based on
the doc, not from experience, But I think what you should print would be
$_[0].

The routine indicated by $SIG{__DIE__} is called when a
fatal exception is about to be thrown. The error message is
passed as the first argument.



For example:
$ perl -le 'local $SIG{__DIE__}=sub {warn qq{Intercepted "$_[0]"}}; \
eval {die "foo"} '

results in:

Intercepted "foo at -e line 2.
" at -e line 1.

(OK, so now I guess I have actually used SIG die handlers, so disclaim my
disclaimer.)
I'm glad you were able to translate that perldoc statement (which I
struggle to understand, with little success) into something that makes
sense! Thanks!

You're welcome.
The die handler is designed to catch my own die() calls. I die within
my script under various dire circumstances, but I want to do some
housecleaning before I really leave (dispatching final logging methods,
closing databases cleanly, etc),

I think dispatching final logging methods should probably happen in an END
block, or perhaps should be automatically triggered when the logging object
goes out of scope and is destroyed (which happens even if you are exiting
via die).

For closing databases cleanly, it is not clear to me that one can generally
do a better job at handling that than the code already built into DBI does,
which is triggered when an open db handle goes out of scope or is
destroyed, for example during clean up after a uncaught "die". There are
exceptions to every generalization and YMMV, of course.

so I use the handler. Maybe that's not
the best way to do it...

I think that:

{
local $SIG{__DIE__} = sub { do_something_with_error($_[0]) };
## rest of code in block;
};

Should usually be functionally equivalent to:

eval {
## rest of code in block;
};
if ([email protected]) { do_something_with_error([email protected]); die [email protected] };

Except the latter doesn't intercept other peoples dies if those dies are in
evals of their own, while the former does. (One potential problem is that
the handler can be a closure upon lexicals in the block, while the if after
the eval can not.)


Xho
 

Top