Commit 95765dfc authored by mbaxter's avatar mbaxter Committed by GitHub

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
parent 717330e9
...@@ -105,15 +105,16 @@ func (m *InstrumentedState) handleSyscall() error { ...@@ -105,15 +105,16 @@ func (m *InstrumentedState) handleSyscall() error {
return nil return nil
case exec.SysFutex: case exec.SysFutex:
// args: a0 = addr, a1 = op, a2 = val, a3 = timeout // args: a0 = addr, a1 = op, a2 = val, a3 = timeout
effAddr := a0 & 0xFFffFFfc
switch a1 { switch a1 {
case exec.FutexWaitPrivate: case exec.FutexWaitPrivate:
m.memoryTracker.TrackMemAccess(a0) m.memoryTracker.TrackMemAccess(effAddr)
mem := m.state.Memory.GetMemory(a0) mem := m.state.Memory.GetMemory(effAddr)
if mem != a2 { if mem != a2 {
v0 = exec.SysErrorSignal v0 = exec.SysErrorSignal
v1 = exec.MipsEAGAIN v1 = exec.MipsEAGAIN
} else { } else {
thread.FutexAddr = a0 thread.FutexAddr = effAddr
thread.FutexVal = a2 thread.FutexVal = a2
if a3 == 0 { if a3 == 0 {
thread.FutexTimeoutStep = exec.FutexNoTimeout thread.FutexTimeoutStep = exec.FutexNoTimeout
...@@ -126,7 +127,7 @@ func (m *InstrumentedState) handleSyscall() error { ...@@ -126,7 +127,7 @@ func (m *InstrumentedState) handleSyscall() error {
case exec.FutexWakePrivate: case exec.FutexWakePrivate:
// Trigger thread traversal starting from the left stack until we find one waiting on the wakeup // Trigger thread traversal starting from the left stack until we find one waiting on the wakeup
// address // 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. // 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. // The woken up thread should indicate this in userspace.
v0 = 0 v0 = 0
...@@ -255,8 +256,9 @@ func (m *InstrumentedState) mipsStep() error { ...@@ -255,8 +256,9 @@ func (m *InstrumentedState) mipsStep() error {
m.onWaitComplete(thread, true) m.onWaitComplete(thread, true)
return nil return nil
} else { } else {
m.memoryTracker.TrackMemAccess(thread.FutexAddr) effAddr := thread.FutexAddr & 0xFFffFFfc
mem := m.state.Memory.GetMemory(thread.FutexAddr) m.memoryTracker.TrackMemAccess(effAddr)
mem := m.state.Memory.GetMemory(effAddr)
if thread.FutexVal == mem { if thread.FutexVal == mem {
// still got expected value, continue sleeping, try next thread. // still got expected value, continue sleeping, try next thread.
m.preemptThread(thread) m.preemptThread(thread)
......
...@@ -654,17 +654,22 @@ func TestEVM_SysFutex_WaitPrivate(t *testing.T) { ...@@ -654,17 +654,22 @@ func TestEVM_SysFutex_WaitPrivate(t *testing.T) {
var tracer *tracing.Hooks var tracer *tracing.Hooks
cases := []struct { cases := []struct {
name string name string
address uint32 addressParam uint32
effAddr uint32
targetValue uint32 targetValue uint32
actualValue uint32 actualValue uint32
timeout uint32 timeout uint32
shouldFail bool shouldFail bool
shouldSetTimeout bool shouldSetTimeout bool
}{ }{
{name: "successful wait, no timeout", address: 0x1234, targetValue: 0x01, actualValue: 0x01}, {name: "successful wait, no timeout", addressParam: 0x1234, effAddr: 0x1234, targetValue: 0x01, actualValue: 0x01},
{name: "memory mismatch, no timeout", address: 0x1200, targetValue: 0x01, actualValue: 0x02, shouldFail: true}, {name: "successful wait, no timeout, unaligned addr", addressParam: 0x1235, effAddr: 0x1234, targetValue: 0x01, actualValue: 0x01},
{name: "successful wait w timeout", address: 0x1234, targetValue: 0x01, actualValue: 0x01, timeout: 1000000, shouldSetTimeout: true}, {name: "memory mismatch, no timeout", addressParam: 0x1200, effAddr: 0x1200, targetValue: 0x01, actualValue: 0x02, shouldFail: true},
{name: "memory mismatch w timeout", address: 0x1200, targetValue: 0x01, actualValue: 0x02, timeout: 2000000, 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 { for i, c := range cases {
...@@ -673,9 +678,9 @@ func TestEVM_SysFutex_WaitPrivate(t *testing.T) { ...@@ -673,9 +678,9 @@ func TestEVM_SysFutex_WaitPrivate(t *testing.T) {
step := state.GetStep() step := state.GetStep()
state.Memory.SetMemory(state.GetPC(), syscallInsn) 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()[2] = exec.SysFutex // Set syscall number
state.GetRegistersRef()[4] = c.address state.GetRegistersRef()[4] = c.addressParam
state.GetRegistersRef()[5] = exec.FutexWaitPrivate state.GetRegistersRef()[5] = exec.FutexWaitPrivate
state.GetRegistersRef()[6] = c.targetValue state.GetRegistersRef()[6] = c.targetValue
state.GetRegistersRef()[7] = c.timeout state.GetRegistersRef()[7] = c.timeout
...@@ -691,7 +696,7 @@ func TestEVM_SysFutex_WaitPrivate(t *testing.T) { ...@@ -691,7 +696,7 @@ func TestEVM_SysFutex_WaitPrivate(t *testing.T) {
expected.ActiveThread().Registers[7] = exec.MipsEAGAIN expected.ActiveThread().Registers[7] = exec.MipsEAGAIN
} else { } else {
// PC and return registers should not update on success, updates happen when wait completes // 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().FutexVal = c.targetValue
expected.ActiveThread().FutexTimeoutStep = exec.FutexNoTimeout expected.ActiveThread().FutexTimeoutStep = exec.FutexNoTimeout
if c.shouldSetTimeout { if c.shouldSetTimeout {
...@@ -716,18 +721,25 @@ func TestEVM_SysFutex_WakePrivate(t *testing.T) { ...@@ -716,18 +721,25 @@ func TestEVM_SysFutex_WakePrivate(t *testing.T) {
var tracer *tracing.Hooks var tracer *tracing.Hooks
cases := []struct { cases := []struct {
name string name string
address uint32 addressParam uint32
effAddr uint32
activeThreadCount int activeThreadCount int
inactiveThreadCount int inactiveThreadCount int
traverseRight bool traverseRight bool
expectTraverseRight bool expectTraverseRight bool
}{ }{
{name: "Traverse right", address: 0x6789, activeThreadCount: 2, inactiveThreadCount: 1, traverseRight: true}, {name: "Traverse right", addressParam: 0x6700, effAddr: 0x6700, activeThreadCount: 2, inactiveThreadCount: 1, traverseRight: true},
{name: "Traverse right, no left threads", address: 0x6789, activeThreadCount: 2, inactiveThreadCount: 0, traverseRight: true}, {name: "Traverse right, unaligned addr", addressParam: 0x6789, effAddr: 0x6788, activeThreadCount: 2, inactiveThreadCount: 1, traverseRight: true},
{name: "Traverse right, single thread", address: 0x6789, activeThreadCount: 1, inactiveThreadCount: 0, traverseRight: true}, {name: "Traverse right, no left threads", addressParam: 0x6784, effAddr: 0x6784, activeThreadCount: 2, inactiveThreadCount: 0, traverseRight: true},
{name: "Traverse left", address: 0x6789, activeThreadCount: 2, inactiveThreadCount: 1, traverseRight: false}, {name: "Traverse right, no left threads, unaligned addr", addressParam: 0x678E, effAddr: 0x678C, activeThreadCount: 2, inactiveThreadCount: 0, traverseRight: true},
{name: "Traverse left, switch directions", address: 0x6789, activeThreadCount: 1, inactiveThreadCount: 1, traverseRight: false, expectTraverseRight: true}, {name: "Traverse right, single thread", addressParam: 0x6788, effAddr: 0x6788, activeThreadCount: 1, inactiveThreadCount: 0, traverseRight: true},
{name: "Traverse left, single thread", address: 0x6789, activeThreadCount: 1, inactiveThreadCount: 0, traverseRight: false, expectTraverseRight: 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 { for i, c := range cases {
...@@ -738,7 +750,7 @@ func TestEVM_SysFutex_WakePrivate(t *testing.T) { ...@@ -738,7 +750,7 @@ func TestEVM_SysFutex_WakePrivate(t *testing.T) {
state.Memory.SetMemory(state.GetPC(), syscallInsn) state.Memory.SetMemory(state.GetPC(), syscallInsn)
state.GetRegistersRef()[2] = exec.SysFutex // Set syscall number state.GetRegistersRef()[2] = exec.SysFutex // Set syscall number
state.GetRegistersRef()[4] = c.address state.GetRegistersRef()[4] = c.addressParam
state.GetRegistersRef()[5] = exec.FutexWakePrivate state.GetRegistersRef()[5] = exec.FutexWakePrivate
// Set up post-state expectations // Set up post-state expectations
...@@ -746,7 +758,7 @@ func TestEVM_SysFutex_WakePrivate(t *testing.T) { ...@@ -746,7 +758,7 @@ func TestEVM_SysFutex_WakePrivate(t *testing.T) {
expected.ExpectStep() expected.ExpectStep()
expected.ActiveThread().Registers[2] = 0 expected.ActiveThread().Registers[2] = 0
expected.ActiveThread().Registers[7] = 0 expected.ActiveThread().Registers[7] = 0
expected.Wakeup = c.address expected.Wakeup = c.effAddr
expected.ExpectPreemption(state) expected.ExpectPreemption(state)
expected.TraverseRight = c.expectTraverseRight expected.TraverseRight = c.expectTraverseRight
if c.traverseRight != c.expectTraverseRight { if c.traverseRight != c.expectTraverseRight {
...@@ -1192,13 +1204,17 @@ func TestEVM_NormalTraversalStep_HandleWaitingThread(t *testing.T) { ...@@ -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 #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 #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 #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 #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 #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 #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 #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 #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 #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 #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 { for _, c := range cases {
...@@ -1209,7 +1225,7 @@ func TestEVM_NormalTraversalStep_HandleWaitingThread(t *testing.T) { ...@@ -1209,7 +1225,7 @@ func TestEVM_NormalTraversalStep_HandleWaitingThread(t *testing.T) {
if !c.shouldWakeup && c.shouldTimeout { if !c.shouldWakeup && c.shouldTimeout {
require.Fail(t, "Invalid test case - cannot expect a timeout with no wakeup") 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) goVm, state, contracts := setup(t, i, nil)
mttestutil.SetupThreads(int64(i*101), state, traverseRight, c.activeStackSize, c.otherStackSize) mttestutil.SetupThreads(int64(i*101), state, traverseRight, c.activeStackSize, c.otherStackSize)
state.Step = c.step state.Step = c.step
...@@ -1218,7 +1234,7 @@ func TestEVM_NormalTraversalStep_HandleWaitingThread(t *testing.T) { ...@@ -1218,7 +1234,7 @@ func TestEVM_NormalTraversalStep_HandleWaitingThread(t *testing.T) {
activeThread.FutexAddr = c.futexAddr activeThread.FutexAddr = c.futexAddr
activeThread.FutexVal = c.targetValue activeThread.FutexVal = c.targetValue
activeThread.FutexTimeoutStep = c.timeoutStep activeThread.FutexTimeoutStep = c.timeoutStep
state.GetMemory().SetMemory(c.futexAddr, c.actualValue) state.GetMemory().SetMemory(effAddr, c.actualValue)
// Set up post-state expectations // Set up post-state expectations
expected := mttestutil.NewExpectedMTState(state) expected := mttestutil.NewExpectedMTState(state)
...@@ -1312,11 +1328,12 @@ func TestEVM_NormalTraversal_Full(t *testing.T) { ...@@ -1312,11 +1328,12 @@ func TestEVM_NormalTraversal_Full(t *testing.T) {
} }
func TestEVM_WakeupTraversalStep(t *testing.T) { func TestEVM_WakeupTraversalStep(t *testing.T) {
wakeupAddr := uint32(0x1234) addr := uint32(0x1234)
wakeupVal := uint32(0x999) wakeupVal := uint32(0x999)
var tracer *tracing.Hooks var tracer *tracing.Hooks
cases := []struct { cases := []struct {
name string name string
wakeupAddr uint32
futexAddr uint32 futexAddr uint32
targetVal uint32 targetVal uint32
traverseRight bool traverseRight bool
...@@ -1325,19 +1342,28 @@ func TestEVM_WakeupTraversalStep(t *testing.T) { ...@@ -1325,19 +1342,28 @@ func TestEVM_WakeupTraversalStep(t *testing.T) {
shouldClearWakeup bool shouldClearWakeup bool
shouldPreempt 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, not wakeable, first thread", wakeupAddr: addr, futexAddr: addr, 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, 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", futexAddr: wakeupAddr, targetVal: wakeupVal, traverseRight: true, activeStackSize: 1, otherStackSize: 2, 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", futexAddr: wakeupAddr, targetVal: wakeupVal + 1, 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", futexAddr: wakeupAddr, targetVal: wakeupVal, traverseRight: false, activeStackSize: 2, 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", futexAddr: wakeupAddr, targetVal: wakeupVal + 1, traverseRight: true, 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", futexAddr: wakeupAddr + 4, traverseRight: true, activeStackSize: 1, otherStackSize: 2, shouldPreempt: true, 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", futexAddr: wakeupAddr + 4, traverseRight: true, activeStackSize: 2, otherStackSize: 2, shouldPreempt: true}, {name: "Mismatched addr", wakeupAddr: addr, futexAddr: addr + 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", wakeupAddr: addr, futexAddr: addr + 4, traverseRight: false, activeStackSize: 2, otherStackSize: 0, shouldPreempt: true},
{name: "Mismatched addr", futexAddr: wakeupAddr + 4, traverseRight: false, activeStackSize: 1, otherStackSize: 0, shouldPreempt: true}, {name: "Mismatched addr", wakeupAddr: addr, futexAddr: addr + 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", wakeupAddr: addr, 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", wakeupAddr: addr, 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: "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 { for i, c := range cases {
...@@ -1346,8 +1372,8 @@ func TestEVM_WakeupTraversalStep(t *testing.T) { ...@@ -1346,8 +1372,8 @@ func TestEVM_WakeupTraversalStep(t *testing.T) {
mttestutil.SetupThreads(int64(i*101), state, c.traverseRight, c.activeStackSize, c.otherStackSize) mttestutil.SetupThreads(int64(i*101), state, c.traverseRight, c.activeStackSize, c.otherStackSize)
step := state.Step step := state.Step
state.Wakeup = wakeupAddr state.Wakeup = c.wakeupAddr
state.GetMemory().SetMemory(wakeupAddr, wakeupVal) state.GetMemory().SetMemory(c.wakeupAddr&0xFF_FF_FF_FC, wakeupVal)
activeThread := state.GetCurrentThread() activeThread := state.GetCurrentThread()
activeThread.FutexAddr = c.futexAddr activeThread.FutexAddr = c.futexAddr
activeThread.FutexVal = c.targetVal activeThread.FutexVal = c.targetVal
......
...@@ -144,8 +144,8 @@ ...@@ -144,8 +144,8 @@
"sourceCodeHash": "0xba4674e1846afbbc708877332a38dfabd4b8d1e48ce07d8ebf0a45c9f27f16b0" "sourceCodeHash": "0xba4674e1846afbbc708877332a38dfabd4b8d1e48ce07d8ebf0a45c9f27f16b0"
}, },
"src/cannon/MIPS2.sol": { "src/cannon/MIPS2.sol": {
"initCodeHash": "0xdaed5d70cc84a53f224c28f24f8eef26d5d53dfba9fdc4f1b28c3b231b974e53", "initCodeHash": "0xd9da47f735b7a655a25ae0e867b467620a2cb537eb65d184a361f5ea4174d384",
"sourceCodeHash": "0x4026eb7ae7b303ec4c3c2880e14e260dbcfc0b4290459bcd22994cfed8655f80" "sourceCodeHash": "0x3a6d83a7d46eb267f6778f8ae116383fe3c14ad553d90b6c761fafeef22ae29c"
}, },
"src/cannon/PreimageOracle.sol": { "src/cannon/PreimageOracle.sol": {
"initCodeHash": "0x801e52f9c8439fcf7089575fa93272dfb874641dbfc7d82f36d979c987271c0b", "initCodeHash": "0x801e52f9c8439fcf7089575fa93272dfb874641dbfc7d82f36d979c987271c0b",
......
...@@ -57,8 +57,8 @@ contract MIPS2 is ISemver { ...@@ -57,8 +57,8 @@ contract MIPS2 is ISemver {
} }
/// @notice The semantic version of the MIPS2 contract. /// @notice The semantic version of the MIPS2 contract.
/// @custom:semver 1.0.0-beta.9 /// @custom:semver 1.0.0-beta.10
string public constant version = "1.0.0-beta.9"; string public constant version = "1.0.0-beta.10";
/// @notice The preimage oracle contract. /// @notice The preimage oracle contract.
IPreimageOracle internal immutable ORACLE; IPreimageOracle internal immutable ORACLE;
...@@ -175,7 +175,7 @@ contract MIPS2 is ISemver { ...@@ -175,7 +175,7 @@ contract MIPS2 is ISemver {
// Don't allow regular execution until we resolved if we have woken up any thread. // 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 != sys.FUTEX_EMPTY_ADDR) {
if (state.wakeup == thread.futexAddr) { if (state.wakeup == thread.futexAddr) {
// completed wake traverssal // completed wake traversal
// resume execution on woken up thread // resume execution on woken up thread
state.wakeup = sys.FUTEX_EMPTY_ADDR; state.wakeup = sys.FUTEX_EMPTY_ADDR;
return outputState(); return outputState();
...@@ -431,15 +431,15 @@ contract MIPS2 is ISemver { ...@@ -431,15 +431,15 @@ contract MIPS2 is ISemver {
return outputState(); return outputState();
} else if (syscall_no == sys.SYS_FUTEX) { } else if (syscall_no == sys.SYS_FUTEX) {
// args: a0 = addr, a1 = op, a2 = val, a3 = timeout // args: a0 = addr, a1 = op, a2 = val, a3 = timeout
uint32 effAddr = a0 & 0xFFffFFfc;
if (a1 == sys.FUTEX_WAIT_PRIVATE) { if (a1 == sys.FUTEX_WAIT_PRIVATE) {
uint32 mem = MIPSMemory.readMem( uint32 mem =
state.memRoot, a0 & 0xFFffFFfc, MIPSMemory.memoryProofOffset(MEM_PROOF_OFFSET, 1) MIPSMemory.readMem(state.memRoot, effAddr, MIPSMemory.memoryProofOffset(MEM_PROOF_OFFSET, 1));
);
if (mem != a2) { if (mem != a2) {
v0 = sys.SYS_ERROR_SIGNAL; v0 = sys.SYS_ERROR_SIGNAL;
v1 = sys.EAGAIN; v1 = sys.EAGAIN;
} else { } else {
thread.futexAddr = a0; thread.futexAddr = effAddr;
thread.futexVal = a2; thread.futexVal = a2;
thread.futexTimeoutStep = a3 == 0 ? sys.FUTEX_NO_TIMEOUT : state.step + sys.FUTEX_TIMEOUT_STEPS; 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` // Leave cpu scalars as-is. This instruction will be completed by `onWaitComplete`
...@@ -449,7 +449,7 @@ contract MIPS2 is ISemver { ...@@ -449,7 +449,7 @@ contract MIPS2 is ISemver {
} else if (a1 == sys.FUTEX_WAKE_PRIVATE) { } else if (a1 == sys.FUTEX_WAKE_PRIVATE) {
// Trigger thread traversal starting from the left stack until we find one waiting on the wakeup // Trigger thread traversal starting from the left stack until we find one waiting on the wakeup
// address // 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. // 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. // The woken up thread should indicate this in userspace.
v0 = 0; v0 = 0;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment