develooper Front page | perl.perl5.porters | Postings from March 2016

Re: Putting Winsock errors into $^E

Thread Previous | Thread Next
From:
Steve Hay via perl5-porters
Date:
March 16, 2016 18:37
Subject:
Re: Putting Winsock errors into $^E
Message ID:
CADED=K5zN+7bwOWn0Ejd9XkC4vOcox_9ZdWg-JVyRCcvP80GDQ@mail.gmail.com
On 16 March 2016 at 17:23, Laurent <laurent.aml@gmail.com> wrote:
> Hi,
>
> I'd like to present a little bit different perspective of the situation than
> presented here.
>
> On Wed, Feb 17, 2016 at 3:59 AM, Steve Hay via perl5-porters
> <perl5-porters@perl.org> wrote:
>>
>> Nearly a year ago there was some discussion about the way in which
>> perl handles errors from socket functions on Windows:
>>
>> http://nntp.perl.org/group/perl.perl5.porters/226581
>> http://nntp.perl.org/group/perl.perl5.porters/226793
>> http://nntp.perl.org/group/perl.perl5.porters/226604
>>
>>
>>
>> There were two main issues:
>>
>> One was some minor breakage caused by checking for a hard-coded
>> Winsock error code (10035) instead of a POSIX error constant
>> (EWOULDBLOCK) which they are mapped to.
>>
>> The values placed in $!
>> changed in 5.20.0 to incorporate the same mapping of WSAE* values to
>> E* that had long been in effect since 5.8 in Errno.pm and 5.12 in
>> POSIX.pm. This was done to avert some problems caused by the addition
>> of new POSIX error constants in the errno.h of VC10+ and recent gccs.
>> The danger of breakage for anyone using hard-coded error codes was
>> documented in 5.20.0's perldelta:
>>
>>
>> http://perldoc.perl.org/perl5200delta.html#Assignments-of-Windows-sockets-error-codes-to-%24!-now-prefer-_errno.h_-values-over-WSAGetLastError%28%29-values
>
>
> That's a twisted way to present things.
> Checking for Winsock error codes was legitimate (as long as Perl had been
> returning WSA* codes for socket calls).
> The fact that hardcoded values where used instead of Perl's E* codes made
> also prefect sense when considering portability and/or the inadequation of
> the E* code semantics on Windows.
>
> The cause of the breakage is that p5p decided to affect POSIX codes to $!
> instead of the WSA one for winsock calls.
>
>>
>> The second, more significant, issue is the fact that this old mapping,
>> despite many other languages apparently having similar code in them
>> (e.g. similar code was found in each of Python, Ruby, Tcl and PHP), is
>> not good because some similarly-named constants do not have compatible
>> meanings (e.g. EINPROGRESS indicates that a non-blocking connection
>> could not be immediately established and will instead be established
>> asynchronously, whereas WSAEINPROGRESS indicates that a blocking
>> operation (which Winsock only allows a single one of per-task or
>> thread) is currently executing. In fact, WSAEWOULDBLOCK matches
>> EINPROGRESS far better than WSAEINPROGRESS does).
>
>
> Other languages were broken, many other libs and programs are/were certainly
> equally broken. I don't think there is a point to be made here.
> But it is interesting to note that some Perl libs were not, were correctly
> dealing with the situation, and got broken due to the breakage above.
> In the meantime, broken code stayed broken (using E* constants instead of
> WSAE* constants/values).
>
> The issue is the namespace clash between Perl (when E* = WSAE*) and M$ (who
> decides to defined related E* in a different way), especially in XS modules.
> I believe (just a guess), that resolving the namespace conflict in CPAN and
> XS modules (eg, by replacing E* with appropriate WSAE* constants for winsock
> related errors) is considered a too huge job.
>
>>
>> The most robust solution that was put forward (myself, Leon and Sinan
>> all suggested it) to solve the various issues with defining/exporting
>> error constants and mapping/setting error codes in $! was to simply
>> forget about $! and POSIX error codes for Winsock functions, and
>> instead just set the Winsock error code directly into $^E.
>
>
> That's an opinion. I believe this solution is rather motivated by looking
> for the least work it would involve, and more precisely by trying to avoid
> having to fix broken code using POSIX codes instead of WSA* ones.
>
>>
>> I therefore propose to leave the whole $! thing as it is now, put the
>> Winsock error codes into $^E after each Winsock function call, export
>> the WSAE* error constants from Errno.pm and POSIX.pm for checking
>> those error codes against and henceforth encourage people to test $^E
>> (against WSAE* constants) rather than $! (against E* constants) on
>> Windows from 5.24.0 onwards.
>
>
> I still consider this a not so good solution because:
> - it still breaks compatibility with correct code and older perls
> - $! continues to hold E* posix codes that are misleading for winsock
> - CPAN/XS/... code using E* instead of WSAE* one is still broken. And
> nothing prevents new code to fall in this trap again.
> Basically, making correct portable code, between platforms and perl
> versions, gets harder than ever for sockets.
>
> What I would consider "correct" would be:
> - let E* codes be POSIX (we agree on that), to solve the namespace clash.
> - let $! return the correct codes (WSA*) for winsock calls, at least when E*
> POSIX semantic is not 100% compatible.
>   - that does not break compatibility with "correct" code (not using POSIX
> error codes with a non-POSIX semantic).
>   - that prevents comparison with POSIX codes to inadvertently get true (so
> non-Windows code paths are not triggered inadvertently on Windows).
>
> This is also backward compatible with older Perl versions, once broken code
> get fixed regarding the namespace clash (using WSAE* codes where appropriate
> instead of POSIX ones).
> Obviously, the downside of this approach is that broken code (that happened
> to work in most cases) gets really broken (and will certainly not work in
> most cases anymore). Looking at this in a more positive way, I would say
> that the broken code would not be hidden anymore, which would force it to be
> fixed once and for all.
> Another potential issue is that there can be at some point a clash between
> WSA IDs and POSIX ones.
>
> On a side note, I hope POSIX.pm will not export WSA* codes which are,
> well... not POSIX.
>
>>
>> I have made the necessary code changes in the top three commits on this
>> branch:
>>
>>
>> http://perl5.git.perl.org/perl.git/shortlog/refs/heads/smoke-me/steveh/oserror
>>
>> This works for me, and has smoked as cleanly as seems to be normal:
>>
>> http://perl.develop-help.com/?b=smoke-me/steveh/oserror
>>
>> I would like to commit this before the "user-visible changes freeze"
>> on 20th, and will do so if no objections are raised. I will, of
>> course, add some appropriate documentation (in perldelta and
>> elsewhere) too.
>
>
> As a summary, what most disturbs me on the chosen solution it that $! still
> holds POSIX values that are not semantically compatible with winsock errors.
> I believe that as long as you think that broken code (Perl or XS) checking
> $! against E* for winsock should not be impacted by your fix, this
> discussion will not progress.
>

