edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Initializers.Generated.cs;C490874
File: Initializers.Generated.cs
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Initializers.Generated.cs;C490874  (server)    7/1/2008 4:37 PM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Initializers.Generated.cs;StringGsubVersion
@@ -58,7 +58,7 @@
             ExtendModule(typeof(System.Collections.Generic.IDictionary<System.Object, System.Object>), new System.Action<Ruby.Builtins.RubyModule>(LoadSystem__Collections__Generic__IDictionary_Instance), null, new Ruby.Builtins.RubyModule[] {def18, });
             ExtendModule(typeof(System.Collections.IEnumerable), new System.Action<Ruby.Builtins.RubyModule>(LoadSystem__Collections__IEnumerable_Instance), null, new Ruby.Builtins.RubyModule[] {def18, });
             ExtendModule(typeof(System.Collections.IList), new System.Action<Ruby.Builtins.RubyModule>(LoadSystem__Collections__IList_Instance), null, new Ruby.Builtins.RubyModule[] {def18, });
-            ExtendModule(typeof(System.IComparable), new System.Action<Ruby.Builtins.RubyModule>(LoadSystem__IComparable_Instance), null, new Ruby.Builtins.RubyModule[] {def27, });
+            Ruby.Builtins.RubyModule def31 = ExtendModule(typeof(System.IComparable), new System.Action<Ruby.Builtins.RubyModule>(LoadSystem__IComparable_Instance), null, new Ruby.Builtins.RubyModule[] {def27, });
             ExtendClass(typeof(System.Scripting.Actions.TypeGroup), new System.Action<Ruby.Builtins.RubyModule>(LoadSystem__Scripting__Actions__TypeGroup_Instance), null, new Ruby.Builtins.RubyModule[] {def18, }, null);
             DefineGlobalClass("Array", typeof(Ruby.Builtins.RubyArray), Context.ObjectClass, new System.Action<Ruby.Builtins.RubyModule>(LoadArray_Instance), new System.Action<Ruby.Builtins.RubyModule>(LoadArray_Class), new Ruby.Builtins.RubyModule[] {def18, }, new System.Delegate[] {
                 new System.Func<Ruby.Builtins.RubyArray>(Ruby.Builtins.ArrayOps.CreateArray),
@@ -70,7 +70,7 @@
                 new System.Func<System.Scripting.Runtime.CodeContext, Ruby.Runtime.BlockParam, System.Object, System.Object>(Ruby.Builtins.ArrayOps.CreateArray),
             });
             DefineGlobalClass("Binding", typeof(Ruby.Builtins.Binding), Context.ObjectClass, null, null, Ruby.Builtins.RubyModule.EmptyArray, null);
-            DefineGlobalClass("ClrString", typeof(System.String), Context.ObjectClass, new System.Action<Ruby.Builtins.RubyModule>(LoadClrString_Instance), null, Ruby.Builtins.RubyModule.EmptyArray, null);
+            DefineGlobalClass("ClrString", typeof(System.String), Context.ObjectClass, new System.Action<Ruby.Builtins.RubyModule>(LoadClrString_Instance), null, new Ruby.Builtins.RubyModule[] {def31, }, null);
             DefineGlobalClass("Dir", typeof(Ruby.Builtins.RubyDir), Context.ObjectClass, new System.Action<Ruby.Builtins.RubyModule>(LoadDir_Instance), new System.Action<Ruby.Builtins.RubyModule>(LoadDir_Class), new Ruby.Builtins.RubyModule[] {def18, }, null);
             Ruby.Builtins.RubyClass def28 = Context.ExceptionClass = DefineGlobalClass("Exception", typeof(System.Exception), Context.ObjectClass, new System.Action<Ruby.Builtins.RubyModule>(LoadException_Instance), new System.Action<Ruby.Builtins.RubyModule>(LoadException_Class), Ruby.Builtins.RubyModule.EmptyArray, new System.Delegate[] {
                 new System.Func<Ruby.Builtins.MutableString, System.Exception>(Ruby.Builtins.ExceptionOps.Factory),
@@ -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;C490874
File: MutableStringOps.cs
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/MutableStringOps.cs;C490874  (server)    7/3/2008 3:34 PM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/MutableStringOps.cs;StringGsubVersion
@@ -463,7 +463,7 @@
         [RubyMethod("concat")]
         public static MutableString Append(CodeContext/*!*/ context, MutableString/*!*/ self, int c) {
             RubyUtils.RequiresNotFrozen(context, self);
-
+            
             if (c < 0 || c > 255) {
                 throw RubyExceptions.CreateTypeConversionError("Fixnum", "String");
             }
@@ -592,6 +592,7 @@
             // TODO: optimize if the value is not read:
             int result = self.PeekByte(index);
             self.Remove(index, 1);
+            self.Version++;
             return result;
         }
 
@@ -616,6 +617,7 @@
 
             MutableString result = CreateSubClass(context, self, self.GetSlice(start, length));
             self.Remove(start, length);
+            self.Version++;
             return RubyUtils.FlowTaint(context, self, result);
         }
 
@@ -808,6 +810,7 @@
 
         public static MutableString/*!*/ RemoveChar(MutableString/*!*/ self, int index) {
             self.Remove(index, 1);
+            self.Version++;
             return MutableString.CreateMutable();
         }
 
@@ -825,7 +828,8 @@
             }
 
             self.Replace(index, 1, value);
