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

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

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|WAITING                     |RESOLVED
         Resolution|---                         |WONTFIX

--- Comment #4 from Martin Sebor <msebor at gcc dot gnu.org> ---
Thanks for the test case.  The warning is based on the IL below.  In basic
block 16 the result of operator new is assigned to _134, and in basic block 19
the code stores zero at an negative offset from _134.  So the warning is doing
its job here: the invalid statement exists in the emitted program, it just may
be unreachable and GCC can't prove that.

  <bb 16> [local count: 19040066]:
  _82 = len_49 - lastpos.2_4;
  length_83 = (int) _82;
  o ={v} {CLOBBER};
  _134 = operator new (1);       >>> _134
  goto <bb 18>; [100.00%]
  ...
  <bb 18> [local count: 19040066]:
  MEM[(char *)_134] = 0;
  _85 = length_83 + 1;
  _86 = (unsigned int) _85;
  if (_86 == 0)
    goto <bb 19>; [80.71%]
  else
    goto <bb 20>; [19.29%]

  <bb 19> [local count: 25513689]:
  MEM[(char *)_134 + -1B] = 0;   <<< -Wstringop-overflow
  goto <bb 26>; [100.00%]

The cause of the warning is in the subString() function where it can't prove
that the length argument won't become negative:

        string<T> subString(unsigned begin, int length) const
        {
                // if start after string
                // or no proper substring length
                if ((length <= 0) || (begin>=size()))
                        return string<T>{ "" };
                // clamp length to maximal value
                if ((length+begin) > size())
                        length = size()-begin;   <<< length not proven to
become -1

                string<T> o;
                o.reserve(length+1);

                for (int i=0; i<length; ++i)
                        o.array[i] = array[i+begin];

                o.array[length] = 0;             <<< store to o.array[-1]
emitted
                o.used = length + 1;

                return o;
        }

Adding the following just before the definition of the string o prevents the
warning.  Another alternative is to make both length and the loop control
variable unsigned (making variables that represent sizes unsigned and keeping
them that is a good practice since it communicates that constraint to the
compiler).

                if (length < 0)
                  __builtin_unreachable ();

In general, unless the compiler can prove that some expression won't reach a
value that's invalid in some context, it can substitute the value for it in the
process of optimizing surrounding code, which can then lead to the invalid code
materializing even if it's not actually in the original source and even if the
emitted invalid object code isn't reachable.  GCC warnings that are designed to
look for this invalid code then trigger on it.  Resolving these warnings can
often help GCC generate better object code (the __builtin_unreachable() trick
isn't necessarily always the best way; it's only appropriate if the
precondition is in the source and GCC loses track of it).  Long story short,
there is nothing for us to do to.

Reply via email to