Previously, the checker only tracked one raw pointer symbol for each container object.
But member functions returning a pointer to the object's inner buffer may be called on the object several times.
These pointer symbols are now collected in a set inside the program state map and thus all of them is checked for use-after-free problems.
Details
- Reviewers
NoQ xazax.hun george.karpenkov - Commits
- rG5f70d9b9582e: [analyzer] Track multiple raw pointer symbols in DanglingInternalBufferChecker.
rL336835: [analyzer] Track multiple raw pointer symbols in DanglingInternalBufferChecker.
rC336835: [analyzer] Track multiple raw pointer symbols in DanglingInternalBufferChecker.
Diff Detail
Event Timeline
Overall looks good, some nits inline. Let's run it on some projects to exercise this change.
lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp | ||
---|---|---|
27 | I think we should use using now instead of typedef. | |
126 | Is it possible here the set to be empty? We just added a new element to it above. Maybe turn this into an assert or just omit this if it is impossible? | |
138 | Using both contains and get will result in two lookups. Maybe it would be better to just use get and check if the result is nullptr? | |
159 | Same comment as above. | |
test/Analysis/dangling-internal-buffer.cpp | ||
111 | We started to use lowercase letters for variable names. Maybe this is not the best, since it is not following the LLVM coding guidelines. So I think it would be better to rename this Cond to start with a lowercase letter in this patch for consistency, and update the tests to follow the LLVM coding styleguide in a separate patch later. |
Addressed comments.
lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp | ||
---|---|---|
126 | I'm not sure whether add() can fail. I turned it into an assert now and will see if it ever fails. |
Thanks! The changes look good, I forgot to mark one double lookup though in my previous review.
lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp | ||
---|---|---|
120 | Oh, there is also a double lookup here, sorry I did not spot it in the initial review. |
lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp | ||
---|---|---|
120 | Thanks for noticing. I should have seen it in the first place :) |
Much symbols!
lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp | ||
---|---|---|
32–40 | Please add a comment on how this template is useful. This trick is used by some checkers, but it's a veeeery unobvious trick. We should probably add a macro for that, i.e. REGISTER_FACTORY_WITH_PROGRAMSTATE or something like that. | |
113 | Maybe turn the FIXME into a NOTE or something like that. It indeed seems fine, but let's still make sure the reader realizes that there's a subtle potential problem here. | |
115 | I'd much rather unwrap the symbol here, i.e. if (SymbolRef Sym = RawPtr.getAsSymbol()). A lot of other cornercases may occur if the implementation is accidentally inlined (Undefined, concrete regions). Also, speculatively, .getAsSymbol(/* search for symbolic base = */ true) for the same reason*. If we didn't care about inlined implementations, the Unknown check would have been redundant. So it should also be safe to straightforwardly ignore inlined implementations by consulting C.wasInlined, then the presence of the symbol can be asserted. But i'd rather speculatively care about inlined implementations as long as it seems easy. __ | |
118 | My favorite idiom for such cases, looks a bit cleaner: const PtrSet *SetPtr = State->get<RawPtrMap>(ObjRegion) PtrSet Set = SetPtr ? *SetPtr : F.getEmptySet() | |
121 | This contains check is very unlikely to yield true because if the implementation is not inlined, the symbol is newly born. I'd much rather skip the check; it doesn't sound like it'd make things any faster. Even better, let's assert that: assert(C.wasInlined || !Set.contains(Sym)). It'll probably help us catch some "reincarnated symbol" bugs in the core. | |
126 | It totally can't. We're just adding an object to a set. What could possibly go wrong? |
I think we should use using now instead of typedef.