Skip to content

Commit c46bcab

Browse files
committed
Preserve behaviour of allowing an undefined key for tied hash lookups
The previous change prevented the warning, but forced the hash key for defelem to the empty string if the original key was undefined. This wasn't a problem if the hash was already tied when the function was called (and the PVLV created), since the resulting PVLV used packelem magic instead of defelem. But if the hash was tied after the PVLV was created references through the PVLV would be working on $hash{""} instead of $hash{+undef}, breaking this possibly used feature. One issue is whether we want to allow undef keys for tied hash, if we do we should probably make them warn less. Fixes Perl#22423
1 parent b97e089 commit c46bcab

File tree

2 files changed

+57
-6
lines changed

2 files changed

+57
-6
lines changed

mg.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2649,7 +2649,15 @@ Perl_defelem_target(pTHX_ SV *sv, MAGIC *mg)
26492649
if (LvTARGLEN(sv)) {
26502650
if (mg->mg_obj) {
26512651
SV * const ahv = LvTARG(sv);
2652-
SV * const index_sv = SvOK(mg->mg_obj) ? mg->mg_obj : &PL_sv_no;
2652+
/* A call like $h{$s} with $s not defined would warn
2653+
here, which could be confusing. A tied hash could treat
2654+
an undef index specially, so we need to preserve undef
2655+
for a tied hash.
2656+
*/
2657+
SV * const index_sv =
2658+
SvOK(mg->mg_obj) ||
2659+
(SvGMAGICAL(ahv) && mg_find((const SV *)ahv, PERL_MAGIC_tied))
2660+
? mg->mg_obj : &PL_sv_no;
26532661
HE * const he = hv_fetch_ent(MUTABLE_HV(ahv), index_sv, FALSE, 0);
26542662
if (he)
26552663
targ = HeVAL(he);

t/lib/warnings/mg

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,10 @@ Use of uninitialized value $s in hash element at - line 6.
9393
# NAME Use of uninitialized value $_[0] in defined operator (tied)
9494
# github 22423
9595
# should we allow tied hashes to distinguish between undef and ""
96-
# without warning? For now test the current behaviour
96+
# without warning? For now test the current behaviour, this
97+
# didn't produce the warning described in github #22423 since
98+
# if the hash is tied for the call the PVLV uses packelem (tie)
99+
# magic rather than defelem magic
97100
use v5.36;
98101
++$|;
99102
sub f { defined $_[0] }
@@ -124,9 +127,49 @@ sub EXISTS {
124127
}
125128

126129
EXPECT
127-
Use of uninitialized value $s in hash element at - line 9.
128-
Use of uninitialized value in hash element at - line 10.
129-
Use of uninitialized value in hash element at - line 12.
130+
Use of uninitialized value $s in hash element at - line 12.
131+
Use of uninitialized value in hash element at - line 13.
132+
Use of uninitialized value in hash element at - line 15.
130133
1
131-
Use of uninitialized value $s in hash element at - line 13.
134+
Use of uninitialized value $s in hash element at - line 16.
135+
########
136+
# NAME Use of uninitialized value $_[0] in defined operator (tied2)
137+
# github 22423
138+
# In this case we have a tied hash, but it's only tied after the
139+
# PVLV is created for the element. This *does* produce the warning
140+
# complained about in #22423
141+
use v5.36;
142+
++$|;
143+
my %h;
144+
sub f {
145+
tie %h, "Foo";
146+
my $x = defined $_[0];
147+
$_[0] = "tied-undef";
148+
}
149+
my $s;
150+
f($h{$s});
151+
$h{""} = "tied";
152+
say $h{+undef};
153+
154+
package Foo;
132155

156+
sub TIEHASH {
157+
bless {}, shift;
158+
}
159+
sub STORE($self, $index, $val) {
160+
$self->{defined $index ? $index : "+undef"} = $val;
161+
}
162+
sub FETCH($self, $index) {
163+
$self->{defined $index ? $index : "+undef"};
164+
}
165+
sub EXISTS($self, $index) {
166+
exists $self->{defined $index ? $index : "+undef"};
167+
}
168+
sub DELETE($self, $index) {
169+
delete $self->{defined $index ? $index : "+undef"};
170+
}
171+
EXPECT
172+
Use of uninitialized value $s in hash element at - line 14.
173+
Use of uninitialized value $_[0] in scalar assignment at - line 11.
174+
Use of uninitialized value in hash element at - line 16.
175+
tied-undef

0 commit comments

Comments
 (0)