-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Java: Add ValueDiscardingExpr
#8571
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Java: Add ValueDiscardingExpr
#8571
Conversation
Seems reasonable to me (paging @aschackmull to double check) |
@@ -2133,3 +2133,41 @@ class Argument extends Expr { | |||
) | |||
} | |||
} | |||
|
|||
/** | |||
* A statement expression, as specified by JLS 17 section 14.8. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I read JLS 17 section 14.8 a statement expression is the set of expressions that could occur in an ExprStmt
, which means that e.g. method invocations and assignments are statement expressions regardless of whether their results are discarded or not. So the JLS definition seems to be broader than what's defined here.
Now, I don't think the JLS definition of statement expressions is going to be particularly useful to have in QL, so I won't ask for that. On the contrary, I think this more restricted version that only includes those statement expressions that actually have their result discarded is a lot more useful, as the other changes in this PR also indicates. But I wonder whether we should perhaps use a different name for this class, since it doesn't exactly match the JLS definition? Maybe something like DiscardedStmtExpr
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
method invocations and assignments are statement expressions regardless of whether their results are discarded or not
But if they appear as ExprStmt.getExpr()
, then their result is always discarded, isn't it? Because (if I understand it correctly) CodeQL's ExprStmt
is exactly the same as JLS' ExpressionStatement
. And an ExpressionStatement
always discards the result, e.g.:
getValue();
// vs.
consume(getValue());
int i;
i = 1;
// vs.
int i;
int j = (i = 1);
And a few lines below (line 2147 currently) this = any(ExprStmt s).getExpr()
is included in the results.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. I don't believe I wrote anything that indicated otherwise. I still think we should use a different name for this QL class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I might have understood your "regardless of whether their results are discarded or not" and "the JLS definition seems to be broader than what's defined here" then incorrectly. To me that sounded as if in some cases the result of a statement expression is not discarded.
This is also why I don't completely understand the need to use a different QL class name, except if there are some general concerns about the name, regardless of functionality.
Which specific case are you thinking of where this QL class would behave differently that defined by the JLS (maybe I am just completely overlooking it at the moment)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To me that sounded as if in some cases the result of a statement expression is not discarded.
Yes, when taking "statement expression" expression to mean the thing that's defined in the JLS, then I believe that's the case. Indeed it looks to me like a JLS-defined "statement expression" includes among other things all method calls, regardless of whether they occur in an ExprStmt
and thereby have their result discarded.
This discrepancy between the JLS definition of "statement expression" and the QL class defined here is what leads me to suggest a different name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, you are right, I did not consider that. Because "statement expression" was defined in the context of expression statement, I assumed that it is also similarly restricted. But it appears there is no such restriction and as you mentioned it simply is a set of expression types.
Maybe similar to your suggested alternative name, what do you think about the following names?
DiscardingStmtExpr
("discarding" instead of "discarded" because the expression itself is not discarded)ValueDiscardingExpr
(similar to how the JLS mentions multiple times "if the expression has a value, the value is discarded")ResultDiscardingExpr
The CodeQL class could then also be refined to exclude method calls with void
as return type.
The documentation for the CodeQL class could then for example be:
An expression for which the value of the expression as a whole is discarded. Only cases of discarded values at the language level (as described by the JLS) are considered; data flow, for example to determine if an assigned variable value is ever read, is not considered. Such expressions can for example appear as part of a
ExprStmt
or as initializer of afor
loop.For example, for the statement
i++;
the value of the increment expression, that is the old value of variablei
, is discarded. Whereas for the statementprintln(i++);
the value of the increment expression is not discarded but used as argument for the method call.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Of those I think I like ValueDiscardingExpr
the best. And your suggested qldoc looks good!
…tatement-expression
Predicate behavior has been fixed on `main`.
As mentioned by aschackmull during review, StatementExpression as defined by the JLS only lists possible types of expressions, it does _not_ specify that their value is discarded. Therefore, for example any method call could be considered a StatementExpression. The name ValueDiscardingExpr was chosen as replacement because the JLS uses the phrase "if the expression has a value, the value is discarded" multiple times.
…tatement-expression
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Found 1 vulnerability.
Adds the CodeQL class
StmtExpr
which models statement expressions, that is, expressions whose result is discarded. This covers more cases than the existingExprStmt
.The tests are currently placed under
library-test/StmtExpr
, that is probably not ideal but I did not find an existing well matchinglibrary-test
subdirectory; any recommendations are welcome.The newly covered cases by this pull request will probably not occur that often in code, but maybe it is useful to cover them nonetheless.
I have not modified the control flow library, but possibly it could be changed (or simplified) by using
StmtExpr
.