mirror of
https://github.com/github/codeql.git
synced 2026-07-05 03:25:31 +02:00
Compare commits
1 Commits
codeql-cli
...
aml-auto-e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
709cbb4316 |
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
|
env QHELP_OUT_DIR=qhelp-out make qhelp-to-markdown
|
||||||
|
|
||||||
- name: Upload qhelp markdown
|
- name: Upload qhelp markdown
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: qhelp-markdown
|
name: qhelp-markdown
|
||||||
path: go/qhelp-out/**/*.md
|
path: go/qhelp-out/**/*.md
|
||||||
|
|||||||
2
.github/workflows/qhelp-pr-preview.yml
vendored
2
.github/workflows/qhelp-pr-preview.yml
vendored
@@ -27,7 +27,7 @@ on:
|
|||||||
- main
|
- main
|
||||||
- "rc/*"
|
- "rc/*"
|
||||||
paths:
|
paths:
|
||||||
- "**/*.qhelp"
|
- "ruby/**/*.qhelp"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
qhelp:
|
qhelp:
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ This open source repository contains the standard CodeQL libraries and queries t
|
|||||||
|
|
||||||
## How do I learn CodeQL and run queries?
|
## 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
|
## Contributing
|
||||||
|
|
||||||
|
|||||||
@@ -33,9 +33,8 @@
|
|||||||
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl4.qll",
|
"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/DataFlowImpl.qll",
|
||||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.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/DataFlowImplForHttpClientLibraries.qll",
|
||||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForPathname.qll",
|
|
||||||
"swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl.qll"
|
"swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl.qll"
|
||||||
],
|
],
|
||||||
"DataFlow Java/C++/C#/Python Common": [
|
"DataFlow Java/C++/C#/Python Common": [
|
||||||
@@ -70,7 +69,7 @@
|
|||||||
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking3/TaintTrackingImpl.qll",
|
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking3/TaintTrackingImpl.qll",
|
||||||
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking4/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/tainttracking1/TaintTrackingImpl.qll",
|
||||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/tainttrackingforregexp/TaintTrackingImpl.qll",
|
"ruby/ql/lib/codeql/ruby/dataflow/internal/tainttrackingforlibraries/TaintTrackingImpl.qll",
|
||||||
"swift/ql/lib/codeql/swift/dataflow/internal/tainttracking1/TaintTrackingImpl.qll"
|
"swift/ql/lib/codeql/swift/dataflow/internal/tainttracking1/TaintTrackingImpl.qll"
|
||||||
],
|
],
|
||||||
"DataFlow Java/C++/C#/Python Consistency checks": [
|
"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.5
|
||||||
|
|
||||||
## 0.3.4
|
## 0.3.4
|
||||||
|
|||||||
@@ -1,14 +1,4 @@
|
|||||||
## 0.4.0
|
---
|
||||||
|
category: feature
|
||||||
### 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`.
|
* 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
|
---
|
||||||
|
category: deprecated
|
||||||
### Deprecated APIs
|
---
|
||||||
|
|
||||||
* Some classes/modules with upper-case acronyms in their name have been renamed to follow our style-guide.
|
* 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.
|
* `source1` and `source2` must belong to the same callable.
|
||||||
*/
|
*/
|
||||||
predicate isSourcePair(
|
predicate isSourcePair(
|
||||||
DataFlow::Node source1, DataFlow::FlowState state1, DataFlow::Node source2,
|
DataFlow::Node source1, string state1, DataFlow::Node source2, string state2
|
||||||
DataFlow::FlowState state2
|
|
||||||
) {
|
) {
|
||||||
state1 = "" and
|
state1 = "" and
|
||||||
state2 = "" and
|
state2 = "" and
|
||||||
@@ -50,101 +49,6 @@ module ProductFlow {
|
|||||||
this.isSinkPair(sink1, sink2)
|
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(
|
predicate hasFlowPath(
|
||||||
DataFlow::PathNode source1, DataFlow2::PathNode source2, DataFlow::PathNode sink1,
|
DataFlow::PathNode source1, DataFlow2::PathNode source2, DataFlow::PathNode sink1,
|
||||||
DataFlow2::PathNode sink2
|
DataFlow2::PathNode sink2
|
||||||
@@ -159,78 +63,38 @@ module ProductFlow {
|
|||||||
class Conf1 extends DataFlow::Configuration {
|
class Conf1 extends DataFlow::Configuration {
|
||||||
Conf1() { this = "Conf1" }
|
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, _, _))
|
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, _, _))
|
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 {
|
class Conf2 extends DataFlow2::Configuration {
|
||||||
Conf2() { this = "Conf2" }
|
Conf2() { this = "Conf2" }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) {
|
override predicate isSource(DataFlow::Node source, string state) {
|
||||||
exists(Configuration conf, DataFlow::PathNode source1 |
|
exists(Configuration conf, DataFlow::Node source1 |
|
||||||
conf.isSourcePair(source1.getNode(), source1.getState(), source, state) and
|
conf.isSourcePair(source1, _, source, state) and
|
||||||
any(Conf1 c).hasFlowPath(source1, _)
|
any(Conf1 c).hasFlow(source1, _)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) {
|
override predicate isSink(DataFlow::Node sink, string state) {
|
||||||
exists(Configuration conf, DataFlow::PathNode sink1 |
|
exists(Configuration conf, DataFlow::Node sink1 |
|
||||||
conf.isSinkPair(sink1.getNode(), sink1.getState(), sink, state) and
|
conf.isSinkPair(sink1, _, sink, state) and any(Conf1 c).hasFlow(_, sink1)
|
||||||
any(Conf1 c).hasFlowPath(_, 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(
|
private predicate reachableInterprocEntry(
|
||||||
Configuration conf, DataFlow::PathNode source1, DataFlow2::PathNode source2,
|
Configuration conf, DataFlow::PathNode source1, DataFlow2::PathNode source2,
|
||||||
DataFlow::PathNode node1, DataFlow2::PathNode node2
|
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
|
node1 = source1 and
|
||||||
node2 = source2
|
node2 = source2
|
||||||
or
|
or
|
||||||
@@ -293,7 +157,7 @@ module ProductFlow {
|
|||||||
) {
|
) {
|
||||||
exists(DataFlow::PathNode mid1, DataFlow2::PathNode mid2 |
|
exists(DataFlow::PathNode mid1, DataFlow2::PathNode mid2 |
|
||||||
reachableInterprocEntry(conf, source1, source2, mid1, mid2) and
|
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
|
localPathStep1*(mid1, sink1) and
|
||||||
localPathStep2*(mid2, sink2)
|
localPathStep2*(mid2, sink2)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -558,16 +558,13 @@ private predicate expectsContentEx(NodeEx n, Content c) {
|
|||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
|
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate store(
|
private predicate store(
|
||||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||||
) {
|
) {
|
||||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||||
contentType) and
|
contentType) and
|
||||||
hasReadStep(tc.getContent(), config) and
|
read(_, tc.getContent(), _, config) and
|
||||||
stepFilter(node1, node2, config)
|
stepFilter(node1, node2, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -601,9 +598,13 @@ private predicate hasSinkCallCtx(Configuration config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private module Stage1 implements StageSig {
|
private module Stage1 implements StageSig {
|
||||||
|
class ApApprox = Unit;
|
||||||
|
|
||||||
class Ap = Unit;
|
class Ap = Unit;
|
||||||
|
|
||||||
private class Cc = boolean;
|
class ApOption = Unit;
|
||||||
|
|
||||||
|
class Cc = boolean;
|
||||||
|
|
||||||
/* Begin: Stage 1 logic. */
|
/* Begin: Stage 1 logic. */
|
||||||
/**
|
/**
|
||||||
@@ -612,7 +613,7 @@ private module Stage1 implements StageSig {
|
|||||||
* The Boolean `cc` records whether the node is reached through an
|
* The Boolean `cc` records whether the node is reached through an
|
||||||
* argument in a call.
|
* 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
|
sourceNode(node, _, config) and
|
||||||
if hasSourceCallCtx(config) then cc = true else cc = false
|
if hasSourceCallCtx(config) then cc = true else cc = false
|
||||||
or
|
or
|
||||||
@@ -752,7 +753,7 @@ private module Stage1 implements StageSig {
|
|||||||
* the enclosing callable in order to reach a sink.
|
* the enclosing callable in order to reach a sink.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||||
revFlow0(node, toReturn, config) and
|
revFlow0(node, toReturn, config) and
|
||||||
fwdFlow(node, config)
|
fwdFlow(node, config)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -558,16 +558,13 @@ private predicate expectsContentEx(NodeEx n, Content c) {
|
|||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
|
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate store(
|
private predicate store(
|
||||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||||
) {
|
) {
|
||||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||||
contentType) and
|
contentType) and
|
||||||
hasReadStep(tc.getContent(), config) and
|
read(_, tc.getContent(), _, config) and
|
||||||
stepFilter(node1, node2, config)
|
stepFilter(node1, node2, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -601,9 +598,13 @@ private predicate hasSinkCallCtx(Configuration config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private module Stage1 implements StageSig {
|
private module Stage1 implements StageSig {
|
||||||
|
class ApApprox = Unit;
|
||||||
|
|
||||||
class Ap = Unit;
|
class Ap = Unit;
|
||||||
|
|
||||||
private class Cc = boolean;
|
class ApOption = Unit;
|
||||||
|
|
||||||
|
class Cc = boolean;
|
||||||
|
|
||||||
/* Begin: Stage 1 logic. */
|
/* Begin: Stage 1 logic. */
|
||||||
/**
|
/**
|
||||||
@@ -612,7 +613,7 @@ private module Stage1 implements StageSig {
|
|||||||
* The Boolean `cc` records whether the node is reached through an
|
* The Boolean `cc` records whether the node is reached through an
|
||||||
* argument in a call.
|
* 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
|
sourceNode(node, _, config) and
|
||||||
if hasSourceCallCtx(config) then cc = true else cc = false
|
if hasSourceCallCtx(config) then cc = true else cc = false
|
||||||
or
|
or
|
||||||
@@ -752,7 +753,7 @@ private module Stage1 implements StageSig {
|
|||||||
* the enclosing callable in order to reach a sink.
|
* the enclosing callable in order to reach a sink.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||||
revFlow0(node, toReturn, config) and
|
revFlow0(node, toReturn, config) and
|
||||||
fwdFlow(node, config)
|
fwdFlow(node, config)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -558,16 +558,13 @@ private predicate expectsContentEx(NodeEx n, Content c) {
|
|||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
|
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate store(
|
private predicate store(
|
||||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||||
) {
|
) {
|
||||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||||
contentType) and
|
contentType) and
|
||||||
hasReadStep(tc.getContent(), config) and
|
read(_, tc.getContent(), _, config) and
|
||||||
stepFilter(node1, node2, config)
|
stepFilter(node1, node2, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -601,9 +598,13 @@ private predicate hasSinkCallCtx(Configuration config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private module Stage1 implements StageSig {
|
private module Stage1 implements StageSig {
|
||||||
|
class ApApprox = Unit;
|
||||||
|
|
||||||
class Ap = Unit;
|
class Ap = Unit;
|
||||||
|
|
||||||
private class Cc = boolean;
|
class ApOption = Unit;
|
||||||
|
|
||||||
|
class Cc = boolean;
|
||||||
|
|
||||||
/* Begin: Stage 1 logic. */
|
/* Begin: Stage 1 logic. */
|
||||||
/**
|
/**
|
||||||
@@ -612,7 +613,7 @@ private module Stage1 implements StageSig {
|
|||||||
* The Boolean `cc` records whether the node is reached through an
|
* The Boolean `cc` records whether the node is reached through an
|
||||||
* argument in a call.
|
* 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
|
sourceNode(node, _, config) and
|
||||||
if hasSourceCallCtx(config) then cc = true else cc = false
|
if hasSourceCallCtx(config) then cc = true else cc = false
|
||||||
or
|
or
|
||||||
@@ -752,7 +753,7 @@ private module Stage1 implements StageSig {
|
|||||||
* the enclosing callable in order to reach a sink.
|
* the enclosing callable in order to reach a sink.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||||
revFlow0(node, toReturn, config) and
|
revFlow0(node, toReturn, config) and
|
||||||
fwdFlow(node, config)
|
fwdFlow(node, config)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -558,16 +558,13 @@ private predicate expectsContentEx(NodeEx n, Content c) {
|
|||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
|
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate store(
|
private predicate store(
|
||||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||||
) {
|
) {
|
||||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||||
contentType) and
|
contentType) and
|
||||||
hasReadStep(tc.getContent(), config) and
|
read(_, tc.getContent(), _, config) and
|
||||||
stepFilter(node1, node2, config)
|
stepFilter(node1, node2, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -601,9 +598,13 @@ private predicate hasSinkCallCtx(Configuration config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private module Stage1 implements StageSig {
|
private module Stage1 implements StageSig {
|
||||||
|
class ApApprox = Unit;
|
||||||
|
|
||||||
class Ap = Unit;
|
class Ap = Unit;
|
||||||
|
|
||||||
private class Cc = boolean;
|
class ApOption = Unit;
|
||||||
|
|
||||||
|
class Cc = boolean;
|
||||||
|
|
||||||
/* Begin: Stage 1 logic. */
|
/* Begin: Stage 1 logic. */
|
||||||
/**
|
/**
|
||||||
@@ -612,7 +613,7 @@ private module Stage1 implements StageSig {
|
|||||||
* The Boolean `cc` records whether the node is reached through an
|
* The Boolean `cc` records whether the node is reached through an
|
||||||
* argument in a call.
|
* 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
|
sourceNode(node, _, config) and
|
||||||
if hasSourceCallCtx(config) then cc = true else cc = false
|
if hasSourceCallCtx(config) then cc = true else cc = false
|
||||||
or
|
or
|
||||||
@@ -752,7 +753,7 @@ private module Stage1 implements StageSig {
|
|||||||
* the enclosing callable in order to reach a sink.
|
* the enclosing callable in order to reach a sink.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||||
revFlow0(node, toReturn, config) and
|
revFlow0(node, toReturn, config) and
|
||||||
fwdFlow(node, config)
|
fwdFlow(node, config)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -416,21 +416,6 @@ class SsaPhiNode extends Node, TSsaPhiNode {
|
|||||||
final override Location getLocationImpl() { result = phi.getBasicBlock().getLocation() }
|
final override Location getLocationImpl() { result = phi.getBasicBlock().getLocation() }
|
||||||
|
|
||||||
override string toStringImpl() { result = "Phi" }
|
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(_) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -301,12 +301,7 @@ private predicate defToNode(Node nodeFrom, Def def) {
|
|||||||
nodeHasInstruction(nodeFrom, def.getDefiningInstruction(), def.getIndirectionIndex())
|
nodeHasInstruction(nodeFrom, def.getDefiningInstruction(), def.getIndirectionIndex())
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private predicate nodeToDefOrUse(Node nodeFrom, SsaDefOrUse defOrUse) {
|
||||||
* INTERNAL: Do not use.
|
|
||||||
*
|
|
||||||
* Holds if `nodeFrom` is the node that correspond to the definition or use `defOrUse`.
|
|
||||||
*/
|
|
||||||
predicate nodeToDefOrUse(Node nodeFrom, SsaDefOrUse defOrUse) {
|
|
||||||
// Node -> Def
|
// Node -> Def
|
||||||
defToNode(nodeFrom, defOrUse)
|
defToNode(nodeFrom, defOrUse)
|
||||||
or
|
or
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ private import semmle.code.cpp.ir.IR as IR
|
|||||||
private import Semantic
|
private import Semantic
|
||||||
private import experimental.semmle.code.cpp.rangeanalysis.Bound as IRBound
|
private import experimental.semmle.code.cpp.rangeanalysis.Bound as IRBound
|
||||||
private import semmle.code.cpp.controlflow.IRGuards as IRGuards
|
private import semmle.code.cpp.controlflow.IRGuards as IRGuards
|
||||||
private import semmle.code.cpp.ir.ValueNumbering
|
|
||||||
|
|
||||||
module SemanticExprConfig {
|
module SemanticExprConfig {
|
||||||
class Location = Cpp::Location;
|
class Location = Cpp::Location;
|
||||||
@@ -121,15 +120,7 @@ module SemanticExprConfig {
|
|||||||
|
|
||||||
newtype TSsaVariable =
|
newtype TSsaVariable =
|
||||||
TSsaInstruction(IR::Instruction instr) { instr.hasMemoryResult() } or
|
TSsaInstruction(IR::Instruction instr) { instr.hasMemoryResult() } or
|
||||||
TSsaOperand(IR::Operand op) { op.isDefinitionInexact() } or
|
TSsaOperand(IR::Operand op) { op.isDefinitionInexact() }
|
||||||
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, _, _, _)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
class SsaVariable extends TSsaVariable {
|
class SsaVariable extends TSsaVariable {
|
||||||
string toString() { none() }
|
string toString() { none() }
|
||||||
@@ -138,8 +129,6 @@ module SemanticExprConfig {
|
|||||||
|
|
||||||
IR::Instruction asInstruction() { none() }
|
IR::Instruction asInstruction() { none() }
|
||||||
|
|
||||||
IR::PointerArithmeticInstruction asPointerArithGuard() { none() }
|
|
||||||
|
|
||||||
IR::Operand asOperand() { none() }
|
IR::Operand asOperand() { none() }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,18 +144,6 @@ module SemanticExprConfig {
|
|||||||
final override IR::Instruction asInstruction() { result = instr }
|
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 {
|
class SsaOperand extends SsaVariable, TSsaOperand {
|
||||||
IR::Operand op;
|
IR::Operand op;
|
||||||
|
|
||||||
@@ -191,11 +168,7 @@ module SemanticExprConfig {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr getAUse(SsaVariable v) {
|
Expr getAUse(SsaVariable v) { result.(IR::LoadInstruction).getSourceValue() = v.asInstruction() }
|
||||||
result.(IR::LoadInstruction).getSourceValue() = v.asInstruction()
|
|
||||||
or
|
|
||||||
result = valueNumber(v.asPointerArithGuard()).getAnInstruction()
|
|
||||||
}
|
|
||||||
|
|
||||||
SemType getSsaVariableType(SsaVariable v) {
|
SemType getSsaVariableType(SsaVariable v) {
|
||||||
result = getSemanticType(v.asInstruction().getResultIRType())
|
result = getSemanticType(v.asInstruction().getResultIRType())
|
||||||
@@ -235,9 +208,7 @@ module SemanticExprConfig {
|
|||||||
|
|
||||||
final override predicate hasRead(SsaVariable v) {
|
final override predicate hasRead(SsaVariable v) {
|
||||||
exists(IR::Operand operand |
|
exists(IR::Operand operand |
|
||||||
operand.getDef() = v.asInstruction() or
|
operand.getDef() = v.asInstruction() and
|
||||||
operand.getDef() = valueNumber(v.asPointerArithGuard()).getAnInstruction()
|
|
||||||
|
|
|
||||||
not operand instanceof IR::PhiInputOperand and
|
not operand instanceof IR::PhiInputOperand and
|
||||||
operand.getUse().getBlock() = block
|
operand.getUse().getBlock() = block
|
||||||
)
|
)
|
||||||
@@ -256,9 +227,7 @@ module SemanticExprConfig {
|
|||||||
|
|
||||||
final override predicate hasRead(SsaVariable v) {
|
final override predicate hasRead(SsaVariable v) {
|
||||||
exists(IR::PhiInputOperand operand |
|
exists(IR::PhiInputOperand operand |
|
||||||
operand.getDef() = v.asInstruction() or
|
operand.getDef() = v.asInstruction() and
|
||||||
operand.getDef() = valueNumber(v.asPointerArithGuard()).getAnInstruction()
|
|
||||||
|
|
|
||||||
operand.getPredecessorBlock() = pred and
|
operand.getPredecessorBlock() = pred and
|
||||||
operand.getUse().getBlock() = succ
|
operand.getUse().getBlock() = succ
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ class SemSsaVariable instanceof Specific::SsaVariable {
|
|||||||
|
|
||||||
final Specific::Location getLocation() { result = super.getLocation() }
|
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) }
|
final SemType getType() { result = Specific::getSsaVariableType(this) }
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
name: codeql/cpp-all
|
name: codeql/cpp-all
|
||||||
version: 0.4.1
|
version: 0.4.0-dev
|
||||||
groups: cpp
|
groups: cpp
|
||||||
dbscheme: semmlecode.cpp.dbscheme
|
dbscheme: semmlecode.cpp.dbscheme
|
||||||
extractor: cpp
|
extractor: cpp
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import cpp
|
|||||||
* A function that concatenates the string from its second argument
|
* A function that concatenates the string from its second argument
|
||||||
* to the string from its first argument, for example `strcat`.
|
* to the string from its first argument, for example `strcat`.
|
||||||
*/
|
*/
|
||||||
deprecated class StrcatFunction extends Function {
|
class StrcatFunction extends Function {
|
||||||
StrcatFunction() {
|
StrcatFunction() {
|
||||||
getName() =
|
getName() =
|
||||||
[
|
[
|
||||||
|
|||||||
@@ -558,16 +558,13 @@ private predicate expectsContentEx(NodeEx n, Content c) {
|
|||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
|
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate store(
|
private predicate store(
|
||||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||||
) {
|
) {
|
||||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||||
contentType) and
|
contentType) and
|
||||||
hasReadStep(tc.getContent(), config) and
|
read(_, tc.getContent(), _, config) and
|
||||||
stepFilter(node1, node2, config)
|
stepFilter(node1, node2, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -601,9 +598,13 @@ private predicate hasSinkCallCtx(Configuration config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private module Stage1 implements StageSig {
|
private module Stage1 implements StageSig {
|
||||||
|
class ApApprox = Unit;
|
||||||
|
|
||||||
class Ap = Unit;
|
class Ap = Unit;
|
||||||
|
|
||||||
private class Cc = boolean;
|
class ApOption = Unit;
|
||||||
|
|
||||||
|
class Cc = boolean;
|
||||||
|
|
||||||
/* Begin: Stage 1 logic. */
|
/* Begin: Stage 1 logic. */
|
||||||
/**
|
/**
|
||||||
@@ -612,7 +613,7 @@ private module Stage1 implements StageSig {
|
|||||||
* The Boolean `cc` records whether the node is reached through an
|
* The Boolean `cc` records whether the node is reached through an
|
||||||
* argument in a call.
|
* 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
|
sourceNode(node, _, config) and
|
||||||
if hasSourceCallCtx(config) then cc = true else cc = false
|
if hasSourceCallCtx(config) then cc = true else cc = false
|
||||||
or
|
or
|
||||||
@@ -752,7 +753,7 @@ private module Stage1 implements StageSig {
|
|||||||
* the enclosing callable in order to reach a sink.
|
* the enclosing callable in order to reach a sink.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||||
revFlow0(node, toReturn, config) and
|
revFlow0(node, toReturn, config) and
|
||||||
fwdFlow(node, config)
|
fwdFlow(node, config)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -558,16 +558,13 @@ private predicate expectsContentEx(NodeEx n, Content c) {
|
|||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
|
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate store(
|
private predicate store(
|
||||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||||
) {
|
) {
|
||||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||||
contentType) and
|
contentType) and
|
||||||
hasReadStep(tc.getContent(), config) and
|
read(_, tc.getContent(), _, config) and
|
||||||
stepFilter(node1, node2, config)
|
stepFilter(node1, node2, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -601,9 +598,13 @@ private predicate hasSinkCallCtx(Configuration config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private module Stage1 implements StageSig {
|
private module Stage1 implements StageSig {
|
||||||
|
class ApApprox = Unit;
|
||||||
|
|
||||||
class Ap = Unit;
|
class Ap = Unit;
|
||||||
|
|
||||||
private class Cc = boolean;
|
class ApOption = Unit;
|
||||||
|
|
||||||
|
class Cc = boolean;
|
||||||
|
|
||||||
/* Begin: Stage 1 logic. */
|
/* Begin: Stage 1 logic. */
|
||||||
/**
|
/**
|
||||||
@@ -612,7 +613,7 @@ private module Stage1 implements StageSig {
|
|||||||
* The Boolean `cc` records whether the node is reached through an
|
* The Boolean `cc` records whether the node is reached through an
|
||||||
* argument in a call.
|
* 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
|
sourceNode(node, _, config) and
|
||||||
if hasSourceCallCtx(config) then cc = true else cc = false
|
if hasSourceCallCtx(config) then cc = true else cc = false
|
||||||
or
|
or
|
||||||
@@ -752,7 +753,7 @@ private module Stage1 implements StageSig {
|
|||||||
* the enclosing callable in order to reach a sink.
|
* the enclosing callable in order to reach a sink.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||||
revFlow0(node, toReturn, config) and
|
revFlow0(node, toReturn, config) and
|
||||||
fwdFlow(node, config)
|
fwdFlow(node, config)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -558,16 +558,13 @@ private predicate expectsContentEx(NodeEx n, Content c) {
|
|||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
|
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate store(
|
private predicate store(
|
||||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||||
) {
|
) {
|
||||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||||
contentType) and
|
contentType) and
|
||||||
hasReadStep(tc.getContent(), config) and
|
read(_, tc.getContent(), _, config) and
|
||||||
stepFilter(node1, node2, config)
|
stepFilter(node1, node2, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -601,9 +598,13 @@ private predicate hasSinkCallCtx(Configuration config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private module Stage1 implements StageSig {
|
private module Stage1 implements StageSig {
|
||||||
|
class ApApprox = Unit;
|
||||||
|
|
||||||
class Ap = Unit;
|
class Ap = Unit;
|
||||||
|
|
||||||
private class Cc = boolean;
|
class ApOption = Unit;
|
||||||
|
|
||||||
|
class Cc = boolean;
|
||||||
|
|
||||||
/* Begin: Stage 1 logic. */
|
/* Begin: Stage 1 logic. */
|
||||||
/**
|
/**
|
||||||
@@ -612,7 +613,7 @@ private module Stage1 implements StageSig {
|
|||||||
* The Boolean `cc` records whether the node is reached through an
|
* The Boolean `cc` records whether the node is reached through an
|
||||||
* argument in a call.
|
* 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
|
sourceNode(node, _, config) and
|
||||||
if hasSourceCallCtx(config) then cc = true else cc = false
|
if hasSourceCallCtx(config) then cc = true else cc = false
|
||||||
or
|
or
|
||||||
@@ -752,7 +753,7 @@ private module Stage1 implements StageSig {
|
|||||||
* the enclosing callable in order to reach a sink.
|
* the enclosing callable in order to reach a sink.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||||
revFlow0(node, toReturn, config) and
|
revFlow0(node, toReturn, config) and
|
||||||
fwdFlow(node, config)
|
fwdFlow(node, config)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -558,16 +558,13 @@ private predicate expectsContentEx(NodeEx n, Content c) {
|
|||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
|
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate store(
|
private predicate store(
|
||||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||||
) {
|
) {
|
||||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||||
contentType) and
|
contentType) and
|
||||||
hasReadStep(tc.getContent(), config) and
|
read(_, tc.getContent(), _, config) and
|
||||||
stepFilter(node1, node2, config)
|
stepFilter(node1, node2, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -601,9 +598,13 @@ private predicate hasSinkCallCtx(Configuration config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private module Stage1 implements StageSig {
|
private module Stage1 implements StageSig {
|
||||||
|
class ApApprox = Unit;
|
||||||
|
|
||||||
class Ap = Unit;
|
class Ap = Unit;
|
||||||
|
|
||||||
private class Cc = boolean;
|
class ApOption = Unit;
|
||||||
|
|
||||||
|
class Cc = boolean;
|
||||||
|
|
||||||
/* Begin: Stage 1 logic. */
|
/* Begin: Stage 1 logic. */
|
||||||
/**
|
/**
|
||||||
@@ -612,7 +613,7 @@ private module Stage1 implements StageSig {
|
|||||||
* The Boolean `cc` records whether the node is reached through an
|
* The Boolean `cc` records whether the node is reached through an
|
||||||
* argument in a call.
|
* 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
|
sourceNode(node, _, config) and
|
||||||
if hasSourceCallCtx(config) then cc = true else cc = false
|
if hasSourceCallCtx(config) then cc = true else cc = false
|
||||||
or
|
or
|
||||||
@@ -752,7 +753,7 @@ private module Stage1 implements StageSig {
|
|||||||
* the enclosing callable in order to reach a sink.
|
* the enclosing callable in order to reach a sink.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||||
revFlow0(node, toReturn, config) and
|
revFlow0(node, toReturn, config) and
|
||||||
fwdFlow(node, config)
|
fwdFlow(node, config)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -558,16 +558,13 @@ private predicate expectsContentEx(NodeEx n, Content c) {
|
|||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
|
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate store(
|
private predicate store(
|
||||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||||
) {
|
) {
|
||||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||||
contentType) and
|
contentType) and
|
||||||
hasReadStep(tc.getContent(), config) and
|
read(_, tc.getContent(), _, config) and
|
||||||
stepFilter(node1, node2, config)
|
stepFilter(node1, node2, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -601,9 +598,13 @@ private predicate hasSinkCallCtx(Configuration config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private module Stage1 implements StageSig {
|
private module Stage1 implements StageSig {
|
||||||
|
class ApApprox = Unit;
|
||||||
|
|
||||||
class Ap = Unit;
|
class Ap = Unit;
|
||||||
|
|
||||||
private class Cc = boolean;
|
class ApOption = Unit;
|
||||||
|
|
||||||
|
class Cc = boolean;
|
||||||
|
|
||||||
/* Begin: Stage 1 logic. */
|
/* Begin: Stage 1 logic. */
|
||||||
/**
|
/**
|
||||||
@@ -612,7 +613,7 @@ private module Stage1 implements StageSig {
|
|||||||
* The Boolean `cc` records whether the node is reached through an
|
* The Boolean `cc` records whether the node is reached through an
|
||||||
* argument in a call.
|
* 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
|
sourceNode(node, _, config) and
|
||||||
if hasSourceCallCtx(config) then cc = true else cc = false
|
if hasSourceCallCtx(config) then cc = true else cc = false
|
||||||
or
|
or
|
||||||
@@ -752,7 +753,7 @@ private module Stage1 implements StageSig {
|
|||||||
* the enclosing callable in order to reach a sink.
|
* the enclosing callable in order to reach a sink.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||||
revFlow0(node, toReturn, config) and
|
revFlow0(node, toReturn, config) and
|
||||||
fwdFlow(node, config)
|
fwdFlow(node, config)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -558,16 +558,13 @@ private predicate expectsContentEx(NodeEx n, Content c) {
|
|||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
|
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate store(
|
private predicate store(
|
||||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||||
) {
|
) {
|
||||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||||
contentType) and
|
contentType) and
|
||||||
hasReadStep(tc.getContent(), config) and
|
read(_, tc.getContent(), _, config) and
|
||||||
stepFilter(node1, node2, config)
|
stepFilter(node1, node2, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -601,9 +598,13 @@ private predicate hasSinkCallCtx(Configuration config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private module Stage1 implements StageSig {
|
private module Stage1 implements StageSig {
|
||||||
|
class ApApprox = Unit;
|
||||||
|
|
||||||
class Ap = Unit;
|
class Ap = Unit;
|
||||||
|
|
||||||
private class Cc = boolean;
|
class ApOption = Unit;
|
||||||
|
|
||||||
|
class Cc = boolean;
|
||||||
|
|
||||||
/* Begin: Stage 1 logic. */
|
/* Begin: Stage 1 logic. */
|
||||||
/**
|
/**
|
||||||
@@ -612,7 +613,7 @@ private module Stage1 implements StageSig {
|
|||||||
* The Boolean `cc` records whether the node is reached through an
|
* The Boolean `cc` records whether the node is reached through an
|
||||||
* argument in a call.
|
* 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
|
sourceNode(node, _, config) and
|
||||||
if hasSourceCallCtx(config) then cc = true else cc = false
|
if hasSourceCallCtx(config) then cc = true else cc = false
|
||||||
or
|
or
|
||||||
@@ -752,7 +753,7 @@ private module Stage1 implements StageSig {
|
|||||||
* the enclosing callable in order to reach a sink.
|
* the enclosing callable in order to reach a sink.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||||
revFlow0(node, toReturn, config) and
|
revFlow0(node, toReturn, config) and
|
||||||
fwdFlow(node, config)
|
fwdFlow(node, config)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -558,16 +558,13 @@ private predicate expectsContentEx(NodeEx n, Content c) {
|
|||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
|
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate store(
|
private predicate store(
|
||||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||||
) {
|
) {
|
||||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||||
contentType) and
|
contentType) and
|
||||||
hasReadStep(tc.getContent(), config) and
|
read(_, tc.getContent(), _, config) and
|
||||||
stepFilter(node1, node2, config)
|
stepFilter(node1, node2, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -601,9 +598,13 @@ private predicate hasSinkCallCtx(Configuration config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private module Stage1 implements StageSig {
|
private module Stage1 implements StageSig {
|
||||||
|
class ApApprox = Unit;
|
||||||
|
|
||||||
class Ap = Unit;
|
class Ap = Unit;
|
||||||
|
|
||||||
private class Cc = boolean;
|
class ApOption = Unit;
|
||||||
|
|
||||||
|
class Cc = boolean;
|
||||||
|
|
||||||
/* Begin: Stage 1 logic. */
|
/* Begin: Stage 1 logic. */
|
||||||
/**
|
/**
|
||||||
@@ -612,7 +613,7 @@ private module Stage1 implements StageSig {
|
|||||||
* The Boolean `cc` records whether the node is reached through an
|
* The Boolean `cc` records whether the node is reached through an
|
||||||
* argument in a call.
|
* 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
|
sourceNode(node, _, config) and
|
||||||
if hasSourceCallCtx(config) then cc = true else cc = false
|
if hasSourceCallCtx(config) then cc = true else cc = false
|
||||||
or
|
or
|
||||||
@@ -752,7 +753,7 @@ private module Stage1 implements StageSig {
|
|||||||
* the enclosing callable in order to reach a sink.
|
* the enclosing callable in order to reach a sink.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||||
revFlow0(node, toReturn, config) and
|
revFlow0(node, toReturn, config) and
|
||||||
fwdFlow(node, config)
|
fwdFlow(node, config)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -558,16 +558,13 @@ private predicate expectsContentEx(NodeEx n, Content c) {
|
|||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
|
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate store(
|
private predicate store(
|
||||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||||
) {
|
) {
|
||||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||||
contentType) and
|
contentType) and
|
||||||
hasReadStep(tc.getContent(), config) and
|
read(_, tc.getContent(), _, config) and
|
||||||
stepFilter(node1, node2, config)
|
stepFilter(node1, node2, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -601,9 +598,13 @@ private predicate hasSinkCallCtx(Configuration config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private module Stage1 implements StageSig {
|
private module Stage1 implements StageSig {
|
||||||
|
class ApApprox = Unit;
|
||||||
|
|
||||||
class Ap = Unit;
|
class Ap = Unit;
|
||||||
|
|
||||||
private class Cc = boolean;
|
class ApOption = Unit;
|
||||||
|
|
||||||
|
class Cc = boolean;
|
||||||
|
|
||||||
/* Begin: Stage 1 logic. */
|
/* Begin: Stage 1 logic. */
|
||||||
/**
|
/**
|
||||||
@@ -612,7 +613,7 @@ private module Stage1 implements StageSig {
|
|||||||
* The Boolean `cc` records whether the node is reached through an
|
* The Boolean `cc` records whether the node is reached through an
|
||||||
* argument in a call.
|
* 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
|
sourceNode(node, _, config) and
|
||||||
if hasSourceCallCtx(config) then cc = true else cc = false
|
if hasSourceCallCtx(config) then cc = true else cc = false
|
||||||
or
|
or
|
||||||
@@ -752,7 +753,7 @@ private module Stage1 implements StageSig {
|
|||||||
* the enclosing callable in order to reach a sink.
|
* the enclosing callable in order to reach a sink.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||||
revFlow0(node, toReturn, config) and
|
revFlow0(node, toReturn, config) and
|
||||||
fwdFlow(node, config)
|
fwdFlow(node, config)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -558,16 +558,13 @@ private predicate expectsContentEx(NodeEx n, Content c) {
|
|||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
|
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate store(
|
private predicate store(
|
||||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||||
) {
|
) {
|
||||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||||
contentType) and
|
contentType) and
|
||||||
hasReadStep(tc.getContent(), config) and
|
read(_, tc.getContent(), _, config) and
|
||||||
stepFilter(node1, node2, config)
|
stepFilter(node1, node2, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -601,9 +598,13 @@ private predicate hasSinkCallCtx(Configuration config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private module Stage1 implements StageSig {
|
private module Stage1 implements StageSig {
|
||||||
|
class ApApprox = Unit;
|
||||||
|
|
||||||
class Ap = Unit;
|
class Ap = Unit;
|
||||||
|
|
||||||
private class Cc = boolean;
|
class ApOption = Unit;
|
||||||
|
|
||||||
|
class Cc = boolean;
|
||||||
|
|
||||||
/* Begin: Stage 1 logic. */
|
/* Begin: Stage 1 logic. */
|
||||||
/**
|
/**
|
||||||
@@ -612,7 +613,7 @@ private module Stage1 implements StageSig {
|
|||||||
* The Boolean `cc` records whether the node is reached through an
|
* The Boolean `cc` records whether the node is reached through an
|
||||||
* argument in a call.
|
* 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
|
sourceNode(node, _, config) and
|
||||||
if hasSourceCallCtx(config) then cc = true else cc = false
|
if hasSourceCallCtx(config) then cc = true else cc = false
|
||||||
or
|
or
|
||||||
@@ -752,7 +753,7 @@ private module Stage1 implements StageSig {
|
|||||||
* the enclosing callable in order to reach a sink.
|
* the enclosing callable in order to reach a sink.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||||
revFlow0(node, toReturn, config) and
|
revFlow0(node, toReturn, config) and
|
||||||
fwdFlow(node, config)
|
fwdFlow(node, config)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -267,6 +267,9 @@ Instruction getSourceAddressFromNode(Node node) {
|
|||||||
result = getSourceAddress(node.asOperand().(SideEffectOperand).getUse())
|
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
|
* Gets the operand that represents the source value of `instr` if it's an instruction
|
||||||
* that behaves like a `LoadInstruction`.
|
* 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]
|
pragma[noopt]
|
||||||
private predicate hasMemoryOperandDefinition(
|
private predicate hasMemoryOperandDefinition(
|
||||||
OldInstruction oldInstruction, OldIR::NonPhiMemoryOperand oldOperand, Overlap overlap,
|
OldInstruction oldInstruction, OldIR::NonPhiMemoryOperand oldOperand, Overlap overlap,
|
||||||
|
|||||||
@@ -256,6 +256,12 @@ CppType getInstructionOperandType(Instruction instruction, TypedOperandTag tag)
|
|||||||
.getInstructionMemoryOperandType(getInstructionTag(instruction), tag)
|
.getInstructionMemoryOperandType(getInstructionTag(instruction), tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Instruction getPhiOperandDefinition(
|
||||||
|
PhiInstruction instruction, IRBlock predecessorBlock, Overlap overlap
|
||||||
|
) {
|
||||||
|
none()
|
||||||
|
}
|
||||||
|
|
||||||
Instruction getPhiInstructionBlockStart(PhiInstruction instr) { none() }
|
Instruction getPhiInstructionBlockStart(PhiInstruction instr) { none() }
|
||||||
|
|
||||||
Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
|
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]
|
pragma[noopt]
|
||||||
private predicate hasMemoryOperandDefinition(
|
private predicate hasMemoryOperandDefinition(
|
||||||
OldInstruction oldInstruction, OldIR::NonPhiMemoryOperand oldOperand, Overlap overlap,
|
OldInstruction oldInstruction, OldIR::NonPhiMemoryOperand oldOperand, Overlap overlap,
|
||||||
|
|||||||
@@ -205,81 +205,26 @@ private predicate deconstructSizeExpr(Expr sizeExpr, Expr lengthExpr, int sizeof
|
|||||||
sizeof = 1
|
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.
|
|
||||||
*/
|
|
||||||
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);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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`.
|
* An allocation expression that is a function call, such as call to `malloc`.
|
||||||
*/
|
*/
|
||||||
class CallAllocationExprImpl instanceof FunctionCall {
|
private class CallAllocationExpr extends AllocationExpr, FunctionCall {
|
||||||
Target target;
|
AllocationFunction target;
|
||||||
|
|
||||||
CallAllocationExprImpl() {
|
CallAllocationExpr() {
|
||||||
target = this.getTarget() and
|
target = this.getTarget() and
|
||||||
// realloc(ptr, 0) only frees the pointer
|
// realloc(ptr, 0) only frees the pointer
|
||||||
not (
|
not (
|
||||||
exists(getReallocPtrArg(target)) and
|
exists(target.getReallocPtrArg()) and
|
||||||
this.getArgument(getSizeArg(target)).getValue().toInt() = 0
|
this.getArgument(target.getSizeArg()).getValue().toInt() = 0
|
||||||
) and
|
) and
|
||||||
// these are modeled directly (and more accurately), avoid duplication
|
// these are modeled directly (and more accurately), avoid duplication
|
||||||
not exists(NewOrNewArrayExpr new | new.getAllocatorCall() = this)
|
not exists(NewOrNewArrayExpr new | new.getAllocatorCall() = this)
|
||||||
}
|
}
|
||||||
|
|
||||||
string toString() { result = super.toString() }
|
override Expr getSizeExpr() {
|
||||||
|
exists(Expr sizeExpr | sizeExpr = this.getArgument(target.getSizeArg()) |
|
||||||
Expr getSizeExprImpl() {
|
if exists(target.getSizeMult())
|
||||||
exists(Expr sizeExpr | sizeExpr = super.getArgument(getSizeArg(target)) |
|
|
||||||
if exists(getSizeMult(target))
|
|
||||||
then result = sizeExpr
|
then result = sizeExpr
|
||||||
else
|
else
|
||||||
exists(Expr lengthExpr |
|
exists(Expr lengthExpr |
|
||||||
@@ -289,65 +234,28 @@ private module CallAllocationExprBase<CallAllocationExprTarget Target> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
int getSizeMultImpl() {
|
override int getSizeMult() {
|
||||||
// malloc with multiplier argument that is a constant
|
// malloc with multiplier argument that is a constant
|
||||||
result = super.getArgument(getSizeMult(target)).getValue().toInt()
|
result = this.getArgument(target.getSizeMult()).getValue().toInt()
|
||||||
or
|
or
|
||||||
// malloc with no multiplier argument
|
// malloc with no multiplier argument
|
||||||
not exists(getSizeMult(target)) and
|
not exists(target.getSizeMult()) and
|
||||||
deconstructSizeExpr(super.getArgument(getSizeArg(target)), _, result)
|
deconstructSizeExpr(this.getArgument(target.getSizeArg()), _, result)
|
||||||
}
|
}
|
||||||
|
|
||||||
int getSizeBytesImpl() {
|
override int getSizeBytes() {
|
||||||
result = this.getSizeExprImpl().getValue().toInt() * this.getSizeMultImpl()
|
result = this.getSizeExpr().getValue().toInt() * this.getSizeMult()
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr getReallocPtrImpl() { result = super.getArgument(getReallocPtrArg(target)) }
|
override Expr getReallocPtr() { result = this.getArgument(target.getReallocPtrArg()) }
|
||||||
|
|
||||||
Type getAllocatedElementTypeImpl() {
|
override Type getAllocatedElementType() {
|
||||||
result =
|
result =
|
||||||
super.getFullyConverted().getType().stripTopLevelSpecifiers().(PointerType).getBaseType() and
|
this.getFullyConverted().getType().stripTopLevelSpecifiers().(PointerType).getBaseType() and
|
||||||
not result instanceof VoidType
|
not result instanceof VoidType
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate requiresDeallocImpl() { requiresDealloc(target) }
|
override predicate requiresDealloc() { target.requiresDealloc() }
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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() }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -386,99 +294,3 @@ private class NewArrayAllocationExpr extends AllocationExpr, NewArrayExpr {
|
|||||||
|
|
||||||
override predicate requiresDealloc() { not exists(this.getPlacementPointer()) }
|
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
|
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.fromSource() and
|
||||||
c.isTopLevel() and
|
c.isTopLevel() and
|
||||||
c.getParentScope() instanceof GlobalNamespace
|
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
|
t.fromSource() and
|
||||||
n = t.getMetrics().getEfferentSourceCoupling() and
|
n = t.getMetrics().getEfferentSourceCoupling() and
|
||||||
n > 10
|
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 = f.getMetrics().getNumberOfCalls() and
|
||||||
n > 99 and
|
n > 99 and
|
||||||
not f.isMultiplyDefined()
|
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
|
f.getMetrics().getNumberOfParameters() > 15
|
||||||
select f,
|
select f,
|
||||||
"This function has too many parameters (" + f.getMetrics().getNumberOfParameters().toString() +
|
"This function has too many parameters (" + f.getMetrics().getNumberOfParameters().toString() +
|
||||||
")."
|
")"
|
||||||
|
|||||||
@@ -21,5 +21,5 @@ where
|
|||||||
rhsType.getAMember() = m and
|
rhsType.getAMember() = m and
|
||||||
not m.(VirtualFunction).isPure()
|
not m.(VirtualFunction).isPure()
|
||||||
) // add additional checks for concrete members in in-between supertypes
|
) // 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()
|
lhsType, lhsType.getName()
|
||||||
|
|||||||
@@ -72,6 +72,18 @@ predicate floatTrivial(Literal lit) {
|
|||||||
|
|
||||||
predicate charLiteral(Literal lit) { lit instanceof CharLiteral }
|
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 numberType(Type t) { t instanceof FloatingPointType or t instanceof IntegralType }
|
||||||
|
|
||||||
predicate stringLiteral(Literal literal) { literal instanceof StringLiteral }
|
predicate stringLiteral(Literal literal) { literal instanceof StringLiteral }
|
||||||
|
|||||||
@@ -18,4 +18,4 @@ where
|
|||||||
f.hasSpecifier("virtual") and
|
f.hasSpecifier("virtual") and
|
||||||
f.getFile().fromSource() and
|
f.getFile().fromSource() and
|
||||||
not f instanceof Destructor
|
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
|
fclass = f.getDeclaringType() and
|
||||||
hubIndex = fclass.getMetrics().getAfferentCoupling() * fclass.getMetrics().getEfferentCoupling() and
|
hubIndex = fclass.getMetrics().getAfferentCoupling() * fclass.getMetrics().getEfferentCoupling() and
|
||||||
hubIndex > 100
|
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
|
sc = switch.getASwitchCase() and
|
||||||
tooLong(sc) and
|
tooLong(sc) and
|
||||||
switchCaseLength(sc, lines)
|
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)"
|
sc.getExpr().toString() + " (" + lines.toString() + " lines)"
|
||||||
|
|||||||
@@ -58,4 +58,4 @@ where
|
|||||||
not exists(AsmStmt s | f = s.getEnclosingFunction()) and
|
not exists(AsmStmt s | f = s.getEnclosingFunction()) and
|
||||||
not v.getAnAttribute().getName() = "unused" and
|
not v.getAnAttribute().getName() = "unused" and
|
||||||
not any(ErrorExpr e).getEnclosingFunction() = f // unextracted expr may use `v`
|
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"
|
||||||
|
|||||||
@@ -27,4 +27,4 @@ where
|
|||||||
not declarationHasSideEffects(v) and
|
not declarationHasSideEffects(v) and
|
||||||
not v.getAnAttribute().hasName("used") and
|
not v.getAnAttribute().hasName("used") and
|
||||||
not v.getAnAttribute().hasName("unused")
|
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.4
|
||||||
|
|
||||||
## 0.3.3
|
## 0.3.3
|
||||||
|
|||||||
@@ -64,5 +64,5 @@ where
|
|||||||
) and
|
) and
|
||||||
(if context = test then testresult = "succeed" else testresult = "fail")
|
(if context = test then testresult = "succeed" else testresult = "fail")
|
||||||
select cond,
|
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 + "."
|
||||||
|
|||||||
@@ -29,4 +29,4 @@ from Expr alloc
|
|||||||
where
|
where
|
||||||
allocateDescriptorCall(alloc) and
|
allocateDescriptorCall(alloc) and
|
||||||
not exists(ClosedExpr closed | closed.pointsTo() = alloc)
|
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
|
fopenVariableReaches(v, def, ret) and
|
||||||
ret.getAChild*() = v.getAnAccess()
|
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
|
from Expr alloc
|
||||||
where fopenCall(alloc) and not fopenCallMayBeClosed(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)
|
definitionUsePair(v, other, unchecked)
|
||||||
)
|
)
|
||||||
select 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"
|
||||||
|
|||||||
@@ -190,4 +190,4 @@ where
|
|||||||
allocatedVariableReaches(v, def, ret) and
|
allocatedVariableReaches(v, def, ret) and
|
||||||
ret.getAChild*() = v.getAnAccess()
|
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
|
where
|
||||||
alloc.requiresDealloc() and
|
alloc.requiresDealloc() and
|
||||||
not allocMayBeFreed(alloc)
|
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.getCall() = call and
|
||||||
output.hasGuardedAccess(access, false)
|
output.hasGuardedAccess(access, false)
|
||||||
select access,
|
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 " +
|
"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
|
where
|
||||||
allocReaches(freed, alloc, "new[]") and
|
allocReaches(freed, alloc, "new[]") and
|
||||||
freeExprOrIndirect(free, freed, "delete")
|
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
|
where
|
||||||
allocReaches(freed, alloc, "new") and
|
allocReaches(freed, alloc, "new") and
|
||||||
freeExprOrIndirect(free, freed, "delete[]")
|
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 v.getType().getUnderlyingType() instanceof ReferenceType and
|
||||||
not exists(ScopeUtilityClass util | def = util.getAUse()) and
|
not exists(ScopeUtilityClass util | def = util.getAUse()) and
|
||||||
not def.isInMacroExpansion()
|
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
|
from UseAfterFreeReachability r, StackVariable v, Expr free, Expr e
|
||||||
where r.reaches(free, v, e)
|
where r.reaches(free, v, e)
|
||||||
select e, "Memory pointed to by '" + v.getName().toString() + "' may have $@.", free,
|
select e, "Memory pointed to by '" + v.getName().toString() + "' may have been previously freed $@",
|
||||||
"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.
|
* @description Lists all files in the source code directory that were extracted without encountering a problem in the file.
|
||||||
* @kind diagnostic
|
* @kind diagnostic
|
||||||
* @id cpp/diagnostics/successfully-extracted-files
|
* @id cpp/diagnostics/successfully-extracted-files
|
||||||
* @tags successfully-extracted-files
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import cpp
|
import cpp
|
||||||
@@ -13,4 +12,4 @@ from File f
|
|||||||
where
|
where
|
||||||
not exists(ExtractionProblem e | e.getFile() = f) and
|
not exists(ExtractionProblem e | e.getFile() = f) and
|
||||||
exists(f.getRelativePath())
|
exists(f.getRelativePath())
|
||||||
select f, "File successfully extracted."
|
select f, "File successfully extracted"
|
||||||
|
|||||||
@@ -22,4 +22,4 @@ where
|
|||||||
not overflowTest(cmp) and
|
not overflowTest(cmp) and
|
||||||
not cmp.isFromTemplateInstantiation(_) and
|
not cmp.isFromTemplateInstantiation(_) and
|
||||||
not isFromMacroDefinition(cmp)
|
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) {
|
override predicate isSource(DataFlow::Node node) {
|
||||||
not node.asExpr() instanceof Conversion and
|
not node.asExpr() instanceof Conversion and
|
||||||
exists(Type baseType1, Type baseType2 |
|
introducesNewField(node.asExpr().getType().(DerivedType).getBaseType(),
|
||||||
hasBaseType(node.asExpr(), baseType1) and
|
node.asExpr().getConversion*().getType().(DerivedType).getBaseType())
|
||||||
hasBaseType(node.asExpr().getConversion*(), baseType2) and
|
|
||||||
introducesNewField(baseType1, baseType2)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node node) {
|
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
|
* `derived` has a (possibly indirect) base class of `base`, and at least one new
|
||||||
* field has been introduced in the inheritance chain after `base`.
|
* field has been introduced in the inheritance chain after `base`.
|
||||||
@@ -69,5 +55,5 @@ where
|
|||||||
cfg.hasFlowPath(source, sink) and
|
cfg.hasFlowPath(source, sink) and
|
||||||
source.getNode().asExpr().getFullyConverted().getUnspecifiedType() =
|
source.getNode().asExpr().getFullyConverted().getUnspecifiedType() =
|
||||||
sink.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 $@.",
|
select sink, source, sink,
|
||||||
source, "this cast"
|
"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.getExplicitlyConverted().getType().getSize() > fct.getSize() and
|
||||||
va.getTarget() = fi and
|
va.getTarget() = fi and
|
||||||
not fct.getUnspecifiedType() instanceof BoolType
|
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
|
c.hasImplicitConversion() and
|
||||||
not whiteListWrapped(c)
|
not whiteListWrapped(c)
|
||||||
select 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
|
not actual.getUnspecifiedType() instanceof ErroneousType
|
||||||
select arg,
|
select arg,
|
||||||
"This argument should be of type '" + expected.getName() + "' but is of type '" +
|
"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
|
from Expr source, Expr sink, PossibleYearArithmeticOperationCheckConfiguration config
|
||||||
where config.hasFlow(DataFlow::exprNode(source), DataFlow::exprNode(sink))
|
where config.hasFlow(DataFlow::exprNode(source), DataFlow::exprNode(sink))
|
||||||
select sink,
|
select sink,
|
||||||
"An arithmetic operation $@ that uses a constant value of 365 ends up modifying this date/time, without considering leap year scenarios.",
|
"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()
|
source, source.toString(), sink, sink.toString()
|
||||||
|
|||||||
@@ -13,4 +13,4 @@ import NtohlArrayNoBound
|
|||||||
|
|
||||||
from NetworkToBufferSizeConfiguration bufConfig, DataFlow::Node source, DataFlow::Node sink
|
from NetworkToBufferSizeConfiguration bufConfig, DataFlow::Node source, DataFlow::Node sink
|
||||||
where bufConfig.hasFlow(source, 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()
|
||||||
|
|||||||
@@ -81,4 +81,4 @@ from UninitialisedLocalReachability r, LocalVariable v, VariableAccess va
|
|||||||
where
|
where
|
||||||
r.reaches(_, v, va) and
|
r.reaches(_, v, va) and
|
||||||
not va = commonException()
|
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
|
) and
|
||||||
source.asStore() = store and
|
source.asStore() = store and
|
||||||
sink.asSink(_) = load
|
sink.asSink(_) = load
|
||||||
select sink, source, sink, "Stack variable $@ escapes at $@ and is used after it has expired.", var,
|
select sink, source, sink, "Stack variable $@ escapes $@ and is used after it has expired.", var,
|
||||||
var.toString(), store, "this store"
|
var.toString(), store, "here"
|
||||||
|
|||||||
@@ -83,4 +83,4 @@ where
|
|||||||
c.getAMemberFunction().getAnOverriddenFunction() = call.getStaticCallTarget()
|
c.getAMemberFunction().getAnOverriddenFunction() = call.getStaticCallTarget()
|
||||||
)
|
)
|
||||||
select call.getUnconvertedResultExpression(), source, sink,
|
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
|
isOptionSet(cc, BoostorgAsio::getShiftedSslOptionsNoTls1_2(), e) and
|
||||||
msg = "no_tlsv1_2 was set"
|
msg = "no_tlsv1_2 was set"
|
||||||
)
|
)
|
||||||
select cc,
|
select cc, "Usage of $@ with protocol $@ is not configured correctly: The option $@.", cc,
|
||||||
"This usage of 'boost::asio::ssl::context::context' with protocol $@ is not configured correctly: The option $@.",
|
"boost::asio::ssl::context::context", protocolSource, protocolSource.toString(), e, msg
|
||||||
protocolSource, protocolSource.toString(), e, msg
|
|
||||||
|
|||||||
@@ -67,5 +67,5 @@ where
|
|||||||
// the pointer was null. To follow this idea to its full generality, we
|
// the pointer was null. To follow this idea to its full generality, we
|
||||||
// should also give an alert when `check` post-dominates `deref`.
|
// should also give an alert when `check` post-dominates `deref`.
|
||||||
deref.getBlock() = dominator
|
deref.getBlock() = dominator
|
||||||
select checked, "This null check is redundant because $@ in any case.", deref,
|
select checked, "This null check is redundant because the value is $@ in any case", deref,
|
||||||
"the value is dereferenced"
|
"dereferenced here"
|
||||||
|
|||||||
@@ -60,5 +60,5 @@ where
|
|||||||
taintedWithPath(taintSource, taintedArg, sourceNode, sinkNode) and
|
taintedWithPath(taintSource, taintedArg, sourceNode, sinkNode) and
|
||||||
isUserInput(taintSource, taintCause)
|
isUserInput(taintSource, taintCause)
|
||||||
select taintedArg, sourceNode, sinkNode,
|
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 + ")"
|
taintSource, "user input (" + taintCause + ")"
|
||||||
|
|||||||
@@ -158,5 +158,5 @@ where
|
|||||||
concatResult = sinkNode.getState().(ExecState).getSndNode()
|
concatResult = sinkNode.getState().(ExecState).getSndNode()
|
||||||
select sinkAsArgumentIndirection(sinkNode.getNode()), sourceNode, sinkNode,
|
select sinkAsArgumentIndirection(sinkNode.getNode()), sourceNode, sinkNode,
|
||||||
"This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to "
|
"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()
|
concatResult.toString()
|
||||||
|
|||||||
@@ -50,5 +50,5 @@ where
|
|||||||
taintedWithPath(taintSource, taintedArg, sourceNode, sinkNode) and
|
taintedWithPath(taintSource, taintedArg, sourceNode, sinkNode) and
|
||||||
isUserInput(taintSource, taintCause)
|
isUserInput(taintSource, taintCause)
|
||||||
select taintedArg, sourceNode, sinkNode,
|
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 + ")"
|
taintSource, "user input (" + taintCause + ")"
|
||||||
|
|||||||
@@ -34,5 +34,5 @@ where
|
|||||||
isProcessOperationExplanation(arg, processOperation) and
|
isProcessOperationExplanation(arg, processOperation) and
|
||||||
taintedWithPath(source, arg, sourceNode, sinkNode)
|
taintedWithPath(source, arg, sourceNode, sinkNode)
|
||||||
select arg, sourceNode, sinkNode,
|
select arg, sourceNode, sinkNode,
|
||||||
"The value of this argument may come from $@ and is being passed to " + processOperation + ".",
|
"The value of this argument may come from $@ and is being passed to " + processOperation, source,
|
||||||
source, source.toString()
|
source.toString()
|
||||||
|
|||||||
@@ -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
|
from
|
||||||
ImproperArrayIndexValidationConfig conf, DataFlow::PathNode source, DataFlow::PathNode sink,
|
ImproperArrayIndexValidationConfig conf, DataFlow::PathNode source, DataFlow::PathNode sink,
|
||||||
string sourceType
|
string sourceType
|
||||||
@@ -127,5 +123,5 @@ where
|
|||||||
conf.hasFlowPath(source, sink) and
|
conf.hasFlowPath(source, sink) and
|
||||||
isFlowSource(source.getNode(), sourceType)
|
isFlowSource(source.getNode(), sourceType)
|
||||||
select sink.getNode(), source, sink,
|
select sink.getNode(), source, sink,
|
||||||
"An array indexing expression depends on $@ that might be outside the bounds of the array.",
|
"$@ flows to here and is used in an array indexing expression, potentially causing an invalid access.",
|
||||||
source.getNode(), lowerFirst(sourceType)
|
source.getNode(), sourceType
|
||||||
|
|||||||
@@ -34,4 +34,4 @@ where
|
|||||||
isUserInput(userValue, cause)
|
isUserInput(userValue, cause)
|
||||||
select arg, sourceNode, sinkNode,
|
select arg, sourceNode, sinkNode,
|
||||||
"The value of this argument may come from $@ and is being used as a formatting argument to " +
|
"The value of this argument may come from $@ and is being used as a formatting argument to " +
|
||||||
printfFunction + ".", userValue, cause
|
printfFunction, userValue, cause
|
||||||
|
|||||||
@@ -37,4 +37,4 @@ where
|
|||||||
isUserInput(userValue, cause)
|
isUserInput(userValue, cause)
|
||||||
select arg, sourceNode, sinkNode,
|
select arg, sourceNode, sinkNode,
|
||||||
"The value of this argument may come from $@ and is being used as a formatting argument to " +
|
"The value of this argument may come from $@ and is being used as a formatting argument to " +
|
||||||
printfFunction + ".", userValue, cause
|
printfFunction, userValue, cause
|
||||||
|
|||||||
@@ -86,5 +86,4 @@ class TaintSource extends VariableAccess {
|
|||||||
|
|
||||||
from TaintSource source, VariableAccess sink
|
from TaintSource source, VariableAccess sink
|
||||||
where source.reaches(sink)
|
where source.reaches(sink)
|
||||||
select sink, "String operation depends on a $@ that may not be null terminated.", source,
|
select sink, "$@ flows to here and may not be null terminated.", source, "User-provided value"
|
||||||
"user-provided value"
|
|
||||||
|
|||||||
@@ -50,5 +50,5 @@ where
|
|||||||
op.getAnOperand() = e and
|
op.getAnOperand() = e and
|
||||||
missingGuard(op, e, effect)
|
missingGuard(op, e, effect)
|
||||||
select e, sourceNode, sinkNode,
|
select e, sourceNode, sinkNode,
|
||||||
"$@ flows to an operand of an arithmetic expression, potentially causing an " + effect + ".",
|
"$@ flows to here and is used in arithmetic, potentially causing an " + effect + ".", origin,
|
||||||
origin, "User-provided value"
|
"User-provided value"
|
||||||
|
|||||||
@@ -135,5 +135,5 @@ where
|
|||||||
sink.getNode().asExpr() = va and
|
sink.getNode().asExpr() = va and
|
||||||
missingGuard(va, effect)
|
missingGuard(va, effect)
|
||||||
select sink.getNode(), source, sink,
|
select sink.getNode(), source, sink,
|
||||||
"Arithmetic expression depends on an $@, potentially causing an " + effect + ".",
|
"$@ flows to here and is used in arithmetic, potentially causing an " + effect + ".",
|
||||||
getExpr(source.getNode()), "uncontrolled value"
|
getExpr(source.getNode()), "Uncontrolled value"
|
||||||
|
|||||||
@@ -75,6 +75,5 @@ where
|
|||||||
missingGuardAgainstOverflow(op, va) and effect = "overflow"
|
missingGuardAgainstOverflow(op, va) and effect = "overflow"
|
||||||
) and
|
) and
|
||||||
causeEffectCorrespond(cause, effect)
|
causeEffectCorrespond(cause, effect)
|
||||||
select va,
|
select va, "$@ flows to here and is used in arithmetic, potentially causing an " + effect + ".",
|
||||||
"$@ flows to an operand of an arithmetic expression, potentially causing an " + effect + ".",
|
|
||||||
origin, "Extreme value"
|
origin, "Extreme value"
|
||||||
|
|||||||
@@ -36,4 +36,5 @@ where
|
|||||||
not inSystemMacroExpansion(use) and
|
not inSystemMacroExpansion(use) and
|
||||||
// Avoid double-counting: don't include all the conversions of `use`.
|
// Avoid double-counting: don't include all the conversions of `use`.
|
||||||
not use instanceof Conversion
|
not use instanceof Conversion
|
||||||
select use, "$@ flows an expression which might " + kind + ".", origin, "User-provided value"
|
select use, "$@ flows to here and is used in an expression which might " + kind + ".", origin,
|
||||||
|
"User-provided value"
|
||||||
|
|||||||
@@ -99,5 +99,5 @@ where
|
|||||||
isFlowSource(source.getNode(), taintCause) and
|
isFlowSource(source.getNode(), taintCause) and
|
||||||
conf.hasFlowPath(source, sink) and
|
conf.hasFlowPath(source, sink) and
|
||||||
allocSink(alloc, sink.getNode())
|
allocSink(alloc, sink.getNode())
|
||||||
select alloc, source, sink, "This allocation size is derived from $@ and might overflow.",
|
select alloc, source, sink, "This allocation size is derived from $@ and might overflow",
|
||||||
source.getNode(), "user input (" + taintCause + ")"
|
source.getNode(), "user input (" + taintCause + ")"
|
||||||
|
|||||||
@@ -39,13 +39,9 @@ where
|
|||||||
isHresultBooleanConverted(e1, e2) and
|
isHresultBooleanConverted(e1, e2) and
|
||||||
if e2.isImplicit()
|
if e2.isImplicit()
|
||||||
then
|
then
|
||||||
msg =
|
msg = "Implicit conversion from " + e1.getType().toString() + " to " + e2.getType().toString()
|
||||||
"Implicit conversion from " + e1.getType().toString() + " to " + e2.getType().toString() +
|
|
||||||
"."
|
|
||||||
else
|
else
|
||||||
msg =
|
msg = "Explicit conversion from " + e1.getType().toString() + " to " + e2.getType().toString()
|
||||||
"Explicit conversion from " + e1.getType().toString() + " to " + e2.getType().toString() +
|
|
||||||
"."
|
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(ControlStructure ctls |
|
exists(ControlStructure ctls |
|
||||||
@@ -53,7 +49,7 @@ where
|
|||||||
e1.getType().(TypedefType).hasName("HRESULT") and
|
e1.getType().(TypedefType).hasName("HRESULT") and
|
||||||
not isHresultBooleanConverted(e1) and
|
not isHresultBooleanConverted(e1) and
|
||||||
not ctls instanceof SwitchStmt and // not controlled by a boolean condition
|
not ctls instanceof SwitchStmt and // not controlled by a boolean condition
|
||||||
msg = "Direct usage of a type " + e1.getType().toString() + " as a conditional expression."
|
msg = "Direct usage of a type " + e1.getType().toString() + " as a conditional expression"
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
(
|
(
|
||||||
@@ -61,14 +57,14 @@ where
|
|||||||
e1.getType().(TypedefType).hasName("HRESULT") and
|
e1.getType().(TypedefType).hasName("HRESULT") and
|
||||||
msg =
|
msg =
|
||||||
"Usage of a type " + e1.getType().toString() +
|
"Usage of a type " + e1.getType().toString() +
|
||||||
" as an argument of a binary logical operation."
|
" as an argument of a binary logical operation"
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(UnaryLogicalOperation ulop | ulop.getAnOperand() = e1 |
|
exists(UnaryLogicalOperation ulop | ulop.getAnOperand() = e1 |
|
||||||
e1.getType().(TypedefType).hasName("HRESULT") and
|
e1.getType().(TypedefType).hasName("HRESULT") and
|
||||||
msg =
|
msg =
|
||||||
"Usage of a type " + e1.getType().toString() +
|
"Usage of a type " + e1.getType().toString() +
|
||||||
" as an argument of a unary logical operation."
|
" as an argument of a unary logical operation"
|
||||||
) and
|
) and
|
||||||
not isHresultBooleanConverted(e1)
|
not isHresultBooleanConverted(e1)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -44,5 +44,5 @@ where
|
|||||||
w.getASource() = sinkNode.getNode().asExpr() and
|
w.getASource() = sinkNode.getNode().asExpr() and
|
||||||
dest = w.getDest()
|
dest = w.getDest()
|
||||||
select w, sourceNode, sinkNode,
|
select w, sourceNode, sinkNode,
|
||||||
"This write into buffer '" + dest.toString() + "' may contain unencrypted data from $@.", source,
|
"This write into buffer '" + dest.toString() + "' may contain unencrypted data from $@", source,
|
||||||
"user input (" + source.getSourceType() + ")"
|
"user input (" + source.getSourceType() + ")"
|
||||||
|
|||||||
@@ -73,5 +73,5 @@ where
|
|||||||
not isFileName(globalValueNumber(source)) and // file names are not passwords
|
not isFileName(globalValueNumber(source)) and // file names are not passwords
|
||||||
not exists(string convChar | convChar = w.getSourceConvChar(mid) | not convChar = ["s", "S"]) // ignore things written with other conversion characters
|
not exists(string convChar | convChar = w.getSourceConvChar(mid) | not convChar = ["s", "S"]) // ignore things written with other conversion characters
|
||||||
select w, sourceNode, midNode,
|
select w, sourceNode, midNode,
|
||||||
"This write into file '" + dest.toString() + "' may contain unencrypted data from $@.", source,
|
"This write into file '" + dest.toString() + "' may contain unencrypted data from $@", source,
|
||||||
"this source."
|
"this source."
|
||||||
|
|||||||
@@ -258,9 +258,9 @@ where
|
|||||||
then
|
then
|
||||||
msg =
|
msg =
|
||||||
"This operation transmits '" + sink.toString() +
|
"This operation transmits '" + sink.toString() +
|
||||||
"', which may contain unencrypted sensitive data from $@."
|
"', which may contain unencrypted sensitive data from $@"
|
||||||
else
|
else
|
||||||
msg =
|
msg =
|
||||||
"This operation receives into '" + sink.toString() +
|
"This operation receives into '" + sink.toString() +
|
||||||
"', which may put unencrypted sensitive data into $@."
|
"', which may put unencrypted sensitive data into $@"
|
||||||
select networkSendRecv, source, sink, msg, source, source.getNode().toString()
|
select networkSendRecv, source, sink, msg, source, source.getNode().toString()
|
||||||
|
|||||||
@@ -74,6 +74,5 @@ where
|
|||||||
config.hasFlowPath(source, sink) and
|
config.hasFlowPath(source, sink) and
|
||||||
source.getNode().asExpr() = sensitive and
|
source.getNode().asExpr() = sensitive and
|
||||||
sqliteCall.getASource() = sink.getNode().asExpr()
|
sqliteCall.getASource() = sink.getNode().asExpr()
|
||||||
select sqliteCall, source, sink,
|
select sqliteCall, source, sink, "This SQLite call may store $@ in a non-encrypted SQLite database",
|
||||||
"This SQLite call may store $@ in a non-encrypted SQLite database.", sensitive,
|
sensitive, "sensitive information"
|
||||||
"sensitive information"
|
|
||||||
|
|||||||
@@ -97,4 +97,4 @@ from
|
|||||||
where
|
where
|
||||||
config.hasFlowPath(source, sink) and
|
config.hasFlowPath(source, sink) and
|
||||||
str = source.getNode().asExpr()
|
str = source.getNode().asExpr()
|
||||||
select str, source, sink, "This URL may be constructed with the HTTP protocol."
|
select str, source, sink, "A URL may be constructed with the HTTP protocol."
|
||||||
|
|||||||
@@ -10,6 +10,12 @@ private predicate reaches(ControlFlowNode a, ControlFlowNode b) = fastTC(success
|
|||||||
|
|
||||||
private predicate successor(ControlFlowNode a, ControlFlowNode b) { b = a.getASuccessor() }
|
private predicate successor(ControlFlowNode a, ControlFlowNode b) { b = a.getASuccessor() }
|
||||||
|
|
||||||
|
class WhitelistedCallsConfig extends string {
|
||||||
|
WhitelistedCallsConfig() { this = "config" }
|
||||||
|
|
||||||
|
abstract predicate isWhitelisted(Call c);
|
||||||
|
}
|
||||||
|
|
||||||
abstract class WhitelistedCall extends Call {
|
abstract class WhitelistedCall extends Call {
|
||||||
override Function getTarget() { none() }
|
override Function getTarget() { none() }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,5 +44,5 @@ where
|
|||||||
)
|
)
|
||||||
select dest,
|
select dest,
|
||||||
"This pointer might have type $@ (size " + sourceBase.getSize() +
|
"This pointer might have type $@ (size " + sourceBase.getSize() +
|
||||||
"), but this pointer arithmetic is done with type " + destType + " (size " + destBase.getSize() +
|
"), but the pointer arithmetic here is done with type " + destType + " (size " +
|
||||||
").", sourceLoc, sourceBase.toString()
|
destBase.getSize() + ").", sourceLoc, sourceBase.toString()
|
||||||
|
|||||||
@@ -51,5 +51,5 @@ where
|
|||||||
destBase instanceof CharType
|
destBase instanceof CharType
|
||||||
select dest,
|
select dest,
|
||||||
"This pointer might have type $@ (size " + sourceBase.getSize() +
|
"This pointer might have type $@ (size " + sourceBase.getSize() +
|
||||||
"), but this pointer arithmetic is done with type " + destType + " (size " + destBase.getSize() +
|
"), but the pointer arithmetic here is done with type " + destType + " (size " +
|
||||||
").", sourceLoc, sourceBase.toString()
|
destBase.getSize() + ").", sourceLoc, sourceBase.toString()
|
||||||
|
|||||||
@@ -26,4 +26,4 @@ where
|
|||||||
destBase instanceof VoidType
|
destBase instanceof VoidType
|
||||||
select dest,
|
select dest,
|
||||||
"This pointer might have type $@ (size " + sourceBase.getSize() +
|
"This pointer might have type $@ (size " + sourceBase.getSize() +
|
||||||
"), but this pointer arithmetic is done with type void.", sourceLoc, sourceBase.toString()
|
"), but the pointer arithmetic here is done with type void", sourceLoc, sourceBase.toString()
|
||||||
|
|||||||
@@ -18,4 +18,4 @@ from FunctionCall call, Function target
|
|||||||
where
|
where
|
||||||
call.getTarget() = target and
|
call.getTarget() = target and
|
||||||
target.hasGlobalOrStdName("gets")
|
target.hasGlobalOrStdName("gets")
|
||||||
select call, "'gets' does not guard against buffer overflow."
|
select call, "gets does not guard against buffer overflow"
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import cpp
|
|||||||
predicate potentiallyDangerousFunction(Function f, string message) {
|
predicate potentiallyDangerousFunction(Function f, string message) {
|
||||||
exists(string name | f.hasGlobalName(name) |
|
exists(string name | f.hasGlobalName(name) |
|
||||||
name = ["gmtime", "localtime", "ctime", "asctime"] and
|
name = ["gmtime", "localtime", "ctime", "asctime"] and
|
||||||
message = "Call to '" + name + "' is potentially dangerous."
|
message = "Call to " + name + " is potentially dangerous"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,4 +16,4 @@ import FilePermissions
|
|||||||
from FileCreationWithOptionalModeExpr fc
|
from FileCreationWithOptionalModeExpr fc
|
||||||
where not fc.hasModeArgument()
|
where not fc.hasModeArgument()
|
||||||
select fc,
|
select fc,
|
||||||
"This creates a file without providing a mode argument, which may leak bits from the stack."
|
"A file is created here without providing a mode argument, which may leak bits from the stack."
|
||||||
|
|||||||
@@ -37,5 +37,5 @@ from Expr source, Expr condition, Expr raise, PathNode sourceNode, PathNode sink
|
|||||||
where
|
where
|
||||||
taintedWithPath(source, condition, sourceNode, sinkNode) and
|
taintedWithPath(source, condition, sourceNode, sinkNode) and
|
||||||
sensitiveCondition(condition, raise)
|
sensitiveCondition(condition, raise)
|
||||||
select condition, sourceNode, sinkNode, "Reliance on untrusted input $@ to raise privilege at $@.",
|
select condition, sourceNode, sinkNode, "Reliance on untrusted input $@ to raise privilege at $@",
|
||||||
source, source.toString(), raise, raise.toString()
|
source, source.toString(), raise, raise.toString()
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user