Front page | perl.perl5.porters |
Postings from March 2016
Re: Putting Winsock errors into $^E
From: Steve Hay via perl5-porters
March 17, 2016 00:07
Re: Putting Winsock errors into $^E
Message ID: CADED=K5RSjwf8fDnPnpC-dOSD_+nnPfbbViE+bQaU4WQqo7UZw@mail.gmail.com
On 16 Mar 2016 22:56, "Laurent" <firstname.lastname@example.org> wrote:
> On Wed, Mar 16, 2016 at 2:37 PM, Steve Hay <email@example.com>
>> On 16 March 2016 at 17:23, Laurent <firstname.lastname@example.org> wrote:
>> > As a summary, what most disturbs me on the chosen solution it that $!
>> > holds POSIX values that are not semantically compatible with winsock
>> > I believe that as long as you think that broken code (Perl or XS)
>> > $! 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.
> There we disagree.
> Using a POSIX constant that has a defined semantic, for something else
that has a different semantic (the WSA one), is broken by design (even more
in a cross-platform language).
> This is not an opinion, this is a fact. That's part of my definition of
broken, if you wish.
> I disagree with your argument that because the code "works" (to some
extend) then it is not broken. Perl, for instance, has been broken for this
reason for years (assigning WSA* codes to E* constants), but "worked
fine"... until the namespace clash happened. And your solution is still
broken as it puts a WSA error into $! with a POSIX code.
> There are also example of code "working fine", eg: assuming that keys of
hashes were always sorted in the same order, that got "fixed" anyway (no
intent to debate more on this).
> It may happen that the semantic differences does not have a visible
effect in 95% of the cases; that is not enough to say that the code is not
> It is quite difficult to be sure that a code using POSIX constants for
winsocks is not broken. So the "safe" approach is to consider it is.
> For constants where you are 100% sure they are semantically compatible
(*WOULDBLOCK?), that could help backward compatibility (let broken code
still "work"), though with adding some confusion around which E constants
can or cannot be used.
>> 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.
> You are comparing breaking potentially broken code with breaking probably
non-broken code. That's not the same thing.
> The issue is that it seems there is much more potentially broken code
than probably non-broken one.
>> 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.
> My vision is that the objective is the least possible work, not safety,
nor robustness, both which are contradictory with allowing semantic twist.
> That's a sensible objective, I just wish it would not be the main one.
>> 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*
> When is it not wrong? That's certainly quite hard to tell... so hard that
one should rather assume this will not completely work as expected.
>> 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
>> (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...)
> The issue is that you place in $! a POSIX value which is not semantically
compatible with the winsock error.
> Any other option but this one would look more sensible to me, eg:
returning no error (ie, check $^E), or an error telling you that an
OS-level error occurred (ie: check $^E), or the WSA code.
> But requesting $!/E* comparison to still work prevents any of those.
> There is indeed a lot of confusion around winsock. But making it look
like unix sockets with POSIX error codes certainly does not help solve this
>> 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
> I don't believe it either, but that's of no importance.
> I believe that people will continue to confuse WSAE* and E*:
> - as Perl let them do this (as Perl actually does it itself in $!)
> - as Perl doc often does not define error codes, leaving users check the
system man pages instead (and by habit... one could directly go to man
pages in such cases).
> - because when porting Perl code to Windows, one can easily overlook the
problem as the broken $! comparison will possibly hide the issue.
> - as there will be many examples of broken code in the wild (including in
CPAN, given that modules have no strong reasons to fix their code).
The main issue here for me is that it's now trivial to write correct code,
using $^E, which was previously very difficult to do using $!.
The secondary issue is what, if anything, to put in $!. For now I've
decided to leave it untouched to avoid further backwards incompatible
changes to that on top of the changes that were made in 5.20. Code will
continue working (to a lesser or greater extent) exactly as it has done in
5.20 and 5.22, and if anyone stumbles into the problems that lurk there
then we now have an answer to them - switch to $^E instead.
However, I agree that what is left in $! right now is not ideal (obviously
-- if that wasn't the case then there would have been no reason to make the
$^E changes), and I think ultimately the best solution for it is one that
you mention above -- stop putting anything at all in $! for Winsock calls
-- but I still believe it would cause more trouble to pull the rug out from
under people's feet by doing that now.
I would prefer that change to go through a deprecation cycle: Document the
new $^E solution now and encourage people to switch to it, with a warning
that the old $! value will be removed in some specifued future release.
That way there are no further surprises suddenly forced on people now, and
they have a release or two in which to update their code.