diff options
author | Father Chrysostomos <sprout@cpan.org> | 2011-12-17 19:22:51 -0800 |
---|---|---|
committer | Father Chrysostomos <sprout@cpan.org> | 2011-12-17 23:19:03 -0800 |
commit | 69930016894689da4e8234c429d5ef26b311e7ec (patch) | |
tree | 850166ef2a979490826efdb5cfd42a12646854c4 /sv.c | |
parent | d6ec5f13c8daa49c1550a4fa54a8410f913203fd (diff) | |
download | perl-69930016894689da4e8234c429d5ef26b311e7ec.tar.gz |
[perl #97988] Nullify PL_last_in_gv when unglobbed
Code like this can cause PL_last_in_gv to point to a coercible glob:
$f{g} = *STDOUT;
readline $f{g};
If $f{g} is then modified such that it is no longer a glob,
PL_last_in_gv ends up pointing to a non-glob:
$f{g} = 3;
If $f{g} is freed now, the PL_last_in_gv-nulling code in sv_clear will
be skipped, as it only applies to globs.
undef %f; # now PL_last_in_gv points to a freed scalar
The resulting freed scalar can be reused by another handle,
*{"foom"} = *other;
causing tell() with no arguments to return the position on *other,
even though *other was no the last handle read from.
This commit fixes it by nulling PL_last_in_gv when a coercible glob
is coerced.
Diffstat (limited to 'sv.c')
-rw-r--r-- | sv.c | 4 |
1 files changed, 4 insertions, 0 deletions
@@ -6116,6 +6116,7 @@ Perl_sv_clear(pTHX_ SV *const orig_sv) /* FIXME. There are probably more unreferenced pointers to SVs * in the interpreter struct that we should check and tidy in * a similar fashion to this: */ + /* See also S_sv_unglob, which does the same thing. */ if ((const GV *)sv == PL_last_in_gv) PL_last_in_gv = NULL; case SVt_PVMG: @@ -9518,6 +9519,9 @@ S_sv_unglob(pTHX_ SV *const sv, U32 flags) set operation as merely an internal storage change. */ if (flags & SV_COW_DROP_PV) SvOK_off(sv); else sv_setsv_flags(sv, temp, 0); + + if ((const GV *)sv == PL_last_in_gv) + PL_last_in_gv = NULL; } /* |