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

I just know that this is going to be something really stupid (on my behalf probably), but danged if I can see it today. With the call to test2() commented this compiles and runs clean producing the output shown. Uncomment that call and it produces the output from test() and then segfaults. Why?

#! perl -slw use strict; use Inline C => <<'__C__'; #include <stdio.h> void test ( char* text ) { printf( "Got:'%s'\n", text ); printf( "%x\n", stderr ); } void test2 ( char* text ) { fprintf( stderr, "Got:'%s'\n", text ); } __C__ test( 'fred' ); #test2( 'fred' ); __END__ C:\test>IC-junk1.pl Got:'fred' 77c5acc0

Update: Platform is Win32. Microsoft (R) 32-bit C/C++ Standard Compiler Version 13.00.9466 for 80x86

Using stderr from a c program built with the same compiler works just fine.


Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
"Too many [] have been sedated by an oppressive environment of political correctness and risk aversion."

Replies are listed 'Best First'.
Re: Inline C: using stderr segfaults? (A solution)
by BrowserUk (Patriarch) on Nov 05, 2007 at 13:52 UTC
Re: Inline C: using stderr segfaults?
by mwah (Hermit) on Nov 05, 2007 at 12:26 UTC
    Microsoft (R) 32-bit C/C++ Standard Compiler Version 13.00.9466 for 80x86

    Maybe thats the point.

    Wasn't Activestate Perl build with the 12.xx version?

    Using your code, I got a clean run under AS 822 and

    Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8804 for 80x86

    where it says:

      Got:'fred'
      77c2fcc0
      Got:'fred'

    Regards

    mwa

      You may well be right I fear, though this is the first time I have encountered a problem with the apparent mismatch. I tracked the error using a debugger to an Rtl CriticalSection function.

      And the following version which crudely approximates using fprintf() runs fine:

      #! perl -slw use strict; use Inline 'FORCE'; use Inline C => 'DATA', NAME => 'IC_junk1', CLEAN_AFTER_BUILD => 0; test( 'fred' ); test2( 'fred' ); __DATA__ __C__ //#include <stdio.h> void test ( char* text ) { printf( "Got:'%s'\n", text ); printf( "%x\n", stderr ); } void test2 ( char* text ) { char buf[ 255 ]; sprintf( buf, "%s", text ); fputs( stderr, buf ); }

      So it does look like some difference in the CRTs that is responsible. I'd swear that I've used fprintf() from inline C before, but a quick scan of my files revealed none and I found a couple that called Perl_warn(), so maybe I encountered and worked around it some time ago and forgot.


      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.
        So it does look like some difference in the CRTs that is responsible

        It need not exactly be a "difference in the CRTs". When perl uses one CRT and the compiler uses a different CRT, you can get situations where something (eg a handle) is created by one CRT and then passed to the other CRT (which knows nothing about that handle, and segfaults).

        This problem arises when you try to build Win32::SharedFileOpen - which is the only example I know of, btw. A little surprising (at first glance) is the fact that you can build Win32::SharedFileOpen on ActivePerl using the MinGW compiler ... but it's not really surprising, because MinGW uses the same CRT as ActivePerl.

        Fwiw, the original script you provided builds fine for me on ActivePerl using MinGW.

        Cheers,
        Rob
Re: Inline C: using stderr segfaults?
by parv (Parson) on Nov 05, 2007 at 10:10 UTC
    Just a data point: no problem here (FreeBSD 6-STABLE/i386 32 bit, gcc 3.4.6, Perl 5.8.8 (64-bit integer support), Inline::C 0.44) with test2 call.
Re: Inline C: using stderr segfaults?
by moritz (Cardinal) on Nov 05, 2007 at 10:14 UTC
    Works for me as well, perl 5.8.8, gcc 4.1.2, on Debian GNU/Linux "Etch", 32 bit.
Re: Inline C: using stderr segfaults?
by salva (Canon) on Nov 05, 2007 at 16:16 UTC
    another possibility is perl redefining fprintf or stderr with some macro.

    Add to your script

    use Inline Config => FORCE_BUILD => 1, CLEAN_AFTER_BUILD => 0, BUILD_NOISY => 1;
    to see what Inline is doing and then rerun the compilation step manually adding the option to only perform the C preprocessing (for instance, with gcc it is -E).

    Then, on the preprocessor output, look for test2 and check the fprintf expansion.

      Good call++ This is what the call fprintf( stderr, "Got:'%s'\n", text ); gets translated into:

      fprintf( ( *( *Perl_IStdIO_ptr( ( ( PerlInterpreter *)Perl_get_context() ) ) )->pStderr ) ( ( *Perl_IStdIO_ptr( ( ( PerlInterpreter* ) Perl_get_context() ) ) ) ), "Get:'%s'\n", text );

      And if you can make sense of that your a better man that I.

      It's no wonder function calls are slow in perl. Some single lines of XS code end up calling Perl_get_context() 7 or 8 times. There has to be a better way.


      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.
        And if you can make sense of that...

        The only explanation I can find to that code is that

        (*Perl_IStdIO_ptr(((PerlInterpreter *)Perl_get_context())))->pStderr
        returns a function pointer, and the next parenthesized expresion,
        ((*Perl_IStdIO_ptr((( PerlInterpreter* ) Perl_get_context()))))
        are the arguments for calling that function.

        It's no wonder function calls are slow in perl. Some single lines of XS code end up calling Perl_get_context() 7 or 8 times. There has to be a better way

        Well, yes, there is a better way!... at least for XS, I don't know about Inline::C, though probably not.

        You have to start your XS files defining the macro ...

        #define PERL_NO_GET_CONTEXT 1
        ... and then pass the Perl context manually from function to function using pTHX, aTHX, pTHX_ and aTHX_. See perlguts for the details.