@@ -286,7 +286,7 @@ fn make_code_region(
286
286
start_line = source_map. doctest_offset_line ( & file. name , start_line) ;
287
287
end_line = source_map. doctest_offset_line ( & file. name , end_line) ;
288
288
}
289
- Some ( CodeRegion {
289
+ check_code_region ( CodeRegion {
290
290
file_name,
291
291
start_line : start_line as u32 ,
292
292
start_col : start_col as u32 ,
@@ -295,6 +295,37 @@ fn make_code_region(
295
295
} )
296
296
}
297
297
298
+ /// If `llvm-cov` sees a code region that is improperly ordered (end < start),
299
+ /// it will immediately exit with a fatal error. To prevent that from happening,
300
+ /// discard regions that are improperly ordered, or might be interpreted in a
301
+ /// way that makes them improperly ordered.
302
+ fn check_code_region ( code_region : CodeRegion ) -> Option < CodeRegion > {
303
+ let CodeRegion { file_name : _, start_line, start_col, end_line, end_col } = code_region;
304
+
305
+ // Line/column coordinates are supposed to be 1-based. If we ever emit
306
+ // coordinates of 0, `llvm-cov` might misinterpret them.
307
+ let all_nonzero = [ start_line, start_col, end_line, end_col] . into_iter ( ) . all ( |x| x != 0 ) ;
308
+ // Coverage mappings use the high bit of `end_col` to indicate that a
309
+ // region is actually a "gap" region, so make sure it's unset.
310
+ let end_col_has_high_bit_unset = ( end_col & ( 1 << 31 ) ) == 0 ;
311
+ // If a region is improperly ordered (end < start), `llvm-cov` will exit
312
+ // with a fatal error, which is inconvenient for users and hard to debug.
313
+ let is_ordered = ( start_line, start_col) <= ( end_line, end_col) ;
314
+
315
+ if all_nonzero && end_col_has_high_bit_unset && is_ordered {
316
+ Some ( code_region)
317
+ } else {
318
+ debug ! (
319
+ ?code_region,
320
+ ?all_nonzero,
321
+ ?end_col_has_high_bit_unset,
322
+ ?is_ordered,
323
+ "Skipping code region that would be misinterpreted or rejected by LLVM"
324
+ ) ;
325
+ None
326
+ }
327
+ }
328
+
298
329
fn is_eligible_for_coverage ( tcx : TyCtxt < ' _ > , def_id : LocalDefId ) -> bool {
299
330
// Only instrument functions, methods, and closures (not constants since they are evaluated
300
331
// at compile time by Miri).
0 commit comments