From eb428d9568f244a3c64a37b4ea41b4a868c0afc4 Mon Sep 17 00:00:00 2001 From: vmakhnychev Date: Mon, 15 Jul 2024 14:16:59 +0400 Subject: [PATCH 1/3] get rid of 'reference not set to an instance of an object' error, which appears when context is null --- Jint/AstExtensions.cs | 15 ++++++++++++--- Jint/Engine.cs | 6 +++--- Jint/Native/Function/EvalFunction.cs | 13 ++++++++++++- .../Interpreter/Expressions/JintExpression.cs | 2 +- 4 files changed, 28 insertions(+), 8 deletions(-) diff --git a/Jint/AstExtensions.cs b/Jint/AstExtensions.cs index 3cab91dde5..bdf61e089f 100644 --- a/Jint/AstExtensions.cs +++ b/Jint/AstExtensions.cs @@ -79,7 +79,16 @@ or NodeType.FunctionExpression or NodeType.YieldExpression or NodeType.TemplateLiteral) { - var context = engine._activeEvaluationContext; + var context = new EvaluationContext(); + + if (engine._activeEvaluationContext == null) + { + context = new EvaluationContext(engine); + } + else + { + context = engine._activeEvaluationContext; + } return JintExpression.Build(expression).GetValue(context!); } @@ -152,7 +161,7 @@ internal static bool IsAnonymousFunctionDefinition(this T node) where T : Nod internal static bool IsOptional(this T node) where T : Expression { return node is IChainElement { Optional: true }; - } + } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static string LiteralKeyToString(Literal literal) @@ -318,7 +327,7 @@ internal static Record DefineMethod(this T m, ObjectInstance obj, ObjectInsta var runningExecutionContext = engine.ExecutionContext; var env = runningExecutionContext.LexicalEnvironment; - var privateEnv= runningExecutionContext.PrivateEnvironment; + var privateEnv = runningExecutionContext.PrivateEnvironment; var prototype = functionPrototype ?? intrinsics.Function.PrototypeObject; var function = m.Value as IFunction; diff --git a/Jint/Engine.cs b/Jint/Engine.cs index 3c50a94e85..2ba6a12429 100644 --- a/Jint/Engine.cs +++ b/Jint/Engine.cs @@ -62,7 +62,7 @@ public sealed partial class Engine : IDisposable internal readonly Dictionary TypeCache = new(StringComparer.Ordinal); // we use registered type reference as prototype if it's known - internal Dictionary? _typeReferences; + internal Dictionary? _typeReferences; // cache for already wrapped CLR objects to keep object identity internal ConditionalWeakTable? _objectWrapperCache; @@ -459,7 +459,7 @@ private Engine ScriptEvaluation(ScriptRecord scriptRecord, ParserOptions parserO // TODO what about callstack and thrown exceptions? RunAvailableContinuations(); - return this; + return this; } finally { @@ -1243,7 +1243,7 @@ internal void EvalDeclarationInstantiation( { foreach (var name in pointer.Names) { - privateIdentifiers??= new HashSet(PrivateIdentifierNameComparer._instance); + privateIdentifiers ??= new HashSet(PrivateIdentifierNameComparer._instance); privateIdentifiers.Add(name.Key); } diff --git a/Jint/Native/Function/EvalFunction.cs b/Jint/Native/Function/EvalFunction.cs index 4aa9af4baf..84980222bb 100644 --- a/Jint/Native/Function/EvalFunction.cs +++ b/Jint/Native/Function/EvalFunction.cs @@ -1,6 +1,7 @@ using Jint.Runtime; using Jint.Runtime.Descriptors; using Jint.Runtime.Environments; +using Jint.Runtime.Interpreter; using Jint.Runtime.Interpreter.Statements; using Environment = Jint.Runtime.Environments.Environment; @@ -178,7 +179,17 @@ internal JsValue PerformEval(JsValue x, Realm callerRealm, bool strictCaller, bo Engine.EvalDeclarationInstantiation(script, varEnv, lexEnv, privateEnv, strictEval); var statement = new JintScript(script); - var result = statement.Execute(_engine._activeEvaluationContext!); + var result = new Completion(); + + if (_engine._activeEvaluationContext == null) + { + result = statement.Execute(new EvaluationContext(_engine)); + } + else + { + result = statement.Execute(_engine._activeEvaluationContext); + } + var value = result.GetValueOrDefault(); if (result.Type == CompletionType.Throw) diff --git a/Jint/Runtime/Interpreter/Expressions/JintExpression.cs b/Jint/Runtime/Interpreter/Expressions/JintExpression.cs index 4a5f0f9feb..2767688dd6 100644 --- a/Jint/Runtime/Interpreter/Expressions/JintExpression.cs +++ b/Jint/Runtime/Interpreter/Expressions/JintExpression.cs @@ -132,7 +132,7 @@ protected internal static JintExpression Build(Expression expression) : new JintMemberExpression((MemberExpression) ((ChainExpression) expression).Expression), NodeType.AwaitExpression => new JintAwaitExpression((AwaitExpression) expression), NodeType.YieldExpression => new JintYieldExpression((YieldExpression) expression), - _ => null + _ => null }; if (result is null) From a4e1d114d621f6659da6982d1189e4f155abe5d4 Mon Sep 17 00:00:00 2001 From: vmakhnychev Date: Tue, 16 Jul 2024 16:30:29 +0400 Subject: [PATCH 2/3] added test which shows that before the fix null context will throw 'Object reference not set to an instance of an object' --- Jint.Tests/Runtime/EvaluationContextTests.cs | 15 +++++++++++++++ Jint/AstExtensions.cs | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 Jint.Tests/Runtime/EvaluationContextTests.cs diff --git a/Jint.Tests/Runtime/EvaluationContextTests.cs b/Jint.Tests/Runtime/EvaluationContextTests.cs new file mode 100644 index 0000000000..62fdaf5217 --- /dev/null +++ b/Jint.Tests/Runtime/EvaluationContextTests.cs @@ -0,0 +1,15 @@ +namespace Jint.Tests.Runtime +{ + public class EvaluationContextTests + { + [Fact] + public void ShouldThrowJavaScriptException() + { + var mockedEngine = new Engine(); + + Expression expression = new Identifier(NodeType.MemberExpression.ToString()); + + Assert.Throws(() => AstExtensions.TryGetComputedPropertyKey(expression, mockedEngine)); + } + } +} diff --git a/Jint/AstExtensions.cs b/Jint/AstExtensions.cs index bdf61e089f..33b7bcfc7a 100644 --- a/Jint/AstExtensions.cs +++ b/Jint/AstExtensions.cs @@ -62,7 +62,7 @@ internal static JsValue TryGetKey(this T expression, Engine engine, bool reso return key; } - private static JsValue TryGetComputedPropertyKey(T expression, Engine engine) + internal static JsValue TryGetComputedPropertyKey(T expression, Engine engine) where T : Expression { if (expression.Type is NodeType.Identifier From 15b57fe1e03a1de700ce6b2306500892c44dbf36 Mon Sep 17 00:00:00 2001 From: Marko Lahma Date: Wed, 17 Jul 2024 20:43:42 +0300 Subject: [PATCH 3/3] tweaks --- Jint.Tests/Runtime/EvaluationContextTests.cs | 17 ++++++++--------- Jint/AstExtensions.cs | 13 ++----------- Jint/Native/Function/EvalFunction.cs | 12 ++---------- 3 files changed, 12 insertions(+), 30 deletions(-) diff --git a/Jint.Tests/Runtime/EvaluationContextTests.cs b/Jint.Tests/Runtime/EvaluationContextTests.cs index 62fdaf5217..1cdb4f3f97 100644 --- a/Jint.Tests/Runtime/EvaluationContextTests.cs +++ b/Jint.Tests/Runtime/EvaluationContextTests.cs @@ -1,15 +1,14 @@ -namespace Jint.Tests.Runtime +namespace Jint.Tests.Runtime; + +public class EvaluationContextTests { - public class EvaluationContextTests + [Fact] + public void ShouldThrowJavaScriptException() { - [Fact] - public void ShouldThrowJavaScriptException() - { - var mockedEngine = new Engine(); + var mockedEngine = new Engine(); - Expression expression = new Identifier(NodeType.MemberExpression.ToString()); + Expression expression = new Identifier(NodeType.MemberExpression.ToString()); - Assert.Throws(() => AstExtensions.TryGetComputedPropertyKey(expression, mockedEngine)); - } + Assert.Throws(() => AstExtensions.TryGetComputedPropertyKey(expression, mockedEngine)); } } diff --git a/Jint/AstExtensions.cs b/Jint/AstExtensions.cs index 33b7bcfc7a..a5583f1e3e 100644 --- a/Jint/AstExtensions.cs +++ b/Jint/AstExtensions.cs @@ -79,17 +79,8 @@ or NodeType.FunctionExpression or NodeType.YieldExpression or NodeType.TemplateLiteral) { - var context = new EvaluationContext(); - - if (engine._activeEvaluationContext == null) - { - context = new EvaluationContext(engine); - } - else - { - context = engine._activeEvaluationContext; - } - return JintExpression.Build(expression).GetValue(context!); + var context = engine._activeEvaluationContext ?? new EvaluationContext(engine); + return JintExpression.Build(expression).GetValue(context); } return JsValue.Undefined; diff --git a/Jint/Native/Function/EvalFunction.cs b/Jint/Native/Function/EvalFunction.cs index 84980222bb..099067c488 100644 --- a/Jint/Native/Function/EvalFunction.cs +++ b/Jint/Native/Function/EvalFunction.cs @@ -179,16 +179,8 @@ internal JsValue PerformEval(JsValue x, Realm callerRealm, bool strictCaller, bo Engine.EvalDeclarationInstantiation(script, varEnv, lexEnv, privateEnv, strictEval); var statement = new JintScript(script); - var result = new Completion(); - - if (_engine._activeEvaluationContext == null) - { - result = statement.Execute(new EvaluationContext(_engine)); - } - else - { - result = statement.Execute(_engine._activeEvaluationContext); - } + var context = _engine._activeEvaluationContext ?? new EvaluationContext(_engine); + var result = statement.Execute(context); var value = result.GetValueOrDefault();