Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: addressability problem #2689

Closed
wants to merge 29 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions gnovm/pkg/gnolang/alloc.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,14 +196,16 @@ func (alloc *Allocator) NewString(s string) StringValue {
func (alloc *Allocator) NewListArray(n int) *ArrayValue {
alloc.AllocateListArray(int64(n))
return &ArrayValue{
List: make([]TypedValue, n),
List: make([]TypedValue, n),
NotAddressable: true,
}
}

func (alloc *Allocator) NewDataArray(n int) *ArrayValue {
alloc.AllocateDataArray(int64(n))
return &ArrayValue{
Data: make([]byte, n),
Data: make([]byte, n),
NotAddressable: true,
}
}

Expand Down
1 change: 1 addition & 0 deletions gnovm/pkg/gnolang/gonative.go
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,7 @@
}
}
tv.V = av
tv.NotAddressable = av.NotAddressable

Check warning on line 718 in gnovm/pkg/gnolang/gonative.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/gonative.go#L718

Added line #L718 was not covered by tests
}
case reflect.Slice:
rvl := rv.Len()
Expand Down
10 changes: 9 additions & 1 deletion gnovm/pkg/gnolang/machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -1954,6 +1954,10 @@ func (m *Machine) PopFrameAndReturn() {
if res.IsUndefined() && rtypes[i].Type.Kind() != InterfaceKind {
res.T = rtypes[i].Type
}

if _, ok := res.V.(*ArrayValue); ok {
res.Unaddressable()
}
m.Values[fr.NumValues+i] = res
}
m.NumValues = fr.NumValues + numRes
Expand Down Expand Up @@ -2087,10 +2091,14 @@ func (m *Machine) PopAsPointer(lx Expr) PointerValue {
case *IndexExpr:
iv := m.PopValue()
xv := m.PopValue()

return xv.GetPointerAtIndex(m.Alloc, m.Store, iv)
case *SelectorExpr:
xv := m.PopValue()
return xv.GetPointerTo(m.Alloc, m.Store, lx.Path)
nxv := xv.GetPointerTo(m.Alloc, m.Store, lx.Path)
nxv.TV.NotRef = xv.NotRef

return nxv
case *StarExpr:
ptr := m.PopValue().V.(PointerValue)
return ptr
Expand Down
3 changes: 3 additions & 0 deletions gnovm/pkg/gnolang/op_assign.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ func (m *Machine) doOpDefine() {
}
}
}
rvs[i].Addressable()
ptr.Assign2(m.Alloc, m.Store, m.Realm, rvs[i], true)
}
}
Expand All @@ -41,6 +42,8 @@ func (m *Machine) doOpAssign() {
}
}
}

rvs[i].Addressable()
lv.Assign2(m.Alloc, m.Store, m.Realm, rvs[i], true)
}
}
Expand Down
4 changes: 4 additions & 0 deletions gnovm/pkg/gnolang/op_call.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,9 @@ func (m *Machine) doOpCall() {
list := m.PopCopyValues(nvar)
vart := pts[numParams-1].Type.(*SliceType)
varg := m.Alloc.NewSliceFromList(list)

varg.Addressable()

m.PushValue(TypedValue{
T: vart,
V: varg,
Expand Down Expand Up @@ -165,6 +168,7 @@ func (m *Machine) doOpCall() {
// Make a copy so that a reference to the argument isn't used
// in cases where the non-primitive value type is represented
// as a pointer, *StructValue, for example.
pv.Addressable()
b.Values[i] = pv.Copy(m.Alloc)
}
}
Expand Down
1 change: 1 addition & 0 deletions gnovm/pkg/gnolang/op_decl.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ func (m *Machine) doOpValueDecl() {
}
nx := s.NameExprs[i]
ptr := lb.GetPointerTo(m.Store, nx.Path)
tv.Addressable()
ptr.Assign2(m.Alloc, m.Store, m.Realm, tv, false)
}
}
Expand Down
38 changes: 34 additions & 4 deletions gnovm/pkg/gnolang/op_expressions.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ func (m *Machine) doOpIndex1() {
}
iv := m.PopValue() // index
xv := m.PeekValue(1) // x

