This patch handles unevaluated contexts to ensure no warnings are produced by the machinery for buffer access made within an unevaluated contexts. However, such accesses must be considered by a FixableGadget and produce the necessary fixits.
Details
Diff Detail
Event Timeline
clang/lib/Analysis/UnsafeBufferUsage.cpp | ||
---|---|---|
84–85 | We should still visit other subexpressions when ignoreUnevaluatedContext is false. |
Addressing the comment on _Generic handling and fixing the machinery to correctly track all DREs.
clang/lib/Analysis/UnsafeBufferUsage.cpp | ||
---|---|---|
84–85 | Fixed! |
Aha, looks correct now!
We probably want some more tests to demonstrate that even though warnings aren't emitted against evaluated code, fixits still are.
clang/lib/Analysis/UnsafeBufferUsage.cpp | ||
---|---|---|
48 | Looks like some of these spaces are tabs. |
@NoQ I don't want to be annoying but I think you meant "warnings aren't emitted against UNEVALUATED code", is that right?
clang/test/SemaCXX/warn-unsafe-buffer-usage.cpp | ||
---|---|---|
113 | Do we think splitting this off as a separate test would help make the tests better? |
clang/lib/Analysis/UnsafeBufferUsage.cpp | ||
---|---|---|
1010 | I like this idea: skipping unevaluated-contexts from the very beginning! A nitpick to this change is that now we traverse the function body twice (one for fixables and one for warnings). But I suspect if the overhead (if there is any) is ever gonna be visible. | |
clang/test/SemaCXX/warn-unsafe-buffer-usage.cpp | ||
113 | I agree. Other than these, this patch LGTM so I'm going to accept it. |
clang/lib/Analysis/UnsafeBufferUsage.cpp | ||
---|---|---|
1002 | Just realized that any_dre and PointerReferenceGadget can match the same node. |
clang/lib/Analysis/UnsafeBufferUsage.cpp | ||
---|---|---|
1002 | Hmm but wouldn't PointerReferenceGadget include a UPC or something? | |
1010 | Warning gadgets can be found at arbitrary depths inside unevaluated contexts, so you can't simply whitelist a few patterns, you need to communicate with the traversal methods to properly ignore them. So another approach to this problem would be to maintain a count of reasons why current context is unevaluated in the visitor, and have the visitor accept two sub-matchers: one is invoked every time, the other is invoked only when the count is zero. That's very ugly but we can try that if we find it useful for performance. I also like the current approach because it maps nicely to what kinds of traversal matchers I'd like to have in clang-tidy. Namely, forEveryDescendantEvaluatedStmt() is what people actually want 90% of the time when they write forEachDescendant() and then hopefully deal with unintended consequences manually. (We still want to move these matchers to ASTMatchers.h right???) |
clang/lib/Analysis/UnsafeBufferUsage.cpp | ||
---|---|---|
176–188 | While we're at it, maybe let's return to clang's existing naming convention now that the Stmt suffix makes it unambiguous? |
clang/lib/Analysis/UnsafeBufferUsage.cpp | ||
---|---|---|
1002 | you are right, though I did encounter such a bug once. But I failed to reproduce it now. Let's not worry about this issue until it appears again. |
clang/lib/Analysis/UnsafeBufferUsage.cpp | ||
---|---|---|
1002 | I have a reproducer now. Then I realized that it is not that any_dre and PointerReferenceGadget can race in anyOf. It is in fact FixableGadgets race in anyOf. |
clang/lib/Analysis/UnsafeBufferUsage.cpp | ||
---|---|---|
1002 | @ziqingluo-90: Can you please add a link to the bug description? |
clang/lib/Analysis/UnsafeBufferUsage.cpp | ||
---|---|---|
1002 | An example of two FixableGadgets race in anyOf is at a call statement foo(++p, p) where p is a raw pointer. The two FixableGadgets represent a pre-increment and a standalone pointer, respectively, in context of an unsafe call. The matcher representing the context is callExpr(forEachArgumentWithParam(.... The match succeeds as long as there is at least one parameter matches the sub-matcher (i.e., pre-increment or standalone pointer). Therefore, both Gadgets match the same call statement. A quick fix is to change anyOf to eachOf but maybe there are more efficient solutions. |
clang/lib/Analysis/UnsafeBufferUsage.cpp | ||
---|---|---|
1002 | If I recall correctly, we discussed changing this from anyOf to eachOf offline and were concerned about potential clashes among the fixits. So, it was decided to leave it alone for now and handle this as a separate patch. But you are right, this can be a real pain point for us and we need to address this soonish. For your example, this may prevent us from generating any fixits as at least one of the of the DREs will never get claimed. |
Code looks great now, and wow that's a lot of tests!
clang/lib/Analysis/UnsafeBufferUsage.cpp | ||
---|---|---|
1002 |
Can we already add such test case? Regardless of whether it passes, it can help us confirm that we're not doing something terrible (eg. crashing) in such cases. At a glance, switching to eachOf() could totally crash us, so I'd rather document the potential problem in the form of a test while it's hot. |
clang/lib/Analysis/UnsafeBufferUsage.cpp | ||
---|---|---|
1002 | So, it looks like this has already been changed to eachOf on the llvm main branch. Updating this to reflect the same. |
Looks like some of these spaces are tabs.