Merge branch 'main' into rdmarsh/cpp/use-taint-configuration-dtt

This commit is contained in:
Mathias Vorreiter Pedersen
2021-03-26 09:11:12 +01:00
824 changed files with 19318 additions and 9855 deletions

View File

@@ -1,3 +1,5 @@
name: Check change note
on:
pull_request_target:
types: [labeled, unlabeled, opened, synchronize, reopened, ready_for_review]

View File

@@ -1,29 +0,0 @@
# When a PR is labelled with 'ready-for-docs-review',
# this workflow comments on the PR to notify the GitHub CodeQL docs team.
name: Request docs review
on:
# Runs in the context of the base repo.
# This gives the workflow write access to comment on PRs.
# The workflow should not check out or build the given ref,
# or use untrusted data from the event payload in a command line.
pull_request_target:
types: [labeled]
jobs:
request-docs-review:
name: Request docs review
# Run only on labelled PRs to the main repository.
# Do not run on PRs to forks.
if:
github.event.label.name == 'ready-for-docs-review'
&& github.event.pull_request.draft == false
&& github.event.pull_request.base.repo.full_name == 'github/codeql'
runs-on: ubuntu-latest
steps:
- name: Comment to request docs review
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
gh pr comment "$PR_NUMBER" --repo "github/codeql" \
--body "Hello @github/docs-content-codeql - this PR is ready for docs review."

View File

@@ -1,3 +1,3 @@
{
"omnisharp.autoStart": false
}
}

View File

@@ -377,7 +377,6 @@
],
"DuplicationProblems.inc.qhelp": [
"cpp/ql/src/Metrics/Files/DuplicationProblems.inc.qhelp",
"csharp/ql/src/Metrics/Files/DuplicationProblems.inc.qhelp",
"javascript/ql/src/Metrics/DuplicationProblems.inc.qhelp",
"python/ql/src/Metrics/DuplicationProblems.inc.qhelp"
],
@@ -430,10 +429,11 @@
"SSA C#": [
"csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImplCommon.qll",
"csharp/ql/src/semmle/code/csharp/controlflow/internal/pressa/SsaImplCommon.qll",
"csharp/ql/src/semmle/code/csharp/dataflow/internal/basessa/SsaImplCommon.qll"
"csharp/ql/src/semmle/code/csharp/dataflow/internal/basessa/SsaImplCommon.qll",
"csharp/ql/src/semmle/code/cil/internal/SsaImplCommon.qll"
],
"CryptoAlgorithms Python/JS": [
"javascript/ql/src/semmle/javascript/security/CryptoAlgorithms.qll",
"python/ql/src/semmle/crypto/Crypto.qll"
]
}
}

View File

@@ -17,7 +17,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Build" Version="16.0.461" />
<PackageReference Include="Microsoft.Build" Version="16.9.0" />
</ItemGroup>
<ItemGroup>

View File

@@ -0,0 +1,2 @@
lgtm,codescanning
* The 'Resource not released in destructor' (cpp/resource-not-released-in-destructor) query has been improved to recognize more releases of resources.

View File

@@ -0,0 +1,16 @@
/**
* @name Extraction errors
* @description List all extraction errors for files in the source code directory.
* @kind diagnostic
* @id cpp/diagnostics/extraction-errors
*/
import cpp
import ExtractionErrors
from ExtractionError error
where
error instanceof ExtractionUnknownError or
exists(error.getFile().getRelativePath())
select error, "Extraction failed in " + error.getFile() + " with error " + error.getErrorMessage(),
error.getSeverity()

View File

@@ -0,0 +1,137 @@
/**
* Provides a common hierarchy of all types of errors that can occur during extraction.
*/
import cpp
/*
* A note about how the C/C++ extractor emits diagnostics:
* When the extractor frontend encounters an error, it emits a diagnostic message,
* that includes a message, location and severity.
* However, that process is best-effort and may fail (e.g. due to lack of memory).
* Thus, if the extractor emitted at least one diagnostic of severity discretionary
* error (or higher), it *also* emits a simple "There was an error during this compilation"
* error diagnostic, without location information.
* In the common case, this means that a compilation during which one or more errors happened also gets
* the catch-all diagnostic.
* This diagnostic has the empty string as file path.
* We filter out these useless diagnostics if there is at least one error-level diagnostic
* for the affected compilation in the database.
* Otherwise, we show it to indicate that something went wrong and that we
* don't know what exactly happened.
*/
/**
* An error that, if present, leads to a file being marked as non-successfully extracted.
*/
class ReportableError extends Diagnostic {
ReportableError() {
(
this instanceof CompilerDiscretionaryError or
this instanceof CompilerError or
this instanceof CompilerCatastrophe
) and
// Filter for the catch-all diagnostic, see note above.
not this.getFile().getAbsolutePath() = ""
}
}
private newtype TExtractionError =
TReportableError(ReportableError err) or
TCompilationFailed(Compilation c, File f) {
f = c.getAFileCompiled() and not c.normalTermination()
} or
// Show the catch-all diagnostic (see note above) only if we haven't seen any other error-level diagnostic
// for that compilation
TUnknownError(CompilerError err) {
not exists(ReportableError e | e.getCompilation() = err.getCompilation())
}
/**
* Superclass for the extraction error hierarchy.
*/
class ExtractionError extends TExtractionError {
/** Gets the string representation of the error. */
string toString() { none() }
/** Gets the error message for this error. */
string getErrorMessage() { none() }
/** Gets the file this error occured in. */
File getFile() { none() }
/** Gets the location this error occured in. */
Location getLocation() { none() }
/** Gets the SARIF severity of this error. */
int getSeverity() {
// Unfortunately, we can't distinguish between errors and fatal errors in SARIF,
// so all errors have severity 2.
result = 2
}
}
/**
* An unrecoverable extraction error, where extraction was unable to finish.
* This can be caused by a multitude of reasons, for example:
* - hitting a frontend assertion
* - crashing due to dereferencing an invalid pointer
* - stack overflow
* - out of memory
*/
class ExtractionUnrecoverableError extends ExtractionError, TCompilationFailed {
Compilation c;
File f;
ExtractionUnrecoverableError() { this = TCompilationFailed(c, f) }
override string toString() {
result = "Unrecoverable extraction error while compiling " + f.toString()
}
override string getErrorMessage() { result = "unrecoverable compilation failure." }
override File getFile() { result = f }
override Location getLocation() { result = f.getLocation() }
}
/**
* A recoverable extraction error.
* These are compiler errors from the frontend.
* Upon encountering one of these, we still continue extraction, but the
* database will be incomplete for that file.
*/
class ExtractionRecoverableError extends ExtractionError, TReportableError {
ReportableError err;
ExtractionRecoverableError() { this = TReportableError(err) }
override string toString() { result = "Recoverable extraction error: " + err }
override string getErrorMessage() { result = err.getFullMessage() }
override File getFile() { result = err.getFile() }
override Location getLocation() { result = err.getLocation() }
}
/**
* An unknown error happened during extraction.
* These are only displayed if we know that we encountered an error during extraction,
* but, for some reason, failed to emit a proper diagnostic with location information
* and error message.
*/
class ExtractionUnknownError extends ExtractionError, TUnknownError {
CompilerError err;
ExtractionUnknownError() { this = TUnknownError(err) }
override string toString() { result = "Unknown extraction error: " + err }
override string getErrorMessage() { result = err.getFullMessage() }
override File getFile() { result = err.getFile() }
override Location getLocation() { result = err.getLocation() }
}

View File

@@ -1,8 +1,8 @@
/**
* @name Failed extractions
* @description Gives the command-line of compilations for which extraction did not run to completion.
* @name Failed extractor invocations
* @description Gives the command line of compilations for which extraction did not run to completion.
* @kind diagnostic
* @id cpp/diagnostics/failed-extractions
* @id cpp/diagnostics/failed-extractor-invocations
*/
import cpp
@@ -19,4 +19,4 @@ string describe(Compilation c) {
from Compilation c
where not c.normalTermination()
select c, "Extraction failed for " + describe(c), 2
select c, "Extraction aborted for " + describe(c), 2

View File

@@ -0,0 +1,15 @@
/**
* @name Successfully extracted files
* @description Lists all files in the source code directory that were extracted without encountering an error in the file.
* @kind diagnostic
* @id cpp/diagnostics/successfully-extracted-files
*/
import cpp
import ExtractionErrors
from File f
where
not exists(ExtractionError e | e.getFile() = f) and
exists(f.getRelativePath())
select f, ""

View File

@@ -0,0 +1,11 @@
/**
* @id cpp/summary/lines-of-code
* @name Total lines of C/C++ code in the database
* @description The total number of lines of C/C++ code across all files, including system headers, libraries, and auto-generated files. This is a useful metric of the size of a database. For all files that were seen during the build, this query counts the lines of code, excluding whitespace or comments.
* @kind metric
* @tags summary
*/
import cpp
select sum(File f | f.fromSource() | f.getMetrics().getNumberOfLinesOfCode())

View File

@@ -13,6 +13,7 @@
import cpp
import Critical.NewDelete
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
/**
* An expression that acquires a resource, and the kind of resource that is acquired. The
@@ -90,15 +91,17 @@ private predicate exprReleases(Expr e, Expr released, string kind) {
// `e` is a call to a release function and `released` is the released argument
releaseExpr(e, released, kind)
or
exists(Function f, int arg |
exists(int arg, VariableAccess access, Function f |
// `e` is a call to a function that releases one of it's parameters,
// and `released` is the corresponding argument
(
e.(FunctionCall).getTarget() = f or
e.(FunctionCall).getTarget().(MemberFunction).getAnOverridingFunction+() = f
) and
access = f.getParameter(arg).getAnAccess() and
e.(FunctionCall).getArgument(arg) = released and
exprReleases(_, exprOrDereference(f.getParameter(arg).getAnAccess()), kind)
exprReleases(_,
pragma[only_bind_into](exprOrDereference(globalValueNumber(access).getAnExpr())), kind)
)
or
exists(Function f, ThisExpr innerThis |
@@ -110,7 +113,7 @@ private predicate exprReleases(Expr e, Expr released, string kind) {
) and
e.(FunctionCall).getQualifier() = exprOrDereference(released) and
innerThis.getEnclosingFunction() = f and
exprReleases(_, innerThis, kind)
exprReleases(_, pragma[only_bind_into](globalValueNumber(innerThis).getAnExpr()), kind)
)
}

View File

@@ -6,6 +6,9 @@ import semmle.code.cpp.Location
/** A compiler-generated error, warning or remark. */
class Diagnostic extends Locatable, @diagnostic {
/** Gets the compilation that generated this diagnostic. */
Compilation getCompilation() { diagnostic_for(underlyingElement(this), result, _, _) }
/**
* Gets the severity of the message, on a range from 1 to 5: 1=remark,
* 2=warning, 3=discretionary error, 4=error, 5=catastrophic error.

View File

@@ -444,8 +444,8 @@ private module Stage1 {
// read
exists(Node mid, Content c |
read(node, c, mid) and
fwdFlowConsCand(c, unbind(config)) and
revFlow(mid, toReturn, config)
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
revFlow(mid, toReturn, pragma[only_bind_into](config))
)
or
// flow into a callable
@@ -471,18 +471,18 @@ private module Stage1 {
pragma[nomagic]
private predicate revFlowConsCand(Content c, Configuration config) {
exists(Node mid, Node node |
fwdFlow(node, unbind(config)) and
fwdFlow(node, pragma[only_bind_into](config)) and
read(node, c, mid) and
fwdFlowConsCand(c, unbind(config)) and
revFlow(mid, _, config)
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
)
}
pragma[nomagic]
private predicate revFlowStore(Content c, Node node, boolean toReturn, Configuration config) {
exists(Node mid, TypedContent tc |
revFlow(mid, toReturn, config) and
fwdFlowConsCand(c, unbind(config)) and
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
store(node, tc, mid, _) and
c = tc.getContent()
)
@@ -552,8 +552,8 @@ private module Stage1 {
Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
) {
exists(Content c |
revFlowIsReadAndStored(c, config) and
revFlow(node2, unbind(config)) and
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(node2, pragma[only_bind_into](config)) and
store(node1, tc, node2, contentType) and
c = tc.getContent() and
exists(ap1)
@@ -562,8 +562,8 @@ private module Stage1 {
pragma[nomagic]
predicate readStepCand(Node n1, Content c, Node n2, Configuration config) {
revFlowIsReadAndStored(c, config) and
revFlow(n2, unbind(config)) and
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(n2, pragma[only_bind_into](config)) and
read(n1, c, n2)
}
@@ -626,9 +626,6 @@ private module Stage1 {
/* End: Stage 1 logic. */
}
bindingset[result, b]
private boolean unbindBool(boolean b) { result != b.booleanNot() }
pragma[noinline]
private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
Stage1::revFlow(node2, config) and
@@ -864,16 +861,16 @@ private module Stage2 {
)
or
exists(Node mid |
fwdFlow(mid, _, _, ap, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone()
)
or
exists(Node mid, ApNil nil |
fwdFlow(mid, _, _, nil, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone() and
@@ -1045,9 +1042,9 @@ private module Stage2 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, config) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
@@ -1059,9 +1056,9 @@ private module Stage2 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(mid, _, _, nil, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
@@ -1114,9 +1111,10 @@ private module Stage2 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(Node mid |
exists(Node mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
readStepFwd(_, cons, c, mid, tail, config)
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
)
}
@@ -1182,9 +1180,10 @@ private module Stage2 {
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, ap2, config) and
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
revFlowStore(ap1, c, /*unbind*/ unbindBool(ap2), _, _, _, _, _, unbind(config))
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
pragma[only_bind_into](config))
)
}
@@ -1240,8 +1239,8 @@ private predicate flowOutOfCallNodeCand2(
DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, config) and
Stage2::revFlow(node1, unbind(config))
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlow(node1, pragma[only_bind_into](config))
}
pragma[nomagic]
@@ -1250,8 +1249,8 @@ private predicate flowIntoCallNodeCand2(
Configuration config
) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, config) and
Stage2::revFlow(node1, unbind(config))
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlow(node1, pragma[only_bind_into](config))
}
private module LocalFlowBigStep {
@@ -1306,8 +1305,8 @@ private module LocalFlowBigStep {
pragma[noinline]
private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) {
additionalLocalFlowStepNodeCand1(node1, node2, config) and
Stage2::revFlow(node1, _, _, false, config) and
Stage2::revFlow(node2, _, _, false, unbind(config))
Stage2::revFlow(node1, _, _, false, pragma[only_bind_into](config)) and
Stage2::revFlow(node2, _, _, false, pragma[only_bind_into](config))
}
/**
@@ -1324,7 +1323,7 @@ private module LocalFlowBigStep {
) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, config) and
localFlowEntry(node1, pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and
@@ -1337,22 +1336,22 @@ private module LocalFlowBigStep {
node1 != node2 and
cc.relevantFor(getNodeEnclosingCallable(node1)) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, unbind(config))
Stage2::revFlow(node2, pragma[only_bind_into](config))
or
exists(Node mid |
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
localFlowStepPlus(node1, mid, preservesValue, t, pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, unbind(config))
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
or
exists(Node mid |
localFlowStepPlus(node1, mid, _, _, config, cc) and
localFlowStepPlus(node1, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = getNodeType(node2) and
Stage2::revFlow(node2, unbind(config))
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
)
}
@@ -1459,6 +1458,13 @@ private module Stage3 {
PrevStage::revFlow(node, _, _, apa, config)
}
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
exists(ApApprox apa0 |
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
)
}
/**
* Holds if `node` is reachable with access path `ap` from a source in the
* configuration `config`.
@@ -1470,7 +1476,7 @@ private module Stage3 {
pragma[nomagic]
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindBool(getApprox(ap)), config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
@@ -1494,16 +1500,16 @@ private module Stage3 {
)
or
exists(Node mid |
fwdFlow(mid, _, _, ap, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone()
)
or
exists(Node mid, ApNil nil |
fwdFlow(mid, _, _, nil, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone() and
@@ -1548,7 +1554,7 @@ private module Stage3 {
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindBool(getApprox(ap1)), tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType)
)
}
@@ -1627,7 +1633,7 @@ private module Stage3 {
) {
exists(ParameterNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindBool(getApprox(ap)), config)
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
}
@@ -1675,9 +1681,9 @@ private module Stage3 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, config) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
@@ -1689,9 +1695,9 @@ private module Stage3 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(mid, _, _, nil, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
@@ -1744,9 +1750,10 @@ private module Stage3 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(Node mid |
exists(Node mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
readStepFwd(_, cons, c, mid, tail, config)
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
)
}
@@ -1812,9 +1819,10 @@ private module Stage3 {
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, ap2, config) and
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
pragma[only_bind_into](config))
)
}
@@ -2125,8 +2133,11 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
localFlowEntry(node, config) and
result = getLocalCallContext(cc, getNodeEnclosingCallable(node))
exists(Cc cc0 |
cc = pragma[only_bind_into](cc0) and
localFlowEntry(node, config) and
result = getLocalCallContext(cc0, getNodeEnclosingCallable(node))
)
}
private predicate localStep(
@@ -2141,8 +2152,8 @@ private module Stage4 {
Configuration config
) {
flowOutOfCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, config) and
PrevStage::revFlow(node1, _, _, _, unbind(config))
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
}
pragma[nomagic]
@@ -2151,8 +2162,8 @@ private module Stage4 {
Configuration config
) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, config) and
PrevStage::revFlow(node1, _, _, _, unbind(config))
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
}
bindingset[node, ap]
@@ -2167,6 +2178,13 @@ private module Stage4 {
PrevStage::revFlow(node, _, _, apa, config)
}
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
exists(ApApprox apa0 |
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
)
}
/**
* Holds if `node` is reachable with access path `ap` from a source in the
* configuration `config`.
@@ -2178,7 +2196,7 @@ private module Stage4 {
pragma[nomagic]
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, getApprox(ap), config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
@@ -2202,16 +2220,16 @@ private module Stage4 {
)
or
exists(Node mid |
fwdFlow(mid, _, _, ap, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone()
)
or
exists(Node mid, ApNil nil |
fwdFlow(mid, _, _, nil, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone() and
@@ -2256,7 +2274,7 @@ private module Stage4 {
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType)
)
}
@@ -2335,7 +2353,7 @@ private module Stage4 {
) {
exists(ParameterNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
}
@@ -2383,9 +2401,9 @@ private module Stage4 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, config) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
@@ -2397,9 +2415,9 @@ private module Stage4 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(mid, _, _, nil, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
@@ -2452,9 +2470,10 @@ private module Stage4 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(Node mid |
exists(Node mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
readStepFwd(_, cons, c, mid, tail, config)
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
)
}
@@ -2520,9 +2539,10 @@ private module Stage4 {
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, ap2, config) and
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
pragma[only_bind_into](config))
)
}
@@ -2574,7 +2594,9 @@ private module Stage4 {
}
bindingset[conf, result]
private Configuration unbind(Configuration conf) { result >= conf and result <= conf }
private Configuration unbindConf(Configuration conf) {
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
}
private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration config) {
exists(DataFlowCallable c, AccessPathApprox apa0 |
@@ -2744,13 +2766,13 @@ private newtype TPathNode =
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
pathStep(mid, node, cc, sc, ap) and
config = mid.getConfiguration() and
Stage4::revFlow(node, _, _, ap.getApprox(), unbind(config))
pragma[only_bind_into](config) = mid.getConfiguration() and
Stage4::revFlow(node, _, _, ap.getApprox(), pragma[only_bind_into](config))
)
} or
TPathNodeSink(Node node, Configuration config) {
config.isSink(node) and
Stage4::revFlow(node, unbind(config)) and
pragma[only_bind_into](config).isSink(node) and
Stage4::revFlow(node, pragma[only_bind_into](config)) and
(
// A sink that is also a source ...
config.isSource(node)
@@ -2758,7 +2780,7 @@ private newtype TPathNode =
// ... or a sink that can be reached from a source
exists(PathNodeMid mid |
pathStep(mid, node, _, _, TAccessPathNil(_)) and
config = unbind(mid.getConfiguration())
pragma[only_bind_into](config) = mid.getConfiguration()
)
)
}
@@ -3055,7 +3077,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
private PathNodeMid getSuccMid() {
pathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx(), result.getAp()) and
result.getConfiguration() = unbind(this.getConfiguration())
result.getConfiguration() = unbindConf(this.getConfiguration())
}
override PathNodeImpl getASuccessorImpl() {
@@ -3067,7 +3089,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
mid = getSuccMid() and
mid.getNode() = sink.getNode() and
mid.getAp() instanceof AccessPathNil and
sink.getConfiguration() = unbind(mid.getConfiguration()) and
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
result = sink
)
}
@@ -3298,7 +3320,7 @@ private predicate pathThroughCallable0(
) {
exists(CallContext innercc, SummaryCtx sc |
pathIntoCallable(mid, _, cc, innercc, sc, call) and
paramFlowsThrough(kind, innercc, sc, ap, apa, unbind(mid.getConfiguration()))
paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration()))
)
}
@@ -3310,7 +3332,7 @@ pragma[noinline]
private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) {
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
out = getAnOutNodeFlow(kind, call, apa, unbind(mid.getConfiguration()))
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
)
}
@@ -3433,8 +3455,8 @@ private module FlowExploration {
private predicate callableExtStepFwd(TCallableExt ce1, TCallableExt ce2) {
exists(DataFlowCallable c1, DataFlowCallable c2, Configuration config |
callableStep(c1, c2, config) and
ce1 = TCallable(c1, config) and
ce2 = TCallable(c2, unbind(config))
ce1 = TCallable(c1, pragma[only_bind_into](config)) and
ce2 = TCallable(c2, pragma[only_bind_into](config))
)
or
exists(Node n, Configuration config |

View File

@@ -444,8 +444,8 @@ private module Stage1 {
// read
exists(Node mid, Content c |
read(node, c, mid) and
fwdFlowConsCand(c, unbind(config)) and
revFlow(mid, toReturn, config)
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
revFlow(mid, toReturn, pragma[only_bind_into](config))
)
or
// flow into a callable
@@ -471,18 +471,18 @@ private module Stage1 {
pragma[nomagic]
private predicate revFlowConsCand(Content c, Configuration config) {
exists(Node mid, Node node |
fwdFlow(node, unbind(config)) and
fwdFlow(node, pragma[only_bind_into](config)) and
read(node, c, mid) and
fwdFlowConsCand(c, unbind(config)) and
revFlow(mid, _, config)
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
)
}
pragma[nomagic]
private predicate revFlowStore(Content c, Node node, boolean toReturn, Configuration config) {
exists(Node mid, TypedContent tc |
revFlow(mid, toReturn, config) and
fwdFlowConsCand(c, unbind(config)) and
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
store(node, tc, mid, _) and
c = tc.getContent()
)
@@ -552,8 +552,8 @@ private module Stage1 {
Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
) {
exists(Content c |
revFlowIsReadAndStored(c, config) and
revFlow(node2, unbind(config)) and
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(node2, pragma[only_bind_into](config)) and
store(node1, tc, node2, contentType) and
c = tc.getContent() and
exists(ap1)
@@ -562,8 +562,8 @@ private module Stage1 {
pragma[nomagic]
predicate readStepCand(Node n1, Content c, Node n2, Configuration config) {
revFlowIsReadAndStored(c, config) and
revFlow(n2, unbind(config)) and
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(n2, pragma[only_bind_into](config)) and
read(n1, c, n2)
}
@@ -626,9 +626,6 @@ private module Stage1 {
/* End: Stage 1 logic. */
}
bindingset[result, b]
private boolean unbindBool(boolean b) { result != b.booleanNot() }
pragma[noinline]
private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
Stage1::revFlow(node2, config) and
@@ -864,16 +861,16 @@ private module Stage2 {
)
or
exists(Node mid |
fwdFlow(mid, _, _, ap, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone()
)
or
exists(Node mid, ApNil nil |
fwdFlow(mid, _, _, nil, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone() and
@@ -1045,9 +1042,9 @@ private module Stage2 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, config) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
@@ -1059,9 +1056,9 @@ private module Stage2 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(mid, _, _, nil, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
@@ -1114,9 +1111,10 @@ private module Stage2 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(Node mid |
exists(Node mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
readStepFwd(_, cons, c, mid, tail, config)
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
)
}
@@ -1182,9 +1180,10 @@ private module Stage2 {
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, ap2, config) and
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
revFlowStore(ap1, c, /*unbind*/ unbindBool(ap2), _, _, _, _, _, unbind(config))
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
pragma[only_bind_into](config))
)
}
@@ -1240,8 +1239,8 @@ private predicate flowOutOfCallNodeCand2(
DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, config) and
Stage2::revFlow(node1, unbind(config))
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlow(node1, pragma[only_bind_into](config))
}
pragma[nomagic]
@@ -1250,8 +1249,8 @@ private predicate flowIntoCallNodeCand2(
Configuration config
) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, config) and
Stage2::revFlow(node1, unbind(config))
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlow(node1, pragma[only_bind_into](config))
}
private module LocalFlowBigStep {
@@ -1306,8 +1305,8 @@ private module LocalFlowBigStep {
pragma[noinline]
private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) {
additionalLocalFlowStepNodeCand1(node1, node2, config) and
Stage2::revFlow(node1, _, _, false, config) and
Stage2::revFlow(node2, _, _, false, unbind(config))
Stage2::revFlow(node1, _, _, false, pragma[only_bind_into](config)) and
Stage2::revFlow(node2, _, _, false, pragma[only_bind_into](config))
}
/**
@@ -1324,7 +1323,7 @@ private module LocalFlowBigStep {
) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, config) and
localFlowEntry(node1, pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and
@@ -1337,22 +1336,22 @@ private module LocalFlowBigStep {
node1 != node2 and
cc.relevantFor(getNodeEnclosingCallable(node1)) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, unbind(config))
Stage2::revFlow(node2, pragma[only_bind_into](config))
or
exists(Node mid |
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
localFlowStepPlus(node1, mid, preservesValue, t, pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, unbind(config))
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
or
exists(Node mid |
localFlowStepPlus(node1, mid, _, _, config, cc) and
localFlowStepPlus(node1, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = getNodeType(node2) and
Stage2::revFlow(node2, unbind(config))
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
)
}
@@ -1459,6 +1458,13 @@ private module Stage3 {
PrevStage::revFlow(node, _, _, apa, config)
}
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
exists(ApApprox apa0 |
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
)
}
/**
* Holds if `node` is reachable with access path `ap` from a source in the
* configuration `config`.
@@ -1470,7 +1476,7 @@ private module Stage3 {
pragma[nomagic]
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindBool(getApprox(ap)), config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
@@ -1494,16 +1500,16 @@ private module Stage3 {
)
or
exists(Node mid |
fwdFlow(mid, _, _, ap, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone()
)
or
exists(Node mid, ApNil nil |
fwdFlow(mid, _, _, nil, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone() and
@@ -1548,7 +1554,7 @@ private module Stage3 {
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindBool(getApprox(ap1)), tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType)
)
}
@@ -1627,7 +1633,7 @@ private module Stage3 {
) {
exists(ParameterNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindBool(getApprox(ap)), config)
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
}
@@ -1675,9 +1681,9 @@ private module Stage3 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, config) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
@@ -1689,9 +1695,9 @@ private module Stage3 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(mid, _, _, nil, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
@@ -1744,9 +1750,10 @@ private module Stage3 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(Node mid |
exists(Node mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
readStepFwd(_, cons, c, mid, tail, config)
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
)
}
@@ -1812,9 +1819,10 @@ private module Stage3 {
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, ap2, config) and
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
pragma[only_bind_into](config))
)
}
@@ -2125,8 +2133,11 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
localFlowEntry(node, config) and
result = getLocalCallContext(cc, getNodeEnclosingCallable(node))
exists(Cc cc0 |
cc = pragma[only_bind_into](cc0) and
localFlowEntry(node, config) and
result = getLocalCallContext(cc0, getNodeEnclosingCallable(node))
)
}
private predicate localStep(
@@ -2141,8 +2152,8 @@ private module Stage4 {
Configuration config
) {
flowOutOfCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, config) and
PrevStage::revFlow(node1, _, _, _, unbind(config))
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
}
pragma[nomagic]
@@ -2151,8 +2162,8 @@ private module Stage4 {
Configuration config
) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, config) and
PrevStage::revFlow(node1, _, _, _, unbind(config))
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
}
bindingset[node, ap]
@@ -2167,6 +2178,13 @@ private module Stage4 {
PrevStage::revFlow(node, _, _, apa, config)
}
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
exists(ApApprox apa0 |
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
)
}
/**
* Holds if `node` is reachable with access path `ap` from a source in the
* configuration `config`.
@@ -2178,7 +2196,7 @@ private module Stage4 {
pragma[nomagic]
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, getApprox(ap), config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
@@ -2202,16 +2220,16 @@ private module Stage4 {
)
or
exists(Node mid |
fwdFlow(mid, _, _, ap, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone()
)
or
exists(Node mid, ApNil nil |
fwdFlow(mid, _, _, nil, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone() and
@@ -2256,7 +2274,7 @@ private module Stage4 {
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType)
)
}
@@ -2335,7 +2353,7 @@ private module Stage4 {
) {
exists(ParameterNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
}
@@ -2383,9 +2401,9 @@ private module Stage4 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, config) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
@@ -2397,9 +2415,9 @@ private module Stage4 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(mid, _, _, nil, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
@@ -2452,9 +2470,10 @@ private module Stage4 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(Node mid |
exists(Node mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
readStepFwd(_, cons, c, mid, tail, config)
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
)
}
@@ -2520,9 +2539,10 @@ private module Stage4 {
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, ap2, config) and
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
pragma[only_bind_into](config))
)
}
@@ -2574,7 +2594,9 @@ private module Stage4 {
}
bindingset[conf, result]
private Configuration unbind(Configuration conf) { result >= conf and result <= conf }
private Configuration unbindConf(Configuration conf) {
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
}
private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration config) {
exists(DataFlowCallable c, AccessPathApprox apa0 |
@@ -2744,13 +2766,13 @@ private newtype TPathNode =
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
pathStep(mid, node, cc, sc, ap) and
config = mid.getConfiguration() and
Stage4::revFlow(node, _, _, ap.getApprox(), unbind(config))
pragma[only_bind_into](config) = mid.getConfiguration() and
Stage4::revFlow(node, _, _, ap.getApprox(), pragma[only_bind_into](config))
)
} or
TPathNodeSink(Node node, Configuration config) {
config.isSink(node) and
Stage4::revFlow(node, unbind(config)) and
pragma[only_bind_into](config).isSink(node) and
Stage4::revFlow(node, pragma[only_bind_into](config)) and
(
// A sink that is also a source ...
config.isSource(node)
@@ -2758,7 +2780,7 @@ private newtype TPathNode =
// ... or a sink that can be reached from a source
exists(PathNodeMid mid |
pathStep(mid, node, _, _, TAccessPathNil(_)) and
config = unbind(mid.getConfiguration())
pragma[only_bind_into](config) = mid.getConfiguration()
)
)
}
@@ -3055,7 +3077,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
private PathNodeMid getSuccMid() {
pathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx(), result.getAp()) and
result.getConfiguration() = unbind(this.getConfiguration())
result.getConfiguration() = unbindConf(this.getConfiguration())
}
override PathNodeImpl getASuccessorImpl() {
@@ -3067,7 +3089,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
mid = getSuccMid() and
mid.getNode() = sink.getNode() and
mid.getAp() instanceof AccessPathNil and
sink.getConfiguration() = unbind(mid.getConfiguration()) and
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
result = sink
)
}
@@ -3298,7 +3320,7 @@ private predicate pathThroughCallable0(
) {
exists(CallContext innercc, SummaryCtx sc |
pathIntoCallable(mid, _, cc, innercc, sc, call) and
paramFlowsThrough(kind, innercc, sc, ap, apa, unbind(mid.getConfiguration()))
paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration()))
)
}
@@ -3310,7 +3332,7 @@ pragma[noinline]
private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) {
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
out = getAnOutNodeFlow(kind, call, apa, unbind(mid.getConfiguration()))
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
)
}
@@ -3433,8 +3455,8 @@ private module FlowExploration {
private predicate callableExtStepFwd(TCallableExt ce1, TCallableExt ce2) {
exists(DataFlowCallable c1, DataFlowCallable c2, Configuration config |
callableStep(c1, c2, config) and
ce1 = TCallable(c1, config) and
ce2 = TCallable(c2, unbind(config))
ce1 = TCallable(c1, pragma[only_bind_into](config)) and
ce2 = TCallable(c2, pragma[only_bind_into](config))
)
or
exists(Node n, Configuration config |

View File

@@ -444,8 +444,8 @@ private module Stage1 {
// read
exists(Node mid, Content c |
read(node, c, mid) and
fwdFlowConsCand(c, unbind(config)) and
revFlow(mid, toReturn, config)
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
revFlow(mid, toReturn, pragma[only_bind_into](config))
)
or
// flow into a callable
@@ -471,18 +471,18 @@ private module Stage1 {
pragma[nomagic]
private predicate revFlowConsCand(Content c, Configuration config) {
exists(Node mid, Node node |
fwdFlow(node, unbind(config)) and
fwdFlow(node, pragma[only_bind_into](config)) and
read(node, c, mid) and
fwdFlowConsCand(c, unbind(config)) and
revFlow(mid, _, config)
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
)
}
pragma[nomagic]
private predicate revFlowStore(Content c, Node node, boolean toReturn, Configuration config) {
exists(Node mid, TypedContent tc |
revFlow(mid, toReturn, config) and
fwdFlowConsCand(c, unbind(config)) and
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
store(node, tc, mid, _) and
c = tc.getContent()
)
@@ -552,8 +552,8 @@ private module Stage1 {
Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
) {
exists(Content c |
revFlowIsReadAndStored(c, config) and
revFlow(node2, unbind(config)) and
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(node2, pragma[only_bind_into](config)) and
store(node1, tc, node2, contentType) and
c = tc.getContent() and
exists(ap1)
@@ -562,8 +562,8 @@ private module Stage1 {
pragma[nomagic]
predicate readStepCand(Node n1, Content c, Node n2, Configuration config) {
revFlowIsReadAndStored(c, config) and
revFlow(n2, unbind(config)) and
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(n2, pragma[only_bind_into](config)) and
read(n1, c, n2)
}
@@ -626,9 +626,6 @@ private module Stage1 {
/* End: Stage 1 logic. */
}
bindingset[result, b]
private boolean unbindBool(boolean b) { result != b.booleanNot() }
pragma[noinline]
private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
Stage1::revFlow(node2, config) and
@@ -864,16 +861,16 @@ private module Stage2 {
)
or
exists(Node mid |
fwdFlow(mid, _, _, ap, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone()
)
or
exists(Node mid, ApNil nil |
fwdFlow(mid, _, _, nil, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone() and
@@ -1045,9 +1042,9 @@ private module Stage2 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, config) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
@@ -1059,9 +1056,9 @@ private module Stage2 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(mid, _, _, nil, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
@@ -1114,9 +1111,10 @@ private module Stage2 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(Node mid |
exists(Node mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
readStepFwd(_, cons, c, mid, tail, config)
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
)
}
@@ -1182,9 +1180,10 @@ private module Stage2 {
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, ap2, config) and
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
revFlowStore(ap1, c, /*unbind*/ unbindBool(ap2), _, _, _, _, _, unbind(config))
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
pragma[only_bind_into](config))
)
}
@@ -1240,8 +1239,8 @@ private predicate flowOutOfCallNodeCand2(
DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, config) and
Stage2::revFlow(node1, unbind(config))
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlow(node1, pragma[only_bind_into](config))
}
pragma[nomagic]
@@ -1250,8 +1249,8 @@ private predicate flowIntoCallNodeCand2(
Configuration config
) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, config) and
Stage2::revFlow(node1, unbind(config))
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlow(node1, pragma[only_bind_into](config))
}
private module LocalFlowBigStep {
@@ -1306,8 +1305,8 @@ private module LocalFlowBigStep {
pragma[noinline]
private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) {
additionalLocalFlowStepNodeCand1(node1, node2, config) and
Stage2::revFlow(node1, _, _, false, config) and
Stage2::revFlow(node2, _, _, false, unbind(config))
Stage2::revFlow(node1, _, _, false, pragma[only_bind_into](config)) and
Stage2::revFlow(node2, _, _, false, pragma[only_bind_into](config))
}
/**
@@ -1324,7 +1323,7 @@ private module LocalFlowBigStep {
) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, config) and
localFlowEntry(node1, pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and
@@ -1337,22 +1336,22 @@ private module LocalFlowBigStep {
node1 != node2 and
cc.relevantFor(getNodeEnclosingCallable(node1)) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, unbind(config))
Stage2::revFlow(node2, pragma[only_bind_into](config))
or
exists(Node mid |
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
localFlowStepPlus(node1, mid, preservesValue, t, pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, unbind(config))
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
or
exists(Node mid |
localFlowStepPlus(node1, mid, _, _, config, cc) and
localFlowStepPlus(node1, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = getNodeType(node2) and
Stage2::revFlow(node2, unbind(config))
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
)
}
@@ -1459,6 +1458,13 @@ private module Stage3 {
PrevStage::revFlow(node, _, _, apa, config)
}
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
exists(ApApprox apa0 |
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
)
}
/**
* Holds if `node` is reachable with access path `ap` from a source in the
* configuration `config`.
@@ -1470,7 +1476,7 @@ private module Stage3 {
pragma[nomagic]
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindBool(getApprox(ap)), config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
@@ -1494,16 +1500,16 @@ private module Stage3 {
)
or
exists(Node mid |
fwdFlow(mid, _, _, ap, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone()
)
or
exists(Node mid, ApNil nil |
fwdFlow(mid, _, _, nil, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone() and
@@ -1548,7 +1554,7 @@ private module Stage3 {
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindBool(getApprox(ap1)), tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType)
)
}
@@ -1627,7 +1633,7 @@ private module Stage3 {
) {
exists(ParameterNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindBool(getApprox(ap)), config)
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
}
@@ -1675,9 +1681,9 @@ private module Stage3 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, config) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
@@ -1689,9 +1695,9 @@ private module Stage3 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(mid, _, _, nil, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
@@ -1744,9 +1750,10 @@ private module Stage3 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(Node mid |
exists(Node mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
readStepFwd(_, cons, c, mid, tail, config)
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
)
}
@@ -1812,9 +1819,10 @@ private module Stage3 {
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, ap2, config) and
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
pragma[only_bind_into](config))
)
}
@@ -2125,8 +2133,11 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
localFlowEntry(node, config) and
result = getLocalCallContext(cc, getNodeEnclosingCallable(node))
exists(Cc cc0 |
cc = pragma[only_bind_into](cc0) and
localFlowEntry(node, config) and
result = getLocalCallContext(cc0, getNodeEnclosingCallable(node))
)
}
private predicate localStep(
@@ -2141,8 +2152,8 @@ private module Stage4 {
Configuration config
) {
flowOutOfCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, config) and
PrevStage::revFlow(node1, _, _, _, unbind(config))
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
}
pragma[nomagic]
@@ -2151,8 +2162,8 @@ private module Stage4 {
Configuration config
) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, config) and
PrevStage::revFlow(node1, _, _, _, unbind(config))
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
}
bindingset[node, ap]
@@ -2167,6 +2178,13 @@ private module Stage4 {
PrevStage::revFlow(node, _, _, apa, config)
}
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
exists(ApApprox apa0 |
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
)
}
/**
* Holds if `node` is reachable with access path `ap` from a source in the
* configuration `config`.
@@ -2178,7 +2196,7 @@ private module Stage4 {
pragma[nomagic]
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, getApprox(ap), config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
@@ -2202,16 +2220,16 @@ private module Stage4 {
)
or
exists(Node mid |
fwdFlow(mid, _, _, ap, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone()
)
or
exists(Node mid, ApNil nil |
fwdFlow(mid, _, _, nil, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone() and
@@ -2256,7 +2274,7 @@ private module Stage4 {
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType)
)
}
@@ -2335,7 +2353,7 @@ private module Stage4 {
) {
exists(ParameterNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
}
@@ -2383,9 +2401,9 @@ private module Stage4 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, config) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
@@ -2397,9 +2415,9 @@ private module Stage4 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(mid, _, _, nil, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
@@ -2452,9 +2470,10 @@ private module Stage4 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(Node mid |
exists(Node mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
readStepFwd(_, cons, c, mid, tail, config)
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
)
}
@@ -2520,9 +2539,10 @@ private module Stage4 {
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, ap2, config) and
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
pragma[only_bind_into](config))
)
}
@@ -2574,7 +2594,9 @@ private module Stage4 {
}
bindingset[conf, result]
private Configuration unbind(Configuration conf) { result >= conf and result <= conf }
private Configuration unbindConf(Configuration conf) {
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
}
private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration config) {
exists(DataFlowCallable c, AccessPathApprox apa0 |
@@ -2744,13 +2766,13 @@ private newtype TPathNode =
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
pathStep(mid, node, cc, sc, ap) and
config = mid.getConfiguration() and
Stage4::revFlow(node, _, _, ap.getApprox(), unbind(config))
pragma[only_bind_into](config) = mid.getConfiguration() and
Stage4::revFlow(node, _, _, ap.getApprox(), pragma[only_bind_into](config))
)
} or
TPathNodeSink(Node node, Configuration config) {
config.isSink(node) and
Stage4::revFlow(node, unbind(config)) and
pragma[only_bind_into](config).isSink(node) and
Stage4::revFlow(node, pragma[only_bind_into](config)) and
(
// A sink that is also a source ...
config.isSource(node)
@@ -2758,7 +2780,7 @@ private newtype TPathNode =
// ... or a sink that can be reached from a source
exists(PathNodeMid mid |
pathStep(mid, node, _, _, TAccessPathNil(_)) and
config = unbind(mid.getConfiguration())
pragma[only_bind_into](config) = mid.getConfiguration()
)
)
}
@@ -3055,7 +3077,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
private PathNodeMid getSuccMid() {
pathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx(), result.getAp()) and
result.getConfiguration() = unbind(this.getConfiguration())
result.getConfiguration() = unbindConf(this.getConfiguration())
}
override PathNodeImpl getASuccessorImpl() {
@@ -3067,7 +3089,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
mid = getSuccMid() and
mid.getNode() = sink.getNode() and
mid.getAp() instanceof AccessPathNil and
sink.getConfiguration() = unbind(mid.getConfiguration()) and
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
result = sink
)
}
@@ -3298,7 +3320,7 @@ private predicate pathThroughCallable0(
) {
exists(CallContext innercc, SummaryCtx sc |
pathIntoCallable(mid, _, cc, innercc, sc, call) and
paramFlowsThrough(kind, innercc, sc, ap, apa, unbind(mid.getConfiguration()))
paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration()))
)
}
@@ -3310,7 +3332,7 @@ pragma[noinline]
private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) {
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
out = getAnOutNodeFlow(kind, call, apa, unbind(mid.getConfiguration()))
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
)
}
@@ -3433,8 +3455,8 @@ private module FlowExploration {
private predicate callableExtStepFwd(TCallableExt ce1, TCallableExt ce2) {
exists(DataFlowCallable c1, DataFlowCallable c2, Configuration config |
callableStep(c1, c2, config) and
ce1 = TCallable(c1, config) and
ce2 = TCallable(c2, unbind(config))
ce1 = TCallable(c1, pragma[only_bind_into](config)) and
ce2 = TCallable(c2, pragma[only_bind_into](config))
)
or
exists(Node n, Configuration config |

View File

@@ -444,8 +444,8 @@ private module Stage1 {
// read
exists(Node mid, Content c |
read(node, c, mid) and
fwdFlowConsCand(c, unbind(config)) and
revFlow(mid, toReturn, config)
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
revFlow(mid, toReturn, pragma[only_bind_into](config))
)
or
// flow into a callable
@@ -471,18 +471,18 @@ private module Stage1 {
pragma[nomagic]
private predicate revFlowConsCand(Content c, Configuration config) {
exists(Node mid, Node node |
fwdFlow(node, unbind(config)) and
fwdFlow(node, pragma[only_bind_into](config)) and
read(node, c, mid) and
fwdFlowConsCand(c, unbind(config)) and
revFlow(mid, _, config)
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
)
}
pragma[nomagic]
private predicate revFlowStore(Content c, Node node, boolean toReturn, Configuration config) {
exists(Node mid, TypedContent tc |
revFlow(mid, toReturn, config) and
fwdFlowConsCand(c, unbind(config)) and
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
store(node, tc, mid, _) and
c = tc.getContent()
)
@@ -552,8 +552,8 @@ private module Stage1 {
Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
) {
exists(Content c |
revFlowIsReadAndStored(c, config) and
revFlow(node2, unbind(config)) and
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(node2, pragma[only_bind_into](config)) and
store(node1, tc, node2, contentType) and
c = tc.getContent() and
exists(ap1)
@@ -562,8 +562,8 @@ private module Stage1 {
pragma[nomagic]
predicate readStepCand(Node n1, Content c, Node n2, Configuration config) {
revFlowIsReadAndStored(c, config) and
revFlow(n2, unbind(config)) and
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(n2, pragma[only_bind_into](config)) and
read(n1, c, n2)
}
@@ -626,9 +626,6 @@ private module Stage1 {
/* End: Stage 1 logic. */
}
bindingset[result, b]
private boolean unbindBool(boolean b) { result != b.booleanNot() }
pragma[noinline]
private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
Stage1::revFlow(node2, config) and
@@ -864,16 +861,16 @@ private module Stage2 {
)
or
exists(Node mid |
fwdFlow(mid, _, _, ap, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone()
)
or
exists(Node mid, ApNil nil |
fwdFlow(mid, _, _, nil, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone() and
@@ -1045,9 +1042,9 @@ private module Stage2 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, config) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
@@ -1059,9 +1056,9 @@ private module Stage2 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(mid, _, _, nil, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
@@ -1114,9 +1111,10 @@ private module Stage2 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(Node mid |
exists(Node mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
readStepFwd(_, cons, c, mid, tail, config)
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
)
}
@@ -1182,9 +1180,10 @@ private module Stage2 {
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, ap2, config) and
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
revFlowStore(ap1, c, /*unbind*/ unbindBool(ap2), _, _, _, _, _, unbind(config))
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
pragma[only_bind_into](config))
)
}
@@ -1240,8 +1239,8 @@ private predicate flowOutOfCallNodeCand2(
DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, config) and
Stage2::revFlow(node1, unbind(config))
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlow(node1, pragma[only_bind_into](config))
}
pragma[nomagic]
@@ -1250,8 +1249,8 @@ private predicate flowIntoCallNodeCand2(
Configuration config
) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, config) and
Stage2::revFlow(node1, unbind(config))
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlow(node1, pragma[only_bind_into](config))
}
private module LocalFlowBigStep {
@@ -1306,8 +1305,8 @@ private module LocalFlowBigStep {
pragma[noinline]
private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) {
additionalLocalFlowStepNodeCand1(node1, node2, config) and
Stage2::revFlow(node1, _, _, false, config) and
Stage2::revFlow(node2, _, _, false, unbind(config))
Stage2::revFlow(node1, _, _, false, pragma[only_bind_into](config)) and
Stage2::revFlow(node2, _, _, false, pragma[only_bind_into](config))
}
/**
@@ -1324,7 +1323,7 @@ private module LocalFlowBigStep {
) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, config) and
localFlowEntry(node1, pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and
@@ -1337,22 +1336,22 @@ private module LocalFlowBigStep {
node1 != node2 and
cc.relevantFor(getNodeEnclosingCallable(node1)) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, unbind(config))
Stage2::revFlow(node2, pragma[only_bind_into](config))
or
exists(Node mid |
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
localFlowStepPlus(node1, mid, preservesValue, t, pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, unbind(config))
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
or
exists(Node mid |
localFlowStepPlus(node1, mid, _, _, config, cc) and
localFlowStepPlus(node1, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = getNodeType(node2) and
Stage2::revFlow(node2, unbind(config))
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
)
}
@@ -1459,6 +1458,13 @@ private module Stage3 {
PrevStage::revFlow(node, _, _, apa, config)
}
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
exists(ApApprox apa0 |
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
)
}
/**
* Holds if `node` is reachable with access path `ap` from a source in the
* configuration `config`.
@@ -1470,7 +1476,7 @@ private module Stage3 {
pragma[nomagic]
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindBool(getApprox(ap)), config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
@@ -1494,16 +1500,16 @@ private module Stage3 {
)
or
exists(Node mid |
fwdFlow(mid, _, _, ap, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone()
)
or
exists(Node mid, ApNil nil |
fwdFlow(mid, _, _, nil, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone() and
@@ -1548,7 +1554,7 @@ private module Stage3 {
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindBool(getApprox(ap1)), tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType)
)
}
@@ -1627,7 +1633,7 @@ private module Stage3 {
) {
exists(ParameterNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindBool(getApprox(ap)), config)
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
}
@@ -1675,9 +1681,9 @@ private module Stage3 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, config) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
@@ -1689,9 +1695,9 @@ private module Stage3 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(mid, _, _, nil, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
@@ -1744,9 +1750,10 @@ private module Stage3 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(Node mid |
exists(Node mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
readStepFwd(_, cons, c, mid, tail, config)
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
)
}
@@ -1812,9 +1819,10 @@ private module Stage3 {
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, ap2, config) and
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
pragma[only_bind_into](config))
)
}
@@ -2125,8 +2133,11 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
localFlowEntry(node, config) and
result = getLocalCallContext(cc, getNodeEnclosingCallable(node))
exists(Cc cc0 |
cc = pragma[only_bind_into](cc0) and
localFlowEntry(node, config) and
result = getLocalCallContext(cc0, getNodeEnclosingCallable(node))
)
}
private predicate localStep(
@@ -2141,8 +2152,8 @@ private module Stage4 {
Configuration config
) {
flowOutOfCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, config) and
PrevStage::revFlow(node1, _, _, _, unbind(config))
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
}
pragma[nomagic]
@@ -2151,8 +2162,8 @@ private module Stage4 {
Configuration config
) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, config) and
PrevStage::revFlow(node1, _, _, _, unbind(config))
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
}
bindingset[node, ap]
@@ -2167,6 +2178,13 @@ private module Stage4 {
PrevStage::revFlow(node, _, _, apa, config)
}
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
exists(ApApprox apa0 |
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
)
}
/**
* Holds if `node` is reachable with access path `ap` from a source in the
* configuration `config`.
@@ -2178,7 +2196,7 @@ private module Stage4 {
pragma[nomagic]
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, getApprox(ap), config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
@@ -2202,16 +2220,16 @@ private module Stage4 {
)
or
exists(Node mid |
fwdFlow(mid, _, _, ap, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone()
)
or
exists(Node mid, ApNil nil |
fwdFlow(mid, _, _, nil, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone() and
@@ -2256,7 +2274,7 @@ private module Stage4 {
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType)
)
}
@@ -2335,7 +2353,7 @@ private module Stage4 {
) {
exists(ParameterNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
}
@@ -2383,9 +2401,9 @@ private module Stage4 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, config) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
@@ -2397,9 +2415,9 @@ private module Stage4 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(mid, _, _, nil, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
@@ -2452,9 +2470,10 @@ private module Stage4 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(Node mid |
exists(Node mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
readStepFwd(_, cons, c, mid, tail, config)
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
)
}
@@ -2520,9 +2539,10 @@ private module Stage4 {
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, ap2, config) and
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
pragma[only_bind_into](config))
)
}
@@ -2574,7 +2594,9 @@ private module Stage4 {
}
bindingset[conf, result]
private Configuration unbind(Configuration conf) { result >= conf and result <= conf }
private Configuration unbindConf(Configuration conf) {
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
}
private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration config) {
exists(DataFlowCallable c, AccessPathApprox apa0 |
@@ -2744,13 +2766,13 @@ private newtype TPathNode =
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
pathStep(mid, node, cc, sc, ap) and
config = mid.getConfiguration() and
Stage4::revFlow(node, _, _, ap.getApprox(), unbind(config))
pragma[only_bind_into](config) = mid.getConfiguration() and
Stage4::revFlow(node, _, _, ap.getApprox(), pragma[only_bind_into](config))
)
} or
TPathNodeSink(Node node, Configuration config) {
config.isSink(node) and
Stage4::revFlow(node, unbind(config)) and
pragma[only_bind_into](config).isSink(node) and
Stage4::revFlow(node, pragma[only_bind_into](config)) and
(
// A sink that is also a source ...
config.isSource(node)
@@ -2758,7 +2780,7 @@ private newtype TPathNode =
// ... or a sink that can be reached from a source
exists(PathNodeMid mid |
pathStep(mid, node, _, _, TAccessPathNil(_)) and
config = unbind(mid.getConfiguration())
pragma[only_bind_into](config) = mid.getConfiguration()
)
)
}
@@ -3055,7 +3077,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
private PathNodeMid getSuccMid() {
pathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx(), result.getAp()) and
result.getConfiguration() = unbind(this.getConfiguration())
result.getConfiguration() = unbindConf(this.getConfiguration())
}
override PathNodeImpl getASuccessorImpl() {
@@ -3067,7 +3089,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
mid = getSuccMid() and
mid.getNode() = sink.getNode() and
mid.getAp() instanceof AccessPathNil and
sink.getConfiguration() = unbind(mid.getConfiguration()) and
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
result = sink
)
}
@@ -3298,7 +3320,7 @@ private predicate pathThroughCallable0(
) {
exists(CallContext innercc, SummaryCtx sc |
pathIntoCallable(mid, _, cc, innercc, sc, call) and
paramFlowsThrough(kind, innercc, sc, ap, apa, unbind(mid.getConfiguration()))
paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration()))
)
}
@@ -3310,7 +3332,7 @@ pragma[noinline]
private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) {
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
out = getAnOutNodeFlow(kind, call, apa, unbind(mid.getConfiguration()))
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
)
}
@@ -3433,8 +3455,8 @@ private module FlowExploration {
private predicate callableExtStepFwd(TCallableExt ce1, TCallableExt ce2) {
exists(DataFlowCallable c1, DataFlowCallable c2, Configuration config |
callableStep(c1, c2, config) and
ce1 = TCallable(c1, config) and
ce2 = TCallable(c2, unbind(config))
ce1 = TCallable(c1, pragma[only_bind_into](config)) and
ce2 = TCallable(c2, pragma[only_bind_into](config))
)
or
exists(Node n, Configuration config |

View File

@@ -26,15 +26,243 @@ predicate accessPathCostLimits(int apLimit, int tupleLimit) {
tupleLimit = 1000
}
/**
* Provides a simple data-flow analysis for resolving lambda calls. The analysis
* currently excludes read-steps, store-steps, and flow-through.
*
* The analysis uses non-linear recursion: When computing a flow path in or out
* of a call, we use the results of the analysis recursively to resolve lamba
* calls. For this reason, we cannot reuse the code from `DataFlowImpl.qll` directly.
*/
private module LambdaFlow {
private predicate viableParamNonLambda(DataFlowCall call, int i, ParameterNode p) {
p.isParameterOf(viableCallable(call), i)
}
private predicate viableParamLambda(DataFlowCall call, int i, ParameterNode p) {
p.isParameterOf(viableCallableLambda(call, _), i)
}
private predicate viableParamArgNonLambda(DataFlowCall call, ParameterNode p, ArgumentNode arg) {
exists(int i |
viableParamNonLambda(call, i, p) and
arg.argumentOf(call, i)
)
}
private predicate viableParamArgLambda(DataFlowCall call, ParameterNode p, ArgumentNode arg) {
exists(int i |
viableParamLambda(call, i, p) and
arg.argumentOf(call, i)
)
}
private newtype TReturnPositionSimple =
TReturnPositionSimple0(DataFlowCallable c, ReturnKind kind) {
exists(ReturnNode ret |
c = getNodeEnclosingCallable(ret) and
kind = ret.getKind()
)
}
pragma[noinline]
private TReturnPositionSimple getReturnPositionSimple(ReturnNode ret, ReturnKind kind) {
result = TReturnPositionSimple0(getNodeEnclosingCallable(ret), kind)
}
pragma[nomagic]
private TReturnPositionSimple viableReturnPosNonLambda(DataFlowCall call, ReturnKind kind) {
result = TReturnPositionSimple0(viableCallable(call), kind)
}
pragma[nomagic]
private TReturnPositionSimple viableReturnPosLambda(
DataFlowCall call, DataFlowCallOption lastCall, ReturnKind kind
) {
result = TReturnPositionSimple0(viableCallableLambda(call, lastCall), kind)
}
private predicate viableReturnPosOutNonLambda(
DataFlowCall call, TReturnPositionSimple pos, OutNode out
) {
exists(ReturnKind kind |
pos = viableReturnPosNonLambda(call, kind) and
out = getAnOutNode(call, kind)
)
}
private predicate viableReturnPosOutLambda(
DataFlowCall call, DataFlowCallOption lastCall, TReturnPositionSimple pos, OutNode out
) {
exists(ReturnKind kind |
pos = viableReturnPosLambda(call, lastCall, kind) and
out = getAnOutNode(call, kind)
)
}
/**
* Holds if data can flow (inter-procedurally) from `node` (of type `t`) to
* the lambda call `lambdaCall`.
*
* The parameter `toReturn` indicates whether the path from `node` to
* `lambdaCall` goes through a return, and `toJump` whether the path goes
* through a jump step.
*
* The call context `lastCall` records the last call on the path from `node`
* to `lambdaCall`, if any. That is, `lastCall` is able to target the enclosing
* callable of `lambdaCall`.
*/
pragma[nomagic]
predicate revLambdaFlow(
DataFlowCall lambdaCall, LambdaCallKind kind, Node node, DataFlowType t, boolean toReturn,
boolean toJump, DataFlowCallOption lastCall
) {
revLambdaFlow0(lambdaCall, kind, node, t, toReturn, toJump, lastCall) and
if node instanceof CastNode or node instanceof ArgumentNode or node instanceof ReturnNode
then compatibleTypes(t, getNodeType(node))
else any()
}
pragma[nomagic]
predicate revLambdaFlow0(
DataFlowCall lambdaCall, LambdaCallKind kind, Node node, DataFlowType t, boolean toReturn,
boolean toJump, DataFlowCallOption lastCall
) {
lambdaCall(lambdaCall, kind, node) and
t = getNodeType(node) and
toReturn = false and
toJump = false and
lastCall = TDataFlowCallNone()
or
// local flow
exists(Node mid, DataFlowType t0 |
revLambdaFlow(lambdaCall, kind, mid, t0, toReturn, toJump, lastCall)
|
simpleLocalFlowStep(node, mid) and
t = t0
or
exists(boolean preservesValue |
additionalLambdaFlowStep(node, mid, preservesValue) and
getNodeEnclosingCallable(node) = getNodeEnclosingCallable(mid)
|
preservesValue = false and
t = getNodeType(node)
or
preservesValue = true and
t = t0
)
)
or
// jump step
exists(Node mid, DataFlowType t0 |
revLambdaFlow(lambdaCall, kind, mid, t0, _, _, _) and
toReturn = false and
toJump = true and
lastCall = TDataFlowCallNone()
|
jumpStep(node, mid) and
t = t0
or
exists(boolean preservesValue |
additionalLambdaFlowStep(node, mid, preservesValue) and
getNodeEnclosingCallable(node) != getNodeEnclosingCallable(mid)
|
preservesValue = false and
t = getNodeType(node)
or
preservesValue = true and
t = t0
)
)
or
// flow into a callable
exists(ParameterNode p, DataFlowCallOption lastCall0, DataFlowCall call |
revLambdaFlowIn(lambdaCall, kind, p, t, toJump, lastCall0) and
(
if lastCall0 = TDataFlowCallNone() and toJump = false
then lastCall = TDataFlowCallSome(call)
else lastCall = lastCall0
) and
toReturn = false
|
viableParamArgNonLambda(call, p, node)
or
viableParamArgLambda(call, p, node) // non-linear recursion
)
or
// flow out of a callable
exists(TReturnPositionSimple pos |
revLambdaFlowOut(lambdaCall, kind, pos, t, toJump, lastCall) and
getReturnPositionSimple(node, node.(ReturnNode).getKind()) = pos and
toReturn = true
)
}
pragma[nomagic]
predicate revLambdaFlowOutLambdaCall(
DataFlowCall lambdaCall, LambdaCallKind kind, OutNode out, DataFlowType t, boolean toJump,
DataFlowCall call, DataFlowCallOption lastCall
) {
revLambdaFlow(lambdaCall, kind, out, t, _, toJump, lastCall) and
exists(ReturnKindExt rk |
out = rk.getAnOutNode(call) and
lambdaCall(call, _, _)
)
}
pragma[nomagic]
predicate revLambdaFlowOut(
DataFlowCall lambdaCall, LambdaCallKind kind, TReturnPositionSimple pos, DataFlowType t,
boolean toJump, DataFlowCallOption lastCall
) {
exists(DataFlowCall call, OutNode out |
revLambdaFlow(lambdaCall, kind, out, t, _, toJump, lastCall) and
viableReturnPosOutNonLambda(call, pos, out)
or
// non-linear recursion
revLambdaFlowOutLambdaCall(lambdaCall, kind, out, t, toJump, call, lastCall) and
viableReturnPosOutLambda(call, _, pos, out)
)
}
pragma[nomagic]
predicate revLambdaFlowIn(
DataFlowCall lambdaCall, LambdaCallKind kind, ParameterNode p, DataFlowType t, boolean toJump,
DataFlowCallOption lastCall
) {
revLambdaFlow(lambdaCall, kind, p, t, false, toJump, lastCall)
}
}
private DataFlowCallable viableCallableExt(DataFlowCall call) {
result = viableCallable(call)
or
result = viableCallableLambda(call, _)
}
cached
private module Cached {
/**
* Gets a viable target for the lambda call `call`.
*
* `lastCall` records the call required to reach `call` in order for the result
* to be a viable target, if any.
*/
cached
DataFlowCallable viableCallableLambda(DataFlowCall call, DataFlowCallOption lastCall) {
exists(Node creation, LambdaCallKind kind |
LambdaFlow::revLambdaFlow(call, kind, creation, _, _, _, lastCall) and
lambdaCreation(creation, kind, result)
)
}
/**
* Holds if `p` is the `i`th parameter of a viable dispatch target of `call`.
* The instance parameter is considered to have index `-1`.
*/
pragma[nomagic]
private predicate viableParam(DataFlowCall call, int i, ParameterNode p) {
p.isParameterOf(viableCallable(call), i)
p.isParameterOf(viableCallableExt(call), i)
}
/**
@@ -52,7 +280,7 @@ private module Cached {
pragma[nomagic]
private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) {
viableCallable(call) = result.getCallable() and
viableCallableExt(call) = result.getCallable() and
kind = result.getKind()
}
@@ -317,6 +545,35 @@ private module Cached {
cached
private module DispatchWithCallContext {
/**
* Holds if the set of viable implementations that can be called by `call`
* might be improved by knowing the call context.
*/
pragma[nomagic]
private predicate mayBenefitFromCallContextExt(DataFlowCall call, DataFlowCallable callable) {
mayBenefitFromCallContext(call, callable)
or
callable = call.getEnclosingCallable() and
exists(viableCallableLambda(call, TDataFlowCallSome(_)))
}
/**
* Gets a viable dispatch target of `call` in the context `ctx`. This is
* restricted to those `call`s for which a context might make a difference.
*/
pragma[nomagic]
private DataFlowCallable viableImplInCallContextExt(DataFlowCall call, DataFlowCall ctx) {
result = viableImplInCallContext(call, ctx)
or
result = viableCallableLambda(call, TDataFlowCallSome(ctx))
or
exists(DataFlowCallable enclosing |
mayBenefitFromCallContextExt(call, enclosing) and
enclosing = viableCallableExt(ctx) and
result = viableCallableLambda(call, TDataFlowCallNone())
)
}
/**
* Holds if the call context `ctx` reduces the set of viable run-time
* dispatch targets of call `call` in `c`.
@@ -324,10 +581,10 @@ private module Cached {
cached
predicate reducedViableImplInCallContext(DataFlowCall call, DataFlowCallable c, DataFlowCall ctx) {
exists(int tgts, int ctxtgts |
mayBenefitFromCallContext(call, c) and
c = viableCallable(ctx) and
ctxtgts = count(viableImplInCallContext(call, ctx)) and
tgts = strictcount(viableCallable(call)) and
mayBenefitFromCallContextExt(call, c) and
c = viableCallableExt(ctx) and
ctxtgts = count(viableImplInCallContextExt(call, ctx)) and
tgts = strictcount(viableCallableExt(call)) and
ctxtgts < tgts
)
}
@@ -339,7 +596,7 @@ private module Cached {
*/
cached
DataFlowCallable prunedViableImplInCallContext(DataFlowCall call, DataFlowCall ctx) {
result = viableImplInCallContext(call, ctx) and
result = viableImplInCallContextExt(call, ctx) and
reducedViableImplInCallContext(call, _, ctx)
}
@@ -351,10 +608,10 @@ private module Cached {
cached
predicate reducedViableImplInReturn(DataFlowCallable c, DataFlowCall call) {
exists(int tgts, int ctxtgts |
mayBenefitFromCallContext(call, _) and
c = viableCallable(call) and
ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContext(call, ctx)) and
tgts = strictcount(DataFlowCall ctx | viableCallable(ctx) = call.getEnclosingCallable()) and
mayBenefitFromCallContextExt(call, _) and
c = viableCallableExt(call) and
ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContextExt(call, ctx)) and
tgts = strictcount(DataFlowCall ctx | viableCallableExt(ctx) = call.getEnclosingCallable()) and
ctxtgts < tgts
)
}
@@ -367,7 +624,7 @@ private module Cached {
*/
cached
DataFlowCallable prunedViableImplInCallContextReverse(DataFlowCall call, DataFlowCall ctx) {
result = viableImplInCallContext(call, ctx) and
result = viableImplInCallContextExt(call, ctx) and
reducedViableImplInReturn(result, call)
}
}
@@ -481,6 +738,11 @@ private module Cached {
TBooleanNone() or
TBooleanSome(boolean b) { b = true or b = false }
cached
newtype TDataFlowCallOption =
TDataFlowCallNone() or
TDataFlowCallSome(DataFlowCall call)
cached
newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) }
@@ -777,7 +1039,7 @@ ReturnPosition getReturnPosition(ReturnNodeExt ret) {
bindingset[cc, callable]
predicate resolveReturn(CallContext cc, DataFlowCallable callable, DataFlowCall call) {
cc instanceof CallContextAny and callable = viableCallable(call)
cc instanceof CallContextAny and callable = viableCallableExt(call)
or
exists(DataFlowCallable c0, DataFlowCall call0 |
call0.getEnclosingCallable() = callable and
@@ -791,14 +1053,14 @@ DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) {
exists(DataFlowCall ctx | cc = TSpecificCall(ctx) |
if reducedViableImplInCallContext(call, _, ctx)
then result = prunedViableImplInCallContext(call, ctx)
else result = viableCallable(call)
else result = viableCallableExt(call)
)
or
result = viableCallable(call) and cc instanceof CallContextSomeCall
result = viableCallableExt(call) and cc instanceof CallContextSomeCall
or
result = viableCallable(call) and cc instanceof CallContextAny
result = viableCallableExt(call) and cc instanceof CallContextAny
or
result = viableCallable(call) and cc instanceof CallContextReturn
result = viableCallableExt(call) and cc instanceof CallContextReturn
}
predicate read = readStep/3;
@@ -812,6 +1074,19 @@ class BooleanOption extends TBooleanOption {
}
}
/** An optional `DataFlowCall`. */
class DataFlowCallOption extends TDataFlowCallOption {
string toString() {
this = TDataFlowCallNone() and
result = "(none)"
or
exists(DataFlowCall call |
this = TDataFlowCallSome(call) and
result = call.toString()
)
}
}
/** Content tagged with the type of a containing object. */
class TypedContent extends MkTypedContent {
private Content c;

View File

@@ -444,8 +444,8 @@ private module Stage1 {
// read
exists(Node mid, Content c |
read(node, c, mid) and
fwdFlowConsCand(c, unbind(config)) and
revFlow(mid, toReturn, config)
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
revFlow(mid, toReturn, pragma[only_bind_into](config))
)
or
// flow into a callable
@@ -471,18 +471,18 @@ private module Stage1 {
pragma[nomagic]
private predicate revFlowConsCand(Content c, Configuration config) {
exists(Node mid, Node node |
fwdFlow(node, unbind(config)) and
fwdFlow(node, pragma[only_bind_into](config)) and
read(node, c, mid) and
fwdFlowConsCand(c, unbind(config)) and
revFlow(mid, _, config)
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
)
}
pragma[nomagic]
private predicate revFlowStore(Content c, Node node, boolean toReturn, Configuration config) {
exists(Node mid, TypedContent tc |
revFlow(mid, toReturn, config) and
fwdFlowConsCand(c, unbind(config)) and
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
store(node, tc, mid, _) and
c = tc.getContent()
)
@@ -552,8 +552,8 @@ private module Stage1 {
Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
) {
exists(Content c |
revFlowIsReadAndStored(c, config) and
revFlow(node2, unbind(config)) and
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(node2, pragma[only_bind_into](config)) and
store(node1, tc, node2, contentType) and
c = tc.getContent() and
exists(ap1)
@@ -562,8 +562,8 @@ private module Stage1 {
pragma[nomagic]
predicate readStepCand(Node n1, Content c, Node n2, Configuration config) {
revFlowIsReadAndStored(c, config) and
revFlow(n2, unbind(config)) and
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(n2, pragma[only_bind_into](config)) and
read(n1, c, n2)
}
@@ -626,9 +626,6 @@ private module Stage1 {
/* End: Stage 1 logic. */
}
bindingset[result, b]
private boolean unbindBool(boolean b) { result != b.booleanNot() }
pragma[noinline]
private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
Stage1::revFlow(node2, config) and
@@ -864,16 +861,16 @@ private module Stage2 {
)
or
exists(Node mid |
fwdFlow(mid, _, _, ap, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone()
)
or
exists(Node mid, ApNil nil |
fwdFlow(mid, _, _, nil, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone() and
@@ -1045,9 +1042,9 @@ private module Stage2 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, config) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
@@ -1059,9 +1056,9 @@ private module Stage2 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(mid, _, _, nil, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
@@ -1114,9 +1111,10 @@ private module Stage2 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(Node mid |
exists(Node mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
readStepFwd(_, cons, c, mid, tail, config)
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
)
}
@@ -1182,9 +1180,10 @@ private module Stage2 {
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, ap2, config) and
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
revFlowStore(ap1, c, /*unbind*/ unbindBool(ap2), _, _, _, _, _, unbind(config))
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
pragma[only_bind_into](config))
)
}
@@ -1240,8 +1239,8 @@ private predicate flowOutOfCallNodeCand2(
DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, config) and
Stage2::revFlow(node1, unbind(config))
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlow(node1, pragma[only_bind_into](config))
}
pragma[nomagic]
@@ -1250,8 +1249,8 @@ private predicate flowIntoCallNodeCand2(
Configuration config
) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, config) and
Stage2::revFlow(node1, unbind(config))
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlow(node1, pragma[only_bind_into](config))
}
private module LocalFlowBigStep {
@@ -1306,8 +1305,8 @@ private module LocalFlowBigStep {
pragma[noinline]
private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) {
additionalLocalFlowStepNodeCand1(node1, node2, config) and
Stage2::revFlow(node1, _, _, false, config) and
Stage2::revFlow(node2, _, _, false, unbind(config))
Stage2::revFlow(node1, _, _, false, pragma[only_bind_into](config)) and
Stage2::revFlow(node2, _, _, false, pragma[only_bind_into](config))
}
/**
@@ -1324,7 +1323,7 @@ private module LocalFlowBigStep {
) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, config) and
localFlowEntry(node1, pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and
@@ -1337,22 +1336,22 @@ private module LocalFlowBigStep {
node1 != node2 and
cc.relevantFor(getNodeEnclosingCallable(node1)) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, unbind(config))
Stage2::revFlow(node2, pragma[only_bind_into](config))
or
exists(Node mid |
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
localFlowStepPlus(node1, mid, preservesValue, t, pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, unbind(config))
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
or
exists(Node mid |
localFlowStepPlus(node1, mid, _, _, config, cc) and
localFlowStepPlus(node1, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = getNodeType(node2) and
Stage2::revFlow(node2, unbind(config))
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
)
}
@@ -1459,6 +1458,13 @@ private module Stage3 {
PrevStage::revFlow(node, _, _, apa, config)
}
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
exists(ApApprox apa0 |
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
)
}
/**
* Holds if `node` is reachable with access path `ap` from a source in the
* configuration `config`.
@@ -1470,7 +1476,7 @@ private module Stage3 {
pragma[nomagic]
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindBool(getApprox(ap)), config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
@@ -1494,16 +1500,16 @@ private module Stage3 {
)
or
exists(Node mid |
fwdFlow(mid, _, _, ap, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone()
)
or
exists(Node mid, ApNil nil |
fwdFlow(mid, _, _, nil, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone() and
@@ -1548,7 +1554,7 @@ private module Stage3 {
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindBool(getApprox(ap1)), tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType)
)
}
@@ -1627,7 +1633,7 @@ private module Stage3 {
) {
exists(ParameterNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindBool(getApprox(ap)), config)
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
}
@@ -1675,9 +1681,9 @@ private module Stage3 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, config) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
@@ -1689,9 +1695,9 @@ private module Stage3 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(mid, _, _, nil, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
@@ -1744,9 +1750,10 @@ private module Stage3 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(Node mid |
exists(Node mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
readStepFwd(_, cons, c, mid, tail, config)
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
)
}
@@ -1812,9 +1819,10 @@ private module Stage3 {
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, ap2, config) and
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
pragma[only_bind_into](config))
)
}
@@ -2125,8 +2133,11 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
localFlowEntry(node, config) and
result = getLocalCallContext(cc, getNodeEnclosingCallable(node))
exists(Cc cc0 |
cc = pragma[only_bind_into](cc0) and
localFlowEntry(node, config) and
result = getLocalCallContext(cc0, getNodeEnclosingCallable(node))
)
}
private predicate localStep(
@@ -2141,8 +2152,8 @@ private module Stage4 {
Configuration config
) {
flowOutOfCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, config) and
PrevStage::revFlow(node1, _, _, _, unbind(config))
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
}
pragma[nomagic]
@@ -2151,8 +2162,8 @@ private module Stage4 {
Configuration config
) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, config) and
PrevStage::revFlow(node1, _, _, _, unbind(config))
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
}
bindingset[node, ap]
@@ -2167,6 +2178,13 @@ private module Stage4 {
PrevStage::revFlow(node, _, _, apa, config)
}
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
exists(ApApprox apa0 |
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
)
}
/**
* Holds if `node` is reachable with access path `ap` from a source in the
* configuration `config`.
@@ -2178,7 +2196,7 @@ private module Stage4 {
pragma[nomagic]
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, getApprox(ap), config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
@@ -2202,16 +2220,16 @@ private module Stage4 {
)
or
exists(Node mid |
fwdFlow(mid, _, _, ap, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone()
)
or
exists(Node mid, ApNil nil |
fwdFlow(mid, _, _, nil, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone() and
@@ -2256,7 +2274,7 @@ private module Stage4 {
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType)
)
}
@@ -2335,7 +2353,7 @@ private module Stage4 {
) {
exists(ParameterNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
}
@@ -2383,9 +2401,9 @@ private module Stage4 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, config) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
@@ -2397,9 +2415,9 @@ private module Stage4 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(mid, _, _, nil, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
@@ -2452,9 +2470,10 @@ private module Stage4 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(Node mid |
exists(Node mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
readStepFwd(_, cons, c, mid, tail, config)
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
)
}
@@ -2520,9 +2539,10 @@ private module Stage4 {
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, ap2, config) and
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
pragma[only_bind_into](config))
)
}
@@ -2574,7 +2594,9 @@ private module Stage4 {
}
bindingset[conf, result]
private Configuration unbind(Configuration conf) { result >= conf and result <= conf }
private Configuration unbindConf(Configuration conf) {
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
}
private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration config) {
exists(DataFlowCallable c, AccessPathApprox apa0 |
@@ -2744,13 +2766,13 @@ private newtype TPathNode =
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
pathStep(mid, node, cc, sc, ap) and
config = mid.getConfiguration() and
Stage4::revFlow(node, _, _, ap.getApprox(), unbind(config))
pragma[only_bind_into](config) = mid.getConfiguration() and
Stage4::revFlow(node, _, _, ap.getApprox(), pragma[only_bind_into](config))
)
} or
TPathNodeSink(Node node, Configuration config) {
config.isSink(node) and
Stage4::revFlow(node, unbind(config)) and
pragma[only_bind_into](config).isSink(node) and
Stage4::revFlow(node, pragma[only_bind_into](config)) and
(
// A sink that is also a source ...
config.isSource(node)
@@ -2758,7 +2780,7 @@ private newtype TPathNode =
// ... or a sink that can be reached from a source
exists(PathNodeMid mid |
pathStep(mid, node, _, _, TAccessPathNil(_)) and
config = unbind(mid.getConfiguration())
pragma[only_bind_into](config) = mid.getConfiguration()
)
)
}
@@ -3055,7 +3077,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
private PathNodeMid getSuccMid() {
pathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx(), result.getAp()) and
result.getConfiguration() = unbind(this.getConfiguration())
result.getConfiguration() = unbindConf(this.getConfiguration())
}
override PathNodeImpl getASuccessorImpl() {
@@ -3067,7 +3089,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
mid = getSuccMid() and
mid.getNode() = sink.getNode() and
mid.getAp() instanceof AccessPathNil and
sink.getConfiguration() = unbind(mid.getConfiguration()) and
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
result = sink
)
}
@@ -3298,7 +3320,7 @@ private predicate pathThroughCallable0(
) {
exists(CallContext innercc, SummaryCtx sc |
pathIntoCallable(mid, _, cc, innercc, sc, call) and
paramFlowsThrough(kind, innercc, sc, ap, apa, unbind(mid.getConfiguration()))
paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration()))
)
}
@@ -3310,7 +3332,7 @@ pragma[noinline]
private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) {
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
out = getAnOutNodeFlow(kind, call, apa, unbind(mid.getConfiguration()))
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
)
}
@@ -3433,8 +3455,8 @@ private module FlowExploration {
private predicate callableExtStepFwd(TCallableExt ce1, TCallableExt ce2) {
exists(DataFlowCallable c1, DataFlowCallable c2, Configuration config |
callableStep(c1, c2, config) and
ce1 = TCallable(c1, config) and
ce2 = TCallable(c2, unbind(config))
ce1 = TCallable(c1, pragma[only_bind_into](config)) and
ce2 = TCallable(c2, pragma[only_bind_into](config))
)
or
exists(Node n, Configuration config |

View File

@@ -312,3 +312,14 @@ predicate isImmutableOrUnobservable(Node n) {
/** Holds if `n` should be hidden from path explanations. */
predicate nodeIsHidden(Node n) { none() }
class LambdaCallKind = Unit;
/** Holds if `creation` is an expression that creates a lambda of kind `kind` for `c`. */
predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c) { none() }
/** Holds if `call` is a lambda call of kind `kind` where `receiver` is the lambda expression. */
predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) { none() }
/** Extra data-flow steps needed for lamba flow analysis. */
predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) { none() }

View File

@@ -444,8 +444,8 @@ private module Stage1 {
// read
exists(Node mid, Content c |
read(node, c, mid) and
fwdFlowConsCand(c, unbind(config)) and
revFlow(mid, toReturn, config)
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
revFlow(mid, toReturn, pragma[only_bind_into](config))
)
or
// flow into a callable
@@ -471,18 +471,18 @@ private module Stage1 {
pragma[nomagic]
private predicate revFlowConsCand(Content c, Configuration config) {
exists(Node mid, Node node |
fwdFlow(node, unbind(config)) and
fwdFlow(node, pragma[only_bind_into](config)) and
read(node, c, mid) and
fwdFlowConsCand(c, unbind(config)) and
revFlow(mid, _, config)
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
)
}
pragma[nomagic]
private predicate revFlowStore(Content c, Node node, boolean toReturn, Configuration config) {
exists(Node mid, TypedContent tc |
revFlow(mid, toReturn, config) and
fwdFlowConsCand(c, unbind(config)) and
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
store(node, tc, mid, _) and
c = tc.getContent()
)
@@ -552,8 +552,8 @@ private module Stage1 {
Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
) {
exists(Content c |
revFlowIsReadAndStored(c, config) and
revFlow(node2, unbind(config)) and
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(node2, pragma[only_bind_into](config)) and
store(node1, tc, node2, contentType) and
c = tc.getContent() and
exists(ap1)
@@ -562,8 +562,8 @@ private module Stage1 {
pragma[nomagic]
predicate readStepCand(Node n1, Content c, Node n2, Configuration config) {
revFlowIsReadAndStored(c, config) and
revFlow(n2, unbind(config)) and
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(n2, pragma[only_bind_into](config)) and
read(n1, c, n2)
}
@@ -626,9 +626,6 @@ private module Stage1 {
/* End: Stage 1 logic. */
}
bindingset[result, b]
private boolean unbindBool(boolean b) { result != b.booleanNot() }
pragma[noinline]
private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
Stage1::revFlow(node2, config) and
@@ -864,16 +861,16 @@ private module Stage2 {
)
or
exists(Node mid |
fwdFlow(mid, _, _, ap, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone()
)
or
exists(Node mid, ApNil nil |
fwdFlow(mid, _, _, nil, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone() and
@@ -1045,9 +1042,9 @@ private module Stage2 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, config) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
@@ -1059,9 +1056,9 @@ private module Stage2 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(mid, _, _, nil, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
@@ -1114,9 +1111,10 @@ private module Stage2 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(Node mid |
exists(Node mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
readStepFwd(_, cons, c, mid, tail, config)
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
)
}
@@ -1182,9 +1180,10 @@ private module Stage2 {
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, ap2, config) and
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
revFlowStore(ap1, c, /*unbind*/ unbindBool(ap2), _, _, _, _, _, unbind(config))
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
pragma[only_bind_into](config))
)
}
@@ -1240,8 +1239,8 @@ private predicate flowOutOfCallNodeCand2(
DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, config) and
Stage2::revFlow(node1, unbind(config))
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlow(node1, pragma[only_bind_into](config))
}
pragma[nomagic]
@@ -1250,8 +1249,8 @@ private predicate flowIntoCallNodeCand2(
Configuration config
) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, config) and
Stage2::revFlow(node1, unbind(config))
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlow(node1, pragma[only_bind_into](config))
}
private module LocalFlowBigStep {
@@ -1306,8 +1305,8 @@ private module LocalFlowBigStep {
pragma[noinline]
private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) {
additionalLocalFlowStepNodeCand1(node1, node2, config) and
Stage2::revFlow(node1, _, _, false, config) and
Stage2::revFlow(node2, _, _, false, unbind(config))
Stage2::revFlow(node1, _, _, false, pragma[only_bind_into](config)) and
Stage2::revFlow(node2, _, _, false, pragma[only_bind_into](config))
}
/**
@@ -1324,7 +1323,7 @@ private module LocalFlowBigStep {
) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, config) and
localFlowEntry(node1, pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and
@@ -1337,22 +1336,22 @@ private module LocalFlowBigStep {
node1 != node2 and
cc.relevantFor(getNodeEnclosingCallable(node1)) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, unbind(config))
Stage2::revFlow(node2, pragma[only_bind_into](config))
or
exists(Node mid |
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
localFlowStepPlus(node1, mid, preservesValue, t, pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, unbind(config))
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
or
exists(Node mid |
localFlowStepPlus(node1, mid, _, _, config, cc) and
localFlowStepPlus(node1, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = getNodeType(node2) and
Stage2::revFlow(node2, unbind(config))
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
)
}
@@ -1459,6 +1458,13 @@ private module Stage3 {
PrevStage::revFlow(node, _, _, apa, config)
}
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
exists(ApApprox apa0 |
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
)
}
/**
* Holds if `node` is reachable with access path `ap` from a source in the
* configuration `config`.
@@ -1470,7 +1476,7 @@ private module Stage3 {
pragma[nomagic]
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindBool(getApprox(ap)), config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
@@ -1494,16 +1500,16 @@ private module Stage3 {
)
or
exists(Node mid |
fwdFlow(mid, _, _, ap, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone()
)
or
exists(Node mid, ApNil nil |
fwdFlow(mid, _, _, nil, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone() and
@@ -1548,7 +1554,7 @@ private module Stage3 {
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindBool(getApprox(ap1)), tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType)
)
}
@@ -1627,7 +1633,7 @@ private module Stage3 {
) {
exists(ParameterNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindBool(getApprox(ap)), config)
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
}
@@ -1675,9 +1681,9 @@ private module Stage3 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, config) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
@@ -1689,9 +1695,9 @@ private module Stage3 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(mid, _, _, nil, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
@@ -1744,9 +1750,10 @@ private module Stage3 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(Node mid |
exists(Node mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
readStepFwd(_, cons, c, mid, tail, config)
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
)
}
@@ -1812,9 +1819,10 @@ private module Stage3 {
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, ap2, config) and
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
pragma[only_bind_into](config))
)
}
@@ -2125,8 +2133,11 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
localFlowEntry(node, config) and
result = getLocalCallContext(cc, getNodeEnclosingCallable(node))
exists(Cc cc0 |
cc = pragma[only_bind_into](cc0) and
localFlowEntry(node, config) and
result = getLocalCallContext(cc0, getNodeEnclosingCallable(node))
)
}
private predicate localStep(
@@ -2141,8 +2152,8 @@ private module Stage4 {
Configuration config
) {
flowOutOfCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, config) and
PrevStage::revFlow(node1, _, _, _, unbind(config))
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
}
pragma[nomagic]
@@ -2151,8 +2162,8 @@ private module Stage4 {
Configuration config
) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, config) and
PrevStage::revFlow(node1, _, _, _, unbind(config))
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
}
bindingset[node, ap]
@@ -2167,6 +2178,13 @@ private module Stage4 {
PrevStage::revFlow(node, _, _, apa, config)
}
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
exists(ApApprox apa0 |
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
)
}
/**
* Holds if `node` is reachable with access path `ap` from a source in the
* configuration `config`.
@@ -2178,7 +2196,7 @@ private module Stage4 {
pragma[nomagic]
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, getApprox(ap), config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
@@ -2202,16 +2220,16 @@ private module Stage4 {
)
or
exists(Node mid |
fwdFlow(mid, _, _, ap, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone()
)
or
exists(Node mid, ApNil nil |
fwdFlow(mid, _, _, nil, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone() and
@@ -2256,7 +2274,7 @@ private module Stage4 {
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType)
)
}
@@ -2335,7 +2353,7 @@ private module Stage4 {
) {
exists(ParameterNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
}
@@ -2383,9 +2401,9 @@ private module Stage4 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, config) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
@@ -2397,9 +2415,9 @@ private module Stage4 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(mid, _, _, nil, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
@@ -2452,9 +2470,10 @@ private module Stage4 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(Node mid |
exists(Node mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
readStepFwd(_, cons, c, mid, tail, config)
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
)
}
@@ -2520,9 +2539,10 @@ private module Stage4 {
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, ap2, config) and
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
pragma[only_bind_into](config))
)
}
@@ -2574,7 +2594,9 @@ private module Stage4 {
}
bindingset[conf, result]
private Configuration unbind(Configuration conf) { result >= conf and result <= conf }
private Configuration unbindConf(Configuration conf) {
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
}
private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration config) {
exists(DataFlowCallable c, AccessPathApprox apa0 |
@@ -2744,13 +2766,13 @@ private newtype TPathNode =
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
pathStep(mid, node, cc, sc, ap) and
config = mid.getConfiguration() and
Stage4::revFlow(node, _, _, ap.getApprox(), unbind(config))
pragma[only_bind_into](config) = mid.getConfiguration() and
Stage4::revFlow(node, _, _, ap.getApprox(), pragma[only_bind_into](config))
)
} or
TPathNodeSink(Node node, Configuration config) {
config.isSink(node) and
Stage4::revFlow(node, unbind(config)) and
pragma[only_bind_into](config).isSink(node) and
Stage4::revFlow(node, pragma[only_bind_into](config)) and
(
// A sink that is also a source ...
config.isSource(node)
@@ -2758,7 +2780,7 @@ private newtype TPathNode =
// ... or a sink that can be reached from a source
exists(PathNodeMid mid |
pathStep(mid, node, _, _, TAccessPathNil(_)) and
config = unbind(mid.getConfiguration())
pragma[only_bind_into](config) = mid.getConfiguration()
)
)
}
@@ -3055,7 +3077,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
private PathNodeMid getSuccMid() {
pathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx(), result.getAp()) and
result.getConfiguration() = unbind(this.getConfiguration())
result.getConfiguration() = unbindConf(this.getConfiguration())
}
override PathNodeImpl getASuccessorImpl() {
@@ -3067,7 +3089,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
mid = getSuccMid() and
mid.getNode() = sink.getNode() and
mid.getAp() instanceof AccessPathNil and
sink.getConfiguration() = unbind(mid.getConfiguration()) and
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
result = sink
)
}
@@ -3298,7 +3320,7 @@ private predicate pathThroughCallable0(
) {
exists(CallContext innercc, SummaryCtx sc |
pathIntoCallable(mid, _, cc, innercc, sc, call) and
paramFlowsThrough(kind, innercc, sc, ap, apa, unbind(mid.getConfiguration()))
paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration()))
)
}
@@ -3310,7 +3332,7 @@ pragma[noinline]
private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) {
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
out = getAnOutNodeFlow(kind, call, apa, unbind(mid.getConfiguration()))
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
)
}
@@ -3433,8 +3455,8 @@ private module FlowExploration {
private predicate callableExtStepFwd(TCallableExt ce1, TCallableExt ce2) {
exists(DataFlowCallable c1, DataFlowCallable c2, Configuration config |
callableStep(c1, c2, config) and
ce1 = TCallable(c1, config) and
ce2 = TCallable(c2, unbind(config))
ce1 = TCallable(c1, pragma[only_bind_into](config)) and
ce2 = TCallable(c2, pragma[only_bind_into](config))
)
or
exists(Node n, Configuration config |

View File

@@ -444,8 +444,8 @@ private module Stage1 {
// read
exists(Node mid, Content c |
read(node, c, mid) and
fwdFlowConsCand(c, unbind(config)) and
revFlow(mid, toReturn, config)
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
revFlow(mid, toReturn, pragma[only_bind_into](config))
)
or
// flow into a callable
@@ -471,18 +471,18 @@ private module Stage1 {
pragma[nomagic]
private predicate revFlowConsCand(Content c, Configuration config) {
exists(Node mid, Node node |
fwdFlow(node, unbind(config)) and
fwdFlow(node, pragma[only_bind_into](config)) and
read(node, c, mid) and
fwdFlowConsCand(c, unbind(config)) and
revFlow(mid, _, config)
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
)
}
pragma[nomagic]
private predicate revFlowStore(Content c, Node node, boolean toReturn, Configuration config) {
exists(Node mid, TypedContent tc |
revFlow(mid, toReturn, config) and
fwdFlowConsCand(c, unbind(config)) and
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
store(node, tc, mid, _) and
c = tc.getContent()
)
@@ -552,8 +552,8 @@ private module Stage1 {
Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
) {
exists(Content c |
revFlowIsReadAndStored(c, config) and
revFlow(node2, unbind(config)) and
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(node2, pragma[only_bind_into](config)) and
store(node1, tc, node2, contentType) and
c = tc.getContent() and
exists(ap1)
@@ -562,8 +562,8 @@ private module Stage1 {
pragma[nomagic]
predicate readStepCand(Node n1, Content c, Node n2, Configuration config) {
revFlowIsReadAndStored(c, config) and
revFlow(n2, unbind(config)) and
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(n2, pragma[only_bind_into](config)) and
read(n1, c, n2)
}
@@ -626,9 +626,6 @@ private module Stage1 {
/* End: Stage 1 logic. */
}
bindingset[result, b]
private boolean unbindBool(boolean b) { result != b.booleanNot() }
pragma[noinline]
private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
Stage1::revFlow(node2, config) and
@@ -864,16 +861,16 @@ private module Stage2 {
)
or
exists(Node mid |
fwdFlow(mid, _, _, ap, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone()
)
or
exists(Node mid, ApNil nil |
fwdFlow(mid, _, _, nil, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone() and
@@ -1045,9 +1042,9 @@ private module Stage2 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, config) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
@@ -1059,9 +1056,9 @@ private module Stage2 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(mid, _, _, nil, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
@@ -1114,9 +1111,10 @@ private module Stage2 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(Node mid |
exists(Node mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
readStepFwd(_, cons, c, mid, tail, config)
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
)
}
@@ -1182,9 +1180,10 @@ private module Stage2 {
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, ap2, config) and
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
revFlowStore(ap1, c, /*unbind*/ unbindBool(ap2), _, _, _, _, _, unbind(config))
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
pragma[only_bind_into](config))
)
}
@@ -1240,8 +1239,8 @@ private predicate flowOutOfCallNodeCand2(
DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, config) and
Stage2::revFlow(node1, unbind(config))
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlow(node1, pragma[only_bind_into](config))
}
pragma[nomagic]
@@ -1250,8 +1249,8 @@ private predicate flowIntoCallNodeCand2(
Configuration config
) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, config) and
Stage2::revFlow(node1, unbind(config))
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlow(node1, pragma[only_bind_into](config))
}
private module LocalFlowBigStep {
@@ -1306,8 +1305,8 @@ private module LocalFlowBigStep {
pragma[noinline]
private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) {
additionalLocalFlowStepNodeCand1(node1, node2, config) and
Stage2::revFlow(node1, _, _, false, config) and
Stage2::revFlow(node2, _, _, false, unbind(config))
Stage2::revFlow(node1, _, _, false, pragma[only_bind_into](config)) and
Stage2::revFlow(node2, _, _, false, pragma[only_bind_into](config))
}
/**
@@ -1324,7 +1323,7 @@ private module LocalFlowBigStep {
) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, config) and
localFlowEntry(node1, pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and
@@ -1337,22 +1336,22 @@ private module LocalFlowBigStep {
node1 != node2 and
cc.relevantFor(getNodeEnclosingCallable(node1)) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, unbind(config))
Stage2::revFlow(node2, pragma[only_bind_into](config))
or
exists(Node mid |
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
localFlowStepPlus(node1, mid, preservesValue, t, pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, unbind(config))
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
or
exists(Node mid |
localFlowStepPlus(node1, mid, _, _, config, cc) and
localFlowStepPlus(node1, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = getNodeType(node2) and
Stage2::revFlow(node2, unbind(config))
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
)
}
@@ -1459,6 +1458,13 @@ private module Stage3 {
PrevStage::revFlow(node, _, _, apa, config)
}
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
exists(ApApprox apa0 |
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
)
}
/**
* Holds if `node` is reachable with access path `ap` from a source in the
* configuration `config`.
@@ -1470,7 +1476,7 @@ private module Stage3 {
pragma[nomagic]
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindBool(getApprox(ap)), config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
@@ -1494,16 +1500,16 @@ private module Stage3 {
)
or
exists(Node mid |
fwdFlow(mid, _, _, ap, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone()
)
or
exists(Node mid, ApNil nil |
fwdFlow(mid, _, _, nil, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone() and
@@ -1548,7 +1554,7 @@ private module Stage3 {
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindBool(getApprox(ap1)), tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType)
)
}
@@ -1627,7 +1633,7 @@ private module Stage3 {
) {
exists(ParameterNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindBool(getApprox(ap)), config)
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
}
@@ -1675,9 +1681,9 @@ private module Stage3 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, config) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
@@ -1689,9 +1695,9 @@ private module Stage3 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(mid, _, _, nil, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
@@ -1744,9 +1750,10 @@ private module Stage3 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(Node mid |
exists(Node mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
readStepFwd(_, cons, c, mid, tail, config)
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
)
}
@@ -1812,9 +1819,10 @@ private module Stage3 {
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, ap2, config) and
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
pragma[only_bind_into](config))
)
}
@@ -2125,8 +2133,11 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
localFlowEntry(node, config) and
result = getLocalCallContext(cc, getNodeEnclosingCallable(node))
exists(Cc cc0 |
cc = pragma[only_bind_into](cc0) and
localFlowEntry(node, config) and
result = getLocalCallContext(cc0, getNodeEnclosingCallable(node))
)
}
private predicate localStep(
@@ -2141,8 +2152,8 @@ private module Stage4 {
Configuration config
) {
flowOutOfCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, config) and
PrevStage::revFlow(node1, _, _, _, unbind(config))
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
}
pragma[nomagic]
@@ -2151,8 +2162,8 @@ private module Stage4 {
Configuration config
) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, config) and
PrevStage::revFlow(node1, _, _, _, unbind(config))
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
}
bindingset[node, ap]
@@ -2167,6 +2178,13 @@ private module Stage4 {
PrevStage::revFlow(node, _, _, apa, config)
}
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
exists(ApApprox apa0 |
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
)
}
/**
* Holds if `node` is reachable with access path `ap` from a source in the
* configuration `config`.
@@ -2178,7 +2196,7 @@ private module Stage4 {
pragma[nomagic]
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, getApprox(ap), config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
@@ -2202,16 +2220,16 @@ private module Stage4 {
)
or
exists(Node mid |
fwdFlow(mid, _, _, ap, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone()
)
or
exists(Node mid, ApNil nil |
fwdFlow(mid, _, _, nil, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone() and
@@ -2256,7 +2274,7 @@ private module Stage4 {
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType)
)
}
@@ -2335,7 +2353,7 @@ private module Stage4 {
) {
exists(ParameterNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
}
@@ -2383,9 +2401,9 @@ private module Stage4 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, config) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
@@ -2397,9 +2415,9 @@ private module Stage4 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(mid, _, _, nil, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
@@ -2452,9 +2470,10 @@ private module Stage4 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(Node mid |
exists(Node mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
readStepFwd(_, cons, c, mid, tail, config)
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
)
}
@@ -2520,9 +2539,10 @@ private module Stage4 {
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, ap2, config) and
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
pragma[only_bind_into](config))
)
}
@@ -2574,7 +2594,9 @@ private module Stage4 {
}
bindingset[conf, result]
private Configuration unbind(Configuration conf) { result >= conf and result <= conf }
private Configuration unbindConf(Configuration conf) {
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
}
private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration config) {
exists(DataFlowCallable c, AccessPathApprox apa0 |
@@ -2744,13 +2766,13 @@ private newtype TPathNode =
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
pathStep(mid, node, cc, sc, ap) and
config = mid.getConfiguration() and
Stage4::revFlow(node, _, _, ap.getApprox(), unbind(config))
pragma[only_bind_into](config) = mid.getConfiguration() and
Stage4::revFlow(node, _, _, ap.getApprox(), pragma[only_bind_into](config))
)
} or
TPathNodeSink(Node node, Configuration config) {
config.isSink(node) and
Stage4::revFlow(node, unbind(config)) and
pragma[only_bind_into](config).isSink(node) and
Stage4::revFlow(node, pragma[only_bind_into](config)) and
(
// A sink that is also a source ...
config.isSource(node)
@@ -2758,7 +2780,7 @@ private newtype TPathNode =
// ... or a sink that can be reached from a source
exists(PathNodeMid mid |
pathStep(mid, node, _, _, TAccessPathNil(_)) and
config = unbind(mid.getConfiguration())
pragma[only_bind_into](config) = mid.getConfiguration()
)
)
}
@@ -3055,7 +3077,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
private PathNodeMid getSuccMid() {
pathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx(), result.getAp()) and
result.getConfiguration() = unbind(this.getConfiguration())
result.getConfiguration() = unbindConf(this.getConfiguration())
}
override PathNodeImpl getASuccessorImpl() {
@@ -3067,7 +3089,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
mid = getSuccMid() and
mid.getNode() = sink.getNode() and
mid.getAp() instanceof AccessPathNil and
sink.getConfiguration() = unbind(mid.getConfiguration()) and
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
result = sink
)
}
@@ -3298,7 +3320,7 @@ private predicate pathThroughCallable0(
) {
exists(CallContext innercc, SummaryCtx sc |
pathIntoCallable(mid, _, cc, innercc, sc, call) and
paramFlowsThrough(kind, innercc, sc, ap, apa, unbind(mid.getConfiguration()))
paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration()))
)
}
@@ -3310,7 +3332,7 @@ pragma[noinline]
private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) {
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
out = getAnOutNodeFlow(kind, call, apa, unbind(mid.getConfiguration()))
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
)
}
@@ -3433,8 +3455,8 @@ private module FlowExploration {
private predicate callableExtStepFwd(TCallableExt ce1, TCallableExt ce2) {
exists(DataFlowCallable c1, DataFlowCallable c2, Configuration config |
callableStep(c1, c2, config) and
ce1 = TCallable(c1, config) and
ce2 = TCallable(c2, unbind(config))
ce1 = TCallable(c1, pragma[only_bind_into](config)) and
ce2 = TCallable(c2, pragma[only_bind_into](config))
)
or
exists(Node n, Configuration config |

View File

@@ -444,8 +444,8 @@ private module Stage1 {
// read
exists(Node mid, Content c |
read(node, c, mid) and
fwdFlowConsCand(c, unbind(config)) and
revFlow(mid, toReturn, config)
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
revFlow(mid, toReturn, pragma[only_bind_into](config))
)
or
// flow into a callable
@@ -471,18 +471,18 @@ private module Stage1 {
pragma[nomagic]
private predicate revFlowConsCand(Content c, Configuration config) {
exists(Node mid, Node node |
fwdFlow(node, unbind(config)) and
fwdFlow(node, pragma[only_bind_into](config)) and
read(node, c, mid) and
fwdFlowConsCand(c, unbind(config)) and
revFlow(mid, _, config)
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
)
}
pragma[nomagic]
private predicate revFlowStore(Content c, Node node, boolean toReturn, Configuration config) {
exists(Node mid, TypedContent tc |
revFlow(mid, toReturn, config) and
fwdFlowConsCand(c, unbind(config)) and
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
store(node, tc, mid, _) and
c = tc.getContent()
)
@@ -552,8 +552,8 @@ private module Stage1 {
Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
) {
exists(Content c |
revFlowIsReadAndStored(c, config) and
revFlow(node2, unbind(config)) and
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(node2, pragma[only_bind_into](config)) and
store(node1, tc, node2, contentType) and
c = tc.getContent() and
exists(ap1)
@@ -562,8 +562,8 @@ private module Stage1 {
pragma[nomagic]
predicate readStepCand(Node n1, Content c, Node n2, Configuration config) {
revFlowIsReadAndStored(c, config) and
revFlow(n2, unbind(config)) and
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(n2, pragma[only_bind_into](config)) and
read(n1, c, n2)
}
@@ -626,9 +626,6 @@ private module Stage1 {
/* End: Stage 1 logic. */
}
bindingset[result, b]
private boolean unbindBool(boolean b) { result != b.booleanNot() }
pragma[noinline]
private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
Stage1::revFlow(node2, config) and
@@ -864,16 +861,16 @@ private module Stage2 {
)
or
exists(Node mid |
fwdFlow(mid, _, _, ap, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone()
)
or
exists(Node mid, ApNil nil |
fwdFlow(mid, _, _, nil, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone() and
@@ -1045,9 +1042,9 @@ private module Stage2 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, config) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
@@ -1059,9 +1056,9 @@ private module Stage2 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(mid, _, _, nil, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
@@ -1114,9 +1111,10 @@ private module Stage2 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(Node mid |
exists(Node mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
readStepFwd(_, cons, c, mid, tail, config)
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
)
}
@@ -1182,9 +1180,10 @@ private module Stage2 {
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, ap2, config) and
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
revFlowStore(ap1, c, /*unbind*/ unbindBool(ap2), _, _, _, _, _, unbind(config))
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
pragma[only_bind_into](config))
)
}
@@ -1240,8 +1239,8 @@ private predicate flowOutOfCallNodeCand2(
DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, config) and
Stage2::revFlow(node1, unbind(config))
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlow(node1, pragma[only_bind_into](config))
}
pragma[nomagic]
@@ -1250,8 +1249,8 @@ private predicate flowIntoCallNodeCand2(
Configuration config
) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, config) and
Stage2::revFlow(node1, unbind(config))
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlow(node1, pragma[only_bind_into](config))
}
private module LocalFlowBigStep {
@@ -1306,8 +1305,8 @@ private module LocalFlowBigStep {
pragma[noinline]
private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) {
additionalLocalFlowStepNodeCand1(node1, node2, config) and
Stage2::revFlow(node1, _, _, false, config) and
Stage2::revFlow(node2, _, _, false, unbind(config))
Stage2::revFlow(node1, _, _, false, pragma[only_bind_into](config)) and
Stage2::revFlow(node2, _, _, false, pragma[only_bind_into](config))
}
/**
@@ -1324,7 +1323,7 @@ private module LocalFlowBigStep {
) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, config) and
localFlowEntry(node1, pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and
@@ -1337,22 +1336,22 @@ private module LocalFlowBigStep {
node1 != node2 and
cc.relevantFor(getNodeEnclosingCallable(node1)) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, unbind(config))
Stage2::revFlow(node2, pragma[only_bind_into](config))
or
exists(Node mid |
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
localFlowStepPlus(node1, mid, preservesValue, t, pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, unbind(config))
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
or
exists(Node mid |
localFlowStepPlus(node1, mid, _, _, config, cc) and
localFlowStepPlus(node1, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = getNodeType(node2) and
Stage2::revFlow(node2, unbind(config))
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
)
}
@@ -1459,6 +1458,13 @@ private module Stage3 {
PrevStage::revFlow(node, _, _, apa, config)
}
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
exists(ApApprox apa0 |
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
)
}
/**
* Holds if `node` is reachable with access path `ap` from a source in the
* configuration `config`.
@@ -1470,7 +1476,7 @@ private module Stage3 {
pragma[nomagic]
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindBool(getApprox(ap)), config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
@@ -1494,16 +1500,16 @@ private module Stage3 {
)
or
exists(Node mid |
fwdFlow(mid, _, _, ap, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone()
)
or
exists(Node mid, ApNil nil |
fwdFlow(mid, _, _, nil, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone() and
@@ -1548,7 +1554,7 @@ private module Stage3 {
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindBool(getApprox(ap1)), tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType)
)
}
@@ -1627,7 +1633,7 @@ private module Stage3 {
) {
exists(ParameterNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindBool(getApprox(ap)), config)
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
}
@@ -1675,9 +1681,9 @@ private module Stage3 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, config) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
@@ -1689,9 +1695,9 @@ private module Stage3 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(mid, _, _, nil, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
@@ -1744,9 +1750,10 @@ private module Stage3 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(Node mid |
exists(Node mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
readStepFwd(_, cons, c, mid, tail, config)
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
)
}
@@ -1812,9 +1819,10 @@ private module Stage3 {
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, ap2, config) and
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
pragma[only_bind_into](config))
)
}
@@ -2125,8 +2133,11 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
localFlowEntry(node, config) and
result = getLocalCallContext(cc, getNodeEnclosingCallable(node))
exists(Cc cc0 |
cc = pragma[only_bind_into](cc0) and
localFlowEntry(node, config) and
result = getLocalCallContext(cc0, getNodeEnclosingCallable(node))
)
}
private predicate localStep(
@@ -2141,8 +2152,8 @@ private module Stage4 {
Configuration config
) {
flowOutOfCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, config) and
PrevStage::revFlow(node1, _, _, _, unbind(config))
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
}
pragma[nomagic]
@@ -2151,8 +2162,8 @@ private module Stage4 {
Configuration config
) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, config) and
PrevStage::revFlow(node1, _, _, _, unbind(config))
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
}
bindingset[node, ap]
@@ -2167,6 +2178,13 @@ private module Stage4 {
PrevStage::revFlow(node, _, _, apa, config)
}
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
exists(ApApprox apa0 |
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
)
}
/**
* Holds if `node` is reachable with access path `ap` from a source in the
* configuration `config`.
@@ -2178,7 +2196,7 @@ private module Stage4 {
pragma[nomagic]
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, getApprox(ap), config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
@@ -2202,16 +2220,16 @@ private module Stage4 {
)
or
exists(Node mid |
fwdFlow(mid, _, _, ap, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone()
)
or
exists(Node mid, ApNil nil |
fwdFlow(mid, _, _, nil, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone() and
@@ -2256,7 +2274,7 @@ private module Stage4 {
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType)
)
}
@@ -2335,7 +2353,7 @@ private module Stage4 {
) {
exists(ParameterNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
}
@@ -2383,9 +2401,9 @@ private module Stage4 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, config) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
@@ -2397,9 +2415,9 @@ private module Stage4 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(mid, _, _, nil, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
@@ -2452,9 +2470,10 @@ private module Stage4 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(Node mid |
exists(Node mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
readStepFwd(_, cons, c, mid, tail, config)
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
)
}
@@ -2520,9 +2539,10 @@ private module Stage4 {
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, ap2, config) and
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
pragma[only_bind_into](config))
)
}
@@ -2574,7 +2594,9 @@ private module Stage4 {
}
bindingset[conf, result]
private Configuration unbind(Configuration conf) { result >= conf and result <= conf }
private Configuration unbindConf(Configuration conf) {
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
}
private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration config) {
exists(DataFlowCallable c, AccessPathApprox apa0 |
@@ -2744,13 +2766,13 @@ private newtype TPathNode =
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
pathStep(mid, node, cc, sc, ap) and
config = mid.getConfiguration() and
Stage4::revFlow(node, _, _, ap.getApprox(), unbind(config))
pragma[only_bind_into](config) = mid.getConfiguration() and
Stage4::revFlow(node, _, _, ap.getApprox(), pragma[only_bind_into](config))
)
} or
TPathNodeSink(Node node, Configuration config) {
config.isSink(node) and
Stage4::revFlow(node, unbind(config)) and
pragma[only_bind_into](config).isSink(node) and
Stage4::revFlow(node, pragma[only_bind_into](config)) and
(
// A sink that is also a source ...
config.isSource(node)
@@ -2758,7 +2780,7 @@ private newtype TPathNode =
// ... or a sink that can be reached from a source
exists(PathNodeMid mid |
pathStep(mid, node, _, _, TAccessPathNil(_)) and
config = unbind(mid.getConfiguration())
pragma[only_bind_into](config) = mid.getConfiguration()
)
)
}
@@ -3055,7 +3077,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
private PathNodeMid getSuccMid() {
pathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx(), result.getAp()) and
result.getConfiguration() = unbind(this.getConfiguration())
result.getConfiguration() = unbindConf(this.getConfiguration())
}
override PathNodeImpl getASuccessorImpl() {
@@ -3067,7 +3089,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
mid = getSuccMid() and
mid.getNode() = sink.getNode() and
mid.getAp() instanceof AccessPathNil and
sink.getConfiguration() = unbind(mid.getConfiguration()) and
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
result = sink
)
}
@@ -3298,7 +3320,7 @@ private predicate pathThroughCallable0(
) {
exists(CallContext innercc, SummaryCtx sc |
pathIntoCallable(mid, _, cc, innercc, sc, call) and
paramFlowsThrough(kind, innercc, sc, ap, apa, unbind(mid.getConfiguration()))
paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration()))
)
}
@@ -3310,7 +3332,7 @@ pragma[noinline]
private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) {
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
out = getAnOutNodeFlow(kind, call, apa, unbind(mid.getConfiguration()))
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
)
}
@@ -3433,8 +3455,8 @@ private module FlowExploration {
private predicate callableExtStepFwd(TCallableExt ce1, TCallableExt ce2) {
exists(DataFlowCallable c1, DataFlowCallable c2, Configuration config |
callableStep(c1, c2, config) and
ce1 = TCallable(c1, config) and
ce2 = TCallable(c2, unbind(config))
ce1 = TCallable(c1, pragma[only_bind_into](config)) and
ce2 = TCallable(c2, pragma[only_bind_into](config))
)
or
exists(Node n, Configuration config |

View File

@@ -444,8 +444,8 @@ private module Stage1 {
// read
exists(Node mid, Content c |
read(node, c, mid) and
fwdFlowConsCand(c, unbind(config)) and
revFlow(mid, toReturn, config)
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
revFlow(mid, toReturn, pragma[only_bind_into](config))
)
or
// flow into a callable
@@ -471,18 +471,18 @@ private module Stage1 {
pragma[nomagic]
private predicate revFlowConsCand(Content c, Configuration config) {
exists(Node mid, Node node |
fwdFlow(node, unbind(config)) and
fwdFlow(node, pragma[only_bind_into](config)) and
read(node, c, mid) and
fwdFlowConsCand(c, unbind(config)) and
revFlow(mid, _, config)
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
)
}
pragma[nomagic]
private predicate revFlowStore(Content c, Node node, boolean toReturn, Configuration config) {
exists(Node mid, TypedContent tc |
revFlow(mid, toReturn, config) and
fwdFlowConsCand(c, unbind(config)) and
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
store(node, tc, mid, _) and
c = tc.getContent()
)
@@ -552,8 +552,8 @@ private module Stage1 {
Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
) {
exists(Content c |
revFlowIsReadAndStored(c, config) and
revFlow(node2, unbind(config)) and
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(node2, pragma[only_bind_into](config)) and
store(node1, tc, node2, contentType) and
c = tc.getContent() and
exists(ap1)
@@ -562,8 +562,8 @@ private module Stage1 {
pragma[nomagic]
predicate readStepCand(Node n1, Content c, Node n2, Configuration config) {
revFlowIsReadAndStored(c, config) and
revFlow(n2, unbind(config)) and
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(n2, pragma[only_bind_into](config)) and
read(n1, c, n2)
}
@@ -626,9 +626,6 @@ private module Stage1 {
/* End: Stage 1 logic. */
}
bindingset[result, b]
private boolean unbindBool(boolean b) { result != b.booleanNot() }
pragma[noinline]
private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
Stage1::revFlow(node2, config) and
@@ -864,16 +861,16 @@ private module Stage2 {
)
or
exists(Node mid |
fwdFlow(mid, _, _, ap, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone()
)
or
exists(Node mid, ApNil nil |
fwdFlow(mid, _, _, nil, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone() and
@@ -1045,9 +1042,9 @@ private module Stage2 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, config) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
@@ -1059,9 +1056,9 @@ private module Stage2 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(mid, _, _, nil, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
@@ -1114,9 +1111,10 @@ private module Stage2 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(Node mid |
exists(Node mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
readStepFwd(_, cons, c, mid, tail, config)
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
)
}
@@ -1182,9 +1180,10 @@ private module Stage2 {
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, ap2, config) and
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
revFlowStore(ap1, c, /*unbind*/ unbindBool(ap2), _, _, _, _, _, unbind(config))
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
pragma[only_bind_into](config))
)
}
@@ -1240,8 +1239,8 @@ private predicate flowOutOfCallNodeCand2(
DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, config) and
Stage2::revFlow(node1, unbind(config))
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlow(node1, pragma[only_bind_into](config))
}
pragma[nomagic]
@@ -1250,8 +1249,8 @@ private predicate flowIntoCallNodeCand2(
Configuration config
) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, config) and
Stage2::revFlow(node1, unbind(config))
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
Stage2::revFlow(node1, pragma[only_bind_into](config))
}
private module LocalFlowBigStep {
@@ -1306,8 +1305,8 @@ private module LocalFlowBigStep {
pragma[noinline]
private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) {
additionalLocalFlowStepNodeCand1(node1, node2, config) and
Stage2::revFlow(node1, _, _, false, config) and
Stage2::revFlow(node2, _, _, false, unbind(config))
Stage2::revFlow(node1, _, _, false, pragma[only_bind_into](config)) and
Stage2::revFlow(node2, _, _, false, pragma[only_bind_into](config))
}
/**
@@ -1324,7 +1323,7 @@ private module LocalFlowBigStep {
) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, config) and
localFlowEntry(node1, pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and
@@ -1337,22 +1336,22 @@ private module LocalFlowBigStep {
node1 != node2 and
cc.relevantFor(getNodeEnclosingCallable(node1)) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, unbind(config))
Stage2::revFlow(node2, pragma[only_bind_into](config))
or
exists(Node mid |
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
localFlowStepPlus(node1, mid, preservesValue, t, pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, unbind(config))
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
or
exists(Node mid |
localFlowStepPlus(node1, mid, _, _, config, cc) and
localFlowStepPlus(node1, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = getNodeType(node2) and
Stage2::revFlow(node2, unbind(config))
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
)
}
@@ -1459,6 +1458,13 @@ private module Stage3 {
PrevStage::revFlow(node, _, _, apa, config)
}
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
exists(ApApprox apa0 |
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
)
}
/**
* Holds if `node` is reachable with access path `ap` from a source in the
* configuration `config`.
@@ -1470,7 +1476,7 @@ private module Stage3 {
pragma[nomagic]
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindBool(getApprox(ap)), config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
@@ -1494,16 +1500,16 @@ private module Stage3 {
)
or
exists(Node mid |
fwdFlow(mid, _, _, ap, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone()
)
or
exists(Node mid, ApNil nil |
fwdFlow(mid, _, _, nil, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone() and
@@ -1548,7 +1554,7 @@ private module Stage3 {
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindBool(getApprox(ap1)), tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType)
)
}
@@ -1627,7 +1633,7 @@ private module Stage3 {
) {
exists(ParameterNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindBool(getApprox(ap)), config)
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
}
@@ -1675,9 +1681,9 @@ private module Stage3 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, config) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
@@ -1689,9 +1695,9 @@ private module Stage3 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(mid, _, _, nil, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
@@ -1744,9 +1750,10 @@ private module Stage3 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(Node mid |
exists(Node mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
readStepFwd(_, cons, c, mid, tail, config)
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
)
}
@@ -1812,9 +1819,10 @@ private module Stage3 {
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, ap2, config) and
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
pragma[only_bind_into](config))
)
}
@@ -2125,8 +2133,11 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
localFlowEntry(node, config) and
result = getLocalCallContext(cc, getNodeEnclosingCallable(node))
exists(Cc cc0 |
cc = pragma[only_bind_into](cc0) and
localFlowEntry(node, config) and
result = getLocalCallContext(cc0, getNodeEnclosingCallable(node))
)
}
private predicate localStep(
@@ -2141,8 +2152,8 @@ private module Stage4 {
Configuration config
) {
flowOutOfCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, config) and
PrevStage::revFlow(node1, _, _, _, unbind(config))
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
}
pragma[nomagic]
@@ -2151,8 +2162,8 @@ private module Stage4 {
Configuration config
) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, config) and
PrevStage::revFlow(node1, _, _, _, unbind(config))
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
}
bindingset[node, ap]
@@ -2167,6 +2178,13 @@ private module Stage4 {
PrevStage::revFlow(node, _, _, apa, config)
}
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
exists(ApApprox apa0 |
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
)
}
/**
* Holds if `node` is reachable with access path `ap` from a source in the
* configuration `config`.
@@ -2178,7 +2196,7 @@ private module Stage4 {
pragma[nomagic]
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, getApprox(ap), config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
@@ -2202,16 +2220,16 @@ private module Stage4 {
)
or
exists(Node mid |
fwdFlow(mid, _, _, ap, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone()
)
or
exists(Node mid, ApNil nil |
fwdFlow(mid, _, _, nil, config) and
flowCand(node, _, unbind(config)) and
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
flowCand(node, _, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
cc = ccNone() and
argAp = apNone() and
@@ -2256,7 +2274,7 @@ private module Stage4 {
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
typecheckStore(ap1, contentType)
)
}
@@ -2335,7 +2353,7 @@ private module Stage4 {
) {
exists(ParameterNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
}
@@ -2383,9 +2401,9 @@ private module Stage4 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
localStep(node, mid, false, _, config, _) and
revFlow(mid, toReturn, returnAp, nil, config) and
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
ap instanceof ApNil
)
or
@@ -2397,9 +2415,9 @@ private module Stage4 {
)
or
exists(Node mid, ApNil nil |
fwdFlow(node, _, _, ap, config) and
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
additionalJumpStep(node, mid, config) and
revFlow(mid, _, _, nil, config) and
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
toReturn = false and
returnAp = apNone() and
ap instanceof ApNil
@@ -2452,9 +2470,10 @@ private module Stage4 {
*/
pragma[nomagic]
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
exists(Node mid |
exists(Node mid, Ap tail0 |
revFlow(mid, _, _, tail, config) and
readStepFwd(_, cons, c, mid, tail, config)
tail = pragma[only_bind_into](tail0) and
readStepFwd(_, cons, c, mid, tail0, config)
)
}
@@ -2520,9 +2539,10 @@ private module Stage4 {
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
exists(Ap ap1, Ap ap2 |
revFlow(node2, _, _, ap2, config) and
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
readStepFwd(node1, ap1, c, node2, ap2, config) and
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
pragma[only_bind_into](config))
)
}
@@ -2574,7 +2594,9 @@ private module Stage4 {
}
bindingset[conf, result]
private Configuration unbind(Configuration conf) { result >= conf and result <= conf }
private Configuration unbindConf(Configuration conf) {
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
}
private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration config) {
exists(DataFlowCallable c, AccessPathApprox apa0 |
@@ -2744,13 +2766,13 @@ private newtype TPathNode =
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
pathStep(mid, node, cc, sc, ap) and
config = mid.getConfiguration() and
Stage4::revFlow(node, _, _, ap.getApprox(), unbind(config))
pragma[only_bind_into](config) = mid.getConfiguration() and
Stage4::revFlow(node, _, _, ap.getApprox(), pragma[only_bind_into](config))
)
} or
TPathNodeSink(Node node, Configuration config) {
config.isSink(node) and
Stage4::revFlow(node, unbind(config)) and
pragma[only_bind_into](config).isSink(node) and
Stage4::revFlow(node, pragma[only_bind_into](config)) and
(
// A sink that is also a source ...
config.isSource(node)
@@ -2758,7 +2780,7 @@ private newtype TPathNode =
// ... or a sink that can be reached from a source
exists(PathNodeMid mid |
pathStep(mid, node, _, _, TAccessPathNil(_)) and
config = unbind(mid.getConfiguration())
pragma[only_bind_into](config) = mid.getConfiguration()
)
)
}
@@ -3055,7 +3077,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
private PathNodeMid getSuccMid() {
pathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx(), result.getAp()) and
result.getConfiguration() = unbind(this.getConfiguration())
result.getConfiguration() = unbindConf(this.getConfiguration())
}
override PathNodeImpl getASuccessorImpl() {
@@ -3067,7 +3089,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
mid = getSuccMid() and
mid.getNode() = sink.getNode() and
mid.getAp() instanceof AccessPathNil and
sink.getConfiguration() = unbind(mid.getConfiguration()) and
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
result = sink
)
}
@@ -3298,7 +3320,7 @@ private predicate pathThroughCallable0(
) {
exists(CallContext innercc, SummaryCtx sc |
pathIntoCallable(mid, _, cc, innercc, sc, call) and
paramFlowsThrough(kind, innercc, sc, ap, apa, unbind(mid.getConfiguration()))
paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration()))
)
}
@@ -3310,7 +3332,7 @@ pragma[noinline]
private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) {
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
out = getAnOutNodeFlow(kind, call, apa, unbind(mid.getConfiguration()))
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
)
}
@@ -3433,8 +3455,8 @@ private module FlowExploration {
private predicate callableExtStepFwd(TCallableExt ce1, TCallableExt ce2) {
exists(DataFlowCallable c1, DataFlowCallable c2, Configuration config |
callableStep(c1, c2, config) and
ce1 = TCallable(c1, config) and
ce2 = TCallable(c2, unbind(config))
ce1 = TCallable(c1, pragma[only_bind_into](config)) and
ce2 = TCallable(c2, pragma[only_bind_into](config))
)
or
exists(Node n, Configuration config |

View File

@@ -26,15 +26,243 @@ predicate accessPathCostLimits(int apLimit, int tupleLimit) {
tupleLimit = 1000
}
/**
* Provides a simple data-flow analysis for resolving lambda calls. The analysis
* currently excludes read-steps, store-steps, and flow-through.
*
* The analysis uses non-linear recursion: When computing a flow path in or out
* of a call, we use the results of the analysis recursively to resolve lamba
* calls. For this reason, we cannot reuse the code from `DataFlowImpl.qll` directly.
*/
private module LambdaFlow {
private predicate viableParamNonLambda(DataFlowCall call, int i, ParameterNode p) {
p.isParameterOf(viableCallable(call), i)
}
private predicate viableParamLambda(DataFlowCall call, int i, ParameterNode p) {
p.isParameterOf(viableCallableLambda(call, _), i)
}
private predicate viableParamArgNonLambda(DataFlowCall call, ParameterNode p, ArgumentNode arg) {
exists(int i |
viableParamNonLambda(call, i, p) and
arg.argumentOf(call, i)
)
}
private predicate viableParamArgLambda(DataFlowCall call, ParameterNode p, ArgumentNode arg) {
exists(int i |
viableParamLambda(call, i, p) and
arg.argumentOf(call, i)
)
}
private newtype TReturnPositionSimple =
TReturnPositionSimple0(DataFlowCallable c, ReturnKind kind) {
exists(ReturnNode ret |
c = getNodeEnclosingCallable(ret) and
kind = ret.getKind()
)
}
pragma[noinline]
private TReturnPositionSimple getReturnPositionSimple(ReturnNode ret, ReturnKind kind) {
result = TReturnPositionSimple0(getNodeEnclosingCallable(ret), kind)
}
pragma[nomagic]
private TReturnPositionSimple viableReturnPosNonLambda(DataFlowCall call, ReturnKind kind) {
result = TReturnPositionSimple0(viableCallable(call), kind)
}
pragma[nomagic]
private TReturnPositionSimple viableReturnPosLambda(
DataFlowCall call, DataFlowCallOption lastCall, ReturnKind kind
) {
result = TReturnPositionSimple0(viableCallableLambda(call, lastCall), kind)
}
private predicate viableReturnPosOutNonLambda(
DataFlowCall call, TReturnPositionSimple pos, OutNode out
) {
exists(ReturnKind kind |
pos = viableReturnPosNonLambda(call, kind) and
out = getAnOutNode(call, kind)
)
}
private predicate viableReturnPosOutLambda(
DataFlowCall call, DataFlowCallOption lastCall, TReturnPositionSimple pos, OutNode out
) {
exists(ReturnKind kind |
pos = viableReturnPosLambda(call, lastCall, kind) and
out = getAnOutNode(call, kind)
)
}
/**
* Holds if data can flow (inter-procedurally) from `node` (of type `t`) to
* the lambda call `lambdaCall`.
*
* The parameter `toReturn` indicates whether the path from `node` to
* `lambdaCall` goes through a return, and `toJump` whether the path goes
* through a jump step.
*
* The call context `lastCall` records the last call on the path from `node`
* to `lambdaCall`, if any. That is, `lastCall` is able to target the enclosing
* callable of `lambdaCall`.
*/
pragma[nomagic]
predicate revLambdaFlow(
DataFlowCall lambdaCall, LambdaCallKind kind, Node node, DataFlowType t, boolean toReturn,
boolean toJump, DataFlowCallOption lastCall
) {
revLambdaFlow0(lambdaCall, kind, node, t, toReturn, toJump, lastCall) and
if node instanceof CastNode or node instanceof ArgumentNode or node instanceof ReturnNode
then compatibleTypes(t, getNodeType(node))
else any()
}
pragma[nomagic]
predicate revLambdaFlow0(
DataFlowCall lambdaCall, LambdaCallKind kind, Node node, DataFlowType t, boolean toReturn,
boolean toJump, DataFlowCallOption lastCall
) {
lambdaCall(lambdaCall, kind, node) and
t = getNodeType(node) and
toReturn = false and
toJump = false and
lastCall = TDataFlowCallNone()
or
// local flow
exists(Node mid, DataFlowType t0 |
revLambdaFlow(lambdaCall, kind, mid, t0, toReturn, toJump, lastCall)
|
simpleLocalFlowStep(node, mid) and
t = t0
or
exists(boolean preservesValue |
additionalLambdaFlowStep(node, mid, preservesValue) and
getNodeEnclosingCallable(node) = getNodeEnclosingCallable(mid)
|
preservesValue = false and
t = getNodeType(node)
or
preservesValue = true and
t = t0
)
)
or
// jump step
exists(Node mid, DataFlowType t0 |
revLambdaFlow(lambdaCall, kind, mid, t0, _, _, _) and
toReturn = false and
toJump = true and
lastCall = TDataFlowCallNone()
|
jumpStep(node, mid) and
t = t0
or
exists(boolean preservesValue |
additionalLambdaFlowStep(node, mid, preservesValue) and
getNodeEnclosingCallable(node) != getNodeEnclosingCallable(mid)
|
preservesValue = false and
t = getNodeType(node)
or
preservesValue = true and
t = t0
)
)
or
// flow into a callable
exists(ParameterNode p, DataFlowCallOption lastCall0, DataFlowCall call |
revLambdaFlowIn(lambdaCall, kind, p, t, toJump, lastCall0) and
(
if lastCall0 = TDataFlowCallNone() and toJump = false
then lastCall = TDataFlowCallSome(call)
else lastCall = lastCall0
) and
toReturn = false
|
viableParamArgNonLambda(call, p, node)
or
viableParamArgLambda(call, p, node) // non-linear recursion
)
or
// flow out of a callable
exists(TReturnPositionSimple pos |
revLambdaFlowOut(lambdaCall, kind, pos, t, toJump, lastCall) and
getReturnPositionSimple(node, node.(ReturnNode).getKind()) = pos and
toReturn = true
)
}
pragma[nomagic]
predicate revLambdaFlowOutLambdaCall(
DataFlowCall lambdaCall, LambdaCallKind kind, OutNode out, DataFlowType t, boolean toJump,
DataFlowCall call, DataFlowCallOption lastCall
) {
revLambdaFlow(lambdaCall, kind, out, t, _, toJump, lastCall) and
exists(ReturnKindExt rk |
out = rk.getAnOutNode(call) and
lambdaCall(call, _, _)
)
}
pragma[nomagic]
predicate revLambdaFlowOut(
DataFlowCall lambdaCall, LambdaCallKind kind, TReturnPositionSimple pos, DataFlowType t,
boolean toJump, DataFlowCallOption lastCall
) {
exists(DataFlowCall call, OutNode out |
revLambdaFlow(lambdaCall, kind, out, t, _, toJump, lastCall) and
viableReturnPosOutNonLambda(call, pos, out)
or
// non-linear recursion
revLambdaFlowOutLambdaCall(lambdaCall, kind, out, t, toJump, call, lastCall) and
viableReturnPosOutLambda(call, _, pos, out)
)
}
pragma[nomagic]
predicate revLambdaFlowIn(
DataFlowCall lambdaCall, LambdaCallKind kind, ParameterNode p, DataFlowType t, boolean toJump,
DataFlowCallOption lastCall
) {
revLambdaFlow(lambdaCall, kind, p, t, false, toJump, lastCall)
}
}
private DataFlowCallable viableCallableExt(DataFlowCall call) {
result = viableCallable(call)
or
result = viableCallableLambda(call, _)
}
cached
private module Cached {
/**
* Gets a viable target for the lambda call `call`.
*
* `lastCall` records the call required to reach `call` in order for the result
* to be a viable target, if any.
*/
cached
DataFlowCallable viableCallableLambda(DataFlowCall call, DataFlowCallOption lastCall) {
exists(Node creation, LambdaCallKind kind |
LambdaFlow::revLambdaFlow(call, kind, creation, _, _, _, lastCall) and
lambdaCreation(creation, kind, result)
)
}
/**
* Holds if `p` is the `i`th parameter of a viable dispatch target of `call`.
* The instance parameter is considered to have index `-1`.
*/
pragma[nomagic]
private predicate viableParam(DataFlowCall call, int i, ParameterNode p) {
p.isParameterOf(viableCallable(call), i)
p.isParameterOf(viableCallableExt(call), i)
}
/**
@@ -52,7 +280,7 @@ private module Cached {
pragma[nomagic]
private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) {
viableCallable(call) = result.getCallable() and
viableCallableExt(call) = result.getCallable() and
kind = result.getKind()
}
@@ -317,6 +545,35 @@ private module Cached {
cached
private module DispatchWithCallContext {
/**
* Holds if the set of viable implementations that can be called by `call`
* might be improved by knowing the call context.
*/
pragma[nomagic]
private predicate mayBenefitFromCallContextExt(DataFlowCall call, DataFlowCallable callable) {
mayBenefitFromCallContext(call, callable)
or
callable = call.getEnclosingCallable() and
exists(viableCallableLambda(call, TDataFlowCallSome(_)))
}
/**
* Gets a viable dispatch target of `call` in the context `ctx`. This is
* restricted to those `call`s for which a context might make a difference.
*/
pragma[nomagic]
private DataFlowCallable viableImplInCallContextExt(DataFlowCall call, DataFlowCall ctx) {
result = viableImplInCallContext(call, ctx)
or
result = viableCallableLambda(call, TDataFlowCallSome(ctx))
or
exists(DataFlowCallable enclosing |
mayBenefitFromCallContextExt(call, enclosing) and
enclosing = viableCallableExt(ctx) and
result = viableCallableLambda(call, TDataFlowCallNone())
)
}
/**
* Holds if the call context `ctx` reduces the set of viable run-time
* dispatch targets of call `call` in `c`.
@@ -324,10 +581,10 @@ private module Cached {
cached
predicate reducedViableImplInCallContext(DataFlowCall call, DataFlowCallable c, DataFlowCall ctx) {
exists(int tgts, int ctxtgts |
mayBenefitFromCallContext(call, c) and
c = viableCallable(ctx) and
ctxtgts = count(viableImplInCallContext(call, ctx)) and
tgts = strictcount(viableCallable(call)) and
mayBenefitFromCallContextExt(call, c) and
c = viableCallableExt(ctx) and
ctxtgts = count(viableImplInCallContextExt(call, ctx)) and
tgts = strictcount(viableCallableExt(call)) and
ctxtgts < tgts
)
}
@@ -339,7 +596,7 @@ private module Cached {
*/
cached
DataFlowCallable prunedViableImplInCallContext(DataFlowCall call, DataFlowCall ctx) {
result = viableImplInCallContext(call, ctx) and
result = viableImplInCallContextExt(call, ctx) and
reducedViableImplInCallContext(call, _, ctx)
}
@@ -351,10 +608,10 @@ private module Cached {
cached
predicate reducedViableImplInReturn(DataFlowCallable c, DataFlowCall call) {
exists(int tgts, int ctxtgts |
mayBenefitFromCallContext(call, _) and
c = viableCallable(call) and
ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContext(call, ctx)) and
tgts = strictcount(DataFlowCall ctx | viableCallable(ctx) = call.getEnclosingCallable()) and
mayBenefitFromCallContextExt(call, _) and
c = viableCallableExt(call) and
ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContextExt(call, ctx)) and
tgts = strictcount(DataFlowCall ctx | viableCallableExt(ctx) = call.getEnclosingCallable()) and
ctxtgts < tgts
)
}
@@ -367,7 +624,7 @@ private module Cached {
*/
cached
DataFlowCallable prunedViableImplInCallContextReverse(DataFlowCall call, DataFlowCall ctx) {
result = viableImplInCallContext(call, ctx) and
result = viableImplInCallContextExt(call, ctx) and
reducedViableImplInReturn(result, call)
}
}
@@ -481,6 +738,11 @@ private module Cached {
TBooleanNone() or
TBooleanSome(boolean b) { b = true or b = false }
cached
newtype TDataFlowCallOption =
TDataFlowCallNone() or
TDataFlowCallSome(DataFlowCall call)
cached
newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) }
@@ -777,7 +1039,7 @@ ReturnPosition getReturnPosition(ReturnNodeExt ret) {
bindingset[cc, callable]
predicate resolveReturn(CallContext cc, DataFlowCallable callable, DataFlowCall call) {
cc instanceof CallContextAny and callable = viableCallable(call)
cc instanceof CallContextAny and callable = viableCallableExt(call)
or
exists(DataFlowCallable c0, DataFlowCall call0 |
call0.getEnclosingCallable() = callable and
@@ -791,14 +1053,14 @@ DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) {
exists(DataFlowCall ctx | cc = TSpecificCall(ctx) |
if reducedViableImplInCallContext(call, _, ctx)
then result = prunedViableImplInCallContext(call, ctx)
else result = viableCallable(call)
else result = viableCallableExt(call)
)
or
result = viableCallable(call) and cc instanceof CallContextSomeCall
result = viableCallableExt(call) and cc instanceof CallContextSomeCall
or
result = viableCallable(call) and cc instanceof CallContextAny
result = viableCallableExt(call) and cc instanceof CallContextAny
or
result = viableCallable(call) and cc instanceof CallContextReturn
result = viableCallableExt(call) and cc instanceof CallContextReturn
}
predicate read = readStep/3;
@@ -812,6 +1074,19 @@ class BooleanOption extends TBooleanOption {
}
}
/** An optional `DataFlowCall`. */
class DataFlowCallOption extends TDataFlowCallOption {
string toString() {
this = TDataFlowCallNone() and
result = "(none)"
or
exists(DataFlowCall call |
this = TDataFlowCallSome(call) and
result = call.toString()
)
}
}
/** Content tagged with the type of a containing object. */
class TypedContent extends MkTypedContent {
private Content c;

View File

@@ -548,3 +548,14 @@ predicate isImmutableOrUnobservable(Node n) {
/** Holds if `n` should be hidden from path explanations. */
predicate nodeIsHidden(Node n) { n instanceof OperandNode and not n instanceof ArgumentNode }
class LambdaCallKind = Unit;
/** Holds if `creation` is an expression that creates a lambda of kind `kind` for `c`. */
predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c) { none() }
/** Holds if `call` is a lambda call of kind `kind` where `receiver` is the lambda expression. */
predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) { none() }
/** Extra data-flow steps needed for lamba flow analysis. */
predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) { none() }

View File

@@ -15,9 +15,7 @@ import semmle.code.cpp.models.interfaces.SideEffect
private class Accept extends ArrayFunction, AliasFunction, TaintFunction, SideEffectFunction {
Accept() { this.hasGlobalName(["accept", "accept4", "WSAAccept"]) }
override predicate hasArrayWithVariableSize(int bufParam, int countParam) {
bufParam = 1 and countParam = 2
}
override predicate hasArrayWithUnknownSize(int bufParam) { bufParam = 1 }
override predicate hasArrayInput(int bufParam) { bufParam = 1 }
@@ -46,8 +44,8 @@ private class Accept extends ArrayFunction, AliasFunction, TaintFunction, SideEf
i = 1 and buffer = false
}
override ParameterIndex getParameterSizeIndex(ParameterIndex i) { i = 1 and result = 2 }
// NOTE: The size parameter is a pointer to the size. So we can't implement `getParameterSizeIndex` for
// this model.
// NOTE: We implement thse two predicates as none because we can't model the low-level changes made to
// the structure pointed to by the file-descriptor argument.
override predicate hasOnlySpecificReadSideEffects() { none() }

View File

@@ -19,6 +19,6 @@ void test_accept() {
int size = sizeof(sockaddr);
int a = accept(s, &addr, &size);
sink(a); // $ ast=17:11 SPURIOUS: ast=18:12 MISSING: ir
sink(addr); // $ ast MISSING: ir
sink(a); // $ ast=17:11 ir SPURIOUS: ast=18:12
sink(addr); // $ ast,ir
}

View File

@@ -0,0 +1,7 @@
void accept(int arg, char *buf, unsigned long* bufSize);
void testAccept(int socket1, int socket2)
{
char buffer[1024];
accept(socket2, 0, 0);
}

View File

@@ -47,6 +47,18 @@ edges
| test.cpp:76:12:76:17 | fgets output argument | test.cpp:79:10:79:13 | (const char *)... |
| test.cpp:76:12:76:17 | fgets output argument | test.cpp:79:10:79:13 | data |
| test.cpp:76:12:76:17 | fgets output argument | test.cpp:79:10:79:13 | data indirection |
| test.cpp:98:17:98:22 | buffer | test.cpp:99:15:99:20 | (const char *)... |
| test.cpp:98:17:98:22 | buffer | test.cpp:99:15:99:20 | buffer |
| test.cpp:98:17:98:22 | buffer | test.cpp:99:15:99:20 | buffer indirection |
| test.cpp:98:17:98:22 | recv output argument | test.cpp:99:15:99:20 | (const char *)... |
| test.cpp:98:17:98:22 | recv output argument | test.cpp:99:15:99:20 | buffer |
| test.cpp:98:17:98:22 | recv output argument | test.cpp:99:15:99:20 | buffer indirection |
| test.cpp:106:17:106:22 | buffer | test.cpp:107:15:107:20 | (const char *)... |
| test.cpp:106:17:106:22 | buffer | test.cpp:107:15:107:20 | buffer |
| test.cpp:106:17:106:22 | buffer | test.cpp:107:15:107:20 | buffer indirection |
| test.cpp:106:17:106:22 | recv output argument | test.cpp:107:15:107:20 | (const char *)... |
| test.cpp:106:17:106:22 | recv output argument | test.cpp:107:15:107:20 | buffer |
| test.cpp:106:17:106:22 | recv output argument | test.cpp:107:15:107:20 | buffer indirection |
nodes
| test.cpp:24:30:24:36 | *command | semmle.label | *command |
| test.cpp:24:30:24:36 | command | semmle.label | command |
@@ -94,6 +106,20 @@ nodes
| test.cpp:79:10:79:13 | data | semmle.label | data |
| test.cpp:79:10:79:13 | data indirection | semmle.label | data indirection |
| test.cpp:79:10:79:13 | data indirection | semmle.label | data indirection |
| test.cpp:98:17:98:22 | buffer | semmle.label | buffer |
| test.cpp:98:17:98:22 | recv output argument | semmle.label | recv output argument |
| test.cpp:99:15:99:20 | (const char *)... | semmle.label | (const char *)... |
| test.cpp:99:15:99:20 | (const char *)... | semmle.label | (const char *)... |
| test.cpp:99:15:99:20 | buffer | semmle.label | buffer |
| test.cpp:99:15:99:20 | buffer indirection | semmle.label | buffer indirection |
| test.cpp:99:15:99:20 | buffer indirection | semmle.label | buffer indirection |
| test.cpp:106:17:106:22 | buffer | semmle.label | buffer |
| test.cpp:106:17:106:22 | recv output argument | semmle.label | recv output argument |
| test.cpp:107:15:107:20 | (const char *)... | semmle.label | (const char *)... |
| test.cpp:107:15:107:20 | (const char *)... | semmle.label | (const char *)... |
| test.cpp:107:15:107:20 | buffer | semmle.label | buffer |
| test.cpp:107:15:107:20 | buffer indirection | semmle.label | buffer indirection |
| test.cpp:107:15:107:20 | buffer indirection | semmle.label | buffer indirection |
#select
| test.cpp:26:10:26:16 | command | test.cpp:42:18:42:23 | call to getenv | test.cpp:26:10:26:16 | command | The value of this argument may come from $@ and is being passed to system | test.cpp:42:18:42:23 | call to getenv | call to getenv |
| test.cpp:31:10:31:16 | command | test.cpp:43:18:43:23 | call to getenv | test.cpp:31:10:31:16 | command | The value of this argument may come from $@ and is being passed to system | test.cpp:43:18:43:23 | call to getenv | call to getenv |
@@ -101,3 +127,5 @@ nodes
| test.cpp:63:10:63:13 | data | test.cpp:56:12:56:17 | buffer | test.cpp:63:10:63:13 | data | The value of this argument may come from $@ and is being passed to system | test.cpp:56:12:56:17 | buffer | buffer |
| test.cpp:78:10:78:15 | buffer | test.cpp:76:12:76:17 | buffer | test.cpp:78:10:78:15 | buffer | The value of this argument may come from $@ and is being passed to system | test.cpp:76:12:76:17 | buffer | buffer |
| test.cpp:79:10:79:13 | data | test.cpp:76:12:76:17 | buffer | test.cpp:79:10:79:13 | data | The value of this argument may come from $@ and is being passed to system | test.cpp:76:12:76:17 | buffer | buffer |
| test.cpp:99:15:99:20 | buffer | test.cpp:98:17:98:22 | buffer | test.cpp:99:15:99:20 | buffer | The value of this argument may come from $@ and is being passed to LoadLibrary | test.cpp:98:17:98:22 | buffer | buffer |
| test.cpp:107:15:107:20 | buffer | test.cpp:106:17:106:22 | buffer | test.cpp:107:15:107:20 | buffer | The value of this argument may come from $@ and is being passed to LoadLibrary | test.cpp:106:17:106:22 | buffer | buffer |

View File

@@ -81,3 +81,29 @@ void testReferencePointer2()
system(data2); // BAD [NOT DETECTED]
}
}
// ---
typedef unsigned long size_t;
void accept(int arg, char *buf, size_t *bufSize);
void recv(int arg, char *buf, size_t bufSize);
void LoadLibrary(const char *arg);
void testAcceptRecv(int socket1, int socket2)
{
{
char buffer[1024];
recv(socket1, buffer, 1024);
LoadLibrary(buffer); // BAD: using data from recv
}
{
char buffer[1024];
accept(socket2, 0, 0);
recv(socket2, buffer, 1024);
LoadLibrary(buffer); // BAD: using data from recv
}
}

