diff options
author | Nicholas Clark <nick@ccl4.org> | 2010-02-25 21:35:39 +0000 |
---|---|---|
committer | Nicholas Clark <nick@ccl4.org> | 2010-05-24 15:50:57 +0100 |
commit | 05d04d9c74ee968bace5e063c9ded74f94b3df24 (patch) | |
tree | 27922dc03aaf175082115331cae0eb7d968c06d1 /pad.c | |
parent | 4cee4ca8b28e9dadc530df8ce100439bc4a78e73 (diff) | |
download | perl-05d04d9c74ee968bace5e063c9ded74f94b3df24.tar.gz |
Don't clone the contents of lexicals in pads.
This stops the values of lexicals in active stack frames in the parent leaking
into the lexicals in the child thread.
With an exception for lexicals with a reference count of > 1, to cope with the
implementation of ?{{ ... }} blocks in regexps. :-(
Diffstat (limited to 'pad.c')
-rw-r--r-- | pad.c | 46 |
1 files changed, 45 insertions, 1 deletions
@@ -1772,6 +1772,7 @@ Perl_padlist_dup(pTHX_ AV *const srcpad, CLONE_PARAMS *const param) I32 ix = AvFILLp((const AV *)AvARRAY(srcpad)[1]); AV *pad1; + const I32 names_fill = AvFILLp((const AV *)(AvARRAY(srcpad)[0])); const AV *const srcpad1 = (const AV *) AvARRAY(srcpad)[1]; SV **oldpad = AvARRAY(srcpad1); SV **names; @@ -1803,7 +1804,50 @@ Perl_padlist_dup(pTHX_ AV *const srcpad, CLONE_PARAMS *const param) AvFILLp(pad1) = ix; for ( ;ix > 0; ix--) { - pad1a[ix] = sv_dup_inc(oldpad[ix], param); + if (!oldpad[ix]) { + pad1a[ix] = NULL; + } else if (names_fill >= ix && names[ix] != &PL_sv_undef) { + const char sigil = SvPVX_const(names[ix])[0]; + if ((SvFLAGS(names[ix]) & SVf_FAKE) + || (SvFLAGS(names[ix]) & SVpad_STATE) + || sigil == '&') + { + /* outer lexical or anon code */ + pad1a[ix] = sv_dup_inc(oldpad[ix], param); + } + else { /* our own lexical */ + if(SvREFCNT(oldpad[ix]) > 1) { + pad1a[ix] = sv_dup_inc(oldpad[ix], param); + } else { + SV *sv; + + if (sigil == '@') + sv = MUTABLE_SV(newAV()); + else if (sigil == '%') + sv = MUTABLE_SV(newHV()); + else + sv = newSV(0); + pad1a[ix] = sv; + SvPADMY_on(sv); + } + } + } + else if (IS_PADGV(oldpad[ix]) || IS_PADCONST(oldpad[ix])) { + pad1a[ix] = sv_dup_inc(oldpad[ix], param); + } + else { + /* save temporaries on recursion? */ + SV * const sv = newSV(0); + pad1a[ix] = sv; + + /* SvREFCNT(oldpad[ix]) != 1 for some code in threads.xs + FIXTHAT before merging this branch. + (And I know how to) */ + if (SvPADMY(oldpad[ix])) + SvPADMY_on(sv); + else + SvPADTMP_on(sv); + } } if (oldpad[0]) { |