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