Skip to content

Commit 43297ff

Browse files
authored
Rollup merge of #138581 - Zoxc:abort-handler-if-locked, r=SparrowLii
Abort in deadlock handler if we fail to get a query map Resolving query cycles requires the complete active query map, or it may miss query cycles. We did not check that the map is completely constructed before. If there is some error collecting the map, something has gone wrong already. This adds a check to abort/panic if we fail to construct the complete map. This can help differentiate errors from the `deadlock detected` case if constructing query map has errors in practice. An `Option` is not used for `collect_active_jobs` as the panic handler can still make use of a partial map.
2 parents 81e2275 + 34244c1 commit 43297ff

File tree

5 files changed

+43
-12
lines changed

5 files changed

+43
-12
lines changed

compiler/rustc_interface/src/util.rs

+13-2
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,18 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce(CurrentGcx) -> R + Send,
192192
// `TyCtxt` TLS reference here.
193193
let query_map = current_gcx2.access(|gcx| {
194194
tls::enter_context(&tls::ImplicitCtxt::new(gcx), || {
195-
tls::with(|tcx| QueryCtxt::new(tcx).collect_active_jobs())
195+
tls::with(|tcx| {
196+
match QueryCtxt::new(tcx).collect_active_jobs() {
197+
Ok(query_map) => query_map,
198+
Err(_) => {
199+
// There was an unexpected error collecting all active jobs, which we need
200+
// to find cycles to break.
201+
// We want to avoid panicking in the deadlock handler, so we abort instead.
202+
eprintln!("internal compiler error: failed to get query map in deadlock handler, aborting process");
203+
process::abort();
204+
}
205+
}
206+
})
196207
})
197208
});
198209
let query_map = FromDyn::from(query_map);
@@ -201,7 +212,7 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce(CurrentGcx) -> R + Send,
201212
.name("rustc query cycle handler".to_string())
202213
.spawn(move || {
203214
let on_panic = defer(|| {
204-
eprintln!("query cycle handler thread panicked, aborting process");
215+
eprintln!("internal compiler error: query cycle handler thread panicked, aborting process");
205216
// We need to abort here as we failed to resolve the deadlock,
206217
// otherwise the compiler could just hang,
207218
process::abort();

compiler/rustc_query_impl/src/plumbing.rs

+18-6
Original file line numberDiff line numberDiff line change
@@ -79,14 +79,20 @@ impl QueryContext for QueryCtxt<'_> {
7979
tls::with_related_context(self.tcx, |icx| icx.query)
8080
}
8181

82-
fn collect_active_jobs(self) -> QueryMap {
82+
/// Returns a query map representing active query jobs.
83+
/// It returns an incomplete map as an error if it fails
84+
/// to take locks.
85+
fn collect_active_jobs(self) -> Result<QueryMap, QueryMap> {
8386
let mut jobs = QueryMap::default();
87+
let mut complete = true;
8488

8589
for collect in super::TRY_COLLECT_ACTIVE_JOBS.iter() {
86-
collect(self.tcx, &mut jobs);
90+
if collect(self.tcx, &mut jobs).is_none() {
91+
complete = false;
92+
}
8793
}
8894

89-
jobs
95+
if complete { Ok(jobs) } else { Err(jobs) }
9096
}
9197

9298
// Interactions with on_disk_cache
@@ -139,7 +145,12 @@ impl QueryContext for QueryCtxt<'_> {
139145
}
140146

141147
fn depth_limit_error(self, job: QueryJobId) {
142-
let (info, depth) = job.find_dep_kind_root(self.collect_active_jobs());
148+
// FIXME: `collect_active_jobs` expects no locks to be held, which doesn't hold for this call.
149+
let query_map = match self.collect_active_jobs() {
150+
Ok(query_map) => query_map,
151+
Err(query_map) => query_map,
152+
};
153+
let (info, depth) = job.find_dep_kind_root(query_map);
143154

144155
let suggested_limit = match self.recursion_limit() {
145156
Limit(0) => Limit(2),
@@ -677,7 +688,7 @@ macro_rules! define_queries {
677688
}
678689
}
679690

680-
pub(crate) fn try_collect_active_jobs<'tcx>(tcx: TyCtxt<'tcx>, qmap: &mut QueryMap) {
691+
pub(crate) fn try_collect_active_jobs<'tcx>(tcx: TyCtxt<'tcx>, qmap: &mut QueryMap) -> Option<()> {
681692
let make_query = |tcx, key| {
682693
let kind = rustc_middle::dep_graph::dep_kinds::$name;
683694
let name = stringify!($name);
@@ -697,6 +708,7 @@ macro_rules! define_queries {
697708
stringify!($name)
698709
);
699710
}
711+
res
700712
}
701713

702714
pub(crate) fn alloc_self_profile_query_strings<'tcx>(
@@ -756,7 +768,7 @@ macro_rules! define_queries {
756768

757769
// These arrays are used for iteration and can't be indexed by `DepKind`.
758770

759-
const TRY_COLLECT_ACTIVE_JOBS: &[for<'tcx> fn(TyCtxt<'tcx>, &mut QueryMap)] =
771+
const TRY_COLLECT_ACTIVE_JOBS: &[for<'tcx> fn(TyCtxt<'tcx>, &mut QueryMap) -> Option<()>] =
760772
&[$(query_impl::$name::try_collect_active_jobs),*];
761773

762774
const ALLOC_SELF_PROFILE_QUERY_STRINGS: &[

compiler/rustc_query_system/src/query/job.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -588,7 +588,12 @@ pub fn print_query_stack<Qcx: QueryContext>(
588588
// state if it was responsible for triggering the panic.
589589
let mut count_printed = 0;
590590
let mut count_total = 0;
591-
let query_map = qcx.collect_active_jobs();
591+
592+
// Make use of a partial query map if we fail to take locks collecting active queries.
593+
let query_map = match qcx.collect_active_jobs() {
594+
Ok(query_map) => query_map,
595+
Err(query_map) => query_map,
596+
};
592597

593598
if let Some(ref mut file) = file {
594599
let _ = writeln!(file, "\n\nquery stack during panic:");

compiler/rustc_query_system/src/query/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ pub trait QueryContext: HasDepContext {
8686
/// Get the query information from the TLS context.
8787
fn current_query_job(self) -> Option<QueryJobId>;
8888

89-
fn collect_active_jobs(self) -> QueryMap;
89+
fn collect_active_jobs(self) -> Result<QueryMap, QueryMap>;
9090

9191
/// Load a side effect associated to the node in the previous session.
9292
fn load_side_effect(

compiler/rustc_query_system/src/query/plumbing.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -260,8 +260,11 @@ where
260260
Q: QueryConfig<Qcx>,
261261
Qcx: QueryContext,
262262
{
263-
let error =
264-
try_execute.find_cycle_in_stack(qcx.collect_active_jobs(), &qcx.current_query_job(), span);
263+
// Ensure there was no errors collecting all active jobs.
264+
// We need the complete map to ensure we find a cycle to break.
265+
let query_map = qcx.collect_active_jobs().expect("failed to collect active queries");
266+
267+
let error = try_execute.find_cycle_in_stack(query_map, &qcx.current_query_job(), span);
265268
(mk_cycle(query, qcx, error), None)
266269
}
267270

0 commit comments

Comments
 (0)