Reinventing the Std::wheel

| Comments

This little story is about why reinventing the wheel is not only wasteful but could also be dangerous.

On one sunny day I inserted some pretty innocent std::map into a struct, added a couple of one-liners, made sure it does what’s supposed to, committed and pushed. In some minutes I hear a scream. The damn thing crashes on a Linux. Why? It’s dead simple, it surely worked for me, there just cannot be anything wrong with it, it must work. Right?

It just didn’t. After a quick look it was pretty clear — it’s a GCC bug. Perhaps the version is too recent and it has to be crawling with bugs. I started trying other versions but the problem wouldn’t go away. Well, it’s pretty clear now — it’s a GCC family bug! That would be a glorious discovery.

We sit down together and start to minimize the example, trying to reproduce it with fewer lines of code. We are trying this and that, replacing types with simpler ones, making all kinds of changes, renaming classes, moving them to different files, rearranging the lines, etc., etc. Other people come and join us, we are three, four, five and people keep coming. Everyone’s interested, everyone’s got a theory.

There are wild versions of how the mutable keyword or a const_cast can crash the whole thing without even being called. How one should not be using STL for anything since it’s a piece of crap and has never been stable. How C++ is a rotten language and nothing even remotely close to reliable or at least deterministic could be produced with it. Many, many ridiculous theories, just because any normal ones don’t make sense.

The time goes by. It’s already the second day. It’s going to be the third soon. A bunch of people are involved. The air is electrified. We are already down to just a few lines of code. It appears that the destructor of std::map is causing all the trouble. But it’s used everywhere else and everything has been ok so far. In this case though the map is part of the structure that is inserted into a homegrown version of std::vector that is used everywhere else and has been ok so far as well.

We start to get suspicious but nobody yet dives into blasphemy and tries to condemn CVector (let’s call it that way). After all it underpins the whole foundation, it’s used everywhere and has been for years. It’s definitely better and more reliable than std::vector; it’s faster and smarter and it’s written by the cool guys (though, not exactly compatible and sometimes needs duct tape and a bit of voodoo to work). But the line is crossed and we start to poke around the CVector code. And…

There it was. One big shiny memmove in the CVector’s resize function. It seems the person who wrote that class thought there was nothing dangerous in moving some memory from one place to another. We used to do that in C all the time. It’s just a bunch of dumb bytes after all. But C++ is no C and moving an object to another place without telling it (read assigning or copy-constructing) could break it. This what apparently was happening with std::map shipped with GCC.

The problem was fixed in a minute by replacing CVector with std::vector. One minute fix which took a few people many hours to identify and track down. All of which could be avoided in the first place if someone didn’t try to reinvent the wheel driven by the not invented here syndrome.