Skip to content

Inaccurate Coverage Information Due to __llvm_profile_dump During Program Blocking, Requesting Solution #135117

Open
@Kurtcobainzl

Description

@Kurtcobainzl

I have created a demo to investigate coverage collection, and I've observed that the code coverage information for the code located after a blocking operation (such as sleep, scanf, etc.) is inaccurate when __llvm_profile_dump is executed while the program is blocked. Below are the details of my experiment and environment information. I would appreciate guidance and potential solutions to this issue.
Environment Information:
`clang --version
Homebrew clang version 20.1.1
Target: arm64-apple-darwin24.2.0
Thread model: posix
InstalledDir: /opt/homebrew/Cellar/llvm/20.1.1/bin
Configuration file: /opt/homebrew/etc/clang/arm64-apple-darwin24.cfg

llvm-cov --version
Homebrew LLVM version 20.1.1
Optimized build.`

Demo Code:

`

#include <stdint.h>
#include <dlfcn.h>
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
#include <signal.h>
#include
#include
#include
#include

extern "C" void __llvm_profile_reset_counters(void);
extern "C" int __llvm_profile_dump(void);

std::atomic keep_running(true);

void* profile_dumper_thread(void* arg) {
while (keep_running) {
sleep(5);
printf("\n[Background Thread] Dumping coverage data...\n");
__llvm_profile_dump();
__llvm_profile_reset_counters();
}
return nullptr;
}

void foo() {
printf("foo() running\n");
}

void conditional_function(int value) {
printf("conditional_function() running, value = %d\n", value);
if (value > 10) {
printf("value > 10\n");
} else {
printf("value <= 10\n");
}
}

int main() {
printf("Hello, SanitizerCoverage!\n");
int choice1 = 1;
if (choice1 == 1) {
printf("hello1");
} else {
printf("world1");
}
// Create background thread
pthread_t thread_id;
if (pthread_create(&thread_id, nullptr, profile_dumper_thread, nullptr) != 0) {
perror("Failed to create background thread");
return 1;
}
printf("\nProgram will block, waiting for input...\n");
// conditional_function(15);
// std::cin.get();
sleep(5);
conditional_function(15);
sleep(5);
int choice2 = 2;
if (choice2 == 2) {
printf("hello2");
} else {
printf("world2");
}

sleep(5);
int choice3 = 3;
if (choice3 == 3) {
    printf("hello3");
} else {
    printf("world3");
}

sleep(5);
int choice4 = 4;
if (choice4 == 4) {
    printf("hello4");
} else {
    printf("world4");
}

sleep(5);
int choice5 = 5;
if (choice5 == 5) {
    printf("hello5");
} else {
    printf("world5");
}

sleep(5);
int choice6 = 6;
if (choice6 == 6) {
    printf("hello6");
} else {
    printf("world6");
}


sleep(5);
int choice7 = 7;
if (choice7 == 7) {
    printf("hello7");
} else {
    printf("world7");
}

sleep(5);
int choice8 = 8;
if (choice8 == 8) {
    printf("hello8");
} else {
    printf("world8");
}

sleep(5);
int choice9 = 9;
if (choice9 == 9) {
    printf("hello9");
} else {
    printf("world9");
}

sleep(5);
int choice10 = 10;
if (choice10 == 10) {
    printf("hello10");
} else {
    printf("world10");
}
return 0;

}
`
Execution Process:

First Execution:

  1. Build the executable: clang++ -fprofile-instr-generate -fcoverage-mapping -mllvm -runtime-counter-relocation demo06.cpp -o demo
  2. Run the executable: ./demo
  3. Wait for a while, but do not let the program finish naturally.
  4. Execute the command llvm-profdata merge -sparse default.profraw -o default.profdata. At this point, the coverage information has been translated into the default.profdata file. You can terminate the running program.
  5. Execute the command llvm-cov show ./demo -instr-profile=default.profdata --show-line-counts-or-regions to view the coverage information.

Image

Image

Image

You can observe that the coverage information before line 79 is correct, but after line 79, although none of the code is actually executed, a significant portion of the code is marked as executed.

Second Execution:

Clear the files generated during the first execution. Repeat the steps of the first execution, but this time, allow the program to finish naturally before collecting the coverage. You will see that the coverage information is accurate.

Image

Image

I suspect that the blocking execution is causing the subsequent code coverage to fail to be recorded correctly when __llvm_profile_dump is called during the blocked state. I hope the official team can clarify my doubts. If possible, I would appreciate any guidance on how to accurately obtain C++ coverage information in such scenarios.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions