diff options
author | Father Chrysostomos <sprout@cpan.org> | 2013-11-03 04:23:43 -0800 |
---|---|---|
committer | Father Chrysostomos <sprout@cpan.org> | 2013-11-04 05:10:18 -0800 |
commit | ca58dfd9e0b19f1ae344f4aea62e3e4193f9c34f (patch) | |
tree | d5144a5a62e6b4593eacb65377b13c37af7f0d8e /mg.c | |
parent | 5a34f1cdd2a19f0ff733c8488b899233b60188db (diff) | |
download | perl-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.c | 7 |
1 files changed, 7 insertions, 0 deletions
@@ -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 */ |