🌐 AI搜索 & 代理 主页
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
193 changes: 47 additions & 146 deletions csharp/ql/lib/semmle/code/csharp/controlflow/Guards.qll
Original file line number Diff line number Diff line change
Expand Up @@ -842,6 +842,40 @@ module Internal {
e3 = any(NullCoalescingExpr nce | e1 = nce.getLeftOperand() and e2 = nce.getRightOperand())
}

predicate nullValueImplied(Expr e) {
nullValue(e)
or
exists(Expr e1 | nullValueImplied(e1) and nullValueImpliedUnary(e1, e))
or
exists(Expr e1, Expr e2 |
nullValueImplied(e1) and nullValueImplied(e2) and nullValueImpliedBinary(e1, e2, e)
)
or
e =
any(Ssa::Definition def |
forex(Ssa::Definition u | u = def.getAnUltimateDefinition() | nullDef(u))
).getARead()
}

private predicate nullDef(Ssa::ExplicitDefinition def) {
nullValueImplied(def.getADefinition().getSource())
}

predicate nonNullValueImplied(Expr e) {
nonNullValue(e)
or
exists(Expr e1 | nonNullValueImplied(e1) and nonNullValueImpliedUnary(e1, e))
or
e =
any(Ssa::Definition def |
forex(Ssa::Definition u | u = def.getAnUltimateDefinition() | nonNullDef(u))
).getARead()
}

private predicate nonNullDef(Ssa::ExplicitDefinition def) {
nonNullValueImplied(def.getADefinition().getSource())
}

/** A callable that always returns a non-`null` value. */
private class NonNullCallable extends Callable {
NonNullCallable() { this = any(SystemObjectClass c).getGetTypeMethod() }
Expand Down Expand Up @@ -936,154 +970,21 @@ module Internal {
e = any(BinaryArithmeticOperation bao | result = bao.getAnOperand())
}

// The predicates in this module should be evaluated in the same stage as the CFG
// construction stage. This is to avoid recomputation of pre-basic-blocks and
// pre-SSA predicates
private module PreCfg {
private import semmle.code.csharp.controlflow.internal.PreBasicBlocks as PreBasicBlocks
private import semmle.code.csharp.controlflow.internal.PreSsa

private predicate nullDef(PreSsa::Definition def) {
nullValueImplied(def.getDefinition().getSource())
}

private predicate nonNullDef(PreSsa::Definition def) {
nonNullValueImplied(def.getDefinition().getSource())
}

private predicate emptyDef(PreSsa::Definition def) {
emptyValue(def.getDefinition().getSource())
}

private predicate nonEmptyDef(PreSsa::Definition def) {
nonEmptyValue(def.getDefinition().getSource())
}

deprecated predicate isGuard(Expr e, GuardValue val) {
(
e.getType() instanceof BoolType and
not e instanceof BoolLiteral and
not e instanceof SwitchCaseExpr and
not e instanceof PatternExpr and
exists(val.asBooleanValue())
or
e instanceof DereferenceableExpr and
val.isNullness(_)
) and
not e = any(ExprStmt es).getExpr() and
not e = any(LocalVariableDeclStmt s).getAVariableDeclExpr()
}

cached
private module CachedWithCfg {
private import semmle.code.csharp.Caching

private predicate firstReadSameVarUniquePredecessor(
PreSsa::Definition def, AssignableRead read
) {
read = def.getAFirstRead() and
(
not PreSsa::adjacentReadPairSameVar(_, read)
or
read = unique(AssignableRead read0 | PreSsa::adjacentReadPairSameVar(read0, read))
)
}

cached
predicate nullValueImplied(Expr e) {
nullValue(e)
or
exists(Expr e1 | nullValueImplied(e1) and nullValueImpliedUnary(e1, e))
or
exists(Expr e1, Expr e2 |
nullValueImplied(e1) and nullValueImplied(e2) and nullValueImpliedBinary(e1, e2, e)
)
or
e =
any(PreSsa::Definition def |
forex(PreSsa::Definition u | u = def.getAnUltimateDefinition() | nullDef(u))
).getARead()
}

cached
predicate nonNullValueImplied(Expr e) {
nonNullValue(e)
or
exists(Expr e1 | nonNullValueImplied(e1) and nonNullValueImpliedUnary(e1, e))
or
e =
any(PreSsa::Definition def |
forex(PreSsa::Definition u | u = def.getAnUltimateDefinition() | nonNullDef(u))
).getARead()
}

private predicate adjacentReadPairSameVarUniquePredecessor(
AssignableRead read1, AssignableRead read2
) {
PreSsa::adjacentReadPairSameVar(read1, read2) and
(
read1 = read2 and
read1 = unique(AssignableRead other | PreSsa::adjacentReadPairSameVar(other, read2))
or
read1 =
unique(AssignableRead other |
PreSsa::adjacentReadPairSameVar(other, read2) and other != read2
)
)
}

cached
predicate emptyValue(Expr e) {
e.(ArrayCreation).getALengthArgument().getValue().toInt() = 0
or
e.(ArrayInitializer).hasNoElements()
or
exists(Expr mid | emptyValue(mid) |
mid = e.(AssignExpr).getRValue()
or
mid = e.(Cast).getExpr()
)
or
exists(PreSsa::Definition def | emptyDef(def) | firstReadSameVarUniquePredecessor(def, e))
or
exists(MethodCall mc |
mc.getTarget().getAnUltimateImplementee().getUnboundDeclaration() =
any(SystemCollectionsGenericICollectionInterface c).getClearMethod() and
adjacentReadPairSameVarUniquePredecessor(mc.getQualifier(), e)
)
}

cached
predicate nonEmptyValue(Expr e) {
forex(Expr length | length = e.(ArrayCreation).getALengthArgument() |
length.getValue().toInt() != 0
)
or
e.(ArrayInitializer).getNumberOfElements() > 0
or
exists(Expr mid | nonEmptyValue(mid) |
mid = e.(AssignExpr).getRValue()
or
mid = e.(Cast).getExpr()
)
or
exists(PreSsa::Definition def | nonEmptyDef(def) |
firstReadSameVarUniquePredecessor(def, e)
)
or
exists(MethodCall mc |
mc.getTarget().getAnUltimateImplementee().getUnboundDeclaration() =
any(SystemCollectionsGenericICollectionInterface c).getAddMethod() and
adjacentReadPairSameVarUniquePredecessor(mc.getQualifier(), e)
)
}
}

import CachedWithCfg
deprecated predicate isGuard(Expr e, GuardValue val) {
(
e.getType() instanceof BoolType and
not e instanceof BoolLiteral and
not e instanceof SwitchCaseExpr and
not e instanceof PatternExpr and
exists(val.asBooleanValue())
or
e instanceof DereferenceableExpr and
val.isNullness(_)
) and
not e = any(ExprStmt es).getExpr() and
not e = any(LocalVariableDeclStmt s).getAVariableDeclExpr()
}

import PreCfg

private predicate interestingDescendantCandidate(Expr e) {
guardControls(e, _, _)
or
Expand Down
Loading