diff options
| author | bors <bors@rust-lang.org> | 2023-03-12 14:00:28 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2023-03-12 14:00:28 +0000 |
| commit | f41927f30943e4d57af62cfcedc9f07b819013e7 (patch) | |
| tree | ac1896f170229aa3f52c6a8e402d890208071e51 /compiler/rustc_query_system | |
| parent | 24c0b81c1fd5de8e00276524896d3352ed91a8cb (diff) | |
| parent | e955ec0908c54b33ab08d4b768c9f8aa8071c643 (diff) | |
| download | rust-f41927f30943e4d57af62cfcedc9f07b819013e7.tar.gz rust-f41927f30943e4d57af62cfcedc9f07b819013e7.zip | |
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".
Diffstat (limited to 'compiler/rustc_query_system')
| -rw-r--r-- | compiler/rustc_query_system/src/query/config.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_query_system/src/query/plumbing.rs | 32 |
2 files changed, 26 insertions, 8 deletions
diff --git a/compiler/rustc_query_system/src/query/config.rs b/compiler/rustc_query_system/src/query/config.rs index e44a00ca6cb..a0aeb812af9 100644 --- a/compiler/rustc_query_system/src/query/config.rs +++ b/compiler/rustc_query_system/src/query/config.rs @@ -43,6 +43,8 @@ pub trait QueryConfig<Qcx: QueryContext>: Copy { fn try_load_from_disk(self, qcx: Qcx, idx: &Self::Key) -> TryLoadFromDisk<Qcx, Self::Value>; + fn loadable_from_disk(self, qcx: Qcx, key: &Self::Key, idx: SerializedDepNodeIndex) -> bool; + fn anon(self) -> bool; fn eval_always(self) -> bool; fn depth_limit(self) -> bool; diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 7b9e0c3a0a6..a3656f4ebe6 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -564,10 +564,17 @@ where // can be forced from `DepNode`. debug_assert!( !qcx.dep_context().fingerprint_style(dep_node.kind).reconstructible(), - "missing on-disk cache entry for {dep_node:?}" + "missing on-disk cache entry for reconstructible {dep_node:?}" ); } + // Sanity check for the logic in `ensure`: if the node is green and the result loadable, + // we should actually be able to load it. + debug_assert!( + !query.loadable_from_disk(qcx, &key, prev_dep_node_index), + "missing on-disk cache entry for loadable {dep_node:?}" + ); + // We could not load a result from the on-disk cache, so // recompute. let prof_timer = qcx.dep_context().profiler().query_provider(); @@ -718,6 +725,7 @@ fn ensure_must_run<Q, Qcx>( query: Q, qcx: Qcx, key: &Q::Key, + check_cache: bool, ) -> (bool, Option<DepNode<Qcx::DepKind>>) where Q: QueryConfig<Qcx>, @@ -733,7 +741,7 @@ where let dep_node = query.construct_dep_node(*qcx.dep_context(), key); let dep_graph = qcx.dep_context().dep_graph(); - match dep_graph.try_mark_green(qcx, &dep_node) { + let serialized_dep_node_index = match dep_graph.try_mark_green(qcx, &dep_node) { None => { // A None return from `try_mark_green` means that this is either // a new dep node or that the dep node has already been marked red. @@ -741,20 +749,28 @@ where // DepNodeIndex. We must invoke the query itself. The performance cost // this introduces should be negligible as we'll immediately hit the // in-memory cache, or another query down the line will. - (true, Some(dep_node)) + return (true, Some(dep_node)); } - Some((_, dep_node_index)) => { + Some((serialized_dep_node_index, dep_node_index)) => { dep_graph.read_index(dep_node_index); qcx.dep_context().profiler().query_cache_hit(dep_node_index.into()); - (false, None) + serialized_dep_node_index } + }; + + // We do not need the value at all, so do not check the cache. + if !check_cache { + return (false, None); } + + let loadable = query.loadable_from_disk(qcx, key, serialized_dep_node_index); + (!loadable, Some(dep_node)) } #[derive(Debug)] pub enum QueryMode { Get, - Ensure, + Ensure { check_cache: bool }, } #[inline(always)] @@ -769,8 +785,8 @@ where Q: QueryConfig<Qcx>, Qcx: QueryContext, { - let dep_node = if let QueryMode::Ensure = mode { - let (must_run, dep_node) = ensure_must_run(query, qcx, &key); + let dep_node = if let QueryMode::Ensure { check_cache } = mode { + let (must_run, dep_node) = ensure_must_run(query, qcx, &key, check_cache); if !must_run { return None; } |
