https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120348

            Bug ID: 120348
           Summary: Bogus line coverage triggered by passing pointers via
                    extern "C" functions
           Product: gcc
           Version: 16.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: gcov-profile
          Assignee: unassigned at gcc dot gnu.org
          Reporter: wentaoz5 at illinois dot edu
  Target Milestone: ---

Hit the issue when measuring
https://sources.debian.org/src/lzma/9.22-2.2/CPP/7zip/Compress/LzmaDecoder.cpp/#L101
where RINOK is defined as:

#define RINOK(x)                                                          \
  {                                                                       \
    int __result__ = (x);                                                 \
    if (__result__ != 0)                                                  \
      return __result__;                                                  \
  }

The direct output from gcov is:

 -:  96: for (;;)
 -:  97: {
 6:  98:   if (_inPos == _inSize)
 -:  99:   {
 6: 100:     _inPos = _inSize = 0;
9*: 101:     RINOK(inStream->Read(_inBuf, _inBufSizeAllocated, &_inSize));
 -: 102:   }

A reduced reproducing step is given as follow:

$ gcc --version
gcc (GCC) 16.0.0 20250511 (experimental)
Copyright (C) 2025 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 > src1.cc << 'EOF'
int g;

extern "C" {
    int foo(int *x);
}

int never;

void bar() {
    int j = 0;
    while (1)
    {
        g++;
        if (never) {
            g++;
            return;
        }

        int l; // has to be local and in this scope
        foo(&l);

        j++;
        if (j == 11)
            return;
    }
}

int main() {
    for (int i = 0; i < 7; i++)
        bar();
    return 0;
}
EOF

$ cat > src2.c << 'EOF'
int foo(int *x) {
    return 0;
}
EOF

$ rm -f *.gcov *.gcda *.gcno
$ g++ -c --coverage src1.cc
$ gcc -c --coverage src2.c
$ g++ --coverage  src1.o src2.o -o prog
$ ./prog
$ gcov src1
$ cat src1.cc.gcov
        -:    0:Source:src1.cc
        -:    0:Graph:src1.gcno
        -:    0:Data:src1.gcda
        -:    0:Runs:1
        -:    1:int g;
        -:    2:
        -:    3:extern "C" {
        -:    4:    int foo(int *x);
        -:    5:}
        -:    6:
        -:    7:int never;
        -:    8:
        7:    9:void bar() {
        7:   10:    int j = 0;
        -:   11:    while (1)
        -:   12:    {
       77:   13:        g++;
       77:   14:        if (never) {
    #####:   15:            g++;
       7*:   16:            return;
        -:   17:        }
        -:   18:
        -:   19:        int l; // has to be local and in this scope
       77:   20:        foo(&l);
        -:   21:
       77:   22:        j++;
       77:   23:        if (j == 11)
        7:   24:            return;
       70:   25:    }
        -:   26:}
        -:   27:
        1:   28:int main() {
        8:   29:    for (int i = 0; i < 7; i++)
        7:   30:        bar();
        1:   31:    return 0;
        -:   32:}

where line coverage for line 16 is reported to be a nonzero value.

Tweaking the code format can produce what's closer to the original symptom
I experienced in lzma (although the first format seems more concerning):

        -:   12:    {
       77:   13:        g++;
      84*:   14:        if (never) { g++; return; }
        -:   15:

Reply via email to