For most of my C++ projects, I strongly rely on static analysis to prevent bugprone code getting into the master branch.
However, nothing seems to detect bugs caused by unspecified order of evaluation. While some tools may spot suspicious code like foo(++i, --i)
, none of them seem to detect the problem here:
std::map<int, int> m;
int i = 0;
m[++i] = --i;
Here is the list of analyzers I've tried:
- cppcheck
- clang diagnostics (-Wunsequenced)
- clang-tidy (haven't found anything while searching the list of diagnostics for words "sequence", "order", "evaluation")
- PVS‑Studio
EDIT: as pointed out in the comments, the problem in the snippet above is detected by clang -std=c++14 -Wunsequenced
. Here is a less trivial example that closely resembles a bug I've recently discovered in my project, and no warnings is given:
#include <unordered_map>
#include <cassert>
#include <memory>
#include <iostream>
struct Object {
};
struct Wrapper {
std::unique_ptr<Object> object;
std::string description;
};
class ObjectRegistry {
public:
void add_object(Wrapper& w) {
objects_[w.object.get()] = Wrapper{std::move(w.object), "added from " + w.description};
// this assertion may or may not fail depending on the order of evaluation in the line above, which is unspecified
assert(objects_.begin()->first != nullptr);
}
private:
// In our application, we need to quickly access the wrapper by raw pointer of its object
std::unordered_map<Object*, Wrapper> objects_;
};
int main(int argc, char *argv[]) {
ObjectRegistry registry;
Wrapper w{std::make_unique<Object>(), "first object"};
registry.add_object(w);
return 0;
}
Is there any fundamental problem why this can't be detected with static analysis? If not, does there exist a tool that's able to detect it?