diff options
author | Tony Cook <tony@develop-help.com> | 2021-09-06 11:53:29 +1000 |
---|---|---|
committer | Tony Cook <tony@develop-help.com> | 2021-09-13 10:05:02 +1000 |
commit | 2647863031762b1897841364c638c3727bc043f1 (patch) | |
tree | a77a5f26a32d549c5d3078a89b78be08e0220c7f /dist | |
parent | e0f95237e410dc356b393fde2beec8ec83d476ef (diff) | |
download | perl-2647863031762b1897841364c638c3727bc043f1.tar.gz |
ParseXS: always XSprePUSH when producing an output list
The late XSprePUSH with a non-PUSHx() RETVAL was causing the
stack and accesses to ST(n) to be out of sync.
If generated RETVAL code does write directly to ST(n) (as much does),
doesn't generate a push and we're generating output list code,
adjust SP to match to keep things in sync.
Also test that the original example case that worked, continues to
work.
Fixes #19054
Diffstat (limited to 'dist')
-rw-r--r-- | dist/ExtUtils-ParseXS/lib/ExtUtils/ParseXS.pm | 22 | ||||
-rw-r--r-- | dist/ExtUtils-ParseXS/t/002-more.t | 8 | ||||
-rw-r--r-- | dist/ExtUtils-ParseXS/t/XSMore.xs | 36 |
3 files changed, 57 insertions, 9 deletions
diff --git a/dist/ExtUtils-ParseXS/lib/ExtUtils/ParseXS.pm b/dist/ExtUtils-ParseXS/lib/ExtUtils/ParseXS.pm index d2205acd5a..cc10ff9465 100644 --- a/dist/ExtUtils-ParseXS/lib/ExtUtils/ParseXS.pm +++ b/dist/ExtUtils-ParseXS/lib/ExtUtils/ParseXS.pm @@ -690,10 +690,17 @@ EOF do_push => undef, } ) for grep $self->{in_out}->{$_} =~ /OUT$/, sort keys %{ $self->{in_out} }; - my $prepush_done; + my $c = @{ $outlist_ref }; + if ($c) { + my $ext = $c; + ++$ext if $self->{gotRETVAL} || $wantRETVAL; + print "\tXSprePUSH;"; + print "\tEXTEND(SP,$ext);\n"; + } # all OUTPUT done, so now push the return value on the stack if ($self->{gotRETVAL} && $self->{RETVAL_code}) { print "\t$self->{RETVAL_code}\n"; + print "\t++SP;\n" if $c; } elsif ($self->{gotRETVAL} || $wantRETVAL) { my $outputmap = $self->{typemap}->get_outputmap( ctype => $self->{ret_type} ); @@ -708,8 +715,9 @@ EOF ); if (not $trgt->{with_size} and $trgt->{type} eq 'p') { # sv_setpv # PUSHp corresponds to sv_setpvn. Treat sv_setpv directly - print "\tsv_setpv(TARG, $what); XSprePUSH; PUSHTARG;\n"; - $prepush_done = 1; + print "\tsv_setpv(TARG, $what);\n"; + print "\tXSprePUSH;\n" unless $c; + print "\tPUSHTARG;\n"; } else { my $tsize = $trgt->{what_size}; @@ -718,8 +726,8 @@ EOF qq("$tsize"), {var => $var, type => $self->{ret_type}} ); - print "\tXSprePUSH; PUSH$trgt->{type}($what$tsize);\n"; - $prepush_done = 1; + print "\tXSprePUSH;\n" unless $c; + print "\tPUSH$trgt->{type}($what$tsize);\n"; } } else { @@ -731,14 +739,12 @@ EOF do_setmagic => 0, do_push => undef, } ); + print "\t++SP;\n" if $c; } } $xsreturn = 1 if $self->{ret_type} ne "void"; my $num = $xsreturn; - my $c = @{ $outlist_ref }; - print "\tXSprePUSH;" if $c and not $prepush_done; - print "\tEXTEND(SP,$c);\n" if $c; $xsreturn += $c; $self->generate_output( { type => $self->{var_types}->{$_}, diff --git a/dist/ExtUtils-ParseXS/t/002-more.t b/dist/ExtUtils-ParseXS/t/002-more.t index 3ea89c2583..c8cc7bf97c 100644 --- a/dist/ExtUtils-ParseXS/t/002-more.t +++ b/dist/ExtUtils-ParseXS/t/002-more.t @@ -9,7 +9,7 @@ use ExtUtils::CBuilder; use attributes; use overload; -plan tests => 30; +plan tests => 32; my ($source_file, $obj_file, $lib_file); @@ -91,6 +91,12 @@ SKIP: { is_deeply [XSMore::outlist()], [ord('a'), ord('b')], 'the OUTLIST keyword'; + is_deeply [XSMore::outlist_bool("a", "b")], [ !0, "ab" ], + "OUTLIST with a bool RETVAL"; + + is_deeply [XSMore::outlist_int("c", "d")], [ 11, "cd" ], + "OUTLIST with an int RETVAL"; + # eval so compile-time sees any prototype is_deeply [ eval 'XSMore::outlist()' ], [ord('a'), ord('b')], 'OUTLIST prototypes'; diff --git a/dist/ExtUtils-ParseXS/t/XSMore.xs b/dist/ExtUtils-ParseXS/t/XSMore.xs index 21ad41df89..f8413f43bd 100644 --- a/dist/ExtUtils-ParseXS/t/XSMore.xs +++ b/dist/ExtUtils-ParseXS/t/XSMore.xs @@ -38,6 +38,36 @@ outlist(int* a, int* b){ *b = 'b'; } +STATIC bool +outlist_bool(const char *a, const char *b, char **c) +{ + dTHX; + STRLEN lena = strlen(a); + STRLEN lenb = strlen(b); + STRLEN lenc = lena + lenb; + Newx(*c, lenc+1, char); + strcpy(*c, a); + strcat(*c, b); + SAVEFREEPV(*c); + + return TRUE; +} + +STATIC int +outlist_int(const char *a, const char *b, char **c) +{ + dTHX; + STRLEN lena = strlen(a); + STRLEN lenb = strlen(b); + STRLEN lenc = lena + lenb; + Newx(*c, lenc+1, char); + strcpy(*c, a); + strcat(*c, b); + SAVEFREEPV(*c); + + return 11; +} + STATIC int len(const char* const s, int const l){ PERL_UNUSED_ARG(s); @@ -201,6 +231,12 @@ CLEANUP: void outlist(OUTLIST int a, OUTLIST int b) +bool +outlist_bool(const char *a, const char *b, OUTLIST char *c) + +int +outlist_int(const char *a, const char *b, OUTLIST char *c) + int len(char* s, int length(s)) |