Skip to content

Commit

Permalink
Merge pull request #2592 from onflow/sainati/entitlement-conversion-c…
Browse files Browse the repository at this point in the history
…rash

Fix crash on entitlement mappings with empty outputs
  • Loading branch information
dsainati1 authored Jun 21, 2023
2 parents c2dc828 + 0983bf8 commit 4c889d8
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 12 deletions.
12 changes: 6 additions & 6 deletions runtime/interpreter/interpreter.go
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,7 @@ func (interpreter *Interpreter) InvokeExternally(

var self *MemberAccessibleValue
var base *EphemeralReferenceValue
var boundAuth *EntitlementSetAuthorization
var boundAuth Authorization
if boundFunc, ok := functionValue.(BoundFunctionValue); ok {
self = boundFunc.Self
base = boundFunc.Base
Expand Down Expand Up @@ -1713,7 +1713,7 @@ func (interpreter *Interpreter) substituteMappedEntitlements(ty sema.Type) sema.
return sema.NewReferenceType(
interpreter,
refType.Type,
interpreter.MustConvertStaticAuthorizationToSemaAccess(*interpreter.SharedState.currentEntitlementMappedValue),
interpreter.MustConvertStaticAuthorizationToSemaAccess(interpreter.SharedState.currentEntitlementMappedValue),
)
}
}
Expand Down Expand Up @@ -4900,17 +4900,17 @@ func (interpreter *Interpreter) mapMemberValueAuthorization(self Value, memberAc
return resultValue
}
if mappedAccess, isMappedAccess := (*memberAccess).(sema.EntitlementMapAccess); isMappedAccess {
var auth EntitlementSetAuthorization
var auth Authorization
switch selfValue := self.(type) {
case AuthorizedValue:
selfAccess := interpreter.MustConvertStaticAuthorizationToSemaAccess(selfValue.GetAuthorization())
imageAccess, err := mappedAccess.Image(selfAccess, func() ast.Range { return ast.EmptyRange })
if err != nil {
panic(err)
}
auth = ConvertSemaAccesstoStaticAuthorization(interpreter, imageAccess).(EntitlementSetAuthorization)
auth = ConvertSemaAccesstoStaticAuthorization(interpreter, imageAccess)
default:
auth = ConvertSemaAccesstoStaticAuthorization(interpreter, mappedAccess.Codomain()).(EntitlementSetAuthorization)
auth = ConvertSemaAccesstoStaticAuthorization(interpreter, mappedAccess.Codomain())
}

switch refValue := resultValue.(type) {
Expand All @@ -4919,7 +4919,7 @@ func (interpreter *Interpreter) mapMemberValueAuthorization(self Value, memberAc
case *StorageReferenceValue:
return NewStorageReferenceValue(interpreter, auth, refValue.TargetStorageAddress, refValue.TargetPath, refValue.BorrowedType)
case BoundFunctionValue:
return NewBoundFunctionValue(interpreter, refValue.Function, refValue.Self, refValue.Base, &auth)
return NewBoundFunctionValue(interpreter, refValue.Function, refValue.Self, refValue.Base, auth)
}
}
return resultValue
Expand Down
2 changes: 1 addition & 1 deletion runtime/interpreter/interpreter_expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -1148,7 +1148,7 @@ func (interpreter *Interpreter) VisitReferenceExpression(referenceExpression *as
// if we are currently interpretering a function that was declared with mapped entitlement access, any appearances
// of that mapped access in the body of the function should be replaced with the computed output of the map
if _, isMapped := typ.Authorization.(sema.EntitlementMapAccess); isMapped && interpreter.SharedState.currentEntitlementMappedValue != nil {
auth = *interpreter.SharedState.currentEntitlementMappedValue
auth = interpreter.SharedState.currentEntitlementMappedValue
} else {
auth = ConvertSemaAccesstoStaticAuthorization(interpreter, typ.Authorization)
}
Expand Down
4 changes: 2 additions & 2 deletions runtime/interpreter/invocation.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ type Invocation struct {
LocationRange LocationRange
Self *MemberAccessibleValue
Base *EphemeralReferenceValue
BoundAuthorization *EntitlementSetAuthorization
BoundAuthorization Authorization
TypeParameterTypes *sema.TypeParameterTypeOrderedMap
Interpreter *Interpreter
Arguments []Value
Expand All @@ -39,7 +39,7 @@ func NewInvocation(
interpreter *Interpreter,
self *MemberAccessibleValue,
base *EphemeralReferenceValue,
boundAuth *EntitlementSetAuthorization,
boundAuth Authorization,
arguments []Value,
argumentTypes []sema.Type,
typeParameterTypes *sema.TypeParameterTypeOrderedMap,
Expand Down
2 changes: 1 addition & 1 deletion runtime/interpreter/sharedstate.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ type SharedState struct {
storageMutatedDuringIteration bool
CapabilityControllerIterations map[AddressPath]int
MutationDuringCapabilityControllerIteration bool
currentEntitlementMappedValue *EntitlementSetAuthorization
currentEntitlementMappedValue Authorization
}

func NewSharedState(config *Config) *SharedState {
Expand Down
4 changes: 2 additions & 2 deletions runtime/interpreter/value_function.go
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ type BoundFunctionValue struct {
Function FunctionValue
Base *EphemeralReferenceValue
Self *MemberAccessibleValue
BoundAuthorization *EntitlementSetAuthorization
BoundAuthorization Authorization
}

var _ Value = BoundFunctionValue{}
Expand All @@ -336,7 +336,7 @@ func NewBoundFunctionValue(
function FunctionValue,
self *MemberAccessibleValue,
base *EphemeralReferenceValue,
boundAuth *EntitlementSetAuthorization,
boundAuth Authorization,
) BoundFunctionValue {

common.UseMemory(interpreter, common.BoundFunctionValueMemoryUsage)
Expand Down
38 changes: 38 additions & 0 deletions runtime/tests/interpreter/entitlements_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2380,6 +2380,44 @@ func TestInterpretEntitledAttachments(t *testing.T) {
).Equal(value.(*interpreter.EphemeralReferenceValue).Authorization),
)
})

t.Run("empty output", func(t *testing.T) {

t.Parallel()

inter := parseCheckAndInterpret(t, `
entitlement A
entitlement B
entitlement mapping M {
A -> B
}
struct S {
access(M) fun foo(): auth(M) &AnyStruct {
let a: AnyStruct = "hello"
return &a as auth(M) &AnyStruct
}
}
fun test(): &AnyStruct {
let s = S()
let ref = &s as &S
// Must return an unauthorized ref
return ref.foo()
}
`)

value, err := inter.Invoke("test")
require.NoError(t, err)

require.Equal(
t,
interpreter.UnauthorizedAccess,
value.(*interpreter.EphemeralReferenceValue).Authorization,
)
})
}

func TestInterpretEntitledReferenceCollections(t *testing.T) {
Expand Down

0 comments on commit 4c889d8

Please sign in to comment.