interp: defer out-of-bounds loads to runtime instead of crashing#5458
Conversation
When the interpreter encountered a load that was out of bounds of the
object, it panicked with "interp: load out of bounds", crashing the
compiler. This can happen for valid Go programs, for example when
dereferencing the pointer returned by unsafe.SliceData on a
zero-capacity slice, which points to a zero-sized object:
package main
import "unsafe"
var p = unsafe.SliceData([]int{})
var v = *p
func main() {}
Return nil for an out-of-bounds load, the same as for an external
global, so the caller defers the load to runtime instead of crashing.
This matches what regular Go does, where the load reads from the
runtime zero-base at runtime.
Fixes tinygo-org#4214
|
/cc @aykevl for interp |
jakebailey
left a comment
There was a problem hiding this comment.
Based on my own (limited) experience in interp, this seems right to me? e.g. in my PR to limit interp iterations bailing out is the right way to get it to do something at runtime instead. The only reason this code should panic is for internal errors, not because the user code does something that will panic at runtime.
|
@aykevl or anyone else have any feedback here? |
|
Based on previous feedback from @niaow since this is undefined behavior, we probably should not do what is in this PR? Not sure on that, however. |
|
It is, but I don't think bad code should crash the compiler |
aykevl
left a comment
There was a problem hiding this comment.
Looks good to me. It doesn't add undefined behavior, it just bails and defers to runtime (where the panic should be caught).
|
Thank you for the fix @iamrajiv and to everyone who reviewed. Now merging! |
Fixes #4214
When the interpreter encountered a load that was out of bounds of the object, it panicked with "interp: load out of bounds", crashing the compiler. This can happen for valid Go programs, for example when dereferencing the pointer returned by unsafe.SliceData on a zero-capacity slice, which points to a zero-sized object:
Return nil for an out-of-bounds load, the same as for an external global, so the caller defers the load to runtime instead of crashing. This matches what regular Go does, where the load reads from the runtime zero-base at runtime.