Skip to content

Commit

Permalink
Make @isa a readonly array on class stashes so user code can't fiddle…
Browse files Browse the repository at this point in the history
… with it and break stuff
  • Loading branch information
leonerd committed Feb 10, 2023
1 parent 9bf25cf commit e51627a
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 3 deletions.
14 changes: 11 additions & 3 deletions class.c
Original file line number Diff line number Diff line change
Expand Up @@ -379,14 +379,22 @@ apply_class_attribute_isa(pTHX_ HV *stash, SV *value)
* You'd think that GvAV() of hv_fetchs() would do it, but no, because it
* won't lazily create a proper (magical) GV if one didn't already exist.
*/
AV *isa;
{
SV *isaname = newSVpvf("%" HEKf "::ISA", HvNAME_HEK(stash));
sv_2mortal(isaname);

isa = get_av(SvPV_nolen(isaname), GV_ADD | (SvFLAGS(isaname) & SVf_UTF8));
AV *isa = get_av(SvPV_nolen(isaname), GV_ADD | (SvFLAGS(isaname) & SVf_UTF8));

ENTER;

/* Temporarily remove the SVf_READONLY flag */
SAVESETSVFLAGS((SV *)isa, SVf_READONLY|SVf_PROTECT, SVf_READONLY|SVf_PROTECT);
SvREADONLY_off((SV *)isa);

av_push(isa, newSVsv(value));

LEAVE;
}
av_push(isa, newSVsv(value));

aux->xhv_class_superclass = (HV *)SvREFCNT_inc(superstash);

Expand Down
8 changes: 8 additions & 0 deletions gv.c
Original file line number Diff line number Diff line change
Expand Up @@ -1763,6 +1763,14 @@ S_gv_magicalize_isa(pTHX_ GV *gv)
GvMULTI_on(gv);
sv_magic(MUTABLE_SV(av), MUTABLE_SV(gv), PERL_MAGIC_isa,
NULL, 0);

if(HvSTASH_IS_CLASS(GvSTASH(gv))) {
/* Don't permit modification of @ISA outside of the class management
* code. This is temporarily undone by class.c when fiddling with the
* array, so it knows it can be done safely.
*/
SvREADONLY_on((SV *)av);
}
}

/* This function grabs name and tries to split a stash and glob
Expand Down
2 changes: 2 additions & 0 deletions t/class/inherit.t
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ no warnings 'experimental::class';
ok($obj isa Test1B, 'Object is its own class');
ok($obj isa Test1A, 'Object is also its base class');

ok(eq_array(\@Test1B::ISA, ["Test1A"]), '@Test1B::ISA is set correctly');

is($obj->y, "derived class", 'Object has derived class field');

can_ok($obj, "x");
Expand Down
7 changes: 7 additions & 0 deletions t/lib/croak/class
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,10 @@ class XXX {}
class XXX {}
EXPECT
Cannot reopen existing class "XXX" at - line 4.
########
no warnings 'experimental::class';
use feature 'class';
class XXX {}
push @XXX::ISA, q(Another);
EXPECT
Modification of a read-only value attempted at - line 4.

0 comments on commit e51627a

Please sign in to comment.