switch ct := baseOf(xv.T).(type) {
case *MapType:
mv := xv.V.(*MapValue)
Expand Down Expand Up @@ -44,6 +45,7 @@ func (m *Machine) doOpIndex2() {
}
iv := m.PeekValue(1) // index
xv := m.PeekValue(2) // x

switch ct := baseOf(xv.T).(type) {
case *MapType:
vt := ct.Value
Expand Down Expand Up @@ -105,6 +107,11 @@ func (m *Machine) doOpSlice() {
}
// slice base x
xv := m.PopValue()

if _, ok := xv.V.(Addressable); ok && xv.NotAddressable {
panic(fmt.Sprintf("doOpSlice: expr not addressable: %+v\n", xv))
}

// if a is a pointer to an array, a[low : high : max] is
// shorthand for (*a)[low : high : max]
if xv.T.Kind() == PointerKind &&
Expand Down Expand Up @@ -199,9 +206,21 @@ func (m *Machine) doOpRef() {
if elt == DataByteType {
elt = xv.TV.V.(DataByteValue).ElemType
}

if array, ok := xv.Base.(*ArrayValue); ok {
if array.NotAddressable {
panic(fmt.Sprintf("doOpRef: expr not addressable: %+v\n", array))
}
}

if xv.TV.NotRef {
panic(fmt.Sprintf("doOpRef: expr not addressable: %+v\n", xv.TV))
}

m.PushValue(TypedValue{
T: m.Alloc.NewType(&PointerType{Elt: elt}),
V: xv,
T: m.Alloc.NewType(&PointerType{Elt: elt}),
V: xv,
NotAddressable: xv.TV.NotAddressable,
})
}

Expand All @@ -215,6 +234,11 @@ func (m *Machine) doOpTypeAssert1() {
xv := m.PeekValue(1) // value result / value to assert
xt := xv.T // underlying value's type

defer func() {
xv.Unaddressable()
xv.NotRef = true
}()

// xt may be nil, but we need to wait to return because the value of xt that is set
// will depend on whether we are trying to assert to an interface or concrete type.
// xt can be nil in the case where recover can't find a panic to recover from and
Expand Down Expand Up @@ -322,6 +346,11 @@ func (m *Machine) doOpTypeAssert2() {
xv := m.PeekValue(2) // value result / value to assert
xt := xv.T // underlying value's type

defer func() {
xv.Unaddressable()
xv.NotRef = true
}()

// xt may be nil, but we need to wait to return because the value of xt that is set
// will depend on whether we are trying to assert to an interface or concrete type.
// xt can be nil in the case where recover can't find a panic to recover from and
Expand Down Expand Up @@ -550,8 +579,9 @@ func (m *Machine) doOpArrayLit() {
}
// push value
m.PushValue(TypedValue{
T: at,
V: av,
T: at,
V: av,
NotAddressable: av.NotAddressable,
})
}

Expand Down
140 changes: 133 additions & 7 deletions gnovm/pkg/gnolang/values.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@
"github.com/gnolang/gno/tm2/pkg/crypto"
)

type Addressable interface {
Addressable()
Unaddressable()
}

// ----------------------------------------
// (runtime) Value

Expand Down Expand Up @@ -186,6 +191,37 @@
Key *TypedValue `json:",omitempty"` // for maps.
}

func (pv *PointerValue) Addressable() {
if pv.TV == nil {
return

Check warning on line 196 in gnovm/pkg/gnolang/values.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/values.go#L196

Added line #L196 was not covered by tests
}

// if addressable
if !pv.TV.NotAddressable {
return

Check warning on line 201 in gnovm/pkg/gnolang/values.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/values.go#L201

Added line #L201 was not covered by tests
}

pv.TV.NotAddressable = false
if iface, ok := pv.TV.V.(Addressable); ok {
iface.Addressable()
}
}

func (pv *PointerValue) Unaddressable() {
if pv.TV == nil {
return

Check warning on line 212 in gnovm/pkg/gnolang/values.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/values.go#L210-L212

Added lines #L210 - L212 were not covered by tests
}

if pv.TV.NotAddressable {
return

Check warning on line 216 in gnovm/pkg/gnolang/values.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/values.go#L215-L216

Added lines #L215 - L216 were not covered by tests
}

pv.TV.NotAddressable = true
if iface, ok := pv.TV.V.(Addressable); ok {
iface.Unaddressable()

Check warning on line 221 in gnovm/pkg/gnolang/values.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/values.go#L219-L221

Added lines #L219 - L221 were not covered by tests
}
}

const (
PointerIndexBlockBlank = -1 // for the "_" identifier in blocks
PointerIndexMap = -2 // Base is Map, use Key.
Expand Down Expand Up @@ -315,8 +351,34 @@

type ArrayValue struct {
ObjectInfo
List []TypedValue
Data []byte
List []TypedValue
Data []byte
NotAddressable bool
}

func (av *ArrayValue) Addressable() {
// if addressable
if !av.NotAddressable {
return
}

av.NotAddressable = false

for i := range av.List {
av.List[i].Addressable()
}
}

func (av *ArrayValue) Unaddressable() {
if av.NotAddressable {
return
}

av.NotAddressable = true

Check warning on line 377 in gnovm/pkg/gnolang/values.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/values.go#L377

Added line #L377 was not covered by tests

for i := range av.List {
av.List[i].Unaddressable()

Check warning on line 380 in gnovm/pkg/gnolang/values.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/values.go#L379-L380

Added lines #L379 - L380 were not covered by tests
}
}

// NOTE: Result should not be written to,
Expand Down Expand Up @@ -392,6 +454,7 @@
if av.Data == nil {
av2 := alloc.NewListArray(len(av.List))
copy(av2.List, av.List)
av2.NotAddressable = av.NotAddressable
return av2
}
av2 := alloc.NewDataArray(len(av.Data))
Expand All @@ -409,6 +472,18 @@
Maxcap int
}

func (sv *SliceValue) Addressable() {
if iface, ok := sv.Base.(Addressable); ok {
iface.Addressable()
}
}

func (sv *SliceValue) Unaddressable() {
if iface, ok := sv.Base.(Addressable); ok {
iface.Unaddressable()

Check warning on line 483 in gnovm/pkg/gnolang/values.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/values.go#L481-L483

Added lines #L481 - L483 were not covered by tests
}
}

func (sv *SliceValue) GetBase(store Store) *ArrayValue {
switch cv := sv.Base.(type) {
case nil:
Expand Down Expand Up @@ -454,6 +529,18 @@
Fields []TypedValue
}

func (sv *StructValue) Addressable() {
for i := range sv.Fields {
sv.Fields[i].Addressable()

Check warning on line 534 in gnovm/pkg/gnolang/values.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/values.go#L532-L534

Added lines #L532 - L534 were not covered by tests
}
}

func (sv *StructValue) Unaddressable() {
for i := range sv.Fields {
sv.Fields[i].Unaddressable()

Check warning on line 540 in gnovm/pkg/gnolang/values.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/values.go#L538-L540

Added lines #L538 - L540 were not covered by tests
}
}

// TODO handle unexported fields in debug, and also ensure in the preprocessor.
func (sv *StructValue) GetPointerTo(store Store, path ValuePath) PointerValue {
if debug {
Expand Down Expand Up @@ -955,9 +1042,37 @@
// TypedValue (is not a value, but a tuple)

type TypedValue struct {
T Type `json:",omitempty"` // never nil
V Value `json:",omitempty"` // an untyped value
N [8]byte `json:",omitempty"` // numeric bytes
T Type `json:",omitempty"` // never nil
V Value `json:",omitempty"` // an untyped value
N [8]byte `json:",omitempty"` // numeric bytes
NotAddressable bool `json:"-"`
NotRef bool `json:"-"`
}

func (tv *TypedValue) Addressable() {
// if addressable
if !tv.NotAddressable {
return
}
tv.NotAddressable = false
if p, ok := tv.V.(PointerValue); ok {
p.Addressable()
} else if iface, ok := tv.V.(Addressable); ok {
iface.Addressable()
}
}

func (tv *TypedValue) Unaddressable() {
// if addressable
if tv.NotAddressable {
return
}
tv.NotAddressable = true
if p, ok := tv.V.(PointerValue); ok {
p.Unaddressable()

Check warning on line 1072 in gnovm/pkg/gnolang/values.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/values.go#L1072

Added line #L1072 was not covered by tests
} else if iface, ok := tv.V.(Addressable); ok {
iface.Unaddressable()
}
}

func (tv *TypedValue) IsDefined() bool {
Expand Down Expand Up @@ -2589,9 +2704,20 @@
if t.Kind() == InterfaceKind {
return TypedValue{}
}

dv := defaultValue(alloc, t)

var naddr bool

switch v := dv.(type) {
case *ArrayValue:
naddr = v.NotAddressable
}

return TypedValue{
T: t,
V: defaultValue(alloc, t),
T: t,
V: dv,
NotAddressable: naddr,
}
}

Expand Down
6 changes: 3 additions & 3 deletions gnovm/stdlibs/crypto/sha256/sha256_test.gno
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import (
)

func TestSha256Sum(t *testing.T) {
got := sha256.Sum256([]byte("sha256 this string"))[:]
got := sha256.Sum256([]byte("sha256 this string"))
expected := "1af1dfa857bf1d8814fe1af8983c18080019922e557f15a8a0d3db739d77aacb"

if hex.EncodeToString(got) != expected {
t.Errorf("got %v(%T), expected %v(%T)", hex.EncodeToString(got), got, expected, expected)
if hex.EncodeToString(got[:]) != expected {
t.Errorf("got %v(%T), expected %v(%T)", hex.EncodeToString(got[:]), got, expected, expected)
}
}
Loading
Loading