View File

@@ -0,0 +1 @@
| 93 |

View File

@@ -0,0 +1 @@
Summary/LinesOfCode.ql

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1,123 @@
int a00(float x) {
return (int)x;
}
int a01(float x) {
return (int)x;
}
int a02(float x) {
return (int)x;
}
int a03(float x) {
return (int)x;
}
int a04(float x) {
return (int)x;
}
int a05(float x) {
return (int)x;
}
int a06(float x) {
return (int)x;
}
/**
* This is a multi-line comment
*/
int a07(float x) {
return (int)x;
}
// this is a single-line comment
int a08(float x) {
return (int)x;
}
int a09(float x) {
return (int)x;
}
int a10(float x) {
return (int)x;
}
int a11(float x) {
return (int)x;
}
int a12(float x) {
return (int)x;
}
int a13(float x) {
return (int)x;
}
int a14(float x) {
return (int)x;
}
int a15(float x) {
return (int)x;
}
int a16(float x) {
return (int)x;
}
int a17(float x) {
return (int)x;
}
int a18(float x) {
return (int)x;
}
int a19(float x) {
return (int)x;
}
int a20(float x) {
return (int)x;
}
int a21(float x) {
return (int)x;
}
int a22(float x) {
return (int)x;
}
int a23(float x) {
return (int)x;
}
int a24(float x) {
return (int)x;
}
int a25(float x) {
return (int)x;
}
int a26(float x) {
return (int)x;
}
int a27(float x) {
return (int)x;
}
int a28(float x) {
return (int)x;
}
int a29(float x) {
return (int)x;
}

