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 8201df7

Browse files
authoredJan 23, 2024
Rollup merge of rust-lang#119460 - Zalathar:improper-region, r=wesleywiser
coverage: Never emit improperly-ordered coverage regions If we emit a coverage region that is improperly ordered (end < start), `llvm-cov` will fail with `coveragemap_error::malformed`, which is inconvenient for users and also very hard to debug. Ideally we would fix the root causes of these situations, but they tend to occur in very obscure edge-case scenarios (often involving nested macros), and we don't always have a good MCVE to work from. So it makes sense to also have a catch-all check that will prevent improperly-ordered regions from ever being emitted. --- This is mainly aimed at resolving rust-lang#119453. We don't have a specific way to reproduce it, which is why I haven't been able to add a test case in this PR. But based on the information provided in that issue, this change seems likely to avoid the error in `llvm-cov`. ``@rustbot`` label +A-code-coverage
2 parents 98a7664 + 21e5bea commit 8201df7

File tree

1 file changed

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

1 file changed

+34
-1
lines changed
 

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

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

332-
Some(CodeRegion {
332+
check_code_region(CodeRegion {
333333
file_name,
334334
start_line: start_line as u32,
335335
start_col: start_col as u32,
@@ -338,6 +338,39 @@ fn make_code_region(
338338
})
339339
}
340340

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

0 commit comments

Comments
 (0)
Please sign in to comment.