[libc-commits] [libc] 72f5694 - [libc] Enable full-build code coverage (#221802)

via libc-commits libc-commits at lists.llvm.org
Thu Sep 10 09:50:36 PDT 2026


Author: Tapiwa Gonga
Date: 2026-09-10T17:50:31+01:00
New Revision: 72f5694df7b6c9fa94f22468f5cd468d305b9917

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

LOG: [libc] Enable full-build code coverage (#221802)

Extended LIBC_ENABLE_COVERAGE to support LLVM_LIBC_FULL_BUILD=ON and
added the LIBC_ENABLE_COVERAGE_MCDC CMake option for MC/DC coverage.

This enables developers and CI pipelines to measure source-level and
MC/DC coverage directly on hermetic tests in full-build configurations
without relying on the host C library.

Updated add_libc_hermetic in LLVMLibCTestRules.cmake to link hermetic
tests with -noprofilelib, -u__llvm_profile_runtime, and compiler-rt's
profiling library. Replaced internal entrypoint objects in
link_object_files with public entrypoint objects for the C functions
referenced by libclang_rt.profile.a.

Added calloc and __errno_location to HermeticTestUtils.cpp to satisfy
remaining freestanding profiling runtime dependencies. Updated
libc/docs/dev/code_coverage.md with full-build instructions.

Assisted-by: Automated tooling, human reviewed.

Added: 
    

Modified: 
    libc/CMakeLists.txt
    libc/cmake/modules/LLVMLibCTestRules.cmake
    libc/docs/dev/code_coverage.md
    libc/test/UnitTest/CMakeLists.txt
    libc/test/UnitTest/HermeticTestUtils.cpp

Removed: 
    


################################################################################
diff  --git a/libc/CMakeLists.txt b/libc/CMakeLists.txt
index b21741c161e44..d7769bb7d0667 100644
--- a/libc/CMakeLists.txt
+++ b/libc/CMakeLists.txt
@@ -93,15 +93,20 @@ set(LIBC_TEST_LINK_OPTIONS_DEFAULT "" CACHE STRING "Common link options for all
 
 # Enable source-based code coverage using Clang's continuous profiling mode.
 option(LIBC_ENABLE_COVERAGE "Build libc with coverage instrumentation" OFF)
+option(LIBC_ENABLE_COVERAGE_MCDC
+       "Enable Modified Condition / Decision Coverage (MC/DC)" OFF)
 if(LIBC_ENABLE_COVERAGE)
   if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
     list(APPEND LIBC_COMPILE_OPTIONS_DEFAULT
-         "-fprofile-instr-generate=libc_cov_%c%p.profraw"
+         "-fprofile-instr-generate=libc_cov_%p.profraw"
          "-fcoverage-mapping"
          "-fprofile-continuous")
     list(APPEND LIBC_TEST_LINK_OPTIONS_DEFAULT
-         "-fprofile-instr-generate=libc_cov_%c%p.profraw"
+         "-fprofile-instr-generate=libc_cov_%p.profraw"
          "-fprofile-continuous")
+    if(LIBC_ENABLE_COVERAGE_MCDC)
+      list(APPEND LIBC_COMPILE_OPTIONS_DEFAULT "-fcoverage-mcdc")
+    endif()
   else()
     message(FATAL_ERROR
             "Coverage instrumentation is currently only supported with Clang")
@@ -181,10 +186,31 @@ if(LIBC_ENABLE_COVERAGE)
       "LIBC_ENABLE_COVERAGE is not supported on GPU or baremetal targets.")
   endif()
   if(LLVM_LIBC_FULL_BUILD)
-    message(FATAL_ERROR
-      "LIBC_ENABLE_COVERAGE is only supported in overlay mode "
-      "(LLVM_LIBC_FULL_BUILD=OFF). Full build mode uses hermetic tests "
-      "which cannot link the compiler-rt profiling runtime.")
+    set(target_arg "")
+    if(LIBC_TARGET_TRIPLE)
+      set(target_arg "--target=${LIBC_TARGET_TRIPLE}")
+    endif()
+    execute_process(
+      COMMAND ${CMAKE_CXX_COMPILER} ${target_arg}
+              --print-file-name=libclang_rt.profile.a
+      OUTPUT_STRIP_TRAILING_WHITESPACE
+      OUTPUT_VARIABLE libc_profile_lib
+    )
+    if(NOT EXISTS "${libc_profile_lib}")
+      set(profile_arch_lib
+          "libclang_rt.profile-${LIBC_TARGET_ARCHITECTURE}.a")
+      execute_process(
+        COMMAND ${CMAKE_CXX_COMPILER} ${target_arg}
+                --print-file-name=${profile_arch_lib}
+        OUTPUT_STRIP_TRAILING_WHITESPACE
+        OUTPUT_VARIABLE libc_profile_lib
+      )
+    endif()
+    if(NOT EXISTS "${libc_profile_lib}")
+      message(FATAL_ERROR "Coverage enabled but profile runtime not found.")
+    endif()
+    set(LIBC_CLANG_PROFILE_LIB "${libc_profile_lib}"
+        CACHE INTERNAL "Clang profile runtime")
   endif()
 endif()
 option(LLVM_LIBC_IMPLEMENTATION_DEFINED_TEST_BEHAVIOR "Build LLVM libc tests assuming our implementation-defined behavior" ON)

diff  --git a/libc/cmake/modules/LLVMLibCTestRules.cmake b/libc/cmake/modules/LLVMLibCTestRules.cmake
index 7c9d79a741945..b9bda4fd08b4d 100644
--- a/libc/cmake/modules/LLVMLibCTestRules.cmake
+++ b/libc/cmake/modules/LLVMLibCTestRules.cmake
@@ -824,6 +824,49 @@ function(add_libc_hermetic test_name)
     list(APPEND fq_deps_list libc.src.time.clock)
   endif()
 
+  if(LIBC_ENABLE_COVERAGE)
+     set(coverage_deps
+      libc.src.stdio.fclose
+      libc.src.stdio.fdopen
+      libc.src.stdio.feof
+      libc.src.stdio.fflush
+      libc.src.stdio.fileno
+      libc.src.stdio.fopen
+      libc.src.stdio.fprintf
+      libc.src.stdio.fread
+      libc.src.stdio.fseek
+      libc.src.stdio.ftell
+      libc.src.stdio.fwrite
+      libc.src.stdio.snprintf
+      libc.src.stdio.stderr
+      libc.src.stdio.vfprintf
+      libc.src.stdio.vsnprintf
+      libc.src.fcntl.fcntl
+      libc.src.fcntl.open
+      libc.src.stdlib.getenv
+      libc.src.stdlib.setenv
+      libc.src.stdlib.strtol
+      libc.src.string.strchr
+      libc.src.string.strcmp
+      libc.src.string.strdup
+      libc.src.string.strerror
+      libc.src.string.strlen
+      libc.src.string.strncpy
+      libc.src.string.strrchr
+      libc.src.sys.mman.madvise
+      libc.src.sys.mman.mmap
+      libc.src.sys.mman.munmap
+      libc.src.sys.prctl.prctl
+      libc.src.sys.stat.mkdir
+      libc.src.sys.utsname.uname
+      libc.src.unistd.fork
+      libc.src.unistd.ftruncate
+      libc.src.unistd.getpagesize
+      libc.src.unistd.getpid
+    )
+    list(APPEND fq_deps_list ${coverage_deps})
+  endif()
+
   list(REMOVE_DUPLICATES fq_deps_list)
 
   # TODO: Instead of gathering internal object files from entrypoints,
@@ -840,6 +883,18 @@ function(add_libc_hermetic test_name)
   endif()
   list(REMOVE_DUPLICATES link_object_files)
 
+  if(LIBC_ENABLE_COVERAGE)
+    foreach(cov_dep IN LISTS coverage_deps)
+      get_target_property(is_alias ${cov_dep} "IS_ALIAS")
+      if(is_alias)
+        get_target_property(real_target ${cov_dep} "DEPS")
+      else()
+        set(real_target ${cov_dep})
+      endif()
+      string(REPLACE "${real_target}.__internal__" "${real_target}" link_object_files "${link_object_files}")
+    endforeach()
+  endif()
+
   # Make a library of all deps
   add_library(
     ${fq_target_name}.__libc__
@@ -905,6 +960,12 @@ function(add_libc_hermetic test_name)
       ${LIBC_LINK_OPTIONS_DEFAULT}
       ${LIBC_TEST_LINK_OPTIONS_DEFAULT}
     )
+    if(LIBC_ENABLE_COVERAGE)
+      list(APPEND link_options
+        -noprofilelib
+        -u__llvm_profile_runtime
+      )
+    endif()
     target_link_options(${fq_build_target_name} PRIVATE ${link_options})
   else()
     # Older version of gcc does not support `nostdlib++` flag.  We use
@@ -916,15 +977,31 @@ function(add_libc_hermetic test_name)
       ${LIBC_LINK_OPTIONS_DEFAULT}
       ${LIBC_TEST_LINK_OPTIONS_DEFAULT}
     )
+    if(LIBC_ENABLE_COVERAGE)
+      list(APPEND link_options
+        -noprofilelib
+        -u__llvm_profile_runtime
+      )
+    endif()
     target_link_options(${fq_build_target_name} PRIVATE ${link_options})
     list(APPEND compiler_runtime ${LIBGCC_S_LOCATION})
   endif()
+
+  set(coverage_link_libs "")
+  if(LIBC_ENABLE_COVERAGE)
+    set(coverage_link_libs
+      "${LIBC_CLANG_PROFILE_LIB}"
+       ${fq_target_name}.__libc__
+    )
+  endif()
+
   target_link_libraries(
     ${fq_build_target_name}
     PRIVATE
       libc.startup.${LIBC_TARGET_OS}.crt1
       ${HERMETIC_TEST_LINK_LIBRARIES}
       ${fq_target_name}.__libc__
+      ${coverage_link_libs}
       ${compiler_runtime}
   )
   add_dependencies(${fq_build_target_name} ${fq_deps_list})

diff  --git a/libc/docs/dev/code_coverage.md b/libc/docs/dev/code_coverage.md
index ab6a8288f1fdc..8e58ca5d14ffd 100644
--- a/libc/docs/dev/code_coverage.md
+++ b/libc/docs/dev/code_coverage.md
@@ -51,27 +51,32 @@ executed across parent and child processes directly to the profile file.
 
 ### Build System Integration
 Setting `-DLIBC_ENABLE_COVERAGE=ON` in the CMake configuration passes
-`-fprofile-instr-generate=libc_cov_%c%p.profraw`, `-fcoverage-mapping`, and
+`-fprofile-instr-generate=libc_cov_%p.profraw`, `-fcoverage-mapping`, and
 `-fprofile-continuous` across all LLVM-libc compilation units and test link
-steps. This ensures uniform instrumentation across entrypoints and unit test
-harnesses.
+steps. When `-fprofile-continuous` is enabled, Clang automatically prepends
+`%c` to the profile file template, avoiding duplicate specifier warnings at
+runtime. Setting `-DLIBC_ENABLE_COVERAGE_MCDC=ON` additionally enables
+`-fcoverage-mcdc`.
 
 ## Running Code Coverage Locally
 
 ### Prerequisites & Toolchain Setup
 
-Generating coverage reports requires Clang, LLVM profile tools, CMake, and
+Generating coverage reports requires Clang 24, LLVM profile tools, CMake, and
 Ninja:
 
-* **Compiler:** Clang 18 or later (Clang 21 or later is required for MC/DC
-  instrumentation).
-* **LLVM Utilities:** Matching major versions of `llvm-profdata` and `llvm-cov`.
+* **Compiler:** Clang 24 (or Clang built from HEAD). Full-build hermetic tests
+  link `libclang_rt.profile.a`, which must match the compiler version and cannot
+  rely on distro-built libraries with glibc source fortification.
+* **LLVM Utilities:** Matching Clang 24 versions of `llvm-profdata` and
+  `llvm-cov`.
+* **Linker:** `lld` is recommended when configuring full-build mode.
 * **Build System:** CMake 3.28+ and Ninja.
 
 #### Toolchain Discovery
 
-If your Linux distribution packages version-suffixed binaries (e.g. `clang-21`,
-`llvm-profdata-21`), discover and export them:
+If your Linux distribution packages version-suffixed binaries (e.g. `clang-24`,
+`llvm-profdata-24`), discover and export them:
 
 ```bash
 CLANG_MAJOR=$(clang --version | sed -n 's/.*version \([0-9]*\).*/\1/p')
@@ -90,6 +95,25 @@ export LLVM_COV=llvm-cov
 
 Subsequent merge and report commands reference `$LLVM_PROFDATA` and `$LLVM_COV`.
 
+#### Building Clang 24 with Profiling Support
+
+Full-build hermetic tests link `libclang_rt.profile.a`. Distro-built compiler-rt
+packages on distributions like Debian or Ubuntu are built with glibc source
+fortification enabled, which LLVM-libc does not support because it introduces
+unresolved symbols such as `__vfprintf_chk`. Furthermore, compiler-rt must
+match the exact version of the compiler used to build. The recommended approach
+is building Clang 24, lld, and compiler-rt from HEAD:
+
+```bash
+cmake -G Ninja -S llvm -B build-clang \
+  -DCMAKE_BUILD_TYPE=Release \
+  -DCMAKE_INSTALL_PREFIX="$HOME/clang" \
+  -DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra;lld" \
+  -DLLVM_ENABLE_RUNTIMES="compiler-rt" \
+  -DLLVM_USE_LINKER=lld
+ninja -C build-clang install
+```
+
 ---
 
 ## Cleaning Profile Counters
@@ -111,51 +135,67 @@ rm -f libc_full.profdata libc_mcdc.profdata libc_single.profdata \
 Standard coverage measures physical line execution and conditional branch
 outcomes across all LLVM-libc entrypoints and internal support utilities.
 
-### 1. CMake Configuration
+### 1. Clean Prior Profile Artifacts
 
-Configures CMake to build LLVM-libc in overlay mode, setting
-`-DLIBC_ENABLE_COVERAGE=ON` to pass Clang's continuous profiling and coverage
-mapping flags to the compiler:
+Removes previously generated raw profile counters and profile data to maintain
+a clean baseline:
+
+```bash
+rm -f build-cov/libc_cov_*.profraw libc_cov_*.profraw profraw_list.txt libc_full.profdata
+```
+
+### 2. Configure Full-Build Coverage with Clang 24
+
+Configures CMake to build LLVM-libc with code coverage enabled using Clang 24
+and LLD:
 
 ```bash
 cmake -G Ninja -S runtimes -B build-cov \
-  -DCMAKE_C_COMPILER=clang \
-  -DCMAKE_CXX_COMPILER=clang++ \
+  -DCMAKE_C_COMPILER="$PWD/build-clang/bin/clang" \
+  -DCMAKE_CXX_COMPILER="$PWD/build-clang/bin/clang++" \
+  -DLLVM_USE_LINKER=lld \
   -DCMAKE_BUILD_TYPE=Debug \
   -DLLVM_ENABLE_RUNTIMES="libc" \
-  -DLLVM_LIBC_FULL_BUILD=OFF \
+  -DLLVM_LIBC_FULL_BUILD=ON \
   -DLIBC_ENABLE_COVERAGE=ON
 ```
 
-### 2. Build and Execute All Unit Tests
+### 3. Export Environment Variables
+
+Exports the profile output pattern and Clang 24 tool paths:
+
+```bash
+export LLVM_PROFILE_FILE="libc_cov_%p.profraw"
+export LLVM_PROFDATA="$PWD/build-clang/bin/llvm-profdata"
+export LLVM_COV="$PWD/build-clang/bin/llvm-cov"
+```
+
+### 4. Build and Execute Hermetic Tests
 
-Compiles all libc unit test executables and executes them in parallel. As each
-test executes, its counters are mapped directly to disk via the OS page cache:
+Compiles and executes the full hermetic test suite:
 
 ```bash
-export LLVM_PROFILE_FILE="libc_cov_%c%p.profraw"
-ninja -k 0 -C build-cov libc-unit-tests
+ninja -k 0 -C build-cov libc-hermetic-tests
 ```
 
 :::{note}
-In LLVM-libc, `libc-unit-tests` builds and executes tests in a single
-invocation. The `-k 0` flag ensures Ninja continues executing all remaining
-test targets even if an individual edge-case test encounters an error. To only
-compile test binaries without immediately executing them, use
-`ninja -C build-cov libc-unit-tests-build`.
+The `-k 0` flag ensures Ninja continues executing all remaining test targets
+even if an individual edge-case test encounters an error. To only compile test
+binaries without executing them, use
+`ninja -C build-cov libc-hermetic-tests-build`.
 :::
 
-### 3. Merge Profile Counters
+### 5. Merge Profile Counters
 
 Scans the build tree for all generated `.profraw` files and indexes them into a
 unified, sparse `.profdata` archive using `$LLVM_PROFDATA`:
 
 ```bash
-find build-cov/ -name "libc_cov_*.profraw" > profraw_list.txt
+find build-cov -name "libc_cov_*.profraw" > profraw_list.txt
 "$LLVM_PROFDATA" merge -sparse -f profraw_list.txt -o libc_full.profdata
 ```
 
-### 4. Generate Coverage Reports
+### 6. Generate Coverage Reports
 
 Collects all compiled test binary paths and invokes `$LLVM_COV` to correlate
 recorded profile counters against the libc source tree:
@@ -171,6 +211,7 @@ done
 Reports can be generated in 
diff erent formats:
 
 #### Option 1: Terminal Summary Report
+
 Prints an aggregated terminal summary showing line, region, and branch coverage
 percentages for each file:
 
@@ -182,7 +223,17 @@ percentages for each file:
   -ignore-filename-regex=".*(test|utils).*"
 ```
 
+To restrict the terminal report to a specific source file:
+
+```bash
+"$LLVM_COV" report \
+  -instr-profile=libc_full.profdata \
+  "${TEST_BINS[0]}" "${OBJECT_FLAGS[@]}" \
+  libc/src/string/strlen.cpp
+```
+
 #### Option 2: Interactive HTML Dashboard
+
 Generates an interactive HTML dashboard containing sortable directory metrics
 and syntax-highlighted source views:
 
@@ -209,44 +260,61 @@ as `if (A && B)`). It verifies that each individual sub-condition evaluates to
 both true and false and independently affects the outcome of the enclosing
 decision.
 
-### 1. CMake Configuration
+### 1. Clean Prior Profile Artifacts
 
-Configures CMake with `-fcoverage-mcdc` alongside profiling flags, enabling the
-compiler frontend to generate boolean condition bitmaps for compound decisions:
+Removes previous MC/DC profile counters and profile data:
+
+```bash
+rm -f build-cov-mcdc/libc_cov_*.profraw libc_cov_*.profraw profraw_list.txt libc_mcdc.profdata
+```
+
+### 2. Configure Full-Build Coverage with MC/DC using Clang 24
+
+Configures CMake with `-DLIBC_ENABLE_COVERAGE_MCDC=ON` alongside profiling
+flags using Clang 24 and LLD:
 
 ```bash
 cmake -G Ninja -S runtimes -B build-cov-mcdc \
-  -DCMAKE_C_COMPILER=clang \
-  -DCMAKE_CXX_COMPILER=clang++ \
+  -DCMAKE_C_COMPILER="$PWD/build-clang/bin/clang" \
+  -DCMAKE_CXX_COMPILER="$PWD/build-clang/bin/clang++" \
+  -DLLVM_USE_LINKER=lld \
   -DCMAKE_BUILD_TYPE=Debug \
   -DLLVM_ENABLE_RUNTIMES="libc" \
-  -DLLVM_LIBC_FULL_BUILD=OFF \
+  -DLLVM_LIBC_FULL_BUILD=ON \
   -DLIBC_ENABLE_COVERAGE=ON \
-  -DCMAKE_C_FLAGS="-fcoverage-mcdc" \
-  -DCMAKE_CXX_FLAGS="-fcoverage-mcdc"
+  -DLIBC_ENABLE_COVERAGE_MCDC=ON
+```
+
+### 3. Export Environment Variables
+
+Exports the profile output pattern and Clang 24 tool paths:
+
+```bash
+export LLVM_PROFILE_FILE="libc_cov_%p.profraw"
+export LLVM_PROFDATA="$PWD/build-clang/bin/llvm-profdata"
+export LLVM_COV="$PWD/build-clang/bin/llvm-cov"
 ```
 
-### 2. Build and Execute Tests
+### 4. Build and Execute Hermetic Tests
 
-Compiles and executes all unit tests with MC/DC instrumentation enabled, saving
-condition evaluation bitmasks into raw profile files upon completion:
+Compiles and executes test executables in parallel with MC/DC instrumentation
+enabled:
 
 ```bash
-export LLVM_PROFILE_FILE="libc_cov_%c%p.profraw"
-ninja -k 0 -C build-cov-mcdc libc-unit-tests
+ninja -k 0 -C build-cov-mcdc libc-hermetic-tests
 ```
 
-### 3. Merge Profiles
+### 5. Merge Profile Counters
 
 Indexes and merges all MC/DC `.profraw` files into a unified
 `libc_mcdc.profdata` archive for report generation:
 
 ```bash
-find build-cov-mcdc/ -name "libc_cov_*.profraw" > profraw_list.txt
+find build-cov-mcdc -name "libc_cov_*.profraw" > profraw_list.txt
 "$LLVM_PROFDATA" merge -sparse -f profraw_list.txt -o libc_mcdc.profdata
 ```
 
-### 4. Generate Reports
+### 6. Generate MC/DC Coverage Reports
 
 Maps MC/DC bitmap records to source AST decisions and evaluates condition
 independence pairs:
@@ -262,6 +330,7 @@ done
 Reports can be generated in two formats depending on your needs:
 
 #### Option 1: Terminal Summary Report
+
 Displays the terminal coverage summary including MC/DC Condition and Missed
 Condition percentages:
 
@@ -275,6 +344,7 @@ Condition percentages:
 ```
 
 #### Option 2: Interactive HTML Dashboard
+
 Produces an HTML report with expandable MC/DC decision truth tables and test
 vector coverage breakdowns:
 
@@ -299,7 +369,7 @@ xdg-open coverage_mcdc_html/index.html
 ## Running Coverage for a Single Test
 
 When developing or modifying a specific function, coverage can be collected for
-a single test without building and executing the entire test suite.
+a single hermetic test without building and executing the entire test suite.
 
 The commands below use `libc.test.src.ctype.isalpha_test` (which tests
 `libc/src/ctype/isalpha.cpp`) as an example. You can test any other entrypoint
@@ -309,25 +379,32 @@ by substituting the target name and source file path:
 * **Source path pattern:** `libc/<path_to_source>/<source_file>.cpp`
   (e.g. `libc/src/string/strlen.cpp`)
 
-### 1. Build and Execute the Targeted Test
+### 1. Clean Prior Profile Artifacts
+
+Removes previously generated raw profile counters:
+
+```bash
+rm -f libc_cov_*.profraw profraw_list.txt libc_single.profdata
+```
+
+### 2. Build and Execute the Targeted Test
 
 Compiles and runs only the specified test binary, immediately writing execution
 profile counters to disk upon completion:
 
 ```bash
-export LLVM_PROFILE_FILE="libc_cov_%c%p.profraw"
+export LLVM_PROFILE_FILE="libc_cov_%p.profraw"
 
-# For a standard coverage build
+# Standard coverage build
 ninja -C build-cov libc.test.src.ctype.isalpha_test
 
-# For an MC/DC build
+# MC/DC coverage build
 ninja -C build-cov-mcdc libc.test.src.ctype.isalpha_test
 ```
 
-### 2. Merge the Profile
+### 3. Merge the Profile
 
-Merges the single test's raw profile into an indexed database for targeted
-inspection (searching whichever build directory was compiled):
+Merges the single test's raw profile into an indexed database:
 
 ```bash
 find build-cov/ build-cov-mcdc/ \
@@ -335,12 +412,10 @@ find build-cov/ build-cov-mcdc/ \
 "$LLVM_PROFDATA" merge -sparse -f profraw_list.txt -o libc_single.profdata
 ```
 
-### 3. View the Terminal Report
-
-Reports can be viewed as an overall file summary or an annotated line-by-line
-breakdown:
+### 4. View Coverage Reports
 
 #### Option 1: Summary Table Report
+
 ```bash
 BIN_DIR="build-cov/libc/test/src/ctype"
 "$LLVM_COV" report \
@@ -350,6 +425,7 @@ BIN_DIR="build-cov/libc/test/src/ctype"
 ```
 
 #### Option 2: Line-by-Line & Truth Table View
+
 ```bash
 BIN_DIR="build-cov-mcdc/libc/test/src/ctype"
 "$LLVM_COV" show \
@@ -405,9 +481,10 @@ When inspecting with `--show-mcdc`, `llvm-cov` displays an MC/DC analysis table
 beneath each compound decision. For instance, consider the following decision:
 
 ```text
-   19|  if (c < 0 || c > 255)
-  -----------------------------------------------
-  | Conditions: C1 = (c < 0), C2 = (c > 255)
+   19|  if (c < 0 || c > cpp::numeric_limits<unsigned char>::max())
+  ------------------------------------------------------------------
+  | Conditions: C1 = (c < 0)
+  |             C2 = (c > cpp::numeric_limits<unsigned char>::max())
   |
   | Executed Test Vectors:
   |    C1, C2    Result
@@ -417,10 +494,11 @@ beneath each compound decision. For instance, consider the following decision:
   | C1-Pair: covered (1, 2)
   | C2-Pair: not covered
   | MC/DC Coverage: 50.00%
-  -----------------------------------------------
+  ------------------------------------------------------------------
 ```
 
-* **Conditions:** **C1** represents `c < 0` and **C2** represents `c > 255`.
+* **Conditions:** **C1** represents `c < 0` and **C2** represents
+  `c > cpp::numeric_limits<unsigned char>::max()`.
 * **Executed Vectors:**
   * **Vector 1 (`F, F = F`):** Tested with a valid character (`c = 'a'`). Both
     C1 and C2 evaluated False, producing an overall False result.

diff  --git a/libc/test/UnitTest/CMakeLists.txt b/libc/test/UnitTest/CMakeLists.txt
index e6d978e16b46f..f409b644ef852 100644
--- a/libc/test/UnitTest/CMakeLists.txt
+++ b/libc/test/UnitTest/CMakeLists.txt
@@ -169,7 +169,9 @@ add_unittest_framework_library(
   SRCS
     ${libc_hermetic_test_support_srcs}
   DEPENDS
+    libc.hdr.errno_macros
     libc.hdr.stdint_proxy
+    libc.src.__support.libc_errno
 )
 
 add_header_library(

diff  --git a/libc/test/UnitTest/HermeticTestUtils.cpp b/libc/test/UnitTest/HermeticTestUtils.cpp
index a9bbf13a1f190..4a5cbd8040b52 100644
--- a/libc/test/UnitTest/HermeticTestUtils.cpp
+++ b/libc/test/UnitTest/HermeticTestUtils.cpp
@@ -6,8 +6,10 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "hdr/errno_macros.h"
 #include "hdr/stdint_proxy.h"
 #include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
 #include "src/__support/macros/config.h"
 #include <stddef.h>
 
@@ -123,6 +125,26 @@ unsigned long __getauxval(unsigned long id) {
 }
 #endif
 
+void *calloc(size_t num, size_t size) {
+  if (num == 0 || size == 0)
+    return nullptr;
+  size_t total = 0;
+  if (__builtin_mul_overflow(num, size, &total)) {
+    LIBC_NAMESPACE::libc_errno = ENOMEM;
+    return nullptr;
+  }
+  void *mem = malloc(total);
+  if (mem == nullptr) {
+    LIBC_NAMESPACE::libc_errno = ENOMEM;
+    return nullptr;
+  }
+  LIBC_NAMESPACE::memset(mem, 0, total);
+  return mem;
+}
+#if defined(__linux__)
+int *__errno_location() noexcept { return LIBC_NAMESPACE::__llvm_libc_errno(); }
+#endif
+
 } // extern "C"
 
 void *operator new([[maybe_unused]] size_t size, void *ptr) { return ptr; }


        


More information about the libc-commits mailing list