View File

@@ -0,0 +1,3 @@
int g(float x) {
return (int)x;
}

View File

@@ -145,7 +145,7 @@ namespace Semmle.Autobuild.CSharp
try
{
var o = JObject.Parse(File.ReadAllText(path));
version = (string)o["sdk"]["version"];
version = (string)(o?["sdk"]?["version"]!);
}
catch // lgtm[cs/catch-of-all-exceptions]
{

View File

@@ -17,8 +17,8 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Build" Version="16.0.461" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
<PackageReference Include="Microsoft.Build" Version="16.9.0" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
</ItemGroup>
<ItemGroup>

View File

@@ -14,7 +14,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Build" Version="16.0.461" />
<PackageReference Include="Microsoft.Build" Version="16.9.0" />
</ItemGroup>
<ItemGroup>

View File

@@ -0,0 +1,3 @@
lgtm,codescanning
* Data flow for tuples has been improved to track data flowing into and out of
tuple fields. Tuple extraction was changed to extract non-named tuple elements.

View File

@@ -0,0 +1,2 @@
lgtm,codescanning
* A static single assignment (SSA) library has been added to the CIL analysis library. The SSA library replaces the existing `DefUse` module, which has been deprecated.

View File

@@ -0,0 +1,2 @@
lgtm,codescanning
* Legacy queries in the folders `external` and `filters` have all been removed.

View File

@@ -0,0 +1,2 @@
lgtm,codescanning
* The query `VulnerablePackage.ql` has been removed.

View File

@@ -23,7 +23,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Build" Version="16.0.461" />
<PackageReference Include="Microsoft.Build" Version="16.9.0" />
<PackageReference Include="Microsoft.Win32.Primitives" Version="4.3.0" />
<PackageReference Include="System.Net.Primitives" Version="4.3.1" />
<PackageReference Include="System.Security.Principal" Version="4.3.0" />

View File

@@ -151,13 +151,10 @@ namespace Semmle.Extraction.CSharp.Entities
if (handleProp is null)
{
var underlyingSymbolProp = GetPropertyInfo(Symbol, "UnderlyingSymbol");
if (underlyingSymbolProp is not null)
if (underlyingSymbolProp?.GetValue(Symbol) is object underlying)
{
if (underlyingSymbolProp.GetValue(Symbol) is object underlying)
{
handleProp = GetPropertyInfo(underlying, "Handle");
handleObj = underlying;
}
handleProp = GetPropertyInfo(underlying, "Handle");
handleObj = underlying;
}
}

View File

@@ -12,11 +12,11 @@ namespace Semmle.Extraction.CSharp.Entities
internal class Expression : FreshEntity, IExpressionParentEntity
{
private readonly IExpressionInfo info;
public AnnotatedTypeSymbol? Type { get; }
public AnnotatedTypeSymbol? Type { get; private set; }
public Extraction.Entities.Location Location { get; }
public ExprKind Kind { get; }
internal Expression(IExpressionInfo info)
internal Expression(IExpressionInfo info, bool shouldPopulate = true)
: base(info.Context)
{
this.info = info;
@@ -24,7 +24,10 @@ namespace Semmle.Extraction.CSharp.Entities
Kind = info.Kind;
Type = info.Type;
TryPopulate();
if (shouldPopulate)
{
TryPopulate();
}
}
protected sealed override void Populate(TextWriter trapFile)
@@ -59,6 +62,14 @@ namespace Semmle.Extraction.CSharp.Entities
public override Location? ReportingLocation => Location.Symbol;
internal void SetType(ITypeSymbol? type)
{
if (type is not null)
{
Type = new AnnotatedTypeSymbol(type, type.NullableAnnotation);
}
}
bool IExpressionParentEntity.IsTopLevelParent => false;
/// <summary>

View File

@@ -3,7 +3,7 @@ using Semmle.Extraction.Kinds;
namespace Semmle.Extraction.CSharp.Entities.Expressions
{
internal class ImplicitCast : Expression
internal sealed class ImplicitCast : Expression
{
public Expression Expr
{

View File

@@ -4,7 +4,7 @@ using Semmle.Extraction.Kinds;
namespace Semmle.Extraction.CSharp.Entities.Expressions
{
internal class MemberAccess : Expression
internal sealed class MemberAccess : Expression
{
private MemberAccess(ExpressionNodeInfo info, ExpressionSyntax qualifier, ISymbol? target) : base(info)
{

View File

@@ -3,7 +3,9 @@ using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Semmle.Extraction.CSharp.Populators;
using Semmle.Extraction.Kinds;
using Semmle.Extraction.Entities;
using System.Collections.Generic;
using System.Linq;
using System.Collections.Immutable;
namespace Semmle.Extraction.CSharp.Entities.Expressions
{
@@ -47,16 +49,17 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
/// Create a tuple expression representing a parenthesized variable declaration.
/// That is, we consider `var (x, y) = ...` to be equivalent to `(var x, var y) = ...`.
/// </summary>
public static Expression CreateParenthesized(Context cx, DeclarationExpressionSyntax node, ParenthesizedVariableDesignationSyntax designation, IExpressionParentEntity parent, int child)
public static Expression CreateParenthesized(Context cx, DeclarationExpressionSyntax node, ParenthesizedVariableDesignationSyntax designation, IExpressionParentEntity parent, int child, INamedTypeSymbol? t)
{
AnnotatedTypeSymbol? type = null; // Should ideally be a corresponding tuple type
var type = t is null ? (AnnotatedTypeSymbol?)null : new AnnotatedTypeSymbol(t, t.NullableAnnotation);
var tuple = new Expression(new ExpressionInfo(cx, type, cx.CreateLocation(node.GetLocation()), ExprKind.TUPLE, parent, child, false, null));
cx.Try(null, null, () =>
{
var child0 = 0;
foreach (var variable in designation.Variables)
Create(cx, node, variable, tuple, child0++);
for (var child0 = 0; child0 < designation.Variables.Count; child0++)
{
Create(cx, node, designation.Variables[child0], tuple, child0, t?.TypeArguments[child0] as INamedTypeSymbol);
}
});
return tuple;
@@ -64,18 +67,21 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
public static Expression CreateParenthesized(Context cx, VarPatternSyntax varPattern, ParenthesizedVariableDesignationSyntax designation, IExpressionParentEntity parent, int child)
{
AnnotatedTypeSymbol? type = null; // Should ideally be a corresponding tuple type
var tuple = new Expression(new ExpressionInfo(cx, type, cx.CreateLocation(varPattern.GetLocation()), ExprKind.TUPLE, parent, child, false, null));
var tuple = new Expression(
new ExpressionInfo(cx, null, cx.CreateLocation(varPattern.GetLocation()), ExprKind.TUPLE, parent, child, false, null),
shouldPopulate: false);
var elementTypes = new List<ITypeSymbol?>();
cx.Try(null, null, () =>
{
var child0 = 0;
foreach (var variable in designation.Variables)
{
Expression sub;
switch (variable)
{
case ParenthesizedVariableDesignationSyntax paren:
CreateParenthesized(cx, varPattern, paren, tuple, child0++);
sub = CreateParenthesized(cx, varPattern, paren, tuple, child0++);
break;
case SingleVariableDesignationSyntax single:
if (cx.GetModel(variable).GetDeclaredSymbol(single) is ILocalSymbol local)
@@ -83,6 +89,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
var decl = Create(cx, variable, local.GetAnnotatedType(), tuple, child0++);
var l = LocalVariable.Create(cx, local);
l.PopulateManual(decl, true);
sub = decl;
}
else
{
@@ -90,26 +97,43 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
}
break;
case DiscardDesignationSyntax discard:
new Discard(cx, discard, tuple, child0++);
sub = new Discard(cx, discard, tuple, child0++);
if (!sub.Type.HasValue || sub.Type.Value.Symbol is null)
{
// The type is only updated in memory, it will not be written to the trap file.
sub.SetType(cx.Compilation.GetSpecialType(SpecialType.System_Object));
}
break;
default:
throw new InternalError(variable, "Unhandled designation type");
}
elementTypes.Add(sub.Type.HasValue && sub.Type.Value.Symbol?.Kind != SymbolKind.ErrorType
? sub.Type.Value.Symbol
: null);
}
});
INamedTypeSymbol? tupleType = null;
if (!elementTypes.Any(et => et is null))
{
tupleType = cx.Compilation.CreateTupleTypeSymbol(elementTypes.ToImmutableArray()!);
}
tuple.SetType(tupleType);
tuple.TryPopulate();
return tuple;
}
private static Expression Create(Context cx, DeclarationExpressionSyntax node, VariableDesignationSyntax? designation, IExpressionParentEntity parent, int child)
private static Expression Create(Context cx, DeclarationExpressionSyntax node, VariableDesignationSyntax? designation, IExpressionParentEntity parent, int child, INamedTypeSymbol? declarationType)
{
switch (designation)
{
case SingleVariableDesignationSyntax single:
return CreateSingle(cx, node, single, parent, child);
case ParenthesizedVariableDesignationSyntax paren:
return CreateParenthesized(cx, node, paren, parent, child);
return CreateParenthesized(cx, node, paren, parent, child, declarationType);
case DiscardDesignationSyntax discard:
var type = cx.GetType(discard);
return Create(cx, node, type, parent, child);
@@ -120,7 +144,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
}
public static Expression Create(Context cx, DeclarationExpressionSyntax node, IExpressionParentEntity parent, int child) =>
Create(cx, node, node.Designation, parent, child);
Create(cx, node, node.Designation, parent, child, cx.GetTypeInfo(node).Type.DisambiguateType() as INamedTypeSymbol);
public static VariableDeclaration Create(Context cx, CSharpSyntaxNode c, AnnotatedTypeSymbol? type, IExpressionParentEntity parent, int child) =>
new VariableDeclaration(new ExpressionInfo(cx, type, cx.CreateLocation(c.FixedLocation()), ExprKind.LOCAL_VAR_DECL, parent, child, false, null));

View File

@@ -17,7 +17,7 @@ namespace Semmle.Extraction.CSharp.Entities
type = new Lazy<Type>(() => Entities.Type.Create(cx, Symbol.Type));
}
public static Field Create(Context cx, IFieldSymbol field) => FieldFactory.Instance.CreateEntityFromSymbol(cx, field);
public static Field Create(Context cx, IFieldSymbol field) => FieldFactory.Instance.CreateEntityFromSymbol(cx, field.CorrespondingTupleField ?? field);
// Do not populate backing fields.
// Populate Tuple fields.

View File

@@ -13,7 +13,7 @@ namespace Semmle.Extraction.CSharp.Entities
/// </summary>
internal class TupleType : Type<INamedTypeSymbol>
{
public static TupleType Create(Context cx, INamedTypeSymbol type) => TupleTypeFactory.Instance.CreateEntityFromSymbol(cx, type);
public static TupleType Create(Context cx, INamedTypeSymbol type) => TupleTypeFactory.Instance.CreateEntityFromSymbol(cx, type.TupleUnderlyingType ?? type);
private class TupleTypeFactory : CachedEntityFactory<INamedTypeSymbol, TupleType>
{
@@ -41,7 +41,7 @@ namespace Semmle.Extraction.CSharp.Entities
PopulateType(trapFile);
PopulateGenerics();
var underlyingType = NamedType.CreateNamedTypeFromTupleType(Context, Symbol.TupleUnderlyingType ?? Symbol);
var underlyingType = NamedType.CreateNamedTypeFromTupleType(Context, Symbol);
trapFile.tuple_underlying_type(this, underlyingType);

View File

@@ -22,7 +22,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.8.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.9.0" />
</ItemGroup>
</Project>

View File

@@ -295,7 +295,7 @@ namespace Semmle.Extraction.CSharp
trapFile.BuildList(",", named.TupleElements,
(f, tb0) =>
{
trapFile.Write(f.Name);
trapFile.Write((f.CorrespondingTupleField ?? f).Name);
trapFile.Write(":");
f.Type.BuildOrWriteId(cx, tb0, symbolBeingDefined, addBaseClass);
}
@@ -625,7 +625,14 @@ namespace Semmle.Extraction.CSharp
{
try
{
return symbol.Accept(new Populators.Symbols(cx));
var entity = symbol.Accept(new Populators.Symbols(cx));
if (entity is null)
{
cx.ModelError(symbol, $"Symbol visitor returned null entity on symbol: {symbol}");
}
#nullable disable warnings
return entity;
#nullable restore warnings
}
catch (Exception ex) // lgtm[cs/catch-of-all-exceptions]
{

View File

@@ -13,7 +13,7 @@ namespace Semmle.Extraction
protected abstract void Populate(TextWriter trapFile);
protected void TryPopulate()
public void TryPopulate()
{
Context.Try(null, null, () => Populate(Context.TrapWriter.Writer));
}

View File

@@ -15,7 +15,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis" Version="3.8.0" />
<PackageReference Include="Microsoft.CodeAnalysis" Version="3.9.0" />
<PackageReference Include="GitInfo" Version="2.0.20">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>

View File

@@ -5,7 +5,6 @@
* @kind treemap
* @treemap.warnOn highValues
* @metricType externalDependency
* @precision medium
* @id cs/external-dependencies
*/

View File

@@ -1,16 +0,0 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
Duplicated code increases overall code size, making the code base
harder to maintain and harder to understand. It also becomes harder to fix bugs,
since a programmer applying a fix to one copy has to always remember to update
other copies accordingly. Finally, code duplication is generally an indication of
a poorly designed or hastily written code base, which typically suffers from other
problems as well.
</p>
</overview>
</qhelp>

View File

@@ -5,7 +5,6 @@
* @treemap.warnOn highValues
* @metricType file
* @metricAggregate avg sum max
* @precision very-high
* @id cs/lines-of-code-in-files
* @tags maintainability
* complexity

View File

@@ -5,7 +5,6 @@
* @treemap.warnOn lowValues
* @metricType file
* @metricAggregate avg sum max
* @precision very-high
* @id cs/lines-of-comments-in-files
* @tags maintainability
* documentation

View File

@@ -5,7 +5,6 @@
* @treemap.warnOn highValues
* @metricType file
* @metricAggregate avg sum max
* @precision high
* @id cs/lines-of-commented-out-code-in-files
* @tags maintainability
* documentation

View File

@@ -1,30 +0,0 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
A file that contains many lines that are duplicated within the code base is problematic
for a number of reasons.
</p>
</overview>
<include src="DuplicationProblems.inc.qhelp" />
<recommendation>
<p>
Refactor files with lots of duplicated code to extract the common code into
shared classes and assemblies.
</p>
</recommendation>
<references>
<li>Wikipedia: <a href="http://en.wikipedia.org/wiki/Duplicate_code">Duplicate code</a>.</li>
<li>M. Fowler, <em>Refactoring</em>. Addison-Wesley, 1999.</li>
</references>
</qhelp>

View File

@@ -1,27 +0,0 @@
/**
* @deprecated
* @name Duplicated lines in files
* @description The number of lines in a file, including code, comment and whitespace lines,
* which are duplicated in at least one other place.
* @kind treemap
* @treemap.warnOn highValues
* @metricType file
* @metricAggregate avg sum max
* @precision high
* @id cs/duplicated-lines-in-files
* @tags testability
* modularity
*/
import external.CodeDuplication
from SourceFile f, int n
where
n =
count(int line |
exists(DuplicateBlock d | d.sourceFile() = f |
line in [d.sourceStartLine() .. d.sourceEndLine()] and
not whitelistedLineForDuplication(f, line)
)
)
select f, n order by n desc

View File

@@ -5,7 +5,6 @@
* @treemap.warnOn highValues
* @metricType file
* @metricAggregate avg sum max
* @precision medium
* @id cs/tests-in-files
* @tags maintainability
*/

View File

@@ -1,335 +0,0 @@
/**
* Provides a list of NuGet packages with known vulnerabilities.
*
* To add a new vulnerability follow the existing pattern.
* Create a new class that extends the abstract class `Vulnerability`,
* supplying the name and the URL, and override one (or both) of
* `matchesRange` and `matchesVersion`.
*/
import csharp
import Vulnerability
class MicrosoftAdvisory4021279 extends Vulnerability {
MicrosoftAdvisory4021279() { this = "Microsoft Security Advisory 4021279" }
override string getUrl() { result = "https://github.com/dotnet/corefx/issues/19535" }
override predicate matchesRange(string name, Version affected, Version fixed) {
name = "System.Text.Encodings.Web" and
(
affected = "4.0.0" and fixed = "4.0.1"
or
affected = "4.3.0" and fixed = "4.3.1"
)
or
name = "System.Net.Http" and
(
affected = "4.1.1" and fixed = "4.1.2"
or
affected = "4.3.1" and fixed = "4.3.2"
)
or
name = "System.Net.Http.WinHttpHandler" and
(
affected = "4.0.1" and fixed = "4.0.2"
or
affected = "4.3.0" and fixed = "4.3.1"
)
or
name = "System.Net.Security" and
(
affected = "4.0.0" and fixed = "4.0.1"
or
affected = "4.3.0" and fixed = "4.3.1"
)
or
(
name = "Microsoft.AspNetCore.Mvc"
or
name = "Microsoft.AspNetCore.Mvc.Core"
or
name = "Microsoft.AspNetCore.Mvc.Abstractions"
or
name = "Microsoft.AspNetCore.Mvc.ApiExplorer"
or
name = "Microsoft.AspNetCore.Mvc.Cors"
or
name = "Microsoft.AspNetCore.Mvc.DataAnnotations"
or
name = "Microsoft.AspNetCore.Mvc.Formatters.Json"
or
name = "Microsoft.AspNetCore.Mvc.Formatters.Xml"
or
name = "Microsoft.AspNetCore.Mvc.Localization"
or
name = "Microsoft.AspNetCore.Mvc.Razor.Host"
or
name = "Microsoft.AspNetCore.Mvc.Razor"
or
name = "Microsoft.AspNetCore.Mvc.TagHelpers"
or
name = "Microsoft.AspNetCore.Mvc.ViewFeatures"
or
name = "Microsoft.AspNetCore.Mvc.WebApiCompatShim"
) and
(
affected = "1.0.0" and fixed = "1.0.4"
or
affected = "1.1.0" and fixed = "1.1.3"
)
}
}
class CVE_2017_8700 extends Vulnerability {
CVE_2017_8700() { this = "CVE-2017-8700" }
override string getUrl() { result = "https://github.com/aspnet/Announcements/issues/279" }
override predicate matchesRange(string name, Version affected, Version fixed) {
(
name = "Microsoft.AspNetCore.Mvc.Core"
or
name = "Microsoft.AspNetCore.Mvc.Cors"
) and
(
affected = "1.0.0" and fixed = "1.0.6"
or
affected = "1.1.0" and fixed = "1.1.6"
)
}
}
class CVE_2018_0765 extends Vulnerability {
CVE_2018_0765() { this = "CVE-2018-0765" }
override string getUrl() { result = "https://github.com/dotnet/announcements/issues/67" }
override predicate matchesRange(string name, Version affected, Version fixed) {
name = "System.Security.Cryptography.Xml" and
affected = "0.0.0" and
fixed = "4.4.2"
}
}
class AspNetCore_Mar18 extends Vulnerability {
AspNetCore_Mar18() { this = "ASPNETCore-Mar18" }
override string getUrl() { result = "https://github.com/aspnet/Announcements/issues/300" }
override predicate matchesRange(string name, Version affected, Version fixed) {
(
name = "Microsoft.AspNetCore.Server.Kestrel.Core"
or
name = "Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions"
or
name = "Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv"
) and
affected = "2.0.0" and
fixed = "2.0.3"
or
name = "Microsoft.AspNetCore.All" and
affected = "2.0.0" and
fixed = "2.0.8"
}
}
class CVE_2018_8409 extends Vulnerability {
CVE_2018_8409() { this = "CVE-2018-8409" }
override string getUrl() { result = "https://github.com/aspnet/Announcements/issues/316" }
override predicate matchesRange(string name, Version affected, Version fixed) {
name = "System.IO.Pipelines" and affected = "4.5.0" and fixed = "4.5.1"
or
(name = "Microsoft.AspNetCore.All" or name = "Microsoft.AspNetCore.App") and
affected = "2.1.0" and
fixed = "2.1.4"
}
}
class CVE_2018_8171 extends Vulnerability {
CVE_2018_8171() { this = "CVE-2018-8171" }
override string getUrl() { result = "https://github.com/aspnet/Announcements/issues/310" }
override predicate matchesRange(string name, Version affected, Version fixed) {
name = "Microsoft.AspNetCore.Identity" and
(
affected = "1.0.0" and fixed = "1.0.6"
or
affected = "1.1.0" and fixed = "1.1.6"
or
affected = "2.0.0" and fixed = "2.0.4"
or
affected = "2.1.0" and fixed = "2.1.2"
)
}
}
class CVE_2018_8356 extends Vulnerability {
CVE_2018_8356() { this = "CVE-2018-8356" }
override string getUrl() { result = "https://github.com/dotnet/announcements/issues/73" }
override predicate matchesRange(string name, Version affected, Version fixed) {
(
name = "System.Private.ServiceModel"
or
name = "System.ServiceModel.Http"
or
name = "System.ServiceModel.NetTcp"
) and
(
affected = "4.0.0" and fixed = "4.1.3"
or
affected = "4.3.0" and fixed = "4.3.3"
or
affected = "4.4.0" and fixed = "4.4.4"
or
affected = "4.5.0" and fixed = "4.5.3"
)
or
(
name = "System.ServiceModel.Duplex"
or
name = "System.ServiceModel.Security"
) and
(
affected = "4.0.0" and fixed = "4.0.4"
or
affected = "4.3.0" and fixed = "4.3.3"
or
affected = "4.4.0" and fixed = "4.4.4"
or
affected = "4.5.0" and fixed = "4.5.3"
)
or
name = "System.ServiceModel.NetTcp" and
(
affected = "4.0.0" and fixed = "4.1.3"
or
affected = "4.3.0" and fixed = "4.3.3"
or
affected = "4.4.0" and fixed = "4.4.4"
or
affected = "4.5.0" and fixed = "4.5.1"
)
}
}
class ASPNETCore_Jul18 extends Vulnerability {
ASPNETCore_Jul18() { this = "ASPNETCore-July18" }
override string getUrl() { result = "https://github.com/aspnet/Announcements/issues/311" }
override predicate matchesRange(string name, Version affected, Version fixed) {
name = "Microsoft.AspNetCore.Server.Kestrel.Core" and
(
affected = "2.0.0" and fixed = "2.0.4"
or
affected = "2.1.0" and fixed = "2.1.2"
)
or
name = "Microsoft.AspNetCore.All" and
(
affected = "2.0.0" and fixed = "2.0.9"
or
affected = "2.1.0" and fixed = "2.1.2"
)
or
name = "Microsoft.AspNetCore.App" and
affected = "2.1.0" and
fixed = "2.1.2"
}
}
class CVE_2018_8292 extends Vulnerability {
CVE_2018_8292() { this = "CVE-2018-8292" }
override string getUrl() { result = "https://github.com/dotnet/announcements/issues/88" }
override predicate matchesVersion(string name, Version affected, Version fixed) {
name = "System.Net.Http" and
(
affected = "2.0" or
affected = "4.0.0" or
affected = "4.1.0" or
affected = "1.1.1" or
affected = "4.1.2" or
affected = "4.3.0" or
affected = "4.3.1" or
affected = "4.3.2" or
affected = "4.3.3"
) and
fixed = "4.3.4"
}
}
class CVE_2018_0786 extends Vulnerability {
CVE_2018_0786() { this = "CVE-2018-0786" }
override string getUrl() { result = "https://github.com/dotnet/announcements/issues/51" }
override predicate matchesRange(string name, Version affected, Version fixed) {
(
name = "System.ServiceModel.Primitives"
or
name = "System.ServiceModel.Http"
or
name = "System.ServiceModel.NetTcp"
or
name = "System.ServiceModel.Duplex"
or
name = "System.ServiceModel.Security"
or
name = "System.Private.ServiceModel"
) and
(
affected = "4.4.0" and fixed = "4.4.1"
or
affected = "4.3.0" and fixed = "4.3.1"
)
or
(
name = "System.ServiceModel.Primitives"
or
name = "System.ServiceModel.Http"
or
name = "System.ServiceModel.NetTcp"
or
name = "System.Private.ServiceModel"
) and
affected = "4.1.0" and
fixed = "4.1.1"
or
(
name = "System.ServiceModel.Duplex"
or
name = "System.ServiceModel.Security"
) and
affected = "4.0.1" and
fixed = "4.0.2"
}
}
class CVE_2019_0657 extends Vulnerability {
CVE_2019_0657() { this = "CVE-2019-0657" }
override predicate matchesRange(string name, Version affected, Version fixed) {
name = "Microsoft.NETCore.App" and
(
affected = "2.1.0" and fixed = "2.1.8"
or
affected = "2.2.0" and fixed = "2.2.2"
)
}
override predicate matchesVersion(string name, Version affected, Version fixed) {
name = "System.Private.Uri" and
affected = "4.3.0" and
fixed = "4.3.1"
}
override string getUrl() { result = "https://github.com/dotnet/announcements/issues/97" }
}

View File

@@ -1,93 +0,0 @@
import csharp
/**
* A package reference in an XML file, for example in a
* `.csproj` file, a `.props` file, or a `packages.config` file.
*/
class Package extends XMLElement {
string name;
Version version;
Package() {
(this.getName() = "PackageManagement" or this.getName() = "PackageReference") and
name = this.getAttributeValue("Include") and
version = this.getAttributeValue("Version")
or
this.getName() = "package" and
name = this.getAttributeValue("id") and
version = this.getAttributeValue("version")
}
/** Gets the name of the package, for example `System.IO.Pipelines`. */
string getPackageName() { result = name }
/** Gets the version of the package, for example `4.5.1`. */
Version getVersion() { result = version }
override string toString() { result = name + " " + version }
}
/**
* A vulnerability, where the name of the vulnerability is this string.
* One of `matchesRange` or `matchesVersion` must be overridden in order to
* specify which packages are vulnerable.
*/
abstract class Vulnerability extends string {
bindingset[this]
Vulnerability() { any() }
/**
* Holds if a package with name `name` is vulnerable from version `affected`
* until version `fixed`.
*/
predicate matchesRange(string name, Version affected, Version fixed) { none() }
/**
* Holds if a package with name `name` is vulnerable in version `affected`, and
* is fixed by version `fixed`.
*/
predicate matchesVersion(string name, Version affected, Version fixed) { none() }
/** Gets the URL describing the vulnerability. */
abstract string getUrl();
/**
* Holds if a package with name `name` and version `version`
* has this vulnerability. The fixed version is given by `fixed`.
*/
bindingset[name, version]
predicate isVulnerable(string name, Version version, Version fixed) {
exists(Version affected, string n | name.toLowerCase() = n.toLowerCase() |
matchesRange(n, affected, fixed) and
version.compareTo(fixed) < 0 and
version.compareTo(affected) >= 0
or
matchesVersion(n, affected, fixed) and
version.compareTo(affected) = 0
)
}
}
bindingset[name, version]
private Version getUltimateFix(string name, Version version) {
result = max(Version fix | any(Vulnerability v).isVulnerable(name, version, fix))
}
/**
* A package with a vulnerability.
*/
class VulnerablePackage extends Package {
Vulnerability vuln;
VulnerablePackage() { vuln.isVulnerable(this.getPackageName(), this.getVersion(), _) }
/** Gets the vulnerability of this package. */
Vulnerability getVulnerability() { result = vuln }
/** Gets the version of this package where the vulnerability is fixed. */
Version getFixedVersion() {
// This is needed because sometimes the "fixed" version of some
// vulnerabilities are themselves vulnerable to other vulnerabilities.
result = getUltimateFix(this.getPackageName(), this.getVersion())
}
}

View File

@@ -1,43 +0,0 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
Using a package with a known vulnerability is a security risk that could leave the
software vulnerable to attack.
</p>
<p>
This query reads the packages imported by the project build files and
<code>.config</code> files, and checks them against a list of packages with known
vulnerabilities.
</p>
</overview>
<recommendation>
<p>
Upgrade the package to the recommended version using, for example, the NuGet package manager,
or by editing the project files directly.
</p>
</recommendation>
<example>
<p>
The following example shows a C# project file referencing package <code>System.Net.Http</code>
version 4.3.1, which is vulnerable to <a href="https://github.com/dotnet/announcements/issues/88">CVE-2018-8292</a>.
</p>
<sample src="VulnerablePackageBAD.csproj" />
<p>
The project file can be fixed by changing the version of the package to 4.3.4.
</p>
<sample src="VulnerablePackageGOOD.csproj" />
</example>
<references>
<li>
OWASP: <a href="https://www.owasp.org/index.php/Top_10-2017_A9-Using_Components_with_Known_Vulnerabilities">A9-Using Components with Known Vulnerabilities</a>.
</li>
</references>
</qhelp>

View File

@@ -1,20 +0,0 @@
/**
* @name Using a package with a known vulnerability
* @description Using a package with a known vulnerability is a security risk.
* Upgrade the package to a version that does not contain the vulnerability.
* @kind problem
* @problem.severity error
* @precision high
* @id cs/use-of-vulnerable-package
* @tags security
* external/cwe/cwe-937
*/
import csharp
import Vulnerabilities
from Vulnerability vuln, VulnerablePackage package
where vuln = package.getVulnerability()
select package,
"Package '" + package + "' has vulnerability $@, and should be upgraded to version " +
package.getFixedVersion() + ".", vuln.getUrl(), vuln.toString()

View File

@@ -1,15 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
<AssemblyName>Semmle.Autobuild</AssemblyName>
<RootNamespace>Semmle.Autobuild</RootNamespace>
<OutputType>Exe</OutputType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Build" Version="15.8.166" />
<PackageReference Include="System.Net.Http" Version="4.3.1" />
</ItemGroup>
</Project>

View File

@@ -1,15 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
<AssemblyName>Semmle.Autobuild</AssemblyName>
<RootNamespace>Semmle.Autobuild</RootNamespace>
<OutputType>Exe</OutputType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Build" Version="15.8.166" />
<PackageReference Include="System.Net.Http" Version="4.3.4" />
</ItemGroup>
</Project>

View File

@@ -1,305 +0,0 @@
import csharp
private string relativePath(File file) { result = file.getRelativePath().replaceAll("\\", "/") }
/**
* Holds if the `index`-th token of block `copy` is in file `file`, spanning
* column `sc` of line `sl` to column `ec` of line `el`.
*
* For more information, see [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
*/
pragma[nomagic]
predicate tokenLocation(File file, int sl, int sc, int ec, int el, Copy copy, int index) {
file = copy.sourceFile() and
tokens(copy, index, sl, sc, ec, el)
}
class Copy extends @duplication_or_similarity {
private int lastToken() { result = max(int i | tokens(this, i, _, _, _, _) | i) }
int tokenStartingAt(Location loc) {
tokenLocation(loc.getFile(), loc.getStartLine(), loc.getStartColumn(), _, _, this, result)
}
int tokenEndingAt(Location loc) {
tokenLocation(loc.getFile(), _, _, loc.getEndLine(), loc.getEndColumn(), this, result)
}
int sourceStartLine() { tokens(this, 0, result, _, _, _) }
int sourceStartColumn() { tokens(this, 0, _, result, _, _) }
int sourceEndLine() { tokens(this, lastToken(), _, _, result, _) }
int sourceEndColumn() { tokens(this, lastToken(), _, _, _, result) }
int sourceLines() { result = this.sourceEndLine() + 1 - this.sourceStartLine() }
int getEquivalenceClass() { duplicateCode(this, _, result) or similarCode(this, _, result) }
File sourceFile() {
exists(string name | duplicateCode(this, name, _) or similarCode(this, name, _) |
name.replaceAll("\\", "/") = relativePath(result)
)
}
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
sourceFile().getAbsolutePath() = filepath and
startline = sourceStartLine() and
startcolumn = sourceStartColumn() and
endline = sourceEndLine() and
endcolumn = sourceEndColumn()
}
string toString() { none() }
}
class DuplicateBlock extends Copy, @duplication {
override string toString() { result = "Duplicate code: " + sourceLines() + " duplicated lines." }
}
class SimilarBlock extends Copy, @similarity {
override string toString() {
result = "Similar code: " + sourceLines() + " almost duplicated lines."
}
}
private Method sourceMethod() { method_location(result, _) and numlines(result, _, _, _) }
private int numberOfSourceMethods(Class c) {
result = count(Method m | m = sourceMethod() and m.getDeclaringType() = c)
}
private predicate blockCoversStatement(int equivClass, int first, int last, Stmt stmt) {
exists(DuplicateBlock b, Location loc |
stmt.getLocation() = loc and
first = b.tokenStartingAt(loc) and
last = b.tokenEndingAt(loc) and
b.getEquivalenceClass() = equivClass
)
}
private Stmt statementInMethod(Method m) {
result.getEnclosingCallable() = m and
not result instanceof BlockStmt
}
private predicate duplicateStatement(Method m1, Method m2, Stmt s1, Stmt s2) {
exists(int equivClass, int first, int last |
s1 = statementInMethod(m1) and
s2 = statementInMethod(m2) and
blockCoversStatement(equivClass, first, last, s1) and
blockCoversStatement(equivClass, first, last, s2) and
s1 != s2 and
m1 != m2
)
}
/** Holds if `duplicate` number of statements are duplicated in the methods. */
predicate duplicateStatements(Method m1, Method m2, int duplicate, int total) {
duplicate = strictcount(Stmt s | duplicateStatement(m1, m2, s, _)) and
total = strictcount(statementInMethod(m1))
}
/**
* Find pairs of methods are identical
*/
predicate duplicateMethod(Method m, Method other) {
exists(int total | duplicateStatements(m, other, total, total))
}
private predicate similarLines(File f, int line) {
exists(SimilarBlock b | b.sourceFile() = f and line in [b.sourceStartLine() .. b.sourceEndLine()])
}
private predicate similarLinesPerEquivalenceClass(int equivClass, int lines, File f) {
lines =
strictsum(SimilarBlock b, int toSum |
(b.sourceFile() = f and b.getEquivalenceClass() = equivClass) and
toSum = b.sourceLines()
|
toSum
)
}
pragma[noopt]
private predicate similarLinesCovered(File f, int coveredLines, File otherFile) {
exists(int numLines | numLines = f.getNumberOfLines() |
exists(int coveredApprox |
coveredApprox =
strictsum(int num |
exists(int equivClass |
similarLinesPerEquivalenceClass(equivClass, num, f) and
similarLinesPerEquivalenceClass(equivClass, num, otherFile) and
f != otherFile
)
) and
exists(int n, int product | product = coveredApprox * 100 and n = product / numLines | n > 75)
) and
exists(int notCovered |
notCovered =
count(int j |
j in [1 .. numLines] and
not similarLines(f, j)
) and
coveredLines = numLines - notCovered
)
)
}
private predicate duplicateLines(File f, int line) {
exists(DuplicateBlock b |
b.sourceFile() = f and line in [b.sourceStartLine() .. b.sourceEndLine()]
)
}
private predicate duplicateLinesPerEquivalenceClass(int equivClass, int lines, File f) {
lines =
strictsum(DuplicateBlock b, int toSum |
(b.sourceFile() = f and b.getEquivalenceClass() = equivClass) and
toSum = b.sourceLines()
|
toSum
)
}
pragma[noopt]
private predicate duplicateLinesCovered(File f, int coveredLines, File otherFile) {
exists(int numLines | numLines = f.getNumberOfLines() |
exists(int coveredApprox |
coveredApprox =
strictsum(int num |
exists(int equivClass |
duplicateLinesPerEquivalenceClass(equivClass, num, f) and
duplicateLinesPerEquivalenceClass(equivClass, num, otherFile) and
f != otherFile
)
) and
exists(int n, int product | product = coveredApprox * 100 and n = product / numLines | n > 75)
) and
exists(int notCovered |
notCovered =
count(int j |
j in [1 .. numLines] and
not duplicateLines(f, j)
) and
coveredLines = numLines - notCovered
)
)
}
/** Holds if the two files are not duplicated but have more than 80% similar lines. */
predicate similarFiles(File f, File other, int percent) {
exists(int covered, int total |
similarLinesCovered(f, covered, other) and
total = f.getNumberOfLines() and
covered * 100 / total = percent and
percent > 80
) and
not duplicateFiles(f, other, _)
}
/** Holds if the two files have more than 70% duplicated lines. */
predicate duplicateFiles(File f, File other, int percent) {
exists(int covered, int total |
duplicateLinesCovered(f, covered, other) and
total = f.getNumberOfLines() and
covered * 100 / total = percent and
percent > 70
)
}
pragma[noopt]
private predicate duplicateAnonymousClass(AnonymousClass c, AnonymousClass other) {
exists(int numDup |
numDup =
strictcount(Method m1 |
exists(Method m2 |
duplicateMethod(m1, m2) and
m1 = sourceMethod() and
m1.getDeclaringType() = c and
c instanceof AnonymousClass and
m2.getDeclaringType() = other and
other instanceof AnonymousClass and
c != other
)
) and
numDup = numberOfSourceMethods(c) and
numDup = numberOfSourceMethods(other) and
forall(Type t | c.getABaseType() = t | t = other.getABaseType())
)
}
pragma[noopt]
private predicate mostlyDuplicateClassBase(Class c, Class other, int numDup, int total) {
numDup =
strictcount(Method m1 |
exists(Method m2 |
duplicateMethod(m1, m2) and
m1 = sourceMethod() and
m1.getDeclaringType() = c and
m2.getDeclaringType() = other and
other instanceof Class and
c != other
)
) and
total = numberOfSourceMethods(c) and
exists(int n, int product | product = 100 * numDup and n = product / total | n > 80) and
not c instanceof AnonymousClass and
not other instanceof AnonymousClass
}
/** Holds if the methods in the two classes are more than 80% duplicated. */
predicate mostlyDuplicateClass(Class c, Class other, string message) {
exists(int numDup, int total |
mostlyDuplicateClassBase(c, other, numDup, total) and
(
total != numDup and
exists(string s1, string s2, string s3, string name |
s1 = " out of " and
s2 = " methods in " and
s3 = " are duplicated in $@." and
name = c.getName()
|
message = numDup + s1 + total + s2 + name + s3
)
or
total = numDup and
exists(string s1, string s2, string name |
s1 = "All methods in " and s2 = " are identical in $@." and name = c.getName()
|
message = s1 + name + s2
)
)
)
}
/** Holds if the two files are similar or duplicated. */
predicate fileLevelDuplication(File f, File other) {
similarFiles(f, other, _) or duplicateFiles(f, other, _)
}
/**
* Holds if the two classes are duplicated anonymous classes or more than 80% of
* their methods are duplicated.
*/
predicate classLevelDuplication(Class c, Class other) {
duplicateAnonymousClass(c, other) or mostlyDuplicateClass(c, other, _)
}
private Element whitelistedDuplicateElement() {
result instanceof UsingNamespaceDirective or
result instanceof UsingStaticDirective
}
/**
* Holds if the `line` in the `file` contains an element, such as a `using`
* directive, that is not considered for code duplication.
*/
predicate whitelistedLineForDuplication(File file, int line) {
exists(Location loc | loc = whitelistedDuplicateElement().getLocation() |
line = loc.getStartLine() and file = loc.getFile()
)
}

View File

@@ -1,34 +0,0 @@
import csharp
external predicate defectResults(
int id, string queryPath, string file, int startline, int startcol, int endline, int endcol,
string message
);
class DefectResult extends int {
DefectResult() { defectResults(this, _, _, _, _, _, _, _) }
string getQueryPath() { defectResults(this, result, _, _, _, _, _, _) }
File getFile() {
exists(string path |
defectResults(this, _, path, _, _, _, _, _) and result.getAbsolutePath() = path
)
}
int getStartLine() { defectResults(this, _, _, result, _, _, _, _) }
int getStartColumn() { defectResults(this, _, _, _, result, _, _, _) }
int getEndLine() { defectResults(this, _, _, _, _, result, _, _) }
int getEndColumn() { defectResults(this, _, _, _, _, _, result, _) }
string getMessage() { defectResults(this, _, _, _, _, _, _, result) }
string getURL() {
result =
"file://" + getFile().getAbsolutePath() + ":" + getStartLine() + ":" + getStartColumn() + ":" +
getEndLine() + ":" + getEndColumn()
}
}

View File

@@ -1,22 +0,0 @@
class Toolbox
{
private int x;
private int y;
public void move(int x, int y)
{
this.x = x;
this.y = y;
}
// ...
}
class Window
{
private int x;
private int y;
public void move(int x, int y)
{
this.x = x;
this.y = y;
}
// ...
}

View File

@@ -1,35 +0,0 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>Methods should not be duplicated at more than one place in the program. Duplicating code makes it harder to update
should a change need to be made. It also makes the code harder to read.</p>
</overview>
<recommendation>
<p>Determining how to address this issue requires some consideration. If the duplicate methods are in the same class
then it is normally possible to just remove one and replace all references to that method by references to the other
method. If the methods are in different classes then there might be a need to create a superclass that
contains the method, which both classes inherit. If it is not logical to create a superclass the method
could be moved into a separate utility class.</p>
</recommendation>
<example>
<p>In this example the Toolbox and the Window class both have the same move method. In this case it would be logical to
put this method as well as the x and y properties into a new superclass that Toolbox and Window extend.</p>
<sample src="DuplicateMethod.cs" />
</example>
<section title="Fixing Using a Superclass">
<p>The example could be easily fixed by moving the x and y properties as well as the move method to a parent class. Note
that the x and y properties have to be changed to protected if they are accessed from the Toolbox and Window classes.</p>
<sample src="DuplicateMethodFix.cs" />
</section>
<references>
<li>Elmar Juergens, Florian Deissenboeck, Benjamin Hummel and Stefan Wagner. <em>Do Code Clones Matter?</em>. 2009.</li>
</references>
</qhelp>

View File

@@ -1,41 +0,0 @@
/**
* @deprecated
* @name Duplicate method
* @description There is another identical implementation of this method. Extract the code to a common superclass or delegate to improve sharing.
* @kind problem
* @problem.severity recommendation
* @precision high
* @id cs/duplicate-method
* @tags testability
* maintainability
* useless-code
* duplicate-code
* statistical
* non-attributable
*/
import csharp
import CodeDuplication
predicate relevant(Method m) {
m.getNumberOfLinesOfCode() > 5 and not m.getName().matches("get%")
or
m.getNumberOfLinesOfCode() > 10
}
pragma[noopt]
predicate query(Method m, Method other) {
duplicateMethod(m, other) and
relevant(m) and
not exists(File f1, File f2 |
m.getFile() = f1 and fileLevelDuplication(f1, f2) and other.getFile() = f2
) and
not exists(Type t1, Type t2 |
m.getDeclaringType() = t1 and classLevelDuplication(t1, t2) and other.getDeclaringType() = t2
)
}
from Method m, Method other
where query(m, other)
select m, "Method " + m.getName() + " is duplicated in $@.", other,
other.getDeclaringType().getName() + "." + other.getName()

View File

@@ -1,18 +0,0 @@
class Container
{
protected int x;
protected int y;
public void move(int x, int y)
{
this.x = x;
this.y = y;
}
}
class Toolbox : Container
{
// ...
}
class Window : Container
{
// ...
}

View File

@@ -1,79 +0,0 @@
import csharp
class ExternalElement extends @external_element {
/** Gets a textual representation of this element. */
string toString() { none() }
/** Gets the location of this element. */
Location getLocation() { none() }
/** Gets the file containing this element. */
File getFile() { result = getLocation().getFile() }
}
class ExternalDefect extends ExternalElement, @externalDefect {
string getQueryPath() {
exists(string path |
externalDefects(this, path, _, _, _) and
result = path.replaceAll("\\", "/")
)
}
string getMessage() { externalDefects(this, _, _, result, _) }
float getSeverity() { externalDefects(this, _, _, _, result) }
override Location getLocation() { externalDefects(this, _, result, _, _) }
override string toString() {
result = getQueryPath() + ": " + getLocation() + " - " + getMessage()
}
}
class ExternalMetric extends ExternalElement, @externalMetric {
string getQueryPath() { externalMetrics(this, result, _, _) }
float getValue() { externalMetrics(this, _, _, result) }
override Location getLocation() { externalMetrics(this, _, result, _) }
override string toString() { result = getQueryPath() + ": " + getLocation() + " - " + getValue() }
}
class ExternalData extends ExternalElement, @externalDataElement {
string getDataPath() { externalData(this, result, _, _) }
string getQueryPath() { result = getDataPath().regexpReplaceAll("\\.[^.]*$", ".ql") }
int getNumFields() { result = 1 + max(int i | externalData(this, _, i, _) | i) }
string getField(int index) { externalData(this, _, index, result) }
int getFieldAsInt(int index) { result = getField(index).toInt() }
float getFieldAsFloat(int index) { result = getField(index).toFloat() }
date getFieldAsDate(int index) { result = getField(index).toDate() }
override string toString() { result = getQueryPath() + ": " + buildTupleString(0) }
private string buildTupleString(int start) {
start = getNumFields() - 1 and result = getField(start)
or
start < getNumFields() - 1 and result = getField(start) + "," + buildTupleString(start + 1)
}
}
/**
* External data with a location, and a message, as produced by tools that used to produce QLDs.
*/
class DefectExternalData extends ExternalData {
DefectExternalData() {
this.getField(0).regexpMatch("\\w+://.*:[0-9]+:[0-9]+:[0-9]+:[0-9]+$") and
this.getNumFields() = 2
}
string getURL() { result = getField(0) }
string getMessage() { result = getField(1) }
}

View File

@@ -1,44 +0,0 @@
import csharp
external predicate metricResults(
int id, string queryPath, string file, int startline, int startcol, int endline, int endcol,
float value
);
class MetricResult extends int {
MetricResult() { metricResults(this, _, _, _, _, _, _, _) }
string getQueryPath() { metricResults(this, result, _, _, _, _, _, _) }
File getFile() {
exists(string path |
metricResults(this, _, path, _, _, _, _, _) and result.getAbsolutePath() = path
)
}
int getStartLine() { metricResults(this, _, _, result, _, _, _, _) }
int getStartColumn() { metricResults(this, _, _, _, result, _, _, _) }
int getEndLine() { metricResults(this, _, _, _, _, result, _, _) }
int getEndColumn() { metricResults(this, _, _, _, _, _, result, _) }
predicate hasMatchingLocation() { exists(this.getMatchingLocation()) }
Location getMatchingLocation() {
result.getFile() = this.getFile() and
result.getStartLine() = this.getStartLine() and
result.getEndLine() = this.getEndLine() and
result.getStartColumn() = this.getStartColumn() and
result.getEndColumn() = this.getEndColumn()
}
float getValue() { metricResults(this, _, _, _, _, _, _, result) }
string getURL() {
result =
"file://" + getFile().getAbsolutePath() + ":" + getStartLine() + ":" + getStartColumn() + ":" +
getEndLine() + ":" + getEndColumn()
}
}

View File

@@ -1,20 +0,0 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>If two classes share a lot of each other's methods then there is a lot of unnecessary code duplication.
This makes it difficult to make changes in future and makes the code harder to read.</p>
</overview>
<recommendation>
<p>If a duplicate class has been included by mistake then remove it. Otherwise consider making a common
superclass for both classes or even making one of the classes a superclass of the other.</p>
</recommendation>
<references>
<li>Elmar Juergens, Florian Deissenboeck, Benjamin Hummel and Stefan Wagner. <em>Do Code Clones Matter?</em>. 2009.</li>
</references>
</qhelp>

View File

@@ -1,24 +0,0 @@
/**
* @deprecated
* @name Duplicate class
* @description More than 80% of the methods in this class are duplicated in another class. Create a common supertype to improve code sharing.
* @kind problem
* @problem.severity recommendation
* @precision high
* @id cs/duplicate-class
* @tags testability
* maintainability
* useless-code
* duplicate-code
* statistical
* non-attributable
*/
import csharp
import CodeDuplication
from Class c, string message, Class link
where
mostlyDuplicateClass(c, link, message) and
not fileLevelDuplication(c.getFile(), _)
select c, message, link, link.getName()

View File

@@ -1,31 +0,0 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>If two files share a lot of each other's code then there is a lot of unnecessary code duplication.
This makes it difficult to make changes in future and makes the code harder to read.</p>
</overview>
<recommendation>
<p>While completely duplicated files are rare, they are usually a sign of a simple oversight.
Usually the required action is to remove all but one of them. A common exception to this rule may arise
from generated code that simply occurs in several places in the source tree; the check can be
adapted to exclude such results.</p>
<p>It is far more common to see duplication of many lines between two files, leaving just a few that
are actually different. Consider such situations carefully. Are the differences deliberate or
a result of an inconsistent update to one of the clones? If the latter, then treating the files as
completely duplicate and eliminating one (while preserving any corrections or new features that
may have been introduced) is the best course. If two files serve genuinely different purposes but almost
all of their lines are the same, that can be a sign that there is a missing level of abstraction. Look
for ways to share the functionality, either by creating a utility class for the common parts or by
encapsulating the common parts into a new super class of any classes involved.</p>
</recommendation>
<references>
<li>Elmar Juergens, Florian Deissenboeck, Benjamin Hummel and Stefan Wagner. <em>Do Code Clones Matter?</em>. 2009.</li>
</references>
</qhelp>

View File

@@ -1,23 +0,0 @@
/**
* @deprecated
* @name Mostly duplicate file
* @description There is another file that shares a lot of the code with this file. Merge the two files to improve maintainability.
* @kind problem
* @problem.severity recommendation
* @precision high
* @id cs/duplicate-file
* @tags testability
* maintainability
* useless-code
* duplicate-code
* statistical
* non-attributable
*/
import csharp
import CodeDuplication
from File f, File other, int percent
where duplicateFiles(f, other, percent)
select f, percent + "% of the lines in " + f.getBaseName() + " are copies of lines in $@.", other,
other.getBaseName()

View File

@@ -1,48 +0,0 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>When most of the lines in one method are duplicated in one or more other
methods, the methods themselves are regarded as <em>mostly duplicate</em> or <em>similar</em>.</p>
<p>Code duplication in general is highly undesirable for a range of reasons. The artificially
inflated amount of code is more difficult to understand, and sequences of similar but subtly different lines
can mask the real purpose or intention behind them. Also, there is always a risk that only one
of several copies of the code is updated to address a defect or add a feature.</p>
</overview>
<recommendation>
<p>Although completely duplicated methods are rare, they are usually a sign of a simple
oversight (or deliberate copy/paste) by a developer. Usually the required solution
is to remove all but one of them.</p>
<p>It is more common to see duplication of many lines between two methods, leaving just
a few that are actually different. Decide whether the differences are
intended or the result of an inconsistent update to one of the copies.</p>
<ul>
<li>If the two methods serve different purposes but many of their lines are duplicated, this indicates
that there is a missing level of abstraction. Look for ways of encapsulating the commonality and sharing it while
retaining the differences in functionality. Perhaps the method can be moved to a single place
and given an additional parameter, allowing it to cover all use cases. Alternatively, there
may be a common pre-processing or post-processing step that can be extracted to its own (shared)
method, leaving only the specific parts in the existing methods. Modern IDEs may provide
refactoring support for this sort of issue, usually with the names "Extract method", "Change method signature",
"Pull up" or "Extract supertype".</li>
<li>If the two methods serve the same purpose and are different only as a result of inconsistent updates
then treat the methods as completely duplicate. Determine
the most up-to-date and correct version of the code and eliminate all near duplicates. Callers of the
removed methods should be updated to call the remaining method instead. </li></ul>
</recommendation>
<references>
<li>E. Juergens, F. Deissenboeck, B. Hummel, S. Wagner.
<em>Do code clones matter?</em> Proceedings of the 31st International Conference on
Software Engineering,
485-495, 2009.</li>
</references>
</qhelp>

View File

@@ -1,30 +0,0 @@
/**
* @deprecated
* @name Mostly duplicate method
* @description There is another method that shares a lot of the code with this method. Extract the code to a common superclass or delegate to improve sharing.
* @kind problem
* @problem.severity recommendation
* @precision high
* @id cs/similar-method
* @tags testability
* maintainability
* useless-code
* statistical
* non-attributable
*/
import csharp
import CodeDuplication
from Method m, int covered, int total, Method other, int percent
where
duplicateStatements(m, other, covered, total) and
covered != total and
m.getNumberOfLinesOfCode() > 5 and
covered * 100 / total = percent and
percent > 80 and
not duplicateMethod(m, other) and
not classLevelDuplication(m.getDeclaringType(), other.getDeclaringType()) and
not fileLevelDuplication(m.getFile(), other.getFile())
select m, percent + "% of the statements in " + m.getName() + " are duplicated in $@.", other,
other.getDeclaringType().getName() + "." + other.getName()

View File

@@ -1,24 +0,0 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>This rule identifies two files that have a lot of the same lines but with different variable and method
names. This makes it difficult to make changes in future and makes the code harder to read.</p>
</overview>
<recommendation>
<p>It is important to determine why there are small differences in the files. Sometimes the files might have
been duplicates but an update was only applied to one copy. If this is the case it should be simple to merge
the files, preserving any changes.</p>
<p>If the files are intentionally different then it could be a good idea to consider extracting some of the
shared code into a superclass or a separate utility class.</p>
</recommendation>
<references>
<li>Elmar Juergens, Florian Deissenboeck, Benjamin Hummel and Stefan Wagner. <em>Do Code Clones Matter?</em>. 2009.</li>
</references>
</qhelp>

View File

@@ -1,31 +0,0 @@
/**
* @deprecated
* @name Mostly similar file
* @description There is another file that shares a lot of the code with this file. Notice that names of variables and types may have been changed. Merge the two files to improve maintainability.
* @kind problem
* @problem.severity recommendation
* @precision high
* @id cs/similar-file
* @tags testability
* maintainability
* useless-code
* duplicate-code
* statistical
* non-attributable
*/
import csharp
import CodeDuplication
predicate irrelevant(File f) {
f.getStem() = "AssemblyInfo" or
f.getStem().matches("%.Designer")
}
from File f, File other, int percent
where
similarFiles(f, other, percent) and
not irrelevant(f) and
not irrelevant(other)
select f, percent + "% of the lines in " + f.getBaseName() + " are similar to lines in $@.", other,
other.getBaseName()

View File

@@ -1,20 +0,0 @@
/**
* @name Filter: only keep results from source that have been changed since the base line
* @description Exclude results that have not changed since the base line.
* @id cs/changed-lines-filter
* @kind problem
*/
import csharp
import external.ExternalArtifact
import external.DefectFilter
import ChangedLines
from DefectResult res
where
changedLine(res.getFile(), res.getStartLine())
or
changedLine(res.getFile(), res.getEndLine())
or
res.getStartLine() = 0 and changedLine(res.getFile(), _)
select res, res.getMessage()

View File

@@ -1,12 +0,0 @@
import csharp
import external.ExternalArtifact
pragma[noopt]
predicate changedLine(File f, int line) {
exists(ExternalMetric metric, Location l |
exists(string s | s = "changedLines.ql" and metric.getQueryPath() = s) and
l = metric.getLocation() and
f = l.getFile() and
line = l.getStartLine()
)
}

View File

@@ -1,15 +0,0 @@
/**
* @name Filter: only keep results from source that have been changed since the base line
* @description Exclude results that have not changed since the base line.
* @id cs/changed-lines-metric-filter
* @kind treemap
*/
import csharp
import external.ExternalArtifact
import external.MetricFilter
import ChangedLines
from MetricResult res
where changedLine(res.getFile(), _)
select res, res.getValue()

View File

@@ -2,6 +2,8 @@
* @name Classify files
* @description This query produces a list of all files in a snapshot
* that are classified as generated code or test code.
*
* Used by LGTM.
* @kind file-classifier
* @id cs/file-classifier
*/

View File

@@ -1,13 +0,0 @@
/**
* @name Filter: only keep results from source
* @description Exclude results that do not come from source code files.
* @kind problem
* @id cs/source-filter
*/
import csharp
import external.DefectFilter
from DefectResult res
where res.getFile().fromSource()
select res, res.getMessage()

View File

@@ -1,13 +0,0 @@
/**
* @name Filter: only keep metric results from source
* @description Exclude results that do not come from source code files.
* @kind treemap
* @id cs/source-metric-filter
*/
import csharp
import external.MetricFilter
from MetricResult res
where res.getFile().fromSource()
select res, res.getValue()

View File

@@ -1,13 +0,0 @@
/**
* @name Filter: only keep results in non-generated files
* @description Exclude results that come from generated code.
* @kind problem
* @id cs/not-generated-file-filter
*/
import semmle.code.csharp.commons.GeneratedCode
import external.DefectFilter
from DefectResult res
where not isGeneratedCode(res.getFile())
select res, res.getMessage()

View File

@@ -1,13 +0,0 @@
/**
* @name Filter: only keep metric results in non-generated files
* @description Exclude results that come from generated code.
* @kind treemap
* @id cs/not-generated-file-metric-filter
*/
import semmle.code.csharp.commons.GeneratedCode
import external.MetricFilter
from MetricResult res
where not isGeneratedCode(res.getFile())
select res, res.getValue()

View File

@@ -1,14 +0,0 @@
/**
* @name Filter: only keep results that are outside of test files
* @description Exclude results in test files.
* @kind problem
* @id cs/test-file-filter
*/
import csharp
import semmle.code.csharp.frameworks.Test
import external.DefectFilter
from DefectResult res
where not res.getFile() instanceof TestFile
select res, res.getMessage()

View File

@@ -1,14 +0,0 @@
/**
* @name Filter: only keep results that are outside of test files
* @description Exclude results in test files.
* @kind treemap
* @id cs/test-file-metric-filter
*/
import csharp
import semmle.code.csharp.frameworks.Test
import external.MetricFilter
from MetricResult res
where not res.getFile() instanceof TestFile
select res, res.getValue()

View File

@@ -1,17 +0,0 @@
/**
* @name Filter: only keep results that are outside of test methods
* @description Exclude results in test methods.
* @kind problem
* @id cs/test-method-filter
*/
import csharp
import semmle.code.csharp.frameworks.Test
import external.DefectFilter
from DefectResult res
where
not res.getFile() instanceof TestFile
or
not res.getStartLine() = res.getFile().(TestFile).lineInTestMethod()
select res, res.getMessage()

View File

@@ -1,24 +0,0 @@
/**
* @name Filter: only keep results that are outside of a test method expecting an exception
* @description Exclude results in test methods expecting exceptions.
* @kind problem
* @id cs/test-method-exception-filter
*/
import csharp
import semmle.code.csharp.frameworks.Test
import external.DefectFilter
predicate ignoredLine(File f, int line) {
exists(TestMethod m | m.expectsException() |
f = m.getFile() and
line in [m.getLocation().getStartLine() .. m.getBody().getLocation().getEndLine()]
)
}
from DefectResult res
where
not res.getFile() instanceof TestFile
or
not ignoredLine(res.getFile(), res.getStartLine())
select res, res.getMessage()

View File

@@ -1,22 +0,0 @@
/**
* @name Filter: only keep results from source that have not changed since the base line
* @description Complement of ChangedLines.ql.
* @kind problem
* @id cs/unchanged-lines-filter
*/
import csharp
import external.ExternalArtifact
import external.DefectFilter
import ChangedLines
from DefectResult res
where
not (
changedLine(res.getFile(), res.getStartLine())
or
changedLine(res.getFile(), res.getEndLine())
or
res.getStartLine() = 0 and changedLine(res.getFile(), _)
)
select res, res.getMessage()

View File

@@ -1,15 +0,0 @@
/**
* @name Filter: only keep results from source that have not changed since the base line
* @description Complement of ChangedLinesForMetric.ql.
* @kind treemap
* @id cs/unchanged-lines-metric-filter
*/
import csharp
import external.ExternalArtifact
import external.MetricFilter
import ChangedLines
from MetricResult res
where not changedLine(res.getFile(), _)
select res, res.getValue()

View File

@@ -240,6 +240,9 @@ class BasicBlock extends Cached::TBasicBlockStart {
/** Gets a textual representation of this basic block. */
string toString() { result = getFirstNode().toString() }
/** Gets the location of this basic block. */
Location getLocation() { result = this.getFirstNode().getLocation() }
}
/**
@@ -305,7 +308,7 @@ class EntryBasicBlock extends BasicBlock {
}
/** Holds if `bb` is an entry basic block. */
private predicate entryBB(BasicBlock bb) { bb.getFirstNode() instanceof EntryPoint }
private predicate entryBB(BasicBlock bb) { bb.getFirstNode() instanceof MethodImplementation }
/**
* An exit basic block, that is, a basic block whose last node is

Some files were not shown because too many files have changed in this diff Show More