mirror of
https://github.com/github/codeql.git
synced 2026-05-18 21:27:08 +02:00
Compare commits
1 Commits
aibaars/ru
...
aml-auto-e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3827693a20 |
2
.github/workflows/go-tests.yml
vendored
2
.github/workflows/go-tests.yml
vendored
@@ -43,7 +43,7 @@ jobs:
|
||||
env QHELP_OUT_DIR=qhelp-out make qhelp-to-markdown
|
||||
|
||||
- name: Upload qhelp markdown
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: qhelp-markdown
|
||||
path: go/qhelp-out/**/*.md
|
||||
|
||||
4
.github/workflows/qhelp-pr-preview.yml
vendored
4
.github/workflows/qhelp-pr-preview.yml
vendored
@@ -27,7 +27,7 @@ on:
|
||||
- main
|
||||
- "rc/*"
|
||||
paths:
|
||||
- "**/*.qhelp"
|
||||
- "ruby/**/*.qhelp"
|
||||
|
||||
jobs:
|
||||
qhelp:
|
||||
@@ -52,7 +52,7 @@ jobs:
|
||||
id: changes
|
||||
run: |
|
||||
(git diff -z --name-only --diff-filter=ACMRT HEAD~1 HEAD | grep -z '.qhelp$' | grep -z -v '.inc.qhelp';
|
||||
git diff -z --name-only --diff-filter=ACMRT HEAD~1 HEAD | grep -z '.inc.qhelp$' | xargs --null -rn1 basename -z | xargs --null -rn1 git grep -z -l) |
|
||||
git diff -z --name-only --diff-filter=ACMRT HEAD~1 HEAD | grep -z '.inc.qhelp$' | xargs --null -rn1 basename | xargs --null -rn1 git grep -z -l) |
|
||||
grep -z '.qhelp$' | grep -z -v '^-' | sort -z -u > "${RUNNER_TEMP}/paths.txt"
|
||||
|
||||
- name: QHelp preview
|
||||
|
||||
@@ -4,7 +4,8 @@ This open source repository contains the standard CodeQL libraries and queries t
|
||||
|
||||
## How do I learn CodeQL and run queries?
|
||||
|
||||
There is [extensive documentation](https://codeql.github.com/docs/) on getting started with writing CodeQL using the [CodeQL extension for Visual Studio Code](https://codeql.github.com/docs/codeql-for-visual-studio-code/) and the [CodeQL CLI](https://codeql.github.com/docs/codeql-cli/).
|
||||
There is [extensive documentation](https://codeql.github.com/docs/) on getting started with writing CodeQL.
|
||||
You can use the [CodeQL for Visual Studio Code](https://codeql.github.com/docs/codeql-for-visual-studio-code/) extension or the [interactive query console](https://lgtm.com/help/lgtm/using-query-console) on LGTM.com (Semmle Legacy product) to try out your queries on any open source project that's currently being analyzed.
|
||||
|
||||
## Contributing
|
||||
|
||||
|
||||
@@ -33,9 +33,8 @@
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl4.qll",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.qll",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForRegExp.qll",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForLibraries.qll",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForHttpClientLibraries.qll",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForPathname.qll",
|
||||
"swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl.qll"
|
||||
],
|
||||
"DataFlow Java/C++/C#/Python Common": [
|
||||
@@ -70,6 +69,7 @@
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking3/TaintTrackingImpl.qll",
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking4/TaintTrackingImpl.qll",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/tainttrackingforlibraries/TaintTrackingImpl.qll",
|
||||
"swift/ql/lib/codeql/swift/dataflow/internal/tainttracking1/TaintTrackingImpl.qll"
|
||||
],
|
||||
"DataFlow Java/C++/C#/Python Consistency checks": [
|
||||
|
||||
@@ -1,22 +1,3 @@
|
||||
## 0.4.1
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.4.0
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
* Some classes/modules with upper-case acronyms in their name have been renamed to follow our style-guide.
|
||||
The old name still exists as a deprecated alias.
|
||||
|
||||
### New Features
|
||||
|
||||
* Added subclasses of `BuiltInOperations` for `__is_same`, `__is_function`, `__is_layout_compatible`, `__is_pointer_interconvertible_base_of`, `__is_array`, `__array_rank`, `__array_extent`, `__is_arithmetic`, `__is_complete_type`, `__is_compound`, `__is_const`, `__is_floating_point`, `__is_fundamental`, `__is_integral`, `__is_lvalue_reference`, `__is_member_function_pointer`, `__is_member_object_pointer`, `__is_member_pointer`, `__is_object`, `__is_pointer`, `__is_reference`, `__is_rvalue_reference`, `__is_scalar`, `__is_signed`, `__is_unsigned`, `__is_void`, and `__is_volatile`.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Fixed an issue in the taint tracking analysis where implicit reads were not allowed by default in sinks or additional taint steps that used flow states.
|
||||
|
||||
## 0.3.5
|
||||
|
||||
## 0.3.4
|
||||
|
||||
@@ -1,14 +1,4 @@
|
||||
## 0.4.0
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
* Some classes/modules with upper-case acronyms in their name have been renamed to follow our style-guide.
|
||||
The old name still exists as a deprecated alias.
|
||||
|
||||
### New Features
|
||||
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* Added subclasses of `BuiltInOperations` for `__is_same`, `__is_function`, `__is_layout_compatible`, `__is_pointer_interconvertible_base_of`, `__is_array`, `__array_rank`, `__array_extent`, `__is_arithmetic`, `__is_complete_type`, `__is_compound`, `__is_const`, `__is_floating_point`, `__is_fundamental`, `__is_integral`, `__is_lvalue_reference`, `__is_member_function_pointer`, `__is_member_object_pointer`, `__is_member_pointer`, `__is_object`, `__is_pointer`, `__is_reference`, `__is_rvalue_reference`, `__is_scalar`, `__is_signed`, `__is_unsigned`, `__is_void`, and `__is_volatile`.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Fixed an issue in the taint tracking analysis where implicit reads were not allowed by default in sinks or additional taint steps that used flow states.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: fix
|
||||
---
|
||||
* Fixed an issue in the taint tracking analysis where implicit reads were not allowed by default in sinks or additional taint steps that used flow states.
|
||||
@@ -1,6 +1,5 @@
|
||||
## 0.3.0
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
---
|
||||
category: deprecated
|
||||
---
|
||||
* Some classes/modules with upper-case acronyms in their name have been renamed to follow our style-guide.
|
||||
The old name still exists as a deprecated alias.
|
||||
The old name still exists as a deprecated alias.
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.4.1
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.4.1
|
||||
lastReleaseVersion: 0.3.5
|
||||
|
||||
@@ -20,8 +20,7 @@ module ProductFlow {
|
||||
* `source1` and `source2` must belong to the same callable.
|
||||
*/
|
||||
predicate isSourcePair(
|
||||
DataFlow::Node source1, DataFlow::FlowState state1, DataFlow::Node source2,
|
||||
DataFlow::FlowState state2
|
||||
DataFlow::Node source1, string state1, DataFlow::Node source2, string state2
|
||||
) {
|
||||
state1 = "" and
|
||||
state2 = "" and
|
||||
@@ -50,101 +49,6 @@ module ProductFlow {
|
||||
this.isSinkPair(sink1, sink2)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited through the first projection of the product
|
||||
* dataflow graph when the flow state is `state`.
|
||||
*/
|
||||
predicate isBarrier1(DataFlow::Node node, DataFlow::FlowState state) {
|
||||
this.isBarrier1(node) and state = ""
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited through the second projection of the product
|
||||
* dataflow graph when the flow state is `state`.
|
||||
*/
|
||||
predicate isBarrier2(DataFlow::Node node, DataFlow::FlowState state) {
|
||||
this.isBarrier2(node) and state = ""
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited through the first projection of the product
|
||||
* dataflow graph.
|
||||
*/
|
||||
predicate isBarrier1(DataFlow::Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited through the second projection of the product
|
||||
* dataflow graph.
|
||||
*/
|
||||
predicate isBarrier2(DataFlow::Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow out of `node` is prohibited in the first projection of the product
|
||||
* dataflow graph.
|
||||
*/
|
||||
predicate isBarrierOut1(DataFlow::Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow out of `node` is prohibited in the second projection of the product
|
||||
* dataflow graph.
|
||||
*/
|
||||
predicate isBarrierOut2(DataFlow::Node node) { none() }
|
||||
|
||||
/*
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps in
|
||||
* the first projection of the product dataflow graph.
|
||||
*/
|
||||
|
||||
predicate isAdditionalFlowStep1(DataFlow::Node node1, DataFlow::Node node2) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps in
|
||||
* the first projection of the product dataflow graph.
|
||||
*
|
||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalFlowStep1(
|
||||
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||
DataFlow::FlowState state2
|
||||
) {
|
||||
state1 instanceof DataFlow::FlowStateEmpty and
|
||||
state2 instanceof DataFlow::FlowStateEmpty and
|
||||
this.isAdditionalFlowStep1(node1, node2)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps in
|
||||
* the second projection of the product dataflow graph.
|
||||
*/
|
||||
predicate isAdditionalFlowStep2(DataFlow::Node node1, DataFlow::Node node2) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps in
|
||||
* the second projection of the product dataflow graph.
|
||||
*
|
||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalFlowStep2(
|
||||
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||
DataFlow::FlowState state2
|
||||
) {
|
||||
state1 instanceof DataFlow::FlowStateEmpty and
|
||||
state2 instanceof DataFlow::FlowStateEmpty and
|
||||
this.isAdditionalFlowStep2(node1, node2)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data flow into `node` is prohibited in the first projection of the product
|
||||
* dataflow graph.
|
||||
*/
|
||||
predicate isBarrierIn1(DataFlow::Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow into `node` is prohibited in the second projection of the product
|
||||
* dataflow graph.
|
||||
*/
|
||||
predicate isBarrierIn2(DataFlow::Node node) { none() }
|
||||
|
||||
predicate hasFlowPath(
|
||||
DataFlow::PathNode source1, DataFlow2::PathNode source2, DataFlow::PathNode sink1,
|
||||
DataFlow2::PathNode sink2
|
||||
@@ -159,78 +63,38 @@ module ProductFlow {
|
||||
class Conf1 extends DataFlow::Configuration {
|
||||
Conf1() { this = "Conf1" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) {
|
||||
override predicate isSource(DataFlow::Node source, string state) {
|
||||
exists(Configuration conf | conf.isSourcePair(source, state, _, _))
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) {
|
||||
override predicate isSink(DataFlow::Node sink, string state) {
|
||||
exists(Configuration conf | conf.isSinkPair(sink, state, _, _))
|
||||
}
|
||||
|
||||
override predicate isBarrier(DataFlow::Node node, DataFlow::FlowState state) {
|
||||
exists(Configuration conf | conf.isBarrier1(node, state))
|
||||
}
|
||||
|
||||
override predicate isBarrierOut(DataFlow::Node node) {
|
||||
exists(Configuration conf | conf.isBarrierOut1(node))
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||
DataFlow::FlowState state2
|
||||
) {
|
||||
exists(Configuration conf | conf.isAdditionalFlowStep1(node1, state1, node2, state2))
|
||||
}
|
||||
|
||||
override predicate isBarrierIn(DataFlow::Node node) {
|
||||
exists(Configuration conf | conf.isBarrierIn1(node))
|
||||
}
|
||||
}
|
||||
|
||||
class Conf2 extends DataFlow2::Configuration {
|
||||
Conf2() { this = "Conf2" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) {
|
||||
exists(Configuration conf, DataFlow::PathNode source1 |
|
||||
conf.isSourcePair(source1.getNode(), source1.getState(), source, state) and
|
||||
any(Conf1 c).hasFlowPath(source1, _)
|
||||
override predicate isSource(DataFlow::Node source, string state) {
|
||||
exists(Configuration conf, DataFlow::Node source1 |
|
||||
conf.isSourcePair(source1, _, source, state) and
|
||||
any(Conf1 c).hasFlow(source1, _)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) {
|
||||
exists(Configuration conf, DataFlow::PathNode sink1 |
|
||||
conf.isSinkPair(sink1.getNode(), sink1.getState(), sink, state) and
|
||||
any(Conf1 c).hasFlowPath(_, sink1)
|
||||
override predicate isSink(DataFlow::Node sink, string state) {
|
||||
exists(Configuration conf, DataFlow::Node sink1 |
|
||||
conf.isSinkPair(sink1, _, sink, state) and any(Conf1 c).hasFlow(_, sink1)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isBarrier(DataFlow::Node node, DataFlow::FlowState state) {
|
||||
exists(Configuration conf | conf.isBarrier2(node, state))
|
||||
}
|
||||
|
||||
override predicate isBarrierOut(DataFlow::Node node) {
|
||||
exists(Configuration conf | conf.isBarrierOut2(node))
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||
DataFlow::FlowState state2
|
||||
) {
|
||||
exists(Configuration conf | conf.isAdditionalFlowStep2(node1, state1, node2, state2))
|
||||
}
|
||||
|
||||
override predicate isBarrierIn(DataFlow::Node node) {
|
||||
exists(Configuration conf | conf.isBarrierIn2(node))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate reachableInterprocEntry(
|
||||
Configuration conf, DataFlow::PathNode source1, DataFlow2::PathNode source2,
|
||||
DataFlow::PathNode node1, DataFlow2::PathNode node2
|
||||
) {
|
||||
conf.isSourcePair(node1.getNode(), node1.getState(), node2.getNode(), node2.getState()) and
|
||||
conf.isSourcePair(node1.getNode(), _, node2.getNode(), _) and
|
||||
node1 = source1 and
|
||||
node2 = source2
|
||||
or
|
||||
@@ -293,7 +157,7 @@ module ProductFlow {
|
||||
) {
|
||||
exists(DataFlow::PathNode mid1, DataFlow2::PathNode mid2 |
|
||||
reachableInterprocEntry(conf, source1, source2, mid1, mid2) and
|
||||
conf.isSinkPair(sink1.getNode(), sink1.getState(), sink2.getNode(), sink2.getState()) and
|
||||
conf.isSinkPair(sink1.getNode(), _, sink2.getNode(), _) and
|
||||
localPathStep1*(mid1, sink1) and
|
||||
localPathStep2*(mid2, sink2)
|
||||
)
|
||||
|
||||
@@ -163,9 +163,7 @@ abstract class Configuration extends string {
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink) {
|
||||
sink = any(PathNodeSink n | this = n.getConfiguration()).getNodeEx().asNode()
|
||||
}
|
||||
predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -560,16 +558,13 @@ private predicate expectsContentEx(NodeEx n, Content c) {
|
||||
pragma[nomagic]
|
||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate store(
|
||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||
contentType) and
|
||||
hasReadStep(tc.getContent(), config) and
|
||||
read(_, tc.getContent(), _, config) and
|
||||
stepFilter(node1, node2, config)
|
||||
}
|
||||
|
||||
@@ -603,9 +598,13 @@ private predicate hasSinkCallCtx(Configuration config) {
|
||||
}
|
||||
|
||||
private module Stage1 implements StageSig {
|
||||
class ApApprox = Unit;
|
||||
|
||||
class Ap = Unit;
|
||||
|
||||
private class Cc = boolean;
|
||||
class ApOption = Unit;
|
||||
|
||||
class Cc = boolean;
|
||||
|
||||
/* Begin: Stage 1 logic. */
|
||||
/**
|
||||
@@ -614,7 +613,7 @@ private module Stage1 implements StageSig {
|
||||
* The Boolean `cc` records whether the node is reached through an
|
||||
* argument in a call.
|
||||
*/
|
||||
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
sourceNode(node, _, config) and
|
||||
if hasSourceCallCtx(config) then cc = true else cc = false
|
||||
or
|
||||
@@ -754,7 +753,7 @@ private module Stage1 implements StageSig {
|
||||
* the enclosing callable in order to reach a sink.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
revFlow0(node, toReturn, config) and
|
||||
fwdFlow(node, config)
|
||||
}
|
||||
@@ -838,13 +837,13 @@ private module Stage1 implements StageSig {
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
additional predicate viableReturnPosOutNodeCandFwd1(
|
||||
predicate viableReturnPosOutNodeCandFwd1(
|
||||
DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
|
||||
) {
|
||||
fwdFlowReturnPosition(pos, _, config) and
|
||||
@@ -860,7 +859,7 @@ private module Stage1 implements StageSig {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
viableParamArgEx(call, p, arg) and
|
||||
@@ -907,7 +906,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate revFlowState(FlowState state, Configuration config) {
|
||||
predicate revFlowState(FlowState state, Configuration config) {
|
||||
exists(NodeEx node |
|
||||
sinkNode(node, state, config) and
|
||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||
@@ -999,7 +998,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate stats(
|
||||
predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -1260,7 +1259,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* argument.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate fwdFlow(
|
||||
predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, argAp, ap, config) and
|
||||
@@ -1484,7 +1483,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* the access path of the returned value.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate revFlow(
|
||||
predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow0(node, state, toReturn, returnAp, ap, config) and
|
||||
@@ -1662,7 +1661,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
revFlow(node, state, _, _, _, config)
|
||||
}
|
||||
|
||||
@@ -1675,13 +1674,11 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||
revFlow(node, _, _, _, _, config)
|
||||
}
|
||||
predicate revFlowAlias(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
additional predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
revFlow(node, state, ap, config)
|
||||
}
|
||||
|
||||
@@ -1702,7 +1699,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
}
|
||||
@@ -1744,7 +1741,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate stats(
|
||||
predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -2929,15 +2926,10 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
result = this.getASuccessorImpl()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private PathNodeImpl getANonHiddenSuccessor0() {
|
||||
result = this.getASuccessorIfHidden*() and
|
||||
not result.isHidden()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getANonHiddenSuccessor0() and
|
||||
not this.isHidden()
|
||||
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
not result.isHidden()
|
||||
}
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
@@ -163,9 +163,7 @@ abstract class Configuration extends string {
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink) {
|
||||
sink = any(PathNodeSink n | this = n.getConfiguration()).getNodeEx().asNode()
|
||||
}
|
||||
predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -560,16 +558,13 @@ private predicate expectsContentEx(NodeEx n, Content c) {
|
||||
pragma[nomagic]
|
||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate store(
|
||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||
contentType) and
|
||||
hasReadStep(tc.getContent(), config) and
|
||||
read(_, tc.getContent(), _, config) and
|
||||
stepFilter(node1, node2, config)
|
||||
}
|
||||
|
||||
@@ -603,9 +598,13 @@ private predicate hasSinkCallCtx(Configuration config) {
|
||||
}
|
||||
|
||||
private module Stage1 implements StageSig {
|
||||
class ApApprox = Unit;
|
||||
|
||||
class Ap = Unit;
|
||||
|
||||
private class Cc = boolean;
|
||||
class ApOption = Unit;
|
||||
|
||||
class Cc = boolean;
|
||||
|
||||
/* Begin: Stage 1 logic. */
|
||||
/**
|
||||
@@ -614,7 +613,7 @@ private module Stage1 implements StageSig {
|
||||
* The Boolean `cc` records whether the node is reached through an
|
||||
* argument in a call.
|
||||
*/
|
||||
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
sourceNode(node, _, config) and
|
||||
if hasSourceCallCtx(config) then cc = true else cc = false
|
||||
or
|
||||
@@ -754,7 +753,7 @@ private module Stage1 implements StageSig {
|
||||
* the enclosing callable in order to reach a sink.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
revFlow0(node, toReturn, config) and
|
||||
fwdFlow(node, config)
|
||||
}
|
||||
@@ -838,13 +837,13 @@ private module Stage1 implements StageSig {
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
additional predicate viableReturnPosOutNodeCandFwd1(
|
||||
predicate viableReturnPosOutNodeCandFwd1(
|
||||
DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
|
||||
) {
|
||||
fwdFlowReturnPosition(pos, _, config) and
|
||||
@@ -860,7 +859,7 @@ private module Stage1 implements StageSig {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
viableParamArgEx(call, p, arg) and
|
||||
@@ -907,7 +906,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate revFlowState(FlowState state, Configuration config) {
|
||||
predicate revFlowState(FlowState state, Configuration config) {
|
||||
exists(NodeEx node |
|
||||
sinkNode(node, state, config) and
|
||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||
@@ -999,7 +998,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate stats(
|
||||
predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -1260,7 +1259,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* argument.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate fwdFlow(
|
||||
predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, argAp, ap, config) and
|
||||
@@ -1484,7 +1483,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* the access path of the returned value.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate revFlow(
|
||||
predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow0(node, state, toReturn, returnAp, ap, config) and
|
||||
@@ -1662,7 +1661,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
revFlow(node, state, _, _, _, config)
|
||||
}
|
||||
|
||||
@@ -1675,13 +1674,11 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||
revFlow(node, _, _, _, _, config)
|
||||
}
|
||||
predicate revFlowAlias(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
additional predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
revFlow(node, state, ap, config)
|
||||
}
|
||||
|
||||
@@ -1702,7 +1699,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
}
|
||||
@@ -1744,7 +1741,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate stats(
|
||||
predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -2929,15 +2926,10 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
result = this.getASuccessorImpl()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private PathNodeImpl getANonHiddenSuccessor0() {
|
||||
result = this.getASuccessorIfHidden*() and
|
||||
not result.isHidden()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getANonHiddenSuccessor0() and
|
||||
not this.isHidden()
|
||||
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
not result.isHidden()
|
||||
}
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
@@ -163,9 +163,7 @@ abstract class Configuration extends string {
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink) {
|
||||
sink = any(PathNodeSink n | this = n.getConfiguration()).getNodeEx().asNode()
|
||||
}
|
||||
predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -560,16 +558,13 @@ private predicate expectsContentEx(NodeEx n, Content c) {
|
||||
pragma[nomagic]
|
||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate store(
|
||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||
contentType) and
|
||||
hasReadStep(tc.getContent(), config) and
|
||||
read(_, tc.getContent(), _, config) and
|
||||
stepFilter(node1, node2, config)
|
||||
}
|
||||
|
||||
@@ -603,9 +598,13 @@ private predicate hasSinkCallCtx(Configuration config) {
|
||||
}
|
||||
|
||||
private module Stage1 implements StageSig {
|
||||
class ApApprox = Unit;
|
||||
|
||||
class Ap = Unit;
|
||||
|
||||
private class Cc = boolean;
|
||||
class ApOption = Unit;
|
||||
|
||||
class Cc = boolean;
|
||||
|
||||
/* Begin: Stage 1 logic. */
|
||||
/**
|
||||
@@ -614,7 +613,7 @@ private module Stage1 implements StageSig {
|
||||
* The Boolean `cc` records whether the node is reached through an
|
||||
* argument in a call.
|
||||
*/
|
||||
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
sourceNode(node, _, config) and
|
||||
if hasSourceCallCtx(config) then cc = true else cc = false
|
||||
or
|
||||
@@ -754,7 +753,7 @@ private module Stage1 implements StageSig {
|
||||
* the enclosing callable in order to reach a sink.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
revFlow0(node, toReturn, config) and
|
||||
fwdFlow(node, config)
|
||||
}
|
||||
@@ -838,13 +837,13 @@ private module Stage1 implements StageSig {
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
additional predicate viableReturnPosOutNodeCandFwd1(
|
||||
predicate viableReturnPosOutNodeCandFwd1(
|
||||
DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
|
||||
) {
|
||||
fwdFlowReturnPosition(pos, _, config) and
|
||||
@@ -860,7 +859,7 @@ private module Stage1 implements StageSig {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
viableParamArgEx(call, p, arg) and
|
||||
@@ -907,7 +906,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate revFlowState(FlowState state, Configuration config) {
|
||||
predicate revFlowState(FlowState state, Configuration config) {
|
||||
exists(NodeEx node |
|
||||
sinkNode(node, state, config) and
|
||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||
@@ -999,7 +998,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate stats(
|
||||
predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -1260,7 +1259,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* argument.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate fwdFlow(
|
||||
predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, argAp, ap, config) and
|
||||
@@ -1484,7 +1483,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* the access path of the returned value.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate revFlow(
|
||||
predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow0(node, state, toReturn, returnAp, ap, config) and
|
||||
@@ -1662,7 +1661,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
revFlow(node, state, _, _, _, config)
|
||||
}
|
||||
|
||||
@@ -1675,13 +1674,11 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||
revFlow(node, _, _, _, _, config)
|
||||
}
|
||||
predicate revFlowAlias(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
additional predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
revFlow(node, state, ap, config)
|
||||
}
|
||||
|
||||
@@ -1702,7 +1699,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
}
|
||||
@@ -1744,7 +1741,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate stats(
|
||||
predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -2929,15 +2926,10 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
result = this.getASuccessorImpl()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private PathNodeImpl getANonHiddenSuccessor0() {
|
||||
result = this.getASuccessorIfHidden*() and
|
||||
not result.isHidden()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getANonHiddenSuccessor0() and
|
||||
not this.isHidden()
|
||||
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
not result.isHidden()
|
||||
}
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
@@ -163,9 +163,7 @@ abstract class Configuration extends string {
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink) {
|
||||
sink = any(PathNodeSink n | this = n.getConfiguration()).getNodeEx().asNode()
|
||||
}
|
||||
predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -560,16 +558,13 @@ private predicate expectsContentEx(NodeEx n, Content c) {
|
||||
pragma[nomagic]
|
||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate store(
|
||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||
contentType) and
|
||||
hasReadStep(tc.getContent(), config) and
|
||||
read(_, tc.getContent(), _, config) and
|
||||
stepFilter(node1, node2, config)
|
||||
}
|
||||
|
||||
@@ -603,9 +598,13 @@ private predicate hasSinkCallCtx(Configuration config) {
|
||||
}
|
||||
|
||||
private module Stage1 implements StageSig {
|
||||
class ApApprox = Unit;
|
||||
|
||||
class Ap = Unit;
|
||||
|
||||
private class Cc = boolean;
|
||||
class ApOption = Unit;
|
||||
|
||||
class Cc = boolean;
|
||||
|
||||
/* Begin: Stage 1 logic. */
|
||||
/**
|
||||
@@ -614,7 +613,7 @@ private module Stage1 implements StageSig {
|
||||
* The Boolean `cc` records whether the node is reached through an
|
||||
* argument in a call.
|
||||
*/
|
||||
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
sourceNode(node, _, config) and
|
||||
if hasSourceCallCtx(config) then cc = true else cc = false
|
||||
or
|
||||
@@ -754,7 +753,7 @@ private module Stage1 implements StageSig {
|
||||
* the enclosing callable in order to reach a sink.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
revFlow0(node, toReturn, config) and
|
||||
fwdFlow(node, config)
|
||||
}
|
||||
@@ -838,13 +837,13 @@ private module Stage1 implements StageSig {
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
additional predicate viableReturnPosOutNodeCandFwd1(
|
||||
predicate viableReturnPosOutNodeCandFwd1(
|
||||
DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
|
||||
) {
|
||||
fwdFlowReturnPosition(pos, _, config) and
|
||||
@@ -860,7 +859,7 @@ private module Stage1 implements StageSig {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
viableParamArgEx(call, p, arg) and
|
||||
@@ -907,7 +906,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate revFlowState(FlowState state, Configuration config) {
|
||||
predicate revFlowState(FlowState state, Configuration config) {
|
||||
exists(NodeEx node |
|
||||
sinkNode(node, state, config) and
|
||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||
@@ -999,7 +998,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate stats(
|
||||
predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -1260,7 +1259,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* argument.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate fwdFlow(
|
||||
predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, argAp, ap, config) and
|
||||
@@ -1484,7 +1483,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* the access path of the returned value.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate revFlow(
|
||||
predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow0(node, state, toReturn, returnAp, ap, config) and
|
||||
@@ -1662,7 +1661,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
revFlow(node, state, _, _, _, config)
|
||||
}
|
||||
|
||||
@@ -1675,13 +1674,11 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||
revFlow(node, _, _, _, _, config)
|
||||
}
|
||||
predicate revFlowAlias(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
additional predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
revFlow(node, state, ap, config)
|
||||
}
|
||||
|
||||
@@ -1702,7 +1699,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
}
|
||||
@@ -1744,7 +1741,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate stats(
|
||||
predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -2929,15 +2926,10 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
result = this.getASuccessorImpl()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private PathNodeImpl getANonHiddenSuccessor0() {
|
||||
result = this.getASuccessorIfHidden*() and
|
||||
not result.isHidden()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getANonHiddenSuccessor0() and
|
||||
not this.isHidden()
|
||||
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
not result.isHidden()
|
||||
}
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
@@ -137,7 +137,7 @@ private newtype TReturnKind =
|
||||
exists(IndirectReturnNode return, ReturnIndirectionInstruction returnInd |
|
||||
returnInd.hasIndex(argumentIndex) and
|
||||
return.getAddressOperand() = returnInd.getSourceAddressOperand() and
|
||||
indirectionIndex = return.getIndirectionIndex()
|
||||
indirectionIndex = return.getIndirectionIndex() - 1 // We subtract one because the return loads the value.
|
||||
)
|
||||
}
|
||||
|
||||
@@ -197,7 +197,7 @@ class ReturnIndirectionNode extends IndirectReturnNode, ReturnNode {
|
||||
exists(int argumentIndex, ReturnIndirectionInstruction returnInd |
|
||||
returnInd.hasIndex(argumentIndex) and
|
||||
this.getAddressOperand() = returnInd.getSourceAddressOperand() and
|
||||
result = TIndirectReturnKind(argumentIndex, this.getIndirectionIndex()) and
|
||||
result = TIndirectReturnKind(argumentIndex, this.getIndirectionIndex() - 1) and
|
||||
hasNonInitializeParameterDef(returnInd.getIRVariable())
|
||||
)
|
||||
or
|
||||
@@ -365,7 +365,7 @@ predicate jumpStep(Node n1, Node n2) {
|
||||
predicate storeStep(Node node1, Content c, PostFieldUpdateNode node2) {
|
||||
exists(int indirectionIndex1, int numberOfLoads, StoreInstruction store |
|
||||
nodeHasInstruction(node1, store, pragma[only_bind_into](indirectionIndex1)) and
|
||||
node2.getIndirectionIndex() = 1 and
|
||||
node2.getIndirectionIndex() = 0 and
|
||||
numberOfLoadsFromOperand(node2.getFieldAddress(), store.getDestinationAddressOperand(),
|
||||
numberOfLoads)
|
||||
|
|
||||
@@ -465,20 +465,20 @@ predicate clearsContent(Node n, Content c) {
|
||||
predicate expectsContent(Node n, ContentSet c) { none() }
|
||||
|
||||
/** Gets the type of `n` used for type pruning. */
|
||||
DataFlowType getNodeType(Node n) {
|
||||
IRType getNodeType(Node n) {
|
||||
suppressUnusedNode(n) and
|
||||
result instanceof VoidType // stub implementation
|
||||
result instanceof IRVoidType // stub implementation
|
||||
}
|
||||
|
||||
/** Gets a string representation of a type returned by `getNodeType`. */
|
||||
string ppReprType(DataFlowType t) { none() } // stub implementation
|
||||
string ppReprType(IRType t) { none() } // stub implementation
|
||||
|
||||
/**
|
||||
* Holds if `t1` and `t2` are compatible, that is, whether data can flow from
|
||||
* a node of type `t1` to a node of type `t2`.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate compatibleTypes(DataFlowType t1, DataFlowType t2) {
|
||||
predicate compatibleTypes(IRType t1, IRType t2) {
|
||||
any() // stub implementation
|
||||
}
|
||||
|
||||
@@ -502,7 +502,7 @@ class DataFlowCallable = Cpp::Declaration;
|
||||
|
||||
class DataFlowExpr = Expr;
|
||||
|
||||
class DataFlowType = Type;
|
||||
class DataFlowType = IRType;
|
||||
|
||||
/** A function call relevant for data flow. */
|
||||
class DataFlowCall extends CallInstruction {
|
||||
|
||||
@@ -38,12 +38,13 @@ private module Cached {
|
||||
TVariableNode(Variable var) or
|
||||
TPostFieldUpdateNode(FieldAddress operand, int indirectionIndex) {
|
||||
indirectionIndex =
|
||||
[1 .. Ssa::countIndirectionsForCppType(operand.getObjectAddress().getResultLanguageType())]
|
||||
[0 .. Ssa::countIndirectionsForCppType(operand.getObjectAddress().getResultLanguageType()) -
|
||||
1]
|
||||
} or
|
||||
TSsaPhiNode(Ssa::PhiNode phi) or
|
||||
TIndirectArgumentOutNode(ArgumentOperand operand, int indirectionIndex) {
|
||||
Ssa::isModifiableByCall(operand) and
|
||||
indirectionIndex = [1 .. Ssa::countIndirectionsForCppType(operand.getLanguageType())]
|
||||
indirectionIndex = [0 .. Ssa::countIndirectionsForCppType(operand.getLanguageType()) - 1]
|
||||
} or
|
||||
TIndirectOperand(Operand op, int indirectionIndex) {
|
||||
Ssa::hasIndirectOperand(op, indirectionIndex)
|
||||
@@ -112,7 +113,7 @@ class Node extends TIRDataFlowNode {
|
||||
Declaration getFunction() { none() } // overridden in subclasses
|
||||
|
||||
/** Gets the type of this node. */
|
||||
DataFlowType getType() { none() } // overridden in subclasses
|
||||
IRType getType() { none() } // overridden in subclasses
|
||||
|
||||
/** Gets the instruction corresponding to this node, if any. */
|
||||
Instruction asInstruction() { result = this.(InstructionNode).getInstruction() }
|
||||
@@ -229,13 +230,7 @@ class Node extends TIRDataFlowNode {
|
||||
Expr asIndirectArgument() { result = this.asIndirectArgument(_) }
|
||||
|
||||
/** Gets the positional parameter corresponding to this node, if any. */
|
||||
Parameter asParameter() { result = this.asParameter(0) }
|
||||
|
||||
/**
|
||||
* Gets the uninitialized local variable corresponding to this node, if
|
||||
* any.
|
||||
*/
|
||||
LocalVariable asUninitialized() { result = this.(UninitializedNode).getLocalVariable() }
|
||||
Parameter asParameter() { result = asParameter(0) }
|
||||
|
||||
/**
|
||||
* Gets the positional parameter corresponding to the node that represents
|
||||
@@ -278,7 +273,7 @@ class Node extends TIRDataFlowNode {
|
||||
/**
|
||||
* Gets an upper bound on the type of this node.
|
||||
*/
|
||||
DataFlowType getTypeBound() { result = this.getType() }
|
||||
IRType getTypeBound() { result = this.getType() }
|
||||
|
||||
/** Gets the location of this element. */
|
||||
cached
|
||||
@@ -327,7 +322,7 @@ class InstructionNode extends Node, TInstructionNode {
|
||||
|
||||
override Declaration getFunction() { result = instr.getEnclosingFunction() }
|
||||
|
||||
override DataFlowType getType() { result = instr.getResultType() }
|
||||
override IRType getType() { result = instr.getResultIRType() }
|
||||
|
||||
final override Location getLocationImpl() { result = instr.getLocation() }
|
||||
|
||||
@@ -353,32 +348,13 @@ class OperandNode extends Node, TOperandNode {
|
||||
|
||||
override Declaration getFunction() { result = op.getUse().getEnclosingFunction() }
|
||||
|
||||
override DataFlowType getType() { result = op.getType() }
|
||||
override IRType getType() { result = op.getIRType() }
|
||||
|
||||
final override Location getLocationImpl() { result = op.getLocation() }
|
||||
|
||||
override string toStringImpl() { result = this.getOperand().toString() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns `t`, but stripped of the `n` outermost pointers, references, etc.
|
||||
*
|
||||
* For example, `stripPointers(int*&, 2)` is `int` and `stripPointers(int*, 0)` is `int*`.
|
||||
*/
|
||||
private Type stripPointers(Type t, int n) {
|
||||
result = t and n = 0
|
||||
or
|
||||
result = stripPointers(t.(PointerType).getBaseType(), n - 1)
|
||||
or
|
||||
result = stripPointers(t.(ArrayType).getBaseType(), n - 1)
|
||||
or
|
||||
result = stripPointers(t.(ReferenceType).getBaseType(), n - 1)
|
||||
or
|
||||
result = stripPointers(t.(PointerToMemberType).getBaseType(), n - 1)
|
||||
or
|
||||
result = stripPointers(t.(FunctionPointerIshType).getBaseType(), n - 1)
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL: do not use.
|
||||
*
|
||||
@@ -394,6 +370,8 @@ class PostFieldUpdateNode extends TPostFieldUpdateNode, PartialDefinitionNode {
|
||||
|
||||
override Declaration getEnclosingCallable() { result = this.getFunction() }
|
||||
|
||||
override IRType getType() { result = fieldAddress.getIRType() }
|
||||
|
||||
FieldAddress getFieldAddress() { result = fieldAddress }
|
||||
|
||||
Field getUpdatedField() { result = fieldAddress.getField() }
|
||||
@@ -401,8 +379,10 @@ class PostFieldUpdateNode extends TPostFieldUpdateNode, PartialDefinitionNode {
|
||||
int getIndirectionIndex() { result = indirectionIndex }
|
||||
|
||||
override Node getPreUpdateNode() {
|
||||
// + 1 because we're storing into an lvalue, and the original node should be the rvalue of
|
||||
// the same address.
|
||||
hasOperandAndIndex(result, pragma[only_bind_into](fieldAddress).getObjectAddressOperand(),
|
||||
indirectionIndex)
|
||||
indirectionIndex + 1)
|
||||
}
|
||||
|
||||
override Expr getDefinedExpr() {
|
||||
@@ -431,26 +411,11 @@ class SsaPhiNode extends Node, TSsaPhiNode {
|
||||
|
||||
override Declaration getFunction() { result = phi.getBasicBlock().getEnclosingFunction() }
|
||||
|
||||
override DataFlowType getType() { result = this.getAnInput().getType() }
|
||||
override IRType getType() { result instanceof IRVoidType }
|
||||
|
||||
final override Location getLocationImpl() { result = phi.getBasicBlock().getLocation() }
|
||||
|
||||
override string toStringImpl() { result = "Phi" }
|
||||
|
||||
/**
|
||||
* Gets a node that is used as input to this phi node.
|
||||
* `fromBackEdge` is true if data flows along a back-edge,
|
||||
* and `false` otherwise.
|
||||
*/
|
||||
final Node getAnInput(boolean fromBackEdge) {
|
||||
localFlowStep(result, this) and
|
||||
if phi.getBasicBlock().dominates(getBasicBlock(result))
|
||||
then fromBackEdge = true
|
||||
else fromBackEdge = false
|
||||
}
|
||||
|
||||
/** Gets a node that is used as input to this phi node. */
|
||||
final Node getAnInput() { result = this.getAnInput(_) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -474,6 +439,8 @@ class SideEffectOperandNode extends Node, IndirectOperand {
|
||||
|
||||
override Function getFunction() { result = call.getEnclosingFunction() }
|
||||
|
||||
override IRType getType() { result instanceof IRVoidType }
|
||||
|
||||
Expr getArgument() { result = call.getArgument(argumentIndex).getUnconvertedResultExpression() }
|
||||
}
|
||||
|
||||
@@ -496,6 +463,8 @@ class IndirectParameterNode extends Node, IndirectInstruction {
|
||||
|
||||
override Function getFunction() { result = this.getInstruction().getEnclosingFunction() }
|
||||
|
||||
override IRType getType() { result instanceof IRVoidType }
|
||||
|
||||
override string toStringImpl() {
|
||||
result = this.getParameter().toString() + " indirection"
|
||||
or
|
||||
@@ -520,6 +489,8 @@ class IndirectReturnNode extends IndirectOperand {
|
||||
Operand getAddressOperand() { result = operand }
|
||||
|
||||
override Declaration getEnclosingCallable() { result = this.getFunction() }
|
||||
|
||||
override IRType getType() { result instanceof IRVoidType }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -550,7 +521,9 @@ class IndirectArgumentOutNode extends Node, TIndirectArgumentOutNode, PostUpdate
|
||||
|
||||
override Function getFunction() { result = this.getCallInstruction().getEnclosingFunction() }
|
||||
|
||||
override Node getPreUpdateNode() { hasOperandAndIndex(result, operand, indirectionIndex) }
|
||||
override IRType getType() { result instanceof IRVoidType }
|
||||
|
||||
override Node getPreUpdateNode() { hasOperandAndIndex(result, operand, indirectionIndex + 1) }
|
||||
|
||||
override string toStringImpl() {
|
||||
// This string should be unique enough to be helpful but common enough to
|
||||
@@ -606,38 +579,6 @@ class IndirectReturnOutNode extends Node {
|
||||
int getIndirectionIndex() { result = indirectionIndex }
|
||||
}
|
||||
|
||||
private PointerType getGLValueType(Type t, int indirectionIndex) {
|
||||
result.getBaseType() = stripPointers(t, indirectionIndex - 1)
|
||||
}
|
||||
|
||||
bindingset[isGLValue]
|
||||
private DataFlowType getTypeImpl(Type t, int indirectionIndex, boolean isGLValue) {
|
||||
if isGLValue = true
|
||||
then
|
||||
result = getGLValueType(t, indirectionIndex)
|
||||
or
|
||||
// Ideally, the above case would cover all glvalue cases. However, consider the case where
|
||||
// the database consists only of:
|
||||
// ```
|
||||
// void test() {
|
||||
// int* x;
|
||||
// x = nullptr;
|
||||
// }
|
||||
// ```
|
||||
// and we want to compute the type of `*x` in the assignment `x = nullptr`. Here, `x` is an lvalue
|
||||
// of type int* (which morally is an int**). So when we call `getTypeImpl` it will be with the
|
||||
// parameters:
|
||||
// - t = int*
|
||||
// - indirectionIndex = 1 (when we want to model the dataflow node corresponding to *x)
|
||||
// - isGLValue = true
|
||||
// In this case, `getTypeImpl(t, indirectionIndex, isGLValue)` should give back `int**`. In this
|
||||
// case, however, `int**` does not exist in the database. So instead we return int* (which is
|
||||
// wrong, but at least we have a type).
|
||||
not exists(getGLValueType(t, indirectionIndex)) and
|
||||
result = stripPointers(t, indirectionIndex - 1)
|
||||
else result = stripPointers(t, indirectionIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
@@ -659,11 +600,7 @@ class IndirectOperand extends Node, TIndirectOperand {
|
||||
|
||||
override Declaration getEnclosingCallable() { result = this.getFunction() }
|
||||
|
||||
override DataFlowType getType() {
|
||||
exists(boolean isGLValue | if operand.isGLValue() then isGLValue = true else isGLValue = false |
|
||||
result = getTypeImpl(operand.getType().getUnspecifiedType(), indirectionIndex, isGLValue)
|
||||
)
|
||||
}
|
||||
override IRType getType() { result = this.getOperand().getIRType() }
|
||||
|
||||
final override Location getLocationImpl() { result = this.getOperand().getLocation() }
|
||||
|
||||
@@ -672,25 +609,6 @@ class IndirectOperand extends Node, TIndirectOperand {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The value of an uninitialized local variable, viewed as a node in a data
|
||||
* flow graph.
|
||||
*/
|
||||
class UninitializedNode extends Node {
|
||||
LocalVariable v;
|
||||
|
||||
UninitializedNode() {
|
||||
exists(Ssa::Def def |
|
||||
def.getDefiningInstruction() instanceof UninitializedInstruction and
|
||||
Ssa::nodeToDefOrUse(this, def) and
|
||||
v = def.getSourceVariable().getBaseVariable().(Ssa::BaseIRVariable).getIRVariable().getAst()
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the uninitialized local variable corresponding to this node. */
|
||||
LocalVariable getLocalVariable() { result = v }
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
@@ -712,11 +630,7 @@ class IndirectInstruction extends Node, TIndirectInstruction {
|
||||
|
||||
override Declaration getEnclosingCallable() { result = this.getFunction() }
|
||||
|
||||
override DataFlowType getType() {
|
||||
exists(boolean isGLValue | if instr.isGLValue() then isGLValue = true else isGLValue = false |
|
||||
result = getTypeImpl(instr.getResultType().getUnspecifiedType(), indirectionIndex, isGLValue)
|
||||
)
|
||||
}
|
||||
override IRType getType() { result = this.getInstruction().getResultIRType() }
|
||||
|
||||
final override Location getLocationImpl() { result = this.getInstruction().getLocation() }
|
||||
|
||||
@@ -930,8 +844,6 @@ abstract class PostUpdateNode extends Node {
|
||||
* Gets the node before the state update.
|
||||
*/
|
||||
abstract Node getPreUpdateNode();
|
||||
|
||||
final override DataFlowType getType() { result = this.getPreUpdateNode().getType() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -995,7 +907,7 @@ class VariableNode extends Node, TVariableNode {
|
||||
result = v
|
||||
}
|
||||
|
||||
override DataFlowType getType() { result = v.getType() }
|
||||
override IRType getType() { result.getCanonicalLanguageType().hasUnspecifiedType(v.getType(), _) }
|
||||
|
||||
final override Location getLocationImpl() { result = v.getLocation() }
|
||||
|
||||
@@ -1148,7 +1060,7 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
|
||||
store.getDestinationAddressOperand() = address
|
||||
)
|
||||
or
|
||||
Ssa::outNodeHasAddressAndIndex(nodeFrom, address, indirectionIndex)
|
||||
Ssa::outNodeHasAddressAndIndex(nodeFrom, address, indirectionIndex - 1)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ Node callOutput(CallInstruction call, FunctionOutput output) {
|
||||
// The side effect of a call on the value pointed to by an argument or qualifier
|
||||
exists(int index, int indirectionIndex |
|
||||
result.(IndirectArgumentOutNode).getArgumentIndex() = index and
|
||||
result.(IndirectArgumentOutNode).getIndirectionIndex() = indirectionIndex and
|
||||
result.(IndirectArgumentOutNode).getIndirectionIndex() + 1 = indirectionIndex and
|
||||
result.(IndirectArgumentOutNode).getCallInstruction() = call and
|
||||
output.isParameterDerefOrQualifierObject(index, indirectionIndex)
|
||||
)
|
||||
|
||||
@@ -301,12 +301,7 @@ private predicate defToNode(Node nodeFrom, Def def) {
|
||||
nodeHasInstruction(nodeFrom, def.getDefiningInstruction(), def.getIndirectionIndex())
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* Holds if `nodeFrom` is the node that correspond to the definition or use `defOrUse`.
|
||||
*/
|
||||
predicate nodeToDefOrUse(Node nodeFrom, SsaDefOrUse defOrUse) {
|
||||
private predicate nodeToDefOrUse(Node nodeFrom, SsaDefOrUse defOrUse) {
|
||||
// Node -> Def
|
||||
defToNode(nodeFrom, defOrUse)
|
||||
or
|
||||
|
||||
@@ -11,9 +11,7 @@ private import DataFlowUtil
|
||||
* corresponding `(Indirect)OperandNode`.
|
||||
*/
|
||||
predicate ignoreOperand(Operand operand) {
|
||||
operand = any(Instruction instr | ignoreInstruction(instr)).getAnOperand() or
|
||||
operand = any(Instruction instr | ignoreInstruction(instr)).getAUse() or
|
||||
operand instanceof MemoryOperand
|
||||
operand = any(Instruction instr | ignoreInstruction(instr)).getAnOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -36,7 +36,7 @@ private module SourceVariables {
|
||||
|
||||
override string toString() { result = var.toString() }
|
||||
|
||||
override DataFlowType getType() { result = var.getType() }
|
||||
override DataFlowType getType() { result = var.getIRType() }
|
||||
}
|
||||
|
||||
class BaseCallVariable extends BaseSourceVariable, TBaseCallVariable {
|
||||
@@ -48,7 +48,7 @@ private module SourceVariables {
|
||||
|
||||
override string toString() { result = call.toString() }
|
||||
|
||||
override DataFlowType getType() { result = call.getResultType() }
|
||||
override DataFlowType getType() { result = call.getResultIRType() }
|
||||
}
|
||||
|
||||
private newtype TSourceVariable =
|
||||
|
||||
@@ -7,7 +7,6 @@ private import semmle.code.cpp.ir.IR as IR
|
||||
private import Semantic
|
||||
private import experimental.semmle.code.cpp.rangeanalysis.Bound as IRBound
|
||||
private import semmle.code.cpp.controlflow.IRGuards as IRGuards
|
||||
private import semmle.code.cpp.ir.ValueNumbering
|
||||
|
||||
module SemanticExprConfig {
|
||||
class Location = Cpp::Location;
|
||||
@@ -121,15 +120,7 @@ module SemanticExprConfig {
|
||||
|
||||
newtype TSsaVariable =
|
||||
TSsaInstruction(IR::Instruction instr) { instr.hasMemoryResult() } or
|
||||
TSsaOperand(IR::Operand op) { op.isDefinitionInexact() } or
|
||||
TSsaPointerArithmeticGuard(IR::PointerArithmeticInstruction instr) {
|
||||
exists(Guard g, IR::Operand use | use = instr.getAUse() |
|
||||
g.comparesLt(use, _, _, _, _) or
|
||||
g.comparesLt(_, use, _, _, _) or
|
||||
g.comparesEq(use, _, _, _, _) or
|
||||
g.comparesEq(_, use, _, _, _)
|
||||
)
|
||||
}
|
||||
TSsaOperand(IR::Operand op) { op.isDefinitionInexact() }
|
||||
|
||||
class SsaVariable extends TSsaVariable {
|
||||
string toString() { none() }
|
||||
@@ -138,8 +129,6 @@ module SemanticExprConfig {
|
||||
|
||||
IR::Instruction asInstruction() { none() }
|
||||
|
||||
IR::PointerArithmeticInstruction asPointerArithGuard() { none() }
|
||||
|
||||
IR::Operand asOperand() { none() }
|
||||
}
|
||||
|
||||
@@ -155,18 +144,6 @@ module SemanticExprConfig {
|
||||
final override IR::Instruction asInstruction() { result = instr }
|
||||
}
|
||||
|
||||
class SsaPointerArithmeticGuard extends SsaVariable, TSsaPointerArithmeticGuard {
|
||||
IR::PointerArithmeticInstruction instr;
|
||||
|
||||
SsaPointerArithmeticGuard() { this = TSsaPointerArithmeticGuard(instr) }
|
||||
|
||||
final override string toString() { result = instr.toString() }
|
||||
|
||||
final override Location getLocation() { result = instr.getLocation() }
|
||||
|
||||
final override IR::PointerArithmeticInstruction asPointerArithGuard() { result = instr }
|
||||
}
|
||||
|
||||
class SsaOperand extends SsaVariable, TSsaOperand {
|
||||
IR::Operand op;
|
||||
|
||||
@@ -191,11 +168,7 @@ module SemanticExprConfig {
|
||||
)
|
||||
}
|
||||
|
||||
Expr getAUse(SsaVariable v) {
|
||||
result.(IR::LoadInstruction).getSourceValue() = v.asInstruction()
|
||||
or
|
||||
result = valueNumber(v.asPointerArithGuard()).getAnInstruction()
|
||||
}
|
||||
Expr getAUse(SsaVariable v) { result.(IR::LoadInstruction).getSourceValue() = v.asInstruction() }
|
||||
|
||||
SemType getSsaVariableType(SsaVariable v) {
|
||||
result = getSemanticType(v.asInstruction().getResultIRType())
|
||||
@@ -235,9 +208,7 @@ module SemanticExprConfig {
|
||||
|
||||
final override predicate hasRead(SsaVariable v) {
|
||||
exists(IR::Operand operand |
|
||||
operand.getDef() = v.asInstruction() or
|
||||
operand.getDef() = valueNumber(v.asPointerArithGuard()).getAnInstruction()
|
||||
|
|
||||
operand.getDef() = v.asInstruction() and
|
||||
not operand instanceof IR::PhiInputOperand and
|
||||
operand.getUse().getBlock() = block
|
||||
)
|
||||
@@ -256,9 +227,7 @@ module SemanticExprConfig {
|
||||
|
||||
final override predicate hasRead(SsaVariable v) {
|
||||
exists(IR::PhiInputOperand operand |
|
||||
operand.getDef() = v.asInstruction() or
|
||||
operand.getDef() = valueNumber(v.asPointerArithGuard()).getAnInstruction()
|
||||
|
|
||||
operand.getDef() = v.asInstruction() and
|
||||
operand.getPredecessorBlock() = pred and
|
||||
operand.getUse().getBlock() = succ
|
||||
)
|
||||
|
||||
@@ -10,7 +10,7 @@ class SemSsaVariable instanceof Specific::SsaVariable {
|
||||
|
||||
final Specific::Location getLocation() { result = super.getLocation() }
|
||||
|
||||
final SemExpr getAUse() { result = Specific::getAUse(this) }
|
||||
final SemLoadExpr getAUse() { result = Specific::getAUse(this) }
|
||||
|
||||
final SemType getType() { result = Specific::getSsaVariableType(this) }
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 0.4.2-dev
|
||||
version: 0.4.0-dev
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
|
||||
@@ -6,7 +6,7 @@ import cpp
|
||||
* A function that concatenates the string from its second argument
|
||||
* to the string from its first argument, for example `strcat`.
|
||||
*/
|
||||
deprecated class StrcatFunction extends Function {
|
||||
class StrcatFunction extends Function {
|
||||
StrcatFunction() {
|
||||
getName() =
|
||||
[
|
||||
|
||||
@@ -163,9 +163,7 @@ abstract class Configuration extends string {
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink) {
|
||||
sink = any(PathNodeSink n | this = n.getConfiguration()).getNodeEx().asNode()
|
||||
}
|
||||
predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -560,16 +558,13 @@ private predicate expectsContentEx(NodeEx n, Content c) {
|
||||
pragma[nomagic]
|
||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate store(
|
||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||
contentType) and
|
||||
hasReadStep(tc.getContent(), config) and
|
||||
read(_, tc.getContent(), _, config) and
|
||||
stepFilter(node1, node2, config)
|
||||
}
|
||||
|
||||
@@ -603,9 +598,13 @@ private predicate hasSinkCallCtx(Configuration config) {
|
||||
}
|
||||
|
||||
private module Stage1 implements StageSig {
|
||||
class ApApprox = Unit;
|
||||
|
||||
class Ap = Unit;
|
||||
|
||||
private class Cc = boolean;
|
||||
class ApOption = Unit;
|
||||
|
||||
class Cc = boolean;
|
||||
|
||||
/* Begin: Stage 1 logic. */
|
||||
/**
|
||||
@@ -614,7 +613,7 @@ private module Stage1 implements StageSig {
|
||||
* The Boolean `cc` records whether the node is reached through an
|
||||
* argument in a call.
|
||||
*/
|
||||
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
sourceNode(node, _, config) and
|
||||
if hasSourceCallCtx(config) then cc = true else cc = false
|
||||
or
|
||||
@@ -754,7 +753,7 @@ private module Stage1 implements StageSig {
|
||||
* the enclosing callable in order to reach a sink.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
revFlow0(node, toReturn, config) and
|
||||
fwdFlow(node, config)
|
||||
}
|
||||
@@ -838,13 +837,13 @@ private module Stage1 implements StageSig {
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
additional predicate viableReturnPosOutNodeCandFwd1(
|
||||
predicate viableReturnPosOutNodeCandFwd1(
|
||||
DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
|
||||
) {
|
||||
fwdFlowReturnPosition(pos, _, config) and
|
||||
@@ -860,7 +859,7 @@ private module Stage1 implements StageSig {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
viableParamArgEx(call, p, arg) and
|
||||
@@ -907,7 +906,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate revFlowState(FlowState state, Configuration config) {
|
||||
predicate revFlowState(FlowState state, Configuration config) {
|
||||
exists(NodeEx node |
|
||||
sinkNode(node, state, config) and
|
||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||
@@ -999,7 +998,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate stats(
|
||||
predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -1260,7 +1259,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* argument.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate fwdFlow(
|
||||
predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, argAp, ap, config) and
|
||||
@@ -1484,7 +1483,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* the access path of the returned value.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate revFlow(
|
||||
predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow0(node, state, toReturn, returnAp, ap, config) and
|
||||
@@ -1662,7 +1661,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
revFlow(node, state, _, _, _, config)
|
||||
}
|
||||
|
||||
@@ -1675,13 +1674,11 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||
revFlow(node, _, _, _, _, config)
|
||||
}
|
||||
predicate revFlowAlias(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
additional predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
revFlow(node, state, ap, config)
|
||||
}
|
||||
|
||||
@@ -1702,7 +1699,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
}
|
||||
@@ -1744,7 +1741,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate stats(
|
||||
predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -2929,15 +2926,10 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
result = this.getASuccessorImpl()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private PathNodeImpl getANonHiddenSuccessor0() {
|
||||
result = this.getASuccessorIfHidden*() and
|
||||
not result.isHidden()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getANonHiddenSuccessor0() and
|
||||
not this.isHidden()
|
||||
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
not result.isHidden()
|
||||
}
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
@@ -163,9 +163,7 @@ abstract class Configuration extends string {
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink) {
|
||||
sink = any(PathNodeSink n | this = n.getConfiguration()).getNodeEx().asNode()
|
||||
}
|
||||
predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -560,16 +558,13 @@ private predicate expectsContentEx(NodeEx n, Content c) {
|
||||
pragma[nomagic]
|
||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate store(
|
||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||
contentType) and
|
||||
hasReadStep(tc.getContent(), config) and
|
||||
read(_, tc.getContent(), _, config) and
|
||||
stepFilter(node1, node2, config)
|
||||
}
|
||||
|
||||
@@ -603,9 +598,13 @@ private predicate hasSinkCallCtx(Configuration config) {
|
||||
}
|
||||
|
||||
private module Stage1 implements StageSig {
|
||||
class ApApprox = Unit;
|
||||
|
||||
class Ap = Unit;
|
||||
|
||||
private class Cc = boolean;
|
||||
class ApOption = Unit;
|
||||
|
||||
class Cc = boolean;
|
||||
|
||||
/* Begin: Stage 1 logic. */
|
||||
/**
|
||||
@@ -614,7 +613,7 @@ private module Stage1 implements StageSig {
|
||||
* The Boolean `cc` records whether the node is reached through an
|
||||
* argument in a call.
|
||||
*/
|
||||
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
sourceNode(node, _, config) and
|
||||
if hasSourceCallCtx(config) then cc = true else cc = false
|
||||
or
|
||||
@@ -754,7 +753,7 @@ private module Stage1 implements StageSig {
|
||||
* the enclosing callable in order to reach a sink.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
revFlow0(node, toReturn, config) and
|
||||
fwdFlow(node, config)
|
||||
}
|
||||
@@ -838,13 +837,13 @@ private module Stage1 implements StageSig {
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
additional predicate viableReturnPosOutNodeCandFwd1(
|
||||
predicate viableReturnPosOutNodeCandFwd1(
|
||||
DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
|
||||
) {
|
||||
fwdFlowReturnPosition(pos, _, config) and
|
||||
@@ -860,7 +859,7 @@ private module Stage1 implements StageSig {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
viableParamArgEx(call, p, arg) and
|
||||
@@ -907,7 +906,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate revFlowState(FlowState state, Configuration config) {
|
||||
predicate revFlowState(FlowState state, Configuration config) {
|
||||
exists(NodeEx node |
|
||||
sinkNode(node, state, config) and
|
||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||
@@ -999,7 +998,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate stats(
|
||||
predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -1260,7 +1259,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* argument.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate fwdFlow(
|
||||
predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, argAp, ap, config) and
|
||||
@@ -1484,7 +1483,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* the access path of the returned value.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate revFlow(
|
||||
predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow0(node, state, toReturn, returnAp, ap, config) and
|
||||
@@ -1662,7 +1661,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
revFlow(node, state, _, _, _, config)
|
||||
}
|
||||
|
||||
@@ -1675,13 +1674,11 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||
revFlow(node, _, _, _, _, config)
|
||||
}
|
||||
predicate revFlowAlias(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
additional predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
revFlow(node, state, ap, config)
|
||||
}
|
||||
|
||||
@@ -1702,7 +1699,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
}
|
||||
@@ -1744,7 +1741,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate stats(
|
||||
predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -2929,15 +2926,10 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
result = this.getASuccessorImpl()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private PathNodeImpl getANonHiddenSuccessor0() {
|
||||
result = this.getASuccessorIfHidden*() and
|
||||
not result.isHidden()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getANonHiddenSuccessor0() and
|
||||
not this.isHidden()
|
||||
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
not result.isHidden()
|
||||
}
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
@@ -163,9 +163,7 @@ abstract class Configuration extends string {
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink) {
|
||||
sink = any(PathNodeSink n | this = n.getConfiguration()).getNodeEx().asNode()
|
||||
}
|
||||
predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -560,16 +558,13 @@ private predicate expectsContentEx(NodeEx n, Content c) {
|
||||
pragma[nomagic]
|
||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate store(
|
||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||
contentType) and
|
||||
hasReadStep(tc.getContent(), config) and
|
||||
read(_, tc.getContent(), _, config) and
|
||||
stepFilter(node1, node2, config)
|
||||
}
|
||||
|
||||
@@ -603,9 +598,13 @@ private predicate hasSinkCallCtx(Configuration config) {
|
||||
}
|
||||
|
||||
private module Stage1 implements StageSig {
|
||||
class ApApprox = Unit;
|
||||
|
||||
class Ap = Unit;
|
||||
|
||||
private class Cc = boolean;
|
||||
class ApOption = Unit;
|
||||
|
||||
class Cc = boolean;
|
||||
|
||||
/* Begin: Stage 1 logic. */
|
||||
/**
|
||||
@@ -614,7 +613,7 @@ private module Stage1 implements StageSig {
|
||||
* The Boolean `cc` records whether the node is reached through an
|
||||
* argument in a call.
|
||||
*/
|
||||
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
sourceNode(node, _, config) and
|
||||
if hasSourceCallCtx(config) then cc = true else cc = false
|
||||
or
|
||||
@@ -754,7 +753,7 @@ private module Stage1 implements StageSig {
|
||||
* the enclosing callable in order to reach a sink.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
revFlow0(node, toReturn, config) and
|
||||
fwdFlow(node, config)
|
||||
}
|
||||
@@ -838,13 +837,13 @@ private module Stage1 implements StageSig {
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
additional predicate viableReturnPosOutNodeCandFwd1(
|
||||
predicate viableReturnPosOutNodeCandFwd1(
|
||||
DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
|
||||
) {
|
||||
fwdFlowReturnPosition(pos, _, config) and
|
||||
@@ -860,7 +859,7 @@ private module Stage1 implements StageSig {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
viableParamArgEx(call, p, arg) and
|
||||
@@ -907,7 +906,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate revFlowState(FlowState state, Configuration config) {
|
||||
predicate revFlowState(FlowState state, Configuration config) {
|
||||
exists(NodeEx node |
|
||||
sinkNode(node, state, config) and
|
||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||
@@ -999,7 +998,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate stats(
|
||||
predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -1260,7 +1259,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* argument.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate fwdFlow(
|
||||
predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, argAp, ap, config) and
|
||||
@@ -1484,7 +1483,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* the access path of the returned value.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate revFlow(
|
||||
predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow0(node, state, toReturn, returnAp, ap, config) and
|
||||
@@ -1662,7 +1661,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
revFlow(node, state, _, _, _, config)
|
||||
}
|
||||
|
||||
@@ -1675,13 +1674,11 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||
revFlow(node, _, _, _, _, config)
|
||||
}
|
||||
predicate revFlowAlias(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
additional predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
revFlow(node, state, ap, config)
|
||||
}
|
||||
|
||||
@@ -1702,7 +1699,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
}
|
||||
@@ -1744,7 +1741,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate stats(
|
||||
predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -2929,15 +2926,10 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
result = this.getASuccessorImpl()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private PathNodeImpl getANonHiddenSuccessor0() {
|
||||
result = this.getASuccessorIfHidden*() and
|
||||
not result.isHidden()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getANonHiddenSuccessor0() and
|
||||
not this.isHidden()
|
||||
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
not result.isHidden()
|
||||
}
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
@@ -163,9 +163,7 @@ abstract class Configuration extends string {
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink) {
|
||||
sink = any(PathNodeSink n | this = n.getConfiguration()).getNodeEx().asNode()
|
||||
}
|
||||
predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -560,16 +558,13 @@ private predicate expectsContentEx(NodeEx n, Content c) {
|
||||
pragma[nomagic]
|
||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate store(
|
||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||
contentType) and
|
||||
hasReadStep(tc.getContent(), config) and
|
||||
read(_, tc.getContent(), _, config) and
|
||||
stepFilter(node1, node2, config)
|
||||
}
|
||||
|
||||
@@ -603,9 +598,13 @@ private predicate hasSinkCallCtx(Configuration config) {
|
||||
}
|
||||
|
||||
private module Stage1 implements StageSig {
|
||||
class ApApprox = Unit;
|
||||
|
||||
class Ap = Unit;
|
||||
|
||||
private class Cc = boolean;
|
||||
class ApOption = Unit;
|
||||
|
||||
class Cc = boolean;
|
||||
|
||||
/* Begin: Stage 1 logic. */
|
||||
/**
|
||||
@@ -614,7 +613,7 @@ private module Stage1 implements StageSig {
|
||||
* The Boolean `cc` records whether the node is reached through an
|
||||
* argument in a call.
|
||||
*/
|
||||
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
sourceNode(node, _, config) and
|
||||
if hasSourceCallCtx(config) then cc = true else cc = false
|
||||
or
|
||||
@@ -754,7 +753,7 @@ private module Stage1 implements StageSig {
|
||||
* the enclosing callable in order to reach a sink.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
revFlow0(node, toReturn, config) and
|
||||
fwdFlow(node, config)
|
||||
}
|
||||
@@ -838,13 +837,13 @@ private module Stage1 implements StageSig {
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
additional predicate viableReturnPosOutNodeCandFwd1(
|
||||
predicate viableReturnPosOutNodeCandFwd1(
|
||||
DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
|
||||
) {
|
||||
fwdFlowReturnPosition(pos, _, config) and
|
||||
@@ -860,7 +859,7 @@ private module Stage1 implements StageSig {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
viableParamArgEx(call, p, arg) and
|
||||
@@ -907,7 +906,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate revFlowState(FlowState state, Configuration config) {
|
||||
predicate revFlowState(FlowState state, Configuration config) {
|
||||
exists(NodeEx node |
|
||||
sinkNode(node, state, config) and
|
||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||
@@ -999,7 +998,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate stats(
|
||||
predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -1260,7 +1259,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* argument.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate fwdFlow(
|
||||
predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, argAp, ap, config) and
|
||||
@@ -1484,7 +1483,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* the access path of the returned value.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate revFlow(
|
||||
predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow0(node, state, toReturn, returnAp, ap, config) and
|
||||
@@ -1662,7 +1661,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
revFlow(node, state, _, _, _, config)
|
||||
}
|
||||
|
||||
@@ -1675,13 +1674,11 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||
revFlow(node, _, _, _, _, config)
|
||||
}
|
||||
predicate revFlowAlias(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
additional predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
revFlow(node, state, ap, config)
|
||||
}
|
||||
|
||||
@@ -1702,7 +1699,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
}
|
||||
@@ -1744,7 +1741,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate stats(
|
||||
predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -2929,15 +2926,10 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
result = this.getASuccessorImpl()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private PathNodeImpl getANonHiddenSuccessor0() {
|
||||
result = this.getASuccessorIfHidden*() and
|
||||
not result.isHidden()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getANonHiddenSuccessor0() and
|
||||
not this.isHidden()
|
||||
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
not result.isHidden()
|
||||
}
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
@@ -163,9 +163,7 @@ abstract class Configuration extends string {
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink) {
|
||||
sink = any(PathNodeSink n | this = n.getConfiguration()).getNodeEx().asNode()
|
||||
}
|
||||
predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -560,16 +558,13 @@ private predicate expectsContentEx(NodeEx n, Content c) {
|
||||
pragma[nomagic]
|
||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate store(
|
||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||
contentType) and
|
||||
hasReadStep(tc.getContent(), config) and
|
||||
read(_, tc.getContent(), _, config) and
|
||||
stepFilter(node1, node2, config)
|
||||
}
|
||||
|
||||
@@ -603,9 +598,13 @@ private predicate hasSinkCallCtx(Configuration config) {
|
||||
}
|
||||
|
||||
private module Stage1 implements StageSig {
|
||||
class ApApprox = Unit;
|
||||
|
||||
class Ap = Unit;
|
||||
|
||||
private class Cc = boolean;
|
||||
class ApOption = Unit;
|
||||
|
||||
class Cc = boolean;
|
||||
|
||||
/* Begin: Stage 1 logic. */
|
||||
/**
|
||||
@@ -614,7 +613,7 @@ private module Stage1 implements StageSig {
|
||||
* The Boolean `cc` records whether the node is reached through an
|
||||
* argument in a call.
|
||||
*/
|
||||
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
sourceNode(node, _, config) and
|
||||
if hasSourceCallCtx(config) then cc = true else cc = false
|
||||
or
|
||||
@@ -754,7 +753,7 @@ private module Stage1 implements StageSig {
|
||||
* the enclosing callable in order to reach a sink.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
revFlow0(node, toReturn, config) and
|
||||
fwdFlow(node, config)
|
||||
}
|
||||
@@ -838,13 +837,13 @@ private module Stage1 implements StageSig {
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
additional predicate viableReturnPosOutNodeCandFwd1(
|
||||
predicate viableReturnPosOutNodeCandFwd1(
|
||||
DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
|
||||
) {
|
||||
fwdFlowReturnPosition(pos, _, config) and
|
||||
@@ -860,7 +859,7 @@ private module Stage1 implements StageSig {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
viableParamArgEx(call, p, arg) and
|
||||
@@ -907,7 +906,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate revFlowState(FlowState state, Configuration config) {
|
||||
predicate revFlowState(FlowState state, Configuration config) {
|
||||
exists(NodeEx node |
|
||||
sinkNode(node, state, config) and
|
||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||
@@ -999,7 +998,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate stats(
|
||||
predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -1260,7 +1259,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* argument.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate fwdFlow(
|
||||
predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, argAp, ap, config) and
|
||||
@@ -1484,7 +1483,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* the access path of the returned value.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate revFlow(
|
||||
predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow0(node, state, toReturn, returnAp, ap, config) and
|
||||
@@ -1662,7 +1661,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
revFlow(node, state, _, _, _, config)
|
||||
}
|
||||
|
||||
@@ -1675,13 +1674,11 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||
revFlow(node, _, _, _, _, config)
|
||||
}
|
||||
predicate revFlowAlias(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
additional predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
revFlow(node, state, ap, config)
|
||||
}
|
||||
|
||||
@@ -1702,7 +1699,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
}
|
||||
@@ -1744,7 +1741,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate stats(
|
||||
predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -2929,15 +2926,10 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
result = this.getASuccessorImpl()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private PathNodeImpl getANonHiddenSuccessor0() {
|
||||
result = this.getASuccessorIfHidden*() and
|
||||
not result.isHidden()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getANonHiddenSuccessor0() and
|
||||
not this.isHidden()
|
||||
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
not result.isHidden()
|
||||
}
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
@@ -163,9 +163,7 @@ abstract class Configuration extends string {
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink) {
|
||||
sink = any(PathNodeSink n | this = n.getConfiguration()).getNodeEx().asNode()
|
||||
}
|
||||
predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -560,16 +558,13 @@ private predicate expectsContentEx(NodeEx n, Content c) {
|
||||
pragma[nomagic]
|
||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate store(
|
||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||
contentType) and
|
||||
hasReadStep(tc.getContent(), config) and
|
||||
read(_, tc.getContent(), _, config) and
|
||||
stepFilter(node1, node2, config)
|
||||
}
|
||||
|
||||
@@ -603,9 +598,13 @@ private predicate hasSinkCallCtx(Configuration config) {
|
||||
}
|
||||
|
||||
private module Stage1 implements StageSig {
|
||||
class ApApprox = Unit;
|
||||
|
||||
class Ap = Unit;
|
||||
|
||||
private class Cc = boolean;
|
||||
class ApOption = Unit;
|
||||
|
||||
class Cc = boolean;
|
||||
|
||||
/* Begin: Stage 1 logic. */
|
||||
/**
|
||||
@@ -614,7 +613,7 @@ private module Stage1 implements StageSig {
|
||||
* The Boolean `cc` records whether the node is reached through an
|
||||
* argument in a call.
|
||||
*/
|
||||
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
sourceNode(node, _, config) and
|
||||
if hasSourceCallCtx(config) then cc = true else cc = false
|
||||
or
|
||||
@@ -754,7 +753,7 @@ private module Stage1 implements StageSig {
|
||||
* the enclosing callable in order to reach a sink.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
revFlow0(node, toReturn, config) and
|
||||
fwdFlow(node, config)
|
||||
}
|
||||
@@ -838,13 +837,13 @@ private module Stage1 implements StageSig {
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
additional predicate viableReturnPosOutNodeCandFwd1(
|
||||
predicate viableReturnPosOutNodeCandFwd1(
|
||||
DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
|
||||
) {
|
||||
fwdFlowReturnPosition(pos, _, config) and
|
||||
@@ -860,7 +859,7 @@ private module Stage1 implements StageSig {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
viableParamArgEx(call, p, arg) and
|
||||
@@ -907,7 +906,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate revFlowState(FlowState state, Configuration config) {
|
||||
predicate revFlowState(FlowState state, Configuration config) {
|
||||
exists(NodeEx node |
|
||||
sinkNode(node, state, config) and
|
||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||
@@ -999,7 +998,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate stats(
|
||||
predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -1260,7 +1259,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* argument.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate fwdFlow(
|
||||
predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, argAp, ap, config) and
|
||||
@@ -1484,7 +1483,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* the access path of the returned value.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate revFlow(
|
||||
predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow0(node, state, toReturn, returnAp, ap, config) and
|
||||
@@ -1662,7 +1661,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
revFlow(node, state, _, _, _, config)
|
||||
}
|
||||
|
||||
@@ -1675,13 +1674,11 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||
revFlow(node, _, _, _, _, config)
|
||||
}
|
||||
predicate revFlowAlias(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
additional predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
revFlow(node, state, ap, config)
|
||||
}
|
||||
|
||||
@@ -1702,7 +1699,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
}
|
||||
@@ -1744,7 +1741,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate stats(
|
||||
predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -2929,15 +2926,10 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
result = this.getASuccessorImpl()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private PathNodeImpl getANonHiddenSuccessor0() {
|
||||
result = this.getASuccessorIfHidden*() and
|
||||
not result.isHidden()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getANonHiddenSuccessor0() and
|
||||
not this.isHidden()
|
||||
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
not result.isHidden()
|
||||
}
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
@@ -163,9 +163,7 @@ abstract class Configuration extends string {
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink) {
|
||||
sink = any(PathNodeSink n | this = n.getConfiguration()).getNodeEx().asNode()
|
||||
}
|
||||
predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -560,16 +558,13 @@ private predicate expectsContentEx(NodeEx n, Content c) {
|
||||
pragma[nomagic]
|
||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate store(
|
||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||
contentType) and
|
||||
hasReadStep(tc.getContent(), config) and
|
||||
read(_, tc.getContent(), _, config) and
|
||||
stepFilter(node1, node2, config)
|
||||
}
|
||||
|
||||
@@ -603,9 +598,13 @@ private predicate hasSinkCallCtx(Configuration config) {
|
||||
}
|
||||
|
||||
private module Stage1 implements StageSig {
|
||||
class ApApprox = Unit;
|
||||
|
||||
class Ap = Unit;
|
||||
|
||||
private class Cc = boolean;
|
||||
class ApOption = Unit;
|
||||
|
||||
class Cc = boolean;
|
||||
|
||||
/* Begin: Stage 1 logic. */
|
||||
/**
|
||||
@@ -614,7 +613,7 @@ private module Stage1 implements StageSig {
|
||||
* The Boolean `cc` records whether the node is reached through an
|
||||
* argument in a call.
|
||||
*/
|
||||
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
sourceNode(node, _, config) and
|
||||
if hasSourceCallCtx(config) then cc = true else cc = false
|
||||
or
|
||||
@@ -754,7 +753,7 @@ private module Stage1 implements StageSig {
|
||||
* the enclosing callable in order to reach a sink.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
revFlow0(node, toReturn, config) and
|
||||
fwdFlow(node, config)
|
||||
}
|
||||
@@ -838,13 +837,13 @@ private module Stage1 implements StageSig {
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
additional predicate viableReturnPosOutNodeCandFwd1(
|
||||
predicate viableReturnPosOutNodeCandFwd1(
|
||||
DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
|
||||
) {
|
||||
fwdFlowReturnPosition(pos, _, config) and
|
||||
@@ -860,7 +859,7 @@ private module Stage1 implements StageSig {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
viableParamArgEx(call, p, arg) and
|
||||
@@ -907,7 +906,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate revFlowState(FlowState state, Configuration config) {
|
||||
predicate revFlowState(FlowState state, Configuration config) {
|
||||
exists(NodeEx node |
|
||||
sinkNode(node, state, config) and
|
||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||
@@ -999,7 +998,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate stats(
|
||||
predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -1260,7 +1259,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* argument.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate fwdFlow(
|
||||
predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, argAp, ap, config) and
|
||||
@@ -1484,7 +1483,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* the access path of the returned value.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate revFlow(
|
||||
predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow0(node, state, toReturn, returnAp, ap, config) and
|
||||
@@ -1662,7 +1661,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
revFlow(node, state, _, _, _, config)
|
||||
}
|
||||
|
||||
@@ -1675,13 +1674,11 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||
revFlow(node, _, _, _, _, config)
|
||||
}
|
||||
predicate revFlowAlias(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
additional predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
revFlow(node, state, ap, config)
|
||||
}
|
||||
|
||||
@@ -1702,7 +1699,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
}
|
||||
@@ -1744,7 +1741,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate stats(
|
||||
predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -2929,15 +2926,10 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
result = this.getASuccessorImpl()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private PathNodeImpl getANonHiddenSuccessor0() {
|
||||
result = this.getASuccessorIfHidden*() and
|
||||
not result.isHidden()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getANonHiddenSuccessor0() and
|
||||
not this.isHidden()
|
||||
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
not result.isHidden()
|
||||
}
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
@@ -163,9 +163,7 @@ abstract class Configuration extends string {
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink) {
|
||||
sink = any(PathNodeSink n | this = n.getConfiguration()).getNodeEx().asNode()
|
||||
}
|
||||
predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -560,16 +558,13 @@ private predicate expectsContentEx(NodeEx n, Content c) {
|
||||
pragma[nomagic]
|
||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate store(
|
||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||
contentType) and
|
||||
hasReadStep(tc.getContent(), config) and
|
||||
read(_, tc.getContent(), _, config) and
|
||||
stepFilter(node1, node2, config)
|
||||
}
|
||||
|
||||
@@ -603,9 +598,13 @@ private predicate hasSinkCallCtx(Configuration config) {
|
||||
}
|
||||
|
||||
private module Stage1 implements StageSig {
|
||||
class ApApprox = Unit;
|
||||
|
||||
class Ap = Unit;
|
||||
|
||||
private class Cc = boolean;
|
||||
class ApOption = Unit;
|
||||
|
||||
class Cc = boolean;
|
||||
|
||||
/* Begin: Stage 1 logic. */
|
||||
/**
|
||||
@@ -614,7 +613,7 @@ private module Stage1 implements StageSig {
|
||||
* The Boolean `cc` records whether the node is reached through an
|
||||
* argument in a call.
|
||||
*/
|
||||
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
sourceNode(node, _, config) and
|
||||
if hasSourceCallCtx(config) then cc = true else cc = false
|
||||
or
|
||||
@@ -754,7 +753,7 @@ private module Stage1 implements StageSig {
|
||||
* the enclosing callable in order to reach a sink.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
revFlow0(node, toReturn, config) and
|
||||
fwdFlow(node, config)
|
||||
}
|
||||
@@ -838,13 +837,13 @@ private module Stage1 implements StageSig {
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
additional predicate viableReturnPosOutNodeCandFwd1(
|
||||
predicate viableReturnPosOutNodeCandFwd1(
|
||||
DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
|
||||
) {
|
||||
fwdFlowReturnPosition(pos, _, config) and
|
||||
@@ -860,7 +859,7 @@ private module Stage1 implements StageSig {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
viableParamArgEx(call, p, arg) and
|
||||
@@ -907,7 +906,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate revFlowState(FlowState state, Configuration config) {
|
||||
predicate revFlowState(FlowState state, Configuration config) {
|
||||
exists(NodeEx node |
|
||||
sinkNode(node, state, config) and
|
||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||
@@ -999,7 +998,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate stats(
|
||||
predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -1260,7 +1259,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* argument.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate fwdFlow(
|
||||
predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, argAp, ap, config) and
|
||||
@@ -1484,7 +1483,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* the access path of the returned value.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate revFlow(
|
||||
predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow0(node, state, toReturn, returnAp, ap, config) and
|
||||
@@ -1662,7 +1661,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
revFlow(node, state, _, _, _, config)
|
||||
}
|
||||
|
||||
@@ -1675,13 +1674,11 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||
revFlow(node, _, _, _, _, config)
|
||||
}
|
||||
predicate revFlowAlias(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
additional predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
revFlow(node, state, ap, config)
|
||||
}
|
||||
|
||||
@@ -1702,7 +1699,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
}
|
||||
@@ -1744,7 +1741,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate stats(
|
||||
predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -2929,15 +2926,10 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
result = this.getASuccessorImpl()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private PathNodeImpl getANonHiddenSuccessor0() {
|
||||
result = this.getASuccessorIfHidden*() and
|
||||
not result.isHidden()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getANonHiddenSuccessor0() and
|
||||
not this.isHidden()
|
||||
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
not result.isHidden()
|
||||
}
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
@@ -163,9 +163,7 @@ abstract class Configuration extends string {
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink) {
|
||||
sink = any(PathNodeSink n | this = n.getConfiguration()).getNodeEx().asNode()
|
||||
}
|
||||
predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -560,16 +558,13 @@ private predicate expectsContentEx(NodeEx n, Content c) {
|
||||
pragma[nomagic]
|
||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate store(
|
||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||
contentType) and
|
||||
hasReadStep(tc.getContent(), config) and
|
||||
read(_, tc.getContent(), _, config) and
|
||||
stepFilter(node1, node2, config)
|
||||
}
|
||||
|
||||
@@ -603,9 +598,13 @@ private predicate hasSinkCallCtx(Configuration config) {
|
||||
}
|
||||
|
||||
private module Stage1 implements StageSig {
|
||||
class ApApprox = Unit;
|
||||
|
||||
class Ap = Unit;
|
||||
|
||||
private class Cc = boolean;
|
||||
class ApOption = Unit;
|
||||
|
||||
class Cc = boolean;
|
||||
|
||||
/* Begin: Stage 1 logic. */
|
||||
/**
|
||||
@@ -614,7 +613,7 @@ private module Stage1 implements StageSig {
|
||||
* The Boolean `cc` records whether the node is reached through an
|
||||
* argument in a call.
|
||||
*/
|
||||
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
sourceNode(node, _, config) and
|
||||
if hasSourceCallCtx(config) then cc = true else cc = false
|
||||
or
|
||||
@@ -754,7 +753,7 @@ private module Stage1 implements StageSig {
|
||||
* the enclosing callable in order to reach a sink.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
revFlow0(node, toReturn, config) and
|
||||
fwdFlow(node, config)
|
||||
}
|
||||
@@ -838,13 +837,13 @@ private module Stage1 implements StageSig {
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
additional predicate viableReturnPosOutNodeCandFwd1(
|
||||
predicate viableReturnPosOutNodeCandFwd1(
|
||||
DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
|
||||
) {
|
||||
fwdFlowReturnPosition(pos, _, config) and
|
||||
@@ -860,7 +859,7 @@ private module Stage1 implements StageSig {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
viableParamArgEx(call, p, arg) and
|
||||
@@ -907,7 +906,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate revFlowState(FlowState state, Configuration config) {
|
||||
predicate revFlowState(FlowState state, Configuration config) {
|
||||
exists(NodeEx node |
|
||||
sinkNode(node, state, config) and
|
||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||
@@ -999,7 +998,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate stats(
|
||||
predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -1260,7 +1259,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* argument.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate fwdFlow(
|
||||
predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, argAp, ap, config) and
|
||||
@@ -1484,7 +1483,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* the access path of the returned value.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
additional predicate revFlow(
|
||||
predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow0(node, state, toReturn, returnAp, ap, config) and
|
||||
@@ -1662,7 +1661,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
revFlow(node, state, _, _, _, config)
|
||||
}
|
||||
|
||||
@@ -1675,13 +1674,11 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||
revFlow(node, _, _, _, _, config)
|
||||
}
|
||||
predicate revFlowAlias(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
additional predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
revFlow(node, state, ap, config)
|
||||
}
|
||||
|
||||
@@ -1702,7 +1699,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
}
|
||||
@@ -1744,7 +1741,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate stats(
|
||||
predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -2929,15 +2926,10 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
result = this.getASuccessorImpl()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private PathNodeImpl getANonHiddenSuccessor0() {
|
||||
result = this.getASuccessorIfHidden*() and
|
||||
not result.isHidden()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getANonHiddenSuccessor0() and
|
||||
not this.isHidden()
|
||||
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
not result.isHidden()
|
||||
}
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
@@ -267,6 +267,9 @@ Instruction getSourceAddressFromNode(Node node) {
|
||||
result = getSourceAddress(node.asOperand().(SideEffectOperand).getUse())
|
||||
}
|
||||
|
||||
/** Gets the source value of `instr` if it's an instruction that behaves like a `LoadInstruction`. */
|
||||
Instruction getSourceValue(Instruction instr) { result = getSourceValueOperand(instr).getDef() }
|
||||
|
||||
/**
|
||||
* Gets the operand that represents the source value of `instr` if it's an instruction
|
||||
* that behaves like a `LoadInstruction`.
|
||||
|
||||
@@ -143,6 +143,16 @@ private module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
Instruction getRegisterOperandDefinition(Instruction instruction, RegisterOperandTag tag) {
|
||||
exists(OldInstruction oldInstruction, OldIR::RegisterOperand oldOperand |
|
||||
oldInstruction = getOldInstruction(instruction) and
|
||||
oldOperand = oldInstruction.getAnOperand() and
|
||||
tag = oldOperand.getOperandTag() and
|
||||
result = getNewInstruction(oldOperand.getAnyDef())
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noopt]
|
||||
private predicate hasMemoryOperandDefinition(
|
||||
OldInstruction oldInstruction, OldIR::NonPhiMemoryOperand oldOperand, Overlap overlap,
|
||||
|
||||
@@ -256,6 +256,12 @@ CppType getInstructionOperandType(Instruction instruction, TypedOperandTag tag)
|
||||
.getInstructionMemoryOperandType(getInstructionTag(instruction), tag)
|
||||
}
|
||||
|
||||
Instruction getPhiOperandDefinition(
|
||||
PhiInstruction instruction, IRBlock predecessorBlock, Overlap overlap
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
Instruction getPhiInstructionBlockStart(PhiInstruction instr) { none() }
|
||||
|
||||
Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
|
||||
|
||||
@@ -143,6 +143,16 @@ private module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
Instruction getRegisterOperandDefinition(Instruction instruction, RegisterOperandTag tag) {
|
||||
exists(OldInstruction oldInstruction, OldIR::RegisterOperand oldOperand |
|
||||
oldInstruction = getOldInstruction(instruction) and
|
||||
oldOperand = oldInstruction.getAnOperand() and
|
||||
tag = oldOperand.getOperandTag() and
|
||||
result = getNewInstruction(oldOperand.getAnyDef())
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noopt]
|
||||
private predicate hasMemoryOperandDefinition(
|
||||
OldInstruction oldInstruction, OldIR::NonPhiMemoryOperand oldOperand, Overlap overlap,
|
||||
|
||||
@@ -205,149 +205,57 @@ private predicate deconstructSizeExpr(Expr sizeExpr, Expr lengthExpr, int sizeof
|
||||
sizeof = 1
|
||||
}
|
||||
|
||||
/** A `Function` that is a call target of an allocation. */
|
||||
private signature class CallAllocationExprTarget extends Function;
|
||||
|
||||
/**
|
||||
* This module abstracts over the type of allocation call-targets and provides a
|
||||
* class `CallAllocationExprImpl` which contains the implementation of the various
|
||||
* predicates required by the `Allocation` class.
|
||||
*
|
||||
* This module is then instantiated for two types of allocation call-targets:
|
||||
* - `AllocationFunction`: Functions that we've explicitly modeled as functions that
|
||||
* perform allocations (i.e., `malloc`).
|
||||
* - `HeuristicAllocationFunction`: Functions that we deduce as behaving like an allocation
|
||||
* function using various heuristics.
|
||||
* An allocation expression that is a function call, such as call to `malloc`.
|
||||
*/
|
||||
private module CallAllocationExprBase<CallAllocationExprTarget Target> {
|
||||
/** A module that contains the collection of member-predicates required on `Target`. */
|
||||
signature module Param {
|
||||
/**
|
||||
* Gets the index of the input pointer argument to be reallocated, if
|
||||
* this is a `realloc` function.
|
||||
*/
|
||||
int getReallocPtrArg(Target target);
|
||||
private class CallAllocationExpr extends AllocationExpr, FunctionCall {
|
||||
AllocationFunction target;
|
||||
|
||||
/**
|
||||
* Gets the index of the argument for the allocation size, if any. The actual
|
||||
* allocation size is the value of this argument multiplied by the result of
|
||||
* `getSizeMult()`, in bytes.
|
||||
*/
|
||||
int getSizeArg(Target target);
|
||||
|
||||
/**
|
||||
* Gets the index of an argument that multiplies the allocation size given
|
||||
* by `getSizeArg`, if any.
|
||||
*/
|
||||
int getSizeMult(Target target);
|
||||
|
||||
/**
|
||||
* Holds if this allocation requires a
|
||||
* corresponding deallocation of some sort (most do, but `alloca` for example
|
||||
* does not). If it is unclear, we default to no (for example a placement `new`
|
||||
* allocation may or may not require a corresponding `delete`).
|
||||
*/
|
||||
predicate requiresDealloc(Target target);
|
||||
CallAllocationExpr() {
|
||||
target = this.getTarget() and
|
||||
// realloc(ptr, 0) only frees the pointer
|
||||
not (
|
||||
exists(target.getReallocPtrArg()) and
|
||||
this.getArgument(target.getSizeArg()).getValue().toInt() = 0
|
||||
) and
|
||||
// these are modeled directly (and more accurately), avoid duplication
|
||||
not exists(NewOrNewArrayExpr new | new.getAllocatorCall() = this)
|
||||
}
|
||||
|
||||
/**
|
||||
* A module that abstracts over a collection of predicates in
|
||||
* the `Param` module). This should really be member-predicates
|
||||
* on `CallAllocationExprTarget`, but we cannot yet write this in QL.
|
||||
*/
|
||||
module With<Param P> {
|
||||
private import P
|
||||
|
||||
/**
|
||||
* An allocation expression that is a function call, such as call to `malloc`.
|
||||
*/
|
||||
class CallAllocationExprImpl instanceof FunctionCall {
|
||||
Target target;
|
||||
|
||||
CallAllocationExprImpl() {
|
||||
target = this.getTarget() and
|
||||
// realloc(ptr, 0) only frees the pointer
|
||||
not (
|
||||
exists(getReallocPtrArg(target)) and
|
||||
this.getArgument(getSizeArg(target)).getValue().toInt() = 0
|
||||
) and
|
||||
// these are modeled directly (and more accurately), avoid duplication
|
||||
not exists(NewOrNewArrayExpr new | new.getAllocatorCall() = this)
|
||||
}
|
||||
|
||||
string toString() { result = super.toString() }
|
||||
|
||||
Expr getSizeExprImpl() {
|
||||
exists(Expr sizeExpr | sizeExpr = super.getArgument(getSizeArg(target)) |
|
||||
if exists(getSizeMult(target))
|
||||
then result = sizeExpr
|
||||
else
|
||||
exists(Expr lengthExpr |
|
||||
deconstructSizeExpr(sizeExpr, lengthExpr, _) and
|
||||
result = lengthExpr
|
||||
)
|
||||
override Expr getSizeExpr() {
|
||||
exists(Expr sizeExpr | sizeExpr = this.getArgument(target.getSizeArg()) |
|
||||
if exists(target.getSizeMult())
|
||||
then result = sizeExpr
|
||||
else
|
||||
exists(Expr lengthExpr |
|
||||
deconstructSizeExpr(sizeExpr, lengthExpr, _) and
|
||||
result = lengthExpr
|
||||
)
|
||||
}
|
||||
|
||||
int getSizeMultImpl() {
|
||||
// malloc with multiplier argument that is a constant
|
||||
result = super.getArgument(getSizeMult(target)).getValue().toInt()
|
||||
or
|
||||
// malloc with no multiplier argument
|
||||
not exists(getSizeMult(target)) and
|
||||
deconstructSizeExpr(super.getArgument(getSizeArg(target)), _, result)
|
||||
}
|
||||
|
||||
int getSizeBytesImpl() {
|
||||
result = this.getSizeExprImpl().getValue().toInt() * this.getSizeMultImpl()
|
||||
}
|
||||
|
||||
Expr getReallocPtrImpl() { result = super.getArgument(getReallocPtrArg(target)) }
|
||||
|
||||
Type getAllocatedElementTypeImpl() {
|
||||
result =
|
||||
super.getFullyConverted().getType().stripTopLevelSpecifiers().(PointerType).getBaseType() and
|
||||
not result instanceof VoidType
|
||||
}
|
||||
|
||||
predicate requiresDeallocImpl() { requiresDealloc(target) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private module CallAllocationExpr {
|
||||
private module Param implements CallAllocationExprBase<AllocationFunction>::Param {
|
||||
int getReallocPtrArg(AllocationFunction f) { result = f.getReallocPtrArg() }
|
||||
|
||||
int getSizeArg(AllocationFunction f) { result = f.getSizeArg() }
|
||||
|
||||
int getSizeMult(AllocationFunction f) { result = f.getSizeMult() }
|
||||
|
||||
predicate requiresDealloc(AllocationFunction f) { f.requiresDealloc() }
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A class that provides the implementation of `AllocationExpr` for an allocation
|
||||
* that calls an `AllocationFunction`.
|
||||
*/
|
||||
private class Base =
|
||||
CallAllocationExprBase<AllocationFunction>::With<Param>::CallAllocationExprImpl;
|
||||
|
||||
class CallAllocationExpr extends AllocationExpr, Base {
|
||||
override Expr getSizeExpr() { result = super.getSizeExprImpl() }
|
||||
|
||||
override int getSizeMult() { result = super.getSizeMultImpl() }
|
||||
|
||||
override Type getAllocatedElementType() { result = super.getAllocatedElementTypeImpl() }
|
||||
|
||||
override predicate requiresDealloc() { super.requiresDeallocImpl() }
|
||||
|
||||
override int getSizeBytes() { result = super.getSizeBytesImpl() }
|
||||
|
||||
override Expr getReallocPtr() { result = super.getReallocPtrImpl() }
|
||||
|
||||
override string toString() { result = AllocationExpr.super.toString() }
|
||||
override int getSizeMult() {
|
||||
// malloc with multiplier argument that is a constant
|
||||
result = this.getArgument(target.getSizeMult()).getValue().toInt()
|
||||
or
|
||||
// malloc with no multiplier argument
|
||||
not exists(target.getSizeMult()) and
|
||||
deconstructSizeExpr(this.getArgument(target.getSizeArg()), _, result)
|
||||
}
|
||||
|
||||
override int getSizeBytes() {
|
||||
result = this.getSizeExpr().getValue().toInt() * this.getSizeMult()
|
||||
}
|
||||
|
||||
override Expr getReallocPtr() { result = this.getArgument(target.getReallocPtrArg()) }
|
||||
|
||||
override Type getAllocatedElementType() {
|
||||
result =
|
||||
this.getFullyConverted().getType().stripTopLevelSpecifiers().(PointerType).getBaseType() and
|
||||
not result instanceof VoidType
|
||||
}
|
||||
|
||||
override predicate requiresDealloc() { target.requiresDealloc() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -386,99 +294,3 @@ private class NewArrayAllocationExpr extends AllocationExpr, NewArrayExpr {
|
||||
|
||||
override predicate requiresDealloc() { not exists(this.getPlacementPointer()) }
|
||||
}
|
||||
|
||||
private module HeuristicAllocation {
|
||||
/** A class that maps an `AllocationExpr` to an `HeuristicAllocationExpr`. */
|
||||
private class HeuristicAllocationModeled extends HeuristicAllocationExpr instanceof AllocationExpr {
|
||||
override Expr getSizeExpr() { result = AllocationExpr.super.getSizeExpr() }
|
||||
|
||||
override int getSizeMult() { result = AllocationExpr.super.getSizeMult() }
|
||||
|
||||
override int getSizeBytes() { result = AllocationExpr.super.getSizeBytes() }
|
||||
|
||||
override Expr getReallocPtr() { result = AllocationExpr.super.getReallocPtr() }
|
||||
|
||||
override Type getAllocatedElementType() {
|
||||
result = AllocationExpr.super.getAllocatedElementType()
|
||||
}
|
||||
|
||||
override predicate requiresDealloc() { AllocationExpr.super.requiresDealloc() }
|
||||
}
|
||||
|
||||
/** A class that maps an `AllocationFunction` to an `HeuristicAllocationFunction`. */
|
||||
private class HeuristicAllocationFunctionModeled extends HeuristicAllocationFunction instanceof AllocationFunction {
|
||||
override int getSizeArg() { result = AllocationFunction.super.getSizeArg() }
|
||||
|
||||
override int getSizeMult() { result = AllocationFunction.super.getSizeMult() }
|
||||
|
||||
override int getReallocPtrArg() { result = AllocationFunction.super.getReallocPtrArg() }
|
||||
|
||||
override predicate requiresDealloc() { AllocationFunction.super.requiresDealloc() }
|
||||
}
|
||||
|
||||
private int getAnUnsignedParameter(Function f) {
|
||||
f.getParameter(result).getUnspecifiedType().(IntegralType).isUnsigned()
|
||||
}
|
||||
|
||||
private int getAPointerParameter(Function f) {
|
||||
f.getParameter(result).getUnspecifiedType() instanceof PointerType
|
||||
}
|
||||
|
||||
/**
|
||||
* A class that uses heuristics to find additional allocation functions. The required are as follows:
|
||||
* 1. The word `alloc` must appear in the function name
|
||||
* 2. The function must return a pointer type
|
||||
* 3. There must be a unique parameter of unsigned integral type.
|
||||
*/
|
||||
private class HeuristicAllocationFunctionByName extends HeuristicAllocationFunction instanceof Function {
|
||||
int sizeArg;
|
||||
|
||||
HeuristicAllocationFunctionByName() {
|
||||
Function.super.getName().matches("%alloc%") and
|
||||
Function.super.getUnspecifiedType() instanceof PointerType and
|
||||
sizeArg = unique( | | getAnUnsignedParameter(this))
|
||||
}
|
||||
|
||||
override int getSizeArg() { result = sizeArg }
|
||||
|
||||
override int getReallocPtrArg() {
|
||||
Function.super.getName().matches("%realloc%") and
|
||||
result = unique( | | getAPointerParameter(this))
|
||||
}
|
||||
|
||||
override predicate requiresDealloc() { none() }
|
||||
}
|
||||
|
||||
private module Param implements CallAllocationExprBase<HeuristicAllocationFunction>::Param {
|
||||
int getReallocPtrArg(HeuristicAllocationFunction f) { result = f.getReallocPtrArg() }
|
||||
|
||||
int getSizeArg(HeuristicAllocationFunction f) { result = f.getSizeArg() }
|
||||
|
||||
int getSizeMult(HeuristicAllocationFunction f) { result = f.getSizeMult() }
|
||||
|
||||
predicate requiresDealloc(HeuristicAllocationFunction f) { f.requiresDealloc() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A class that provides the implementation of `AllocationExpr` for an allocation
|
||||
* that calls an `HeuristicAllocationFunction`.
|
||||
*/
|
||||
private class Base =
|
||||
CallAllocationExprBase<HeuristicAllocationFunction>::With<Param>::CallAllocationExprImpl;
|
||||
|
||||
private class CallAllocationExpr extends HeuristicAllocationExpr, Base {
|
||||
override Expr getSizeExpr() { result = super.getSizeExprImpl() }
|
||||
|
||||
override int getSizeMult() { result = super.getSizeMultImpl() }
|
||||
|
||||
override Type getAllocatedElementType() { result = super.getAllocatedElementTypeImpl() }
|
||||
|
||||
override predicate requiresDealloc() { super.requiresDeallocImpl() }
|
||||
|
||||
override int getSizeBytes() { result = super.getSizeBytesImpl() }
|
||||
|
||||
override Expr getReallocPtr() { result = super.getReallocPtrImpl() }
|
||||
|
||||
override string toString() { result = HeuristicAllocationExpr.super.toString() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,84 +113,3 @@ class OperatorNewAllocationFunction extends AllocationFunction {
|
||||
result = 1
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An expression that _might_ allocate memory.
|
||||
*
|
||||
* Unlike `AllocationExpr`, this class uses heuristics (such as a call target's
|
||||
* name and parameters) to include additional expressions.
|
||||
*/
|
||||
abstract class HeuristicAllocationExpr extends Expr {
|
||||
/**
|
||||
* Gets an expression for the allocation size, if any. The actual allocation
|
||||
* size is the value of this expression multiplied by the result of
|
||||
* `getSizeMult()`, in bytes.
|
||||
*/
|
||||
Expr getSizeExpr() { none() }
|
||||
|
||||
/**
|
||||
* Gets a constant multiplier for the allocation size given by `getSizeExpr`,
|
||||
* in bytes.
|
||||
*/
|
||||
int getSizeMult() { none() }
|
||||
|
||||
/**
|
||||
* Gets the size of this allocation in bytes, if it is a fixed size and that
|
||||
* size can be determined.
|
||||
*/
|
||||
int getSizeBytes() { none() }
|
||||
|
||||
/**
|
||||
* Gets the expression for the input pointer argument to be reallocated, if
|
||||
* this is a `realloc` function.
|
||||
*/
|
||||
Expr getReallocPtr() { none() }
|
||||
|
||||
/**
|
||||
* Gets the type of the elements that are allocated, if it can be determined.
|
||||
*/
|
||||
Type getAllocatedElementType() { none() }
|
||||
|
||||
/**
|
||||
* Whether or not this allocation requires a corresponding deallocation of
|
||||
* some sort (most do, but `alloca` for example does not). If it is unclear,
|
||||
* we default to no (for example a placement `new` allocation may or may not
|
||||
* require a corresponding `delete`).
|
||||
*/
|
||||
predicate requiresDealloc() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An function that _might_ allocate memory.
|
||||
*
|
||||
* Unlike `AllocationFunction`, this class uses heuristics (such as the function's
|
||||
* name and its parameters) to include additional functions.
|
||||
*/
|
||||
abstract class HeuristicAllocationFunction extends Function {
|
||||
/**
|
||||
* Gets the index of the argument for the allocation size, if any. The actual
|
||||
* allocation size is the value of this argument multiplied by the result of
|
||||
* `getSizeMult()`, in bytes.
|
||||
*/
|
||||
int getSizeArg() { none() }
|
||||
|
||||
/**
|
||||
* Gets the index of an argument that multiplies the allocation size given by
|
||||
* `getSizeArg`, if any.
|
||||
*/
|
||||
int getSizeMult() { none() }
|
||||
|
||||
/**
|
||||
* Gets the index of the input pointer argument to be reallocated, if this
|
||||
* is a `realloc` function.
|
||||
*/
|
||||
int getReallocPtrArg() { none() }
|
||||
|
||||
/**
|
||||
* Whether or not this allocation requires a corresponding deallocation of
|
||||
* some sort (most do, but `alloca` for example does not). If it is unclear,
|
||||
* we default to no (for example a placement `new` allocation may or may not
|
||||
* require a corresponding `delete`).
|
||||
*/
|
||||
predicate requiresDealloc() { any() }
|
||||
}
|
||||
|
||||
@@ -15,4 +15,4 @@ where
|
||||
c.fromSource() and
|
||||
c.isTopLevel() and
|
||||
c.getParentScope() instanceof GlobalNamespace
|
||||
select c, "This class is not declared in any namespace."
|
||||
select c, "This class is not declared in any namespace"
|
||||
|
||||
@@ -16,4 +16,4 @@ where
|
||||
t.fromSource() and
|
||||
n = t.getMetrics().getEfferentSourceCoupling() and
|
||||
n > 10
|
||||
select t as class_, "This class has too many dependencies (" + n.toString() + ")."
|
||||
select t as class_, "This class has too many dependencies (" + n.toString() + ")"
|
||||
|
||||
@@ -17,4 +17,4 @@ where
|
||||
n = f.getMetrics().getNumberOfCalls() and
|
||||
n > 99 and
|
||||
not f.isMultiplyDefined()
|
||||
select f as function, "This function makes too many calls (" + n.toString() + ")."
|
||||
select f as function, "This function makes too many calls (" + n.toString() + ")"
|
||||
|
||||
@@ -18,4 +18,4 @@ where
|
||||
f.getMetrics().getNumberOfParameters() > 15
|
||||
select f,
|
||||
"This function has too many parameters (" + f.getMetrics().getNumberOfParameters().toString() +
|
||||
")."
|
||||
")"
|
||||
|
||||
@@ -35,4 +35,4 @@ from LocalVariableOrParameter lv, GlobalVariable gv
|
||||
where
|
||||
lv.getName() = gv.getName() and
|
||||
lv.getFile() = gv.getFile()
|
||||
select lv, lv.type() + gv.getName() + " hides a $@ with the same name.", gv, "global variable"
|
||||
select lv, lv.type() + gv.getName() + " hides $@ with the same name.", gv, "a global variable"
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* In this example, the developer intended to use a semicolon but accidentally used a comma:
|
||||
*/
|
||||
|
||||
enum privileges entitlements = NONE;
|
||||
|
||||
if (is_admin)
|
||||
entitlements = FULL, // BAD
|
||||
|
||||
restrict_privileges(entitlements);
|
||||
|
||||
/*
|
||||
* The use of a comma means that the first example is equivalent to this second example:
|
||||
*/
|
||||
|
||||
enum privileges entitlements = NONE;
|
||||
|
||||
if (is_admin) {
|
||||
entitlements = FULL;
|
||||
restrict_privileges(entitlements);
|
||||
}
|
||||
|
||||
/*
|
||||
* The indentation of the first example suggests that the developer probably intended the following code:
|
||||
*/
|
||||
|
||||
enum privileges entitlements = NONE;
|
||||
|
||||
if (is_admin)
|
||||
entitlements = FULL; // GOOD
|
||||
|
||||
restrict_privileges(entitlements);
|
||||
@@ -1,39 +0,0 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>
|
||||
If the expression after the comma operator starts at an earlier column than the expression before the comma, then
|
||||
this suspicious indentation possibly indicates a logic error, caused by a typo that may escape visual inspection.
|
||||
</p>
|
||||
<warning>
|
||||
This query has medium precision because CodeQL currently does not distinguish between tabs and spaces in whitespace.
|
||||
If a file contains mixed tabs and spaces, alerts may highlight code that is correctly indented for one value of tab size but not for other tab sizes.
|
||||
</warning>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>
|
||||
To ensure that your code is easy to read and review, use standard indentation around the comma operator. Always begin the right-hand-side operand at the same level of
|
||||
indentation (column number) as the left-hand-side operand. This makes it easier for other developers to see the intended behavior of your code.
|
||||
</p>
|
||||
<p>
|
||||
Use whitespace consistently to communicate your coding intentions. Where possible, avoid mixing tabs and spaces within a file. If you need to mix them, use them consistently.
|
||||
</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>
|
||||
This example shows three different ways of writing the same code. The first example contains a comma instead of a semicolon which means that the final line is part of the <code>if</code> statement, even though the indentation suggests that it is intended to be separate. The second example looks different but is functionally the same as the first example. It is more likely that the developer intended to write the third example.
|
||||
</p>
|
||||
<sample src="CommaBeforeMisleadingIndentation.cpp" />
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>Wikipedia: <a href="https://en.wikipedia.org/wiki/Comma_operator">Comma operator</a></li>
|
||||
<li>Wikipedia: <a href="https://en.wikipedia.org/wiki/Indentation_style#Tabs,_spaces,_and_size_of_indentations">Indentation style — Tabs, spaces, and size of indentations</a></li>
|
||||
</references>
|
||||
|
||||
</qhelp>
|
||||
@@ -1,53 +0,0 @@
|
||||
/**
|
||||
* @name Comma before misleading indentation
|
||||
* @description If expressions before and after a comma operator use different indentation, it is easy to misread the purpose of the code.
|
||||
* @kind problem
|
||||
* @id cpp/comma-before-misleading-indentation
|
||||
* @problem.severity warning
|
||||
* @security-severity 7.8
|
||||
* @precision medium
|
||||
* @tags maintainability
|
||||
* readability
|
||||
* security
|
||||
* external/cwe/cwe-1078
|
||||
* external/cwe/cwe-670
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.commons.Exclusions
|
||||
|
||||
/** Gets the sub-expression of 'e' with the earliest-starting Location */
|
||||
Expr normalizeExpr(Expr e) {
|
||||
result =
|
||||
min(Expr child |
|
||||
child.getParentWithConversions*() = e.getFullyConverted() and
|
||||
not child.getParentWithConversions*() = any(Call c).getAnArgument()
|
||||
|
|
||||
child order by child.getLocation().getStartColumn(), count(child.getParentWithConversions*())
|
||||
)
|
||||
}
|
||||
|
||||
predicate isParenthesized(CommaExpr ce) {
|
||||
ce.getParent*().(Expr).isParenthesised()
|
||||
or
|
||||
ce.isUnevaluated() // sizeof(), decltype(), alignof(), noexcept(), typeid()
|
||||
or
|
||||
ce.getParent*() = [any(IfStmt i).getCondition(), any(SwitchStmt s).getExpr()]
|
||||
or
|
||||
ce.getParent*() = [any(Loop l).getCondition(), any(ForStmt f).getUpdate()]
|
||||
or
|
||||
ce.getEnclosingStmt() = any(ForStmt f).getInitialization()
|
||||
}
|
||||
|
||||
from CommaExpr ce, Expr left, Expr right, Location leftLoc, Location rightLoc
|
||||
where
|
||||
ce.fromSource() and
|
||||
not isFromMacroDefinition(ce) and
|
||||
left = normalizeExpr(ce.getLeftOperand()) and
|
||||
right = normalizeExpr(ce.getRightOperand()) and
|
||||
leftLoc = left.getLocation() and
|
||||
rightLoc = right.getLocation() and
|
||||
not isParenthesized(ce) and
|
||||
leftLoc.getEndLine() < rightLoc.getStartLine() and
|
||||
leftLoc.getStartColumn() > rightLoc.getStartColumn()
|
||||
select right, "The indentation level may be misleading for some tab sizes."
|
||||
@@ -21,5 +21,5 @@ where
|
||||
rhsType.getAMember() = m and
|
||||
not m.(VirtualFunction).isPure()
|
||||
) // add additional checks for concrete members in in-between supertypes
|
||||
select e, "This assignment expression slices from type $@ to $@.", rhsType, rhsType.getName(),
|
||||
select e, "This assignment expression slices from type $@ to $@", rhsType, rhsType.getName(),
|
||||
lhsType, lhsType.getName()
|
||||
|
||||
@@ -72,6 +72,18 @@ predicate floatTrivial(Literal lit) {
|
||||
|
||||
predicate charLiteral(Literal lit) { lit instanceof CharLiteral }
|
||||
|
||||
Type literalType(Literal literal) { result = literal.getType() }
|
||||
|
||||
predicate stringType(DerivedType t) {
|
||||
t.getBaseType() instanceof CharType
|
||||
or
|
||||
exists(SpecifiedType constCharType |
|
||||
t.getBaseType() = constCharType and
|
||||
constCharType.isConst() and
|
||||
constCharType.getBaseType() instanceof CharType
|
||||
)
|
||||
}
|
||||
|
||||
predicate numberType(Type t) { t instanceof FloatingPointType or t instanceof IntegralType }
|
||||
|
||||
predicate stringLiteral(Literal literal) { literal instanceof StringLiteral }
|
||||
|
||||
@@ -18,4 +18,4 @@ where
|
||||
f.hasSpecifier("virtual") and
|
||||
f.getFile().fromSource() and
|
||||
not f instanceof Destructor
|
||||
select f, "Avoid having public virtual methods (NVI idiom)."
|
||||
select f, "Avoid having public virtual methods (NVI idiom)"
|
||||
|
||||
@@ -23,4 +23,4 @@ where
|
||||
fclass = f.getDeclaringType() and
|
||||
hubIndex = fclass.getMetrics().getAfferentCoupling() * fclass.getMetrics().getEfferentCoupling() and
|
||||
hubIndex > 100
|
||||
select f, "Avoid having public virtual methods (NVI idiom)."
|
||||
select f, "Avoid having public virtual methods (NVI idiom)"
|
||||
|
||||
@@ -38,5 +38,5 @@ where
|
||||
sc = switch.getASwitchCase() and
|
||||
tooLong(sc) and
|
||||
switchCaseLength(sc, lines)
|
||||
select switch, "Switch has at least one case that is too long: $@.", sc,
|
||||
select switch, "Switch has at least one case that is too long: $@", sc,
|
||||
sc.getExpr().toString() + " (" + lines.toString() + " lines)"
|
||||
|
||||
@@ -58,4 +58,4 @@ where
|
||||
not exists(AsmStmt s | f = s.getEnclosingFunction()) and
|
||||
not v.getAnAttribute().getName() = "unused" and
|
||||
not any(ErrorExpr e).getEnclosingFunction() = f // unextracted expr may use `v`
|
||||
select v, "Variable " + v.getName() + " is not used."
|
||||
select v, "Variable " + v.getName() + " is not used"
|
||||
|
||||
@@ -11,7 +11,7 @@ caused by an unhandled case.</p>
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
<p>Check that the unused static variable does not indicate a defect, for example, an unhandled case. If the static variable is genuinely not needed,
|
||||
<p>Check that the unused static variable does not indicate a defect, for example, an unhandled case. If the static variable is genuinuely not needed,
|
||||
then removing it will make code more readable. If the static variable is needed then you should update the code to fix the defect.</p>
|
||||
|
||||
</recommendation>
|
||||
|
||||
@@ -27,4 +27,4 @@ where
|
||||
not declarationHasSideEffects(v) and
|
||||
not v.getAnAttribute().hasName("used") and
|
||||
not v.getAnAttribute().hasName("unused")
|
||||
select v, "Static variable " + v.getName() + " is never read."
|
||||
select v, "Static variable " + v.getName() + " is never read"
|
||||
|
||||
@@ -1,20 +1,3 @@
|
||||
## 0.4.1
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The alert message of many queries have been changed to better follow the style guide and make the message consistent with other languages.
|
||||
|
||||
## 0.4.0
|
||||
|
||||
### New Queries
|
||||
|
||||
* Added a new medium-precision query, `cpp/missing-check-scanf`, which detects `scanf` output variables that are used without a proper return-value check to see that they were actually written. A variation of this query was originally contributed as an [experimental query by @ihsinme](https://github.com/github/codeql/pull/8246).
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Modernizations from "Cleartext storage of sensitive information in buffer" (`cpp/cleartext-storage-buffer`) have been ported to the "Cleartext storage of sensitive information in file" (`cpp/cleartext-storage-file`), "Cleartext transmission of sensitive information" (`cpp/cleartext-transmission`) and "Cleartext storage of sensitive information in an SQLite database" (`cpp/cleartext-storage-database`) queries. These changes may result in more correct results and fewer false positive results from these queries.
|
||||
* The alert message of many queries have been changed to make the message consistent with other languages.
|
||||
|
||||
## 0.3.4
|
||||
|
||||
## 0.3.3
|
||||
|
||||
@@ -64,5 +64,5 @@ where
|
||||
) and
|
||||
(if context = test then testresult = "succeed" else testresult = "fail")
|
||||
select cond,
|
||||
"Variable '" + v.getName() + "' is always " + context + ", this check will always " + testresult +
|
||||
"."
|
||||
"Variable '" + v.getName() + "' is always " + context + " here, this check will always " +
|
||||
testresult + "."
|
||||
|
||||
@@ -19,7 +19,7 @@ This can occur when an operation performed on the open descriptor fails, and the
|
||||
|
||||
<example>
|
||||
<p>In the example below, the <code>sockfd</code> socket may remain open if an error is triggered.
|
||||
The code should be updated to ensure that the socket is always closed when the function ends.
|
||||
The code should be updated to ensure that the socket is always closed when when the function ends.
|
||||
</p>
|
||||
<sample src="DescriptorMayNotBeClosed.cpp" />
|
||||
</example>
|
||||
|
||||
@@ -29,4 +29,4 @@ from Expr alloc
|
||||
where
|
||||
allocateDescriptorCall(alloc) and
|
||||
not exists(ClosedExpr closed | closed.pointsTo() = alloc)
|
||||
select alloc, "This file descriptor is never closed."
|
||||
select alloc, "This file descriptor is never closed"
|
||||
|
||||
@@ -164,4 +164,4 @@ where
|
||||
fopenVariableReaches(v, def, ret) and
|
||||
ret.getAChild*() = v.getAnAccess()
|
||||
)
|
||||
select def, "This file may not be closed at $@.", ret, "this exit point"
|
||||
select def, "The file opened here may not be closed at $@.", ret, "this exit point"
|
||||
|
||||
@@ -14,4 +14,4 @@ import FileClosed
|
||||
|
||||
from Expr alloc
|
||||
where fopenCall(alloc) and not fopenCallMayBeClosed(alloc)
|
||||
select alloc, "The file is never closed."
|
||||
select alloc, "The file is never closed"
|
||||
|
||||
@@ -27,4 +27,4 @@ where
|
||||
definitionUsePair(v, other, unchecked)
|
||||
)
|
||||
select unchecked,
|
||||
"This dereference is not guarded by a non-null check, whereas other dereferences are guarded."
|
||||
"This dereference is not guarded by a non-null check, whereas other dereferences are guarded"
|
||||
|
||||
@@ -49,4 +49,4 @@ where
|
||||
select dangerous,
|
||||
"Variable '" + v.getName() +
|
||||
"' is used as an array-offset before it is tested for being negative (test on line " +
|
||||
check.getLocation().getStartLine().toString() + ")."
|
||||
check.getLocation().getStartLine().toString() + "). "
|
||||
|
||||
@@ -190,4 +190,4 @@ where
|
||||
allocatedVariableReaches(v, def, ret) and
|
||||
ret.getAChild*() = v.getAnAccess()
|
||||
)
|
||||
select def, "This memory allocation may not be released at $@.", ret, "this exit point"
|
||||
select def, "The memory allocated here may not be released at $@.", ret, "this exit point"
|
||||
|
||||
@@ -16,4 +16,4 @@ from AllocationExpr alloc
|
||||
where
|
||||
alloc.requiresDealloc() and
|
||||
not allocMayBeFreed(alloc)
|
||||
select alloc, "This memory is never freed."
|
||||
select alloc, "This memory is never freed"
|
||||
|
||||
@@ -117,6 +117,6 @@ where
|
||||
output.getCall() = call and
|
||||
output.hasGuardedAccess(access, false)
|
||||
select access,
|
||||
"This variable is read, but may not have been written. " +
|
||||
"$@ is read here, but may not have been written. " +
|
||||
"It should be guarded by a check that the $@ returns at least " +
|
||||
output.getMinimumGuardConstant() + ".", call, call.toString()
|
||||
output.getMinimumGuardConstant() + ".", access, access.toString(), call, call.toString()
|
||||
|
||||
@@ -14,4 +14,4 @@ from Expr alloc, Expr free, Expr freed
|
||||
where
|
||||
allocReaches(freed, alloc, "new[]") and
|
||||
freeExprOrIndirect(free, freed, "delete")
|
||||
select free, "This memory may have been allocated with $@, not 'new'.", alloc, "new[]"
|
||||
select free, "This memory may have been allocated with '$@', not 'new'.", alloc, "new[]"
|
||||
|
||||
@@ -14,4 +14,4 @@ from Expr alloc, Expr free, Expr freed
|
||||
where
|
||||
allocReaches(freed, alloc, "new") and
|
||||
freeExprOrIndirect(free, freed, "delete[]")
|
||||
select free, "This memory may have been allocated with $@, not 'new[]'.", alloc, "new"
|
||||
select free, "This memory may have been allocated with '$@', not 'new[]'.", alloc, "new"
|
||||
|
||||
@@ -30,4 +30,4 @@ where
|
||||
not v.getType().getUnderlyingType() instanceof ReferenceType and
|
||||
not exists(ScopeUtilityClass util | def = util.getAUse()) and
|
||||
not def.isInMacroExpansion()
|
||||
select def, "Variable '" + v.getName() + "' is assigned a value that is never used."
|
||||
select def, "Variable '" + v.getName() + "' is assigned a value that is never used"
|
||||
|
||||
@@ -62,5 +62,5 @@ class UseAfterFreeReachability extends StackVariableReachability {
|
||||
|
||||
from UseAfterFreeReachability r, StackVariable v, Expr free, Expr e
|
||||
where r.reaches(free, v, e)
|
||||
select e, "Memory pointed to by '" + v.getName().toString() + "' may have $@.", free,
|
||||
"been previously freed"
|
||||
select e, "Memory pointed to by '" + v.getName().toString() + "' may have been previously freed $@",
|
||||
free, "here"
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
* @description Lists all files in the source code directory that were extracted without encountering a problem in the file.
|
||||
* @kind diagnostic
|
||||
* @id cpp/diagnostics/successfully-extracted-files
|
||||
* @tags successfully-extracted-files
|
||||
*/
|
||||
|
||||
import cpp
|
||||
@@ -13,4 +12,4 @@ from File f
|
||||
where
|
||||
not exists(ExtractionProblem e | e.getFile() = f) and
|
||||
exists(f.getRelativePath())
|
||||
select f, "File successfully extracted."
|
||||
select f, "File successfully extracted"
|
||||
|
||||
@@ -15,7 +15,7 @@ As an exception, because their purpose is usually obvious, it is not necessary t
|
||||
</overview>
|
||||
<recommendation>
|
||||
<p>
|
||||
Add comments to document the purpose of the function. In particular, ensure that the public API of the function is carefully documented. This reduces the chance that a future change to the function will introduce a defect by changing the API and breaking the expectations of the calling functions.
|
||||
Add comments to document the purpose of the function. In particular, ensure that the public API of the function is carefully documented. This reduces the chance that a future change to the function will introduce a defect by changing the API and breaking the expections of the calling functions.
|
||||
</p>
|
||||
|
||||
</recommendation>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
<overview>
|
||||
<p>
|
||||
This rule finds comparison expressions that use 2 or more comparison operators and are not completely parenthesized.
|
||||
This rule finds comparison expressions that use 2 or more comparison operators and are not completely paranthesized.
|
||||
It is best to fully parenthesize complex comparison expressions to explicitly define the order of the comparison operators.
|
||||
</p>
|
||||
|
||||
|
||||
@@ -22,4 +22,4 @@ where
|
||||
not overflowTest(cmp) and
|
||||
not cmp.isFromTemplateInstantiation(_) and
|
||||
not isFromMacroDefinition(cmp)
|
||||
select cmp, "This expression compares an $@ to itself.", cmp.getLeftOperand(), "expression"
|
||||
select cmp, "Self comparison."
|
||||
|
||||
@@ -25,11 +25,8 @@ class CastToPointerArithFlow extends DataFlow::Configuration {
|
||||
|
||||
override predicate isSource(DataFlow::Node node) {
|
||||
not node.asExpr() instanceof Conversion and
|
||||
exists(Type baseType1, Type baseType2 |
|
||||
hasBaseType(node.asExpr(), baseType1) and
|
||||
hasBaseType(node.asExpr().getConversion*(), baseType2) and
|
||||
introducesNewField(baseType1, baseType2)
|
||||
)
|
||||
introducesNewField(node.asExpr().getType().(DerivedType).getBaseType(),
|
||||
node.asExpr().getConversion*().getType().(DerivedType).getBaseType())
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node node) {
|
||||
@@ -38,17 +35,6 @@ class CastToPointerArithFlow extends DataFlow::Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the type of `e` is a `DerivedType` with `base` as its base type.
|
||||
*
|
||||
* This predicate ensures that joins go from `e` to `base` instead
|
||||
* of the other way around.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate hasBaseType(Expr e, Type base) {
|
||||
pragma[only_bind_into](base) = e.getType().(DerivedType).getBaseType()
|
||||
}
|
||||
|
||||
/**
|
||||
* `derived` has a (possibly indirect) base class of `base`, and at least one new
|
||||
* field has been introduced in the inheritance chain after `base`.
|
||||
@@ -69,5 +55,5 @@ where
|
||||
cfg.hasFlowPath(source, sink) and
|
||||
source.getNode().asExpr().getFullyConverted().getUnspecifiedType() =
|
||||
sink.getNode().asExpr().getFullyConverted().getUnspecifiedType()
|
||||
select sink, source, sink, "This pointer arithmetic may be done with the wrong type because of $@.",
|
||||
source, "this cast"
|
||||
select sink, source, sink,
|
||||
"Pointer arithmetic here may be done with the wrong type because of the cast $@.", source, "here"
|
||||
|
||||
@@ -24,4 +24,4 @@ where
|
||||
va.getExplicitlyConverted().getType().getSize() > fct.getSize() and
|
||||
va.getTarget() = fi and
|
||||
not fct.getUnspecifiedType() instanceof BoolType
|
||||
select va, "Implicit downcast of bitfield $@.", fi, fi.toString()
|
||||
select va, "Implicit downcast of bitfield $@", fi, fi.toString()
|
||||
|
||||
@@ -49,4 +49,5 @@ where
|
||||
c.hasImplicitConversion() and
|
||||
not whiteListWrapped(c)
|
||||
select c,
|
||||
"Return value of type " + t1.toString() + " is implicitly converted to " + t2.toString() + "."
|
||||
"Return value of type " + t1.toString() + " is implicitly converted to " + t2.toString() +
|
||||
" here."
|
||||
|
||||
@@ -173,4 +173,4 @@ where
|
||||
not actual.getUnspecifiedType() instanceof ErroneousType
|
||||
select arg,
|
||||
"This argument should be of type '" + expected.getName() + "' but is of type '" +
|
||||
actual.getUnspecifiedType().getName() + "'."
|
||||
actual.getUnspecifiedType().getName() + "'"
|
||||
|
||||
@@ -17,5 +17,5 @@ import LeapYear
|
||||
from Expr source, Expr sink, PossibleYearArithmeticOperationCheckConfiguration config
|
||||
where config.hasFlow(DataFlow::exprNode(source), DataFlow::exprNode(sink))
|
||||
select sink,
|
||||
"An arithmetic operation $@ that uses a constant value of 365 ends up modifying this date/time, without considering leap year scenarios.",
|
||||
source, source.toString()
|
||||
"This arithmetic operation $@ uses a constant value of 365 ends up modifying the date/time located at $@, without considering leap year scenarios.",
|
||||
source, source.toString(), sink, sink.toString()
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
<overview>
|
||||
<p>This rule finds logical-not operator usage as an operator for in a bit-wise operation.</p>
|
||||
|
||||
<p>Due to the nature of logical operation result value, only the lowest bit could possibly be set, and it is unlikely to be intent in bitwise operations. Violations are often indicative of a typo, using a logical-not (<code>!</code>) operator instead of the bit-wise not (<code>~</code>) operator. </p>
|
||||
<p>Due to the nature of logical operation result value, only the lowest bit could possibly be set, and it is unlikely to be intent in bitwise opeartions. Violations are often indicative of a typo, using a logical-not (<code>!</code>) opeartor instead of the bit-wise not (<code>~</code>) operator. </p>
|
||||
<p>This rule is restricted to analyze bit-wise and (<code>&</code>) and bit-wise or (<code>|</code>) operation in order to provide better precision.</p>
|
||||
<p>This rule ignores instances where a double negation (<code>!!</code>) is explicitly used as the operator of the bitwise operation, as this is a commonly used as a mechanism to normalize an integer value to either 1 or 0.</p>
|
||||
<p>This rule ignores instances where a double negation (<code>!!</code>) is explicitly used as the opeartor of the bitwise operation, as this is a commonly used as a mechanism to normalize an integer value to either 1 or 0.</p>
|
||||
<p>NOTE: It is not recommended to use this rule in kernel code or older C code as it will likely find several false positive instances.</p>
|
||||
|
||||
</overview>
|
||||
|
||||
@@ -13,4 +13,4 @@ import NtohlArrayNoBound
|
||||
|
||||
from NetworkToBufferSizeConfiguration bufConfig, DataFlow::Node source, DataFlow::Node sink
|
||||
where bufConfig.hasFlow(source, sink)
|
||||
select sink, "Unchecked use of data from network function $@.", source, source.toString()
|
||||
select sink, "Unchecked use of data from network function $@", source, source.toString()
|
||||
|
||||
@@ -49,7 +49,7 @@ pointer overflow.
|
||||
|
||||
<p>
|
||||
While it's not the subject of this query, the expression <code>ptr + i <
|
||||
ptr_end</code> is also an invalid range check. It's undefined behavior in
|
||||
ptr_end</code> is also an invalid range check. It's undefined behavor in
|
||||
C/C++ to create a pointer that points more than one past the end of an
|
||||
allocation.
|
||||
</p>
|
||||
|
||||
@@ -12,7 +12,7 @@ the third argument to the entire size of the destination buffer.
|
||||
Executing a call of this type may cause a buffer overflow unless the buffer is known to be empty.</p>
|
||||
|
||||
<p>Similarly, calls of the form <code>strncat(dest, src, sizeof (dest) - strlen (dest))</code> allow one
|
||||
byte to be written outside the <code>dest</code> buffer.</p>
|
||||
byte to be written ouside the <code>dest</code> buffer.</p>
|
||||
|
||||
<p>Buffer overflows can lead to anything from a segmentation fault to a security vulnerability.</p>
|
||||
|
||||
|
||||
@@ -81,4 +81,4 @@ from UninitialisedLocalReachability r, LocalVariable v, VariableAccess va
|
||||
where
|
||||
r.reaches(_, v, va) and
|
||||
not va = commonException()
|
||||
select va, "The variable $@ may not be initialized at this access.", v, v.getName()
|
||||
select va, "The variable $@ may not be initialized here.", v, v.getName()
|
||||
|
||||
@@ -399,5 +399,5 @@ where
|
||||
) and
|
||||
source.asStore() = store and
|
||||
sink.asSink(_) = load
|
||||
select sink, source, sink, "Stack variable $@ escapes at $@ and is used after it has expired.", var,
|
||||
var.toString(), store, "this store"
|
||||
select sink, source, sink, "Stack variable $@ escapes $@ and is used after it has expired.", var,
|
||||
var.toString(), store, "here"
|
||||
|
||||
@@ -83,4 +83,4 @@ where
|
||||
c.getAMemberFunction().getAnOverriddenFunction() = call.getStaticCallTarget()
|
||||
)
|
||||
select call.getUnconvertedResultExpression(), source, sink,
|
||||
"Call to pure virtual function during " + msg + "."
|
||||
"Call to pure virtual function during " + msg
|
||||
|
||||
@@ -92,6 +92,5 @@ where
|
||||
isOptionSet(cc, BoostorgAsio::getShiftedSslOptionsNoTls1_2(), e) and
|
||||
msg = "no_tlsv1_2 was set"
|
||||
)
|
||||
select cc,
|
||||
"This usage of 'boost::asio::ssl::context::context' with protocol $@ is not configured correctly: The option $@.",
|
||||
protocolSource, protocolSource.toString(), e, msg
|
||||
select cc, "Usage of $@ with protocol $@ is not configured correctly: The option $@.", cc,
|
||||
"boost::asio::ssl::context::context", protocolSource, protocolSource.toString(), e, msg
|
||||
|
||||
@@ -67,5 +67,5 @@ where
|
||||
// the pointer was null. To follow this idea to its full generality, we
|
||||
// should also give an alert when `check` post-dominates `deref`.
|
||||
deref.getBlock() = dominator
|
||||
select checked, "This null check is redundant because $@ in any case.", deref,
|
||||
"the value is dereferenced"
|
||||
select checked, "This null check is redundant because the value is $@ in any case", deref,
|
||||
"dereferenced here"
|
||||
|
||||
@@ -48,5 +48,5 @@ where
|
||||
not coordinatePair(iterationVar, innerVar)
|
||||
select iterationVar,
|
||||
"Iteration variable " + iterationVar.getName() +
|
||||
" for $@ should have a descriptive name, since there is a $@.", outer, "this loop", inner,
|
||||
"nested loop"
|
||||
" for $@ should have a descriptive name, since there is $@.", outer, "this loop", inner,
|
||||
"a nested loop"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<p>
|
||||
This metric provides an indication of the lack of cohesion of a class,
|
||||
using a method proposed by Chidamber and Kemerer in 1994. The idea
|
||||
behind measuring a class's cohesion is that most functions in well-designed
|
||||
behind measuring a class's cohesion is that most funcions in well-designed
|
||||
classes will access the same fields. Types that exhibit a lack of cohesion
|
||||
are often trying to take on multiple responsibilities, and should be split
|
||||
into several smaller classes.
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
by changes to other packages. If this metric value is high, a package is easily
|
||||
influenced. If the values is low, the impact of changes to other packages is likely to be minimal. Instability
|
||||
is estimated as the number of outgoing dependencies relative to the total
|
||||
number of dependencies.</p>
|
||||
number of depencies.</p>
|
||||
</overview>
|
||||
|
||||
<references>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
by changes to other packages. If this metric value is high, a package is easily
|
||||
influenced. If the values is low, the impact of changes to other packages is likely to be minimal. Instability
|
||||
is estimated as the number of outgoing dependencies relative to the total
|
||||
number of dependencies.</p>
|
||||
number of depencies.</p>
|
||||
</overview>
|
||||
|
||||
<references>
|
||||
|
||||
@@ -60,5 +60,5 @@ where
|
||||
taintedWithPath(taintSource, taintedArg, sourceNode, sinkNode) and
|
||||
isUserInput(taintSource, taintCause)
|
||||
select taintedArg, sourceNode, sinkNode,
|
||||
"This argument to a file access function is derived from $@ and then passed to " + callChain + ".",
|
||||
"This argument to a file access function is derived from $@ and then passed to " + callChain,
|
||||
taintSource, "user input (" + taintCause + ")"
|
||||
|
||||
@@ -158,5 +158,5 @@ where
|
||||
concatResult = sinkNode.getState().(ExecState).getSndNode()
|
||||
select sinkAsArgumentIndirection(sinkNode.getNode()), sourceNode, sinkNode,
|
||||
"This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to "
|
||||
+ callChain + ".", sourceNode, "user input (" + taintCause + ")", concatResult,
|
||||
+ callChain, sourceNode, "user input (" + taintCause + ")", concatResult,
|
||||
concatResult.toString()
|
||||
|
||||
@@ -50,5 +50,5 @@ where
|
||||
taintedWithPath(taintSource, taintedArg, sourceNode, sinkNode) and
|
||||
isUserInput(taintSource, taintCause)
|
||||
select taintedArg, sourceNode, sinkNode,
|
||||
"This argument to a SQL query function is derived from $@ and then passed to " + callChain + ".",
|
||||
"This argument to a SQL query function is derived from $@ and then passed to " + callChain,
|
||||
taintSource, "user input (" + taintCause + ")"
|
||||
|
||||
@@ -34,5 +34,5 @@ where
|
||||
isProcessOperationExplanation(arg, processOperation) and
|
||||
taintedWithPath(source, arg, sourceNode, sinkNode)
|
||||
select arg, sourceNode, sinkNode,
|
||||
"The value of this argument may come from $@ and is being passed to " + processOperation + ".",
|
||||
source, source.toString()
|
||||
"The value of this argument may come from $@ and is being passed to " + processOperation, source,
|
||||
source.toString()
|
||||
|
||||
@@ -56,26 +56,29 @@ class VarargsFunction extends Function {
|
||||
result = strictcount(FunctionCall fc | fc = this.getACallToThisFunction())
|
||||
}
|
||||
|
||||
string normalTerminator(int cnt, int totalCount) {
|
||||
// the terminator is 0 or -1
|
||||
string normalTerminator(int cnt) {
|
||||
result = ["0", "-1"] and
|
||||
// at least 80% of calls have the terminator
|
||||
cnt = this.trailingArgValueCount(result) and
|
||||
totalCount = this.totalCount() and
|
||||
100 * cnt / totalCount >= 80 and
|
||||
// terminator value is not used in a non-terminating position
|
||||
not exists(FunctionCall fc, int index | this.nonTrailingVarArgValue(fc, index) = result)
|
||||
2 * cnt > this.totalCount() and
|
||||
not exists(FunctionCall fc, int index |
|
||||
// terminator value is used in a non-terminating position
|
||||
this.nonTrailingVarArgValue(fc, index) = result
|
||||
)
|
||||
}
|
||||
|
||||
predicate isWhitelisted() { this.hasGlobalName(["open", "fcntl", "ptrace", "mremap"]) }
|
||||
predicate isWhitelisted() {
|
||||
this.hasGlobalName("open") or
|
||||
this.hasGlobalName("fcntl") or
|
||||
this.hasGlobalName("ptrace")
|
||||
}
|
||||
}
|
||||
|
||||
from VarargsFunction f, FunctionCall fc, string terminator, int cnt, int totalCount
|
||||
from VarargsFunction f, FunctionCall fc, string terminator, int cnt
|
||||
where
|
||||
terminator = f.normalTerminator(cnt, totalCount) and
|
||||
terminator = f.normalTerminator(cnt) and
|
||||
fc = f.getACallToThisFunction() and
|
||||
not normalisedExprValue(f.trailingArgumentIn(fc)) = terminator and
|
||||
not f.isWhitelisted()
|
||||
select fc,
|
||||
"Calls to $@ should use the value " + terminator + " as a terminator (" + cnt + " of " +
|
||||
totalCount + " calls do).", f, f.getQualifiedName()
|
||||
"Calls to $@ should use the value " + terminator + " as a terminator (" + cnt + " calls do).", f,
|
||||
f.getQualifiedName()
|
||||
|
||||
@@ -116,10 +116,6 @@ class ImproperArrayIndexValidationConfig extends TaintTracking::Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
/** Gets `str` where the first letter has been lowercased. */
|
||||
bindingset[str]
|
||||
string lowerFirst(string str) { result = str.prefix(1).toLowerCase() + str.suffix(1) }
|
||||
|
||||
from
|
||||
ImproperArrayIndexValidationConfig conf, DataFlow::PathNode source, DataFlow::PathNode sink,
|
||||
string sourceType
|
||||
@@ -127,5 +123,5 @@ where
|
||||
conf.hasFlowPath(source, sink) and
|
||||
isFlowSource(source.getNode(), sourceType)
|
||||
select sink.getNode(), source, sink,
|
||||
"An array indexing expression depends on $@ that might be outside the bounds of the array.",
|
||||
source.getNode(), lowerFirst(sourceType)
|
||||
"$@ flows to here and is used in an array indexing expression, potentially causing an invalid access.",
|
||||
source.getNode(), sourceType
|
||||
|
||||
@@ -34,4 +34,4 @@ where
|
||||
isUserInput(userValue, cause)
|
||||
select arg, sourceNode, sinkNode,
|
||||
"The value of this argument may come from $@ and is being used as a formatting argument to " +
|
||||
printfFunction + ".", userValue, cause
|
||||
printfFunction, userValue, cause
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user