vm: clone Struct on APPEND

This commit is contained in:
Evgenii Stratonikov 2019-09-18 14:03:15 +03:00
parent facf34e821
commit 99f1d761ca
3 changed files with 34 additions and 2 deletions

View file

@ -75,6 +75,21 @@ func (i *StructItem) String() string {
return "Struct" return "Struct"
} }
// Clone returns a Struct with all Struct fields copied by value.
// Array fields are still copied by reference.
func (i *StructItem) Clone() *StructItem {
ret := &StructItem{make([]StackItem, len(i.value))}
for j := range i.value {
switch t := i.value[j].(type) {
case *StructItem:
ret.value[j] = t.Clone()
default:
ret.value[j] = t
}
}
return ret
}
// BigIntegerItem represents a big integer on the stack. // BigIntegerItem represents a big integer on the stack.
type BigIntegerItem struct { type BigIntegerItem struct {
value *big.Int value *big.Int

View file

@ -642,14 +642,19 @@ func (v *VM) execute(ctx *Context, op Instruction) {
itemElem := v.estack.Pop() itemElem := v.estack.Pop()
arrElem := v.estack.Pop() arrElem := v.estack.Pop()
val := itemElem.value
if t, ok := itemElem.value.(*StructItem); ok {
val = t.Clone()
}
switch t := arrElem.value.(type) { switch t := arrElem.value.(type) {
case *ArrayItem: case *ArrayItem:
arr := t.Value().([]StackItem) arr := t.Value().([]StackItem)
arr = append(arr, itemElem.value) arr = append(arr, val)
t.value = arr t.value = arr
case *StructItem: case *StructItem:
arr := t.Value().([]StackItem) arr := t.Value().([]StackItem)
arr = append(arr, itemElem.value) arr = append(arr, val)
t.value = arr t.value = arr
default: default:
panic("APPEND: not of underlying type Array") panic("APPEND: not of underlying type Array")

View file

@ -538,6 +538,18 @@ func TestAPPENDStruct(t *testing.T) {
assert.Equal(t, &StructItem{[]StackItem{makeStackItem(5)}}, vm.estack.Pop().value) assert.Equal(t, &StructItem{[]StackItem{makeStackItem(5)}}, vm.estack.Pop().value)
} }
func TestAPPENDCloneStruct(t *testing.T) {
prog := makeProgram(DUP, PUSH0, NEWSTRUCT, TOALTSTACK, DUPFROMALTSTACK, APPEND, FROMALTSTACK, PUSH1, APPEND)
vm := load(prog)
vm.estack.Push(&Element{value: &ArrayItem{}})
vm.Run()
assert.Equal(t, false, vm.state.HasFlag(faultState))
assert.Equal(t, 1, vm.estack.Len())
assert.Equal(t, &ArrayItem{[]StackItem{
&StructItem{[]StackItem{}},
}}, vm.estack.Pop().value)
}
func TestAPPENDBadNoArguments(t *testing.T) { func TestAPPENDBadNoArguments(t *testing.T) {
prog := makeProgram(APPEND) prog := makeProgram(APPEND)
vm := load(prog) vm := load(prog)