Skip to content

Commit 539e010

Browse files
committed
class.c, injected_constructor: prevent loop exits exiting
Using last, next etc would pop the context stack to above the call_sv(), generally resulting in a crash or assertion failure. The search the context to pop to stops at the top of the current context stack, and PUSHSTACKi() switches to a new stack, preventing the search from finding any loop outside the call_sv() Similar to #16608
1 parent 095b290 commit 539e010

File tree

4 files changed

+34
-1
lines changed

4 files changed

+34
-1
lines changed

class.c

+3
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ XS(injected_constructor)
175175

176176
SV *self = sv_2mortal(newRV_noinc(instance));
177177

178+
PUSHSTACKi(PERLSI_CONSTRUCTOR);
178179
assert(aux->xhv_class_initfields_cv);
179180
{
180181
ENTER;
@@ -221,6 +222,8 @@ XS(injected_constructor)
221222
}
222223
}
223224

225+
POPSTACK;
226+
224227
if(params && hv_iterinit(params) > 0) {
225228
/* TODO: consider sorting these into a canonical order, but that's awkward */
226229
HE *he = hv_iternext(params);

cop.h

+1
Original file line numberDiff line numberDiff line change
@@ -1259,6 +1259,7 @@ struct context {
12591259
#define PERLSI_MULTICALL 10
12601260
#define PERLSI_REGCOMP 11
12611261
#define PERLSI_SMARTMATCH 12
1262+
#define PERLSI_CONSTRUCTOR 13
12621263

12631264
struct stackinfo {
12641265
AV * si_stack; /* stack for current runlevel */

deb.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,8 @@ static const char * const si_names[] = {
238238
"REQUIRE",
239239
"MULTICALL",
240240
"REGCOMP",
241-
"SMARTMATCH"
241+
"SMARTMATCH",
242+
"CONSTRUCTOR"
242243
};
243244
#endif
244245

t/lib/croak/class

+28
Original file line numberDiff line numberDiff line change
@@ -185,3 +185,31 @@ class XXX {
185185
}
186186
EXPECT
187187
Cannot apply a :writer attribute to a non-scalar field at - line 6.
188+
########
189+
use v5.36;
190+
use feature 'class';
191+
no warnings 'experimental::class';
192+
sub f { last }
193+
class X {
194+
field $x = ::f();
195+
}
196+
# two warnings since we exit the initfields cv and f()
197+
X->new for 0;
198+
EXPECT
199+
Exiting subroutine via last at - line 4.
200+
Exiting subroutine via last at - line 4.
201+
Can't "last" outside a loop block at - line 4.
202+
########
203+
use v5.36;
204+
use feature 'class';
205+
no warnings 'experimental::class';
206+
class X {
207+
field $x;
208+
ADJUST {
209+
last;
210+
}
211+
}
212+
X->new for 0;
213+
EXPECT
214+
Exiting subroutine via last at - line 7.
215+
Can't "last" outside a loop block at - line 7.

0 commit comments

Comments
 (0)