summaryrefslogtreecommitdiff
path: root/dist
diff options
context:
space:
mode:
authorTony Cook <tony@develop-help.com>2021-09-06 11:53:29 +1000
committerTony Cook <tony@develop-help.com>2021-09-13 10:05:02 +1000
commit2647863031762b1897841364c638c3727bc043f1 (patch)
treea77a5f26a32d549c5d3078a89b78be08e0220c7f /dist
parente0f95237e410dc356b393fde2beec8ec83d476ef (diff)
downloadperl-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.pm22
-rw-r--r--dist/ExtUtils-ParseXS/t/002-more.t8
-rw-r--r--dist/ExtUtils-ParseXS/t/XSMore.xs36
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))