@@ -78,23 +78,61 @@ export function makeVatKeeper(
78
78
return harden ( { source, options } ) ;
79
79
}
80
80
81
+ function parseReachableAndVatSlot ( value ) {
82
+ assert . typeof ( value , 'string' , X `non-string value: ${ value } ` ) ;
83
+ const flag = value . slice ( 0 , 1 ) ;
84
+ assert . equal ( value . slice ( 1 , 2 ) , ' ' ) ;
85
+ const vatSlot = value . slice ( 2 ) ;
86
+ let reachable ;
87
+ if ( flag === 'R' ) {
88
+ reachable = true ;
89
+ } else if ( flag === '_' ) {
90
+ reachable = false ;
91
+ } else {
92
+ assert ( `flag (${ flag } ) must be 'R' or '_'` ) ;
93
+ }
94
+ return { reachable, vatSlot } ;
95
+ }
96
+
97
+ function buildReachableAndVatSlot ( reachable , vatSlot ) {
98
+ return `${ reachable ? 'R' : '_' } ${ vatSlot } ` ;
99
+ }
100
+
101
+ function getReachableAndVatSlot ( kernelSlot ) {
102
+ const kernelKey = `${ vatID } .c.${ kernelSlot } ` ;
103
+ return parseReachableAndVatSlot ( kvStore . get ( kernelKey ) ) ;
104
+ }
105
+
106
+ function setReachableFlag ( kernelSlot ) {
107
+ const kernelKey = `${ vatID } .c.${ kernelSlot } ` ;
108
+ const { vatSlot } = parseReachableAndVatSlot ( kvStore . get ( kernelKey ) ) ;
109
+ kvStore . set ( kernelKey , buildReachableAndVatSlot ( true , vatSlot ) ) ;
110
+ }
111
+
112
+ function clearReachableFlag ( kernelSlot ) {
113
+ const kernelKey = `${ vatID } .c.${ kernelSlot } ` ;
114
+ const { vatSlot } = parseReachableAndVatSlot ( kvStore . get ( kernelKey ) ) ;
115
+ kvStore . set ( kernelKey , buildReachableAndVatSlot ( false , vatSlot ) ) ;
116
+ }
117
+
81
118
/**
82
- * Provide the kernel slot corresponding to a given vat slot, creating the
83
- * kernel slot if it doesn't already exist.
119
+ * Provide the kernel slot corresponding to a given vat slot, allocating a
120
+ * new one (for exports only) if it doesn't already exist. If we're allowed
121
+ * to allocate, we also ensure the 'reachable' flag is set on it (whether
122
+ * we allocated a new one or used an existing one). If we're not allowed to
123
+ * allocate, we insist that the reachable flag was already set.
84
124
*
85
125
* @param {string } vatSlot The vat slot of interest
86
- *
126
+ * @param { bool } setReachable Set the 'reachable' flag on vat exports.
87
127
* @returns {string } the kernel slot that vatSlot maps to
88
- *
89
128
* @throws {Error } if vatSlot is not a kind of thing that can be exported by vats
90
- * or is otherwise invalid.
129
+ * or is otherwise invalid.
91
130
*/
92
- function mapVatSlotToKernelSlot ( vatSlot ) {
131
+ function mapVatSlotToKernelSlot ( vatSlot , setReachable = true ) {
93
132
assert . typeof ( vatSlot , 'string' , X `non-string vatSlot: ${ vatSlot } ` ) ;
133
+ const { type, allocatedByVat } = parseVatSlot ( vatSlot ) ;
94
134
const vatKey = `${ vatID } .c.${ vatSlot } ` ;
95
135
if ( ! kvStore . has ( vatKey ) ) {
96
- const { type, allocatedByVat } = parseVatSlot ( vatSlot ) ;
97
-
98
136
if ( allocatedByVat ) {
99
137
let kernelSlot ;
100
138
if ( type === 'object' ) {
@@ -109,7 +147,10 @@ export function makeVatKeeper(
109
147
incrementRefCount ( kernelSlot , `${ vatID } |vk|clist` ) ;
110
148
const kernelKey = `${ vatID } .c.${ kernelSlot } ` ;
111
149
incStat ( 'clistEntries' ) ;
112
- kvStore . set ( kernelKey , vatSlot ) ;
150
+ // we add the key as "unreachable", and then rely on
151
+ // setReachableFlag() at the end to both mark it reachable and to
152
+ // update any necessary refcounts consistently
153
+ kvStore . set ( kernelKey , buildReachableAndVatSlot ( false , vatSlot ) ) ;
113
154
kvStore . set ( vatKey , kernelSlot ) ;
114
155
kernelSlog &&
115
156
kernelSlog . changeCList (
@@ -126,22 +167,32 @@ export function makeVatKeeper(
126
167
assert . fail ( X `unknown vatSlot ${ q ( vatSlot ) } ` ) ;
127
168
}
128
169
}
170
+ const kernelSlot = kvStore . get ( vatKey ) ;
129
171
130
- return kvStore . get ( vatKey ) ;
172
+ if ( setReachable ) {
173
+ if ( allocatedByVat ) {
174
+ // exports are marked as reachable, if they weren't already
175
+ setReachableFlag ( kernelSlot ) ;
176
+ } else {
177
+ // imports must be reachable
178
+ const { reachable } = getReachableAndVatSlot ( kernelSlot ) ;
179
+ assert ( reachable , X `vat tried to access unreachable import` ) ;
180
+ }
181
+ }
182
+ return kernelSlot ;
131
183
}
132
184
133
185
/**
134
186
* Provide the vat slot corresponding to a given kernel slot, including
135
187
* creating the vat slot if it doesn't already exist.
136
188
*
137
189
* @param {string } kernelSlot The kernel slot of interest
138
- *
190
+ * @param { bool } setReachable Set the 'reachable' flag on vat imports.
139
191
* @returns {string } the vat slot kernelSlot maps to
140
- *
141
192
* @throws {Error } if kernelSlot is not a kind of thing that can be imported by vats
142
- * or is otherwise invalid.
193
+ * or is otherwise invalid.
143
194
*/
144
- function mapKernelSlotToVatSlot ( kernelSlot ) {
195
+ function mapKernelSlotToVatSlot ( kernelSlot , setReachable = true ) {
145
196
assert . typeof ( kernelSlot , 'string' , 'non-string kernelSlot' ) ;
146
197
const kernelKey = `${ vatID } .c.${ kernelSlot } ` ;
147
198
if ( ! kvStore . has ( kernelKey ) ) {
@@ -166,7 +217,7 @@ export function makeVatKeeper(
166
217
const vatKey = `${ vatID } .c.${ vatSlot } ` ;
167
218
incStat ( 'clistEntries' ) ;
168
219
kvStore . set ( vatKey , kernelSlot ) ;
169
- kvStore . set ( kernelKey , vatSlot ) ;
220
+ kvStore . set ( kernelKey , buildReachableAndVatSlot ( false , vatSlot ) ) ;
170
221
kernelSlog &&
171
222
kernelSlog . changeCList (
172
223
vatID ,
@@ -178,7 +229,19 @@ export function makeVatKeeper(
178
229
kdebug ( `Add mapping k->v ${ kernelKey } <=>${ vatKey } ` ) ;
179
230
}
180
231
181
- return kvStore . get ( kernelKey ) ;
232
+ const { reachable, vatSlot } = getReachableAndVatSlot ( kernelSlot ) ;
233
+ const { allocatedByVat } = parseVatSlot ( vatSlot ) ;
234
+ if ( setReachable ) {
235
+ if ( ! allocatedByVat ) {
236
+ // imports are marked as reachable, if they weren't already
237
+ setReachableFlag ( kernelSlot ) ;
238
+ } else {
239
+ // if the kernel is sending non-reachable exports back into
240
+ // exporting vat, that's a kernel bug
241
+ assert ( reachable , X `kernel sent unreachable export` ) ;
242
+ }
243
+ }
244
+ return vatSlot ;
182
245
}
183
246
184
247
/**
@@ -293,6 +356,8 @@ export function makeVatKeeper(
293
356
getSourceAndOptions,
294
357
mapVatSlotToKernelSlot,
295
358
mapKernelSlotToVatSlot,
359
+ setReachableFlag,
360
+ clearReachableFlag,
296
361
hasCListEntry,
297
362
deleteCListEntry,
298
363
deleteCListEntriesForKernelSlots,
0 commit comments