diff options
author | Ruslan Zakirov <ruz@bestpractical.com> | 2012-10-08 17:32:24 +0400 |
---|---|---|
committer | Father Chrysostomos <sprout@cpan.org> | 2012-12-11 08:59:40 -0800 |
commit | 1baa394bebe0d74f5a4f14772cc9000d6bdc99f7 (patch) | |
tree | fb86c9fe73512735fba9af5be271b1cfd042c1fa /pp_hot.c | |
parent | 499ace3b7bbe6fb3aa489db1fb760ac0a6dbbd1b (diff) | |
download | perl-1baa394bebe0d74f5a4f14772cc9000d6bdc99f7.tar.gz |
fix issues in hash assignment with odd elements
1) unify code path of processing odd case with regular
loop that process pairs. fixes memory leak when key
is magic and dies on fetch.
2) in list context put undef that we added to compensate
odd elements into returned values, so (%h = (1))
returns (1, $h{1}) rather than (1). This is documented
in perldoc perlop:
a list assignment in list context produces the list
of lvalues assigned to.
Here can be a dispute, but:
* that key without value on RHS is still assigned with
undef
* consider (%h = (1,2,3,4,5,6,3)). Returning (1,2,3,undef,5,6)
is much easier than (1,2,5,6,3).
* order of returned elements follows cases with even number
of elements on RHS and duplicates
3) hash assignment with duplicates and odd elements on
RHS was returning wrong results in list context.
Now (%h = (1,1,1)) returns (1,$h{1}).
Diffstat (limited to 'pp_hot.c')
-rw-r--r-- | pp_hot.c | 21 |
1 files changed, 6 insertions, 15 deletions
@@ -957,9 +957,6 @@ S_do_oddball(pTHX_ HV *hash, SV **relem, SV **firstrelem) PERL_ARGS_ASSERT_DO_ODDBALL; if (*relem) { - SV *tmpstr; - const HE *didstore; - if (ckWARN(WARN_MISC)) { const char *err; if (relem == firstrelem && @@ -974,15 +971,6 @@ S_do_oddball(pTHX_ HV *hash, SV **relem, SV **firstrelem) Perl_warner(aTHX_ packWARN(WARN_MISC), "%s", err); } - tmpstr = newSV(0); - didstore = hv_store_ent(hash,*relem,tmpstr,0); - if (SvMAGICAL(hash)) { - if (SvSMAGICAL(tmpstr)) - mg_set(tmpstr); - if (!didstore) - sv_2mortal(tmpstr); - } - TAINT_NOT; } } @@ -1097,6 +1085,7 @@ PP(pp_aassign) while (relem < lastrelem) { /* gobble up all the rest */ HE *didstore; + ODD: sv = *relem ? *relem : &PL_sv_no; relem++; tmpstr = sv_newmortal(); @@ -1125,7 +1114,9 @@ PP(pp_aassign) } if (relem == lastrelem) { do_oddball(hash, relem, firsthashrelem); - relem++; + /* we have lelem to reuse, it's not needed anymore */ + *(relem+1) = NULL; + goto ODD; } LEAVE; } @@ -1249,14 +1240,14 @@ PP(pp_aassign) * obliterates the earlier key. So refresh all values. */ lastrelem -= duplicates; relem = firsthashrelem; - while (relem < lastrelem) { + while (relem <= lastrelem) { HE *he; sv = *relem++; he = hv_fetch_ent(hash, sv, 0, 0); *relem++ = (he ? HeVAL(he) : &PL_sv_undef); } } - SP = lastrelem; + SP = ((lastrelem - firsthashrelem)&1)? lastrelem : lastrelem+1; } else SP = firstrelem + (lastlelem - firstlelem); |