Especially with pointees, a lot of meaningless reports came from uninitialized regions that were already reported. This is fixed by storing all reported fields to the GDM.
Details
- Reviewers
NoQ george.karpenkov xazax.hun rnkovacs - Commits
- rG4ff776997461: [analyzer][UninitializedObjectChecker] Uninit regions are only reported once
rL347153: [analyzer][UninitializedObjectChecker] Uninit regions are only reported once
rC347153: [analyzer][UninitializedObjectChecker] Uninit regions are only reported once
Diff Detail
- Repository
- rC Clang
Event Timeline
Hmm, so we're reporting the same region twice in the same bug report through different field chains, right? Why is a state trait necessary here? Maybe just de-duplicate them locally before throwing the report?
Or, wait, hmm, no, we can still de-duplicate the reports with a global set stored in the checker object. Because we would probably like to de-duplicate across different paths as well.
I tried it, but it crashes randomly. I added a mutable std::set<const MemRegion *> to the checker class, used the same logic, but seems to me that you can't just erase elements like this. Is there any other checker doing the same thing?
Another possibility could be to gather CXXConstructorDecl, and emit one warning per ctor, but it would be waaay to drastic. Wouldn't a global set be too?
Ping, @NoQ, can you go a little bit more in depth about what you'd prefer to see here?
Ugh, i was sure i scanned through all of them, sorry! Pls let me recall what's going on><
As I understood it, your objection was that we could collect already reported regions in a global set stored in the checker objects, but I suspect it's impossible to implement (very difficult to see when a pointer is dangling etc).
MemRegions have lifetime of ExprEngine, i.e. a single analysis of top-level function. You'll need to clean them up in checkEndAnalysis().
I think RetainCountChecker is the only checker that maintains such maps and does such cleanup: https://github.com/llvm-mirror/clang/blob/efe41bf98/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h#L288
I didn't know it does that until today.
Sorry for the late reply.
I'm not actually super confident about this idea, I don't think it would add much value, compared to how complicated it would make things. This patch reduces report by a significant amount when pointer chasing is enabled, but a global set might not make things that much cleaner -- if the same report would be made on different execution paths, it would be uniqued with the help of the uniqueing location. If it it wouldn't be, I guess it shouldn't be.
Of course, I'm always open to a discussion!
Oh, and the reason why I think it would add a lot of complication: since only ExprEngine is avaible in the checkEndAnalysis callback, which, from what I can see, doesn't have a handly isDead method, so I'm not even sure how I'd implement it.
Mm, ok, i admit that i don't know what specific de-duplication do we want to have and what are the usability implications of it.
If we want de-duplication for the same region reported in different spots of the same path, we need a state trait.
If we want de-duplication for the same region globally across the whole analysis, we need a checker-wide set of regions, like what you're doing.
If we want de-duplication for the same region globally across the whole translation unit, we need a checker-wide set of AST nodes (eg., field chains) that describe regions in terms that outlive ExprEngine.
If we want de-duplication for different regions within the same constructor call site, we need a uniqueing location at the call site, like what you're doing.
If we want de-duplication for different regions within the same constructor itself, we don't need a uniqueing location.
I guess you should just do whatever you want here?
Mm, what do you need isDead for? Everything is dead at the end of the analysis, you need to clean up everything, otherwise you get use-after-free(?)
lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp | ||
---|---|---|
169 | Hmm, does LocUsedForUniqueing remain uninitialized sometimes? I guess it's on the top frame. What does it do in this case? Why do we need a uniqueing location in other cases? I guess it only *increases* the amount of reports, right? I.e., constructors called from different call sites produce different reports(?) |
Hmm, does LocUsedForUniqueing remain uninitialized sometimes? I guess it's on the top frame. What does it do in this case? Why do we need a uniqueing location in other cases? I guess it only *increases* the amount of reports, right? I.e., constructors called from different call sites produce different reports(?)