diff options
author | Ayke van Laethem <[email protected]> | 2022-05-21 15:46:00 +0200 |
---|---|---|
committer | Ron Evans <[email protected]> | 2022-05-22 15:08:17 +0200 |
commit | b8e433821adca1d1b68abb584e606a1217434894 (patch) | |
tree | e0ac2e84c71bbb01942bf428acda3528fa21bcb1 | |
parent | dd1a836903ea52c7f6a52a01ac4ccc27a63006f2 (diff) | |
download | tinygo-b8e433821adca1d1b68abb584e606a1217434894.tar.gz tinygo-b8e433821adca1d1b68abb584e606a1217434894.zip |
interp: fix some buggy localValue handling
Bug:
1. fn.locals[v.value] returns 0 (the default value) if v.value is not
part of the fn.locals map.
2. locals[fn.locals[v.value]] then returns the first local value, which
is usually non-nil
3. This incorrect value is then used as the operand value.
The manifestation of this convoluted bug was
https://github.com/tinygo-org/tinygo/issues/2842. It didn't occur more
often probably because it only seems to happen in practice with inline
assembly.
Fixes https://github.com/tinygo-org/tinygo/issues/2842
-rw-r--r-- | interp/interpreter.go | 18 |
1 files changed, 17 insertions, 1 deletions
diff --git a/interp/interpreter.go b/interp/interpreter.go index 0f2355a68..cccbe7b3b 100644 --- a/interp/interpreter.go +++ b/interp/interpreter.go @@ -81,12 +81,28 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent if inst.opcode != llvm.PHI { for _, v := range inst.operands { if v, ok := v.(localValue); ok { - if localVal := locals[fn.locals[v.value]]; localVal == nil { + index, ok := fn.locals[v.value] + if !ok { + // This is a localValue that is not local to the + // function. An example would be an inline assembly call + // operand. + isRuntimeInst = true + break + } + localVal := locals[index] + if localVal == nil { + // Trying to read a function-local value before it is + // set. return nil, mem, r.errorAt(inst, errors.New("interp: local not defined")) } else { operands = append(operands, localVal) if _, ok := localVal.(localValue); ok { + // The function-local value is still just a + // localValue (which can't be interpreted at compile + // time). Not sure whether this ever happens in + // practice. isRuntimeInst = true + break } continue } |