memcpy() comparison: C, Rust, and D

Richard Delorme via Digitalmars-d digitalmars-d at puremagic.com
Wed Feb 1 12:38:30 PST 2017


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.



More information about the Digitalmars-d mailing list