On 2004-04-02, at 12:09:12 -0800, Aren Sandersen wrote:

> Hi All --
> 
> Here is a snippet of XS-ish code that I've put together to show a problem
> I'm having trouble with returning many items on the stack.  When CRASH is
> defined, perl segfaults running the test script.  With CRASH is not defined,
> perl works fine.  It seems to be some stack issue, as the crash is after the
> DoCrash function is called.  I thought perhaps the CRASH codepath was as
> abuse of EXTEND, but now I'm not sure after looking at the XPUSHs macro
> definition (It calls EXTEND each time).
> 
> The output is especially interesting -- it prints the strings example0 ...
> example126, then segfaults.  It strikes me as some sort of stack-memory
> reallocation issue.  What am I doing wrong?
> 
> Oh, this is perl 5.8.3 on Redhat 9.
> 
> Thanks,
> Aren
> 
> File: testcrash.pl
> ---
> use CrashModule;
> @values = CrashModule::DoCrash(250);
> print "Returned " . scalar(@values) . " results\n";
> print "values are: @values.\n";
> 
> File: crash.cxx
> ---
> #include "EXTERN.h"
> #include "perl.h"
> #include "XSUB.h"
> 
> #include <vector>
> #include <string>
> 
> #define CRASH
> 
> #ifdef __cplusplus
> extern "C" {
> #endif
> XS(_wrap_DoCrash) {
>  dXSARGS;
> 
>  int argvi = 0;
> 
>  if ((items < 1) || (items > 1)) {
>   croak("Wrong # of args");
>  }
> 
>  int times = (unsigned short) SvUV(ST(0));
> 
> #ifndef CRASH
>  EXTEND(sp, (times - items));
> #endif
> 
>  for (int j = 0; j < times; j++) {
>   char s[80];
> 
>   sprintf(s, "example%d", j);
> #ifdef CRASH
>   if (argvi >= items) {
>    EXTEND(sp, 1);
>   }
> #endif

This is wrong. If you have a look at perlapi.pod:

       EXTEND  Used to extend the argument stack for an XSUB's return values.
               Once used, guarantees that there is room for at least "nitems"
               to be pushed onto the stack.

                       void    EXTEND(SP, int nitems)

So EXTEND guarantees that there's room for nitems on the stack. You keep
calling it over and over again with the same arguments. Only the first
call effectively increases the stack size to 1 (actually, it won't even do
that as the stack is already holding one element). Since the stack pointer
doesn't change (using ST() doesn't alter it), all later calls are no-ops.

The XPUSHs() code

  #define XPUSHs(s)     STMT_START { EXTEND(sp,1); (*++sp = (s)); } STMT_END

works because it increments the stack pointer on each call.

Also, if you EXTEND the stack size at the beginning, you are safe to use
ST() afterwards.

HTH,
Marcus

>   sv_setpvn(ST(argvi) = sv_newmortal(), s, strlen(s));
>   ++argvi;
>  }
> 
>  XSRETURN(argvi);
> }
> 
> XS(boot_CrashModule) {
>     dXSARGS;
>  char* file = __FILE__;
>     XS_VERSION_BOOTCHECK ;
> 
>     newXSproto("CrashModule::DoCrash", _wrap_DoCrash, file, "$;$");
> 
>     XSRETURN_YES;
> }
> 
> #ifdef __cplusplus
> }
> #endif
> 
> 


-- 
Lowery's Law:
        If it jams -- force it.  If it breaks, it needed replacing anyway.

Reply via email to