edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Initializers.Generated.cs;C480993
File: Initializers.Generated.cs
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Initializers.Generated.cs;C480993  (server)    7/1/2008 4:37 PM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Initializers.Generated.cs;StringGsubEach
@@ -3931,6 +3931,7 @@
             
             module.DefineLibraryMethod("gsub", 0x29, new System.Delegate[] {
                 new System.Func<System.Scripting.Runtime.CodeContext, Ruby.Builtins.MutableString, Ruby.Runtime.BlockParam, Ruby.Builtins.RubyRegex, System.Object>(Ruby.Builtins.MutableStringOps.BlockReplaceAll),
+                new System.Func<System.Scripting.Runtime.CodeContext, Ruby.Builtins.MutableString, Ruby.Runtime.BlockParam, Ruby.Builtins.MutableString, System.Object>(Ruby.Builtins.MutableStringOps.BlockReplaceAll),
                 new System.Func<System.Scripting.Runtime.CodeContext, Ruby.Builtins.MutableString, Ruby.Builtins.RubyRegex, Ruby.Builtins.MutableString, Ruby.Builtins.MutableString>(Ruby.Builtins.MutableStringOps.ReplaceAll),
                 new System.Func<System.Scripting.Runtime.CodeContext, Ruby.Builtins.MutableString, System.Object, Ruby.Builtins.MutableString, Ruby.Builtins.MutableString>(Ruby.Builtins.MutableStringOps.ReplaceAll),
                 new System.Func<System.Scripting.Runtime.CodeContext, Ruby.Builtins.MutableString, Ruby.Builtins.RubyRegex, System.Object, Ruby.Builtins.MutableString>(Ruby.Builtins.MutableStringOps.ReplaceAll),
===================================================================
edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/MutableStringOps.cs;C485016
File: MutableStringOps.cs
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/MutableStringOps.cs;C485016  (server)    7/3/2008 3:34 PM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/MutableStringOps.cs;StringGsubEach
@@ -448,7 +448,7 @@
         [RubyMethod("<<")]
         [RubyMethod("concat")]
         public static MutableString Append(CodeContext/*!*/ context, MutableString/*!*/ self, [NotNull]MutableString/*!*/ other) {
-            RubyUtils.RequiresNotFrozen(context, self);
+            RequireNotFrozenAndIncrVersion(context, self);
             self.Append(other);
             return RubyUtils.FlowTaint(context, other, self);
         }
@@ -462,8 +462,8 @@
         [RubyMethod("<<")]
         [RubyMethod("concat")]
         public static MutableString Append(CodeContext/*!*/ context, MutableString/*!*/ self, int c) {
-            RubyUtils.RequiresNotFrozen(context, self);
-
+            RequireNotFrozenAndIncrVersion(context, self);
+            
             if (c < 0 || c > 255) {
                 throw RubyExceptions.CreateTypeConversionError("Fixnum", "String");
             }
@@ -587,7 +587,7 @@
                 return null;
             }
 
-            RubyUtils.RequiresNotFrozen(context, self);
+            RequireNotFrozenAndIncrVersion(context, self);
 
             // TODO: optimize if the value is not read:
             int result = self.PeekByte(index);
@@ -608,7 +608,7 @@
             if (!InRangeNormalized(self, ref start))
                 return null;
 
-            RubyUtils.RequiresNotFrozen(context, self);
+            RequireNotFrozenAndIncrVersion(context, self);
 
             if (start + length > self.Length) {
                 length = self.Length - start;
@@ -813,7 +813,7 @@
 
         [RubyMethod("[]=")]
         public static MutableString SetChar(CodeContext/*!*/ context, MutableString/*!*/ self, int index, [NotNull]MutableString/*!*/ value) {
-            RubyUtils.RequiresNotFrozen(context, self);
+            RequireNotFrozenAndIncrVersion(context, self);
 
             index = index < 0 ? index + self.Length : index;
             if (index < 0 || index >= self.Length)
@@ -825,14 +825,14 @@
             }
 
             self.Replace(index, 1, value);
-            
+
             RubyUtils.FlowTaint(context, value, self);
             return value;
         }
 
         [RubyMethod("[]=")]
         public static int SetChar(CodeContext/*!*/ context, MutableString/*!*/ self, int index, int value) {
-            RubyUtils.RequiresNotFrozen(context, self);
+            RequireNotFrozenAndIncrVersion(context, self);
 
             index = index < 0 ? index + self.Length : index;
             if (index < 0 || index >= self.Length) {
@@ -865,7 +865,7 @@
         [RubyMethod("[]=")]
         public static MutableString SetChar(CodeContext/*!*/ context, MutableString/*!*/ self, int start, int charsToOverwrite, 
             [NotNull]MutableString/*!*/ value) {
-            RubyUtils.RequiresNotFrozen(context, self);
+            RequireNotFrozenAndIncrVersion(context, self);
 
             if (charsToOverwrite < 0)
                 throw RubyExceptions.CreateIndexError(String.Format("negative length {0}", charsToOverwrite));
@@ -899,6 +899,7 @@
 
                 self.Remove(pos, System.Math.Min(charsToRemove, charsLeftInString));
             }
+
             RubyUtils.FlowTaint(context, value, self);
             return value;
         }
@@ -1027,7 +1028,7 @@
 
         [RubyMethod("capitalize!")]
         public static MutableString CapitalizeInPlace(CodeContext/*!*/ context, MutableString/*!*/ self) {
-            RubyUtils.RequiresNotFrozen(context, self);
+            RequireNotFrozenAndIncrVersion(context, self);
             return CapitalizeMutableString(self) ? self : null;
         }
 
@@ -1049,7 +1050,7 @@
 
         [RubyMethod("downcase!")]
         public static MutableString DownCaseInPlace(CodeContext/*!*/ context, MutableString/*!*/ self) {
-            RubyUtils.RequiresNotFrozen(context, self);
+            RequireNotFrozenAndIncrVersion(context, self);
             return DownCaseMutableString(self) ? self : null;
         }
 
@@ -1072,7 +1073,7 @@
 
         [RubyMethod("swapcase!")]
         public static MutableString SwapCaseInPlace(CodeContext/*!*/ context, MutableString/*!*/ self) {
-            RubyUtils.RequiresNotFrozen(context, self);
+            RequireNotFrozenAndIncrVersion(context, self);
             return SwapCaseMutableString(self) ? self : null;
         }
 
@@ -1094,7 +1095,7 @@
 
         [RubyMethod("upcase!")]
         public static MutableString UpCaseInPlace(CodeContext/*!*/ context, MutableString/*!*/ self) {
-            RubyUtils.RequiresNotFrozen(context, self);
+            RequireNotFrozenAndIncrVersion(context, self);
             return UpCaseMutableString(self) ? self : null;
         }
 
@@ -1268,7 +1269,7 @@
             if (result.Equals(self) || result == null)
                 return null;
 
-            RubyUtils.RequiresNotFrozen(context, self);
+            RequireNotFrozenAndIncrVersion(context, self);
             self.Clear();
             self.Append(result);
             return self;
@@ -1309,7 +1310,7 @@
         [RubyMethod("chop!")]
         public static MutableString ChopInPlace(CodeContext/*!*/ context, MutableString/*!*/ self) {
             if (self.Length == 0) return null;
-            RubyUtils.RequiresNotFrozen(context, self);
+            RequireNotFrozenAndIncrVersion(context, self);
             return Chop(self);
         }
 
@@ -1447,6 +1448,8 @@
         [RubyMethod("each_line")]
         public static object EachLine(CodeContext/*!*/ context, MutableString/*!*/ self, BlockParam block, [NotNull]MutableString/*!*/ separator) {
 
+            int version = self.version;
+
             bool paragraphMode = false;
             MutableString sep = separator;
             if (separator.Length == 0) {
@@ -1491,6 +1494,9 @@
 
                 start = end;
             }
+
+            // Ensure that the underlying string has not been mutated during the iteration
+            RequireNoVersionChange(version, self);
             return self;
         }
 
@@ -1783,14 +1789,30 @@
         public static object BlockReplaceFirst(CodeContext/*!*/ context, MutableString/*!*/ self, [NotNull]BlockParam/*!*/ block, [NotNull]RubyRegex/*!*/ pattern) {
             object blockResult;
             MutableString result;
-            return BlockReplaceN(context, self, block, pattern, 1, true, out blockResult, out result) ? blockResult : result;
+            int version = self.version;
+            object r = BlockReplaceN(context, self, block, pattern, 1, true, out blockResult, out result) ? blockResult : result;
+            RequireNoVersionChange(version, self);
+            return r;
         }
+        
+        [RubyMethod("gsub")]
+        public static object BlockReplaceAll(CodeContext/*!*/ context, MutableString/*!*/ self, [NotNull]BlockParam/*!*/ block, [NotNull]RubyRegex pattern) {
+            object blockResult;
+            MutableString result;
+            int version = self.version;
+            object r = BlockReplaceN(context, self, block, pattern, -1, true, out blockResult, out result) ? blockResult : result;
+            RequireNoVersionChange(version, self);
+            return r;
+        }
 
         [RubyMethod("gsub")]
-        public static object BlockReplaceAll(CodeContext/*!*/ context, MutableString/*!*/ self, [NotNull]BlockParam/*!*/ block, [NotNull]RubyRegex pattern) {
+        public static object BlockReplaceAll(CodeContext/*!*/ context, MutableString/*!*/ self, [NotNull]BlockParam/*!*/ block, [NotNull]MutableString matchString) {
             object blockResult;
             MutableString result;
-            return BlockReplaceN(context, self, block, pattern, -1, true, out blockResult, out result) ? blockResult : result;
+            int version = self.version;
+            object r = BlockReplaceN(context, self, block, new RubyRegex(Regex.Escape(matchString.ToString()), RubyRegexOptions.NONE), -1, true, out blockResult, out result) ? blockResult : result;
+            RequireNoVersionChange(version, self);
+            return r;
         }
 
         [RubyMethod("sub")]
@@ -1887,7 +1909,7 @@
                 return null;
             }
 
-            RubyUtils.RequiresNotFrozen(context, self);
+            RequireNotFrozenAndIncrVersion(context, self);
 
             self.Replace(0, self.Length, builder);
             return RubyUtils.FlowTaint(context, builder, self);
@@ -1895,12 +1917,18 @@
 
         [RubyMethod("sub!")]
         public static object BlockReplaceFirstInPlace(CodeContext/*!*/ context, MutableString/*!*/ self, [NotNull]BlockParam/*!*/ block, [NotNull]RubyRegex/*!*/ pattern) {
-            return ReplaceInPlaceN(context, self, block, pattern, 1);
+            int version = self.version;
+            object r =  ReplaceInPlaceN(context, self, block, pattern, 1);
+            RequireNoVersionChange(version, self);
+            return r;
         }
 
         [RubyMethod("gsub!")]
         public static object BlockReplaceAllInPlace(CodeContext/*!*/ context, MutableString/*!*/ self, [NotNull]BlockParam/*!*/ block, [NotNull]RubyRegex/*!*/ pattern) {
-            return ReplaceInPlaceN(context, self, block, pattern, -1);
+            int version = self.version;
+            object r = ReplaceInPlaceN(context, self, block, pattern, -1);
+            RequireNoVersionChange(version, self);
+            return r;
         }
 
         [RubyMethod("sub!")]
@@ -2180,7 +2208,7 @@
         }
 
         private static MutableString/*!*/ InternalDeleteInPlace(CodeContext/*!*/ context, MutableString/*!*/ self, params object[]/*!*/ str) {
-            RubyUtils.RequiresNotFrozen(context, self);
+            RequireNotFrozenAndIncrVersion(context, self);
 
             MutableString result = InternalDelete(context, self, str);
             if (self.Equals(result))
@@ -2301,7 +2329,7 @@
             if (offset > self.Length || offset < 0)
                 throw RubyExceptions.CreateIndexError(String.Format("index {0} out of string", start));
 
-            RubyUtils.RequiresNotFrozen(context, self);
+            RequireNotFrozenAndIncrVersion(context, self);
             RubyUtils.FlowTaint(context, value, self);
             return self.Insert(offset, value);
         }
@@ -2552,7 +2580,7 @@
 
         [RubyMethod("succ!")]
         public static MutableString/*!*/ SuccInPlace(CodeContext/*!*/ context, MutableString/*!*/ self) {
-            RubyUtils.RequiresNotFrozen(context, self);
+            RequireNotFrozenAndIncrVersion(context, self);
 
             if (self.Length == 0)
                 return self;
@@ -2794,7 +2822,7 @@
             if (original == stripped)
                 return null;
 
-            RubyUtils.RequiresNotFrozen(context, self);
+            RequireNotFrozenAndIncrVersion(context, self);
             self.Clear();
             self.Append(stripped);
             return self;
@@ -2824,7 +2852,7 @@
 
         [RubyMethod("squeeze!")]
         public static MutableString/*!*/ SqueezeInPlace(CodeContext/*!*/ context, MutableString/*!*/ self, [NotNull]params object[] args) {
-            RubyUtils.RequiresNotFrozen(context, self);
+            RequireNotFrozenAndIncrVersion(context, self);
             return SqueezeMutableString(context, self, args);
         }
 
@@ -3069,7 +3097,7 @@
             if (Object.ReferenceEquals(self, other))
                 return self;
 
-            RubyUtils.RequiresNotFrozen(context, self);
+            RequireNotFrozenAndIncrVersion(context, self);
             self.Clear();
             self.Append(other);
             return RubyUtils.FlowTaint(context, other, self);
@@ -3138,7 +3166,7 @@
 
         [RubyMethod("tr!")]
         public static MutableString/*!*/ TrInPlace(CodeContext/*!*/ context, MutableString/*!*/ self, MutableString/*!*/ from, MutableString/*!*/ to) {
-            RubyUtils.RequiresNotFrozen(context, self);
+            RequireNotFrozenAndIncrVersion(context, self);
 
             MutableString result = Tr(context, self, from, to);
             if (self.Equals(result))
@@ -3280,7 +3308,7 @@
 
         [RubyMethod("reverse!")]
         public static MutableString/*!*/ Reverse(CodeContext/*!*/ context, MutableString/*!*/ self) {
-            RubyUtils.RequiresNotFrozen(context, self);
+            RequireNotFrozenAndIncrVersion(context, self);
             return self.Reverse();            
         }
 
@@ -3503,5 +3531,16 @@
         public static RubyArray/*!*/ Unpack(CodeContext/*!*/ context, MutableString/*!*/ self, object format) {
             return Unpack(context, self, Protocols.CastToString(context, format));
         }
+
+        private static void RequireNotFrozenAndIncrVersion(CodeContext/*!*/ context, MutableString/*!*/ self) {
+            RubyUtils.RequiresNotFrozen(context, self);
+            self.version++;
+        }
+
+        private static void RequireNoVersionChange(int previousVersion, MutableString self) {
+            if (previousVersion != self.version) {
+                throw new RuntimeError("string modified");
+            }
+        }
     }
 }
===================================================================
edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Builtins/MutableString.cs;C468100
File: MutableString.cs
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Builtins/MutableString.cs;C468100  (server)    7/7/2008 10:14 AM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Builtins/MutableString.cs;StringGsubEach
@@ -27,7 +27,8 @@
     [DebuggerDisplay("{GetDebugValue()}", Type = "{GetDebugType()}")]
     public partial class MutableString : IEquatable<MutableString>, IComparable<MutableString>, IDuplicable {
         private Content/*!*/ _content; 
-        private Encoding/*!*/ _encoding; 
+        private Encoding/*!*/ _encoding;
+        public int version { get; set; }
 
         // TODO: consider returning the same frozen MutableString instance in the future?
         public static MutableString/*!*/ Empty { get { return MutableString.Create(String.Empty); } }    
===================================================================
edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Tests/Specs/core/string/.spec/each_excludes.txt;C480993
File: each_excludes.txt
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Tests/Specs/core/string/.spec/each_excludes.txt;C480993  (server)    7/7/2008 4:54 PM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Tests/Specs/core/string/.spec/each_excludes.txt;StringGsubEach
@@ -1,1 +1,0 @@
-String#each raises a RuntimeError if the string is modified while substituting
===================================================================
edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Tests/Specs/core/string/.spec/each_line_excludes.txt;C480993
File: each_line_excludes.txt
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Tests/Specs/core/string/.spec/each_line_excludes.txt;C480993  (server)    7/7/2008 4:54 PM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Tests/Specs/core/string/.spec/each_line_excludes.txt;StringGsubEach
@@ -1,1 +1,0 @@
-String#each_line raises a RuntimeError if the string is modified while substituting
===================================================================
edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Tests/Specs/core/string/.spec/gsub_excludes.txt;C485016
File: gsub_excludes.txt
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Tests/Specs/core/string/.spec/gsub_excludes.txt;C485016  (server)    7/3/2008 4:07 PM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Tests/Specs/core/string/.spec/gsub_excludes.txt;StringGsubEach
@@ -1,4 +1,0 @@
-String#gsub with pattern and block sets $~ for access from the block
-String#gsub with pattern and block restores $~ after leaving the block
-String#gsub with pattern and block sets $~ to MatchData of last match and nil when there's none for access from outside
-String#gsub with pattern and block raises a RuntimeError if the string is modified while substituting
===================================================================
