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

            Bug ID: 116449
           Summary: Miscompilation with UBSAN
           Product: gcc
           Version: 15.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: sanitizer
          Assignee: unassigned at gcc dot gnu.org
          Reporter: sirl at gcc dot gnu.org
                CC: dodji at gcc dot gnu.org, dvyukov at gcc dot gnu.org,
                    jakub at gcc dot gnu.org, kcc at gcc dot gnu.org
  Target Milestone: ---

Hi,

compiling this example with 

  g++-trunk -c -fsanitize=undefined test.cpp -O2 -W -Wall

class C
{
public:
        void P(int);
        void IP();
        int parr[16];
};

typedef void (C::*fp)();

typedef struct arr_t
{
         fp func;
} arr_t;

static arr_t farr[1] =
{
        { &C::IP },
};

void C::P(int c)
{
        ((*this).*farr[parr[c]].func)();
}

results in this warning

test.cpp: In member function 'void C::P(int)':
test.cpp:23:31: warning: '<anonymous>' may be used uninitialized
[-Wmaybe-uninitialized]
   23 |         ((*this).*farr[parr[c]].func)();
      |                   ~~~~~~~~~~~~^

But the real problem is miscompilation that starts already in the gimple dump:

void C::P (struct C * const this, int c)
{
  void C::<T40d> (struct C *) * iftmp.0;
  int D.3291;
  int D.3294;
  struct C * D.3296;

  D.3291 = this->parr[c];
  .UBSAN_BOUNDS (0B, D.3291, 1);
  _1 = farr[D.3291].func.__pfn;
  _2 = (long int) _1;
  _3 = _2 & 1;
  if (_3 == 0) goto <D.3292>; else goto <D.3293>;
  <D.3292>:
  D.3294 = this->parr[c];
  .UBSAN_BOUNDS (0B, D.3294, 1);
  iftmp.0 = farr[D.3294].func.__pfn;
  goto <D.3295>;
  <D.3293>:
  .UBSAN_BOUNDS (0B, D.3294, 1);
  _4 = farr[D.3294].func.__delta;
  _5 = (sizetype) _4;
  _6 = this + _5;
  _7 = MEM[(int (*) () * *)_6];
  .UBSAN_BOUNDS (0B, D.3294, 1);
  _8 = farr[D.3294].func.__pfn;
  _9 = (long int) _8;
  _10 = _9 - 1;
  _11 = (sizetype) _10;
  _12 = _7 + _11;
  iftmp.0 = *_12;
  <D.3295>:
  iftmp.1_13 = iftmp.0;
  .UBSAN_BOUNDS (0B, D.3294, 1);
  _14 = farr[D.3294].func.__delta;
  _15 = (sizetype) _14;
  D.3296 = this + _15;
  .UBSAN_NULL (D.3296, 4B, 4);
  iftmp.1_13 (D.3296);
}

As you can see ".UBSAN_BOUNDS (0B, D.3294, 1)" check is repeated multiple
times, but in the <D.3293> branch D.3294 is not initialized at all.
This causes wrong out-of-bounds reports and eventually even application crashes
(seen in the original testcase).
Tested with trunk@r15-3043, but it seems all versions since at least GCC-10 are
affected.

Reply via email to