From 4e01c338c8228f99810cffd49107a733cfb4d3c4 Mon Sep 17 00:00:00 2001 From: anatol Date: Mon, 7 Jun 2021 11:51:27 +0300 Subject: [PATCH 1/2] fixed BVM for ARM processors --- bvm/bvm2.cpp | 2 +- bvm/wasm_interpreter.cpp | 43 ++++++++++++++++++++++++++++++++++++++-- bvm/wasm_interpreter.h | 14 +++++++++++++ node/processor.cpp | 6 ++++++ 4 files changed, 62 insertions(+), 3 deletions(-) diff --git a/bvm/bvm2.cpp b/bvm/bvm2.cpp index 576742ca1..f6bc736c3 100644 --- a/bvm/bvm2.cpp +++ b/bvm/bvm2.cpp @@ -160,7 +160,7 @@ namespace bvm2 { ZeroObject(m_Code); ZeroObject(m_Data); ZeroObject(m_LinearMem); - ZeroObject(m_Instruction); + m_Instruction.m_p0 = m_Instruction.m_p1 = nullptr; m_vStack.resize((nStackBytes + sizeof(Wasm::Word) - 1) / sizeof(Wasm::Word), 0); diff --git a/bvm/wasm_interpreter.cpp b/bvm/wasm_interpreter.cpp index 65bfd981c..edc75789d 100644 --- a/bvm/wasm_interpreter.cpp +++ b/bvm/wasm_interpreter.cpp @@ -101,6 +101,8 @@ namespace Wasm { static_assert(!std::numeric_limits::is_signed); // the sign flag must be specified separately T ret = 0; + constexpr unsigned int nBitsMax = sizeof(ret) * 8; + for (unsigned int nShift = 0; ; ) { uint8_t n = Read1(); @@ -116,12 +118,49 @@ namespace Wasm { if constexpr (bSigned) { if (0x40 & n) - ret |= (~static_cast(0) << nShift); + { + // Attention: Bug workaround. + // According to the standard we must pad the remaining bits of the result with 1's. + // However this should only be done if there are bits left. That is, only if nShift is lesser than the number of result bits. + // Original code didn't take care of this. + + if (nShift >= nBitsMax) + { + constexpr uint32_t nBitsJustFed = ((nBitsMax - 1) % 7) + 1; // how many bits were just fed into result + static_assert(nBitsJustFed < 6); // the 0x40 bit was not fed. It's unnecessary + + switch (m_Mode) + { + case Mode::AutoWorkAround: + n &= ~0x40; // safe to remove this flag, it's redundant and didn't have to appear at all + Cast::NotConst(m_p0[-1]) = n; // replace it back! + break; + + case Mode::Emulate_x86: + // emulate the unfixed behavior. On x86 bitshift is effective modulo size of operand + ret |= (~static_cast(0) << (nShift % nBitsMax)); + break; + + case Mode::Standard: + // Standard behavior, ignore padding + break; + + default: + assert(false); + // no break; + case Mode::Restrict: + Fail("Conflicting flags"); + } + } + else + // standard padding + ret |= (~static_cast(0) << nShift); + } } break; } - Test(nShift < sizeof(ret) * 8); + Test(nShift < nBitsMax); } return ret; diff --git a/bvm/wasm_interpreter.h b/bvm/wasm_interpreter.h index cd97b5f1d..235f6034c 100644 --- a/bvm/wasm_interpreter.h +++ b/bvm/wasm_interpreter.h @@ -96,6 +96,16 @@ namespace Wasm { const uint8_t* m_p0; const uint8_t* m_p1; + enum struct Mode { + AutoWorkAround, // automatically remove conflicting flags. Default during compilation + Restrict, // fail if conflicting flags are detected. Default for tx verification + Emulate_x86, // emulate unfixed x86/amd64 behavior + Standard, // Comply to wasm standard. Will be activated on the HF4 + + } m_Mode; + + Reader(Mode eMode = Mode::AutoWorkAround) :m_Mode(eMode) {} + void Ensure(uint32_t n); const uint8_t* Consume(uint32_t n); @@ -327,6 +337,10 @@ namespace Wasm { bool m_ExtCall = false; } m_Dbg; + Processor() + :m_Instruction(Reader::Mode::Emulate_x86) + { + } Word get_Ip() const; void Jmp(uint32_t ip); diff --git a/node/processor.cpp b/node/processor.cpp index f837f23c8..de6678f95 100644 --- a/node/processor.cpp +++ b/node/processor.cpp @@ -2329,6 +2329,7 @@ struct NodeProcessor::BlockInterpretCtx bool m_Temporary = false; // Interpretation will be followed by 'undo', try to avoid heavy state changes (use mem vars whenever applicable) bool m_SkipDefinition = false; // no need to calculate the full definition (i.e. not generating/interpreting a block), MMR updates and etc. can be omitted bool m_LimitExceeded = false; + bool m_TxValidation = false; // tx or block uint8_t m_TxStatus = proto::TxStatus::Unspecified; std::ostream* m_pTxErrorInfo = nullptr; @@ -4445,6 +4446,10 @@ bool NodeProcessor::BlockInterpretCtx::BvmProcessor::Invoke(const bvm2::Contract InitStackPlus(m_Stack.AlignUp(static_cast(krn.m_Args.size()))); m_Stack.PushAlias(krn.m_Args); + m_Instruction.m_Mode = m_Bic.m_TxValidation ? + Wasm::Reader::Mode::Restrict : + Wasm::Reader::Mode::Emulate_x86; + CallFar(cid, iMethod, m_Stack.get_AlasSp()); ECC::Hash::Processor hp; @@ -5553,6 +5558,7 @@ uint8_t NodeProcessor::ValidateTxContextEx(const Transaction& tx, const HeightRa bic.SetAssetHi(*this); bic.m_Temporary = true; + bic.m_TxValidation = true; bic.m_SkipDefinition = true; bic.m_pTxErrorInfo = pExtraInfo; From 066319fe89b09fb8fa3ee40ac7663018254fa0c3 Mon Sep 17 00:00:00 2001 From: anatol Date: Mon, 7 Jun 2021 16:17:24 +0300 Subject: [PATCH 2/2] Shaders: updated sids --- bvm/Shaders/pipe/contract.h | 2 +- bvm/Shaders/sidechain/contract.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bvm/Shaders/pipe/contract.h b/bvm/Shaders/pipe/contract.h index f79892986..cf5dc8689 100644 --- a/bvm/Shaders/pipe/contract.h +++ b/bvm/Shaders/pipe/contract.h @@ -5,7 +5,7 @@ namespace Pipe { #pragma pack (push, 1) // the following structures will be stored in the node in binary form - static const ShaderID s_SID = { 0xf8,0xca,0x04,0x65,0x73,0x78,0x82,0xa0,0x0a,0xdd,0x9b,0x48,0xe8,0xa8,0xae,0x12,0x86,0x0a,0xcb,0xd3,0x4c,0xa0,0x3a,0x38,0x4a,0x4d,0xd9,0x3a,0xbc,0x2b,0x61,0x9e }; + static const ShaderID s_SID = { 0x0e,0x62,0x05,0x20,0xda,0x78,0xe9,0x87,0xe0,0x05,0x9b,0x8d,0x30,0xe4,0x75,0x9e,0x36,0x67,0x7d,0xdd,0x3d,0x2d,0xad,0xfb,0xa4,0xff,0x5c,0x0c,0x85,0xdc,0x26,0xff }; struct Cfg { diff --git a/bvm/Shaders/sidechain/contract.h b/bvm/Shaders/sidechain/contract.h index 9eb0d5420..22c4273a7 100644 --- a/bvm/Shaders/sidechain/contract.h +++ b/bvm/Shaders/sidechain/contract.h @@ -3,7 +3,7 @@ namespace Sidechain { - static const ShaderID s_SID = { 0xea,0x2f,0xa3,0x54,0x9f,0x7a,0xcd,0x72,0x79,0xe1,0x36,0x81,0x2d,0xc7,0xc2,0x30,0x6a,0x70,0xa0,0xd1,0x47,0xef,0x39,0xbe,0xaf,0x5b,0xdd,0x87,0x2c,0x7c,0xc1,0x40 }; + static const ShaderID s_SID = { 0x2e,0x9e,0xf4,0xfd,0x41,0xb6,0x52,0x57,0xc4,0xad,0xf4,0xdf,0x68,0x93,0x79,0xba,0x22,0xb1,0x23,0x50,0x1a,0x88,0xe8,0xbe,0xb1,0x22,0x21,0xae,0x45,0x39,0x68,0xb2 }; #pragma pack (push, 1)