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.

Reply via email to