An interesting blog post found through Reddit:

http://randomascii.wordpress.com/2013/06/24/two-years-and-thousands-of-bugs-of-/

The post is about the heavy usage of static analysis on lot of C++ code. They have a Python script that shows new warnings only the first time they appear in the code base. This is a simple but very useful memory, to solve one of the most important downsides of warnings.

The article groups bugs in some different categories. Some of the D code below is derived from the article.

- - - - - - - - - - - - - - - - - -

Format strings:

The most common problem they find are errors in the format string of printf-like functions (despite the code is C++):

The top type of bug that /analyze finds is format string errors – mismatches between printf-style format strings and the corresponding arguments. Sometimes there is a missing argument, sometimes there is an extra argument, and sometimes the arguments don’t match, such as printing a float, long or ‘long long’ with %d.<

Such errors in D are less bad, because writef("%d",x) is usable for all kind of integral values. On the other hand this D program prints just "10" with no errors, ignoring the second x:

import std.stdio;
void main() {
    size_t x = 10;
    writefln("%d", x, x);
}

In a modern statically typed language I'd like such code to give a compile-time error.

This is how how Rust gets this right:

println(fmt!("hello, %d", j))

https://github.com/mozilla/rust/blob/master/src/libsyntax/ext/fmt.rs
https://github.com/Aatch/rust-fmt

In D it can be written a safe function that needs no extra static analysis:

ctWritefln!"%d"(x, x);

- - - - - - - - - - - - - - - - - -

Variable shadowing:

This is a much less common problem in D because this code gives a errors:

void main() {
    bool result = true;
    if (true) {
        bool result = false;
    }
    foreach (i; 0 .. 10) {
        foreach (i; 0 .. 20) {
        }
    }
    for (int i = 0; i < 10; i++) {
        for (int i = 0; i < 20; i++) {
        }
    }
}


test.d(4): Error: is shadowing declaration test.main.result
test.d(7): Error: is shadowing declaration test.main.i
test.d(11): Error: is shadowing declaration test.main.i


There are some situations where this doesn't help, but they are not common in idiomatic D code:

void main() {
    int i, j;
    for (i = 0; i < 10; i++) {
        for (i = 0; i < 20; i++) {
        }
    }
}


In D this is one case similar to variable shadowing, that the compiler doesn't help you with:

class Foo {
    int x, y, z, w;
    this(in int x_, in int y_, in int z_, in int w_) {
        this.x = x_;
        this.y = y_;
        this.z = z;
        this.w = w_;
    }
}
void main() {
    auto f = new Foo(1, 2, 3, 4);
}


I believe the compile should give some warning there:
http://d.puremagic.com/issues/show_bug.cgi?id=3878

- - - - - - - - - - - - - - - - - -

Logic bugs:


bool someFunction() { return true; }
uint getFlags() { return uint.max; }
void main() {
    uint kFlagValue = 2u ^^ 14;
    if (someFunction() || getFlags() | kFlagValue) {}
}


The D compiler gives no warnings. from the article:

The code above is an expensive and misleading way to go "if ( true )". Visual Studio gave a clear warning that described the problem well:

warning C6316: Incorrect operator: tested expression is constant and non-zero. Use bitwise-and to determine whether bits are set.<


See:
http://msdn.microsoft.com/en-us/library/f921xb29.aspx

A simpler example:

enum INPUT_VALUE = 2;
void f(uint flags) {
    if (flags | INPUT_VALUE) {}
}


I have just added it to Bugzilla:
http://d.puremagic.com/issues/show_bug.cgi?id=10480



Another problem:

void main() {
    bool bOnFire = true;
    float angle = 20.0f + bOnFire ? 5.0f : 10.0f;
}


D compiler gives no warnings.

Visual Studio gave:

warning C6336: Arithmetic operator has precedence over question operator, use parentheses to clarify intent.
warning C6323: Use of arithmetic operator on Boolean type(s).<


See:
http://msdn.microsoft.com/en-us/library/ms182085.aspx

I opened an ER lot of time ago, "Require parenthesization of ternary operator when compounded":
http://d.puremagic.com/issues/show_bug.cgi?id=8757

- - - - - - - - - - - - - - - - - -

Signed, unsigned, and tautologies:

Currently this gives no warnings:


This code would have been fine if both a and b were signed – but one of them wasn’t, making this operation nonsensical.<


import std.algorithm: max;
void main() {
    int a = -10;
    uint b = 5;
    auto result = max(0, a - b);
}



We had quite a few places where we were checking to see if unsigned variables were less than zero -- now we have fewer.<

This is a well known problem, it's an issue in Bugzilla since lot of time, and it seems there is no simple way to face it in D.

Bye,
bearophile

Reply via email to