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

Port fixes of v0.42.8-patch.4 #3079

Merged
merged 30 commits into from
Apr 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
df1d4ca
Add resource loss test
SupunS Nov 27, 2023
1e146b6
Prevent resource loss in member assignment
SupunS Dec 1, 2023
63270be
Prevent resource loss in index assignment
SupunS Dec 1, 2023
eb26e45
Refactor. Add resource loss check for variable assignment
SupunS Dec 1, 2023
3fd1b6f
Lint
SupunS Dec 5, 2023
f1f8b26
Add test for nested swap
SupunS Nov 21, 2023
0e61667
reject nested resource swap
turbolent Dec 11, 2023
f38a0c1
adjust test
turbolent Dec 11, 2023
7aa75c0
swap order
turbolent Dec 12, 2023
58b8446
fix checking of switch cases
turbolent Jan 29, 2024
71a1b09
handle unavailable index expression type case
turbolent Jan 29, 2024
774810d
add test for self rugpull resource loss
turbolent Jan 31, 2024
0ef82a8
check import locations when validating contract updates
dsainati1 Jan 31, 2024
afc183a
remove unnecessary code
dsainati1 Jan 31, 2024
eb042fb
remove unnecessary code
dsainati1 Jan 31, 2024
73470a0
add support for imports without explicit identifiers
dsainati1 Feb 1, 2024
abdf1c0
handle optional chaining when checking invoked expression to be a com…
turbolent Feb 2, 2024
752d44f
convert runtime types on failable cast
dsainati1 Feb 5, 2024
8b32c65
add interpreter tests
turbolent Feb 5, 2024
d3e2507
explain error tye
turbolent Feb 5, 2024
98060c7
perform elaboration lookup only once
turbolent Feb 5, 2024
80a057b
move test
turbolent Feb 6, 2024
9a2c5b5
adjust/simplify test, given latest fixes
turbolent Feb 6, 2024
d626227
adjust tests to Cadence 1.0
turbolent Feb 6, 2024
f03315d
Merge branch 'master' of https://github.com/onflow/cadence into basti…
SupunS Apr 2, 2024
68f0aa5
Check for invalidated resource in expression getter-setter
SupunS Apr 2, 2024
0077f05
Convert references based on borrow type
SupunS Apr 2, 2024
fbbe6bc
Temporarily disable TestResourceLossViaSelfRugPull
SupunS Apr 3, 2024
1ea69b1
Merge pull request #3213 from onflow/supun/fix-reference-conversion
SupunS Apr 3, 2024
1dc301a
Merge branch 'master' into bastian/v1.0-port-v0.42.8-patch.4
turbolent Apr 3, 2024
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
26 changes: 13 additions & 13 deletions runtime/interpreter/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -340,19 +340,6 @@ func (e DestroyedResourceError) Error() string {
return "resource was destroyed and cannot be used anymore"
}

// ForceAssignmentToNonNilResourceError
type ForceAssignmentToNonNilResourceError struct {
LocationRange
}

var _ errors.UserError = ForceAssignmentToNonNilResourceError{}

func (ForceAssignmentToNonNilResourceError) IsUserError() {}

func (e ForceAssignmentToNonNilResourceError) Error() string {
return "force assignment to non-nil resource-typed value"
}

// ForceNilError
type ForceNilError struct {
LocationRange
Expand Down Expand Up @@ -1107,3 +1094,16 @@ func (ResourceReferenceDereferenceError) IsInternalError() {}
func (e ResourceReferenceDereferenceError) Error() string {
return "internal error: resource-references cannot be dereferenced"
}

// ResourceLossError
type ResourceLossError struct {
LocationRange
}

var _ errors.UserError = ResourceLossError{}

func (ResourceLossError) IsUserError() {}

func (e ResourceLossError) Error() string {
return "resource loss: attempting to assign to non-nil resource-typed value"
}
114 changes: 74 additions & 40 deletions runtime/interpreter/interpreter.go
Original file line number Diff line number Diff line change
Expand Up @@ -925,27 +925,15 @@
HasPosition: position,
}

// If the assignment is a forced move,
// ensure that the target is nil,
// otherwise panic
// Evaluate the value, and assign it using the setter function

if transferOperation == ast.TransferOperationMoveForced {

// If the force-move assignment is used for the initialization of a field,
// then there is no prior value for the field, so allow missing

const allowMissing = true

target := targetGetterSetter.get(allowMissing)

if _, ok := target.(NilValue); !ok && target != nil {
panic(ForceAssignmentToNonNilResourceError{
LocationRange: locationRange,
})
}
}

