Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VM: avoid checking reference when the stack is not full. #3107

Merged
merged 6 commits into from
Feb 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/Neo.VM/ExecutionEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1681,6 +1681,7 @@ public T Pop<T>() where T : StackItem
/// </summary>
protected virtual void PostExecuteInstruction(Instruction instruction)
{
if (ReferenceCounter.Count < Limits.MaxStackSize) return;
if (ReferenceCounter.CheckZeroReferred() > Limits.MaxStackSize)
throw new InvalidOperationException($"MaxStackSize exceed: {ReferenceCounter.Count}");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does we have a ut that test this exception?

Copy link
Contributor Author

@Jim8y Jim8y Feb 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not a thing for this pr. Its jus keeps conflict and conflic and conflic, please stop considering none pr issues. A single line pr should not take so long to review.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want to trust that this single line doesn't break anything, you must ensure that it works, so yes, this is a thing for this pr.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should break things. It a limit of the vm.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, VM has its limitatoins. 2G at most actally.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dont mean in a bad way.

}
Expand Down
78 changes: 72 additions & 6 deletions tests/Neo.VM.Tests/UT_ReferenceCounter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,11 @@ public void TestCircularReferences()
Assert.AreEqual(VMState.BREAK, debugger.StepInto());
Assert.AreEqual(9, engine.ReferenceCounter.Count);
Assert.AreEqual(VMState.BREAK, debugger.StepInto());
Assert.AreEqual(3, engine.ReferenceCounter.Count);
Assert.AreEqual(6, engine.ReferenceCounter.Count);
Assert.AreEqual(VMState.BREAK, debugger.StepInto());
Assert.AreEqual(2, engine.ReferenceCounter.Count);
Assert.AreEqual(5, engine.ReferenceCounter.Count);
Assert.AreEqual(VMState.HALT, debugger.Execute());
Assert.AreEqual(0, engine.ReferenceCounter.Count);
Assert.AreEqual(4, engine.ReferenceCounter.Count);
}

[TestMethod]
Expand Down Expand Up @@ -156,9 +156,75 @@ public void TestRemoveReferrer()
Assert.AreEqual(VMState.BREAK, debugger.StepInto());
Assert.AreEqual(3, engine.ReferenceCounter.Count);
Assert.AreEqual(VMState.BREAK, debugger.StepInto());
Assert.AreEqual(1, engine.ReferenceCounter.Count);
Assert.AreEqual(2, engine.ReferenceCounter.Count);
Assert.AreEqual(VMState.HALT, debugger.Execute());
Assert.AreEqual(0, engine.ReferenceCounter.Count);
Assert.AreEqual(1, engine.ReferenceCounter.Count);
}

[TestMethod]
public void TestCheckZeroReferredWithArray()
{
using ScriptBuilder sb = new();

sb.EmitPush(ExecutionEngineLimits.Default.MaxStackSize - 1);
sb.Emit(OpCode.NEWARRAY);

// Good with MaxStackSize

using (ExecutionEngine engine = new())
{
engine.LoadScript(sb.ToArray());
Assert.AreEqual(0, engine.ReferenceCounter.Count);

Assert.AreEqual(VMState.HALT, engine.Execute());
Assert.AreEqual((int)ExecutionEngineLimits.Default.MaxStackSize, engine.ReferenceCounter.Count);
}

// Fault with MaxStackSize+1

sb.Emit(OpCode.PUSH1);

using (ExecutionEngine engine = new())
{
engine.LoadScript(sb.ToArray());
Assert.AreEqual(0, engine.ReferenceCounter.Count);

Assert.AreEqual(VMState.FAULT, engine.Execute());
Assert.AreEqual((int)ExecutionEngineLimits.Default.MaxStackSize + 1, engine.ReferenceCounter.Count);
}
}

[TestMethod]
public void TestCheckZeroReferred()
{
using ScriptBuilder sb = new();

for (int x = 0; x < ExecutionEngineLimits.Default.MaxStackSize; x++)
sb.Emit(OpCode.PUSH1);

// Good with MaxStackSize

using (ExecutionEngine engine = new())
{
engine.LoadScript(sb.ToArray());
Assert.AreEqual(0, engine.ReferenceCounter.Count);

Assert.AreEqual(VMState.HALT, engine.Execute());
Assert.AreEqual((int)ExecutionEngineLimits.Default.MaxStackSize, engine.ReferenceCounter.Count);
}

// Fault with MaxStackSize+1

sb.Emit(OpCode.PUSH1);

using (ExecutionEngine engine = new())
{
engine.LoadScript(sb.ToArray());
Assert.AreEqual(0, engine.ReferenceCounter.Count);

Assert.AreEqual(VMState.FAULT, engine.Execute());
Assert.AreEqual((int)ExecutionEngineLimits.Default.MaxStackSize + 1, engine.ReferenceCounter.Count);
}
}

[TestMethod]
Expand All @@ -172,7 +238,7 @@ public void TestArrayNoPush()
Array array = new(engine.ReferenceCounter, new StackItem[] { 1, 2, 3, 4 });
Assert.AreEqual(array.Count, engine.ReferenceCounter.Count);
Assert.AreEqual(VMState.HALT, engine.Execute());
Assert.AreEqual(0, engine.ReferenceCounter.Count);
Assert.AreEqual(array.Count, engine.ReferenceCounter.Count);
}
}
}