memcpy() comparison: C, Rust, and D

Richard Delorme via Digitalmars-d digitalmars-d at puremagic.com
Tue Jan 31 15:00:21 PST 2017


On Tuesday, 31 January 2017 at 19:20:40 UTC, Walter Bright wrote:
> On 1/31/2017 5:50 AM, Richard Delorme wrote:
>> Well, I would not have taken memcpy as an example in favor of 
>> D. Good C
>> compilers (like gcc) know what memcpy does and are able to 
>> optimize it according
>> to its arguments. DMD may know better about memcpy through its 
>> declaration but
>> does not make any use about it.
>
> That may be true, but is not my point. The compiler cannot have 
> built in knowledge of every function. I just used memcpy() as 
> an example because it is extremely well known.
>
> As for making use of the type signature information, DMD uses 
> it to check the memory safety of arguments supplied to 
> memcpy(), something gcc does not do.

May we have an example of how the memory safety of arguments 
supplied to memcpy is checked in a way gcc cannot do?

I was thinking of the return attribute, that prevents for example 
to return the address of a local variable through a call to 
memcpy:

module dmemcpy;

import std.stdio;

extern (C) @system nothrow @nogc
pure void* memcpy(return void* s1, const scope void *s2, size_t 
n);

void *copy(const scope void *c, size_t n) {
	byte [16] d;
	return memcpy(&d[0], c, n);
}	

void main() {
	byte [16] a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 
15];
	byte *b = cast (byte*) copy(&a[0], 8);

	foreach (i; 0..16) write(b[i], ", ");
	writeln();
}
// ------- end ----------
$ dmd dmemcpy2.d
dmemcpy2.d(9): Error: escaping reference to local variable d

without the return attribute in memcpy declaration, dmd does not 
issue this error message.

The equivalent program in C:

#include <string.h>
#include <stdio.h>

void *copy(const void *c, size_t n) {
	char d[16];
	return memcpy(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');
}
// --- end of program ----
Compiling with gcc:
$ gcc memcpy2.c -O2 -W
memcpy2.c: In function 'copy':
memcpy2.c:6:9: warning: function returns address of local 
variable [-Wreturn-local-addr]
   return memcpy(d, c, n);
          ^~~~~~~~~~~~~~~
memcpy2.c:5:7: note: declared here
   char d[16];

Or with clang:
$ clang memcpy2.c --analyze
memcpy2.c:6:2: warning: Address of stack memory associated with 
local variable 'd' returned to caller
         return memcpy(d, c, n);
         ^~~~~~~~~~~~~~~~~~~~~~

So, even without a return attribute, good C compilers like gcc or 
clang are able to emit a warning message.

I am not really convinced by the necessity of attributes to 
enhance memory safety. I think the compiler should be able to 
check for safety without the user to ask it. Having to write 
attributes is a burden put on the user of the compiler. What if I 
forget to write an attribute? I just mistakenly make my program 
unsafe :-( Having a compiler checking for potential errors 
without me asking for is much safer in my humble opinion.

--
Richard Delorme



More information about the Digitalmars-d mailing list