I do indeed believe that code checking $! against E* for Winsock
should not be impacted. The change that was made in 5.20 was careful
to update the values put into $! *and* the values of the E* constants
exported from Errno and POSIX so that they remained in sync because we
believed that most people checked $! against E*, and it remains the
case that I would not want to impact that.

It's clear now that in some cases people quite legitimately don't do
that (due to the non-equivalence of like-named E* and WSAE*
constants), but it's still surely true that there is a lot of code
that does test $! against E* and is working fine since many like-named
E* and WSAE* constants are equivalent. I think it's wrong to say that
all such code is "broken", just as we were wrong when making changes
in 5.20 to believe that code checking $! against hard-coded numbers
was "broken" and should simply be "fixed" to use E* constants instead.

So I believe that any change that causes code testing $! against E* to
break would be bad, in exactly the same way as the change in 5.20
breaking comparisons of $! against hard-coded numbers turned out to be
bad. In fact, I think it would cause even more backwards-compatibility
breakage because probably more code would be affected.

This is why I believe that the safest solution, avoiding any more
backwards-compatibility breakage in existing code, is to start afresh,
with the unadulterated Winsock error value placed in a new location
($^E) and a set of WSAE* constants made available for testing against.

We now have POSIX values that match E* constants placed in $! (albeit
with a warning that I have promised to add to the documentation in
relevant places that the mapping of Winsock values to those POSIX
values is wrong in some cases), and Winsock values that match WSAE*
constants placed in $^E. I think that is quite a sensible state of
affairs, given that $! is normally a representation of the
(cross-platform) C "errno" variable and $^E is an OS-specific error
variable.

(I've written before that I think part of the confusion in where to
put Winsock error codes arises because Winsock functions like
accept(), connect() and select() correspond to functions available on
other OSes, and so, since they are not OS-specific, you might expect
E*-based error codes in $! (exactly as you have for CRT functions,
even on Windows), and yet (unlike MS CRT functions) these Winsock
functions do not actually set the C "errno" variable which $! is
intended to correspond to...)

Code that continues to test $! against E* will continue to work
exactly as it always has done. In some cases, such tests never did
work and people had to test $! against hard-coded numbers instead. We
broke that in 5.20, not realizing that such uses of hard-coded numbers
was necessary. I'm sorry about that but I don't think that another
round of backwards-compatibility-breaking changes here would be a good
thing or would make things any better.

So instead, I'm proposing that in future people should switch code
testing $! against E* over to testing $^E against WSAE* on Windows. I
don't believe that is any harder for people to do than switching over
to testing $! against hard-coded numbers (or exported WSAE* constants)
on Windows, which is what you're proposing, if I have understood
correctly.

Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About