Skip to content

Commit

Permalink
fix(gnovm): correctly update refs count when self-assigning
Browse files Browse the repository at this point in the history
this solution was mostly found by @peter7891

Signed-off-by: Norman Meier <norman@berty.tech>
  • Loading branch information
n0izn0iz committed Jul 15, 2023
1 parent 973be98 commit cb0665c
Showing 1 changed file with 26 additions and 25 deletions.
51 changes: 26 additions & 25 deletions gnovm/pkg/gnolang/realm.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,52 +126,53 @@ func (rlm *Realm) String() string {
// if rlm or po is nil, do nothing.
// xo or co is nil if the element value is undefined or has no
// associated object.
func (rlm *Realm) DidUpdate(po, xo, co Object) {
func (rlm *Realm) DidUpdate(owner, oldValue, newValue Object) {
if rlm == nil {
return
}
if debug {
if co != nil && co.GetIsDeleted() {
if newValue != nil && newValue.GetIsDeleted() {
panic("cannot attach a deleted object")
}
if po != nil && po.GetIsTransient() {
if owner != nil && owner.GetIsTransient() {
panic("should not happen")
}
if po != nil && po.GetIsDeleted() {
if owner != nil && owner.GetIsDeleted() {
panic("cannot attach to a deleted object")
}
}
if po == nil || !po.GetIsReal() {
if owner == nil || !owner.GetIsReal() {
return // do nothing.
}
if po.GetObjectID().PkgID != rlm.ID {
if owner.GetObjectID().PkgID != rlm.ID {
panic("cannot modify external-realm or non-realm object")
}
// From here on, po is real (not new-real).
// Updates to .newCreated/.newEscaped /.newDeleted made here. (first gen)
// More appends happen during FinalizeRealmTransactions(). (second+ gen)
rlm.MarkDirty(po)
if co != nil {
co.IncRefCount()
if co.GetRefCount() > 1 {
if co.GetIsEscaped() {
// already escaped
} else {
rlm.MarkNewEscaped(co)
}
} else if co.GetIsReal() {
rlm.MarkDirty(co)
rlm.MarkDirty(owner)

updateRefs := oldValue != newValue

if newValue != nil {
if updateRefs {
newValue.IncRefCount()
}
if newValue.GetRefCount() > 1 && !newValue.GetIsEscaped() {
rlm.MarkNewEscaped(newValue)
} else if newValue.GetIsReal() {
rlm.MarkDirty(newValue)
} else {
co.SetOwner(po)
rlm.MarkNewReal(co)
newValue.SetOwner(owner)
rlm.MarkNewReal(newValue)
}
}
if xo != nil {
xo.DecRefCount()
if xo.GetRefCount() == 0 {
if xo.GetIsReal() {
rlm.MarkNewDeleted(xo)
}
if oldValue != nil {
if updateRefs {
oldValue.DecRefCount()
}
if oldValue.GetRefCount() == 0 && oldValue.GetIsReal() {
rlm.MarkNewDeleted(oldValue)
}
}
}
Expand Down

0 comments on commit cb0665c

Please sign in to comment.