// Finally, evaluate the value, and assign it using the setter function
// Here it is too early to check whether the existing value is a
// valid non-nil resource (i.e: causing a resource loss), because
// evaluating the `valueExpression` could change things, and
// a `nil`/invalid resource at this point could be valid after
// the evaluation of `valueExpression`.
// Therefore, delay the checking of resource loss as much as possible,
// and check it at the 'setter', at the point where the value is assigned.

value := interpreter.evalExpression(valueExpression)

Expand Down Expand Up @@ -2162,46 +2150,64 @@
}

case *sema.ReferenceType:
if !valueType.Equal(unwrappedTargetType) {
// transferring a reference at runtime does not change its entitlements; this is so that an upcast reference
// can later be downcast back to its original entitlement set

// check defensively that we never create a runtime mapped entitlement value
if _, isMappedAuth := unwrappedTargetType.Authorization.(*sema.EntitlementMapAccess); isMappedAuth {
panic(UnexpectedMappedEntitlementError{
Type: unwrappedTargetType,
LocationRange: locationRange,
})
}

switch ref := value.(type) {
case *EphemeralReferenceValue:
targetAuthorization := ConvertSemaAccessToStaticAuthorization(interpreter, unwrappedTargetType.Authorization)
switch ref := value.(type) {
case *EphemeralReferenceValue:
if interpreter.shouldConvertReference(ref, valueType, unwrappedTargetType, targetAuthorization) {
checkMappedEntitlements(unwrappedTargetType, locationRange)
return NewEphemeralReferenceValue(
interpreter,
ConvertSemaAccessToStaticAuthorization(interpreter, unwrappedTargetType.Authorization),
targetAuthorization,
ref.Value,
unwrappedTargetType.Type,
locationRange,
)
}

case *StorageReferenceValue:
case *StorageReferenceValue:
if interpreter.shouldConvertReference(ref, valueType, unwrappedTargetType, targetAuthorization) {
checkMappedEntitlements(unwrappedTargetType, locationRange)
return NewStorageReferenceValue(
interpreter,
ConvertSemaAccessToStaticAuthorization(interpreter, unwrappedTargetType.Authorization),
targetAuthorization,
ref.TargetStorageAddress,
ref.TargetPath,
unwrappedTargetType.Type,
)

default:
panic(errors.NewUnexpectedError("unsupported reference value: %T", ref))
}

default:
panic(errors.NewUnexpectedError("unsupported reference value: %T", ref))

Check warning on line 2180 in runtime/interpreter/interpreter.go

View check run for this annotation

Codecov / codecov/patch

runtime/interpreter/interpreter.go#L2179-L2180

Added lines #L2179 - L2180 were not covered by tests
}
}

return value
}

func (interpreter *Interpreter) shouldConvertReference(
ref ReferenceValue,
valueType sema.Type,
unwrappedTargetType *sema.ReferenceType,
targetAuthorization Authorization,
) bool {
if !valueType.Equal(unwrappedTargetType) {
return true
}

return !ref.BorrowType().Equal(unwrappedTargetType.Type) ||
!ref.GetAuthorization().Equal(targetAuthorization)
}

func checkMappedEntitlements(unwrappedTargetType *sema.ReferenceType, locationRange LocationRange) {
// check defensively that we never create a runtime mapped entitlement value
if _, isMappedAuth := unwrappedTargetType.Authorization.(*sema.EntitlementMapAccess); isMappedAuth {
panic(UnexpectedMappedEntitlementError{
Type: unwrappedTargetType,
LocationRange: locationRange,
})

Check warning on line 2207 in runtime/interpreter/interpreter.go

View check run for this annotation

Codecov / codecov/patch

runtime/interpreter/interpreter.go#L2204-L2207

Added lines #L2204 - L2207 were not covered by tests
}
}

// BoxOptional boxes a value in optionals, if necessary
func (interpreter *Interpreter) BoxOptional(
locationRange LocationRange,
Expand Down Expand Up @@ -5526,3 +5532,31 @@

f()
}

func (interpreter *Interpreter) checkResourceLoss(value Value, locationRange LocationRange) {
if !value.IsResourceKinded(interpreter) {
return
}

var resourceKindedValue ResourceKindedValue

switch existingValue := value.(type) {
case *CompositeValue:
// A dedicated error is thrown when setting duplicate attachments.
// So don't throw an error here.
if existingValue.Kind == common.CompositeKindAttachment {
return
}
resourceKindedValue = existingValue
case ResourceKindedValue:
resourceKindedValue = existingValue
default:
panic(errors.NewUnreachableError())

Check warning on line 5554 in runtime/interpreter/interpreter.go

View check run for this annotation

Codecov / codecov/patch

runtime/interpreter/interpreter.go#L5553-L5554

Added lines #L5553 - L5554 were not covered by tests
}

if !resourceKindedValue.isInvalidatedResource(interpreter) {
panic(ResourceLossError{
LocationRange: locationRange,
})
}
}
Loading
Loading