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

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

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Keywords|                            |diagnostic
             Status|UNCONFIRMED                 |RESOLVED
         Resolution|---                         |WONTFIX

--- Comment #1 from Martin Sebor <msebor at gcc dot gnu.org> ---
A common mistake with strncat is to specify as the bound the source of the
source string (instead of the remaining space in the destination), as in:

  char d[8] = "1234";
  const char *s = "4567";

  strncat (d, s, strlen (s));

where the strncat call overflows the destination.

Something similar happens in the test case in comment #0, except there the
amount of space in the destination isn't as obvious.  The checker tries to
compute the size of the destination to see if the call can overflow but that
computation fails (it happens too early, before the size is available).  So out
of an abundance of caution, the checker points out that the bound equals the
source length, before the strncat call is folded into memcpy.  Unfortunately,
there is no way to avoid the warning without either compromising its efficacy
(i.e., causing false negatives for buggy code), or without delaying the folding
into memcpy to a point where the destination size is available (delaying the
folding is not a favorable solution).

That being said, the intended and recommended practice is to call strncat with
the amount of space remaining in the destination, e.g., like so:

  strncat (d, s, sizeof d - strlen (d) - 1);

In the test case in comment #0, strncat is being used to do two things: either
a) to append the initial portion of the string at cur without the terminating
nul and b) as a shortcut to to append the full nul-terminated string string
cur.  (a) is the intended use case, but (b) is not.  With that in mind,
changing the code to separate the two use cases like so avoids the warning:

  if (next)
    strncat (plugin_name, cur, next - cur);
  else
    strcpy (plugin_name, cur);

Another alternative is to use sprintf to combine all three calls into one:

  sprintf (plugin_name, "%s%.*s%s", prefix,
           next ? (int)(next - cur) : -1, cur,
           suffix);

I would suggest either of these also makes the code clearer.

Reply via email to