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

Reply via email to