This fixes RT #75596.
pr |int |magic_regdatum_set|NN SV* sv|NN MAGIC* mg
p |int |magic_set |NN SV* sv|NN MAGIC* mg
p |int |magic_setarylen|NN SV* sv|NN MAGIC* mg
+p |int |magic_cleararylen_p|NN SV* sv|NN MAGIC* mg
p |int |magic_freearylen_p|NN SV* sv|NN MAGIC* mg
p |int |magic_setdbline|NN SV* sv|NN MAGIC* mg
p |int |magic_setdefelem|NN SV* sv|NN MAGIC* mg
#define list(a) Perl_list(aTHX_ a)
#define localize(a,b) Perl_localize(aTHX_ a,b)
#define magic_clear_all_env(a,b) Perl_magic_clear_all_env(aTHX_ a,b)
+#define magic_cleararylen_p(a,b) Perl_magic_cleararylen_p(aTHX_ a,b)
#define magic_clearenv(a,b) Perl_magic_clearenv(aTHX_ a,b)
#define magic_clearhint(a,b) Perl_magic_clearhint(aTHX_ a,b)
#define magic_clearhints(a,b) Perl_magic_clearhints(aTHX_ a,b)
}
int
+Perl_magic_cleararylen_p(pTHX_ SV *sv, MAGIC *mg)
+{
+ dVAR;
+
+ PERL_ARGS_ASSERT_MAGIC_CLEARARYLEN_P;
+ PERL_UNUSED_ARG(sv);
+
+ /* Reset the iterator when the array is cleared */
+ if (mg->mg_ptr)
+ *((IV *) mg->mg_ptr) = 0;
+
+ return 0;
+}
+
+int
Perl_magic_freearylen_p(pTHX_ SV *sv, MAGIC *mg)
{
dVAR;
#ifdef DOINIT
EXT_MGVTBL PL_magic_vtables[magic_vtable_max] = {
{ (int (*)(pTHX_ SV *, MAGIC *))Perl_magic_getarylen, Perl_magic_setarylen, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, Perl_magic_freearylen_p, 0, 0, 0 },
+ { 0, 0, 0, Perl_magic_cleararylen_p, Perl_magic_freearylen_p, 0, 0, 0 },
{ 0, 0, 0, 0, Perl_magic_killbackrefs, 0, 0, 0 },
{ 0, 0, 0, 0, 0, Perl_magic_copycallchecker, 0, 0 },
#ifdef USE_LOCALE_COLLATE
read. This ensures that testing C<$@> first (as recommended by the
documentation) always returns the correct result.
+=item *
+
+The array iterator used for the C<each @array> construct is now correctly
+reset when C<@array> is cleared (RT #75596). This happens for example when the
+array is globally assigned to, as in C<@array = (...)>, but not when its
+B<values> are assigned to. In terms of the XS API, it means that C<av_clear()>
+will now reset the iterator.
+
+This mirrors the behaviour of the hash iterator when the hash is cleared.
+
=back
=head1 Known Problems
#define PERL_ARGS_ASSERT_MAGIC_CLEAR_ALL_ENV \
assert(sv); assert(mg)
+PERL_CALLCONV int Perl_magic_cleararylen_p(pTHX_ SV* sv, MAGIC* mg)
+ __attribute__nonnull__(pTHX_1)
+ __attribute__nonnull__(pTHX_2);
+#define PERL_ARGS_ASSERT_MAGIC_CLEARARYLEN_P \
+ assert(sv); assert(mg)
+
PERL_CALLCONV int Perl_magic_clearenv(pTHX_ SV* sv, MAGIC* mg)
__attribute__nonnull__(pTHX_1)
__attribute__nonnull__(pTHX_2);
'isa' => {set => 'setisa', clear => 'clearisa'},
'isaelem' => {set => 'setisa'},
'arylen' => {get => 'getarylen', set => 'setarylen', const => 1},
- 'arylen_p' => {free => 'freearylen_p'},
+ 'arylen_p' => {clear => 'cleararylen_p', free => 'freearylen_p'},
'mglob' => {set => 'setmglob'},
'nkeys' => {get => 'getnkeys', set => 'setnkeys'},
'taint' => {get => 'gettaint', set => 'settaint'},
use warnings;
use vars qw(@array @r $k $v $c);
-plan tests => 57;
+plan tests => 63;
@array = qw(crunch zam bloop);
is ($k, $v);
$v++;
}
+
+# Reset the iterator when the array is cleared [RT #75596]
+{
+ my @a = 'a' .. 'c';
+ my ($i, $v) = each @a;
+ is ("$i-$v", '0-a');
+ @a = 'A' .. 'C';
+ ($i, $v) = each @a;
+ is ("$i-$v", '0-A');
+}
+
+# Check that the iterator is reset when localization ends
+{
+ @array = 'a' .. 'c';
+ my ($i, $v) = each @array;
+ is ("$i-$v", '0-a');
+ {
+ local @array = 'A' .. 'C';
+ my ($i, $v) = each @array;
+ is ("$i-$v", '0-A');
+ ($i, $v) = each @array;
+ is ("$i-$v", '1-B');
+ }
+ ($i, $v) = each @array;
+ is ("$i-$v", '1-b');
+ # Explicit reset
+ while (each @array) { }
+}