C#: Deprecate Assignable(Read)::getAReachableRead

This commit is contained in:
Tom Hvitved
2022-10-12 13:26:58 +02:00
parent d389a183f0
commit f49bfa7bcc
5 changed files with 61 additions and 30 deletions

View File

@@ -111,6 +111,7 @@ class AssignableRead extends AssignableAccess {
* - The reads of `i` on lines 7 and 8 are next to the read on line 6. * - The reads of `i` on lines 7 and 8 are next to the read on line 6.
* - The read of `this.Field` on line 11 is next to the read on line 10. * - The read of `this.Field` on line 11 is next to the read on line 10.
*/ */
pragma[nomagic]
AssignableRead getANextRead() { AssignableRead getANextRead() {
forex(ControlFlow::Node cfn | cfn = result.getAControlFlowNode() | forex(ControlFlow::Node cfn | cfn = result.getAControlFlowNode() |
cfn = this.getAnAdjacentReadSameVar() cfn = this.getAnAdjacentReadSameVar()
@@ -124,7 +125,7 @@ class AssignableRead extends AssignableAccess {
* *
* This is the transitive closure of `getANextRead()`. * This is the transitive closure of `getANextRead()`.
*/ */
AssignableRead getAReachableRead() { result = this.getANextRead+() } deprecated AssignableRead getAReachableRead() { result = this.getANextRead+() }
} }
/** /**
@@ -479,6 +480,7 @@ class AssignableDefinition extends TAssignableDefinition {
* Subsequent reads can be found by following the steps defined by * Subsequent reads can be found by following the steps defined by
* `AssignableRead.getANextRead()`. * `AssignableRead.getANextRead()`.
*/ */
pragma[nomagic]
AssignableRead getAFirstRead() { AssignableRead getAFirstRead() {
forex(ControlFlow::Node cfn | cfn = result.getAControlFlowNode() | forex(ControlFlow::Node cfn | cfn = result.getAControlFlowNode() |
exists(Ssa::ExplicitDefinition def | result = def.getAFirstReadAtNode(cfn) | exists(Ssa::ExplicitDefinition def | result = def.getAFirstReadAtNode(cfn) |
@@ -494,7 +496,7 @@ class AssignableDefinition extends TAssignableDefinition {
* *
* This is the equivalent with `getAFirstRead().getANextRead*()`. * This is the equivalent with `getAFirstRead().getANextRead*()`.
*/ */
AssignableRead getAReachableRead() { result = this.getAFirstRead().getANextRead*() } deprecated AssignableRead getAReachableRead() { result = this.getAFirstRead().getANextRead*() }
/** Gets a textual representation of this assignable definition. */ /** Gets a textual representation of this assignable definition. */
string toString() { none() } string toString() { none() }

View File

@@ -174,7 +174,9 @@ class VariableAccess extends AssignableAccess, @variable_access_expr {
class VariableRead extends VariableAccess, AssignableRead { class VariableRead extends VariableAccess, AssignableRead {
override VariableRead getANextRead() { result = AssignableRead.super.getANextRead() } override VariableRead getANextRead() { result = AssignableRead.super.getANextRead() }
override VariableRead getAReachableRead() { result = AssignableRead.super.getAReachableRead() } deprecated override VariableRead getAReachableRead() {
result = AssignableRead.super.getAReachableRead()
}
} }
/** /**
@@ -200,7 +202,7 @@ class LocalScopeVariableAccess extends VariableAccess, @local_scope_variable_acc
class LocalScopeVariableRead extends LocalScopeVariableAccess, VariableRead { class LocalScopeVariableRead extends LocalScopeVariableAccess, VariableRead {
override LocalScopeVariableRead getANextRead() { result = VariableRead.super.getANextRead() } override LocalScopeVariableRead getANextRead() { result = VariableRead.super.getANextRead() }
override LocalScopeVariableRead getAReachableRead() { deprecated override LocalScopeVariableRead getAReachableRead() {
result = VariableRead.super.getAReachableRead() result = VariableRead.super.getAReachableRead()
} }
} }
@@ -242,7 +244,7 @@ class ParameterAccess extends LocalScopeVariableAccess, @parameter_access_expr {
class ParameterRead extends ParameterAccess, LocalScopeVariableRead { class ParameterRead extends ParameterAccess, LocalScopeVariableRead {
override ParameterRead getANextRead() { result = LocalScopeVariableRead.super.getANextRead() } override ParameterRead getANextRead() { result = LocalScopeVariableRead.super.getANextRead() }
override ParameterRead getAReachableRead() { deprecated override ParameterRead getAReachableRead() {
result = LocalScopeVariableRead.super.getAReachableRead() result = LocalScopeVariableRead.super.getAReachableRead()
} }
} }
@@ -297,7 +299,7 @@ class LocalVariableAccess extends LocalScopeVariableAccess, @local_variable_acce
class LocalVariableRead extends LocalVariableAccess, LocalScopeVariableRead { class LocalVariableRead extends LocalVariableAccess, LocalScopeVariableRead {
override LocalVariableRead getANextRead() { result = LocalScopeVariableRead.super.getANextRead() } override LocalVariableRead getANextRead() { result = LocalScopeVariableRead.super.getANextRead() }
override LocalVariableRead getAReachableRead() { deprecated override LocalVariableRead getAReachableRead() {
result = LocalScopeVariableRead.super.getAReachableRead() result = LocalScopeVariableRead.super.getAReachableRead()
} }
} }
@@ -442,7 +444,9 @@ class PropertyAccess extends AssignableMemberAccess, PropertyAccessExpr {
class PropertyRead extends PropertyAccess, AssignableRead { class PropertyRead extends PropertyAccess, AssignableRead {
override PropertyRead getANextRead() { result = AssignableRead.super.getANextRead() } override PropertyRead getANextRead() { result = AssignableRead.super.getANextRead() }
override PropertyRead getAReachableRead() { result = AssignableRead.super.getAReachableRead() } deprecated override PropertyRead getAReachableRead() {
result = AssignableRead.super.getAReachableRead()
}
} }
/** /**
@@ -581,7 +585,9 @@ class IndexerAccess extends AssignableMemberAccess, ElementAccess, IndexerAccess
class IndexerRead extends IndexerAccess, ElementRead { class IndexerRead extends IndexerAccess, ElementRead {
override IndexerRead getANextRead() { result = ElementRead.super.getANextRead() } override IndexerRead getANextRead() { result = ElementRead.super.getANextRead() }
override IndexerRead getAReachableRead() { result = ElementRead.super.getAReachableRead() } deprecated override IndexerRead getAReachableRead() {
result = ElementRead.super.getAReachableRead()
}
} }
/** /**

View File

@@ -71,6 +71,20 @@ class FormatMethod extends Method {
} }
} }
pragma[nomagic]
private predicate parameterReadPostDominatesEntry(ParameterRead pr) {
pr.getAControlFlowNode().postDominates(pr.getEnclosingCallable().getEntryPoint()) and
getParameterType(pr.getTarget()) instanceof ObjectType
}
pragma[nomagic]
private predicate alwaysPassedToFormatItemParameter(ParameterRead pr) {
pr = any(StringFormatItemParameter other).getAnAssignedArgument() and
parameterReadPostDominatesEntry(pr)
or
alwaysPassedToFormatItemParameter(pr.getANextRead())
}
/** /**
* A parameter that is used as a format item for `string.Format()`. Either a * A parameter that is used as a format item for `string.Format()`. Either a
* format item parameter of `string.Format()`, or a parameter of a method that * format item parameter of `string.Format()`, or a parameter of a method that
@@ -85,15 +99,9 @@ class StringFormatItemParameter extends Parameter {
) )
or or
// Parameter of a source method that forwards to `string.Format()` // Parameter of a source method that forwards to `string.Format()`
exists( exists(AssignableDefinitions::ImplicitParameterDefinition def |
AssignableDefinitions::ImplicitParameterDefinition def, ParameterRead pr,
StringFormatItemParameter other
|
def.getParameter() = this and def.getParameter() = this and
pr = def.getAReachableRead() and alwaysPassedToFormatItemParameter(def.getAFirstRead())
pr.getAControlFlowNode().postDominates(this.getCallable().getEntryPoint()) and
other.getAnAssignedArgument() = pr and
getParameterType(this) instanceof ObjectType
) )
} }
} }

View File

@@ -22,12 +22,22 @@ private class DisposeCall extends MethodCall {
DisposeCall() { this.getTarget() instanceof DisposeMethod } DisposeCall() { this.getTarget() instanceof DisposeMethod }
} }
private predicate localFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { pragma[nomagic]
DataFlow::localFlowStep(nodeFrom, nodeTo) and private predicate isDisposedAccess(AssignableRead ar) {
not exists(AssignableDefinition def, UsingStmt us | exists(AssignableDefinition def, UsingStmt us |
nodeTo.asExpr() = def.getAReachableRead() and ar = def.getAFirstRead() and
def.getTargetAccess() = us.getAVariableDeclExpr().getAccess() def.getTargetAccess() = us.getAVariableDeclExpr().getAccess()
) )
or
exists(AssignableRead mid |
isDisposedAccess(mid) and
ar = mid.getANextRead()
)
}
private predicate localFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
DataFlow::localFlowStep(nodeFrom, nodeTo) and
not isDisposedAccess(nodeTo.asExpr())
} }
private predicate reachesDisposeCall(DisposeCall disposeCall, DataFlow::Node node) { private predicate reachesDisposeCall(DisposeCall disposeCall, DataFlow::Node node) {

View File

@@ -6,6 +6,7 @@ import semmle.code.csharp.frameworks.System
* Holds if expression `e`, of type `t`, invokes `ToString()` either explicitly * Holds if expression `e`, of type `t`, invokes `ToString()` either explicitly
* or implicitly. * or implicitly.
*/ */
pragma[nomagic]
predicate invokesToString(Expr e, ValueOrRefType t) { predicate invokesToString(Expr e, ValueOrRefType t) {
// Explicit invocation // Explicit invocation
exists(MethodCall mc | mc.getQualifier() = e | exists(MethodCall mc | mc.getQualifier() = e |
@@ -20,20 +21,24 @@ predicate invokesToString(Expr e, ValueOrRefType t) {
// Implicit invocation via forwarder method // Implicit invocation via forwarder method
t = e.stripCasts().getType() and t = e.stripCasts().getType() and
not t instanceof StringType and not t instanceof StringType and
exists(Parameter p | exists(AssignableDefinitions::ImplicitParameterDefinition def, Parameter p |
alwaysInvokesToStringOnParameter(p) and def.getParameter() = p and
alwaysInvokesToString(def.getAFirstRead()) and
e = p.getAnAssignedArgument() e = p.getAnAssignedArgument()
) )
} }
pragma[noinline] pragma[nomagic]
private predicate alwaysInvokesToStringOnParameter(Parameter p) { private predicate parameterReadPostDominatesEntry(ParameterRead pr) {
exists(AssignableDefinitions::ImplicitParameterDefinition def, ParameterRead pr | pr.getAControlFlowNode().postDominates(pr.getEnclosingCallable().getEntryPoint())
def.getParameter() = p and }
pr = def.getAReachableRead() and
pr.getAControlFlowNode().postDominates(p.getCallable().getEntryPoint()) and pragma[nomagic]
invokesToString(pr, _) private predicate alwaysInvokesToString(ParameterRead pr) {
) parameterReadPostDominatesEntry(pr) and
invokesToString(pr, _)
or
alwaysInvokesToString(pr.getANextRead())
} }
/** /**