diff options
author | Nicholas Clark <nick@ccl4.org> | 2007-09-19 08:12:09 +0000 |
---|---|---|
committer | Nicholas Clark <nick@ccl4.org> | 2007-09-19 08:12:09 +0000 |
commit | b54b4831042e3002a143d3fcff13b3bad5088c70 (patch) | |
tree | 27aa8960a156889eaaaf419ba915c98f63217bf0 /hv.c | |
parent | 821f5ffa2f9d60b548dcc3fae13ebf47b1875d04 (diff) | |
download | perl-b54b4831042e3002a143d3fcff13b3bad5088c70.tar.gz |
For an LVALUE fetch, "hv_fetch()" will recurse into "hv_store()" for a
hash with magic. Field hashes have u magic, so this recursion triggers.
However, key conversion replaces the original key with the converted
key, so we need to ensure that conversion happens exactly once, else
for a non-idempotent key conversion routine (eg ROT13) we will see
double conversion in this case.
p4raw-id: //depot/perl@31898
Diffstat (limited to 'hv.c')
-rw-r--r-- | hv.c | 29 |
1 files changed, 22 insertions, 7 deletions
@@ -424,8 +424,16 @@ S_hv_fetch_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, return NULL; if (keysv) { - if (SvSMAGICAL(hv) && SvGMAGICAL(hv)) + if (SvSMAGICAL(hv) && SvGMAGICAL(hv) + && !(action & HV_DISABLE_UVAR_XKEY)) { keysv = hv_magic_uvar_xkey(hv, keysv, action); + /* If a fetch-as-store fails on the fetch, then the action is to + recurse once into "hv_store". If we didn't do this, then that + recursive call would call the key conversion routine again. + However, as we replace the original key with the converted + key, this would result in a double conversion, which would show + up as a bug if the conversion routine is not idempotent. */ + } if (flags & HVhek_FREEKEY) Safefree(key); key = SvPV_const(keysv, klen); @@ -489,7 +497,8 @@ S_hv_fetch_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, key) whereas the store is for key (the original) */ entry = hv_fetch_common(hv, NULL, nkey, klen, HVhek_FREEKEY, /* free nkey */ - 0 /* non-LVAL fetch */, + 0 /* non-LVAL fetch */ + | HV_DISABLE_UVAR_XKEY, NULL /* no value */, 0 /* compute hash */); if (!entry && (action & HV_FETCH_LVALUE)) { @@ -497,7 +506,9 @@ S_hv_fetch_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, Do it this way to encourage compiler to tail call optimise. */ entry = hv_fetch_common(hv, keysv, key, klen, - flags, HV_FETCH_ISSTORE, + flags, + HV_FETCH_ISSTORE + | HV_DISABLE_UVAR_XKEY, newSV(0), hash); } else { if (flags & HVhek_FREEKEY) @@ -747,7 +758,8 @@ S_hv_fetch_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, if (env) { sv = newSVpvn(env,len); SvTAINTED_on(sv); - return hv_fetch_common(hv,keysv,key,klen,flags,HV_FETCH_ISSTORE,sv, + return hv_fetch_common(hv, keysv, key, klen, flags, + HV_FETCH_ISSTORE|HV_DISABLE_UVAR_XKEY, sv, hash); } } @@ -772,7 +784,8 @@ S_hv_fetch_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, magic check happen. */ /* gonna assign to this, so it better be there */ return hv_fetch_common(hv, keysv, key, klen, flags, - HV_FETCH_ISSTORE, val, hash); + HV_FETCH_ISSTORE|HV_DISABLE_UVAR_XKEY, val, + hash); /* XXX Surely that could leak if the fetch-was-store fails? Just like the hv_fetch. */ } @@ -954,7 +967,8 @@ S_hv_delete_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, return NULL; if (keysv) { - if (SvSMAGICAL(hv) && SvGMAGICAL(hv)) + if (SvSMAGICAL(hv) && SvGMAGICAL(hv) + && !(d_flags & HV_DISABLE_UVAR_XKEY)) keysv = hv_magic_uvar_xkey(hv, keysv, HV_DELETE); if (k_flags & HVhek_FREEKEY) Safefree(key); @@ -973,7 +987,8 @@ S_hv_delete_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, if (needs_copy) { SV *sv; entry = hv_fetch_common(hv, keysv, key, klen, - k_flags & ~HVhek_FREEKEY, HV_FETCH_LVALUE, + k_flags & ~HVhek_FREEKEY, + HV_FETCH_LVALUE|HV_DISABLE_UVAR_XKEY, NULL, hash); sv = entry ? HeVAL(entry) : NULL; if (sv) { |