Browse Source

ensure string immutability on assignment (#694)

Marko Lahma 5 years ago
parent
commit
5d07e896a8

+ 34 - 0
Jint.Tests/Runtime/StringTests.cs

@@ -0,0 +1,34 @@
+using System;
+using Xunit;
+
+namespace Jint.Tests.Runtime
+{
+    public class StringTests
+    {
+        public StringTests()
+        {
+            _engine = new Engine()
+                .SetValue("log", new Action<object>(Console.WriteLine))
+                .SetValue("assert", new Action<bool>(Assert.True))
+                .SetValue("equal", new Action<object, object>(Assert.Equal));
+        }
+
+        private readonly Engine _engine;
+
+        [Fact]
+        public void StringConcatenationAndReferences()
+        {
+            const string script = @"
+var foo = 'foo';
+foo += 'foo';
+var bar = foo;
+bar += 'bar';
+";
+            var value = _engine.Execute(script);
+            var foo = _engine.Execute("foo").GetCompletionValue().AsString();
+            var bar = _engine.Execute("bar").GetCompletionValue().AsString();
+            Assert.Equal("foofoo", foo);
+            Assert.Equal("foofoobar", bar);
+        }
+    }
+}

+ 5 - 0
Jint/Native/JsString.cs

@@ -233,6 +233,11 @@ namespace Jint.Native
 
 
                 return base.Equals(other);
                 return base.Equals(other);
             }
             }
+
+            internal override JsValue Clone()
+            {
+                return ToString();
+            }
         }
         }
     }
     }
 }
 }

+ 9 - 0
Jint/Native/JsValue.cs

@@ -6,6 +6,7 @@ using System.Runtime.CompilerServices;
 using System.Threading;
 using System.Threading;
 using Jint.Native.Array;
 using Jint.Native.Array;
 using Jint.Native.Date;
 using Jint.Native.Date;
+using Jint.Native.Function;
 using Jint.Native.Iterator;
 using Jint.Native.Iterator;
 using Jint.Native.Object;
 using Jint.Native.Object;
 using Jint.Native.RegExp;
 using Jint.Native.RegExp;
@@ -584,5 +585,13 @@ namespace Jint.Native
                 }
                 }
             }
             }
         }
         }
+
+        /// <summary>
+        /// Some values need to be cloned in order to be assigned, like ConcatenatedString.
+        /// </summary>
+        internal virtual JsValue Clone()
+        {
+            return this;
+        }
     }
     }
 }
 }

+ 1 - 1
Jint/Runtime/Interpreter/Expressions/JintAssignmentExpression.cs

@@ -228,7 +228,7 @@ namespace Jint.Runtime.Interpreter.Expressions
                         ExceptionHelper.ThrowSyntaxError(engine);
                         ExceptionHelper.ThrowSyntaxError(engine);
                     }
                     }
 
 
-                    var rval = right.GetValue();
+                    var rval = right.GetValue().Clone();
 
 
                     if (right._expression.IsFunctionWithName())
                     if (right._expression.IsFunctionWithName())
                     {
                     {

+ 1 - 1
Jint/Runtime/Interpreter/Statements/JintVariableDeclaration.cs

@@ -87,7 +87,7 @@ namespace Jint.Runtime.Interpreter.Statements
                         var lhs = (Reference) declaration.Left.Evaluate();
                         var lhs = (Reference) declaration.Left.Evaluate();
                         lhs.AssertValid(_engine);
                         lhs.AssertValid(_engine);
 
 
-                        var value = declaration.Init.GetValue();
+                        var value = declaration.Init.GetValue().Clone();
 
 
                         if (declaration.Init._expression.IsFunctionWithName())
                         if (declaration.Init._expression.IsFunctionWithName())
                         {
                         {