1
Fork 0

Auto merge of #108820 - cjgillot:ensure-on-disk, r=oli-obk

Ensure value is on the on-disk cache before returning from `ensure()`.

The current logic for `ensure()` a query just checks that the node is green in the dependency graph.
However, a lot of places use `ensure()` to prevent the query from being called later. This is the case before stealing a query result.

If the query is actually green but the value is not available in the on-disk cache, `ensure` would return, but a subsequent call to the full query would run the code, and attempt to read from a stolen value.

This PR conforms the query system to the usage by checking whether the queried value is loadable from disk before returning.

Sadly, I can't manage to craft a proper test...

Should fix all instances of "attempted to read from stolen value".
This commit is contained in:
bors 2023-03-12 14:00:28 +00:00
commit f41927f309
10 changed files with 116 additions and 30 deletions

View file

@ -99,6 +99,11 @@ pub struct TyCtxtEnsure<'tcx> {
pub tcx: TyCtxt<'tcx>,
}
#[derive(Copy, Clone)]
pub struct TyCtxtEnsureWithValue<'tcx> {
pub tcx: TyCtxt<'tcx>,
}
impl<'tcx> TyCtxt<'tcx> {
/// Returns a transparent wrapper for `TyCtxt`, which ensures queries
/// are executed instead of just returning their results.
@ -107,6 +112,15 @@ impl<'tcx> TyCtxt<'tcx> {
TyCtxtEnsure { tcx: self }
}
/// Returns a transparent wrapper for `TyCtxt`, which ensures queries
/// are executed instead of just returning their results.
///
/// This version verifies that the computed result exists in the cache before returning.
#[inline(always)]
pub fn ensure_with_value(self) -> TyCtxtEnsureWithValue<'tcx> {
TyCtxtEnsureWithValue { tcx: self }
}
/// Returns a transparent wrapper for `TyCtxt` which uses
/// `span` as the location of queries performed through it.
#[inline(always)]
@ -314,7 +328,31 @@ macro_rules! define_callbacks {
match try_get_cached(self.tcx, &self.tcx.query_system.caches.$name, &key) {
Some(_) => return,
None => self.tcx.queries.$name(self.tcx, DUMMY_SP, key, QueryMode::Ensure),
None => self.tcx.queries.$name(
self.tcx,
DUMMY_SP,
key,
QueryMode::Ensure { check_cache: false },
),
};
})*
}
impl<'tcx> TyCtxtEnsureWithValue<'tcx> {
$($(#[$attr])*
#[inline(always)]
pub fn $name(self, key: query_helper_param_ty!($($K)*)) {
let key = key.into_query_param();
opt_remap_env_constness!([$($modifiers)*][key]);
match try_get_cached(self.tcx, &self.tcx.query_system.caches.$name, &key) {
Some(_) => return,
None => self.tcx.queries.$name(
self.tcx,
DUMMY_SP,
key,
QueryMode::Ensure { check_cache: true },
),
};
})*
}