in reply to Re^3: GIMME_V==G_ARRAY anomaly on win32 (5.10 only)
in thread GIMME_V==G_ARRAY anomaly on win32 (5.10 only)

( "force" forces a rebuild )

Everything works fine if I do a rebuild. It's only when I run MinGW-built binaries on ActivePerl or ActivePerl-built binaries on MinGW perl that the problem arises (even though it's the exact same compiler building the binaries, irrespective of which perl is being used.) When I run the "foreign" binary on the "perl that didn't build the binary", GIMME_V inevitably returns G_VOID (afaict).

Now some people may raise eyebrows at the practice of throwing binaries around like I'm doing - but it's something I've been doing for quite some time without any troubles at all. I don't see why it should pose a problem, until now I've been quietly confident it would never pose a problem, it's still *not* a problem on perl-5.8.x, but all of a sudden I find that I can't do it on 5.10.x when an XSub relies on GIMME_V.

I'm hoping it's a bug - but even if it is, I may have trouble convincing the people that count :-)
Then again, fairk, I may have been indulging in a bad pratice for all these years, after all. If so, then the implication is that you must provide separate binaries for Strawberry Perl (or any MinGW-built perl) and ActivePerl - which is probably not such a big deal since Strawberry users aren't generally interested in binaries anyway, but it's interesting nonetheless.

I actually provide a few ppm packages (including Net-SSH2) to the uwinnipeg rep - all built using the MinGW compiler. In the past, I haven't paid much attention to whether I built the packages with ActivePerl or with my own MinGW-built perl. But it now looks like I ought to make sure that I build them using ActivePerl.

The result matrices for the code you posted are:
1) For the perl 5.10.x that compiles the script:
1 1 1
2) For the "other" perl 5.10.x:
80 1 0
No matter which perl builds the script, the generated XS and C files are identical. (These files are reproduced below my sig in the <readmore> section.)

Cheers,
Rob

The XS file
#include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "INLINE.h" void foo() { printf("%x\n", GIMME_V); printf("%x\n", G_ARRAY); printf("%d\n", GIMME_V == G_ARRAY); } MODULE = try_pl_73cf PACKAGE = main PROTOTYPES: DISABLE void foo () PREINIT: I32* temp; PPCODE: temp = PL_markstack_ptr++; foo(); if (PL_markstack_ptr != temp) { /* truly void, because dXSARGS not invoked */ PL_markstack_ptr = temp; XSRETURN_EMPTY; /* return empty stack */ } /* must have used dXSARGS; list context implied */ return; /* assume stack size is correct */
The C file:
/* * This file was generated automatically by ExtUtils::ParseXS version +2.18_02 from the * contents of try_pl_73cf.xs. Do not edit this file, edit try_pl_73cf +.xs instead. * * ANY CHANGES MADE HERE WILL BE LOST! * */ #line 1 "try_pl_73cf.xs" #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "INLINE.h" void foo() { printf("%x\n", GIMME_V); printf("%x\n", G_ARRAY); printf("%d\n", GIMME_V == G_ARRAY); } #ifndef PERL_UNUSED_VAR # define PERL_UNUSED_VAR(var) if (0) var = var #endif #line 28 "try_pl_73cf.c" XS(XS_main_foo); /* prototype to pass -Wmissing-prototypes */ XS(XS_main_foo) { #ifdef dVAR dVAR; dXSARGS; #else dXSARGS; #endif if (items != 0) Perl_croak(aTHX_ "Usage: %s(%s)", "main::foo", ""); PERL_UNUSED_VAR(cv); /* -W */ PERL_UNUSED_VAR(ax); /* -Wall */ SP -= items; { #line 22 "try_pl_73cf.xs" I32* temp; #line 46 "try_pl_73cf.c" #line 24 "try_pl_73cf.xs" temp = PL_markstack_ptr++; foo(); if (PL_markstack_ptr != temp) { /* truly void, because dXSARGS not invoked */ PL_markstack_ptr = temp; XSRETURN_EMPTY; /* return empty stack */ } /* must have used dXSARGS; list context implied */ return; /* assume stack size is correct */ #line 57 "try_pl_73cf.c" PUTBACK; return; } } #ifdef __cplusplus extern "C" #endif XS(boot_try_pl_73cf); /* prototype to pass -Wmissing-prototypes */ XS(boot_try_pl_73cf) { #ifdef dVAR dVAR; dXSARGS; #else dXSARGS; #endif char* file = __FILE__; PERL_UNUSED_VAR(cv); /* -W */ PERL_UNUSED_VAR(items); /* -W */ XS_VERSION_BOOTCHECK ; newXS("main::foo", XS_main_foo, file); if (PL_unitcheckav) call_list(PL_scopestack_ix, PL_unitcheckav); XSRETURN_YES; }

Replies are listed 'Best First'.
Re^5: GIMME_V==G_ARRAY anomaly on win32 (5.10 only)
by Anonymous Monk on Dec 19, 2009 at 09:06 UTC
    Using gcc version 3.4.5 (mingw-vista special r3) I get
    1 1 1
    on strawberry v5.10.0, self built 5.10.1 , and activeperl v5.8.9 Build 825 288577

    The XS looks identical to yours and doesn't change between the 3 perls

    Grepping the CORE directory I get in all 3 perls

    CORE/cop.h:#define G_ARRAY 1 lib\CORE/op.h:#define GIMME_V OP_GIMME(PL_op, block_gim +me())
    but on bleadperl I see #define G_ARRAY 3

      Grepping the CORE directory I get in all 3 perls

      lib\CORE/op.h:#define GIMME_V OP_GIMME(PL_op, block_gim +me())

      What matters is not no much that the macro #define doesn't differ, but what machine code the compiler has generated for it.  After full macro expansion, the GIMME_V macro looks like:

      ((((*Perl_Top_ptr(((PerlInterpreter *)pthread_getspecific((*Perl_Gthr_ +key_ptr(((void *)0))))))))->op_flags & 3) == 1 ? 128 : (((*Perl_Top_p +tr(((PerlInterpreter *)pthread_getspecific((*Perl_Gthr_key_ptr(((void + *)0))))))))->op_flags & 3) == 2 ? 0 : (((*Perl_Top_ptr(((PerlInterpr +eter *)pthread_getspecific((*Perl_Gthr_key_ptr(((void *)0))))))))->op +_flags & 3) == 3 ? 1 : Perl_block_gimme(((PerlInterpreter *)pthread_g +etspecific((*Perl_Gthr_key_ptr(((void *)0))))))))

      (this is for a threaded 5.8.8 — replace cc -c ... with cc -E ... in the compiler call issued by Inline::C to obtain the respective snippet for whatever Perl version you're interested in)

      As you can see, some Perl-internal functions/structures are being accessed. And problems may arise if the machine code for this macro generated by the compiler used to compile the extension DLL does not address memory as layed out by the compiler(+options) that compiled the perl DLL (for example, op_flags might be aligned differently (just for the sake of argument — not saying this is necessarily the issue in this particular case)).

        I get your point regarding memory layout.

        The macro does expand the same for me

        perl 5.10.1 void foo() { printf("%x\n", ((((*Perl_Iop_ptr(((PerlInterpreter *)Perl_get_cont +ext()))))->op_flags & 3) == 1 ? 128 : (((*Perl_Iop_ptr(((PerlInterpre +ter *)Perl_get_context()))))->op_flags & 3) == 2 ? 0 : (((*Perl_Iop_p +tr(((PerlInterpreter *)Perl_get_context()))))->op_flags & 3) == 3 ? 1 + : Perl_block_gimme(((PerlInterpreter *)Perl_get_context())))); printf("%x\n", 1); printf("%d\n", ((((*Perl_Iop_ptr(((PerlInterpreter *)Perl_get_cont +ext()))))->op_flags & 3) == 1 ? 128 : (((*Perl_Iop_ptr(((PerlInterpre +ter *)Perl_get_context()))))->op_flags & 3) == 2 ? 0 : (((*Perl_Iop_p +tr(((PerlInterpreter *)Perl_get_context()))))->op_flags & 3) == 3 ? 1 + : Perl_block_gimme(((PerlInterpreter *)Perl_get_context()))) == 1); } strawbery 5.10.0 void foo() { printf("%x\n", ((((*Perl_Iop_ptr(((PerlInterpreter *)Perl_get_cont +ext()))))->op_flags & 3) == 1 ? 128 : (((*Perl_Iop_ptr(((PerlInterpre +ter *)Perl_get_context()))))->op_flags & 3) == 2 ? 0 : (((*Perl_Iop_p +tr(((PerlInterpreter *)Perl_get_context()))))->op_flags & 3) == 3 ? 1 + : Perl_block_gimme(((PerlInterpreter *)Perl_get_context())))); printf("%x\n", 1); printf("%d\n", ((((*Perl_Iop_ptr(((PerlInterpreter *)Perl_get_cont +ext()))))->op_flags & 3) == 1 ? 128 : (((*Perl_Iop_ptr(((PerlInterpre +ter *)Perl_get_context()))))->op_flags & 3) == 2 ? 0 : (((*Perl_Iop_p +tr(((PerlInterpreter *)Perl_get_context()))))->op_flags & 3) == 3 ? 1 + : Perl_block_gimme(((PerlInterpreter *)Perl_get_context()))) == 1); } activeperl v5.8.9 build 825 [288577] void foo() { printf("%x\n", ((((*Perl_Top_ptr(((PerlInterpreter *)Perl_get_cont +ext()))))->op_flags & 3) == 1 ? 128 : (((*Perl_Top_ptr(((PerlInterpre +ter *)Perl_get_context()))))->op_flags & 3) == 2 ? 0 : (((*Perl_Top_p +tr(((PerlInterpreter *)Perl_get_context()))))->op_flags & 3) == 3 ? 1 + : Perl_block_gimme(((PerlInterpreter *)Perl_get_context())))); printf("%x\n", 1); printf("%d\n", ((((*Perl_Top_ptr(((PerlInterpreter *)Perl_get_cont +ext()))))->op_flags & 3) == 1 ? 128 : (((*Perl_Top_ptr(((PerlInterpre +ter *)Perl_get_context()))))->op_flags & 3) == 2 ? 0 : (((*Perl_Top_p +tr(((PerlInterpreter *)Perl_get_context()))))->op_flags & 3) == 3 ? 1 + : Perl_block_gimme(((PerlInterpreter *)Perl_get_context()))) == 1); }
        problems may arise if the machine code for this macro generated by the compiler used to compile the extension DLL does not address memory as layed out by the compiler(+options) that compiled the perl DLL (for example, op_flags might be aligned differently

        Isn't this the sort of thing that would most likely cause a crash, rather than a wrong value being returned ?
        And it would seem to be a coincidence that such a misalignment actually returns one of the three *meaningful* values (0, 1, 128) instead of a nonsense value.

        I guess anything is possible - and the proof probably lies in the debugger (as you've already mentioned).

        Cheers,
        Rob