diff --git a/src/common/evm_traphandler.cpp b/src/common/evm_traphandler.cpp index e291f55b4..516764f2d 100644 --- a/src/common/evm_traphandler.cpp +++ b/src/common/evm_traphandler.cpp @@ -23,7 +23,6 @@ void EVMCallThreadState::setJITTraces() { return; } uint32_t IgnoredDepth = getTrapState().NumIgnoredFrames; - ZEN_ASSERT(Inst); void *JITCode = Inst->getModule()->getJITCode(); void *JITCodeEnd = static_cast(JITCode) + Inst->getModule()->getJITCodeSize(); @@ -120,14 +119,6 @@ bool initEVMPlatformTrapHandler() { // it. It will either crash synchronously, fix up the instruction // so that execution can continue and return, or trigger a crash by // returning the signal to it's original disposition and returning. - - // Unblock the signal before forwarding to the previous handler, - // preserving the same semantics as when SA_NODEFER was used. - sigset_t SignalSet; - sigemptyset(&SignalSet); - sigaddset(&SignalSet, SigNum); - int UnblockResult = sigprocmask(SIG_UNBLOCK, &SignalSet, nullptr); - ZEN_ASSERT(UnblockResult == 0); if ((PrevSigAction->sa_flags & SA_SIGINFO) != 0) { PrevSigAction->sa_sigaction(SigNum, SigInfo, Ctx); } else if ((void (*)(int))PrevSigAction->sa_sigaction == SIG_DFL || @@ -159,9 +150,9 @@ bool initEVMPlatformTrapHandler() { struct sigaction Handler; memset(&Handler, 0x0, sizeof(struct sigaction)); #ifdef ZEN_ENABLE_VIRTUAL_STACK - Handler.sa_flags = SA_SIGINFO | SA_ONSTACK; + Handler.sa_flags = SA_SIGINFO | SA_NODEFER | SA_ONSTACK; #else - Handler.sa_flags = SA_SIGINFO; + Handler.sa_flags = SA_SIGINFO | SA_NODEFER; #endif // ZEN_ENABLE_VIRTUAL_STACK Handler.sa_sigaction = TrapHandler; sigemptyset(&Handler.sa_mask); diff --git a/src/common/evm_traphandler.h b/src/common/evm_traphandler.h index 3008ecb5d..491846774 100644 --- a/src/common/evm_traphandler.h +++ b/src/common/evm_traphandler.h @@ -77,7 +77,7 @@ class EVMCallThreadState { void restartHandler() { Handling = true; } - void jmpToMarked(int Signum) { siglongjmp(*JmpBuf, Signum); } + void jmpToMarked(int Signum) { longjmp(*JmpBuf, Signum); } void setTrapFrameAddr(void *Addr, void *PC, void *FaultingAddress, uint32_t NumIgnoredFrames) { @@ -148,9 +148,12 @@ bool initEVMPlatformTrapHandler(); // may not used // so need set it when unwind backtrace after ud2 #define SAVE_EVM_HOSTAPI_FRAME_POINTER_TO_TLS \ - void *FrameAddr = __builtin_frame_address(0); \ - auto TLS = common::evm_traphandler::EVMCallThreadState::current(); \ - TLS->setTrapFrameAddr(FrameAddr, nullptr, nullptr, 0); + do { \ + void *FrameAddr = __builtin_frame_address(0); \ + auto *TLS_ = common::evm_traphandler::EVMCallThreadState::current(); \ + ZEN_ASSERT(TLS_ != nullptr); \ + TLS_->setTrapFrameAddr(FrameAddr, nullptr, nullptr, 0); \ + } while (0) #endif // ZEN_ENABLE_CPU_EXCEPTION diff --git a/src/evm/evm_cache.cpp b/src/evm/evm_cache.cpp index e7d3113cd..adab58331 100644 --- a/src/evm/evm_cache.cpp +++ b/src/evm/evm_cache.cpp @@ -323,6 +323,9 @@ static CSRGraph buildAdjacencyCSR(const EdgeTables &Edges) { } static void addEdge(EdgeTables &Edges, uint32_t From, uint32_t To) { + if (From >= Edges.Succs.size() || To >= Edges.Succs.size()) { + return; + } auto &FromSuccs = Edges.Succs[From]; if (std::find(FromSuccs.begin(), FromSuccs.end(), To) == FromSuccs.end()) { FromSuccs.push_back(To); @@ -347,6 +350,9 @@ static bool splitCriticalEdges(std::vector &Blocks, EdgeTables &Edges, continue; // Not a critical edge source } for (uint32_t ToId : Edges.Succs[FromId]) { + if (ToId >= Blocks.size()) { + continue; + } if (Edges.Preds[ToId].size() > 1) { // Critical edge: From has multiple succs, To has multiple preds EdgesToSplit.push_back({static_cast(FromId), ToId}); @@ -629,6 +635,9 @@ static std::vector computeInCycle(const CSRGraph &SuccsCSR, while (!Stack.empty()) { const uint32_t Node = Stack.back(); Stack.pop_back(); + if (Node >= NumBlocks) { + continue; + } Component.push_back(Node); for (uint32_t Pred : PredsCSR[Node]) { if (Pred >= NumBlocks) { @@ -641,6 +650,10 @@ static std::vector computeInCycle(const CSRGraph &SuccsCSR, } } + if (Component.empty()) { + continue; + } + if (Component.size() > 1) { for (uint32_t Id : Component) { InCycle[Id] = 1; @@ -702,7 +715,13 @@ static std::vector computeReachable(const CSRGraph &SuccsCSR, while (!Stack.empty()) { const uint32_t Node = Stack.back(); Stack.pop_back(); + if (Node >= NumBlocks) { + continue; + } for (uint32_t Succ : SuccsCSR[Node]) { + if (Succ >= NumBlocks) { + continue; + } if (Reachable[Succ] == 0) { Reachable[Succ] = 1; Stack.push_back(Succ); @@ -762,6 +781,9 @@ static DomInfo computeDomInfo(const CSRGraph &SuccsCSR, } bool HasReachablePred = false; for (uint32_t Pred : PredsCSR[static_cast(I)]) { + if (Pred >= N) { + continue; + } if (Reachable[Pred] != 0) { HasReachablePred = true; break; @@ -864,6 +886,9 @@ static DomInfo computeDomInfo(const CSRGraph &SuccsCSR, uint32_t NewIDom = UINT32_MAX; bool Diverged = false; for (uint32_t Pred : PredsCSR[Node]) { + if (Pred >= N) { + continue; + } if (Reachable[Pred] == 0) { continue; } @@ -964,6 +989,9 @@ findBackEdgesUsingDominators(const CSRGraph &SuccsCSR, const DomInfo &Dom, for (size_t From = 0; From < NumBlocks; ++From) { for (uint32_t To : SuccsCSR[static_cast(From)]) { + if (To >= NumBlocks) { + continue; + } // Classic back-edge: target dominates source. if (Dom.dominates(To, static_cast(From))) { BackEdges[From].push_back(To); @@ -974,6 +1002,9 @@ findBackEdgesUsingDominators(const CSRGraph &SuccsCSR, const DomInfo &Dom, static bool isBackEdge(const std::vector> &BackEdges, uint32_t From, uint32_t To) { + if (From >= BackEdges.size()) { + return false; + } const auto &Edges = BackEdges[From]; return std::find(Edges.begin(), Edges.end(), To) != Edges.end(); } @@ -1013,7 +1044,13 @@ collectNaturalLoop(uint32_t From, uint32_t Header, const CSRGraph &PredsCSR, while (!Stack.empty()) { const uint32_t Node = Stack.back(); Stack.pop_back(); + if (Node >= NumBlocks) { + continue; + } for (uint32_t Pred : PredsCSR[Node]) { + if (Pred >= NumBlocks) { + continue; + } if (Reachable[Pred] == 0) { continue; } @@ -1046,6 +1083,9 @@ static bool buildLoopsUsingDominance( continue; } for (uint32_t To : SuccsCSR[static_cast(From)]) { + if (To >= NumBlocks) { + continue; + } // Header discovery: a back-edge From -> To exists iff To dominates From. if (!Dom.dominates(To, static_cast(From))) { continue; @@ -1150,6 +1190,9 @@ static bool buildLoopsUsingDominance( for (size_t OrderIndex = 0; OrderIndex < LoopOrder.size(); ++OrderIndex) { const size_t LoopId = LoopOrder[OrderIndex]; for (uint32_t Node : Loops[LoopId].Nodes) { + if (Node >= LoopOf.size()) { + return false; + } if (LoopOf[Node] == -1) { LoopOf[Node] = static_cast(LoopId); } @@ -1168,8 +1211,14 @@ static bool buildLoopsUsingDominance( for (size_t LoopId = 0; LoopId < Loops.size(); ++LoopId) { auto &Loop = Loops[LoopId]; for (uint32_t Node : Loop.Nodes) { + if (Node >= NumBlocks) { + continue; + } bool IsExit = false; for (uint32_t Succ : SuccsCSR[Node]) { + if (Succ >= NumBlocks) { + continue; + } if (!bitsetTest(Loop.NodeMask, Succ)) { IsExit = true; break; @@ -1218,6 +1267,9 @@ static bool lemma614Update(uint32_t NodeId, const std::vector &Blocks, uint64_t MinSucc = UINT64_MAX; for (uint32_t Succ : SuccsCSR[NodeId]) { + if (Succ >= Blocks.size() || Succ >= Metering.size()) { + continue; + } if (BackEdges && isBackEdge(*BackEdges, NodeId, Succ)) { continue; } @@ -1244,6 +1296,9 @@ static bool lemma614Update(uint32_t NodeId, const std::vector &Blocks, Metering[NodeId] += MinSucc; for (uint32_t Succ : SuccsCSR[NodeId]) { + if (Succ >= Blocks.size() || Succ >= Metering.size()) { + continue; + } if (BackEdges && isBackEdge(*BackEdges, NodeId, Succ)) { continue; } diff --git a/src/platform/platform.h b/src/platform/platform.h index a8b2c4f25..d299c7291 100644 --- a/src/platform/platform.h +++ b/src/platform/platform.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include diff --git a/src/runtime/evm_instance.cpp b/src/runtime/evm_instance.cpp index 1cf1fccdc..39539f5b1 100644 --- a/src/runtime/evm_instance.cpp +++ b/src/runtime/evm_instance.cpp @@ -189,7 +189,7 @@ void EVMInstance::setInstanceExceptionOnJIT(EVMInstance *Inst, void EVMInstance::throwInstanceExceptionOnJIT(EVMInstance *Inst) { #ifdef ZEN_ENABLE_CPU_EXCEPTION - SAVE_EVM_HOSTAPI_FRAME_POINTER_TO_TLS + SAVE_EVM_HOSTAPI_FRAME_POINTER_TO_TLS; utils::throwCpuIllegalInstructionTrap(); #endif // ZEN_ENABLE_CPU_EXCEPTION diff --git a/src/runtime/evm_instance.h b/src/runtime/evm_instance.h index 6199da8fd..3dcbfb859 100644 --- a/src/runtime/evm_instance.h +++ b/src/runtime/evm_instance.h @@ -11,8 +11,8 @@ #include "runtime/evm_module.h" #include "runtime/instance.h" #include -#include #include +#include #include // Forward declaration for evmc_message @@ -158,8 +158,12 @@ class EVMInstance final : public RuntimeObject { std::unordered_map, evmc::bytes32, PairHash> CalldataLoads; - std::deque ExtcodeHashes; - std::deque Keccak256Results; + // Use std::list (not std::deque) for values whose .bytes pointers are + // returned to JIT and may outlive further push_back calls; deque can + // reallocate and invalidate earlier element addresses. + std::list ExtcodeHashes; + std::list Keccak256Results; + std::list CreateAddresses; bool TxContextCached = false; void clear() { @@ -170,6 +174,7 @@ class EVMInstance final : public RuntimeObject { CalldataLoads.clear(); ExtcodeHashes.clear(); Keccak256Results.clear(); + CreateAddresses.clear(); } }; diff --git a/src/utils/logging.h b/src/utils/logging.h index 58df7f2d7..423037546 100644 --- a/src/utils/logging.h +++ b/src/utils/logging.h @@ -6,7 +6,9 @@ #include "common/defines.h" #include "platform/platform.h" +#include #include +#include #ifdef ZEN_ENABLE_SPDLOG namespace spdlog { diff --git a/src/vm/dt_evmc_vm.cpp b/src/vm/dt_evmc_vm.cpp index 17961c8ea..2e2d2be73 100644 --- a/src/vm/dt_evmc_vm.cpp +++ b/src/vm/dt_evmc_vm.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #ifdef ZEN_ENABLE_VIRTUAL_STACK #include "utils/virtual_stack.h" @@ -174,6 +175,15 @@ bool parseBoolEnvValue(const char *Value, bool &ParsedValue) { return false; } +bool isLikelyPrecompile(const evmc_address &Addr) { + for (size_t I = 0; I < 19; ++I) { + if (Addr.bytes[I] != 0) { + return false; + } + } + return Addr.bytes[19] >= 1 && Addr.bytes[19] <= 9; +} + // VM interface for DTVM struct DTVM : evmc_vm { DTVM(); @@ -247,6 +257,9 @@ struct DTVM : evmc_vm { std::vector> NestedCtxPool; // Instance pool for depth > 0 std::vector CacheInsts; + // Serialize execute() for nested host calls (re-entrancy-safe via + // recursive_mutex). + std::recursive_mutex ExecuteMutex; bool isModuleInUse(const EVMModule *Mod) const { if (CachedMainInst && CachedMainInst->getModule() == Mod) @@ -540,6 +553,9 @@ evmc_result executeInterpreterFastPath(DTVM *VM, evmc_message MsgWithCode = *Msg; MsgWithCode.code = reinterpret_cast(Mod->Code); MsgWithCode.code_size = Mod->CodeSize; + if (Msg->depth == 0) { + TheInst->clearMessageCache(); + } TheInst->setExeResult(evmc::Result{EVMC_SUCCESS, 0, 0}); TheInst->pushMessage(&MsgWithCode); @@ -622,6 +638,20 @@ evmc_result executeMultipassFastPath(DTVM *VM, const evmc_host_interface *Host, return evmc_make_result(EVMC_FAILURE, 0, 0, nullptr, 0); } + // Empty-code top-level CALL to a non-precompile has no bytecode execution. + if (Msg && Msg->depth == 0 && CodeSize == 0 && Msg->kind == EVMC_CALL && + !isLikelyPrecompile(Msg->recipient)) { + evmc::Result NoCodeResult{EVMC_SUCCESS, static_cast(Msg->gas), 0}; + return NoCodeResult.release_raw(); + } + + // Nested empty-code CALLs: use interpreter path (precompiles may have no + // code). + if (Msg && Msg->depth > 0 && CodeSize == 0 && Msg->kind == EVMC_CALL) { + return executeInterpreterFastPath(VM, Host, Context, Rev, Msg, Code, + CodeSize); + } + // Module lookup: L1 address-based cache -> Cold load bool IsTransientMod = false; EVMModule *Mod = @@ -650,6 +680,9 @@ evmc_result executeMultipassFastPath(DTVM *VM, const evmc_host_interface *Host, evmc_message MsgWithCode = *Msg; MsgWithCode.code = reinterpret_cast(Mod->Code); MsgWithCode.code_size = Mod->CodeSize; + if (Msg->depth == 0) { + TheInst->clearMessageCache(); + } TheInst->setExeResult(evmc::Result{EVMC_SUCCESS, 0, 0}); TheInst->pushMessage(&MsgWithCode); @@ -685,6 +718,7 @@ evmc_result execute(evmc_vm *EVMInstance, const evmc_host_interface *Host, const evmc_message *Msg, const uint8_t *Code, size_t CodeSize) { auto *VM = static_cast(EVMInstance); + std::lock_guard Guard(VM->ExecuteMutex); // Interpreter mode: use optimized fast path (bypasses callEVMMain) if (VM->Config.Mode == RunMode::InterpMode) { @@ -743,6 +777,11 @@ DTVM::DTVM() StrictValidation); } } + + // Greedy RA has been observed to crash during long-running multipass JIT + // (e.g. Silkworm sync). Keep the default (greedy enabled); use + // --disable-multipass-greedyra or loadEVMModuleWithRegAllocRetry() FastRA + // fallback when compilation fails in the regalloc phase. } } // namespace