On Thu, Jul 22, 2021 at 12:11:17PM +0200, Vincent Lefevre wrote: > I actually think that the compiler should warn in every case, > but isn't able to detect all potential issues. The strfcpy > definition seems wrong: > > # define strfcpy(A,B,C) strncpy (A,B,C), *(A+(C)-1)=0 > > If A and B are buffers of size C, the strncpy call will yield a > non-null terminated destination at this point, hence a potential > warning (see the gcc(1) man page). > > Note the *(A+(C)-1)=0. This means that A[(C)-1] will be set to 0. > Thus you want to fill A[0] to A[(C)-2], i.e. copy (C)-1 bytes. > So the definition should be > > # define strfcpy(A,B,C) strncpy (A,B,(C)-1), *((A)+(C)-1)=0 > > Now, this doesn't solve the warnings, and I suppose that there is > a bug in GCC.
After playing with gcc 10.2.1 I do think this warning is a bug in gcc. (I didn't read all of the related bug reports in gcc's Bugzilla.) The thing is that actually gcc knows the buffers A and B are the same size (possibly because it is inlining one or more function calls). This means that if B is a string then A cannot get truncated. If you remove the guard *(A+(C)-1)=0 from the macro definition then gcc does not emit a warning for this case because it knows that A is not being truncated. However, this guard causes gcc to optimize the macro to your suggested definition of it: that is, it modifies the strncpy call to copy at most C-1 bytes because it knows the Cth byte will be overwritten. Therefore, in the optimized strncpy call we are copying a string that might be up to 255 bytes long (not including the terminating nul) into a buffer of length 255 - which might cause the terminating nul to get lost, which makes gcc issue a warning. On systems that have memccpy, replacing the strncpy with memccpy is both more efficient and warning-free on this version of gcc. Recall that the definition of strncpy is not just "copy at most n bytes" but also "pad the destination to exactly n bytes". imc