-
Notifications
You must be signed in to change notification settings - Fork 8
Description
The pod documentation mentions lastFileError() reacting to FdGetOsFHandle(),
and File.xs indeed has code to save GetLastError() in that case. I tried
that as a workaround for issue #13. However, _get_osfhandle() does not
document GetLastError() being meaningful. Indeed, my experiments show that a
failing _get_osfhandle() can make GetLastError() return zero, among other
values. Test program:
use strict;
use warnings;
use Test::More;
use Win32API::File();
#use Socket; # changes the error codes further
my $improbable_error_code = 15614; # ERROR_PACKAGE_REPOSITORY_CORRUPTED
my($before, $after);
close STDIN;
for my $winsock_active (0, 1) {
require Socket if $winsock_active;
# fd 0 is closed but below the highest open fd
# fd 100000 is closed and above the highest open fd
# fd 1 is open
for my $fd (0, 100000, 1) {
Win32API::File::fileLastError($improbable_error_code);
$before = 0+Win32API::File::fileLastError();
Win32API::File::FdGetOsFHandle($fd);
$after = 0+Win32API::File::fileLastError();
is($after, $before, "winsock=$winsock_active fd=$fd");
}
}Output:
not ok 1 - winsock=0 fd=0
# Failed test 'winsock=0 fd=0'
# at //tsclient/remote/demo_closed.pl line 21.
# got: '6'
# expected: '15614'
not ok 2 - winsock=0 fd=100000
# Failed test 'winsock=0 fd=100000'
# at //tsclient/remote/demo_closed.pl line 21.
# got: '203'
# expected: '15614'
ok 3 - winsock=0 fd=1
not ok 4 - winsock=1 fd=0
# Failed test 'winsock=1 fd=0'
# at //tsclient/remote/demo_closed.pl line 21.
# got: '0'
# expected: '15614'
not ok 5 - winsock=1 fd=100000
# Failed test 'winsock=1 fd=100000'
# at //tsclient/remote/demo_closed.pl line 21.
# got: '203'
# expected: '15614'
ok 6 - winsock=1 fd=1
# Tests were run but no plan was declared and done_testing() was not seen.
I see the following ways of detecting FdGetOsFHandle() failure today, given
the need to work around issue #13 and $SUBJECT:
-
Test whether Perl is 32-bit. If 32-bit, compare the return value to
0xffffffff. Otherwise, compare the return value to0xffffffffffffffff.
No known disadvantages. -
Use a sequence like:
fileLastError($improbable_error_code); FdGetOsFHandle(...); if ($improbable_error_code == fileLastError()) { # succeeded ...
In practice, I expect _get_osfhandle() can set just a few of the thousands
of error codes, making all others viable as $improbable_error_code. Having
said that, it's infeasible to prove that GetLastError() will never report
$improbable_error_code after _get_osfhandle(). -
Test
$!==9(EBADF). _get_osfhandle() documents this, and I have observed
it to work. The risk would be FdGetOsFHandle() somehow making an
additional library call that clobberserrno. That risk feels significant.
I will likely use (1) for the moment.