-
Notifications
You must be signed in to change notification settings - Fork 981
Description
Summary
I discovered an issue with device.AsmFull
where it incorrectly processes MapUpdate
operations that occur after the AsmFull call, causing the function to return unexpected values from future map modifications instead of the values present at call time.
Problem Description
The issue is in compiler/inlineasm.go
at line 62, where the code uses break
to exit a switch
statement but continues processing subsequent MapUpdate
operations in the referrers loop:
case *ssa.Call:
if r.Common() == instr {
break // ❌ Only breaks from switch, continues for loop
}
This means that map updates happening after the AsmFull call are still collected and can affect the result.
Reproduction
package main
import (
"device"
"machine"
"time"
)
func main() {
machine.Serial.Configure(machine.UARTConfig{BaudRate: 115200})
time.Sleep(1 * time.Second)
place := map[string]interface{}{
"input": uint32(42),
}
result := device.AsmFull("mov {}, {input}", place)
place["input"] = uint32(44) // This MapUpdate affects the result!
println("Expected: 42, Got:", uint32(result))
}
Expected Result
Expected: 42, Got: 42
Actual Result (Before Fix)
Expected: 42, Got: 44
Root Cause Analysis
The original code appears to intend to stop processing referrers when encountering the AsmFull call itself, but uses break
which only exits the switch
statement, not the entire for
loop. This allows subsequent MapUpdate operations to be processed incorrectly.
Impact
This bug can cause: Unexpected behavior where AsmFull returns "future" values instead of call-time values
Thank you for maintaining TinyGo! This is an amazing project and I'm happy to contribute to its improvement. 😊