I hit the issue when dealing with https://github.com/apache/httpd/blob/2.4.62/server/mpm_unix.c#L901. After reduction, I ended up with two variants with slightly different triggering conditions. See comments in code for details. How to reproduce: $ gcc --version gcc (GCC) 15.0.0 20240923 (experimental) Copyright (C) 2024 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. $ cat > test.c << 'EOF' int arr[10]; int *foo() { return arr; } int bar() { return 0; } int main(void) { int *a = arr; int zero = 0; if (zero) {} else { // Variant 1 triggering conditions: // // 1. RHS of assignment is a function call // 2. The first function name and assignment are put in one line; // the second function name is put in the other line // 3. Inside if(){...}, else{...}, for(){...} etc *foo()= bar(); } // Variant 2 triggering conditions: // // 1. RHS of assignment is a dereference // 2. The function name and assignment are put in one line; the second // dereference is put in the other line // 3. The operand of dereference is referenced elsewhere *foo()= *a; &a; return 0; } EOF $ gcc --coverage test.c -o test $ ./test $ gcov test $ cat test.c.gcov ... 2: 22: *foo()= 1: 23: bar(); ... 2: 32: *foo()= 1: 33: *a; ... Line 22 and 32 are reported to executed twice, which is hard to interpret.
I think this is the same underlying issue as PR 117412.
(In reply to Andrew Pinski from comment #1) > I think this is the same underlying issue as PR 117412. Hi Andrew, thanks for your reply! In practice we've seen many such cases caused by multi-line expressions. Internally we have been triaging based on the minimal language constructs needed to reproduce the behavior (triggering conditions). That's why I filed two different bug reports. Do you have suggestions for triaging or debugging in general? Thanks!
From a quick look it seems like the problem is fundamentally the difference in how gcc counts executions (on the basic block) and how that is mapped to lines. I don't know if there a complete fix if the expectation is lines [1], other than maybe applying some heuristics to not count multiple basic blocks in a straight line that map to the same line. [1] For example, you can remove all newlines from the source and it would most likely still be a valid C program. How would you count "lines executed"?