Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 678183e

Browse files
committedJan 9, 2024
coverage: Discard code regions that might cause fatal errors in llvm-cov
1 parent 190f4c9 commit 678183e

File tree

1 file changed

+32
-1
lines changed
  • compiler/rustc_mir_transform/src/coverage

1 file changed

+32
-1
lines changed
 

‎compiler/rustc_mir_transform/src/coverage/mod.rs

+32-1
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ fn make_code_region(
330330
start_line = source_map.doctest_offset_line(&file.name, start_line);
331331
end_line = source_map.doctest_offset_line(&file.name, end_line);
332332

333-
Some(CodeRegion {
333+
check_code_region(CodeRegion {
334334
file_name,
335335
start_line: start_line as u32,
336336
start_col: start_col as u32,
@@ -339,6 +339,37 @@ fn make_code_region(
339339
})
340340
}
341341

342+
/// If `llvm-cov` sees a code region that is improperly ordered (end < start),
343+
/// it will immediately exit with a fatal error. To prevent that from happening,
344+
/// discard regions that are improperly ordered, or might be interpreted in a
345+
/// way that makes them improperly ordered.
346+
fn check_code_region(code_region: CodeRegion) -> Option<CodeRegion> {
347+
let CodeRegion { file_name: _, start_line, start_col, end_line, end_col } = code_region;
348+
349+
// Line/column coordinates are supposed to be 1-based. If we ever emit
350+
// coordinates of 0, `llvm-cov` might misinterpret them.
351+
let all_nonzero = [start_line, start_col, end_line, end_col].into_iter().all(|x| x != 0);
352+
// Coverage mappings use the high bit of `end_col` to indicate that a
353+
// region is actually a "gap" region, so make sure it's unset.
354+
let end_col_has_high_bit_unset = (end_col & (1 << 31)) == 0;
355+
// If a region is improperly ordered (end < start), `llvm-cov` will exit
356+
// with a fatal error, which is inconvenient for users and hard to debug.
357+
let is_ordered = (start_line, start_col) <= (end_line, end_col);
358+
359+
if all_nonzero && end_col_has_high_bit_unset && is_ordered {
360+
Some(code_region)
361+
} else {
362+
debug!(
363+
?code_region,
364+
?all_nonzero,
365+
?end_col_has_high_bit_unset,
366+
?is_ordered,
367+
"Skipping code region that would be misinterpreted or rejected by LLVM"
368+
);
369+
None
370+
}
371+
}
372+
342373
fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
343374
// Only instrument functions, methods, and closures (not constants since they are evaluated
344375
// at compile time by Miri).

0 commit comments

Comments
 (0)
Please sign in to comment.