Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation
 
PerlMonks  

errno in XS not propagating to $! - breaks Net::SSLeay

by nobull (Friar)
on Feb 14, 2008 at 16:32 UTC ( [id://667963]=perlquestion: print w/replies, xml ) Need Help??

nobull has asked for the wisdom of the Perl Monks concerning the following question:

I'm trying to install Net::SSLeay.

It is failing to test correctly and I've traced the problem to the following.

sub AUTOLOAD { # This AUTOLOAD is used to 'autoload' constants from the constant( +) # XS function. If a constant is not found then control is passed # to the AUTOLOAD in AutoLoader. my $constname; ($constname = $AUTOLOAD) =~ s/.*:://; my $val = constant($constname); if ($! != 0) { if ($! =~ /((Invalid)|(not valid))/i || $!{EINVAL}) { $AutoLoader::AUTOLOAD = $AUTOLOAD; goto &AutoLoader::AUTOLOAD; } else { croak "Your vendor has not defined SSLeay macro $constname"; } } eval "sub $AUTOLOAD { $val }"; goto &$AUTOLOAD; }
Where constant is defined in C as
static double constant(char* name) { errno = 0; switch (*name) { case 'A': if (strEQ(name, "AT_MD5_WITH_RSA_ENCRYPTION")) #ifdef SSL_AT_MD5_WITH_RSA_ENCRYPTION return SSL_AT_MD5_WITH_RSA_ENCRYPTION; #else goto not_there; #endif break; /* Snip similar for B..Z */ case '_': if (strEQ(name, "_TEST_INVALID_CONSTANT")) goto not_there; } errno = EINVAL; return 0; not_there: errno = ENOENT; return 0; }

The problem is that setting errno within the XS code is not propagated to the Perl $! variable.

The build process does keep warning me...

*** Be sure to use the same compiler and options to compile your OpenSSL, perl, and Net::SSLeay. Mixing and matching compilers is not supported.

I guess I shouldn't have ignored that warning. Or rather I shouldn't have thought it meant I should mix GCC v Microsoft v Intel compilers.

My Perl build is a binary from ActiveState, v5.8.8 MSWin32-x86-multi-thread build 820. This was built using the Microsoft compiler. My compiler is Microsoft 32-bit C/C++ Optimizing Compiler Version 13.10.3077 for 80x86. I'm guessing these are sufficiently "different" that the errno symbol ends up bound to different variables in auto/Net/SSLeay.dll from it is in perl58.dll. My OpenSSL is a binary download from somewhere.

I've noticed that a lot of people (not just Perl users) seem to use Windows, and many of them download programs/libraries as compiled binaries rather than source. (Indeed I've even noticed that Windows doesn't install the C compiler be default). So how do people get away with such reckless behaviour if Microsoft's compilers are so grossly incompatible between versions?

I've hacked the code of Net::SSLeay so that it doesn't attempt to pass information from the XS code to the Perl via errno and if I get it working I may submit a patch but I can't help wondering if I'm doing the wrong thing.

Replies are listed 'Best First'.
Re: errno in XS not propagating to $! - breaks Net::SSLeay (misblamed)
by tye (Sage) on Feb 14, 2008 at 18:09 UTC

    I recall a change quite a while ago to save-and-restore the value of errno around XS calls, presumably to reduce the noise of XS calls changing the value of $!, presumably unintentionally.

    But despite Net::SSLeay's pretty poor pass/fail ratio on CPAN of late, it does pass tests sometimes. That throws into question my recollection of this feature. Or perhaps it is the case that fairly rarely $! is 0 by luck and the test passes. Or perhaps this feature was only added on some platforms (and Net::SSLeay fails tests on other platforms for other reasons, of course).

    But I certainly don't think your jumping to the conclusion of blaming compiler differences is warranted. I would not expect compiler differences to break linking of the errno global (if linking together global symbols didn't work, then you'd have a ton more problems than errno). And I wouldn't expect compiler difference to cause a change in how Perl deals with errno in some other way, though I'm less certain of that.

    Update: Re^2: errno in XS not propagating to $! - breaks Net::SSLeay describes how there being two different errno globals can actually happen here.

    My next step would be to search for code related to XS handling that sets errno.

    - tye        

Re: errno in XS not propagating to $! - breaks Net::SSLeay
by almut (Canon) on Feb 14, 2008 at 19:44 UTC

    I don't have anything resembling a solution, but I dimly remember having digged around in the same piece of code, while trying to come up with an explanation for another somewhat related problem  (though that was Net::SSLeay in combination with PAR::Packer — so read down a bit in the thread).  Unfortunately, as far as I can tell, the problem never got resolved... but maybe you'll find some additional pieces for the puzzle (if you haven't come across that thread already).  At least, it seems to confirm that - under some circumstances - something strange is happening with the errno values...  Good luck anyway!

Re: errno in XS not propagating to $! - breaks Net::SSLeay
by cdarke (Prior) on Feb 14, 2008 at 17:59 UTC
    Be careful of hacking the code, but a work-around might be, in the C:
    SetLastError(ERROR_FILE_NOT_FOUND); instead of <code>errono=ENOENT; SetLastError(ERROR_INVALID_DATA); instead of <code>errno=EINVAL;
    Be sure to #include <windows.h> and the error code will be available through $^E. Maybe that's what you did? Personally I stay away from the C RTL error handling in Windows XS.
Re: errno in XS not propagating to $! - breaks Net::SSLeay
by syphilis (Archbishop) on Feb 15, 2008 at 09:50 UTC
    My compiler is Microsoft 32-bit C/C++ Optimizing Compiler Version 13.10.3077 for 80x86

    There's definitely the potential for unavoidable gotchas here. The compiler that built ActivePerl and your compiler use different C runtime libraries - and that *can* definitely be nasty - though, mostly, it's not an issue. And I think it's quite possibly *not* an issue here.

    I notice that one of the Test::Exception (which is a Net::SSLeay prereq) tests fails for me on windows. (I tried version 0.26.) Did the same happen for you ? Or does Test::Exception pass all of its tests ? (I'm wondering whether the failure you're up against is related to that Test::Exception failure.)

    On my Win32 box, I've actually used the very same compiler (MinGW) to build OpenSSL, perl and Net::SSLeay. But Net::SSLeay still won't build successfully - and, since it uses Module::Install, it's fairly unlikely that I'll ever make an effort to fix the problem.

    It actually makes me quite angry to see the sorts of issues that are being thrown up by Net::SSLeay on my Win32 box - especially given that Net::SLLeay built easily for me last time I tried it (which, admittedly, was quite some time ago).

    I can set the OPENSSL_PREFIX environment variable to the location of OpenSSL (and perl Makefile.PL finds that library without any trouble). But then I get (during the same Makfile.PL step) the following absurd warnings:
    Note (probably harmless): No library found for -llibeay32MD Note (probably harmless): No library found for -lssleay32MD Note (probably harmless): No library found for -llibeay32 Note (probably harmless): No library found for -lssleay32 Note (probably harmless): No library found for -llibssl32
    WTF is all that crap about ?
    Given that none of those libraries exist, it's no wonder that I get a heap of linking (undefined reference) errors during the dmake step - though I suspect that the same references *are* defined in libcrypto.a or libssl.a (both of which which actually *do* exist).

    Anyway, none of this will help you much - except perhaps for the notion that your problem lies with Test::Exception, rather than Net::SSLeay per se.

    Sorry ... I was really intending to be a little more helpful, but the distasteful state that Net::SSLeay is in (wrt to Win32) raised my ire to such a level that I just couldn't stomach the exercise.

    So how do people get away with such reckless behaviour

    Part of the solution is MinGW (port of gcc). It works seamlessly with recent versions of ActivePerl and, since it uses the same C runtime as the MS compiler that was used to build ActivePerl, you won't experience the "gotchas" I mentioned above. Alternatively, you might like to try Strawberry Perl which was built with MinGW and includes that compiler as part of the download.

    Then there's the MSYS shell, which enables one to build many libraries (including OpenSSL) using MinGW in the usual nix way - ie ./configure, make, make install. All of these are freely available, btw.

    Other than that, you can go down the path that you've already followed. (I suspect you might even be able to build OpenSSL with the compiler you have.)

    Cheers,
    Rob
      The compiler that built ActivePerl and your compiler use different C runtime libraries - and that *can* definitely be nasty - though, mostly, it's not an issue. And I think it's quite possibly *not* an issue here.

      I've confirmed that the perl.exe process has two CRTL DLLs loaded: msvcr71.dll (7.10.6030.0000) and msvcrt.dll (7.00.2600.2180).

      I surmise that both of these export errno and perl58.dll is linking to one and the Net/SSLeay.dll is linking to the other. Thus setting errno in Net/SSLeay.dll does not alter the value of $! in Perl. Indeed now I write this I seem to recall having heard of this exact issue elsewhere.

      Anyway, none of this will help you much - except perhaps for the notion that your problem lies with Test::Exception, rather than Net::SSLeay per se.

      Thanks, but having placed diagnostic prints of errno and $! just before the and after the return from the XS code and I'm sure I've isolated (and circumvented) this problem. I think it will turn out to be the first of many getting Net::SSLeay to work (see Legacy use of splice() as lvalue).

        Finally built Net-SSLeay-1.32 by replacing the existing Makefile.PL with
        use ExtUtils::MakeMaker; WriteMakefile( NAME => 'Net::SSLeay', VERSION_FROM => 'lib/Net/SSLeay.pm', );
        I then ran perl Makefile.PL INC="-IC:/path/to/ssl/include" LIBS="-LC:/path/to/ssl/lib -lssl -lcrypto" followed by dmake.

        Because of the unusual directory structure of the test suite dmake test wouldn't run, so I opted to run the test suite by running perl -Mblib tests.txt where tests.txt contained:
        use warnings; use Test::Harness; my @files = qw ( t/external/08_external.t t/handle/external/10_destroy.t t/handle/external/50_external.t t/handle/local/05_use.t t/local/00_ptr_cast.t t/local/01_pod.t t/local/02_pod_coverage.t t/local/03_use.t t/local/04_basic.t t/local/05_passwd_cb.t t/local/06_tcpecho.t t/local/07_sslecho.t t/local/08_pipe.t t/local/15_bio.t t/local/20_autoload.t t/local/30_error.t t/local/31_rsa_generate_key.t t/local/35_ephemeral.t t/local/50_digest.t t/local/kwalitee.t ); for(@files) {$_ = 'C:/_32/comp/Net-SSLeay-1.32/' . $_} Test::Harness::runtests(@files);
        That throws up one error (test 3 of t/handle/external/10_destroy.t):
        C:/_32/comp/Net-SSLeay-1.32/t/handle/external/10_destroy.....NOK 3# +Failed test 'correct response' # at C:/_32/comp/Net-SSLeay-1.32/t/handle/external/10_destroy.t line + 36. # undef # doesn't match '(?s-xim:^HTTP/1)' C:/_32/comp/Net-SSLeay-1.32/t/handle/external/10_destroy.....ok 5/6# L +ooks like you failed 1 test of 6.
        There were no other failures. Which test was failing for you ?

        Cheers,
        Rob

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://667963]
Approved by Old_Gray_Bear
Front-paged by Old_Gray_Bear
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others musing on the Monastery: (6)
As of 2024-03-28 14:05 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found