Browse Source

Fixed RegExp.toString() throws a NullReferenceException if not called… (#640)

miroslav22 6 years ago
parent
commit
8dbd95abdd

+ 1 - 1
Jint.Tests/Runtime/EngineTests.cs

@@ -2026,7 +2026,7 @@ var prep = function (fn) { fn(); };
         [Fact]
         [Fact]
         public void RegExpPrototypeToString()
         public void RegExpPrototypeToString()
         {
         {
-            RunTest("assert(RegExp.prototype.toString() === '//');");
+            RunTest("assert(RegExp.prototype.toString() === '/(?:)/');");
         }
         }
 
 
         [Fact]
         [Fact]

+ 30 - 2
Jint.Tests/Runtime/RegExpTests.cs

@@ -36,10 +36,38 @@ namespace Jint.Tests.Runtime
         public void PreventsInfiniteLoop()
         public void PreventsInfiniteLoop()
         {
         {
             var engine = new Engine();
             var engine = new Engine();
-            var result = (ArrayInstance) engine.Execute("'x'.match(/|/g);").GetCompletionValue();
-            Assert.Equal((uint) 2, result.Length);
+            var result = (ArrayInstance)engine.Execute("'x'.match(/|/g);").GetCompletionValue();
+            Assert.Equal((uint)2, result.Length);
             Assert.Equal("", result[0]);
             Assert.Equal("", result[0]);
             Assert.Equal("", result[1]);
             Assert.Equal("", result[1]);
         }
         }
+
+        [Fact]
+        public void ToStringWithNonRegExpInstanceAndMissingProperties()
+        {
+            var engine = new Engine();
+            var result = engine.Execute("/./['toString'].call({})").GetCompletionValue().AsString();
+
+            Assert.Equal("/undefined/undefined", result);
+        }
+
+        [Fact]
+        public void ToStringWithNonRegExpInstanceAndValidProperties()
+        {
+            var engine = new Engine();
+            var result = engine.Execute("/./['toString'].call({ source: 'a', flags: 'b' })").GetCompletionValue().AsString();
+
+            Assert.Equal("/a/b", result);
+        }
+
+
+        [Fact]
+        public void ToStringWithRealRegExpInstance()
+        {
+            var engine = new Engine();
+            var result = engine.Execute("/./['toString'].call(/test/g)").GetCompletionValue().AsString();
+
+            Assert.Equal("/test/g", result);
+        }
     }
     }
 }
 }

+ 1 - 0
Jint/Native/RegExp/RegExpConstructor.cs

@@ -182,6 +182,7 @@ namespace Jint.Native.RegExp
             r.SetOwnProperty("ignoreCase", new PropertyDescriptor(r.IgnoreCase, PropertyFlag.AllForbidden));
             r.SetOwnProperty("ignoreCase", new PropertyDescriptor(r.IgnoreCase, PropertyFlag.AllForbidden));
             r.SetOwnProperty("multiline", new PropertyDescriptor(r.Multiline, PropertyFlag.AllForbidden));
             r.SetOwnProperty("multiline", new PropertyDescriptor(r.Multiline, PropertyFlag.AllForbidden));
             r.SetOwnProperty("source", new PropertyDescriptor(r.Source, PropertyFlag.AllForbidden));
             r.SetOwnProperty("source", new PropertyDescriptor(r.Source, PropertyFlag.AllForbidden));
+            r.SetOwnProperty("flags", new PropertyDescriptor(r.Flags, PropertyFlag.AllForbidden));
             r.SetOwnProperty("lastIndex", new PropertyDescriptor(0, PropertyFlag.OnlyWritable));
             r.SetOwnProperty("lastIndex", new PropertyDescriptor(0, PropertyFlag.OnlyWritable));
         }
         }
 
 

+ 9 - 10
Jint/Native/RegExp/RegExpPrototype.cs

@@ -1,6 +1,7 @@
 using System.Text.RegularExpressions;
 using System.Text.RegularExpressions;
 using Jint.Collections;
 using Jint.Collections;
 using Jint.Native.Array;
 using Jint.Native.Array;
+using Jint.Native.Object;
 using Jint.Runtime;
 using Jint.Runtime;
 using Jint.Runtime.Descriptors;
 using Jint.Runtime.Descriptors;
 using Jint.Runtime.Interop;
 using Jint.Runtime.Interop;
@@ -40,24 +41,22 @@ namespace Jint.Native.RegExp
                 ["ignoreCase"] = new PropertyDescriptor(false, false, false, false),
                 ["ignoreCase"] = new PropertyDescriptor(false, false, false, false),
                 ["multiline"] = new PropertyDescriptor(false, false, false, false),
                 ["multiline"] = new PropertyDescriptor(false, false, false, false),
                 ["source"] = new PropertyDescriptor("(?:)", false, false, false),
                 ["source"] = new PropertyDescriptor("(?:)", false, false, false),
+                ["flags"] = new PropertyDescriptor("", false, false, false),
                 ["lastIndex"] = new PropertyDescriptor(0, true, false, false)
                 ["lastIndex"] = new PropertyDescriptor(0, true, false, false)
             };
             };
         }
         }
 
 
         private static JsValue ToRegExpString(JsValue thisObj, JsValue[] arguments)
         private static JsValue ToRegExpString(JsValue thisObj, JsValue[] arguments)
         {
         {
-            var regExp = thisObj.TryCast<RegExpInstance>();
+            var regexObj = thisObj.TryCast<ObjectInstance>();
+            
+            if (regexObj.TryGetValue("source", out var source) == false)
+                source = Undefined.ToString();
 
 
-            string res = "/" + regExp.Source + "/";
-            if (regExp.Flags != null)
-            {
-                res += (regExp.Flags.Contains("g") ? "g" : "")
-                    + (regExp.Flags.Contains("i") ? "i" : "")
-                    + (regExp.Flags.Contains("m") ? "m" : "")
-                ;
-            }
+            if (regexObj.TryGetValue("flags", out var flags) == false)
+                flags = Undefined.ToString();
 
 
-            return res;
+            return $"/{source.AsString()}/{flags.AsString()}";
         }
         }
 
 
         private JsValue Test(JsValue thisObj, JsValue[] arguments)
         private JsValue Test(JsValue thisObj, JsValue[] arguments)