-            
+
+            self.Version++;
             RubyUtils.FlowTaint(context, value, self);
             return value;
         }
@@ -840,6 +844,7 @@
             }
 
             self.SetByte(index, unchecked((byte)value));
+            self.Version++;
             return value;
         }
 
@@ -899,6 +904,8 @@
 
                 self.Remove(pos, System.Math.Min(charsToRemove, charsLeftInString));
             }
+
+            self.Version++;
             RubyUtils.FlowTaint(context, value, self);
             return value;
         }
@@ -968,6 +975,7 @@
                         changed = true;
                 }
             }
+            str.Version++;
             return changed;
         }
 
@@ -977,6 +985,7 @@
                 if (UpCaseChar(str, i))
                     changed = true;
             }
+            str.Version++;
             return changed;
         }
 
@@ -986,6 +995,7 @@
                 if (DownCaseChar(str, i))
                     changed = true;
             }
+            str.Version++;
             return changed;
         }
 
@@ -995,6 +1005,7 @@
                 if (SwapCaseChar(str, i))
                     changed = true;
             }
+            str.Version++;
             return changed;
         }
 
@@ -1214,6 +1225,7 @@
                     break;
                 }
             }
+            str.Version++;
             return str.GetSlice(0, end);
         }
 
@@ -1238,6 +1250,7 @@
                 result.Remove(length - separator.Length, separator.Length);
             }
 
+            self.Version++;
             return result;
         }
 
@@ -1303,6 +1316,7 @@
             } else {
                 self.Remove(self.Length - 2, 2);
             }
+            self.Version++;
             return self;
         }
 
@@ -1443,6 +1457,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) {
@@ -1493,6 +1509,9 @@
 
                 start = end;
             }
+
+            // Ensure that the underlying string has not been mutated during the iteration
+            RequireNoVersionChange(version, self);
             return self;
         }
 
@@ -1646,10 +1665,14 @@
                     MatchData currentMatch = new MatchData(match, input);
                     localScope.CurrentMatch = currentMatch;
 
+                    int version = input.Version;
                     if (InvokeReplaceBlock(currentMatch, input, result, localScope, block, ref offset, out blockResult)) {
                         // block jumped:
                         return true;
                     }
+                    if (input.Version != version) {
+                        return false;
+                    }
                 }
             } else {
                 throw Assert.Unreachable;
@@ -1781,14 +1804,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")]
@@ -1874,6 +1913,7 @@
             }
 
             self.Replace(0, self.Length, builder);
+            self.Version++;
             return RubyUtils.FlowTaint(context, builder, self);
         }
 
@@ -1888,6 +1928,7 @@
             RubyUtils.RequiresNotFrozen(context, self);
 
             self.Replace(0, self.Length, builder);
+            self.Version++;
             return RubyUtils.FlowTaint(context, builder, self);
         }
 
@@ -2157,6 +2198,7 @@
                     result.Append(self.GetChar(i));
                 }
             }
