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

Martin Sebor <msebor at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|UNCONFIRMED                 |ASSIGNED
   Last reconfirmed|                            |2017-01-17
           Assignee|unassigned at gcc dot gnu.org      |msebor at gcc dot 
gnu.org
     Ever confirmed|0                           |1

--- Comment #2 from Martin Sebor <msebor at gcc dot gnu.org> ---
The warning is reproducible with the test case below.  The memset call is
inserted by the loop distribution pass.  The pass should avoid inserting
memcpy/memmove/memset calls with excessively large arguments (> SIZE_MAX / 2)
because they are certainly incorrect and, if executed, will lead to buffer
overflow and memory corruption.  I'm testing a patch that inserts a trap
instead.

FWIW, the warning is working as I hoped it would: it's helping find bugs.  In
this case, the problem is exposed by the loop to memset transformation.  The
warning isn't necessarily useful to the user because the code is inserted by
GCC itself but it has exposed an opportunity to both make the generated code
safer (avoid the memory corruption) and more efficient (it can help GCC
generate code based on the assumption that the overflow is unlikely to happen).

$ cat t.ii && gcc -O3 -S -Wall -Wextra -Wpedantic -xc++
-fdump-tree-optimized=/dev/stdout t.ii 
typedef long unsigned int size_t;

inline void
fill (int *p, size_t n, int)
{
  while (n--)
    *p++ = 0;
}

struct B
{
  int* p0, *p1, *p2;

  size_t size () const {
    return size_t (p1 - p0);
  }

  void resize (size_t n) {
    if (n > size())
      append (n - size());
  }

  void append (size_t n)
  {
    if (size_t (p2 - p1) >= n)   {
      fill (p1, n, 0);
    }
  }
};

void foo (B &b)
{
  b.resize (b.size () - 1);
}

;; Function void foo(B&) (_Z3fooR1B, funcdef_no=4, decl_uid=2299, cgraph_uid=4,
symbol_order=4)

Removing basic block 6
Removing basic block 7
void foo(B&) (struct B & b)
{
  int * _4;
  int * _5;
  int * _6;
  long int _7;
  long int _8;
  long int _13;
  long int _14;

  <bb 2> [4.91%]:
  _4 = MEM[(int * *)b_3(D)];
  _5 = MEM[(int * *)b_3(D) + 8B];
  _13 = (long int) _5;
  _14 = (long int) _4;
  if (_13 == _14)
    goto <bb 3>; [54.00%]
  else
    goto <bb 5>; [46.00%]

  <bb 3> [2.65%]:
  _6 = MEM[(int * *)b_3(D) + 16B];
  _7 = (long int) _6;
  _8 = _7 - _13;
  if (_8 == -4)
    goto <bb 4>; [37.68%]
  else
    goto <bb 5>; [62.32%]

  <bb 4> [1.00%]:
  __builtin_memset (_5, 0, 18446744073709551612); [tail call]

  <bb 5> [4.91%]:
  return;

}


In function ‘void foo(B&)’:
cc1plus: warning: ‘void* __builtin_memset(void*, int, long unsigned int)’:
specified size 18446744073709551612 exceeds maximum object size
9223372036854775807 -Wstringop-overflow=]

Reply via email to