A new fatal error :
Dave Mitchell [Mon, 21 Apr 2003 13:19:50 +0000 (14:19 +0100)]
Subject: [PATCH] Perl_croak("Use of freed value in iteration")
Message-ID: <20030421121950.GB18189@fdgroup.com>
Message-ID: <20030421125433.GC18189@fdgroup.com>

p4raw-id: //depot/perl@19316

pod/perldiag.pod
pp_hot.c
t/cmd/for.t

index 92c4d8a..3baec3a 100644 (file)
@@ -4225,6 +4225,18 @@ defined B<awk> feature.  Use an explicit printf() or sprintf() instead.
 generally because there's a better way to do it, and also because the
 old way has bad side effects.
 
+=item Use of freed value in iteration (perhaps you modified the iterated array within the loop?)
+
+(F) This is typically caused by code like the following:
+
+    @a = (3,4);
+    @a = () for (1,2,@a);
+
+You are not supposed to modify arrays while they are being iterated over.
+For speed and efficiency reasons, Perl internally does not do full
+reference-counting of iterated items, hence deleting such an item in the
+middle of an iteration causes Perl to see a freed value.
+
 =item Use of reference "%s" as array index
 
 (W misc) You tried to use a reference as an array index; this probably
index e407b7b..b740007 100644 (file)
--- a/pp_hot.c
+++ b/pp_hot.c
@@ -1859,6 +1859,12 @@ PP(pp_iter)
     else {
        sv = AvARRAY(av)[++cx->blk_loop.iterix];
     }
+    if (sv && SvREFCNT(sv) == 0) {
+       *itersvp = Nullsv;
+       Perl_croak(aTHX_
+           "Use of freed value in iteration (perhaps you modified the iterated array within the loop?)");
+    }
+
     if (sv)
        SvTEMP_off(sv);
     else
index 3275c71..3a4bc9b 100755 (executable)
@@ -1,6 +1,6 @@
 #!./perl
 
-print "1..12\n";
+print "1..13\n";
 
 for ($i = 0; $i <= 10; $i++) {
     $x[$i] = $i;
@@ -71,3 +71,8 @@ for ("-3" .. "0") {
     $loop_count++;
 }
 print $loop_count == 4 ? "ok" : "not ok", " 12\n";
+
+# modifying arrays in loops is a no-no
+@a = (3,4);
+eval { @a = () for (1,2,@a) };
+print $@ =~ /Use of freed value in iteration/ ? "ok" : "not ok", " 13\n";