Skip to content

Commit

Permalink
Merge pull request #3010 from onflow/bastian/defensive-dereference-check
Browse files Browse the repository at this point in the history
  • Loading branch information
turbolent authored Jan 11, 2024
2 parents 656acc3 + 26d4494 commit 08be353
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 3 deletions.
13 changes: 13 additions & 0 deletions runtime/interpreter/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -1051,3 +1051,16 @@ func (e InclusiveRangeConstructionError) Error() string {
}
return fmt.Sprintf("%s: %s", message, e.Message)
}

// ResourceReferenceDereferenceError
type ResourceReferenceDereferenceError struct {
LocationRange
}

var _ errors.InternalError = ResourceReferenceDereferenceError{}

func (ResourceReferenceDereferenceError) IsInternalError() {}

func (e ResourceReferenceDereferenceError) Error() string {
return "internal error: resource-references cannot be dereferenced"
}
12 changes: 10 additions & 2 deletions runtime/interpreter/value.go
Original file line number Diff line number Diff line change
Expand Up @@ -19932,8 +19932,16 @@ func DereferenceValue(
locationRange LocationRange,
referenceValue ReferenceValue,
) Value {
referencedValue := referenceValue.ReferencedValue(inter, locationRange, true)
return (*referencedValue).Transfer(
referencedValue := *referenceValue.ReferencedValue(inter, locationRange, true)

// Defensive check: ensure that the referenced value is not a resource
if referencedValue.IsResourceKinded(inter) {
panic(ResourceReferenceDereferenceError{
LocationRange: locationRange,
})
}

return referencedValue.Transfer(
inter,
locationRange,
atree.Address{},
Expand Down
67 changes: 66 additions & 1 deletion runtime/tests/interpreter/reference_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1648,7 +1648,7 @@ func TestInterpretReferenceTrackingOnInvocation(t *testing.T) {
`)

_, err := inter.Invoke("main")
require.Error(t, err)
RequireError(t, err)

require.ErrorAs(t, err, &interpreter.InvalidatedResourceReferenceError{})
}
Expand Down Expand Up @@ -2956,4 +2956,69 @@ func TestInterpretDereference(t *testing.T) {
)
})

t.Run("Resource", func(t *testing.T) {
t.Parallel()

t.Run("direct", func(t *testing.T) {
t.Parallel()

inter, err := parseCheckAndInterpretWithOptions(t,
`
resource R {}
fun main() {
let r1 <- create R()
let r1Ref: &R = &r1
let r2 <- *r1Ref
destroy r1
destroy r2
}
`,
ParseCheckAndInterpretOptions{
HandleCheckerError: func(err error) {
errs := checker.RequireCheckerErrors(t, err, 1)

require.IsType(t, &sema.InvalidUnaryOperandError{}, errs[0])
},
},
)
require.NoError(t, err)

_, err = inter.Invoke("main")
RequireError(t, err)

require.ErrorAs(t, err, &interpreter.ResourceReferenceDereferenceError{})
})

t.Run("array", func(t *testing.T) {
t.Parallel()

inter, err := parseCheckAndInterpretWithOptions(t,
`
resource R {}
fun main() {
let rs1 <- [<- create R()]
let rs1Ref: &[R] = &rs1
let rs2 <- *rs1Ref
destroy rs1
destroy rs2
}
`,
ParseCheckAndInterpretOptions{
HandleCheckerError: func(err error) {
errs := checker.RequireCheckerErrors(t, err, 1)

require.IsType(t, &sema.InvalidUnaryOperandError{}, errs[0])
},
},
)
require.NoError(t, err)

_, err = inter.Invoke("main")
RequireError(t, err)

require.ErrorAs(t, err, &interpreter.ResourceReferenceDereferenceError{})
})
})
}

0 comments on commit 08be353

Please sign in to comment.