summaryrefslogtreecommitdiff
path: root/mg.c
diff options
context:
space:
mode:
authorFather Chrysostomos <sprout@cpan.org>2013-11-03 04:23:43 -0800
committerFather Chrysostomos <sprout@cpan.org>2013-11-04 05:10:18 -0800
commitca58dfd9e0b19f1ae344f4aea62e3e4193f9c34f (patch)
treed5144a5a62e6b4593eacb65377b13c37af7f0d8e /mg.c
parent5a34f1cdd2a19f0ff733c8488b899233b60188db (diff)
downloadperl-ca58dfd9e0b19f1ae344f4aea62e3e4193f9c34f.tar.gz
mg.c: Fix misuse of AvARRAY in defelem_target
defelem magic does not usually apply to tied arrays, but an array can be tied after a defelem has been created and points to it. The code for handling deferred elements was never updated for tied arrays when those were added, so it still does AvFILL and AvARRAY. AvFILL works on tied arrays, and calls FETCHSIZE. But AvARRAY accesses the AV’s internal structure. So AvFILL might suggest that the index is within the array, whereas it is actually past the end of AvARRAY. By tying the array after a deferred element with a high index has been created and then extending the tied array (so AvFILL returns a big number), we can make AvARRAY[big number] crash. This script: use Tie::Array; sub { tie @a, "Tie::StdArray"; $#a = 20000; warn pre; "$_[0]"; warn post }->($a[10000]); gives this output: pre at -e line 5. Segmentation fault: 11 For tied arrays, we need to use av_fetch, rather than AvARRAY.
Diffstat (limited to 'mg.c')
-rw-r--r--mg.c7
1 files changed, 7 insertions, 0 deletions
diff --git a/mg.c b/mg.c
index 83aafa4016..e8d22a33a9 100644
--- a/mg.c
+++ b/mg.c
@@ -2299,7 +2299,14 @@ Perl_defelem_target(pTHX_ SV *sv, MAGIC *mg)
else if (LvSTARGOFF(sv) >= 0) {
AV *const av = MUTABLE_AV(LvTARG(sv));
if (LvSTARGOFF(sv) <= AvFILL(av))
+ {
+ if (SvRMAGICAL(av)) {
+ SV * const * const svp = av_fetch(av, LvSTARGOFF(sv), 0);
+ targ = svp ? *svp : NULL;
+ }
+ else
targ = AvARRAY(av)[LvSTARGOFF(sv)];
+ }
}
if (targ && (targ != &PL_sv_undef)) {
/* somebody else defined it for us */