On Wednesday, 1 February 2017 at 10:20:45 UTC, Patrick Schluter
wrote:
On Wednesday, 1 February 2017 at 10:05:49 UTC, Richard Delorme
wrote:
//-----8<-------------------------------------------------------
#include <string.h>
#include <stdio.h>
void* mymemcpy(void* restrict dest, const void* restrict src,
size_t n) {
const char *s = src;
char *d = dest;
for (size_t i = 0; i < n; ++i) d[i] = s[i];
return d;
}
void *copy(const void *c, size_t n) {
char d[16];
return mymemcpy(d, c, n);
}
int main(void) {
char a[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
14, 15};
char *b = copy(a, 8);
for (int i = 0; i < 16; ++i) printf("%d ", b[i]);
putchar('\n');
}
//-----8<-------------------------------------------------------
$ gcc mymemcpy.c -O2 -W
mymemcpy.c: In function 'copy':
mymemcpy.c:13:9: warning: function returns address of local
variable [-Wreturn-local-addr]
return mymemcpy(d, c, n);
^~~~~~~~~~~~~~~~~
memcpy4.c:12:7: note: declared here
char d[16];
clang (version 3.8.1) failed to find error in this code.
You have to define the mymemcpy() in another source file and
only put the prototype in this module. If the compiler sees the
code it can do the complete data flow analyses. With only the
declaration it can't and that is Walter's point. The
annotations allow to give to the declaration the information
the compiler can not deduce itself from the code, because the
code is in another module (object file, library).
Right, if defined in another file, the compiler will not emit any
warning. However other tools can detect this kind of error. For
instance, valgrind works great in this example, directly on the
executable:
$ valgrind --track-origins=yes mymemcpy
[...]
==31041== Conditional jump or move depends on uninitialised
value(s)
==31041== at 0x4E843C7: vfprintf (in /usr/lib64/libc-2.23.so)
==31041== by 0x4E8B9A8: printf (in /usr/lib64/libc-2.23.so)
==31041== by 0x400682: main (main.c:15)
==31041== Uninitialised value was created by a stack allocation
==31041== at 0x400652: main (main.c:13)
[...]
Thus, I still have a mitigated feeling on attributes. In my
humble opinion, it is wrong to put on the programmer the
responsibility to make his program safer by stacking attributes
on function declarations. I prefer to ask the compiler to detect
as much defects as possible (but not more!), and to rely on
external tools like valgrind, gdb, etc. to detect more subtle
bugs.