@@ -330,7 +330,7 @@ fn make_code_region(
330
330
start_line = source_map. doctest_offset_line ( & file. name , start_line) ;
331
331
end_line = source_map. doctest_offset_line ( & file. name , end_line) ;
332
332
333
- Some ( CodeRegion {
333
+ check_code_region ( CodeRegion {
334
334
file_name,
335
335
start_line : start_line as u32 ,
336
336
start_col : start_col as u32 ,
@@ -339,6 +339,41 @@ fn make_code_region(
339
339
} )
340
340
}
341
341
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
+ if cfg ! ( debug_assertions) {
370
+ // If this happens in a debug build, ICE to make it easier to notice.
371
+ bug ! ( "Improper code region: {code_region:?}" ) ;
372
+ }
373
+ None
374
+ }
375
+ }
376
+
342
377
fn is_eligible_for_coverage ( tcx : TyCtxt < ' _ > , def_id : LocalDefId ) -> bool {
343
378
// Only instrument functions, methods, and closures (not constants since they are evaluated
344
379
// at compile time by Miri).
0 commit comments