+            self.Version++;
             return RubyUtils.FlowTaint(context, self, CreateSubClass(context, self, result));
         }
 
@@ -2555,6 +2597,7 @@
             } else {
                 IncrementAlphaNumericChar(self, index);
             }
+            self.Version++;
             return self;
         }
 
@@ -2789,6 +2832,7 @@
             RubyUtils.RequiresNotFrozen(context, self);
             self.Clear();
             self.Append(stripped);
+            self.Version++;
             return self;
         }
 
@@ -2848,6 +2892,7 @@
             s.Remove(k, j-k);
 
             // if not modified return null
+            s.Version++;
             return j == k ? null : s;
         }
 
@@ -3138,6 +3183,7 @@
 
             self.Clear();
             self.Append(result);
+            self.Version++;
             return self;
         }
 
@@ -3273,6 +3319,7 @@
         [RubyMethod("reverse!")]
         public static MutableString/*!*/ Reverse(CodeContext/*!*/ context, MutableString/*!*/ self) {
             RubyUtils.RequiresNotFrozen(context, self);
+            self.Version++;
             return self.Reverse();            
         }
 
@@ -3495,5 +3542,11 @@
         public static RubyArray/*!*/ Unpack(CodeContext/*!*/ context, MutableString/*!*/ self, object format) {
             return Unpack(context, self, Protocols.CastToString(context, format));
         }
+
+        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;StringGsubVersion
@@ -27,8 +27,10 @@
     [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/gsub_spec.rb;C413609
File: gsub_spec.rb
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Tests/Specs/core/string/gsub_spec.rb;C413609  (server)    7/9/2008 9:59 AM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Tests/Specs/core/string/gsub_spec.rb;StringGsubVersion
@@ -255,8 +255,43 @@
   it "raises a RuntimeError if the string is modified while substituting" do
     str = "hello"
     should_raise(RuntimeError) { str.gsub(//) { str[0] = 'x' } }
+    str = "hello"
+    should_raise(RuntimeError) { str.gsub(//) { str.capitalize! } }
+    str = "hello"
+    should_raise(RuntimeError) { str.gsub(//) { str.downcase! } }
+    str = "hello"
+    should_raise(RuntimeError) { str.gsub(//) { str.swapcase! } }
+    str = "hello"
+    should_raise(RuntimeError) { str.gsub(//) { str.upcase! } }
+    str = "hello\n"
+    should_raise(RuntimeError) { str.gsub(//) { str.chomp! } }
+    str = "hello"
+    should_raise(RuntimeError) { str.gsub(//) { str.chop! } }
+    str = "hello"
+    should_raise(RuntimeError) { str.gsub(//) { str.gsub!(/./, ".") } }
+    str = "hello"
+    should_raise(RuntimeError) { str.gsub(//) { str.sub!(/./, ".") } }
+    str = "hello"
+    should_raise(RuntimeError) { str.gsub(//) { str.delete!("l", "lo") } }
+     str = "hello"
+    should_raise(RuntimeError) { str.gsub(//) { str.succ!() } }
+    str = "hello   "
+    should_raise(RuntimeError) { str.gsub(//) { str.strip! } }
+    str = "hello"
+    should_raise(RuntimeError) { str.gsub(//) { str.tr!('aeiou', '*') } }
+    str = "hello"
+    should_raise(RuntimeError) { str.gsub(//) { str.reverse! } }
+    str = "hello"
+    should_raise(RuntimeError) { str.gsub(//) { str.squeeze!('l') } }
+    str = "  hello  "
+    should_raise(RuntimeError) { str.gsub(//) { str.lstrip! } }
+    str = "  hello  "
+    should_raise(RuntimeError) { str.gsub(//) { str.rstrip! } }
+    str  = "hello"
+    should_raise(RuntimeError) { str.gsub(//) {str.tr_s!('l', 'r') } }
   end
   
+  
   it "doesn't interpolate special sequences like \\1 for the block's return value" do
     repl = '\& \0 \1 \` \\\' \+ \\\\ foo'
     "hello".gsub(/(.+)/) { repl }.should == repl
===================================================================
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;StringGsubVersion
@@ -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;StringGsubVersion
@@ -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;StringGsubVersion
@@ -1,4 +1,1 @@
-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
===================================================================
