Skip to content

Commit c193bb7

Browse files
authored
[Coverage] getMaxBitmapSize: Scan max(BitmapIdx) instead of the last Decision (#78963)
In `CoverageMapping.cpp:getMaxBitmapSize()`, this assumed that the last `Decision` has the maxmum `BitmapIdx`. Let it scan `max(BitmapIdx)`. Note that `<=` is used insted of `<`, because `BitmapIdx == 0` is valid and `MaxBitmapID` is `unsigned`. `BitmapIdx` is unique in the record. Fixes #78922
1 parent d8628a0 commit c193bb7

File tree

5 files changed

+74
-5
lines changed

5 files changed

+74
-5
lines changed

llvm/lib/ProfileData/Coverage/CoverageMapping.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,7 @@ Expected<BitVector> CounterMappingContext::evaluateBitmap(
229229
unsigned SizeInBits = llvm::alignTo(uint64_t(1) << NC, CHAR_BIT);
230230
unsigned SizeInBytes = SizeInBits / CHAR_BIT;
231231

232+
assert(ID + SizeInBytes <= BitmapBytes.size() && "BitmapBytes overrun");
232233
ArrayRef<uint8_t> Bytes(&BitmapBytes[ID], SizeInBytes);
233234

234235
// Mask each bitmap byte into the BitVector. Go in reverse so that the
@@ -568,14 +569,14 @@ static unsigned getMaxBitmapSize(const CounterMappingContext &Ctx,
568569
const CoverageMappingRecord &Record) {
569570
unsigned MaxBitmapID = 0;
570571
unsigned NumConditions = 0;
571-
// The last DecisionRegion has the highest bitmap byte index used in the
572-
// function, which when combined with its number of conditions, yields the
573-
// full bitmap size.
572+
// Scan max(BitmapIdx).
573+
// Note that `<=` is used insted of `<`, because `BitmapIdx == 0` is valid
574+
// and `MaxBitmapID is `unsigned`. `BitmapIdx` is unique in the record.
574575
for (const auto &Region : reverse(Record.MappingRegions)) {
575-
if (Region.Kind == CounterMappingRegion::MCDCDecisionRegion) {
576+
if (Region.Kind == CounterMappingRegion::MCDCDecisionRegion &&
577+
MaxBitmapID <= Region.MCDCParams.BitmapIdx) {
576578
MaxBitmapID = Region.MCDCParams.BitmapIdx;
577579
NumConditions = Region.MCDCParams.NumConditions;
578-
break;
579580
}
580581
}
581582
unsigned SizeInBits = llvm::alignTo(uint64_t(1) << NumConditions, CHAR_BIT);
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#define RANGE(a,b,c) ((a) <= (b) && (b) <= (c))
2+
3+
int sub(int c) {
4+
if (RANGE('0', c, '9')) return 1;
5+
return (('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z'));
6+
}
7+
8+
extern void __llvm_profile_write_file(void);
9+
10+
int main(int c, char **v)
11+
{
12+
return (c > 1 ? sub(c) : 0);
13+
}
4.54 KB
Binary file not shown.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
main
2+
# Func Hash:
3+
99164
4+
# Num Counters:
5+
2
6+
# Counter Values:
7+
1
8+
0
9+
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Test not to trigger the assertion failure in llvm-cov with empty bitmap.
2+
# REQUIRES: asserts
3+
4+
# mcdc-maxbs.o contains the record:
5+
#
6+
# sub:
7+
# Decision,File 0, 5:11 -> 5:59 = M:1, C:4
8+
# Branch,File 0, 5:12 -> 5:20 = #5, ((#0 - #1) - #5) [1,3,2]
9+
# Branch,File 0, 5:24 -> 5:32 = #6, (#5 - #6) [3,0,2]
10+
# Branch,File 0, 5:38 -> 5:46 = #7, (#4 - #7) [2,4,0]
11+
# Branch,File 0, 5:50 -> 5:58 = #8, (#7 - #8) [4,0,0]
12+
# Decision,File 1, 1:23 -> 1:47 = M:0, C:2
13+
# Branch,File 1, 1:23 -> 1:33 = #2, (#0 - #2) [1,2,0]
14+
# Branch,File 1, 1:37 -> 1:47 = #3, (#2 - #3) [2,0,0]
15+
#
16+
# With the previous implementation, `Decision M:0 C:2` was picked up as
17+
# the last `Decision`.
18+
# The size of the bitmap was reported as `1` in this case.
19+
# Actually, the largest `Decision` is `M:1 C:4` and the size should be `3`
20+
# (Idx=1, len=16 bits).
21+
#
22+
# When a corresponding bitmap was not emitted, the dummy zero-ed bitmap is
23+
# allocated as `BitmapBytes` with `getMaxBitmapSize(Record) + 1`
24+
# (in this case, `1 + 1`, less than `3`).
25+
# It may overrun and would trigger `unexpected test vector`
26+
# by trailing uninitialized garbage.
27+
28+
# RUN: llvm-profdata merge %S/Inputs/mcdc-maxbs.proftext -o %t.profdata
29+
# RUN: llvm-cov report --show-mcdc-summary %S/Inputs/mcdc-maxbs.o -instr-profile %t.profdata
30+
31+
# Instructions for regenerating the test object:
32+
33+
cd %S/Inputs # or copy %S/Inputs/mcdc-maxbs.c into the working directory
34+
clang -O3 -fcoverage-mcdc -fprofile-instr-generate \
35+
-fcoverage-mapping -fcoverage-compilation-dir=. \
36+
mcdc-maxbs.c -c -o mcdc-maxbs.o
37+
38+
# Instructions for regenerating the test vector:
39+
40+
clang -fprofile-instr-generate mcdc-maxbs.o
41+
42+
# Doesn't crash if argc > 1
43+
./a.out
44+
45+
llvm-profdata merge --sparse -o default.profdata default.profraw
46+
llvm-profdata merge --text -o mcdc-maxbs.proftext default.profdata

0 commit comments

Comments
 (0)