April 01, 2020
On 4/1/2020 12:03 PM, Johan wrote:
> I meant static analysis.

I'm not familiar specifically with clang's static analysis, but my experience with such is they detect a few obvious patterns, and miss the subtle ones that cause all the trouble. For example,

    int* foo(int i) { return &i; }

gets detected by static analysis. This one does not:

    int* bar(int* p) { return p; }

    int* foo(int i) { return bar(&i); }

The idea with D is to solve it in the general case, not by matching specific patterns. #Dip1000 is how D solves the second case in general.
April 02, 2020
On Wednesday, 1 April 2020 at 21:44:27 UTC, Walter Bright wrote:

>     int* foo(int i) { return &i; }

This is detected by Clang without running the static analyzer:

$ clang main.c
main.c:1:27: warning: address of stack memory associated with parameter 'i' returned [-Wreturn-stack-address]
int* foo(int i) { return &i; }
                          ^
1 warning generated.

> gets detected by static analysis. This one does not:
>
>     int* bar(int* p) { return p; }
>
>     int* foo(int i) { return bar(&i); }

The Clang static analyzer detects this:

$ clang --analyze main.c
main.c:2:19: warning: Address of stack memory associated with local variable 'i' returned to caller
int* foo(int i) { return bar(&i); }
         ~~~~~    ^~~~~~~~~~~~~~
1 warning generated.

--
/Jacob Carlborg





April 02, 2020
On Thursday, 2 April 2020 at 10:04:24 UTC, Jacob Carlborg wrote:
> On Wednesday, 1 April 2020 at 21:44:27 UTC, Walter Bright wrote:
>
>> gets detected by static analysis. This one does not:
>>
>>     int* bar(int* p) { return p; }
>>
>>     int* foo(int i) { return bar(&i); }
>
> The Clang static analyzer detects this:
>
> $ clang --analyze main.c
> main.c:2:19: warning: Address of stack memory associated with local variable 'i' returned to caller
> int* foo(int i) { return bar(&i); }
>          ~~~~~    ^~~~~~~~~~~~~~
> 1 warning generated.

Come on, of course such a super simple example is detected by clang's static analyzer. From my Inkscape days, I remember a case where the static analyzer found a bug with 80+ steps across multiple cpp files and complex control flow. I imagine Clang's analyzer is doing similar proofs that the D compiler is doing. My guess is that the problem is similar to the halting problem. And memory issues like this are just not provable (I think): https://github.com/dlang/dmd/pull/7050

Running the program with a sanitizer (memory, threads, UB, ...) appears easier to me in the many cases where this is possible. Nice to see you are advocating it Atila! :)

My only point was to question the newness of the news in OP and the statement that we need to "get on the bus". C++ has had powerful static analysis engines for a long time, and I don't think it changed the landscape. C++ has very nice runtime sanitizers, but again I don't think it is changing the landscape as much as one may have expected.

-Johan

April 02, 2020
On 4/2/2020 3:04 AM, Jacob Carlborg wrote:
> $ clang --analyze main.c
> main.c:2:19: warning: Address of stack memory associated with local variable 'i' returned to caller
> int* foo(int i) { return bar(&i); }
>           ~~~~~    ^~~~~~~~~~~~~~
> 1 warning generated.

Now try:

  int* bar(int* p);
  int* foo(int i) { return bar(&i); }

And then:

  struct S { int* p; };

  struct S foo(struct S* ps, int i)
  {
      ps->p = &i;
      return *ps;
  }

It falls apart. Now let's try D:

  struct S { int* p; }

  @safe S foo(S* ps, int i)
  {
      ps.p = &i; // Error: cannot take address of parameter i in @safe function foo
      return *ps;
  }

The point is to get them all, not a few simple patterns.
April 02, 2020
Some experimenting with clang shows it loses track of things when one level of indirection is added:

  struct S* malloc();
  void free(struct S*);

  void nut(struct S* s, int* pi) { free(s); *pi = 4; }

  void bolt()
  {
    struct S* s = malloc();
    struct S** ps = &s;     // <= add indirection
    nut(*ps, (*ps)->i);
  }

or when extern functions are used (i.e. function bodies are not available).

Other things clang doesn't detect:

  int* malloc();
  void free(int*);

  int nut();

  void bolt(int i)
  {
    int* p = malloc();
    *p = 1;
  }

Doesn't find the memory leak. Also, if you write your own storage allocator, clang doesn't pick it up.

clang actually does a nice job with what it has to work with - it's the C and C++ languages that are not amenable to doing it 100%.
1 2 3
Next ›   Last »