Skip to content

Conversation

hvitved
Copy link
Contributor

@hvitved hvitved commented Oct 24, 2018

Follow-up on #284. This PR joins the predicates controls(), controlsNullness(), and controlsMatching(), as well as the predicates isGuardedBy(), isGuardedByNullness(), and isGuardedByMatching().

@calumgrant

@hvitved hvitved added the C# label Oct 24, 2018
@hvitved hvitved requested a review from calumgrant October 24, 2018 09:16
@hvitved hvitved requested a review from a team as a code owner October 24, 2018 09:16
@hvitved hvitved added the WIP This is a work-in-progress, do not merge yet! label Oct 25, 2018
@hvitved hvitved force-pushed the csharp/guards-logic branch 4 times, most recently from ac65f55 to 92317f1 Compare October 30, 2018 09:02
Unify the logic for Boolean/nullness/matching guards.
@hvitved hvitved force-pushed the csharp/guards-logic branch from 92317f1 to 6651736 Compare October 30, 2018 12:16
@hvitved hvitved removed the WIP This is a work-in-progress, do not merge yet! label Oct 30, 2018
Copy link
Contributor

@calumgrant calumgrant left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice - a few minor comments.

private import semmle.code.csharp.frameworks.System

/** An abstract value representing one of two possible classes of values. */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This probably needs more explanation - let me think how to word it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the latest version of the commit it is now just "An abstract value".

}
}

/** An empty or non-empty value. */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

value -> collection ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I the latest version it is

/** A value that represents an empty or non-empty collection. */
class EmptyCollectionValue extends AbstractValue, TEmptyCollectionValue {

* Gets the conditional qualifier of `e`, if any, where `e` is an access/call
* with a value type, lifted to a nullable type by the conditional access.
*/
Expr getConditionalQualifier(Expr e) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This predicate is confusing because e is the qualifier, rather than result.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Turns out that this predicate is unused, I will remove it.

qe.getQualifier() = e and
qe.isConditional() and
(
result.(FieldAccess).getTarget().getType() instanceof ValueType
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not PropertyAccess as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because a PropertyAccess is also a PropertyCall which is a Call.

* if any. For example, `result = x?.y` and `e = x`, or `result = x + 1`
* and `e = x`.
*/
Expr getNullEquivParent(Expr e) {
exists(QualifiableExpr qe |
result = qe and
result = any(QualifiableExpr qe |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use getConditionalQualifier here instead?


private cached module Cached {
cached
newtype TAbstractValue =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it really necessary to cache these 8 values?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess not.

v1 = TBooleanValue(true) and
v2 = v1
or
e1.(BitwiseOrExpr).getAnOperand() = e2 and
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BitwiseXorExpr as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't conclude anything about one of the operands from the value of xor, nor the other way around.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah ok. We would need 2 abstract values to deduce the third.

*/
cached
predicate impliesStep(Expr e1, AbstractValue v1, Expr e2, AbstractValue v2) {
e1.(BitwiseAndExpr).getAnOperand() = e2 and
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These implications also work in the opposite direction, where e1 is an operand of e2. For example,

e2.(BitwiseAndExpr).getAnOperand() = e1 and
v1 = TBooleanValue(false) and
v2 = v1

etc. for BitwiseOrExpr, LogicalAndExpr and LogicalOrExpr.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Copy link
Contributor

@calumgrant calumgrant left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tiny question, but LGTM.

e1 = ct.getExpr() and
e2 = ct.getAnArgument()
or
// e2 === e1 != true, v1 === v2 xor b
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

true -> b ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but not worth fixing here I think; I have a follow-up PR anyway.

e1 = ct.getExpr() and
ct.getAnArgument() = e2 and
e1 = e2.(LogicalNotExpr).getOperand() and
v2 = TBooleanValue(v1.(BooleanValue).getValue().booleanNot())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder whether it makes sense to implement BooleanValue BooleanValue.booleanNot() as a utility predicate on BooleanValue ?

@semmle-qlci semmle-qlci merged commit 33c02fe into github:master Nov 6, 2018
@hvitved hvitved deleted the csharp/guards-logic branch November 6, 2018 19:06
aibaars added a commit that referenced this pull request Oct 14, 2021
smowton pushed a commit to smowton/codeql that referenced this pull request Apr 16, 2022
Fix data flow through `ExtensionMethodAccess`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants