[Mono-bugs] [Bug 75670][Wis] New - Yield Destroys Reference Values in Current Stack Frame

bugzilla-daemon at bugzilla.ximian.com bugzilla-daemon at bugzilla.ximian.com
Sat Jul 30 13:42:57 EDT 2005


Please do not reply to this email- if you want to comment on the bug, go to the
URL shown below and enter your comments there.

Changed by stephen at covidimus.net.

http://bugzilla.ximian.com/show_bug.cgi?id=75670

--- shadow/75670	2005-07-30 13:42:57.000000000 -0400
+++ shadow/75670.tmp.25031	2005-07-30 13:42:57.000000000 -0400
@@ -0,0 +1,227 @@
+Bug#: 75670
+Product: Mono: Compilers
+Version: 1.1
+OS: 
+OS Details: GNU/Linux
+Status: NEW   
+Resolution: 
+Severity: 
+Priority: Wishlist
+Component: C#
+AssignedTo: mono-bugs at ximian.com                            
+ReportedBy: stephen at covidimus.net               
+QAContact: mono-bugs at ximian.com
+TargetMilestone: ---
+URL: 
+Cc: 
+Summary: Yield Destroys Reference Values in Current Stack Frame
+
+Description of Problem:
+
+Building straight from SVN on 7/30, yielding a value in an iterator, at
+least in some cases, appears to set variables in the current stack frame to
+null after the yield.  That's the symptom, at least, if not the problem. 
+Here's code to repro.  This compiles and works as expected in csc 2.0 beta 2.
+
+==== Begin Code ====
+
+// Yield file members of the current directory first.
+foreach (string child in Directory.GetFiles(Path.Path))
+{
+  Console.WriteLine("Match file: " + ((child == null) ? "null" : child));
+  yield return new XrcFSPath(child);
+}
+
+// Delve into directories to find grandchildren, etc.
+foreach (string child in Directory.GetDirectories(Path.Path))
+{
+  Console.WriteLine("Match directory: " + ((child == null) ? "null" : child));
+  XrcFSPath dirPath = new XrcFSPath(child);
+  // Yield the child itself.
+  yield return dirPath;
+
+  // BUG NOTE: Expect dirPath to not be null here, but "DirPath is null"
+  // gets printed.
+  Console.WriteLine("DirPath is " + ((dirPath == null) ? "null" :
+dirPath.Path));
+  // Yield all grandchildren, etc., through this child.
+  XrcFSPathDescendantIterator childItor =  new
+XrcFSPathDescendantIterator(dirPath);
+  foreach (IXrcDataElement elem in childItor)
+    yield return elem;
+}
+
+==== End Code ====
+
+Weirder: After "yield return dirPath", 'child' also seems to be set to
+null: if I try to construct a new XrcFSPath w/ 'child' to work around the
+bug, I get an ArgumentNullException b/c 'child' has become null after the
+"yield return dirPath".
+
+
+
+Actual Results:
+
+Here's output of a small sample (source included below).  You have to run
+the code in a directory that contains at least one subdirectory to see the
+problem.
+
+==== Program Output Begin ====
+Match file: ./Xircle.Core.dll
+./Xircle.Core.dll
+Match file: ./Xircle.FS.dll
+./Xircle.FS.dll
+Match directory: ./testdir
+./testdir
+DirPath is null
+
+Unhandled Exception: System.ArgumentNullException: Argument cannot be null.
+Parameter name: path
+in <0x00040> TestCode.XrcFSPathIterator:.ctor (TestCode.XrcFSPath path)
+in <0x0000d> TestCode.XrcFSPathDescendantIterator:.ctor (TestCode.XrcFSPath
+path)
+in <0x0025c>
+TestCode.XrcFSPathDescendantIterator+<GetEnumerator>__0:MoveNext ()
+in <0x0014b> TestCode.Program:Main (System.String[] args)
+==== Program Output End ====
+
+
+Expected Results:
+
+Here's what the output should look like, assuming one file in testdir named
+testfile.
+
+==== Program Output Begin ====
+Match file: ./Xircle.Core.dll
+./Xircle.Core.dll
+Match file: ./Xircle.FS.dll
+./Xircle.FS.dll
+Match directory: ./testdir
+./testdir
+DirPath is ./testdir
+Match file: ./testdir/testfile
+./testdir/testfile
+==== Program Output End ====
+
+
+How often does this happen? 
+
+Repeatable.
+
+
+Additional Information:
+
+Here's a sample program that illustrates the problem.
+
+
+using System;
+using System.IO;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace TestCode
+{
+    public class Program
+    {
+        static void Main(String[] args)
+        {
+            XrcFSPath rootPath = new XrcFSPath(".");
+            XrcFSPathDescendantIterator itor = new
+XrcFSPathDescendantIterator(rootPath);
+            foreach(IXrcDataElement elem in itor)
+            {
+                Console.WriteLine(((XrcFSPath) elem).Path);
+            }
+        }
+    }
+
+    public class XrcFSPathDescendantIterator : XrcFSPathIterator
+    {
+        public XrcFSPathDescendantIterator(XrcFSPath path)
+            : base(path)
+        { }
+
+        public override IEnumerator<IXrcDataElement> GetEnumerator()
+        {
+            // NOTE: This is a very straightforward and naive implementation.
+            // It is recursive and creates a bunch of iterator objects.  A
+            // non-recursive solution should probably be coded up when there
+            // is time.
+
+            // Yield file members of the current directory first.
+            foreach (string child in Directory.GetFiles(Path.Path))
+            {
+Console.WriteLine("Match file: " + ((child == null) ? "null" : child));
+                yield return new XrcFSPath(child);
+            }
+
+            // Delve into directories to find grandchildren, etc.
+            foreach (string child in Directory.GetDirectories(Path.Path))
+            {
+Console.WriteLine("Match directory: " + ((child == null) ? "null" : child));
+                XrcFSPath dirPath = new XrcFSPath(child);
+                // Yield the child itself.
+                yield return dirPath;
+
+Console.WriteLine("DirPath is " + ((dirPath == null) ? "null" : dirPath.Path));
+                // Yield all grandchildren, etc., through this child.
+                XrcFSPathDescendantIterator childItor =
+                    new XrcFSPathDescendantIterator(dirPath);
+                foreach (IXrcDataElement elem in childItor)
+                    yield return elem;
+            }
+        }
+    }
+
+    public class XrcFSPath : IXrcDataElement
+    {
+        private string m_path;
+
+        public XrcFSPath(string path)
+        {
+            if (path == null)
+                throw new ArgumentNullException("path");
+
+            m_path = path;
+        }
+
+        public string Path
+        {
+            get { return m_path; }
+        }
+    }
+
+    public abstract class XrcFSPathIterator : IXrcDataIterator
+    {
+        private XrcFSPath m_path;
+
+        public XrcFSPathIterator(XrcFSPath path)
+        {
+            if (path == null)
+                throw new ArgumentNullException("path");
+
+            m_path = path;
+        }
+
+        public XrcFSPath Path
+        {
+            get { return m_path; }
+        }
+
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            return ((XrcFSPathIterator) this).GetEnumerator();
+        }
+
+        public abstract IEnumerator<IXrcDataElement> GetEnumerator();
+    }
+
+    public interface IXrcDataElement
+    {
+        // Elided...
+    }
+
+    public interface IXrcDataIterator : IEnumerable<IXrcDataElement>
+    {
+    }
+}


More information about the mono-bugs mailing list