C++ can’t get that static analyser from Microsoft soon enough

One of the main announcements at CppCon 2015 was a tool being developed by Microsoft that will help catch bugs at “compile-time”, the idea being that backwards compatibility won’t be touched but we get help from a tool that understands the code. It can’t come soon enough.

I just started writing C++ again after quite a bit of a hiatus and pretty much immediately suffered from bullet-in-the-foot syndrome. In retrospect (as always) I was doing something stupid but the fact is my bug wouldn’t have happened in a garbage collected language or, I guess, Rust. C++ was more than happy to compile, run, and crash. I wrote something like this (not production code, it was a mock implementation so I could more easily test):

struct Outer;
struct Inner { Outer& outer; };
struct Outer {
    Outer():_inner{&this} {}
    //...
    Inner _inner;
};
void func(const Outer& outer);
int main() {
    Outer outer;
    setThings(outer);
    func(outer);
}

All that was fine. But the setup I needed to do on the outer struct kept growing, a weekend came in between, and I even completely forgot I had a reference to Outer in there (the commented-out ellipsis was 10-20 lines of code). I thought it’d be much better if instead I returned one of these objects from a function, by value, and pass it to func:

Outer createOuter() {
    Outer outer;
    //several lines of setup on outer
    return outer;
}
int main() {
    func(createOuter); //moves happen in here
}

Oh look, it crashed. Not only that, but I’d forgotten to use std::move several times along the way. Once that was fixed, the program was still crashing, but (of course) in a different way. A better way, mind, it was dereferencing an null pointer. But crashing anyway.

If you haven’t seen the stupid mistake I made by now, I’ll tell you what took me 30min-1h to find out: the compiler-generated move constructor (the copy constructor was similarly flawed) copied the Outer pointer from the moved-to object and set the new inner to point to an object that was about to be destroyed… the solution is to write a boilerplate-heavy move contructor to make the new inner point to the new outer. Fun! The reason it worked before is that the object I was passing in was still alive and would continue to stay that way until far after func had returned.

When Microsoft’s tool comes out, I really want to try it on the code above and see what happens. Sure, it worked fine for std::unique_ptr in the demo, but let’s see what happens in real life. In the meanwhile, I wish I was writing in another language.

Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: