From 95765dfc72c1e6b6c635b6e65d1825cdb213a0a1 Mon Sep 17 00:00:00 2001 From: mbaxter Date: Mon, 16 Sep 2024 17:38:25 -0400 Subject: [PATCH] cannon: Handle unaligned futex addresses (#11929) * cannon: Update tests for futex unaligned memory behavior * cannon: Align futex-related addresses when they are set * cannon: Run lint and semver tasks * cannon: Add wakeup traversal tests with unaligend addresses * cannon: Don't panic if ThreadState.FutexAddr is unaligned * cannon: Run semver lock task * cannon: Cleanup stray whitespace --- cannon/mipsevm/multithreaded/mips.go | 14 +-- .../mipsevm/tests/evm_multithreaded_test.go | 96 ++++++++++++------- packages/contracts-bedrock/semver-lock.json | 4 +- .../contracts-bedrock/src/cannon/MIPS2.sol | 16 ++-- 4 files changed, 79 insertions(+), 51 deletions(-) diff --git a/cannon/mipsevm/multithreaded/mips.go b/cannon/mipsevm/multithreaded/mips.go index 89ecadd01366..daa36d05c0ff 100644 --- a/cannon/mipsevm/multithreaded/mips.go +++ b/cannon/mipsevm/multithreaded/mips.go @@ -105,15 +105,16 @@ func (m *InstrumentedState) handleSyscall() error { return nil case exec.SysFutex: // args: a0 = addr, a1 = op, a2 = val, a3 = timeout + effAddr := a0 & 0xFFffFFfc switch a1 { case exec.FutexWaitPrivate: - m.memoryTracker.TrackMemAccess(a0) - mem := m.state.Memory.GetMemory(a0) + m.memoryTracker.TrackMemAccess(effAddr) + mem := m.state.Memory.GetMemory(effAddr) if mem != a2 { v0 = exec.SysErrorSignal v1 = exec.MipsEAGAIN } else { - thread.FutexAddr = a0 + thread.FutexAddr = effAddr thread.FutexVal = a2 if a3 == 0 { thread.FutexTimeoutStep = exec.FutexNoTimeout @@ -126,7 +127,7 @@ func (m *InstrumentedState) handleSyscall() error { case exec.FutexWakePrivate: // Trigger thread traversal starting from the left stack until we find one waiting on the wakeup // address - m.state.Wakeup = a0 + m.state.Wakeup = effAddr // Don't indicate to the program that we've woken up a waiting thread, as there are no guarantees. // The woken up thread should indicate this in userspace. v0 = 0 @@ -255,8 +256,9 @@ func (m *InstrumentedState) mipsStep() error { m.onWaitComplete(thread, true) return nil } else { - m.memoryTracker.TrackMemAccess(thread.FutexAddr) - mem := m.state.Memory.GetMemory(thread.FutexAddr) + effAddr := thread.FutexAddr & 0xFFffFFfc + m.memoryTracker.TrackMemAccess(effAddr) + mem := m.state.Memory.GetMemory(effAddr) if thread.FutexVal == mem { // still got expected value, continue sleeping, try next thread. m.preemptThread(thread) diff --git a/cannon/mipsevm/tests/evm_multithreaded_test.go b/cannon/mipsevm/tests/evm_multithreaded_test.go index f7ead804c707..a26ebe96eb37 100644 --- a/cannon/mipsevm/tests/evm_multithreaded_test.go +++ b/cannon/mipsevm/tests/evm_multithreaded_test.go @@ -654,17 +654,22 @@ func TestEVM_SysFutex_WaitPrivate(t *testing.T) { var tracer *tracing.Hooks cases := []struct { name string - address uint32 + addressParam uint32 + effAddr uint32 targetValue uint32 actualValue uint32 timeout uint32 shouldFail bool shouldSetTimeout bool }{ - {name: "successful wait, no timeout", address: 0x1234, targetValue: 0x01, actualValue: 0x01}, - {name: "memory mismatch, no timeout", address: 0x1200, targetValue: 0x01, actualValue: 0x02, shouldFail: true}, - {name: "successful wait w timeout", address: 0x1234, targetValue: 0x01, actualValue: 0x01, timeout: 1000000, shouldSetTimeout: true}, - {name: "memory mismatch w timeout", address: 0x1200, targetValue: 0x01, actualValue: 0x02, timeout: 2000000, shouldFail: true}, + {name: "successful wait, no timeout", addressParam: 0x1234, effAddr: 0x1234, targetValue: 0x01, actualValue: 0x01}, + {name: "successful wait, no timeout, unaligned addr", addressParam: 0x1235, effAddr: 0x1234, targetValue: 0x01, actualValue: 0x01}, + {name: "memory mismatch, no timeout", addressParam: 0x1200, effAddr: 0x1200, targetValue: 0x01, actualValue: 0x02, shouldFail: true}, + {name: "memory mismatch, no timeout, unaligned", addressParam: 0x1203, effAddr: 0x1200, targetValue: 0x01, actualValue: 0x02, shouldFail: true}, + {name: "successful wait w timeout", addressParam: 0x1234, effAddr: 0x1234, targetValue: 0x01, actualValue: 0x01, timeout: 1000000, shouldSetTimeout: true}, + {name: "successful wait w timeout, unaligned", addressParam: 0x1232, effAddr: 0x1230, targetValue: 0x01, actualValue: 0x01, timeout: 1000000, shouldSetTimeout: true}, + {name: "memory mismatch w timeout", addressParam: 0x1200, effAddr: 0x1200, targetValue: 0x01, actualValue: 0x02, timeout: 2000000, shouldFail: true}, + {name: "memory mismatch w timeout, unaligned", addressParam: 0x120F, effAddr: 0x120C, targetValue: 0x01, actualValue: 0x02, timeout: 2000000, shouldFail: true}, } for i, c := range cases { @@ -673,9 +678,9 @@ func TestEVM_SysFutex_WaitPrivate(t *testing.T) { step := state.GetStep() state.Memory.SetMemory(state.GetPC(), syscallInsn) - state.Memory.SetMemory(c.address, c.actualValue) + state.Memory.SetMemory(c.effAddr, c.actualValue) state.GetRegistersRef()[2] = exec.SysFutex // Set syscall number - state.GetRegistersRef()[4] = c.address + state.GetRegistersRef()[4] = c.addressParam state.GetRegistersRef()[5] = exec.FutexWaitPrivate state.GetRegistersRef()[6] = c.targetValue state.GetRegistersRef()[7] = c.timeout @@ -691,7 +696,7 @@ func TestEVM_SysFutex_WaitPrivate(t *testing.T) { expected.ActiveThread().Registers[7] = exec.MipsEAGAIN } else { // PC and return registers should not update on success, updates happen when wait completes - expected.ActiveThread().FutexAddr = c.address + expected.ActiveThread().FutexAddr = c.effAddr expected.ActiveThread().FutexVal = c.targetValue expected.ActiveThread().FutexTimeoutStep = exec.FutexNoTimeout if c.shouldSetTimeout { @@ -716,18 +721,25 @@ func TestEVM_SysFutex_WakePrivate(t *testing.T) { var tracer *tracing.Hooks cases := []struct { name string - address uint32 + addressParam uint32 + effAddr uint32 activeThreadCount int inactiveThreadCount int traverseRight bool expectTraverseRight bool }{ - {name: "Traverse right", address: 0x6789, activeThreadCount: 2, inactiveThreadCount: 1, traverseRight: true}, - {name: "Traverse right, no left threads", address: 0x6789, activeThreadCount: 2, inactiveThreadCount: 0, traverseRight: true}, - {name: "Traverse right, single thread", address: 0x6789, activeThreadCount: 1, inactiveThreadCount: 0, traverseRight: true}, - {name: "Traverse left", address: 0x6789, activeThreadCount: 2, inactiveThreadCount: 1, traverseRight: false}, - {name: "Traverse left, switch directions", address: 0x6789, activeThreadCount: 1, inactiveThreadCount: 1, traverseRight: false, expectTraverseRight: true}, - {name: "Traverse left, single thread", address: 0x6789, activeThreadCount: 1, inactiveThreadCount: 0, traverseRight: false, expectTraverseRight: true}, + {name: "Traverse right", addressParam: 0x6700, effAddr: 0x6700, activeThreadCount: 2, inactiveThreadCount: 1, traverseRight: true}, + {name: "Traverse right, unaligned addr", addressParam: 0x6789, effAddr: 0x6788, activeThreadCount: 2, inactiveThreadCount: 1, traverseRight: true}, + {name: "Traverse right, no left threads", addressParam: 0x6784, effAddr: 0x6784, activeThreadCount: 2, inactiveThreadCount: 0, traverseRight: true}, + {name: "Traverse right, no left threads, unaligned addr", addressParam: 0x678E, effAddr: 0x678C, activeThreadCount: 2, inactiveThreadCount: 0, traverseRight: true}, + {name: "Traverse right, single thread", addressParam: 0x6788, effAddr: 0x6788, activeThreadCount: 1, inactiveThreadCount: 0, traverseRight: true}, + {name: "Traverse right, single thread, unaligned", addressParam: 0x6789, effAddr: 0x6788, activeThreadCount: 1, inactiveThreadCount: 0, traverseRight: true}, + {name: "Traverse left", addressParam: 0x6788, effAddr: 0x6788, activeThreadCount: 2, inactiveThreadCount: 1, traverseRight: false}, + {name: "Traverse left, unaliagned", addressParam: 0x6789, effAddr: 0x6788, activeThreadCount: 2, inactiveThreadCount: 1, traverseRight: false}, + {name: "Traverse left, switch directions", addressParam: 0x6788, effAddr: 0x6788, activeThreadCount: 1, inactiveThreadCount: 1, traverseRight: false, expectTraverseRight: true}, + {name: "Traverse left, switch directions, unaligned", addressParam: 0x6789, effAddr: 0x6788, activeThreadCount: 1, inactiveThreadCount: 1, traverseRight: false, expectTraverseRight: true}, + {name: "Traverse left, single thread", addressParam: 0x6788, effAddr: 0x6788, activeThreadCount: 1, inactiveThreadCount: 0, traverseRight: false, expectTraverseRight: true}, + {name: "Traverse left, single thread, unaligned", addressParam: 0x6789, effAddr: 0x6788, activeThreadCount: 1, inactiveThreadCount: 0, traverseRight: false, expectTraverseRight: true}, } for i, c := range cases { @@ -738,7 +750,7 @@ func TestEVM_SysFutex_WakePrivate(t *testing.T) { state.Memory.SetMemory(state.GetPC(), syscallInsn) state.GetRegistersRef()[2] = exec.SysFutex // Set syscall number - state.GetRegistersRef()[4] = c.address + state.GetRegistersRef()[4] = c.addressParam state.GetRegistersRef()[5] = exec.FutexWakePrivate // Set up post-state expectations @@ -746,7 +758,7 @@ func TestEVM_SysFutex_WakePrivate(t *testing.T) { expected.ExpectStep() expected.ActiveThread().Registers[2] = 0 expected.ActiveThread().Registers[7] = 0 - expected.Wakeup = c.address + expected.Wakeup = c.effAddr expected.ExpectPreemption(state) expected.TraverseRight = c.expectTraverseRight if c.traverseRight != c.expectTraverseRight { @@ -1192,13 +1204,17 @@ func TestEVM_NormalTraversalStep_HandleWaitingThread(t *testing.T) { {name: "Preempt, no timeout #1", step: 100, activeStackSize: 1, otherStackSize: 0, futexAddr: 0x100, targetValue: 0x01, actualValue: 0x01, timeoutStep: exec.FutexNoTimeout}, {name: "Preempt, no timeout #2", step: 100, activeStackSize: 1, otherStackSize: 1, futexAddr: 0x100, targetValue: 0x01, actualValue: 0x01, timeoutStep: exec.FutexNoTimeout}, {name: "Preempt, no timeout #3", step: 100, activeStackSize: 2, otherStackSize: 1, futexAddr: 0x100, targetValue: 0x01, actualValue: 0x01, timeoutStep: exec.FutexNoTimeout}, + {name: "Preempt, no timeout, unaligned", step: 100, activeStackSize: 2, otherStackSize: 1, futexAddr: 0x101, targetValue: 0x01, actualValue: 0x01, timeoutStep: exec.FutexNoTimeout}, {name: "Preempt, with timeout #1", step: 100, activeStackSize: 2, otherStackSize: 1, futexAddr: 0x100, targetValue: 0x01, actualValue: 0x01, timeoutStep: 101}, {name: "Preempt, with timeout #2", step: 100, activeStackSize: 1, otherStackSize: 1, futexAddr: 0x100, targetValue: 0x01, actualValue: 0x01, timeoutStep: 150}, + {name: "Preempt, with timeout, unaligned", step: 100, activeStackSize: 1, otherStackSize: 1, futexAddr: 0x101, targetValue: 0x01, actualValue: 0x01, timeoutStep: 150}, {name: "Wakeup, no timeout #1", step: 100, activeStackSize: 1, otherStackSize: 0, futexAddr: 0x100, targetValue: 0x01, actualValue: 0x02, timeoutStep: exec.FutexNoTimeout, shouldWakeup: true}, {name: "Wakeup, no timeout #2", step: 100, activeStackSize: 2, otherStackSize: 1, futexAddr: 0x100, targetValue: 0x01, actualValue: 0x02, timeoutStep: exec.FutexNoTimeout, shouldWakeup: true}, + {name: "Wakeup, no timeout, unaligned", step: 100, activeStackSize: 2, otherStackSize: 1, futexAddr: 0x102, targetValue: 0x01, actualValue: 0x02, timeoutStep: exec.FutexNoTimeout, shouldWakeup: true}, {name: "Wakeup with timeout #1", step: 100, activeStackSize: 2, otherStackSize: 1, futexAddr: 0x100, targetValue: 0x01, actualValue: 0x02, timeoutStep: 100, shouldWakeup: true, shouldTimeout: true}, {name: "Wakeup with timeout #2", step: 100, activeStackSize: 2, otherStackSize: 1, futexAddr: 0x100, targetValue: 0x02, actualValue: 0x02, timeoutStep: 100, shouldWakeup: true, shouldTimeout: true}, {name: "Wakeup with timeout #3", step: 100, activeStackSize: 2, otherStackSize: 1, futexAddr: 0x100, targetValue: 0x02, actualValue: 0x02, timeoutStep: 50, shouldWakeup: true, shouldTimeout: true}, + {name: "Wakeup with timeout, unaligned", step: 100, activeStackSize: 2, otherStackSize: 1, futexAddr: 0x103, targetValue: 0x02, actualValue: 0x02, timeoutStep: 50, shouldWakeup: true, shouldTimeout: true}, } for _, c := range cases { @@ -1209,7 +1225,7 @@ func TestEVM_NormalTraversalStep_HandleWaitingThread(t *testing.T) { if !c.shouldWakeup && c.shouldTimeout { require.Fail(t, "Invalid test case - cannot expect a timeout with no wakeup") } - + effAddr := c.futexAddr & 0xFF_FF_FF_Fc goVm, state, contracts := setup(t, i, nil) mttestutil.SetupThreads(int64(i*101), state, traverseRight, c.activeStackSize, c.otherStackSize) state.Step = c.step @@ -1218,7 +1234,7 @@ func TestEVM_NormalTraversalStep_HandleWaitingThread(t *testing.T) { activeThread.FutexAddr = c.futexAddr activeThread.FutexVal = c.targetValue activeThread.FutexTimeoutStep = c.timeoutStep - state.GetMemory().SetMemory(c.futexAddr, c.actualValue) + state.GetMemory().SetMemory(effAddr, c.actualValue) // Set up post-state expectations expected := mttestutil.NewExpectedMTState(state) @@ -1312,11 +1328,12 @@ func TestEVM_NormalTraversal_Full(t *testing.T) { } func TestEVM_WakeupTraversalStep(t *testing.T) { - wakeupAddr := uint32(0x1234) + addr := uint32(0x1234) wakeupVal := uint32(0x999) var tracer *tracing.Hooks cases := []struct { name string + wakeupAddr uint32 futexAddr uint32 targetVal uint32 traverseRight bool @@ -1325,19 +1342,28 @@ func TestEVM_WakeupTraversalStep(t *testing.T) { shouldClearWakeup bool shouldPreempt bool }{ - {name: "Matching addr, not wakeable, first thread", futexAddr: wakeupAddr, targetVal: wakeupVal, traverseRight: false, activeStackSize: 3, otherStackSize: 0, shouldClearWakeup: true}, - {name: "Matching addr, wakeable, first thread", futexAddr: wakeupAddr, targetVal: wakeupVal + 1, traverseRight: false, activeStackSize: 3, otherStackSize: 0, shouldClearWakeup: true}, - {name: "Matching addr, not wakeable, last thread", futexAddr: wakeupAddr, targetVal: wakeupVal, traverseRight: true, activeStackSize: 1, otherStackSize: 2, shouldClearWakeup: true}, - {name: "Matching addr, wakeable, last thread", futexAddr: wakeupAddr, targetVal: wakeupVal + 1, traverseRight: true, activeStackSize: 1, otherStackSize: 2, shouldClearWakeup: true}, - {name: "Matching addr, not wakeable, intermediate thread", futexAddr: wakeupAddr, targetVal: wakeupVal, traverseRight: false, activeStackSize: 2, otherStackSize: 2, shouldClearWakeup: true}, - {name: "Matching addr, wakeable, intermediate thread", futexAddr: wakeupAddr, targetVal: wakeupVal + 1, traverseRight: true, activeStackSize: 2, otherStackSize: 2, shouldClearWakeup: true}, - {name: "Mismatched addr, last thread", futexAddr: wakeupAddr + 4, traverseRight: true, activeStackSize: 1, otherStackSize: 2, shouldPreempt: true, shouldClearWakeup: true}, - {name: "Mismatched addr", futexAddr: wakeupAddr + 4, traverseRight: true, activeStackSize: 2, otherStackSize: 2, shouldPreempt: true}, - {name: "Mismatched addr", futexAddr: wakeupAddr + 4, traverseRight: false, activeStackSize: 2, otherStackSize: 0, shouldPreempt: true}, - {name: "Mismatched addr", futexAddr: wakeupAddr + 4, traverseRight: false, activeStackSize: 1, otherStackSize: 0, shouldPreempt: true}, - {name: "Non-waiting thread", futexAddr: exec.FutexEmptyAddr, traverseRight: false, activeStackSize: 1, otherStackSize: 0, shouldPreempt: true}, - {name: "Non-waiting thread", futexAddr: exec.FutexEmptyAddr, traverseRight: true, activeStackSize: 2, otherStackSize: 1, shouldPreempt: true}, - {name: "Non-waiting thread, last thread", futexAddr: exec.FutexEmptyAddr, traverseRight: true, activeStackSize: 1, otherStackSize: 1, shouldPreempt: true, shouldClearWakeup: true}, + {name: "Matching addr, not wakeable, first thread", wakeupAddr: addr, futexAddr: addr, targetVal: wakeupVal, traverseRight: false, activeStackSize: 3, otherStackSize: 0, shouldClearWakeup: true}, + {name: "Matching addr, wakeable, first thread", wakeupAddr: addr, futexAddr: addr, targetVal: wakeupVal + 1, traverseRight: false, activeStackSize: 3, otherStackSize: 0, shouldClearWakeup: true}, + {name: "Matching addr, not wakeable, last thread", wakeupAddr: addr, futexAddr: addr, targetVal: wakeupVal, traverseRight: true, activeStackSize: 1, otherStackSize: 2, shouldClearWakeup: true}, + {name: "Matching addr, wakeable, last thread", wakeupAddr: addr, futexAddr: addr, targetVal: wakeupVal + 1, traverseRight: true, activeStackSize: 1, otherStackSize: 2, shouldClearWakeup: true}, + {name: "Matching addr, not wakeable, intermediate thread", wakeupAddr: addr, futexAddr: addr, targetVal: wakeupVal, traverseRight: false, activeStackSize: 2, otherStackSize: 2, shouldClearWakeup: true}, + {name: "Matching addr, wakeable, intermediate thread", wakeupAddr: addr, futexAddr: addr, targetVal: wakeupVal + 1, traverseRight: true, activeStackSize: 2, otherStackSize: 2, shouldClearWakeup: true}, + {name: "Mismatched addr, last thread", wakeupAddr: addr, futexAddr: addr + 4, traverseRight: true, activeStackSize: 1, otherStackSize: 2, shouldPreempt: true, shouldClearWakeup: true}, + {name: "Mismatched addr", wakeupAddr: addr, futexAddr: addr + 4, traverseRight: true, activeStackSize: 2, otherStackSize: 2, shouldPreempt: true}, + {name: "Mismatched addr", wakeupAddr: addr, futexAddr: addr + 4, traverseRight: false, activeStackSize: 2, otherStackSize: 0, shouldPreempt: true}, + {name: "Mismatched addr", wakeupAddr: addr, futexAddr: addr + 4, traverseRight: false, activeStackSize: 1, otherStackSize: 0, shouldPreempt: true}, + {name: "Non-waiting thread", wakeupAddr: addr, futexAddr: exec.FutexEmptyAddr, traverseRight: false, activeStackSize: 1, otherStackSize: 0, shouldPreempt: true}, + {name: "Non-waiting thread", wakeupAddr: addr, futexAddr: exec.FutexEmptyAddr, traverseRight: true, activeStackSize: 2, otherStackSize: 1, shouldPreempt: true}, + {name: "Non-waiting thread, last thread", wakeupAddr: addr, futexAddr: exec.FutexEmptyAddr, traverseRight: true, activeStackSize: 1, otherStackSize: 1, shouldPreempt: true, shouldClearWakeup: true}, + // Check behavior of unaligned addresses - should be the same as aligned addresses (no memory access) + {name: "Matching addr, unaligned", wakeupAddr: addr + 1, futexAddr: addr + 1, targetVal: wakeupVal, traverseRight: false, activeStackSize: 3, otherStackSize: 0, shouldClearWakeup: true}, + {name: "Mismatched addr, last thread, wakeup unaligned", wakeupAddr: addr + 1, futexAddr: addr + 4, traverseRight: true, activeStackSize: 1, otherStackSize: 2, shouldPreempt: true, shouldClearWakeup: true}, + {name: "Mismatched addr, last thread, futex unaligned", wakeupAddr: addr, futexAddr: addr + 5, traverseRight: true, activeStackSize: 1, otherStackSize: 2, shouldPreempt: true, shouldClearWakeup: true}, + {name: "Mismatched addr, last thread, wake & futex unaligned", wakeupAddr: addr + 1, futexAddr: addr + 5, traverseRight: true, activeStackSize: 1, otherStackSize: 2, shouldPreempt: true, shouldClearWakeup: true}, + {name: "Mismatched addr, wakeup unaligned", wakeupAddr: addr + 3, futexAddr: addr + 4, traverseRight: true, activeStackSize: 2, otherStackSize: 2, shouldPreempt: true}, + {name: "Mismatched addr, futex unaligned", wakeupAddr: addr, futexAddr: addr + 6, traverseRight: true, activeStackSize: 2, otherStackSize: 2, shouldPreempt: true}, + {name: "Mismatched addr, wakeup & futex unaligned", wakeupAddr: addr + 2, futexAddr: addr + 6, traverseRight: true, activeStackSize: 2, otherStackSize: 2, shouldPreempt: true}, + {name: "Non-waiting thread, last thread, unaligned wakeup", wakeupAddr: addr + 3, futexAddr: exec.FutexEmptyAddr, traverseRight: true, activeStackSize: 1, otherStackSize: 1, shouldPreempt: true, shouldClearWakeup: true}, } for i, c := range cases { @@ -1346,8 +1372,8 @@ func TestEVM_WakeupTraversalStep(t *testing.T) { mttestutil.SetupThreads(int64(i*101), state, c.traverseRight, c.activeStackSize, c.otherStackSize) step := state.Step - state.Wakeup = wakeupAddr - state.GetMemory().SetMemory(wakeupAddr, wakeupVal) + state.Wakeup = c.wakeupAddr + state.GetMemory().SetMemory(c.wakeupAddr&0xFF_FF_FF_FC, wakeupVal) activeThread := state.GetCurrentThread() activeThread.FutexAddr = c.futexAddr activeThread.FutexVal = c.targetVal diff --git a/packages/contracts-bedrock/semver-lock.json b/packages/contracts-bedrock/semver-lock.json index 9846577f0503..d023f61bc244 100644 --- a/packages/contracts-bedrock/semver-lock.json +++ b/packages/contracts-bedrock/semver-lock.json @@ -144,8 +144,8 @@ "sourceCodeHash": "0xba4674e1846afbbc708877332a38dfabd4b8d1e48ce07d8ebf0a45c9f27f16b0" }, "src/cannon/MIPS2.sol": { - "initCodeHash": "0xdaed5d70cc84a53f224c28f24f8eef26d5d53dfba9fdc4f1b28c3b231b974e53", - "sourceCodeHash": "0x4026eb7ae7b303ec4c3c2880e14e260dbcfc0b4290459bcd22994cfed8655f80" + "initCodeHash": "0xd9da47f735b7a655a25ae0e867b467620a2cb537eb65d184a361f5ea4174d384", + "sourceCodeHash": "0x3a6d83a7d46eb267f6778f8ae116383fe3c14ad553d90b6c761fafeef22ae29c" }, "src/cannon/PreimageOracle.sol": { "initCodeHash": "0x801e52f9c8439fcf7089575fa93272dfb874641dbfc7d82f36d979c987271c0b", diff --git a/packages/contracts-bedrock/src/cannon/MIPS2.sol b/packages/contracts-bedrock/src/cannon/MIPS2.sol index b9da8fa8cc37..45811d9b46c8 100644 --- a/packages/contracts-bedrock/src/cannon/MIPS2.sol +++ b/packages/contracts-bedrock/src/cannon/MIPS2.sol @@ -57,8 +57,8 @@ contract MIPS2 is ISemver { } /// @notice The semantic version of the MIPS2 contract. - /// @custom:semver 1.0.0-beta.9 - string public constant version = "1.0.0-beta.9"; + /// @custom:semver 1.0.0-beta.10 + string public constant version = "1.0.0-beta.10"; /// @notice The preimage oracle contract. IPreimageOracle internal immutable ORACLE; @@ -175,7 +175,7 @@ contract MIPS2 is ISemver { // Don't allow regular execution until we resolved if we have woken up any thread. if (state.wakeup != sys.FUTEX_EMPTY_ADDR) { if (state.wakeup == thread.futexAddr) { - // completed wake traverssal + // completed wake traversal // resume execution on woken up thread state.wakeup = sys.FUTEX_EMPTY_ADDR; return outputState(); @@ -431,15 +431,15 @@ contract MIPS2 is ISemver { return outputState(); } else if (syscall_no == sys.SYS_FUTEX) { // args: a0 = addr, a1 = op, a2 = val, a3 = timeout + uint32 effAddr = a0 & 0xFFffFFfc; if (a1 == sys.FUTEX_WAIT_PRIVATE) { - uint32 mem = MIPSMemory.readMem( - state.memRoot, a0 & 0xFFffFFfc, MIPSMemory.memoryProofOffset(MEM_PROOF_OFFSET, 1) - ); + uint32 mem = + MIPSMemory.readMem(state.memRoot, effAddr, MIPSMemory.memoryProofOffset(MEM_PROOF_OFFSET, 1)); if (mem != a2) { v0 = sys.SYS_ERROR_SIGNAL; v1 = sys.EAGAIN; } else { - thread.futexAddr = a0; + thread.futexAddr = effAddr; thread.futexVal = a2; thread.futexTimeoutStep = a3 == 0 ? sys.FUTEX_NO_TIMEOUT : state.step + sys.FUTEX_TIMEOUT_STEPS; // Leave cpu scalars as-is. This instruction will be completed by `onWaitComplete` @@ -449,7 +449,7 @@ contract MIPS2 is ISemver { } else if (a1 == sys.FUTEX_WAKE_PRIVATE) { // Trigger thread traversal starting from the left stack until we find one waiting on the wakeup // address - state.wakeup = a0; + state.wakeup = effAddr; // Don't indicate to the program that we've woken up a waiting thread, as there are no guarantees. // The woken up thread should indicate this in userspace. v0 = 0;