C/C++: Detect ambiguous assignment of comparison results - #22336
C/C++: Detect ambiguous assignment of comparison results#22336theinfosecguy wants to merge 3 commits into
Conversation
ryao
left a comment
There was a problem hiding this comment.
While I am happy you did the work for me to get this into a PR and made what appear to be improvements, would you add an Original-patch-by: to the commit message to credit my prior work?
Also, have you run your variant against any major corpora (e.g. Linux, curl, OpenZFS) to verify the lack of FPs in production code, like I did with the original version? If it helps:
| not isExplicitlyGrouped(comparison) and | ||
| occursInCondition(assignment) and | ||
| // Assigning a comparison result to a Boolean is normally intentional. | ||
| not assignment.getLValue().getUnspecifiedType() instanceof BoolType and |
There was a problem hiding this comment.
While this is normally intentional, I believe not isExplicitlyGrouped(comparison) precludes this.
There was a problem hiding this comment.
Why is that? It seems like the types of the expressions and the bracketing are mostly independent concerns.
There was a problem hiding this comment.
My reasoning was that if it is a comparison operation, then it is implicitly bool. Maybe with C++ operator overloading, this might not be the case. I had only been imagining C when I made this remark.
geoffw0
left a comment
There was a problem hiding this comment.
I've reviewed the code and docs from a technical perspective (I haven't looked through all the test cases yet). This looks quite promising. I've also done a mass (MRVA) run and found quite a high rate of true positive results!
Original-patch-by: Richard Yao <richard@ryao.dev>
7784270 to
8f0ea61
Compare
|
QHelp previews: cpp/ql/src/Likely Bugs/Likely Typos/AmbiguousAssignmentOfComparison.qhelpAmbiguous assignment of comparison used as truth valueAssignment operators have lower precedence than comparison operators. For example, RecommendationUse parentheses to make the intended operation order explicit. To assign first and compare the assigned value, parenthesize the assignment. To intentionally assign the comparison result, parenthesize the comparison. An explicit cast around the comparison also makes that order clear. ExampleIn the first condition, int read_status();
int check_status() {
int status;
if (status = read_status() < 0) // BAD: assigns the comparison result.
return status;
if ((status = read_status()) < 0) // GOOD: assigns first, then compares.
return status;
return 0;
}
References
|
geoffw0
left a comment
There was a problem hiding this comment.
Nice thorough tests. I've nit-picked a couple of cases but they're not important ones, and you might have more insight into them than I have, from knowing the cases that motivated this query.
I've gained a lot of confidence in this query from reviewing it - just a few small things to discuss and decide if we want to make any changes or not. 👍
|
Thank you for making the changes. The CodeQL looks good to me, as do the tests and MRVA (bulk testing) results. I think I said it before, but I'm seeing lots of true positive results in real world data. :) I've requested a quick review of the |
|
👋 Hello from docs! Just confirming that I've added this to our review board for you to make sure it gets attention and a review soon. If you still need any assistance just reach out on Slack via the |
mchammer01
left a comment
There was a problem hiding this comment.
@theinfosecguy 👋🏻 - Hi from Technical Content (used to be Docs). Overall, this PR looks good, so I’m approving it ✨
I’ve left a few suggestions to make the query help, metadata, and change note easier to read. It would be great if some of these could be applied or tweaked before merging, but I don’t think they need to block the PR. Thanks for adding clear examples and references 🙏
| @@ -0,0 +1,72 @@ | |||
| /** | |||
| * @name Ambiguous assignment of comparison used as truth value | |||
There was a problem hiding this comment.
The query name is grammatically unclear, suggesting the following:
| * @name Ambiguous assignment of comparison used as truth value | |
| * @name Ambiguous assignment of comparison result used as truth value |
| * @description Assigning the result of an unparenthesized comparison when the assignment is used | ||
| * as a truth value may indicate that the assignment and comparison are grouped | ||
| * incorrectly. |
There was a problem hiding this comment.
The description is complex and doesn’t closely follow the preferred “Syntax X causes behavior Y” pattern.
Suggesting something like: (let me know what you think!)
| * @description Assigning the result of an unparenthesized comparison when the assignment is used | |
| * as a truth value may indicate that the assignment and comparison are grouped | |
| * incorrectly. | |
| * @description Assigning the result of an unparenthesized comparison when the assignment is used | |
| * as a truth value can obscure the intended grouping of the operations. |
| </overview> | ||
|
|
||
| <recommendation> | ||
| <p>Use parentheses to make the intended operation order explicit. To assign first and compare the |
There was a problem hiding this comment.
Nit: use more natural language:
| <p>Use parentheses to make the intended operation order explicit. To assign first and compare the | |
| <p>Use parentheses to make the intended order of operations explicit. To assign first and compare the |
|
|
||
| <example> | ||
| <p>In the first condition, <code>status</code> receives either zero or one instead of the value | ||
| returned by <code>read_status</code>. The second condition explicitly performs the assignment |
There was a problem hiding this comment.
Change read_status to read_status() when referring to the function call
| returned by <code>read_status</code>. The second condition explicitly performs the assignment | |
| returned by <code>read_status()</code>. The second condition explicitly performs the assignment |
| * Added a new query, `cpp/ambiguous-assignment-of-comparison`, to detect assignments of | ||
| unparenthesized comparison results when the assignment is used as a truth value. |
There was a problem hiding this comment.
Nit: Whilst this is technically accurate, the wording is dense. “Assignments of unparenthesized comparison results” takes a moment to parse. What about:
| * Added a new query, `cpp/ambiguous-assignment-of-comparison`, to detect assignments of | |
| unparenthesized comparison results when the assignment is used as a truth value. | |
| * Added a new query, `cpp/ambiguous-assignment-of-comparison`, to detect potentially | |
| ambiguous expressions where a comparison result is assigned to a variable and the | |
| assignment is used as a truth value. |
Adds
cpp/ambiguous-assignment-of-comparisonto flag ambiguous assignments when the assignment result is used as a truth value, such as:The query distinguishes this from explicitly grouped assign-then-compare and compare-then-assign expressions. It includes C and C++ tests, query help, and query-suite integration.
Local targeted and neighboring tests pass. The motivating regression is detected, and a run against
git/gitproduced no alerts.Fixes #22286