From 56c133a9614ac2fdacd1ae54c4d96c6b52de9291 Mon Sep 17 00:00:00 2001 From: Hecate2 <2474101468@qq.com> Date: Wed, 2 Oct 2024 15:07:05 +0800 Subject: [PATCH 1/4] reentrancy analyzer test --- .../Contract_Reentrancy.cs | 27 +++++++++++++ .../SecurityAnalyzer/UnitTest_Reentrancy.cs | 21 ++++++++++ .../TestingArtifacts/Contract_Reentrancy.cs | 38 +++++++++++++++++++ 3 files changed, 86 insertions(+) create mode 100644 tests/Neo.Compiler.CSharp.TestContracts/Contract_SecurityAnalyzer/Contract_Reentrancy.cs create mode 100644 tests/Neo.Compiler.CSharp.UnitTests/SecurityAnalyzer/UnitTest_Reentrancy.cs create mode 100644 tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_Reentrancy.cs diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_SecurityAnalyzer/Contract_Reentrancy.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_SecurityAnalyzer/Contract_Reentrancy.cs new file mode 100644 index 000000000..5287ddf27 --- /dev/null +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_SecurityAnalyzer/Contract_Reentrancy.cs @@ -0,0 +1,27 @@ +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Native; +using Neo.SmartContract.Framework.Services; +using System; + +namespace Neo.Compiler.CSharp.TestContracts +{ + public class Contract_Reentrancy : SmartContract.Framework.SmartContract + { + public static void HasReentrancy() + { + try + { + Contract.Call(NEO.Hash, "transfer", CallFlags.All, [UInt160.Zero, UInt160.Zero, 0, null]); + } + catch + { + Storage.Put(Storage.CurrentContext, new byte[] { 0x01 }, 1); + } + } + public static void NoReentrancy() + { + Storage.Put(Storage.CurrentContext, new byte[] { 0x01 }, 1); + Contract.Call(NEO.Hash, "transfer", CallFlags.All, [UInt160.Zero, UInt160.Zero, 0, null]); + } + } +} diff --git a/tests/Neo.Compiler.CSharp.UnitTests/SecurityAnalyzer/UnitTest_Reentrancy.cs b/tests/Neo.Compiler.CSharp.UnitTests/SecurityAnalyzer/UnitTest_Reentrancy.cs new file mode 100644 index 000000000..47eb387b3 --- /dev/null +++ b/tests/Neo.Compiler.CSharp.UnitTests/SecurityAnalyzer/UnitTest_Reentrancy.cs @@ -0,0 +1,21 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Compiler.SecurityAnalyzer; +using Neo.Optimizer; +using Neo.SmartContract.Testing; +using System.Linq; + +namespace Neo.Compiler.CSharp.UnitTests.Optimizer +{ + [TestClass] + public class ReentrancyTests : DebugAndTestBase + { + [TestMethod] + public void Test_HasReentrancy() + { + ReEntrancyAnalyzer.ReEntrancyVulnerabilityPair v = + ReEntrancyAnalyzer.AnalyzeSingleContractReEntrancy(NefFile, Manifest); + Assert.AreEqual(v.vulnerabilityPairs.Count, 1); + v.GetWarningInfo(print: false); + } + } +} diff --git a/tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_Reentrancy.cs b/tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_Reentrancy.cs new file mode 100644 index 000000000..dd16571d3 --- /dev/null +++ b/tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_Reentrancy.cs @@ -0,0 +1,38 @@ +using Neo.Cryptography.ECC; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Numerics; + +namespace Neo.SmartContract.Testing; + +public abstract class Contract_Reentrancy(Neo.SmartContract.Testing.SmartContractInitialize initialize) : Neo.SmartContract.Testing.SmartContract(initialize), IContractInfo +{ + #region Compiled data + + public static Neo.SmartContract.Manifest.ContractManifest Manifest => Neo.SmartContract.Manifest.ContractManifest.Parse(@"{""name"":""Contract_Reentrancy"",""groups"":[],""features"":{},""supportedstandards"":[],""abi"":{""methods"":[{""name"":""hasReentrancy"",""parameters"":[],""returntype"":""Void"",""offset"":0,""safe"":false},{""name"":""noReentrancy"",""parameters"":[],""returntype"":""Void"",""offset"":115,""safe"":false}],""events"":[]},""permissions"":[],""trusts"":[],""extra"":{""nef"":{""optimization"":""All""}}}"); + + /// + /// Optimization: "All" + /// + public static Neo.SmartContract.NefFile Nef => Neo.IO.Helper.AsSerializable(Convert.FromBase64String(@"TkVGM1Rlc3RpbmdFbmdpbmUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANtXAQA7XAALEAwUAAAAAAAAAAAAAAAAAAAAAAAAAAAMFAAAAAAAAAAAAAAAAAAAAAAAAAAAFMAfDAh0cmFuc2ZlcgwU9WPqQLwoPU0OBcSOowWz8qBzQO9BYn1bUkU9FXARDAEB2zBBm/ZnzkHmPxiEPQJAEQwBAdswQZv2Z85B5j8YhAsQDBQAAAAAAAAAAAAAAAAAAAAAAAAAAAwUAAAAAAAAAAAAAAAAAAAAAAAAAAAUwB8MCHRyYW5zZmVyDBT1Y+pAvCg9TQ4FxI6jBbPyoHNA70FifVtSRUB2Hcnz")); + + #endregion + + #region Unsafe methods + + /// + /// Unsafe method + /// + [DisplayName("hasReentrancy")] + public abstract void HasReentrancy(); + + /// + /// Unsafe method + /// + [DisplayName("noReentrancy")] + public abstract void NoReentrancy(); + + #endregion + +} From d7ad6df5e1fd8497964dcf9d75621d6a6d3ffe0d Mon Sep 17 00:00:00 2001 From: Hecate2 <2474101468@qq.com> Date: Wed, 2 Oct 2024 15:17:48 +0800 Subject: [PATCH 2/4] reentrancy from method call --- .../Contract_Reentrancy.cs | 10 ++++++++++ .../SecurityAnalyzer/UnitTest_Reentrancy.cs | 5 ++++- .../TestingArtifacts/Contract_Reentrancy.cs | 16 ++++++++++++++-- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_SecurityAnalyzer/Contract_Reentrancy.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_SecurityAnalyzer/Contract_Reentrancy.cs index 5287ddf27..e027f4280 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_SecurityAnalyzer/Contract_Reentrancy.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_SecurityAnalyzer/Contract_Reentrancy.cs @@ -18,10 +18,20 @@ public static void HasReentrancy() Storage.Put(Storage.CurrentContext, new byte[] { 0x01 }, 1); } } + public static void HasReentrancyFromCall() + { + Contract.Call(GAS.Hash, "transfer", CallFlags.All, [UInt160.Zero, UInt160.Zero, 0, null]); + NoReentrancy(); + } public static void NoReentrancy() { Storage.Put(Storage.CurrentContext, new byte[] { 0x01 }, 1); Contract.Call(NEO.Hash, "transfer", CallFlags.All, [UInt160.Zero, UInt160.Zero, 0, null]); } + public static void NoReentrancyFromCall() + { + Storage.Put(Storage.CurrentContext, new byte[] { 0x01 }, 1); + NoReentrancy(); + } } } diff --git a/tests/Neo.Compiler.CSharp.UnitTests/SecurityAnalyzer/UnitTest_Reentrancy.cs b/tests/Neo.Compiler.CSharp.UnitTests/SecurityAnalyzer/UnitTest_Reentrancy.cs index 47eb387b3..d220e1b56 100644 --- a/tests/Neo.Compiler.CSharp.UnitTests/SecurityAnalyzer/UnitTest_Reentrancy.cs +++ b/tests/Neo.Compiler.CSharp.UnitTests/SecurityAnalyzer/UnitTest_Reentrancy.cs @@ -14,7 +14,10 @@ public void Test_HasReentrancy() { ReEntrancyAnalyzer.ReEntrancyVulnerabilityPair v = ReEntrancyAnalyzer.AnalyzeSingleContractReEntrancy(NefFile, Manifest); - Assert.AreEqual(v.vulnerabilityPairs.Count, 1); + Assert.AreEqual(v.vulnerabilityPairs.Count, 2); + foreach (BasicBlock b in v.vulnerabilityPairs.Keys) + // basic blocks calling contract + Assert.IsTrue(b.startAddr < NefFile.Size * 0.66); v.GetWarningInfo(print: false); } } diff --git a/tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_Reentrancy.cs b/tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_Reentrancy.cs index dd16571d3..e2d214677 100644 --- a/tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_Reentrancy.cs +++ b/tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_Reentrancy.cs @@ -10,12 +10,12 @@ public abstract class Contract_Reentrancy(Neo.SmartContract.Testing.SmartContrac { #region Compiled data - public static Neo.SmartContract.Manifest.ContractManifest Manifest => Neo.SmartContract.Manifest.ContractManifest.Parse(@"{""name"":""Contract_Reentrancy"",""groups"":[],""features"":{},""supportedstandards"":[],""abi"":{""methods"":[{""name"":""hasReentrancy"",""parameters"":[],""returntype"":""Void"",""offset"":0,""safe"":false},{""name"":""noReentrancy"",""parameters"":[],""returntype"":""Void"",""offset"":115,""safe"":false}],""events"":[]},""permissions"":[],""trusts"":[],""extra"":{""nef"":{""optimization"":""All""}}}"); + public static Neo.SmartContract.Manifest.ContractManifest Manifest => Neo.SmartContract.Manifest.ContractManifest.Parse(@"{""name"":""Contract_Reentrancy"",""groups"":[],""features"":{},""supportedstandards"":[],""abi"":{""methods"":[{""name"":""hasReentrancy"",""parameters"":[],""returntype"":""Void"",""offset"":0,""safe"":false},{""name"":""hasReentrancyFromCall"",""parameters"":[],""returntype"":""Void"",""offset"":115,""safe"":false},{""name"":""noReentrancy"",""parameters"":[],""returntype"":""Void"",""offset"":205,""safe"":false},{""name"":""noReentrancyFromCall"",""parameters"":[],""returntype"":""Void"",""offset"":309,""safe"":false}],""events"":[]},""permissions"":[],""trusts"":[],""extra"":{""nef"":{""optimization"":""All""}}}"); /// /// Optimization: "All" /// - public static Neo.SmartContract.NefFile Nef => Neo.IO.Helper.AsSerializable(Convert.FromBase64String(@"TkVGM1Rlc3RpbmdFbmdpbmUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANtXAQA7XAALEAwUAAAAAAAAAAAAAAAAAAAAAAAAAAAMFAAAAAAAAAAAAAAAAAAAAAAAAAAAFMAfDAh0cmFuc2ZlcgwU9WPqQLwoPU0OBcSOowWz8qBzQO9BYn1bUkU9FXARDAEB2zBBm/ZnzkHmPxiEPQJAEQwBAdswQZv2Z85B5j8YhAsQDBQAAAAAAAAAAAAAAAAAAAAAAAAAAAwUAAAAAAAAAAAAAAAAAAAAAAAAAAAUwB8MCHRyYW5zZmVyDBT1Y+pAvCg9TQ4FxI6jBbPyoHNA70FifVtSRUB2Hcnz")); + public static Neo.SmartContract.NefFile Nef => Neo.IO.Helper.AsSerializable(Convert.FromBase64String(@"TkVGM1Rlc3RpbmdFbmdpbmUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP1IAVcBADtcAAsQDBQAAAAAAAAAAAAAAAAAAAAAAAAAAAwUAAAAAAAAAAAAAAAAAAAAAAAAAAAUwB8MCHRyYW5zZmVyDBT1Y+pAvCg9TQ4FxI6jBbPyoHNA70FifVtSRT0VcBEMAQHbMEGb9mfOQeY/GIQ9AkALEAwUAAAAAAAAAAAAAAAAAAAAAAAAAAAMFAAAAAAAAAAAAAAAAAAAAAAAAAAAFMAfDAh0cmFuc2ZlcgwUz3bii9AGLEpHjuNVYQETGfPPpNJBYn1bUkU0A0ARDAEB2zBBm/ZnzkHmPxiECxAMFAAAAAAAAAAAAAAAAAAAAAAAAAAADBQAAAAAAAAAAAAAAAAAAAAAAAAAABTAHwwIdHJhbnNmZXIMFPVj6kC8KD1NDgXEjqMFs/Kgc0DvQWJ9W1JFQBEMAQHbMEGb9mfOQeY/GIQ0iEDnAAGw")); #endregion @@ -27,12 +27,24 @@ public abstract class Contract_Reentrancy(Neo.SmartContract.Testing.SmartContrac [DisplayName("hasReentrancy")] public abstract void HasReentrancy(); + /// + /// Unsafe method + /// + [DisplayName("hasReentrancyFromCall")] + public abstract void HasReentrancyFromCall(); + /// /// Unsafe method /// [DisplayName("noReentrancy")] public abstract void NoReentrancy(); + /// + /// Unsafe method + /// + [DisplayName("noReentrancyFromCall")] + public abstract void NoReentrancyFromCall(); + #endregion } From b52ba858130a06e1f7d604d3ac55b29d06e9c8f7 Mon Sep 17 00:00:00 2001 From: Hecate2 <2474101468@qq.com> Date: Wed, 2 Oct 2024 15:23:49 +0800 Subject: [PATCH 3/4] single basic block reentancy; no reentrancy by jumps --- .../Contract_Reentrancy.cs | 12 ++++++++++++ .../SecurityAnalyzer/UnitTest_Reentrancy.cs | 2 +- .../TestingArtifacts/Contract_Reentrancy.cs | 16 ++++++++++++++-- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_SecurityAnalyzer/Contract_Reentrancy.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_SecurityAnalyzer/Contract_Reentrancy.cs index e027f4280..cab77b5df 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_SecurityAnalyzer/Contract_Reentrancy.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_SecurityAnalyzer/Contract_Reentrancy.cs @@ -18,6 +18,11 @@ public static void HasReentrancy() Storage.Put(Storage.CurrentContext, new byte[] { 0x01 }, 1); } } + public static void HasReentrancyFromSingleBasicBlock() + { + Contract.Call(NEO.Hash, "transfer", CallFlags.All, [UInt160.Zero, UInt160.Zero, 0, null]); + Storage.Put(Storage.CurrentContext, new byte[] { 0x01 }, 1); + } public static void HasReentrancyFromCall() { Contract.Call(GAS.Hash, "transfer", CallFlags.All, [UInt160.Zero, UInt160.Zero, 0, null]); @@ -33,5 +38,12 @@ public static void NoReentrancyFromCall() Storage.Put(Storage.CurrentContext, new byte[] { 0x01 }, 1); NoReentrancy(); } + public static void NoReentrancyFromJump(bool input) + { + if (input) + Contract.Call(GAS.Hash, "transfer", CallFlags.All, [UInt160.Zero, UInt160.Zero, 0, null]); + else + Storage.Put(Storage.CurrentContext, new byte[] { 0x01 }, 1); + } } } diff --git a/tests/Neo.Compiler.CSharp.UnitTests/SecurityAnalyzer/UnitTest_Reentrancy.cs b/tests/Neo.Compiler.CSharp.UnitTests/SecurityAnalyzer/UnitTest_Reentrancy.cs index d220e1b56..93ea304f6 100644 --- a/tests/Neo.Compiler.CSharp.UnitTests/SecurityAnalyzer/UnitTest_Reentrancy.cs +++ b/tests/Neo.Compiler.CSharp.UnitTests/SecurityAnalyzer/UnitTest_Reentrancy.cs @@ -14,7 +14,7 @@ public void Test_HasReentrancy() { ReEntrancyAnalyzer.ReEntrancyVulnerabilityPair v = ReEntrancyAnalyzer.AnalyzeSingleContractReEntrancy(NefFile, Manifest); - Assert.AreEqual(v.vulnerabilityPairs.Count, 2); + Assert.AreEqual(v.vulnerabilityPairs.Count, 3); foreach (BasicBlock b in v.vulnerabilityPairs.Keys) // basic blocks calling contract Assert.IsTrue(b.startAddr < NefFile.Size * 0.66); diff --git a/tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_Reentrancy.cs b/tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_Reentrancy.cs index e2d214677..fd869576a 100644 --- a/tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_Reentrancy.cs +++ b/tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_Reentrancy.cs @@ -10,12 +10,12 @@ public abstract class Contract_Reentrancy(Neo.SmartContract.Testing.SmartContrac { #region Compiled data - public static Neo.SmartContract.Manifest.ContractManifest Manifest => Neo.SmartContract.Manifest.ContractManifest.Parse(@"{""name"":""Contract_Reentrancy"",""groups"":[],""features"":{},""supportedstandards"":[],""abi"":{""methods"":[{""name"":""hasReentrancy"",""parameters"":[],""returntype"":""Void"",""offset"":0,""safe"":false},{""name"":""hasReentrancyFromCall"",""parameters"":[],""returntype"":""Void"",""offset"":115,""safe"":false},{""name"":""noReentrancy"",""parameters"":[],""returntype"":""Void"",""offset"":205,""safe"":false},{""name"":""noReentrancyFromCall"",""parameters"":[],""returntype"":""Void"",""offset"":309,""safe"":false}],""events"":[]},""permissions"":[],""trusts"":[],""extra"":{""nef"":{""optimization"":""All""}}}"); + public static Neo.SmartContract.Manifest.ContractManifest Manifest => Neo.SmartContract.Manifest.ContractManifest.Parse(@"{""name"":""Contract_Reentrancy"",""groups"":[],""features"":{},""supportedstandards"":[],""abi"":{""methods"":[{""name"":""hasReentrancy"",""parameters"":[],""returntype"":""Void"",""offset"":0,""safe"":false},{""name"":""hasReentrancyFromSingleBasicBlock"",""parameters"":[],""returntype"":""Void"",""offset"":115,""safe"":false},{""name"":""hasReentrancyFromCall"",""parameters"":[],""returntype"":""Void"",""offset"":219,""safe"":false},{""name"":""noReentrancy"",""parameters"":[],""returntype"":""Void"",""offset"":309,""safe"":false},{""name"":""noReentrancyFromCall"",""parameters"":[],""returntype"":""Void"",""offset"":413,""safe"":false},{""name"":""noReentrancyFromJump"",""parameters"":[{""name"":""input"",""type"":""Boolean""}],""returntype"":""Void"",""offset"":432,""safe"":false}],""events"":[]},""permissions"":[],""trusts"":[],""extra"":{""nef"":{""optimization"":""All""}}}"); /// /// Optimization: "All" /// - public static Neo.SmartContract.NefFile Nef => Neo.IO.Helper.AsSerializable(Convert.FromBase64String(@"TkVGM1Rlc3RpbmdFbmdpbmUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP1IAVcBADtcAAsQDBQAAAAAAAAAAAAAAAAAAAAAAAAAAAwUAAAAAAAAAAAAAAAAAAAAAAAAAAAUwB8MCHRyYW5zZmVyDBT1Y+pAvCg9TQ4FxI6jBbPyoHNA70FifVtSRT0VcBEMAQHbMEGb9mfOQeY/GIQ9AkALEAwUAAAAAAAAAAAAAAAAAAAAAAAAAAAMFAAAAAAAAAAAAAAAAAAAAAAAAAAAFMAfDAh0cmFuc2ZlcgwUz3bii9AGLEpHjuNVYQETGfPPpNJBYn1bUkU0A0ARDAEB2zBBm/ZnzkHmPxiECxAMFAAAAAAAAAAAAAAAAAAAAAAAAAAADBQAAAAAAAAAAAAAAAAAAAAAAAAAABTAHwwIdHJhbnNmZXIMFPVj6kC8KD1NDgXEjqMFs/Kgc0DvQWJ9W1JFQBEMAQHbMEGb9mfOQeY/GIQ0iEDnAAGw")); + public static Neo.SmartContract.NefFile Nef => Neo.IO.Helper.AsSerializable(Convert.FromBase64String(@"TkVGM1Rlc3RpbmdFbmdpbmUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP0fAlcBADtcAAsQDBQAAAAAAAAAAAAAAAAAAAAAAAAAAAwUAAAAAAAAAAAAAAAAAAAAAAAAAAAUwB8MCHRyYW5zZmVyDBT1Y+pAvCg9TQ4FxI6jBbPyoHNA70FifVtSRT0VcBEMAQHbMEGb9mfOQeY/GIQ9AkALEAwUAAAAAAAAAAAAAAAAAAAAAAAAAAAMFAAAAAAAAAAAAAAAAAAAAAAAAAAAFMAfDAh0cmFuc2ZlcgwU9WPqQLwoPU0OBcSOowWz8qBzQO9BYn1bUkURDAEB2zBBm/ZnzkHmPxiEQAsQDBQAAAAAAAAAAAAAAAAAAAAAAAAAAAwUAAAAAAAAAAAAAAAAAAAAAAAAAAAUwB8MCHRyYW5zZmVyDBTPduKL0AYsSkeO41VhARMZ88+k0kFifVtSRTQDQBEMAQHbMEGb9mfOQeY/GIQLEAwUAAAAAAAAAAAAAAAAAAAAAAAAAAAMFAAAAAAAAAAAAAAAAAAAAAAAAAAAFMAfDAh0cmFuc2ZlcgwU9WPqQLwoPU0OBcSOowWz8qBzQO9BYn1bUkVAEQwBAdswQZv2Z85B5j8YhDSIQFcAAXgmWgsQDBQAAAAAAAAAAAAAAAAAAAAAAAAAAAwUAAAAAAAAAAAAAAAAAAAAAAAAAAAUwB8MCHRyYW5zZmVyDBTPduKL0AYsSkeO41VhARMZ88+k0kFifVtSRUARDAEB2zBBm/ZnzkHmPxiEQEZXjmg=")); #endregion @@ -33,6 +33,12 @@ public abstract class Contract_Reentrancy(Neo.SmartContract.Testing.SmartContrac [DisplayName("hasReentrancyFromCall")] public abstract void HasReentrancyFromCall(); + /// + /// Unsafe method + /// + [DisplayName("hasReentrancyFromSingleBasicBlock")] + public abstract void HasReentrancyFromSingleBasicBlock(); + /// /// Unsafe method /// @@ -45,6 +51,12 @@ public abstract class Contract_Reentrancy(Neo.SmartContract.Testing.SmartContrac [DisplayName("noReentrancyFromCall")] public abstract void NoReentrancyFromCall(); + /// + /// Unsafe method + /// + [DisplayName("noReentrancyFromJump")] + public abstract void NoReentrancyFromJump(bool? input); + #endregion } From 208ad3b176f0dbbcda32f7099df9790917d28b2b Mon Sep 17 00:00:00 2001 From: Hecate2 <2474101468@qq.com> Date: Wed, 2 Oct 2024 17:39:45 +0800 Subject: [PATCH 4/4] method with [NoReentrant] --- .../Contract_SecurityAnalyzer/Contract_Reentrancy.cs | 7 ++++++- .../SecurityAnalyzer/UnitTest_Reentrancy.cs | 3 +-- .../TestingArtifacts/Contract_Reentrancy.cs | 10 ++++++++-- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_SecurityAnalyzer/Contract_Reentrancy.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_SecurityAnalyzer/Contract_Reentrancy.cs index cab77b5df..896cdf3e6 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_SecurityAnalyzer/Contract_Reentrancy.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_SecurityAnalyzer/Contract_Reentrancy.cs @@ -1,7 +1,7 @@ using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; using Neo.SmartContract.Framework.Native; using Neo.SmartContract.Framework.Services; -using System; namespace Neo.Compiler.CSharp.TestContracts { @@ -45,5 +45,10 @@ public static void NoReentrancyFromJump(bool input) else Storage.Put(Storage.CurrentContext, new byte[] { 0x01 }, 1); } + [NoReentrant] + public static void NoReentrancyByAttribute() + { + HasReentrancyFromSingleBasicBlock(); + } } } diff --git a/tests/Neo.Compiler.CSharp.UnitTests/SecurityAnalyzer/UnitTest_Reentrancy.cs b/tests/Neo.Compiler.CSharp.UnitTests/SecurityAnalyzer/UnitTest_Reentrancy.cs index 93ea304f6..574ab9b9c 100644 --- a/tests/Neo.Compiler.CSharp.UnitTests/SecurityAnalyzer/UnitTest_Reentrancy.cs +++ b/tests/Neo.Compiler.CSharp.UnitTests/SecurityAnalyzer/UnitTest_Reentrancy.cs @@ -2,9 +2,8 @@ using Neo.Compiler.SecurityAnalyzer; using Neo.Optimizer; using Neo.SmartContract.Testing; -using System.Linq; -namespace Neo.Compiler.CSharp.UnitTests.Optimizer +namespace Neo.Compiler.CSharp.UnitTests.SecurityAnalyzer { [TestClass] public class ReentrancyTests : DebugAndTestBase diff --git a/tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_Reentrancy.cs b/tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_Reentrancy.cs index fd869576a..dde4b191c 100644 --- a/tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_Reentrancy.cs +++ b/tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_Reentrancy.cs @@ -10,12 +10,12 @@ public abstract class Contract_Reentrancy(Neo.SmartContract.Testing.SmartContrac { #region Compiled data - public static Neo.SmartContract.Manifest.ContractManifest Manifest => Neo.SmartContract.Manifest.ContractManifest.Parse(@"{""name"":""Contract_Reentrancy"",""groups"":[],""features"":{},""supportedstandards"":[],""abi"":{""methods"":[{""name"":""hasReentrancy"",""parameters"":[],""returntype"":""Void"",""offset"":0,""safe"":false},{""name"":""hasReentrancyFromSingleBasicBlock"",""parameters"":[],""returntype"":""Void"",""offset"":115,""safe"":false},{""name"":""hasReentrancyFromCall"",""parameters"":[],""returntype"":""Void"",""offset"":219,""safe"":false},{""name"":""noReentrancy"",""parameters"":[],""returntype"":""Void"",""offset"":309,""safe"":false},{""name"":""noReentrancyFromCall"",""parameters"":[],""returntype"":""Void"",""offset"":413,""safe"":false},{""name"":""noReentrancyFromJump"",""parameters"":[{""name"":""input"",""type"":""Boolean""}],""returntype"":""Void"",""offset"":432,""safe"":false}],""events"":[]},""permissions"":[],""trusts"":[],""extra"":{""nef"":{""optimization"":""All""}}}"); + public static Neo.SmartContract.Manifest.ContractManifest Manifest => Neo.SmartContract.Manifest.ContractManifest.Parse(@"{""name"":""Contract_Reentrancy"",""groups"":[],""features"":{},""supportedstandards"":[],""abi"":{""methods"":[{""name"":""hasReentrancy"",""parameters"":[],""returntype"":""Void"",""offset"":0,""safe"":false},{""name"":""hasReentrancyFromSingleBasicBlock"",""parameters"":[],""returntype"":""Void"",""offset"":115,""safe"":false},{""name"":""hasReentrancyFromCall"",""parameters"":[],""returntype"":""Void"",""offset"":219,""safe"":false},{""name"":""noReentrancy"",""parameters"":[],""returntype"":""Void"",""offset"":309,""safe"":false},{""name"":""noReentrancyFromCall"",""parameters"":[],""returntype"":""Void"",""offset"":413,""safe"":false},{""name"":""noReentrancyFromJump"",""parameters"":[{""name"":""input"",""type"":""Boolean""}],""returntype"":""Void"",""offset"":432,""safe"":false},{""name"":""noReentrancyByAttribute"",""parameters"":[],""returntype"":""Void"",""offset"":543,""safe"":false},{""name"":""_initialize"",""parameters"":[],""returntype"":""Void"",""offset"":708,""safe"":false}],""events"":[]},""permissions"":[],""trusts"":[],""extra"":{""nef"":{""optimization"":""All""}}}"); /// /// Optimization: "All" /// - public static Neo.SmartContract.NefFile Nef => Neo.IO.Helper.AsSerializable(Convert.FromBase64String(@"TkVGM1Rlc3RpbmdFbmdpbmUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP0fAlcBADtcAAsQDBQAAAAAAAAAAAAAAAAAAAAAAAAAAAwUAAAAAAAAAAAAAAAAAAAAAAAAAAAUwB8MCHRyYW5zZmVyDBT1Y+pAvCg9TQ4FxI6jBbPyoHNA70FifVtSRT0VcBEMAQHbMEGb9mfOQeY/GIQ9AkALEAwUAAAAAAAAAAAAAAAAAAAAAAAAAAAMFAAAAAAAAAAAAAAAAAAAAAAAAAAAFMAfDAh0cmFuc2ZlcgwU9WPqQLwoPU0OBcSOowWz8qBzQO9BYn1bUkURDAEB2zBBm/ZnzkHmPxiEQAsQDBQAAAAAAAAAAAAAAAAAAAAAAAAAAAwUAAAAAAAAAAAAAAAAAAAAAAAAAAAUwB8MCHRyYW5zZmVyDBTPduKL0AYsSkeO41VhARMZ88+k0kFifVtSRTQDQBEMAQHbMEGb9mfOQeY/GIQLEAwUAAAAAAAAAAAAAAAAAAAAAAAAAAAMFAAAAAAAAAAAAAAAAAAAAAAAAAAAFMAfDAh0cmFuc2ZlcgwU9WPqQLwoPU0OBcSOowWz8qBzQO9BYn1bUkVAEQwBAdswQZv2Z85B5j8YhDSIQFcAAXgmWgsQDBQAAAAAAAAAAAAAAAAAAAAAAAAAAAwUAAAAAAAAAAAAAAAAAAAAAAAAAAAUwB8MCHRyYW5zZmVyDBTPduKL0AYsSkeO41VhARMZ88+k0kFifVtSRUARDAEB2zBBm/ZnzkHmPxiEQEZXjmg=")); + public static Neo.SmartContract.NefFile Nef => Neo.IO.Helper.AsSerializable(Convert.FromBase64String(@"TkVGM1Rlc3RpbmdFbmdpbmUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP3UAlcBADtcAAsQDBQAAAAAAAAAAAAAAAAAAAAAAAAAAAwUAAAAAAAAAAAAAAAAAAAAAAAAAAAUwB8MCHRyYW5zZmVyDBT1Y+pAvCg9TQ4FxI6jBbPyoHNA70FifVtSRT0VcBEMAQHbMEGb9mfOQeY/GIQ9AkALEAwUAAAAAAAAAAAAAAAAAAAAAAAAAAAMFAAAAAAAAAAAAAAAAAAAAAAAAAAAFMAfDAh0cmFuc2ZlcgwU9WPqQLwoPU0OBcSOowWz8qBzQO9BYn1bUkURDAEB2zBBm/ZnzkHmPxiEQAsQDBQAAAAAAAAAAAAAAAAAAAAAAAAAAAwUAAAAAAAAAAAAAAAAAAAAAAAAAAAUwB8MCHRyYW5zZmVyDBTPduKL0AYsSkeO41VhARMZ88+k0kFifVtSRTQDQBEMAQHbMEGb9mfOQeY/GIQLEAwUAAAAAAAAAAAAAAAAAAAAAAAAAAAMFAAAAAAAAAAAAAAAAAAAAAAAAAAAFMAfDAh0cmFuc2ZlcgwU9WPqQLwoPU0OBcSOowWz8qBzQO9BYn1bUkVAEQwBAdswQZv2Z85B5j8YhDSIQFcAAXgmWgsQDBQAAAAAAAAAAAAAAAAAAAAAAAAAAAwUAAAAAAAAAAAAAAAAAAAAAAAAAAAUwB8MCHRyYW5zZmVyDBTPduKL0AYsSkeO41VhARMZ88+k0kFifVtSRUARDAEB2zBBm/ZnzkHmPxiEQFjYJh4LCxLASlnPDAtub1JlZW50cmFudAH/ABJNNBJgWDQ1NTH+//9YNWgAAABAVwADeDQfekp4EVHQRUGb9mfOeRGIThBR0FASwEp4EFHQRUBXAAFAVwEBeBHOeBDOwUVTi1BBkl3oMXBoC5cMD0FscmVhZHkgZW50ZXJlZOEReBHOeBDOwUVTi1BB5j8YhEBXAAF4Ec54EM7BRVOLUEEvWMXtQFYCCur///8Kqv///xLAYUBpepbw")); #endregion @@ -45,6 +45,12 @@ public abstract class Contract_Reentrancy(Neo.SmartContract.Testing.SmartContrac [DisplayName("noReentrancy")] public abstract void NoReentrancy(); + /// + /// Unsafe method + /// + [DisplayName("noReentrancyByAttribute")] + public abstract void NoReentrancyByAttribute(); + /// /// Unsafe method ///