This patch adds a checker checking std::string operations.
At first, it only checks the std::string single const char * constructor for nullness.
If It might be null, it will constrain it to non-null and place a note tag there.
Details
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
clang/lib/StaticAnalyzer/Checkers/StringChecker.cpp | ||
---|---|---|
38–40 | Constructors have identifiers. They totally work in other checkers. You still need to check for the right overload manually but in general they should work. If you want caching, it probably makes sense to implement it inside CallDescription so that other checkers could take advantage of it as well. | |
84–89 | You can drop the SValBuilder shenanigans and assume on the original value because if (x != nullptr) is entirely equivalent to if (x). | |
96 | I'm not sure this note is necessary. Null dereference checker doesn't make this note. You also made it non-prunable which will cause any nested stack frame that has such note to be brought into the report (never pruned) which may result in hundreds of uninteresting path notes per report. Such note could be useful in case the pointer value is "interesting", eg. it's tracked because it's used in the condition later down the path. If this is the aim, you should check for this explicitly and only then add a note. In this case a similar note can be added to other null dereference related checkers. | |
104 | The modern-day tradition is to keep these as members and initialize inline: class StringChecker { BugType BT_NullCStringParam { this, "...", "..." }; ... }; | |
106 | This is basically a null dereference bug. Let's use the same bug category, probably "logic error". | |
clang/test/Analysis/Inputs/system-header-simulator-cxx.h | ||
567 | I think this is supposed to be a template parameter. It probably doesn't matter but the closer we have our tests to the real-world situation the better. |
Generally I think this is a great start! We might indeed be able to enable it by default from the start. What further plans do you have for this checker?
clang/lib/StaticAnalyzer/Checkers/StringChecker.cpp | ||
---|---|---|
110 | Another great thing to do here is trackExpressionValue(Call.getArgExpr(0)). This would basically take care of all the notes. |
Thanks for the review @NoQ!
clang/lib/StaticAnalyzer/Checkers/StringChecker.cpp | ||
---|---|---|
38–40 | Okay, I'm gonna investigate this more thoroughly. I'm not exactly sure why did I choose to do it this way, but at first, I tried using CallDescriptions for sure. Let me come back to this. About the caching, that is an orthogonal feature, so even if I implement it in the map, it will be done in a follow-up revision. | |
84–89 | Oh yeah! | |
96 |
Yeah, I tried to highlight exactly the same in the comment of the next line. I'm gonna check for interestingness in the next update. | |
104 | Thanks. | |
106 | You are right. | |
110 | Oh sure, I'm not even sure why I stuck with the markinteresting() here. It's simply a mistake. | |
clang/test/Analysis/Inputs/system-header-simulator-cxx.h | ||
567 | I did not want to introduce the std::allocator<> stuff, hence chose this private class instead. I already had to make tradeoffs. I had to drop constexpr and noexcept and the last deleted overload as well since this header is included in older standard version tests. | |
clang/test/Analysis/std-string.cpp | ||
14–23 | To be fair, even if the checker would accidentally select a wrong overload, it would still not emit diagnostic. |
Right now I don't plan to add more to this checker.
clang/lib/StaticAnalyzer/Checkers/StringChecker.cpp | ||
---|---|---|
38–40 | In general, the CallDescription cannot cache the resolved decl, since that would require to match for the given overload. But we can only match for a qualified name and some parameter counts. Matching for the types of operands is generally done at a subsequent step. The extension adding support for matching constructors is in D111535. | |
104 | Wait, I thought we do this to lazily initialize the BugType to prevent unnecessary allocations. |
I like this very much, nice work!
clang/lib/StaticAnalyzer/Checkers/StringChecker.cpp | ||
---|---|---|
49–64 | Argh, I wish CallDescription was able to handle signatures! (StdLibraryFunctionsChecker would receive a big refactor then). | |
69 | Having an early return on if (!isCharToStringCtor(....) could reduce the nesting below. | |
71–72 | How could this happen? Do you have a test case for that? | |
clang/test/Analysis/std-string.cpp | ||
48–55 | Ahhh, this is great! |
I think I addressed all comments I wanted.
I think it's pretty solid, and I want to move forward with this one.
@martong
Constructors have identifiers. They totally work in other checkers. You still need to check for the right overload manually but in general they should work.
If you want caching, it probably makes sense to implement it inside CallDescription so that other checkers could take advantage of it as well.