[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