@@ -177,26 +177,20 @@ \subsection{Description of cast operators}
177
177
will disallow these casts. We also plan to revisit casts between pointers to
178
178
unrelated types.
179
179
180
- The \dynamicboundscast \ operator is not strictly needed.
181
- Programmers could write checks by hand. However, programmers
182
- would have to compute the bounds of expressions by hand too, so it is convenient to
183
- have it. It takes 1 to 3 arguments, depending on the kind of conversion being done:
180
+ The \dynamicboundscast \ operator takes a type argument \var {D} and 1 or 2 expressions
181
+ as arguments:
184
182
\begin {itemize }
185
183
\item
186
- \dynamicboundscastinst {\var {T}}{(\var {e1})}
187
- converts \var {e1} to either a \ptr \ or * type.
188
- \item
189
- \dynamicboundscastinst {\var {T}}{(\var {e1},
190
- \var {e2})} converts \var {e1} to an \arrayptr \ type with bounds \boundscount {\var {e2}}.
184
+ \dynamicboundscastinst {\var {D}}{(\var {e1})}
185
+ converts \var {e1} to either a \ptr \ or \code {*} type. \var {D} is the target \ptr \
186
+ or \code {*} type. \var {D} cannot be a function pointer type.
191
187
\item
192
- \dynamicboundscastinst {\var {T}}{(\var {e1},\var {e2},\var {e3})} converts \var {e1} to an
193
- \arrayptr \ type with bounds
194
- \bounds {\var {e2}}{\var {e3}}. \dynamicboundscastinst {\var {T}, \var {A}}
195
- {(\var {e1},\var {e2},\var {e3})}
196
- optionally changes the relative alignment of the bounds to \var {A}.
188
+ \dynamicboundscastinst {\var {D}}{(\var {e1},
189
+ \var {bounds-exp})} converts \var {e1} to an \arrayptr \ type with
190
+ bounds \var {bounds-exp}. \var {D} is the target \arrayptr \ type.
197
191
\end {itemize }
198
192
199
- Here is the checking that is done. The bounds of \var {e1} are computed
193
+ The bounds of \var {e1} are computed
200
194
using the rules in Section~\ref {section:checking-nested-assignment-expressions }.
201
195
If the bounds of \var {e1} are \boundsunknown , it is a compile-time error.
202
196
If the bounds of \var {e1} are \boundsany , no runtime checks are needed.
@@ -208,46 +202,40 @@ \subsection{Description of cast operators}
208
202
\item Otherwise, if the operator has the form:
209
203
\begin {itemize }
210
204
\item
211
- \dynamicboundscastinst {\var {T}}{(\var {e1})}:
212
- check that there is room for least one element of \var {T} by doing
213
- the check for \dynamicboundscastinst {\var {T}}{(e1, 1)}.
214
- \item
215
- \dynamicboundscastinst {\var {T}}{(\var {e1}, \var {e2})}:
216
- check that \var {lb}
217
- \code {<=} \var {e1} \code {&&} \var {e1} \code {+}
218
- \sizeof {referent-type(\var {T})} * e2 \code {<=}
219
- \var {ub}.
205
+ \dynamicboundscastinst {\var {D}}{(\var {e1})}: \var {D} is pointer to some type \var {T}.
206
+ Check that there is room for at least one element of \var {T} by doing
207
+ the check for \dynamicboundscastinst {\arrayptrinst {\var {T}}}{(e1, \boundscount {\code {1}})}
220
208
\item
221
- \dynamicboundscastinst {\var {T }}{(\var {e1},\var {e2}, \var {e3} )}:
222
- check that \var {lb} \code {<=} \var {e2} \code {&&}
223
- \var {e3} \code {<=} \var {ub}. Also check that \var {e1}, \var {e2}, and \var {e3}
224
- are relatively aligned to \var {T} (or the optional alignment parameter instead, if one
225
- is given).
226
-
209
+ \dynamicboundscastinst {\var {D }}{(\var {e1}, \var {bounds-exp} )}:
210
+ Expand \var {bounds-exp} to the standard
211
+ form \boundsrelval { \var {target-lb}}{ \var {target-ub}}{ \var {v}}.
212
+ Check that \var {lb} \code {<=} \var {target-lb} \code {&&} \var {target-ub} \code {<=} \var {ub}.
213
+ Also check that \var {e1}, \var {target-lb}, and \var {target-lb} are relatively aligned
214
+ with respect to \var {v}.
227
215
\end {itemize }
228
216
\end {itemize }
217
+ The \dynamicboundscast \ operator is not strictly needed.
218
+ Programmers could write checks by hand. It is convenient to have, though,
219
+ because it avoids programmers having to write down the bounds of the source expression.
229
220
230
- The operator \assumeboundscastinst {\var {T }}{} declares bounds that are trusted
221
+ The operator \assumeboundscastinst {\var {D }}{} declares bounds that are trusted
231
222
without verification:
232
223
\begin {itemize }
233
224
\item
234
- \assumeboundscastinst {\var {T}}{(\var {e1},\var {e2})}
235
- converts \var {e1} to an \arrayptr \ type with \boundscount {\var {e2}}
236
- \item
237
- \assumeboundscastinst {\var {T}}{(\var {e1},\var {e2},\var {e3})}
238
- converts \var {e1} to an
239
- \arrayptr \ type with \bounds {\var {e2}}{\var {e3}}.
240
- It must be statically provable that \var {e1}, \var {e2} and \var {e3}
241
- are relatively aligned for \var {T} (or the optional
242
- relative alignment parameter instead, if there is one).
225
+ \assumeboundscastinst {\var {D}}{(\var {e1})}
226
+ converts \var {e1} to a \ptr \ or \code {*} type. \var {D} is the target \ptr \ or \code {*} type.
243
227
\item
244
- \assumeboundscastinst {\var {T}}{(\var {e1})}
245
- converts \var {e1} to a \ptr \ or \code {*} type.
228
+ \assumeboundscastinst {\var {D}}{(\var {e1}, \var {bounds-exp})}
229
+ converts \var {e1} to an \arrayptr \ type with bounds \var {bounds-exp}. \var {D} is the
230
+ target \arrayptr \ type.
246
231
\end {itemize }
232
+ For the second form, the relative alignment must be statically
233
+ provable: expand \var {bounds-exp} to the standard form
234
+ \boundsrelval {\var {target-lb}}{\var {target-ub}}{\var {v}} and check
235
+ that \var {e1}, \var {target-lb} and \var {target-ub} are relatively aligned to \var {v}.
247
236
248
- If any rule depends on \sizeof {\var {T}} and \var {T} is
249
- an incomplete type, the cast operation that uses the rule shall fail
250
- to check at compile-time.
237
+ If any rule requires knowing the size of an incomplete type,
238
+ the cast operation that uses the rule shall fail to check at compile-time.
251
239
252
240
A subtle point about the C cast operator and \dynamicboundscast \
253
241
are that they allow {\em bounds-safe casts} of an expression
@@ -262,7 +250,7 @@ \subsection{Examples}
262
250
263
251
Here are examples of uses of C cast operators to cast unchecked
264
252
pointers to checked pointers. The static checking rules are straightforward
265
- to apply here . The examples assume that integers are
253
+ to apply. The examples assume that integers are
266
254
4 bytes in size:
267
255
\ begin{lstlisting}
268
256
int x = 0;
@@ -271,7 +259,7 @@ \subsection{Examples}
271
259
array_ptr<char> odd_pax : count(3) = (array_ptr<char>) px;
272
260
273
261
char data[12];
274
- ptr<int> pfirst = (ptr<int>) data; // pointed to 1st element as an integer;
262
+ ptr<int> pfirst = (ptr<int>) data; // pointed to 1st element as an integer
275
263
array_ptr<int> pdata : count(3) = (array_ptr<int>) data;
276
264
277
265
void swizzle(ptr<int> p) {
@@ -280,7 +268,43 @@ \subsection{Examples}
280
268
bytes[0] = t3, bytes[1] = t2, bytes[2] = t1, bytes[3] = t0;
281
269
}
282
270
\end {lstlisting }
271
+ The \dynamicboundscast \ operator is used typically when converting
272
+ code to Checked C. The existing code may make assumptions
273
+ about buffers being large enough that are potentially wrong.
274
+ It would be better to check for errors directly, but the code may not
275
+ be structured to handle errors:
276
+ \ begin{lstlisting}
277
+ void f(array_ptr<char> buf : count(len), int len) {
278
+ // We expect buf to have enough space for at least 12 integers.
279
+ array_ptr<int> intbuf : count(12) =
280
+ dynamic_bounds_cast<array_ptr<int>>(buf, count(12));
281
+ ...
282
+ }
283
283
284
+ extern void copy(array_ptr<char> dest : count(n),
285
+ array_ptr<char> src : count(n),
286
+ size_t n);
287
+
288
+ void fill_buffer(array_ptr<char> dest : count(destlen),
289
+ size_t destlen,
290
+ array_ptr<char> src : count(srclen),
291
+ size_t srclen) {
292
+ // Existing code just assumed that dest was large enough; let's add a
293
+ // dynamic_bounds_cast to be sure.
294
+ array_ptr<char> target : count(srclen) =
295
+ dynamic_bounds_cast<array_ptr<char>>(dest, count(srclen));
296
+ copy(target, src, srclen);
297
+ }
298
+ \end {lstlisting }
299
+ Here are examples of using the \assumeboundscast \ operator:
300
+ \ begin{lstlisting}
301
+ // Memory-mapped hardware location where an integer can be written.
302
+ ptr<int> output_loc = assume_bounds_cast<ptr<int>>(0x5055);
303
+ // Memory-mapped hardware buffer starting at 0x6000 that stores 128
304
+ // integers.
305
+ array_ptr<int> output_buf : count(128) =
306
+ assume_bounds_cast<array_ptr<int>>(0x6000, count(128));
307
+ \end {lstlisting }
284
308
\subsection {Non-examples }
285
309
286
310
Here are examples of incorrect uses of C cast operators to cast unchecked
0 commit comments