Skip to content

Commit 51201ae

Browse files
committed
improve safety comment in scope function (#7534)
# Objective - While working on scope recently, I ran into a missing invariant for the transmutes in scope. The references passed into Scope are active for the rest of the scope function, but rust doesn't know this so it allows using the owned `spawned` and `scope` after `f` returns. ## Solution - Update the safety comment - Shadow the owned values so they can't be used.
1 parent 96a1c6c commit 51201ae

File tree

1 file changed

+10
-7
lines changed

1 file changed

+10
-7
lines changed

crates/bevy_tasks/src/task_pool.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -336,35 +336,38 @@ impl TaskPool {
336336
// This is guaranteed because we drive all the futures spawned onto the Scope
337337
// to completion in this function. However, rust has no way of knowing this so we
338338
// transmute the lifetimes to 'env here to appease the compiler as it is unable to validate safety.
339+
// Any usages of the references passed into `Scope` must be accessed through
340+
// the transmuted reference for the rest of this function.
339341
let executor: &async_executor::Executor = &self.executor;
340342
let executor: &'env async_executor::Executor = unsafe { mem::transmute(executor) };
341343
let external_executor: &'env ThreadExecutor<'env> =
342344
unsafe { mem::transmute(external_executor) };
343345
let scope_executor: &'env ThreadExecutor<'env> = unsafe { mem::transmute(scope_executor) };
344346
let spawned: ConcurrentQueue<FallibleTask<T>> = ConcurrentQueue::unbounded();
345-
let spawned_ref: &'env ConcurrentQueue<FallibleTask<T>> =
346-
unsafe { mem::transmute(&spawned) };
347+
// shadow the variable so that the owned value cannot be used for the rest of the function
348+
let spawned: &'env ConcurrentQueue<FallibleTask<T>> = unsafe { mem::transmute(&spawned) };
347349

348350
let scope = Scope {
349351
executor,
350352
external_executor,
351353
scope_executor,
352-
spawned: spawned_ref,
354+
spawned,
353355
scope: PhantomData,
354356
env: PhantomData,
355357
};
356358

357-
let scope_ref: &'env Scope<'_, 'env, T> = unsafe { mem::transmute(&scope) };
359+
// shadow the variable so that the owned value cannot be used for the rest of the function
360+
let scope: &'env Scope<'_, 'env, T> = unsafe { mem::transmute(&scope) };
358361

359-
f(scope_ref);
362+
f(scope);
360363

361364
if spawned.is_empty() {
362365
Vec::new()
363366
} else {
364367
future::block_on(async move {
365368
let get_results = async {
366-
let mut results = Vec::with_capacity(spawned_ref.len());
367-
while let Ok(task) = spawned_ref.pop() {
369+
let mut results = Vec::with_capacity(spawned.len());
370+
while let Ok(task) = spawned.pop() {
368371
results.push(task.await.unwrap());
369372
}
370373
results

0 commit comments

Comments
 (0)