AvALLOC(av) = 0;
SvPV_set(av, (char*)0);
AvMAX(av) = AvFILLp(av) = -1;
- if (AvARYLEN(av)) {
- SvREFCNT_dec(AvARYLEN(av));
- AvARYLEN(av) = 0;
- }
+ /* It's in magic - it must already be gone. */
+ assert (!AvARYLEN(av));
}
/*
}
/* sv_magicext won't set this for us because we pass in a NULL obj */
mg->mg_flags |= MGf_REFCOUNTED;
+
+ /* This is very naughty, but we don't want SvRMAGICAL() set on the
+ hash, because it slows down all accesses. If we pass in a vtable
+ to sv_magicext then it is (correctly) set for us. However, the only
+ entry in our vtable is for free, and mg_free always calls the free
+ vtable entry irrespective of the flags, so it doesn't actually
+ matter that the R flag is off. */
+ mg->mg_virtual = &PL_vtbl_arylen_p;
}
return &(mg->mg_obj);
}
else if (v == &PL_vtbl_amagicelem) s = "amagicelem";
else if (v == &PL_vtbl_backref) s = "backref";
else if (v == &PL_vtbl_utf8) s = "utf8";
+ else if (v == &PL_vtbl_arylen_p) s = "arylen_p";
if (s)
Perl_dump_indent(aTHX_ level, file, " MG_VIRTUAL = &PL_vtbl_%s\n", s);
else
p |int |magic_set |SV* sv|MAGIC* mg
p |int |magic_setamagic|SV* sv|MAGIC* mg
p |int |magic_setarylen|SV* sv|MAGIC* mg
+p |int |magic_freearylen_p|SV* sv|MAGIC* mg
p |int |magic_setbm |SV* sv|MAGIC* mg
p |int |magic_setdbline|SV* sv|MAGIC* mg
p |int |magic_setdefelem|SV* sv|MAGIC* mg
#define magic_set Perl_magic_set
#define magic_setamagic Perl_magic_setamagic
#define magic_setarylen Perl_magic_setarylen
+#define magic_freearylen_p Perl_magic_freearylen_p
#define magic_setbm Perl_magic_setbm
#define magic_setdbline Perl_magic_setdbline
#define magic_setdefelem Perl_magic_setdefelem
#define magic_set(a,b) Perl_magic_set(aTHX_ a,b)
#define magic_setamagic(a,b) Perl_magic_setamagic(aTHX_ a,b)
#define magic_setarylen(a,b) Perl_magic_setarylen(aTHX_ a,b)
+#define magic_freearylen_p(a,b) Perl_magic_freearylen_p(aTHX_ a,b)
#define magic_setbm(a,b) Perl_magic_setbm(aTHX_ a,b)
#define magic_setdbline(a,b) Perl_magic_setdbline(aTHX_ a,b)
#define magic_setdefelem(a,b) Perl_magic_setdefelem(aTHX_ a,b)
int
Perl_magic_getarylen(pTHX_ SV *sv, MAGIC *mg)
{
- sv_setiv(sv, AvFILL((AV*)mg->mg_obj) + PL_curcop->cop_arybase);
+ AV *obj = (AV*)mg->mg_obj;
+ if (obj) {
+ sv_setiv(sv, AvFILL(obj) + PL_curcop->cop_arybase);
+ } else {
+ SvOK_off(sv);
+ }
return 0;
}
int
Perl_magic_setarylen(pTHX_ SV *sv, MAGIC *mg)
{
- av_fill((AV*)mg->mg_obj, SvIV(sv) - PL_curcop->cop_arybase);
+ AV *obj = (AV*)mg->mg_obj;
+ if (obj) {
+ av_fill(obj, SvIV(sv) - PL_curcop->cop_arybase);
+ } else {
+ if (ckWARN(WARN_MISC))
+ Perl_warner(aTHX_ packWARN(WARN_MISC),
+ "Attempt to set length of freed array");
+ }
+ return 0;
+}
+
+int
+Perl_magic_freearylen_p(pTHX_ SV *sv, MAGIC *mg)
+{
+ mg = mg_find (mg->mg_obj, PERL_MAGIC_arylen);
+
+ if (mg) {
+ /* arylen scalar holds a pointer back to the array, but doesn't own a
+ reference. Hence the we (the array) are about to go away with it
+ still pointing at us. Clear its pointer, else it would be pointing
+ at free memory. See the comment in sv_magic about reference loops,
+ and why it can't own a reference to us. */
+ mg->mg_obj = 0;
+ }
return 0;
}
want_vtbl_regdatum,
want_vtbl_backref,
want_vtbl_utf8,
- want_vtbl_symtab
+ want_vtbl_symtab,
+ want_vtbl_arylen_p
};
/* Note: the lowest 8 bits are reserved for
);
MGVTBL_SET(
+ PL_vtbl_arylen_p,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ MEMBER_TO_FPTR(Perl_magic_freearylen_p),
+ NULL,
+ NULL
+);
+
+MGVTBL_SET(
PL_vtbl_glob,
MEMBER_TO_FPTR(Perl_magic_getglob),
MEMBER_TO_FPTR(Perl_magic_setglob),
PERL_CALLCONV int Perl_magic_set(pTHX_ SV* sv, MAGIC* mg);
PERL_CALLCONV int Perl_magic_setamagic(pTHX_ SV* sv, MAGIC* mg);
PERL_CALLCONV int Perl_magic_setarylen(pTHX_ SV* sv, MAGIC* mg);
+PERL_CALLCONV int Perl_magic_freearylen_p(pTHX_ SV* sv, MAGIC* mg);
PERL_CALLCONV int Perl_magic_setbm(pTHX_ SV* sv, MAGIC* mg);
PERL_CALLCONV int Perl_magic_setdbline(pTHX_ SV* sv, MAGIC* mg);
PERL_CALLCONV int Perl_magic_setdefelem(pTHX_ SV* sv, MAGIC* mg);
require 'test.pl';
-plan (85);
+plan (88);
#
# @foo, @bar, and @ary are also used from tie-stdarray after tie-ing them
like($@, qr/Modification of non-creatable array value attempted, subscript -1/, "\$a[-1] = 0");
}
+{
+ local $^W = 1;
+ my $a = \$#{[]};
+ is ($$a, undef, "\$# on freed array is undef");
+ my @warn;
+ local $SIG{__WARN__} = sub {push @warn, "@_"};
+ $$a = 1000;
+ is (scalar @warn, 1);
+ like ($warn[0], qr/^Attempt to set length of freed array/);
+}