You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
// This is a 'brand" capability to mark what can be mentioned in trusted code
16
+
objecttrustedextends caps.Capability
17
+
18
+
// These capabilities are trusted:
19
+
valtrustedLogger:Logger^{trusted}
20
+
valtrustedChannel:Channel[String]^{trusted}
21
+
// These aren't:
22
+
valuntrustedLogger:Logger^
23
+
valuntrustedChannel:Channel[String]^
24
+
25
+
runSecure: () =>
26
+
trustedLogger.log("Hello from trusted code") // ok
27
+
28
+
runSecure: () =>
29
+
trustedChannel.send("I can send") // ok
30
+
trustedLogger.log(trustedChannel.recv()) // ok
31
+
32
+
runSecure: () =>"I am pure and that's ok"// ok
33
+
34
+
runSecure: () =>
35
+
untrustedLogger.log("I can't be used") // error
36
+
untrustedChannel.send("I can't be used") // error
37
+
```
38
+
The idea is that every capability derived from the marker capability `trusted` (and only those) are eligible to be used in the `block` closure
39
+
passed to `runSecure`. We can enforce this by an explicit capability parameter `C` constraining the possible captures of `block` to the interval `>: {trusted} <: {trusted}`.
40
+
41
+
Note that since capabilities of function types are covariant, we could have equivalently specified `runSecure`'s signature using implicit capture polymorphism to achieve the same behavior:
42
+
```scala
43
+
defrunSecure(block: () ->{trusted} Unit):Unit
44
+
```
45
+
46
+
## Capture-safe Lexical Control
47
+
48
+
Capability members and paths to these members can prevent leakage
49
+
of labels for lexically-delimited control operators:
50
+
```scala
51
+
traitLabelextendsCapability:
52
+
typeFv^// the capability set occurring freely in the `block` passed to `boundary` below.
53
+
54
+
defboundary[T, C^](block: Label{typeFv= {C} } ->{C} T):T=???// ensure free caps of label and block match
55
+
defsuspend[U](label: Label)[D^<: {label.Fv}](handler: () ->{D} U):U=???// may only capture the free capabilities of label
56
+
57
+
deftest=
58
+
valx=1
59
+
boundary: outer =>
60
+
valy=2
61
+
boundary: inner =>
62
+
valz=3
63
+
valw= suspend(outer) {() => z} // ok
64
+
valv= suspend(inner) {() => y} // ok
65
+
valu= suspend(inner): () =>
66
+
suspend(outer) {() => w + v} // ok
67
+
y
68
+
suspend(outer): () =>
69
+
println(inner) // error (would leak the inner label)
70
+
x + y + z
71
+
```
72
+
A key property is that `suspend` (think `shift` from delimited continuations) targeting a specific label (such as `outer`) should not accidentally close over labels from a nested `boundary` (such as `inner`), because they would escape their defining scope this way.
73
+
By leveraging capability polymorphism, capability members, and path-dependent capabilities, we can prevent such leaks from occurring at compile time:
74
+
75
+
*`Label`s store the free capabilities `C` of the `block` passed to `boundary` in their capability member `Fv`.
76
+
* When suspending on a given label, the suspension handler can capture at most the capabilities that occur freely at the `boundary` that introduced the label. That prevents mentioning nested bound labels.
// This is a 'brand" capability to mark what can be mentioned in trusted code
794
-
objecttrustedextends caps.Capability
795
-
796
-
// These capabilities are trusted:
797
-
valtrustedLogger:Logger^{trusted}
798
-
valtrustedChannel:Channel[String]^{trusted}
799
-
// These aren't:
800
-
valuntrustedLogger:Logger^
801
-
valuntrustedChannel:Channel[String]^
802
-
803
-
runSecure: () =>
804
-
trustedLogger.log("Hello from trusted code") // ok
805
-
806
-
runSecure: () =>
807
-
trustedChannel.send("I can send") // ok
808
-
trustedLogger.log(trustedChannel.recv()) // ok
809
-
810
-
runSecure: () =>"I am pure and that's ok"// ok
811
-
812
-
runSecure: () =>
813
-
untrustedLogger.log("I can't be used") // error
814
-
untrustedChannel.send("I can't be used") // error
815
-
```
816
-
The idea is that every capability derived from the marker capability `trusted` (and only those) are eligible to be used in the `block` closure
817
-
passed to `runSecure`. We can enforce this by an explicit capability parameter `C` constraining the possible captures of `block` to the interval `>: {trusted} <: {trusted}`.
818
-
819
-
Note that since capabilities of function types are covariant, we could have equivalently specified `runSecure`'s signature using implicit capture polymorphism to achieve the same behavior:
We conclude with a more advanced example, showing how capability members and paths to these members can prevent leakage
848
-
of labels for lexically-delimited control operators:
849
-
```scala
850
-
traitLabelextendsCapability:
851
-
typeFv^// the capability set occurring freely in the `block` passed to `boundary` below.
852
-
853
-
defboundary[T, C^](block: Label{typeFv= {C} } ->{C} T):T=???// ensure free caps of label and block match
854
-
defsuspend[U](label: Label)[D^<: {label.Fv}](handler: () ->{D} U):U=???// may only capture the free capabilities of label
855
-
856
-
deftest=
857
-
valx=1
858
-
boundary: outer =>
859
-
valy=2
860
-
boundary: inner =>
861
-
valz=3
862
-
valw= suspend(outer) {() => z} // ok
863
-
valv= suspend(inner) {() => y} // ok
864
-
valu= suspend(inner): () =>
865
-
suspend(outer) {() => w + v} // ok
866
-
y
867
-
suspend(outer): () =>
868
-
println(inner) // error (would leak the inner label)
869
-
x + y + z
870
-
```
871
-
A key property is that `suspend` (think `shift` from delimited continuations) targeting a specific label (such as `outer`) should not accidentally close over labels from a nested `boundary` (such as `inner`), because they would escape their defining scope this way.
872
-
By leveraging capability polymorphism, capability members, and path-dependent capabilities, we can prevent such leaks from occurring at compile time:
873
-
874
-
*`Label`s store the free capabilities `C` of the `block` passed to `boundary` in their capability member `Fv`.
875
-
* When suspending on a given label, the suspension handler can capture at most the capabilities that occur freely at the `boundary` that introduced the label. That prevents mentioning nested bound labels.
0 commit comments