[llvm] c193bb7 - [Coverage] getMaxBitmapSize: Scan `max(BitmapIdx)` instead of the last `Decision` (#78963)

via llvm-commits llvm-commits at lists.llvm.org
Tue Jan 23 00:59:48 PST 2024


Author: NAKAMURA Takumi
Date: 2024-01-23T17:59:44+09:00
New Revision: c193bb7e9eee02a435944506c732db9b480f0c84

URL: https://github.com/llvm/llvm-project/commit/c193bb7e9eee02a435944506c732db9b480f0c84
DIFF: https://github.com/llvm/llvm-project/commit/c193bb7e9eee02a435944506c732db9b480f0c84.diff

LOG: [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

Added: 
    llvm/test/tools/llvm-cov/Inputs/mcdc-maxbs.c
    llvm/test/tools/llvm-cov/Inputs/mcdc-maxbs.o
    llvm/test/tools/llvm-cov/Inputs/mcdc-maxbs.proftext
    llvm/test/tools/llvm-cov/mcdc-maxbs.test

Modified: 
    llvm/lib/ProfileData/Coverage/CoverageMapping.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index 9c95cd5d76d215..da8e1d87319dde 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -229,6 +229,7 @@ Expected<BitVector> CounterMappingContext::evaluateBitmap(
   unsigned SizeInBits = llvm::alignTo(uint64_t(1) << NC, CHAR_BIT);
   unsigned SizeInBytes = SizeInBits / CHAR_BIT;
 
+  assert(ID + SizeInBytes <= BitmapBytes.size() && "BitmapBytes overrun");
   ArrayRef<uint8_t> Bytes(&BitmapBytes[ID], SizeInBytes);
 
   // Mask each bitmap byte into the BitVector. Go in reverse so that the
@@ -568,14 +569,14 @@ static unsigned getMaxBitmapSize(const CounterMappingContext &Ctx,
                                  const CoverageMappingRecord &Record) {
   unsigned MaxBitmapID = 0;
   unsigned NumConditions = 0;
-  // The last DecisionRegion has the highest bitmap byte index used in the
-  // function, which when combined with its number of conditions, yields the
-  // full bitmap size.
+  // Scan max(BitmapIdx).
+  // Note that `<=` is used insted of `<`, because `BitmapIdx == 0` is valid
+  // and `MaxBitmapID is `unsigned`. `BitmapIdx` is unique in the record.
   for (const auto &Region : reverse(Record.MappingRegions)) {
-    if (Region.Kind == CounterMappingRegion::MCDCDecisionRegion) {
+    if (Region.Kind == CounterMappingRegion::MCDCDecisionRegion &&
+        MaxBitmapID <= Region.MCDCParams.BitmapIdx) {
       MaxBitmapID = Region.MCDCParams.BitmapIdx;
       NumConditions = Region.MCDCParams.NumConditions;
-      break;
     }
   }
   unsigned SizeInBits = llvm::alignTo(uint64_t(1) << NumConditions, CHAR_BIT);

diff  --git a/llvm/test/tools/llvm-cov/Inputs/mcdc-maxbs.c b/llvm/test/tools/llvm-cov/Inputs/mcdc-maxbs.c
new file mode 100644
index 00000000000000..83644b29549455
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/Inputs/mcdc-maxbs.c
@@ -0,0 +1,13 @@
+#define RANGE(a,b,c) ((a) <= (b) && (b) <= (c))
+
+int sub(int c) {
+  if (RANGE('0', c, '9')) return 1;
+  return (('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z'));
+}
+
+extern void __llvm_profile_write_file(void);
+
+int main(int c, char **v)
+{
+  return (c > 1 ? sub(c) : 0);
+}

diff  --git a/llvm/test/tools/llvm-cov/Inputs/mcdc-maxbs.o b/llvm/test/tools/llvm-cov/Inputs/mcdc-maxbs.o
new file mode 100644
index 00000000000000..269902224ccae9
Binary files /dev/null and b/llvm/test/tools/llvm-cov/Inputs/mcdc-maxbs.o 
diff er

diff  --git a/llvm/test/tools/llvm-cov/Inputs/mcdc-maxbs.proftext b/llvm/test/tools/llvm-cov/Inputs/mcdc-maxbs.proftext
new file mode 100644
index 00000000000000..f24e984f657f2b
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/Inputs/mcdc-maxbs.proftext
@@ -0,0 +1,9 @@
+main
+# Func Hash:
+99164
+# Num Counters:
+2
+# Counter Values:
+1
+0
+

diff  --git a/llvm/test/tools/llvm-cov/mcdc-maxbs.test b/llvm/test/tools/llvm-cov/mcdc-maxbs.test
new file mode 100644
index 00000000000000..ad5bc828529cee
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/mcdc-maxbs.test
@@ -0,0 +1,46 @@
+# Test not to trigger the assertion failure in llvm-cov with empty bitmap.
+# REQUIRES: asserts
+
+# mcdc-maxbs.o contains the record:
+#
+# sub:
+#   Decision,File 0, 5:11 -> 5:59 = M:1, C:4
+#   Branch,File 0, 5:12 -> 5:20 = #5, ((#0 - #1) - #5) [1,3,2]
+#   Branch,File 0, 5:24 -> 5:32 = #6, (#5 - #6) [3,0,2]
+#   Branch,File 0, 5:38 -> 5:46 = #7, (#4 - #7) [2,4,0]
+#   Branch,File 0, 5:50 -> 5:58 = #8, (#7 - #8) [4,0,0]
+#   Decision,File 1, 1:23 -> 1:47 = M:0, C:2
+#   Branch,File 1, 1:23 -> 1:33 = #2, (#0 - #2) [1,2,0]
+#   Branch,File 1, 1:37 -> 1:47 = #3, (#2 - #3) [2,0,0]
+#
+# With the previous implementation, `Decision M:0 C:2` was picked up as
+# the last `Decision`.
+# The size of the bitmap was reported as `1` in this case.
+# Actually, the largest `Decision` is `M:1 C:4` and the size should be `3`
+# (Idx=1, len=16 bits).
+#
+# When a corresponding bitmap was not emitted, the dummy zero-ed bitmap is
+# allocated as `BitmapBytes` with `getMaxBitmapSize(Record) + 1`
+# (in this case, `1 + 1`, less than `3`).
+# It may overrun and would trigger `unexpected test vector`
+# by trailing uninitialized garbage.
+
+# RUN: llvm-profdata merge %S/Inputs/mcdc-maxbs.proftext -o %t.profdata
+# RUN: llvm-cov report --show-mcdc-summary %S/Inputs/mcdc-maxbs.o -instr-profile %t.profdata
+
+# Instructions for regenerating the test object:
+
+cd %S/Inputs # or copy %S/Inputs/mcdc-maxbs.c into the working directory
+clang -O3 -fcoverage-mcdc -fprofile-instr-generate \
+    -fcoverage-mapping -fcoverage-compilation-dir=. \
+    mcdc-maxbs.c -c -o mcdc-maxbs.o
+
+# Instructions for regenerating the test vector:
+
+clang -fprofile-instr-generate mcdc-maxbs.o
+
+# Doesn't crash if argc > 1
+./a.out
+
+llvm-profdata merge --sparse -o default.profdata default.profraw
+llvm-profdata merge --text -o mcdc-maxbs.proftext default.profdata


        


More information about the llvm-commits mailing list