mirror of
https://github.com/github/codeql.git
synced 2025-12-24 04:36:35 +01:00
Java/C++/C#: Add support for BarrierGuards.
This commit is contained in:
@@ -75,6 +75,9 @@ abstract class Configuration extends string {
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||
* into account in the analysis.
|
||||
@@ -136,6 +139,11 @@ private predicate fullBarrier(Node node, Configuration config) {
|
||||
or
|
||||
config.isBarrierOut(node) and
|
||||
not config.isSink(node)
|
||||
or
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
node = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
|
||||
private class AdditionalFlowStepSource extends Node {
|
||||
|
||||
@@ -75,6 +75,9 @@ abstract class Configuration extends string {
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||
* into account in the analysis.
|
||||
@@ -136,6 +139,11 @@ private predicate fullBarrier(Node node, Configuration config) {
|
||||
or
|
||||
config.isBarrierOut(node) and
|
||||
not config.isSink(node)
|
||||
or
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
node = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
|
||||
private class AdditionalFlowStepSource extends Node {
|
||||
|
||||
@@ -75,6 +75,9 @@ abstract class Configuration extends string {
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||
* into account in the analysis.
|
||||
@@ -136,6 +139,11 @@ private predicate fullBarrier(Node node, Configuration config) {
|
||||
or
|
||||
config.isBarrierOut(node) and
|
||||
not config.isSink(node)
|
||||
or
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
node = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
|
||||
private class AdditionalFlowStepSource extends Node {
|
||||
|
||||
@@ -75,6 +75,9 @@ abstract class Configuration extends string {
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||
* into account in the analysis.
|
||||
@@ -136,6 +139,11 @@ private predicate fullBarrier(Node node, Configuration config) {
|
||||
or
|
||||
config.isBarrierOut(node) and
|
||||
not config.isSink(node)
|
||||
or
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
node = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
|
||||
private class AdditionalFlowStepSource extends Node {
|
||||
|
||||
@@ -331,3 +331,14 @@ VariableAccess getAnAccessToAssignedVariable(Expr assign) {
|
||||
result = var.getAnAccess()
|
||||
)
|
||||
}
|
||||
|
||||
/** A guard that validates some expression. */
|
||||
class BarrierGuard extends Expr {
|
||||
/** Holds if this guard validates `e` upon evaluating to `branch`. */
|
||||
abstract predicate checks(Expr e, boolean branch);
|
||||
|
||||
/** Gets a node guarded by this. */
|
||||
final Node getAGuardedNode() {
|
||||
none() // stub
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,6 +75,9 @@ abstract class Configuration extends string {
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||
* into account in the analysis.
|
||||
@@ -136,6 +139,11 @@ private predicate fullBarrier(Node node, Configuration config) {
|
||||
or
|
||||
config.isBarrierOut(node) and
|
||||
not config.isSink(node)
|
||||
or
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
node = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
|
||||
private class AdditionalFlowStepSource extends Node {
|
||||
|
||||
@@ -75,6 +75,9 @@ abstract class Configuration extends string {
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||
* into account in the analysis.
|
||||
@@ -136,6 +139,11 @@ private predicate fullBarrier(Node node, Configuration config) {
|
||||
or
|
||||
config.isBarrierOut(node) and
|
||||
not config.isSink(node)
|
||||
or
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
node = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
|
||||
private class AdditionalFlowStepSource extends Node {
|
||||
|
||||
@@ -75,6 +75,9 @@ abstract class Configuration extends string {
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||
* into account in the analysis.
|
||||
@@ -136,6 +139,11 @@ private predicate fullBarrier(Node node, Configuration config) {
|
||||
or
|
||||
config.isBarrierOut(node) and
|
||||
not config.isSink(node)
|
||||
or
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
node = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
|
||||
private class AdditionalFlowStepSource extends Node {
|
||||
|
||||
@@ -75,6 +75,9 @@ abstract class Configuration extends string {
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||
* into account in the analysis.
|
||||
@@ -136,6 +139,11 @@ private predicate fullBarrier(Node node, Configuration config) {
|
||||
or
|
||||
config.isBarrierOut(node) and
|
||||
not config.isSink(node)
|
||||
or
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
node = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
|
||||
private class AdditionalFlowStepSource extends Node {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
private import cpp
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import semmle.code.cpp.controlflow.IRGuards
|
||||
|
||||
/**
|
||||
* A node in a data flow graph.
|
||||
@@ -166,3 +167,14 @@ predicate localFlowStep(Node nodeFrom, Node nodeTo) {
|
||||
* (intra-procedural) steps.
|
||||
*/
|
||||
predicate localFlow(Node source, Node sink) { localFlowStep*(source, sink) }
|
||||
|
||||
/** A guard that validates some expression. */
|
||||
class BarrierGuard extends IRGuardCondition {
|
||||
/** Holds if this guard validates `e` upon evaluating to `b`. */
|
||||
abstract predicate checks(Instruction e, boolean b);
|
||||
|
||||
/** Gets a node guarded by this. */
|
||||
final Node getAGuardedNode() {
|
||||
none() // stub
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,6 +75,9 @@ abstract class Configuration extends string {
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||
* into account in the analysis.
|
||||
@@ -136,6 +139,11 @@ private predicate fullBarrier(Node node, Configuration config) {
|
||||
or
|
||||
config.isBarrierOut(node) and
|
||||
not config.isSink(node)
|
||||
or
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
node = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
|
||||
private class AdditionalFlowStepSource extends Node {
|
||||
|
||||
@@ -75,6 +75,9 @@ abstract class Configuration extends string {
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||
* into account in the analysis.
|
||||
@@ -136,6 +139,11 @@ private predicate fullBarrier(Node node, Configuration config) {
|
||||
or
|
||||
config.isBarrierOut(node) and
|
||||
not config.isSink(node)
|
||||
or
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
node = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
|
||||
private class AdditionalFlowStepSource extends Node {
|
||||
|
||||
@@ -75,6 +75,9 @@ abstract class Configuration extends string {
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||
* into account in the analysis.
|
||||
@@ -136,6 +139,11 @@ private predicate fullBarrier(Node node, Configuration config) {
|
||||
or
|
||||
config.isBarrierOut(node) and
|
||||
not config.isSink(node)
|
||||
or
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
node = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
|
||||
private class AdditionalFlowStepSource extends Node {
|
||||
|
||||
@@ -75,6 +75,9 @@ abstract class Configuration extends string {
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||
* into account in the analysis.
|
||||
@@ -136,6 +139,11 @@ private predicate fullBarrier(Node node, Configuration config) {
|
||||
or
|
||||
config.isBarrierOut(node) and
|
||||
not config.isSink(node)
|
||||
or
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
node = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
|
||||
private class AdditionalFlowStepSource extends Node {
|
||||
|
||||
@@ -75,6 +75,9 @@ abstract class Configuration extends string {
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||
* into account in the analysis.
|
||||
@@ -136,6 +139,11 @@ private predicate fullBarrier(Node node, Configuration config) {
|
||||
or
|
||||
config.isBarrierOut(node) and
|
||||
not config.isSink(node)
|
||||
or
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
node = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
|
||||
private class AdditionalFlowStepSource extends Node {
|
||||
|
||||
@@ -3,6 +3,7 @@ private import cil
|
||||
private import dotnet
|
||||
private import DataFlowPrivate
|
||||
private import semmle.code.csharp.Caching
|
||||
private import semmle.code.csharp.controlflow.Guards
|
||||
|
||||
/**
|
||||
* An element, viewed as a node in a data flow graph. Either an expression
|
||||
@@ -162,3 +163,14 @@ abstract class NonLocalJumpNode extends Node {
|
||||
/** Gets a successor node that is potentially in another callable. */
|
||||
abstract Node getAJumpSuccessor(boolean preservesValue);
|
||||
}
|
||||
|
||||
/** A guard that validates some expression. */
|
||||
class BarrierGuard extends Internal::Guard {
|
||||
/** Holds if this guard validates `e` upon evaluating to `v`. */
|
||||
abstract predicate checks(Expr e, AbstractValue v);
|
||||
|
||||
/** Gets a node guarded by this. */
|
||||
final Node getAGuardedNode() {
|
||||
none() // stub
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,17 @@ import semmle.code.java.dataflow.FlowSources
|
||||
import PathsCommon
|
||||
import DataFlow::PathGraph
|
||||
|
||||
class ContainsDotDotSanitizer extends DataFlow::BarrierGuard {
|
||||
ContainsDotDotSanitizer() {
|
||||
this.(MethodAccess).getMethod().hasName("contains") and
|
||||
this.(MethodAccess).getAnArgument().(StringLiteral).getValue() = ".."
|
||||
}
|
||||
|
||||
override predicate checks(Expr e, boolean branch) {
|
||||
e = this.(MethodAccess).getQualifier() and branch = false
|
||||
}
|
||||
}
|
||||
|
||||
class TaintedPathConfig extends TaintTracking::Configuration {
|
||||
TaintedPathConfig() { this = "TaintedPathConfig" }
|
||||
|
||||
@@ -29,6 +40,10 @@ class TaintedPathConfig extends TaintTracking::Configuration {
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
exists(Type t | t = node.getType() | t instanceof BoxedType or t instanceof PrimitiveType)
|
||||
}
|
||||
|
||||
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
|
||||
guard instanceof ContainsDotDotSanitizer
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, PathCreation p, TaintedPathConfig conf
|
||||
|
||||
@@ -80,6 +80,11 @@ module TaintTracking {
|
||||
|
||||
final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) }
|
||||
|
||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||
|
||||
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) }
|
||||
|
||||
/**
|
||||
* Holds if the additional taint propagation step from `node1` to `node2`
|
||||
* must be taken into account in the analysis.
|
||||
@@ -162,6 +167,11 @@ module TaintTracking {
|
||||
|
||||
final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) }
|
||||
|
||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||
|
||||
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) }
|
||||
|
||||
/**
|
||||
* Holds if the additional taint propagation step from `node1` to `node2`
|
||||
* must be taken into account in the analysis.
|
||||
|
||||
@@ -75,6 +75,9 @@ abstract class Configuration extends string {
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||
* into account in the analysis.
|
||||
@@ -136,6 +139,11 @@ private predicate fullBarrier(Node node, Configuration config) {
|
||||
or
|
||||
config.isBarrierOut(node) and
|
||||
not config.isSink(node)
|
||||
or
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
node = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
|
||||
private class AdditionalFlowStepSource extends Node {
|
||||
|
||||
@@ -75,6 +75,9 @@ abstract class Configuration extends string {
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||
* into account in the analysis.
|
||||
@@ -136,6 +139,11 @@ private predicate fullBarrier(Node node, Configuration config) {
|
||||
or
|
||||
config.isBarrierOut(node) and
|
||||
not config.isSink(node)
|
||||
or
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
node = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
|
||||
private class AdditionalFlowStepSource extends Node {
|
||||
|
||||
@@ -75,6 +75,9 @@ abstract class Configuration extends string {
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||
* into account in the analysis.
|
||||
@@ -136,6 +139,11 @@ private predicate fullBarrier(Node node, Configuration config) {
|
||||
or
|
||||
config.isBarrierOut(node) and
|
||||
not config.isSink(node)
|
||||
or
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
node = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
|
||||
private class AdditionalFlowStepSource extends Node {
|
||||
|
||||
@@ -75,6 +75,9 @@ abstract class Configuration extends string {
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||
* into account in the analysis.
|
||||
@@ -136,6 +139,11 @@ private predicate fullBarrier(Node node, Configuration config) {
|
||||
or
|
||||
config.isBarrierOut(node) and
|
||||
not config.isSink(node)
|
||||
or
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
node = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
|
||||
private class AdditionalFlowStepSource extends Node {
|
||||
|
||||
@@ -75,6 +75,9 @@ abstract class Configuration extends string {
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||
* into account in the analysis.
|
||||
@@ -136,6 +139,11 @@ private predicate fullBarrier(Node node, Configuration config) {
|
||||
or
|
||||
config.isBarrierOut(node) and
|
||||
not config.isSink(node)
|
||||
or
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
node = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
|
||||
private class AdditionalFlowStepSource extends Node {
|
||||
|
||||
@@ -6,6 +6,7 @@ private import java
|
||||
private import DataFlowPrivate
|
||||
private import semmle.code.java.dataflow.SSA
|
||||
private import semmle.code.java.dataflow.TypeFlow
|
||||
private import semmle.code.java.controlflow.Guards
|
||||
import semmle.code.java.dataflow.InstanceAccess
|
||||
|
||||
cached
|
||||
@@ -416,3 +417,19 @@ Node getInstanceArgument(Call call) {
|
||||
explicitInstanceArgument(call, result.asExpr()) or
|
||||
implicitInstanceArgument(call, result.(ImplicitInstanceAccess).getInstanceAccess())
|
||||
}
|
||||
|
||||
/** A guard that validates some expression. */
|
||||
class BarrierGuard extends Guard {
|
||||
/** Holds if this guard validates `e` upon evaluating to `branch`. */
|
||||
abstract predicate checks(Expr e, boolean branch);
|
||||
|
||||
/** Gets a node guarded by this. */
|
||||
final Node getAGuardedNode() {
|
||||
exists(SsaVariable v, boolean branch, RValue use |
|
||||
this.checks(v.getAUse(), branch) and
|
||||
use = v.getAUse() and
|
||||
this.controls(use.getBasicBlock(), branch) and
|
||||
result.asExpr() = use
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user