Merge branch 'main' into redsun82/swift-action-triggers

This commit is contained in:
Paolo Tranquilli 2022-09-20 14:23:22 +02:00 коммит произвёл GitHub
Родитель 9d3039f2b1 ea743173d5
Коммит 9fb4ff70b4
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
111 изменённых файлов: 5629 добавлений и 360 удалений

Просмотреть файл

@ -32,6 +32,14 @@ jobs:
- name: Build Swift extractor
run: |
bazel run //swift:create-extractor-pack
- name: Get Swift version
id: get_swift_version
run: |
VERSION=$(bazel run //swift/extractor -- --version | sed -ne 's/.*version \(\S*\).*/\1/p')
echo "::set-output name=version::$VERSION"
- uses: swift-actions/setup-swift@v1
with:
swift-version: "${{steps.get_swift_version.outputs.version}}"
- name: Run integration tests
run: |
python integration-tests/runner.py

Просмотреть файл

@ -73,10 +73,11 @@
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplConsistency.qll",
"swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImplConsistency.qll"
],
"DataFlow Java/C# Flow Summaries": [
"DataFlow Java/C#/Ruby/Python/Swift Flow Summaries": [
"java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll",
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/FlowSummaryImpl.qll",
"python/ql/lib/semmle/python/dataflow/new/internal/FlowSummaryImpl.qll",
"swift/ql/lib/codeql/swift/dataflow/internal/FlowSummaryImpl.qll"
],
"SsaReadPosition Java/C#": [
@ -532,7 +533,7 @@
"java/ql/lib/semmle/code/java/dataflow/internal/AccessPathSyntax.qll",
"javascript/ql/lib/semmle/javascript/frameworks/data/internal/AccessPathSyntax.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/AccessPathSyntax.qll",
"python/ql/lib/semmle/python/frameworks/data/internal/AccessPathSyntax.qll",
"python/ql/lib/semmle/python/dataflow/new/internal/AccessPathSyntax.qll",
"swift/ql/lib/codeql/swift/dataflow/internal/AccessPathSyntax.qll"
],
"IncompleteUrlSubstringSanitization": [

Просмотреть файл

@ -1,5 +1,5 @@
import semmle.code.cpp.ir.dataflow.DataFlow
import semmle.code.cpp.ir.dataflow.DataFlow2
import experimental.semmle.code.cpp.ir.dataflow.DataFlow
import experimental.semmle.code.cpp.ir.dataflow.DataFlow2
module ProductFlow {
abstract class Configuration extends string {
@ -11,14 +11,43 @@ module ProductFlow {
*
* `source1` and `source2` must belong to the same callable.
*/
abstract predicate isSourcePair(DataFlow::Node source1, DataFlow::Node source2);
predicate isSourcePair(DataFlow::Node source1, DataFlow::Node source2) { none() }
/**
* Holds if `(source1, source2)` is a relevant data flow source with initial states `state1`
* and `state2`, respectively.
*
* `source1` and `source2` must belong to the same callable.
*/
predicate isSourcePair(
DataFlow::Node source1, string state1, DataFlow::Node source2, string state2
) {
state1 = "" and
state2 = "" and
this.isSourcePair(source1, source2)
}
/**
* Holds if `(sink1, sink2)` is a relevant data flow sink.
*
* `sink1` and `sink2` must belong to the same callable.
*/
abstract predicate isSinkPair(DataFlow::Node sink1, DataFlow::Node sink2);
predicate isSinkPair(DataFlow::Node sink1, DataFlow::Node sink2) { none() }
/**
* Holds if `(sink1, sink2)` is a relevant data flow sink with final states `state1`
* and `state2`, respectively.
*
* `sink1` and `sink2` must belong to the same callable.
*/
predicate isSinkPair(
DataFlow::Node sink1, DataFlow::FlowState state1, DataFlow::Node sink2,
DataFlow::FlowState state2
) {
state1 = "" and
state2 = "" and
this.isSinkPair(sink1, sink2)
}
predicate hasFlowPath(
DataFlow::PathNode source1, DataFlow2::PathNode source2, DataFlow::PathNode sink1,
@ -34,28 +63,28 @@ module ProductFlow {
class Conf1 extends DataFlow::Configuration {
Conf1() { this = "Conf1" }
override predicate isSource(DataFlow::Node source) {
exists(Configuration conf | conf.isSourcePair(source, _))
override predicate isSource(DataFlow::Node source, string state) {
exists(Configuration conf | conf.isSourcePair(source, state, _, _))
}
override predicate isSink(DataFlow::Node sink) {
exists(Configuration conf | conf.isSinkPair(sink, _))
override predicate isSink(DataFlow::Node sink, string state) {
exists(Configuration conf | conf.isSinkPair(sink, state, _, _))
}
}
class Conf2 extends DataFlow2::Configuration {
Conf2() { this = "Conf2" }
override predicate isSource(DataFlow::Node source) {
override predicate isSource(DataFlow::Node source, string state) {
exists(Configuration conf, DataFlow::Node source1 |
conf.isSourcePair(source1, source) and
conf.isSourcePair(source1, _, source, state) and
any(Conf1 c).hasFlow(source1, _)
)
}
override predicate isSink(DataFlow::Node sink) {
override predicate isSink(DataFlow::Node sink, string state) {
exists(Configuration conf, DataFlow::Node sink1 |
conf.isSinkPair(sink1, sink) and any(Conf1 c).hasFlow(_, sink1)
conf.isSinkPair(sink1, _, sink, state) and any(Conf1 c).hasFlow(_, sink1)
)
}
}
@ -65,7 +94,7 @@ module ProductFlow {
Configuration conf, DataFlow::PathNode source1, DataFlow2::PathNode source2,
DataFlow::PathNode node1, DataFlow2::PathNode node2
) {
conf.isSourcePair(node1.getNode(), node2.getNode()) and
conf.isSourcePair(node1.getNode(), _, node2.getNode(), _) and
node1 = source1 and
node2 = source2
or
@ -128,7 +157,7 @@ module ProductFlow {
) {
exists(DataFlow::PathNode mid1, DataFlow2::PathNode mid2 |
reachableInterprocEntry(conf, source1, source2, mid1, mid2) and
conf.isSinkPair(sink1.getNode(), sink2.getNode()) and
conf.isSinkPair(sink1.getNode(), _, sink2.getNode(), _) and
localPathStep1*(mid1, sink1) and
localPathStep2*(mid2, sink2)
)

Просмотреть файл

@ -28,6 +28,10 @@ private newtype TBound =
i.(LoadInstruction).getSourceAddress() instanceof FieldAddressInstruction
or
i.getAUse() instanceof ArgumentOperand
or
i instanceof PointerArithmeticInstruction
or
i.getAUse() instanceof AddressOperand
)
}

Просмотреть файл

@ -178,11 +178,11 @@ class SemRelationalExpr extends SemBinaryExpr {
}
class SemAddExpr extends SemBinaryExpr {
SemAddExpr() { opcode instanceof Opcode::Add }
SemAddExpr() { opcode instanceof Opcode::Add or opcode instanceof Opcode::PointerAdd }
}
class SemSubExpr extends SemBinaryExpr {
SemSubExpr() { opcode instanceof Opcode::Sub }
SemSubExpr() { opcode instanceof Opcode::Sub or opcode instanceof Opcode::PointerSub }
}
class SemMulExpr extends SemBinaryExpr {

Просмотреть файл

@ -65,10 +65,18 @@ module Opcode {
override string toString() { result = "Add" }
}
class PointerAdd extends Opcode, TPointerAdd {
override string toString() { result = "PointerAdd" }
}
class Sub extends Opcode, TSub {
override string toString() { result = "Sub" }
}
class PointerSub extends Opcode, TPointerSub {
override string toString() { result = "PointerSub" }
}
class Mul extends Opcode, TMul {
override string toString() { result = "Mul" }
}

Просмотреть файл

@ -223,7 +223,9 @@ private SemGuard boundFlowCond(
else resultIsStrict = testIsTrue.booleanNot()
) and
(
if getTrackedTypeForSsaVariable(v) instanceof SemIntegerType
if
getTrackedTypeForSsaVariable(v) instanceof SemIntegerType or
getTrackedTypeForSsaVariable(v) instanceof SemAddressType
then
upper = true and strengthen = -1
or

Просмотреть файл

@ -0,0 +1,26 @@
void *malloc(unsigned);
unsigned get_size();
void write_data(const unsigned char*, const unsigned char*);
int main(int argc, char* argv[]) {
unsigned size = get_size();
{
unsigned char *begin = (unsigned char*)malloc(size);
if(!begin) return -1;
unsigned char* end = begin + size;
write_data(begin, end);
*end = '\0'; // BAD: Out-of-bounds write
}
{
unsigned char *begin = (unsigned char*)malloc(size);
if(!begin) return -1;
unsigned char* end = begin + size;
write_data(begin, end);
*(end - 1) = '\0'; // GOOD: writing to the last byte
}
}

Просмотреть файл

@ -0,0 +1,31 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>The program performs an out-of-bounds read or write operation. In addition to causing program instability, techniques exist which may allow an attacker to use this vulnerability to execute arbitrary code.</p>
</overview>
<recommendation>
<p>Ensure that pointer dereferences are properly guarded to ensure that they cannot be used to read or write past the end of the allocation.</p>
</recommendation>
<example>
<p>The first example allocates a buffer of size <code>size</code> and creates a local variable that stores the location that is one byte past the end of the allocation.
This local variable is then dereferenced which results in an out-of-bounds write.
The second example subtracts one from the <code>end</code> variable before dereferencing it. This subtraction ensures that the write correctly updates the final byte of the allocation.</p>
<sample src="InvalidPointerDeref.cpp" />
</example>
<references>
<li>CERT C Coding Standard:
<a href="https://wiki.sei.cmu.edu/confluence/display/c/ARR30-C.+Do+not+form+or+use+out-of-bounds+pointers+or+array+subscripts">ARR30-C. Do not form or use out-of-bounds pointers or array subscripts</a>.</li>
<li>
OWASP:
<a href="https://owasp.org/www-community/vulnerabilities/Buffer_Overflow">Buffer Overflow</a>.
</li>
</references>
</qhelp>

Просмотреть файл

@ -0,0 +1,360 @@
/**
* @name Invalid pointer dereference
* @description Dereferencing a pointer that points past it allocation is undefined behavior
* and may lead to security vulnerabilities.
* @kind path-problem
* @problem.severity error
* @precision high
* @id cpp/invalid-pointer-deref
* @tags reliability
* security
* external/cwe/cwe-119
* external/cwe/cwe-125
* external/cwe/cwe-193
* external/cwe/cwe-787
*/
import cpp
import experimental.semmle.code.cpp.dataflow.ProductFlow
import experimental.semmle.code.cpp.ir.dataflow.DataFlow3
import experimental.semmle.code.cpp.semantic.analysis.RangeAnalysis
import experimental.semmle.code.cpp.semantic.SemanticBound
import experimental.semmle.code.cpp.semantic.SemanticExprSpecific
import semmle.code.cpp.ir.IR
pragma[nomagic]
Instruction getABoundIn(SemBound b, IRFunction func) {
result = b.getExpr(0) and
result.getEnclosingIRFunction() = func
}
/**
* Holds if `i <= b + delta`.
*/
pragma[nomagic]
predicate bounded(Instruction i, Instruction b, int delta) {
exists(SemBound bound, IRFunction func |
semBounded(getSemanticExpr(i), bound, delta, true, _) and
b = getABoundIn(bound, func) and
i.getEnclosingIRFunction() = func
)
}
/**
* Holds if the combination of `n` and `state` represents an appropriate
* source for the expression `e` suitable for use-use flow.
*/
private predicate hasSizeImpl(Expr e, DataFlow::Node n, string state) {
// The simple case: If the size is a variable access with no qualifier we can just use the
// dataflow node for that expression and no state.
exists(VariableAccess va |
va = e and
not va instanceof FieldAccess and
n.asConvertedExpr() = va.getFullyConverted() and
state = "0"
)
or
// If the size is a choice between two expressions we allow both to be nodes representing the size.
exists(ConditionalExpr cond | cond = e | hasSizeImpl([cond.getThen(), cond.getElse()], n, state))
or
// If the size is an expression plus a constant, we pick the dataflow node of the expression and
// remember the constant in the state.
exists(Expr const, Expr nonconst |
e.(AddExpr).hasOperands(const, nonconst) and
state = const.getValue() and
hasSizeImpl(nonconst, n, _)
)
or
exists(Expr const, Expr nonconst |
e.(SubExpr).hasOperands(const, nonconst) and
state = "-" + const.getValue() and
hasSizeImpl(nonconst, n, _)
)
}
/**
* Holds if `(n, state)` pair represents the source of flow for the size
* expression associated with `alloc`.
*/
predicate hasSize(AllocationExpr alloc, DataFlow::Node n, string state) {
hasSizeImpl(alloc.getSizeExpr(), n, state)
}
/**
* A product-flow configuration for flow from an (allocation, size) pair to a
* pointer-arithmetic operation that is non-strictly upper-bounded by `allocation + size`.
*
* The goal of this query is to find patterns such as:
* ```cpp
* 1. char* begin = (char*)malloc(size);
* 2. char* end = begin + size;
* 3. for(int *p = begin; p <= end; p++) {
* 4. use(*p);
* 5. }
* ```
*
* We do this by splitting the task up into two configurations:
* 1. `AllocToInvalidPointerConf` find flow from `malloc(size)` to `begin + size`, and
* 2. `InvalidPointerToDerefConf` finds flow from `begin + size` to an `end` (on line 3).
*
* Finally, the range-analysis library will find a load from (or store to) an address that
* is non-strictly upper-bounded by `end` (which in this case is `*p`).
*/
class AllocToInvalidPointerConf extends ProductFlow::Configuration {
AllocToInvalidPointerConf() { this = "AllocToInvalidPointerConf" }
override predicate isSourcePair(
DataFlow::Node source1, string state1, DataFlow::Node source2, string state2
) {
// In the case of an allocation like
// ```cpp
// malloc(size + 1);
// ```
// we use `state2` to remember that there was an offset (in this case an offset of `1`) added
// to the size of the allocation. This state is then checked in `isSinkPair`.
state1 = "" and
hasSize(source1.asConvertedExpr(), source2, state2)
}
override predicate isSinkPair(
DataFlow::Node sink1, DataFlow::FlowState state1, DataFlow::Node sink2,
DataFlow::FlowState state2
) {
state1 = "" and
// We check that the delta computed by the range analysis matches the
// state value that we set in `isSourcePair`.
exists(int delta |
isSinkImpl(_, sink1, sink2, delta) and
state2 = delta.toString()
)
}
}
pragma[nomagic]
predicate pointerAddInstructionHasOperands(
PointerAddInstruction pai, Instruction left, Instruction right
) {
pai.getLeft() = left and
pai.getRight() = right
}
/**
* Holds if `pai` is non-strictly upper bounded by `sink2 + delta` and `sink1` is the
* left operand of the pointer-arithmetic operation.
*
* For example in,
* ```cpp
* char* end = p + (size + 1);
* ```
* We will have:
* - `pai` is `p + (size + 1)`,
* - `sink1` is `p`
* - `sink2` is `size`
* - `delta` is `1`.
*/
pragma[nomagic]
predicate pointerAddInstructionHasBounds(
PointerAddInstruction pai, DataFlow::Node sink1, Instruction sink2, int delta
) {
exists(Instruction right |
pointerAddInstructionHasOperands(pai, sink1.asInstruction(), right) and
bounded(right, sink2, delta)
)
}
/**
* Holds if `pai` is non-strictly upper bounded by `sink2 + delta` and `sink1` is the
* left operand of the pointer-arithmetic operation.
*
* See `pointerAddInstructionHasBounds` for an example.
*/
predicate isSinkImpl(
PointerAddInstruction pai, DataFlow::Node sink1, DataFlow::Node sink2, int delta
) {
pointerAddInstructionHasBounds(pai, sink1, sink2.asInstruction(), delta)
}
/**
* Holds if `sink` is a sink for `InvalidPointerToDerefConf` and `i` is a `StoreInstruction` that
* writes to an address that non-strictly upper-bounds `sink`, or `i` is a `LoadInstruction` that
* reads from an address that non-strictly upper-bounds `sink`.
*/
predicate isInvalidPointerDerefSink(DataFlow::Node sink, Instruction i, string operation) {
exists(AddressOperand addr, int delta |
bounded(addr.getDef(), sink.asInstruction(), delta) and
delta >= 0 and
i.getAnOperand() = addr
|
i instanceof StoreInstruction and
operation = "write"
or
i instanceof LoadInstruction and
operation = "read"
)
}
/**
* A configuration to track flow from a pointer-arithmetic operation found
* by `AllocToInvalidPointerConf` to a dereference of the pointer.
*/
class InvalidPointerToDerefConf extends DataFlow3::Configuration {
InvalidPointerToDerefConf() { this = "InvalidPointerToDerefConf" }
override predicate isSource(DataFlow::Node source) { invalidPointerToDerefSource(_, source, _) }
override predicate isSink(DataFlow::Node sink) { isInvalidPointerDerefSink(sink, _, _) }
}
/**
* Holds if `pai` is a pointer-arithmetic operation and `source` is a dataflow node with a
* pointer-value that is non-strictly upper bounded by `pai + delta`.
*
* For example, if `pai` is a pointer-arithmetic operation `p + size` in an expression such
* as `(p + size) + 1` and `source` is the node representing `(p + size) + 1`. In this
* case `delta` is 1.
*/
predicate invalidPointerToDerefSource(
PointerArithmeticInstruction pai, DataFlow::Node source, int delta
) {
exists(ProductFlow::Configuration conf, DataFlow::PathNode p, DataFlow::Node sink1 |
p.getNode() = sink1 and
conf.hasFlowPath(_, _, p, _) and
isSinkImpl(pai, sink1, _, _) and
bounded(source.asInstruction(), pai, delta) and
delta >= 0
)
}
newtype TMergedPathNode =
// The path nodes computed by the first projection of `AllocToInvalidPointerConf`
TPathNode1(DataFlow::PathNode p) or
// The path nodes computed by `InvalidPointerToDerefConf`
TPathNode3(DataFlow3::PathNode p) or
// The read/write that uses the invalid pointer identified by `InvalidPointerToDerefConf`.
// This one is needed because the sink identified by `InvalidPointerToDerefConf` is the
// pointer, but we want to raise an alert at the dereference.
TPathNodeSink(Instruction i) {
exists(DataFlow::Node n |
any(InvalidPointerToDerefConf conf).hasFlow(_, n) and
isInvalidPointerDerefSink(n, i, _)
)
}
class MergedPathNode extends TMergedPathNode {
string toString() { none() }
final DataFlow::PathNode asPathNode1() { this = TPathNode1(result) }
final DataFlow3::PathNode asPathNode3() { this = TPathNode3(result) }
final Instruction asSinkNode() { this = TPathNodeSink(result) }
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
}
class PathNode1 extends MergedPathNode, TPathNode1 {
override string toString() {
exists(DataFlow::PathNode p |
this = TPathNode1(p) and
result = p.toString()
)
}
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
this.asPathNode1().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
}
class PathNode3 extends MergedPathNode, TPathNode3 {
override string toString() {
exists(DataFlow3::PathNode p |
this = TPathNode3(p) and
result = p.toString()
)
}
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
this.asPathNode3().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
}
class PathSinkNode extends MergedPathNode, TPathNodeSink {
override string toString() {
exists(Instruction i |
this = TPathNodeSink(i) and
result = i.toString()
)
}
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
this.asSinkNode()
.getLocation()
.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
}
query predicate edges(MergedPathNode node1, MergedPathNode node2) {
node1.asPathNode1().getASuccessor() = node2.asPathNode1()
or
joinOn1(_, node1.asPathNode1(), node2.asPathNode3())
or
node1.asPathNode3().getASuccessor() = node2.asPathNode3()
or
joinOn2(node1.asPathNode3(), node2.asSinkNode(), _)
}
/**
* Holds if `p1` is a sink of `AllocToInvalidPointerConf` and `p2` is a source
* of `InvalidPointerToDerefConf`, and they are connected through `pai`.
*/
predicate joinOn1(PointerArithmeticInstruction pai, DataFlow::PathNode p1, DataFlow3::PathNode p2) {
isSinkImpl(pai, p1.getNode(), _, _) and
invalidPointerToDerefSource(pai, p2.getNode(), _)
}
/**
* Holds if `p1` is a sink of `InvalidPointerToDerefConf` and `i` is the instruction
* that dereferences `p1`. The string `operation` describes whether the `i` is
* a `StoreInstruction` or `LoadInstruction`.
*/
predicate joinOn2(DataFlow3::PathNode p1, Instruction i, string operation) {
isInvalidPointerDerefSink(p1.getNode(), i, operation)
}
predicate hasFlowPath(
MergedPathNode source1, MergedPathNode sink, DataFlow3::PathNode source3,
PointerArithmeticInstruction pai, string operation
) {
exists(
AllocToInvalidPointerConf conf1, InvalidPointerToDerefConf conf2, DataFlow3::PathNode sink3,
DataFlow::PathNode sink1
|
conf1.hasFlowPath(source1.asPathNode1(), _, sink1, _) and
joinOn1(pai, sink1, source3) and
conf2.hasFlowPath(source3, sink3) and
joinOn2(sink3, sink.asSinkNode(), operation)
)
}
from
MergedPathNode source, MergedPathNode sink, int k, string kstr, DataFlow3::PathNode source3,
PointerArithmeticInstruction pai, string operation, Expr offset, DataFlow::Node n
where
hasFlowPath(source, sink, source3, pai, operation) and
invalidPointerToDerefSource(pai, source3.getNode(), k) and
offset = pai.getRight().getUnconvertedResultExpression() and
n = source.asPathNode1().getNode() and
if k = 0 then kstr = "" else kstr = " + " + k
select sink, source, sink,
"This " + operation + " might be out of bounds, as the pointer might be equal to $@ + $@" + kstr +
".", n, n.toString(), offset, offset.toString()

Просмотреть файл

@ -20,10 +20,12 @@
| test.cpp:62:10:62:13 | Load: iter | test.cpp:60:17:60:17 | ValueNumberBound | 0 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 |
| test.cpp:62:10:62:13 | Load: iter | test.cpp:60:17:60:17 | ValueNumberBound | 3 | true | CompareLT: ... < ... | test.cpp:61:32:61:51 | test.cpp:61:32:61:51 |
| test.cpp:62:10:62:13 | Load: iter | test.cpp:61:39:61:51 | ValueNumberBound | -1 | true | CompareLT: ... < ... | test.cpp:61:32:61:51 | test.cpp:61:32:61:51 |
| test.cpp:62:10:62:13 | Load: iter | test.cpp:61:48:61:50 | ValueNumberBound | -1 | true | CompareLT: ... < ... | test.cpp:61:32:61:51 | test.cpp:61:32:61:51 |
| test.cpp:67:10:67:13 | Load: iter | test.cpp:60:17:60:17 | ValueNumberBound | 0 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 |
| test.cpp:67:10:67:13 | Load: iter | test.cpp:60:17:60:17 | ValueNumberBound | 3 | true | CompareLT: ... < ... | test.cpp:66:32:66:41 | test.cpp:66:32:66:41 |
| test.cpp:67:10:67:13 | Load: iter | test.cpp:61:32:61:35 | ValueNumberBound | -1 | true | CompareLT: ... < ... | test.cpp:66:32:66:41 | test.cpp:66:32:66:41 |
| test.cpp:67:10:67:13 | Load: iter | test.cpp:61:39:61:51 | ValueNumberBound | -1 | true | CompareLT: ... < ... | test.cpp:66:32:66:41 | test.cpp:66:32:66:41 |
| test.cpp:67:10:67:13 | Load: iter | test.cpp:61:48:61:50 | ValueNumberBound | -1 | true | CompareLT: ... < ... | test.cpp:66:32:66:41 | test.cpp:66:32:66:41 |
| test.cpp:77:12:77:12 | Load: i | file://:0:0:0:0 | 0 | 0 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 |
| test.cpp:77:12:77:12 | Load: i | test.cpp:72:15:72:15 | ValueNumberBound | -1 | true | CompareLT: ... < ... | test.cpp:76:20:76:24 | test.cpp:76:20:76:24 |
| test.cpp:77:12:77:12 | Load: i | test.cpp:72:22:72:22 | ValueNumberBound | -1 | true | CompareLT: ... < ... | test.cpp:76:20:76:24 | test.cpp:76:20:76:24 |

Просмотреть файл

@ -1,2 +1,2 @@
| test.cpp:19:19:19:24 | call to malloc | test.cpp:18:17:18:20 | size | test.cpp:26:18:26:23 | string | test.cpp:26:31:26:39 | (size_t)... |
| test.cpp:19:19:19:24 | call to malloc | test.cpp:18:17:18:20 | size | test.cpp:30:18:30:23 | string | test.cpp:30:31:30:39 | (size_t)... |
| test.cpp:19:19:19:24 | call to malloc | test.cpp:18:17:18:20 | size | test.cpp:26:18:26:23 | Load | test.cpp:26:31:26:39 | Convert |
| test.cpp:19:19:19:24 | call to malloc | test.cpp:18:17:18:20 | size | test.cpp:30:18:30:23 | Load | test.cpp:30:31:30:39 | Convert |

Просмотреть файл

@ -1,23 +1,20 @@
| test.cpp:4:17:4:22 | call to malloc | test.cpp:4:24:4:27 | size | test.cpp:10:9:10:11 | arr | test.cpp:4:24:4:27 | size |
| test.cpp:4:17:4:22 | call to malloc | test.cpp:4:24:4:27 | size | test.cpp:10:9:10:11 | arr | test.cpp:4:24:4:27 | size |
| test.cpp:4:17:4:22 | call to malloc | test.cpp:4:24:4:27 | size | test.cpp:10:9:10:11 | arr | test.cpp:5:25:5:28 | size |
| test.cpp:4:17:4:22 | call to malloc | test.cpp:4:24:4:27 | size | test.cpp:10:9:10:11 | arr | test.cpp:5:25:5:28 | size |
| test.cpp:4:17:4:22 | call to malloc | test.cpp:4:24:4:27 | size | test.cpp:10:9:10:11 | arr | test.cpp:9:26:9:29 | size |
| test.cpp:4:17:4:22 | call to malloc | test.cpp:5:25:5:28 | size | test.cpp:10:9:10:11 | arr | test.cpp:5:25:5:28 | size |
| test.cpp:4:17:4:22 | call to malloc | test.cpp:5:25:5:28 | size | test.cpp:10:9:10:11 | arr | test.cpp:5:25:5:28 | size |
| test.cpp:4:17:4:22 | call to malloc | test.cpp:5:25:5:28 | size | test.cpp:10:9:10:11 | arr | test.cpp:9:26:9:29 | size |
| test.cpp:4:17:4:22 | call to malloc | test.cpp:9:26:9:29 | size | test.cpp:10:9:10:11 | arr | test.cpp:9:26:9:29 | size |
| test.cpp:4:17:4:22 | call to malloc | test.cpp:9:26:9:29 | size | test.cpp:10:9:10:11 | arr | test.cpp:9:26:9:29 | size |
| test.cpp:56:13:56:18 | call to malloc | test.cpp:55:16:55:19 | size | test.cpp:63:13:63:13 | p | test.cpp:55:5:55:19 | Store |
| test.cpp:56:13:56:18 | call to malloc | test.cpp:55:16:55:19 | size | test.cpp:63:13:63:13 | p | test.cpp:55:16:55:19 | size |
| test.cpp:56:13:56:18 | call to malloc | test.cpp:55:16:55:19 | size | test.cpp:63:13:63:13 | p | test.cpp:55:16:55:19 | size |
| test.cpp:56:13:56:18 | call to malloc | test.cpp:55:16:55:19 | size | test.cpp:63:13:63:13 | p | test.cpp:56:20:56:23 | size |
| test.cpp:56:13:56:18 | call to malloc | test.cpp:56:20:56:23 | size | test.cpp:63:13:63:13 | p | test.cpp:56:20:56:23 | size |
| test.cpp:56:13:56:18 | call to malloc | test.cpp:56:20:56:23 | size | test.cpp:63:13:63:13 | p | test.cpp:56:20:56:23 | size |
| test.cpp:56:13:56:18 | call to malloc | test.cpp:58:29:58:32 | size | test.cpp:63:13:63:13 | p | test.cpp:58:29:58:32 | size |
| test.cpp:56:13:56:18 | call to malloc | test.cpp:58:29:58:32 | size | test.cpp:63:13:63:13 | p | test.cpp:58:29:58:32 | size |
| test.cpp:56:13:56:18 | call to malloc | test.cpp:62:30:62:33 | size | test.cpp:63:13:63:13 | p | test.cpp:62:30:62:33 | size |
| test.cpp:56:13:56:18 | call to malloc | test.cpp:62:30:62:33 | size | test.cpp:63:13:63:13 | p | test.cpp:62:30:62:33 | size |
| test.cpp:70:14:70:19 | call to malloc | test.cpp:69:17:69:20 | size | test.cpp:83:14:83:14 | p | test.cpp:82:31:82:34 | size |
| test.cpp:70:14:70:19 | call to malloc | test.cpp:69:17:69:20 | size | test.cpp:93:14:93:14 | p | test.cpp:88:30:88:33 | size |
| test.cpp:70:14:70:19 | call to malloc | test.cpp:69:17:69:20 | size | test.cpp:93:14:93:14 | p | test.cpp:92:31:92:34 | size |
| test.cpp:4:17:4:22 | call to malloc | test.cpp:4:24:4:27 | size | test.cpp:10:9:10:11 | Load | test.cpp:5:25:5:28 | Load |
| test.cpp:4:17:4:22 | call to malloc | test.cpp:4:24:4:27 | size | test.cpp:10:9:10:11 | Load | test.cpp:9:26:9:29 | Load |
| test.cpp:4:17:4:22 | call to malloc | test.cpp:5:25:5:28 | size | test.cpp:10:9:10:11 | Load | test.cpp:5:25:5:28 | Load |
| test.cpp:4:17:4:22 | call to malloc | test.cpp:5:25:5:28 | size | test.cpp:10:9:10:11 | Load | test.cpp:9:26:9:29 | Load |
| test.cpp:4:17:4:22 | call to malloc | test.cpp:9:26:9:29 | size | test.cpp:10:9:10:11 | Load | test.cpp:9:26:9:29 | Load |
| test.cpp:22:13:22:18 | call to malloc | test.cpp:21:16:21:19 | size | test.cpp:35:13:35:13 | Load | test.cpp:30:29:30:32 | Load |
| test.cpp:22:13:22:18 | call to malloc | test.cpp:21:16:21:19 | size | test.cpp:35:13:35:13 | Load | test.cpp:34:30:34:33 | Load |
| test.cpp:22:13:22:18 | call to malloc | test.cpp:21:16:21:19 | size | test.cpp:45:13:45:13 | Load | test.cpp:40:29:40:32 | Load |
| test.cpp:22:13:22:18 | call to malloc | test.cpp:21:16:21:19 | size | test.cpp:45:13:45:13 | Load | test.cpp:44:30:44:33 | Load |
| test.cpp:56:13:56:18 | call to malloc | test.cpp:55:16:55:19 | size | test.cpp:63:13:63:13 | Load | test.cpp:55:5:55:19 | Store |
| test.cpp:56:13:56:18 | call to malloc | test.cpp:55:16:55:19 | size | test.cpp:63:13:63:13 | Load | test.cpp:55:5:55:19 | Store |
| test.cpp:56:13:56:18 | call to malloc | test.cpp:55:16:55:19 | size | test.cpp:63:13:63:13 | Load | test.cpp:55:16:55:19 | Load |
| test.cpp:56:13:56:18 | call to malloc | test.cpp:55:16:55:19 | size | test.cpp:63:13:63:13 | Load | test.cpp:56:20:56:23 | Load |
| test.cpp:56:13:56:18 | call to malloc | test.cpp:55:16:55:19 | size | test.cpp:63:13:63:13 | Load | test.cpp:58:29:58:32 | Load |
| test.cpp:56:13:56:18 | call to malloc | test.cpp:55:16:55:19 | size | test.cpp:63:13:63:13 | Load | test.cpp:62:30:62:33 | Load |
| test.cpp:56:13:56:18 | call to malloc | test.cpp:58:29:58:32 | size | test.cpp:63:13:63:13 | Load | test.cpp:58:29:58:32 | Load |
| test.cpp:56:13:56:18 | call to malloc | test.cpp:62:30:62:33 | size | test.cpp:63:13:63:13 | Load | test.cpp:62:30:62:33 | Load |
| test.cpp:70:14:70:19 | call to malloc | test.cpp:69:17:69:20 | size | test.cpp:83:14:83:14 | Load | test.cpp:82:31:82:34 | Load |
| test.cpp:70:14:70:19 | call to malloc | test.cpp:69:17:69:20 | size | test.cpp:93:14:93:14 | Load | test.cpp:88:30:88:33 | Load |
| test.cpp:70:14:70:19 | call to malloc | test.cpp:69:17:69:20 | size | test.cpp:93:14:93:14 | Load | test.cpp:92:31:92:34 | Load |

Просмотреть файл

@ -32,7 +32,7 @@ void test2(int size) {
}
for (int i = 0; i <= arr.size; i++) {
arr.p[i] = i; // BAD [NOT DETECTED]
arr.p[i] = i; // BAD
}
}
@ -42,7 +42,7 @@ void test3_callee(array_t arr) {
}
for (int i = 0; i <= arr.size; i++) {
arr.p[i] = i; // BAD [NOT DETECTED]
arr.p[i] = i; // BAD
}
}

Просмотреть файл

@ -0,0 +1,627 @@
edges
| test.cpp:4:15:4:20 | call to malloc | test.cpp:5:15:5:15 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:5:15:5:22 | ... + ... |
| test.cpp:5:15:5:15 | Load | test.cpp:5:15:5:22 | ... + ... |
| test.cpp:5:15:5:15 | Load | test.cpp:5:15:5:22 | ... + ... |
| test.cpp:5:15:5:15 | Load | test.cpp:5:15:5:22 | ... + ... |
| test.cpp:5:15:5:15 | Load | test.cpp:5:15:5:22 | Store |
| test.cpp:5:15:5:15 | Load | test.cpp:5:15:5:22 | Store |
| test.cpp:5:15:5:15 | Load | test.cpp:5:15:5:22 | Store |
| test.cpp:5:15:5:15 | Load | test.cpp:5:15:5:22 | Store |
| test.cpp:5:15:5:15 | Load | test.cpp:6:15:6:15 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:6:15:6:15 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:6:15:6:15 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:6:15:6:15 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:7:16:7:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:7:16:7:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:7:16:7:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:7:16:7:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:8:16:8:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:8:16:8:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:8:16:8:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:8:16:8:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:8:16:8:20 | ... + ... |
| test.cpp:5:15:5:15 | Load | test.cpp:8:16:8:20 | ... + ... |
| test.cpp:5:15:5:15 | Load | test.cpp:8:16:8:20 | ... + ... |
| test.cpp:5:15:5:15 | Load | test.cpp:8:16:8:20 | ... + ... |
| test.cpp:5:15:5:15 | Load | test.cpp:9:16:9:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:9:16:9:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:9:16:9:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:9:16:9:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:10:16:10:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:10:16:10:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:10:16:10:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:10:16:10:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:11:16:11:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:11:16:11:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:11:16:11:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:11:16:11:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:12:16:12:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:12:16:12:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:12:16:12:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:12:16:12:16 | Load |
| test.cpp:5:15:5:22 | ... + ... | test.cpp:5:15:5:22 | Store |
| test.cpp:5:15:5:22 | ... + ... | test.cpp:5:15:5:22 | Store |
| test.cpp:5:15:5:22 | ... + ... | test.cpp:6:14:6:15 | Load: * ... |
| test.cpp:5:15:5:22 | ... + ... | test.cpp:6:14:6:15 | Load: * ... |
| test.cpp:5:15:5:22 | ... + ... | test.cpp:6:15:6:15 | Load |
| test.cpp:5:15:5:22 | ... + ... | test.cpp:6:15:6:15 | Load |
| test.cpp:5:15:5:22 | ... + ... | test.cpp:7:16:7:16 | Load |
| test.cpp:5:15:5:22 | ... + ... | test.cpp:7:16:7:16 | Load |
| test.cpp:5:15:5:22 | ... + ... | test.cpp:8:14:8:21 | Load: * ... |
| test.cpp:5:15:5:22 | ... + ... | test.cpp:8:14:8:21 | Load: * ... |
| test.cpp:5:15:5:22 | ... + ... | test.cpp:8:16:8:16 | Load |
| test.cpp:5:15:5:22 | ... + ... | test.cpp:8:16:8:16 | Load |
| test.cpp:5:15:5:22 | ... + ... | test.cpp:9:16:9:16 | Load |
| test.cpp:5:15:5:22 | ... + ... | test.cpp:9:16:9:16 | Load |
| test.cpp:5:15:5:22 | ... + ... | test.cpp:10:16:10:16 | Load |
| test.cpp:5:15:5:22 | ... + ... | test.cpp:10:16:10:16 | Load |
| test.cpp:5:15:5:22 | ... + ... | test.cpp:11:16:11:16 | Load |
| test.cpp:5:15:5:22 | ... + ... | test.cpp:11:16:11:16 | Load |
| test.cpp:5:15:5:22 | ... + ... | test.cpp:12:16:12:16 | Load |
| test.cpp:5:15:5:22 | Store | test.cpp:6:14:6:15 | Load: * ... |
| test.cpp:5:15:5:22 | Store | test.cpp:6:14:6:15 | Load: * ... |
| test.cpp:5:15:5:22 | Store | test.cpp:6:15:6:15 | Load |
| test.cpp:5:15:5:22 | Store | test.cpp:6:15:6:15 | Load |
| test.cpp:5:15:5:22 | Store | test.cpp:7:16:7:16 | Load |
| test.cpp:5:15:5:22 | Store | test.cpp:7:16:7:16 | Load |
| test.cpp:5:15:5:22 | Store | test.cpp:8:14:8:21 | Load: * ... |
| test.cpp:5:15:5:22 | Store | test.cpp:8:14:8:21 | Load: * ... |
| test.cpp:5:15:5:22 | Store | test.cpp:8:16:8:16 | Load |
| test.cpp:5:15:5:22 | Store | test.cpp:8:16:8:16 | Load |
| test.cpp:5:15:5:22 | Store | test.cpp:9:16:9:16 | Load |
| test.cpp:5:15:5:22 | Store | test.cpp:9:16:9:16 | Load |
| test.cpp:5:15:5:22 | Store | test.cpp:10:16:10:16 | Load |
| test.cpp:5:15:5:22 | Store | test.cpp:10:16:10:16 | Load |
| test.cpp:5:15:5:22 | Store | test.cpp:11:16:11:16 | Load |
| test.cpp:5:15:5:22 | Store | test.cpp:11:16:11:16 | Load |
| test.cpp:5:15:5:22 | Store | test.cpp:12:16:12:16 | Load |
| test.cpp:6:15:6:15 | Load | test.cpp:6:14:6:15 | Load: * ... |
| test.cpp:6:15:6:15 | Load | test.cpp:6:14:6:15 | Load: * ... |
| test.cpp:6:15:6:15 | Load | test.cpp:7:16:7:16 | Load |
| test.cpp:6:15:6:15 | Load | test.cpp:7:16:7:16 | Load |
| test.cpp:6:15:6:15 | Load | test.cpp:8:14:8:21 | Load: * ... |
| test.cpp:6:15:6:15 | Load | test.cpp:8:14:8:21 | Load: * ... |
| test.cpp:6:15:6:15 | Load | test.cpp:8:16:8:16 | Load |
| test.cpp:6:15:6:15 | Load | test.cpp:8:16:8:16 | Load |
| test.cpp:6:15:6:15 | Load | test.cpp:9:16:9:16 | Load |
| test.cpp:6:15:6:15 | Load | test.cpp:9:16:9:16 | Load |
| test.cpp:6:15:6:15 | Load | test.cpp:10:16:10:16 | Load |
| test.cpp:6:15:6:15 | Load | test.cpp:10:16:10:16 | Load |
| test.cpp:6:15:6:15 | Load | test.cpp:11:16:11:16 | Load |
| test.cpp:6:15:6:15 | Load | test.cpp:11:16:11:16 | Load |
| test.cpp:6:15:6:15 | Load | test.cpp:12:16:12:16 | Load |
| test.cpp:7:16:7:16 | Load | test.cpp:6:14:6:15 | Load: * ... |
| test.cpp:7:16:7:16 | Load | test.cpp:6:14:6:15 | Load: * ... |
| test.cpp:7:16:7:16 | Load | test.cpp:8:14:8:21 | Load: * ... |
| test.cpp:7:16:7:16 | Load | test.cpp:8:14:8:21 | Load: * ... |
| test.cpp:7:16:7:16 | Load | test.cpp:8:16:8:16 | Load |
| test.cpp:7:16:7:16 | Load | test.cpp:8:16:8:16 | Load |
| test.cpp:7:16:7:16 | Load | test.cpp:9:16:9:16 | Load |
| test.cpp:7:16:7:16 | Load | test.cpp:9:16:9:16 | Load |
| test.cpp:7:16:7:16 | Load | test.cpp:10:16:10:16 | Load |
| test.cpp:7:16:7:16 | Load | test.cpp:10:16:10:16 | Load |
| test.cpp:7:16:7:16 | Load | test.cpp:11:16:11:16 | Load |
| test.cpp:7:16:7:16 | Load | test.cpp:11:16:11:16 | Load |
| test.cpp:7:16:7:16 | Load | test.cpp:12:16:12:16 | Load |
| test.cpp:8:16:8:16 | Load | test.cpp:6:14:6:15 | Load: * ... |
| test.cpp:8:16:8:16 | Load | test.cpp:6:14:6:15 | Load: * ... |
| test.cpp:8:16:8:16 | Load | test.cpp:8:14:8:21 | Load: * ... |
| test.cpp:8:16:8:16 | Load | test.cpp:8:14:8:21 | Load: * ... |
| test.cpp:8:16:8:16 | Load | test.cpp:9:16:9:16 | Load |
| test.cpp:8:16:8:16 | Load | test.cpp:9:16:9:16 | Load |
| test.cpp:8:16:8:16 | Load | test.cpp:10:16:10:16 | Load |
| test.cpp:8:16:8:16 | Load | test.cpp:10:16:10:16 | Load |
| test.cpp:8:16:8:16 | Load | test.cpp:11:16:11:16 | Load |
| test.cpp:8:16:8:16 | Load | test.cpp:11:16:11:16 | Load |
| test.cpp:8:16:8:16 | Load | test.cpp:12:16:12:16 | Load |
| test.cpp:8:16:8:20 | ... + ... | test.cpp:8:14:8:21 | Load: * ... |
| test.cpp:8:16:8:20 | ... + ... | test.cpp:8:14:8:21 | Load: * ... |
| test.cpp:9:16:9:16 | Load | test.cpp:6:14:6:15 | Load: * ... |
| test.cpp:9:16:9:16 | Load | test.cpp:6:14:6:15 | Load: * ... |
| test.cpp:9:16:9:16 | Load | test.cpp:8:14:8:21 | Load: * ... |
| test.cpp:9:16:9:16 | Load | test.cpp:8:14:8:21 | Load: * ... |
| test.cpp:9:16:9:16 | Load | test.cpp:10:16:10:16 | Load |
| test.cpp:9:16:9:16 | Load | test.cpp:10:16:10:16 | Load |
| test.cpp:9:16:9:16 | Load | test.cpp:11:16:11:16 | Load |
| test.cpp:9:16:9:16 | Load | test.cpp:11:16:11:16 | Load |
| test.cpp:9:16:9:16 | Load | test.cpp:12:16:12:16 | Load |
| test.cpp:10:16:10:16 | Load | test.cpp:6:14:6:15 | Load: * ... |
| test.cpp:10:16:10:16 | Load | test.cpp:6:14:6:15 | Load: * ... |
| test.cpp:10:16:10:16 | Load | test.cpp:8:14:8:21 | Load: * ... |
| test.cpp:10:16:10:16 | Load | test.cpp:8:14:8:21 | Load: * ... |
| test.cpp:10:16:10:16 | Load | test.cpp:11:16:11:16 | Load |
| test.cpp:10:16:10:16 | Load | test.cpp:11:16:11:16 | Load |
| test.cpp:10:16:10:16 | Load | test.cpp:12:16:12:16 | Load |
| test.cpp:11:16:11:16 | Load | test.cpp:6:14:6:15 | Load: * ... |
| test.cpp:11:16:11:16 | Load | test.cpp:6:14:6:15 | Load: * ... |
| test.cpp:11:16:11:16 | Load | test.cpp:8:14:8:21 | Load: * ... |
| test.cpp:11:16:11:16 | Load | test.cpp:8:14:8:21 | Load: * ... |
| test.cpp:11:16:11:16 | Load | test.cpp:12:16:12:16 | Load |
| test.cpp:12:16:12:16 | Load | test.cpp:6:14:6:15 | Load: * ... |
| test.cpp:12:16:12:16 | Load | test.cpp:6:14:6:15 | Load: * ... |
| test.cpp:12:16:12:16 | Load | test.cpp:8:14:8:21 | Load: * ... |
| test.cpp:12:16:12:16 | Load | test.cpp:8:14:8:21 | Load: * ... |
| test.cpp:16:15:16:20 | call to malloc | test.cpp:17:15:17:15 | Load |
| test.cpp:17:15:17:15 | Load | test.cpp:17:15:17:22 | ... + ... |
| test.cpp:17:15:17:15 | Load | test.cpp:17:15:17:22 | ... + ... |
| test.cpp:17:15:17:15 | Load | test.cpp:17:15:17:22 | ... + ... |
| test.cpp:17:15:17:15 | Load | test.cpp:17:15:17:22 | ... + ... |
| test.cpp:17:15:17:15 | Load | test.cpp:20:16:20:20 | ... + ... |
| test.cpp:17:15:17:15 | Load | test.cpp:20:16:20:20 | ... + ... |
| test.cpp:17:15:17:15 | Load | test.cpp:20:16:20:20 | ... + ... |
| test.cpp:17:15:17:15 | Load | test.cpp:20:16:20:20 | ... + ... |
| test.cpp:17:15:17:22 | ... + ... | test.cpp:20:14:20:21 | Load: * ... |
| test.cpp:17:15:17:22 | ... + ... | test.cpp:20:14:20:21 | Load: * ... |
| test.cpp:20:16:20:20 | ... + ... | test.cpp:20:14:20:21 | Load: * ... |
| test.cpp:20:16:20:20 | ... + ... | test.cpp:20:14:20:21 | Load: * ... |
| test.cpp:28:15:28:20 | call to malloc | test.cpp:29:15:29:15 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:29:15:29:28 | ... + ... |
| test.cpp:29:15:29:15 | Load | test.cpp:29:15:29:28 | ... + ... |
| test.cpp:29:15:29:15 | Load | test.cpp:29:15:29:28 | ... + ... |
| test.cpp:29:15:29:15 | Load | test.cpp:29:15:29:28 | ... + ... |
| test.cpp:29:15:29:15 | Load | test.cpp:29:15:29:28 | Store |
| test.cpp:29:15:29:15 | Load | test.cpp:29:15:29:28 | Store |
| test.cpp:29:15:29:15 | Load | test.cpp:29:15:29:28 | Store |
| test.cpp:29:15:29:15 | Load | test.cpp:29:15:29:28 | Store |
| test.cpp:29:15:29:15 | Load | test.cpp:30:15:30:15 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:30:15:30:15 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:30:15:30:15 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:30:15:30:15 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:31:16:31:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:31:16:31:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:31:16:31:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:31:16:31:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:32:16:32:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:32:16:32:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:32:16:32:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:32:16:32:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:32:16:32:20 | ... + ... |
| test.cpp:29:15:29:15 | Load | test.cpp:32:16:32:20 | ... + ... |
| test.cpp:29:15:29:15 | Load | test.cpp:32:16:32:20 | ... + ... |
| test.cpp:29:15:29:15 | Load | test.cpp:32:16:32:20 | ... + ... |
| test.cpp:29:15:29:15 | Load | test.cpp:33:16:33:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:33:16:33:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:33:16:33:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:33:16:33:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:34:16:34:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:34:16:34:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:34:16:34:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:34:16:34:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:35:16:35:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:35:16:35:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:35:16:35:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:35:16:35:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:36:16:36:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:36:16:36:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:36:16:36:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:36:16:36:16 | Load |
| test.cpp:29:15:29:28 | ... + ... | test.cpp:29:15:29:28 | Store |
| test.cpp:29:15:29:28 | ... + ... | test.cpp:29:15:29:28 | Store |
| test.cpp:29:15:29:28 | ... + ... | test.cpp:30:14:30:15 | Load: * ... |
| test.cpp:29:15:29:28 | ... + ... | test.cpp:30:14:30:15 | Load: * ... |
| test.cpp:29:15:29:28 | ... + ... | test.cpp:30:15:30:15 | Load |
| test.cpp:29:15:29:28 | ... + ... | test.cpp:30:15:30:15 | Load |
| test.cpp:29:15:29:28 | ... + ... | test.cpp:31:16:31:16 | Load |
| test.cpp:29:15:29:28 | ... + ... | test.cpp:31:16:31:16 | Load |
| test.cpp:29:15:29:28 | ... + ... | test.cpp:32:14:32:21 | Load: * ... |
| test.cpp:29:15:29:28 | ... + ... | test.cpp:32:14:32:21 | Load: * ... |
| test.cpp:29:15:29:28 | ... + ... | test.cpp:32:16:32:16 | Load |
| test.cpp:29:15:29:28 | ... + ... | test.cpp:32:16:32:16 | Load |
| test.cpp:29:15:29:28 | ... + ... | test.cpp:33:16:33:16 | Load |
| test.cpp:29:15:29:28 | ... + ... | test.cpp:33:16:33:16 | Load |
| test.cpp:29:15:29:28 | ... + ... | test.cpp:34:16:34:16 | Load |
| test.cpp:29:15:29:28 | ... + ... | test.cpp:34:16:34:16 | Load |
| test.cpp:29:15:29:28 | ... + ... | test.cpp:35:16:35:16 | Load |
| test.cpp:29:15:29:28 | ... + ... | test.cpp:35:16:35:16 | Load |
| test.cpp:29:15:29:28 | ... + ... | test.cpp:36:16:36:16 | Load |
| test.cpp:29:15:29:28 | Store | test.cpp:30:14:30:15 | Load: * ... |
| test.cpp:29:15:29:28 | Store | test.cpp:30:14:30:15 | Load: * ... |
| test.cpp:29:15:29:28 | Store | test.cpp:30:15:30:15 | Load |
| test.cpp:29:15:29:28 | Store | test.cpp:30:15:30:15 | Load |
| test.cpp:29:15:29:28 | Store | test.cpp:31:16:31:16 | Load |
| test.cpp:29:15:29:28 | Store | test.cpp:31:16:31:16 | Load |
| test.cpp:29:15:29:28 | Store | test.cpp:32:14:32:21 | Load: * ... |
| test.cpp:29:15:29:28 | Store | test.cpp:32:14:32:21 | Load: * ... |
| test.cpp:29:15:29:28 | Store | test.cpp:32:16:32:16 | Load |
| test.cpp:29:15:29:28 | Store | test.cpp:32:16:32:16 | Load |
| test.cpp:29:15:29:28 | Store | test.cpp:33:16:33:16 | Load |
| test.cpp:29:15:29:28 | Store | test.cpp:33:16:33:16 | Load |
| test.cpp:29:15:29:28 | Store | test.cpp:34:16:34:16 | Load |
| test.cpp:29:15:29:28 | Store | test.cpp:34:16:34:16 | Load |
| test.cpp:29:15:29:28 | Store | test.cpp:35:16:35:16 | Load |
| test.cpp:29:15:29:28 | Store | test.cpp:35:16:35:16 | Load |
| test.cpp:29:15:29:28 | Store | test.cpp:36:16:36:16 | Load |
| test.cpp:30:15:30:15 | Load | test.cpp:30:14:30:15 | Load: * ... |
| test.cpp:30:15:30:15 | Load | test.cpp:30:14:30:15 | Load: * ... |
| test.cpp:30:15:30:15 | Load | test.cpp:31:16:31:16 | Load |
| test.cpp:30:15:30:15 | Load | test.cpp:31:16:31:16 | Load |
| test.cpp:30:15:30:15 | Load | test.cpp:32:14:32:21 | Load: * ... |
| test.cpp:30:15:30:15 | Load | test.cpp:32:14:32:21 | Load: * ... |
| test.cpp:30:15:30:15 | Load | test.cpp:32:16:32:16 | Load |
| test.cpp:30:15:30:15 | Load | test.cpp:32:16:32:16 | Load |
| test.cpp:30:15:30:15 | Load | test.cpp:33:16:33:16 | Load |
| test.cpp:30:15:30:15 | Load | test.cpp:33:16:33:16 | Load |
| test.cpp:30:15:30:15 | Load | test.cpp:34:16:34:16 | Load |
| test.cpp:30:15:30:15 | Load | test.cpp:34:16:34:16 | Load |
| test.cpp:30:15:30:15 | Load | test.cpp:35:16:35:16 | Load |
| test.cpp:30:15:30:15 | Load | test.cpp:35:16:35:16 | Load |
| test.cpp:30:15:30:15 | Load | test.cpp:36:16:36:16 | Load |
| test.cpp:31:16:31:16 | Load | test.cpp:30:14:30:15 | Load: * ... |
| test.cpp:31:16:31:16 | Load | test.cpp:30:14:30:15 | Load: * ... |
| test.cpp:31:16:31:16 | Load | test.cpp:32:14:32:21 | Load: * ... |
| test.cpp:31:16:31:16 | Load | test.cpp:32:14:32:21 | Load: * ... |
| test.cpp:31:16:31:16 | Load | test.cpp:32:16:32:16 | Load |
| test.cpp:31:16:31:16 | Load | test.cpp:32:16:32:16 | Load |
| test.cpp:31:16:31:16 | Load | test.cpp:33:16:33:16 | Load |
| test.cpp:31:16:31:16 | Load | test.cpp:33:16:33:16 | Load |
| test.cpp:31:16:31:16 | Load | test.cpp:34:16:34:16 | Load |
| test.cpp:31:16:31:16 | Load | test.cpp:34:16:34:16 | Load |
| test.cpp:31:16:31:16 | Load | test.cpp:35:16:35:16 | Load |
| test.cpp:31:16:31:16 | Load | test.cpp:35:16:35:16 | Load |
| test.cpp:31:16:31:16 | Load | test.cpp:36:16:36:16 | Load |
| test.cpp:32:16:32:16 | Load | test.cpp:30:14:30:15 | Load: * ... |
| test.cpp:32:16:32:16 | Load | test.cpp:30:14:30:15 | Load: * ... |
| test.cpp:32:16:32:16 | Load | test.cpp:32:14:32:21 | Load: * ... |
| test.cpp:32:16:32:16 | Load | test.cpp:32:14:32:21 | Load: * ... |
| test.cpp:32:16:32:16 | Load | test.cpp:33:16:33:16 | Load |
| test.cpp:32:16:32:16 | Load | test.cpp:33:16:33:16 | Load |
| test.cpp:32:16:32:16 | Load | test.cpp:34:16:34:16 | Load |
| test.cpp:32:16:32:16 | Load | test.cpp:34:16:34:16 | Load |
| test.cpp:32:16:32:16 | Load | test.cpp:35:16:35:16 | Load |
| test.cpp:32:16:32:16 | Load | test.cpp:35:16:35:16 | Load |
| test.cpp:32:16:32:16 | Load | test.cpp:36:16:36:16 | Load |
| test.cpp:32:16:32:20 | ... + ... | test.cpp:32:14:32:21 | Load: * ... |
| test.cpp:32:16:32:20 | ... + ... | test.cpp:32:14:32:21 | Load: * ... |
| test.cpp:33:16:33:16 | Load | test.cpp:30:14:30:15 | Load: * ... |
| test.cpp:33:16:33:16 | Load | test.cpp:30:14:30:15 | Load: * ... |
| test.cpp:33:16:33:16 | Load | test.cpp:32:14:32:21 | Load: * ... |
| test.cpp:33:16:33:16 | Load | test.cpp:32:14:32:21 | Load: * ... |
| test.cpp:33:16:33:16 | Load | test.cpp:34:16:34:16 | Load |
| test.cpp:33:16:33:16 | Load | test.cpp:34:16:34:16 | Load |
| test.cpp:33:16:33:16 | Load | test.cpp:35:16:35:16 | Load |
| test.cpp:33:16:33:16 | Load | test.cpp:35:16:35:16 | Load |
| test.cpp:33:16:33:16 | Load | test.cpp:36:16:36:16 | Load |
| test.cpp:34:16:34:16 | Load | test.cpp:30:14:30:15 | Load: * ... |
| test.cpp:34:16:34:16 | Load | test.cpp:30:14:30:15 | Load: * ... |
| test.cpp:34:16:34:16 | Load | test.cpp:32:14:32:21 | Load: * ... |
| test.cpp:34:16:34:16 | Load | test.cpp:32:14:32:21 | Load: * ... |
| test.cpp:34:16:34:16 | Load | test.cpp:35:16:35:16 | Load |
| test.cpp:34:16:34:16 | Load | test.cpp:35:16:35:16 | Load |
| test.cpp:34:16:34:16 | Load | test.cpp:36:16:36:16 | Load |
| test.cpp:35:16:35:16 | Load | test.cpp:30:14:30:15 | Load: * ... |
| test.cpp:35:16:35:16 | Load | test.cpp:30:14:30:15 | Load: * ... |
| test.cpp:35:16:35:16 | Load | test.cpp:32:14:32:21 | Load: * ... |
| test.cpp:35:16:35:16 | Load | test.cpp:32:14:32:21 | Load: * ... |
| test.cpp:35:16:35:16 | Load | test.cpp:36:16:36:16 | Load |
| test.cpp:36:16:36:16 | Load | test.cpp:30:14:30:15 | Load: * ... |
| test.cpp:36:16:36:16 | Load | test.cpp:30:14:30:15 | Load: * ... |
| test.cpp:36:16:36:16 | Load | test.cpp:32:14:32:21 | Load: * ... |
| test.cpp:36:16:36:16 | Load | test.cpp:32:14:32:21 | Load: * ... |
| test.cpp:40:15:40:20 | call to malloc | test.cpp:41:15:41:15 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:41:15:41:28 | ... + ... |
| test.cpp:41:15:41:15 | Load | test.cpp:41:15:41:28 | ... + ... |
| test.cpp:41:15:41:15 | Load | test.cpp:41:15:41:28 | ... + ... |
| test.cpp:41:15:41:15 | Load | test.cpp:41:15:41:28 | ... + ... |
| test.cpp:41:15:41:15 | Load | test.cpp:41:15:41:28 | Store |
| test.cpp:41:15:41:15 | Load | test.cpp:41:15:41:28 | Store |
| test.cpp:41:15:41:15 | Load | test.cpp:41:15:41:28 | Store |
| test.cpp:41:15:41:15 | Load | test.cpp:41:15:41:28 | Store |
| test.cpp:41:15:41:15 | Load | test.cpp:42:15:42:15 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:42:15:42:15 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:42:15:42:15 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:42:15:42:15 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:43:16:43:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:43:16:43:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:43:16:43:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:43:16:43:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:44:16:44:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:44:16:44:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:44:16:44:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:44:16:44:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:44:16:44:20 | ... + ... |
| test.cpp:41:15:41:15 | Load | test.cpp:44:16:44:20 | ... + ... |
| test.cpp:41:15:41:15 | Load | test.cpp:44:16:44:20 | ... + ... |
| test.cpp:41:15:41:15 | Load | test.cpp:44:16:44:20 | ... + ... |
| test.cpp:41:15:41:15 | Load | test.cpp:45:16:45:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:45:16:45:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:45:16:45:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:45:16:45:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:46:16:46:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:46:16:46:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:46:16:46:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:46:16:46:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:47:16:47:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:47:16:47:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:47:16:47:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:47:16:47:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:48:16:48:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:48:16:48:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:48:16:48:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:48:16:48:16 | Load |
| test.cpp:41:15:41:28 | ... + ... | test.cpp:41:15:41:28 | Store |
| test.cpp:41:15:41:28 | ... + ... | test.cpp:41:15:41:28 | Store |
| test.cpp:41:15:41:28 | ... + ... | test.cpp:42:14:42:15 | Load: * ... |
| test.cpp:41:15:41:28 | ... + ... | test.cpp:42:14:42:15 | Load: * ... |
| test.cpp:41:15:41:28 | ... + ... | test.cpp:42:15:42:15 | Load |
| test.cpp:41:15:41:28 | ... + ... | test.cpp:42:15:42:15 | Load |
| test.cpp:41:15:41:28 | ... + ... | test.cpp:43:16:43:16 | Load |
| test.cpp:41:15:41:28 | ... + ... | test.cpp:43:16:43:16 | Load |
| test.cpp:41:15:41:28 | ... + ... | test.cpp:44:14:44:21 | Load: * ... |
| test.cpp:41:15:41:28 | ... + ... | test.cpp:44:14:44:21 | Load: * ... |
| test.cpp:41:15:41:28 | ... + ... | test.cpp:44:16:44:16 | Load |
| test.cpp:41:15:41:28 | ... + ... | test.cpp:44:16:44:16 | Load |
| test.cpp:41:15:41:28 | ... + ... | test.cpp:45:16:45:16 | Load |
| test.cpp:41:15:41:28 | ... + ... | test.cpp:45:16:45:16 | Load |
| test.cpp:41:15:41:28 | ... + ... | test.cpp:46:16:46:16 | Load |
| test.cpp:41:15:41:28 | ... + ... | test.cpp:46:16:46:16 | Load |
| test.cpp:41:15:41:28 | ... + ... | test.cpp:47:16:47:16 | Load |
| test.cpp:41:15:41:28 | ... + ... | test.cpp:47:16:47:16 | Load |
| test.cpp:41:15:41:28 | ... + ... | test.cpp:48:16:48:16 | Load |
| test.cpp:41:15:41:28 | Store | test.cpp:42:14:42:15 | Load: * ... |
| test.cpp:41:15:41:28 | Store | test.cpp:42:14:42:15 | Load: * ... |
| test.cpp:41:15:41:28 | Store | test.cpp:42:15:42:15 | Load |
| test.cpp:41:15:41:28 | Store | test.cpp:42:15:42:15 | Load |
| test.cpp:41:15:41:28 | Store | test.cpp:43:16:43:16 | Load |
| test.cpp:41:15:41:28 | Store | test.cpp:43:16:43:16 | Load |
| test.cpp:41:15:41:28 | Store | test.cpp:44:14:44:21 | Load: * ... |
| test.cpp:41:15:41:28 | Store | test.cpp:44:14:44:21 | Load: * ... |
| test.cpp:41:15:41:28 | Store | test.cpp:44:16:44:16 | Load |
| test.cpp:41:15:41:28 | Store | test.cpp:44:16:44:16 | Load |
| test.cpp:41:15:41:28 | Store | test.cpp:45:16:45:16 | Load |
| test.cpp:41:15:41:28 | Store | test.cpp:45:16:45:16 | Load |
| test.cpp:41:15:41:28 | Store | test.cpp:46:16:46:16 | Load |
| test.cpp:41:15:41:28 | Store | test.cpp:46:16:46:16 | Load |
| test.cpp:41:15:41:28 | Store | test.cpp:47:16:47:16 | Load |
| test.cpp:41:15:41:28 | Store | test.cpp:47:16:47:16 | Load |
| test.cpp:41:15:41:28 | Store | test.cpp:48:16:48:16 | Load |
| test.cpp:42:15:42:15 | Load | test.cpp:42:14:42:15 | Load: * ... |
| test.cpp:42:15:42:15 | Load | test.cpp:42:14:42:15 | Load: * ... |
| test.cpp:42:15:42:15 | Load | test.cpp:43:16:43:16 | Load |
| test.cpp:42:15:42:15 | Load | test.cpp:43:16:43:16 | Load |
| test.cpp:42:15:42:15 | Load | test.cpp:44:14:44:21 | Load: * ... |
| test.cpp:42:15:42:15 | Load | test.cpp:44:14:44:21 | Load: * ... |
| test.cpp:42:15:42:15 | Load | test.cpp:44:16:44:16 | Load |
| test.cpp:42:15:42:15 | Load | test.cpp:44:16:44:16 | Load |
| test.cpp:42:15:42:15 | Load | test.cpp:45:16:45:16 | Load |
| test.cpp:42:15:42:15 | Load | test.cpp:45:16:45:16 | Load |
| test.cpp:42:15:42:15 | Load | test.cpp:46:16:46:16 | Load |
| test.cpp:42:15:42:15 | Load | test.cpp:46:16:46:16 | Load |
| test.cpp:42:15:42:15 | Load | test.cpp:47:16:47:16 | Load |
| test.cpp:42:15:42:15 | Load | test.cpp:47:16:47:16 | Load |
| test.cpp:42:15:42:15 | Load | test.cpp:48:16:48:16 | Load |
| test.cpp:43:16:43:16 | Load | test.cpp:42:14:42:15 | Load: * ... |
| test.cpp:43:16:43:16 | Load | test.cpp:42:14:42:15 | Load: * ... |
| test.cpp:43:16:43:16 | Load | test.cpp:44:14:44:21 | Load: * ... |
| test.cpp:43:16:43:16 | Load | test.cpp:44:14:44:21 | Load: * ... |
| test.cpp:43:16:43:16 | Load | test.cpp:44:16:44:16 | Load |
| test.cpp:43:16:43:16 | Load | test.cpp:44:16:44:16 | Load |
| test.cpp:43:16:43:16 | Load | test.cpp:45:16:45:16 | Load |
| test.cpp:43:16:43:16 | Load | test.cpp:45:16:45:16 | Load |
| test.cpp:43:16:43:16 | Load | test.cpp:46:16:46:16 | Load |
| test.cpp:43:16:43:16 | Load | test.cpp:46:16:46:16 | Load |
| test.cpp:43:16:43:16 | Load | test.cpp:47:16:47:16 | Load |
| test.cpp:43:16:43:16 | Load | test.cpp:47:16:47:16 | Load |
| test.cpp:43:16:43:16 | Load | test.cpp:48:16:48:16 | Load |
| test.cpp:44:16:44:16 | Load | test.cpp:42:14:42:15 | Load: * ... |
| test.cpp:44:16:44:16 | Load | test.cpp:42:14:42:15 | Load: * ... |
| test.cpp:44:16:44:16 | Load | test.cpp:44:14:44:21 | Load: * ... |
| test.cpp:44:16:44:16 | Load | test.cpp:44:14:44:21 | Load: * ... |
| test.cpp:44:16:44:16 | Load | test.cpp:45:16:45:16 | Load |
| test.cpp:44:16:44:16 | Load | test.cpp:45:16:45:16 | Load |
| test.cpp:44:16:44:16 | Load | test.cpp:46:16:46:16 | Load |
| test.cpp:44:16:44:16 | Load | test.cpp:46:16:46:16 | Load |
| test.cpp:44:16:44:16 | Load | test.cpp:47:16:47:16 | Load |
| test.cpp:44:16:44:16 | Load | test.cpp:47:16:47:16 | Load |
| test.cpp:44:16:44:16 | Load | test.cpp:48:16:48:16 | Load |
| test.cpp:44:16:44:20 | ... + ... | test.cpp:44:14:44:21 | Load: * ... |
| test.cpp:44:16:44:20 | ... + ... | test.cpp:44:14:44:21 | Load: * ... |
| test.cpp:45:16:45:16 | Load | test.cpp:42:14:42:15 | Load: * ... |
| test.cpp:45:16:45:16 | Load | test.cpp:42:14:42:15 | Load: * ... |
| test.cpp:45:16:45:16 | Load | test.cpp:44:14:44:21 | Load: * ... |
| test.cpp:45:16:45:16 | Load | test.cpp:44:14:44:21 | Load: * ... |
| test.cpp:45:16:45:16 | Load | test.cpp:46:16:46:16 | Load |
| test.cpp:45:16:45:16 | Load | test.cpp:46:16:46:16 | Load |
| test.cpp:45:16:45:16 | Load | test.cpp:47:16:47:16 | Load |
| test.cpp:45:16:45:16 | Load | test.cpp:47:16:47:16 | Load |
| test.cpp:45:16:45:16 | Load | test.cpp:48:16:48:16 | Load |
| test.cpp:46:16:46:16 | Load | test.cpp:42:14:42:15 | Load: * ... |
| test.cpp:46:16:46:16 | Load | test.cpp:42:14:42:15 | Load: * ... |
| test.cpp:46:16:46:16 | Load | test.cpp:44:14:44:21 | Load: * ... |
| test.cpp:46:16:46:16 | Load | test.cpp:44:14:44:21 | Load: * ... |
| test.cpp:46:16:46:16 | Load | test.cpp:47:16:47:16 | Load |
| test.cpp:46:16:46:16 | Load | test.cpp:47:16:47:16 | Load |
| test.cpp:46:16:46:16 | Load | test.cpp:48:16:48:16 | Load |
| test.cpp:47:16:47:16 | Load | test.cpp:42:14:42:15 | Load: * ... |
| test.cpp:47:16:47:16 | Load | test.cpp:42:14:42:15 | Load: * ... |
| test.cpp:47:16:47:16 | Load | test.cpp:44:14:44:21 | Load: * ... |
| test.cpp:47:16:47:16 | Load | test.cpp:44:14:44:21 | Load: * ... |
| test.cpp:47:16:47:16 | Load | test.cpp:48:16:48:16 | Load |
| test.cpp:48:16:48:16 | Load | test.cpp:42:14:42:15 | Load: * ... |
| test.cpp:48:16:48:16 | Load | test.cpp:42:14:42:15 | Load: * ... |
| test.cpp:48:16:48:16 | Load | test.cpp:44:14:44:21 | Load: * ... |
| test.cpp:48:16:48:16 | Load | test.cpp:44:14:44:21 | Load: * ... |
| test.cpp:51:7:51:14 | VariableAddress indirection | test.cpp:62:39:62:39 | Load |
| test.cpp:51:7:51:14 | VariableAddress indirection | test.cpp:66:39:66:39 | Load |
| test.cpp:51:7:51:14 | VariableAddress indirection | test.cpp:70:38:70:38 | Load |
| test.cpp:51:33:51:35 | Load indirection | test.cpp:60:34:60:37 | mk_array output argument |
| test.cpp:52:19:52:24 | call to malloc | test.cpp:51:7:51:14 | VariableAddress indirection |
| test.cpp:52:19:52:24 | call to malloc | test.cpp:53:12:53:16 | Load |
| test.cpp:53:5:53:23 | Store | test.cpp:51:33:51:35 | Load indirection |
| test.cpp:53:12:53:16 | Load | test.cpp:53:5:53:23 | Store |
| test.cpp:53:12:53:16 | Load | test.cpp:53:5:53:23 | Store |
| test.cpp:53:12:53:16 | Load | test.cpp:53:12:53:23 | ... + ... |
| test.cpp:53:12:53:16 | Load | test.cpp:53:12:53:23 | ... + ... |
| test.cpp:53:12:53:23 | ... + ... | test.cpp:51:33:51:35 | Load indirection |
| test.cpp:60:34:60:37 | mk_array output argument | test.cpp:62:32:62:34 | Load |
| test.cpp:60:34:60:37 | mk_array output argument | test.cpp:66:32:66:34 | Load |
| test.cpp:60:34:60:37 | mk_array output argument | test.cpp:70:31:70:33 | Load |
| test.cpp:62:32:62:34 | Load | test.cpp:67:9:67:14 | Store: ... = ... |
| test.cpp:62:32:62:34 | Load | test.cpp:67:9:67:14 | Store: ... = ... |
| test.cpp:66:32:66:34 | Load | test.cpp:67:9:67:14 | Store: ... = ... |
| test.cpp:66:32:66:34 | Load | test.cpp:67:9:67:14 | Store: ... = ... |
| test.cpp:70:31:70:33 | Load | test.cpp:67:9:67:14 | Store: ... = ... |
| test.cpp:70:31:70:33 | Load | test.cpp:67:9:67:14 | Store: ... = ... |
| test.cpp:80:9:80:16 | VariableAddress indirection [begin] | test.cpp:91:20:91:22 | arr indirection [begin] |
| test.cpp:80:9:80:16 | VariableAddress indirection [begin] | test.cpp:95:20:95:22 | arr indirection [begin] |
| test.cpp:80:9:80:16 | VariableAddress indirection [begin] | test.cpp:99:20:99:22 | arr indirection [begin] |
| test.cpp:80:9:80:16 | VariableAddress indirection [begin] | test.cpp:119:18:119:25 | call to mk_array [begin] |
| test.cpp:80:9:80:16 | VariableAddress indirection [end] | test.cpp:91:36:91:38 | arr indirection [end] |
| test.cpp:80:9:80:16 | VariableAddress indirection [end] | test.cpp:95:36:95:38 | arr indirection [end] |
| test.cpp:80:9:80:16 | VariableAddress indirection [end] | test.cpp:99:35:99:37 | arr indirection [end] |
| test.cpp:80:9:80:16 | VariableAddress indirection [end] | test.cpp:119:18:119:25 | call to mk_array [end] |
| test.cpp:82:5:82:28 | Store | test.cpp:82:9:82:13 | arr indirection [post update] [begin] |
| test.cpp:82:9:82:13 | arr indirection [post update] [begin] | test.cpp:80:9:80:16 | VariableAddress indirection [begin] |
| test.cpp:82:9:82:13 | arr indirection [post update] [begin] | test.cpp:83:15:83:17 | arr indirection [begin] |
| test.cpp:82:17:82:22 | call to malloc | test.cpp:82:5:82:28 | Store |
| test.cpp:83:5:83:30 | Store | test.cpp:83:9:83:11 | arr indirection [post update] [end] |
| test.cpp:83:9:83:11 | arr indirection [post update] [end] | test.cpp:80:9:80:16 | VariableAddress indirection [end] |
| test.cpp:83:15:83:17 | arr indirection [begin] | test.cpp:83:19:83:23 | begin |
| test.cpp:83:15:83:30 | ... + ... | test.cpp:83:5:83:30 | Store |
| test.cpp:83:19:83:23 | Load | test.cpp:83:5:83:30 | Store |
| test.cpp:83:19:83:23 | Load | test.cpp:83:5:83:30 | Store |
| test.cpp:83:19:83:23 | Load | test.cpp:83:15:83:30 | ... + ... |
| test.cpp:83:19:83:23 | Load | test.cpp:83:15:83:30 | ... + ... |
| test.cpp:83:19:83:23 | begin | test.cpp:83:19:83:23 | Load |
| test.cpp:91:20:91:22 | arr indirection [begin] | test.cpp:91:24:91:28 | begin |
| test.cpp:91:20:91:22 | arr indirection [begin] | test.cpp:91:47:91:47 | Load |
| test.cpp:91:24:91:28 | begin | test.cpp:91:47:91:47 | Load |
| test.cpp:91:36:91:38 | arr indirection [end] | test.cpp:91:40:91:42 | end |
| test.cpp:91:40:91:42 | Load | test.cpp:96:9:96:14 | Store: ... = ... |
| test.cpp:91:40:91:42 | Load | test.cpp:96:9:96:14 | Store: ... = ... |
| test.cpp:91:40:91:42 | end | test.cpp:91:40:91:42 | Load |
| test.cpp:95:20:95:22 | arr indirection [begin] | test.cpp:95:24:95:28 | begin |
| test.cpp:95:20:95:22 | arr indirection [begin] | test.cpp:95:47:95:47 | Load |
| test.cpp:95:24:95:28 | begin | test.cpp:95:47:95:47 | Load |
| test.cpp:95:36:95:38 | arr indirection [end] | test.cpp:95:40:95:42 | end |
| test.cpp:95:40:95:42 | Load | test.cpp:96:9:96:14 | Store: ... = ... |
| test.cpp:95:40:95:42 | Load | test.cpp:96:9:96:14 | Store: ... = ... |
| test.cpp:95:40:95:42 | end | test.cpp:95:40:95:42 | Load |
| test.cpp:99:20:99:22 | arr indirection [begin] | test.cpp:99:24:99:28 | begin |
| test.cpp:99:20:99:22 | arr indirection [begin] | test.cpp:99:46:99:46 | Load |
| test.cpp:99:24:99:28 | begin | test.cpp:99:46:99:46 | Load |
| test.cpp:99:35:99:37 | arr indirection [end] | test.cpp:99:39:99:41 | end |
| test.cpp:99:39:99:41 | Load | test.cpp:96:9:96:14 | Store: ... = ... |
| test.cpp:99:39:99:41 | Load | test.cpp:96:9:96:14 | Store: ... = ... |
| test.cpp:99:39:99:41 | end | test.cpp:99:39:99:41 | Load |
| test.cpp:104:27:104:29 | arr [begin] | test.cpp:105:20:105:22 | arr indirection [begin] |
| test.cpp:104:27:104:29 | arr [begin] | test.cpp:109:20:109:22 | arr indirection [begin] |
| test.cpp:104:27:104:29 | arr [begin] | test.cpp:113:20:113:22 | arr indirection [begin] |
| test.cpp:104:27:104:29 | arr [end] | test.cpp:105:36:105:38 | arr indirection [end] |
| test.cpp:104:27:104:29 | arr [end] | test.cpp:109:36:109:38 | arr indirection [end] |
| test.cpp:104:27:104:29 | arr [end] | test.cpp:113:35:113:37 | arr indirection [end] |
| test.cpp:105:20:105:22 | arr indirection [begin] | test.cpp:105:24:105:28 | begin |
| test.cpp:105:20:105:22 | arr indirection [begin] | test.cpp:105:47:105:47 | Load |
| test.cpp:105:24:105:28 | begin | test.cpp:105:47:105:47 | Load |
| test.cpp:105:36:105:38 | arr indirection [end] | test.cpp:105:40:105:42 | end |
| test.cpp:105:40:105:42 | Load | test.cpp:110:9:110:14 | Store: ... = ... |
| test.cpp:105:40:105:42 | Load | test.cpp:110:9:110:14 | Store: ... = ... |
| test.cpp:105:40:105:42 | end | test.cpp:105:40:105:42 | Load |
| test.cpp:109:20:109:22 | arr indirection [begin] | test.cpp:109:24:109:28 | begin |
| test.cpp:109:20:109:22 | arr indirection [begin] | test.cpp:109:47:109:47 | Load |
| test.cpp:109:24:109:28 | begin | test.cpp:109:47:109:47 | Load |
| test.cpp:109:36:109:38 | arr indirection [end] | test.cpp:109:40:109:42 | end |
| test.cpp:109:40:109:42 | Load | test.cpp:110:9:110:14 | Store: ... = ... |
| test.cpp:109:40:109:42 | Load | test.cpp:110:9:110:14 | Store: ... = ... |
| test.cpp:109:40:109:42 | end | test.cpp:109:40:109:42 | Load |
| test.cpp:113:20:113:22 | arr indirection [begin] | test.cpp:113:24:113:28 | begin |
| test.cpp:113:20:113:22 | arr indirection [begin] | test.cpp:113:46:113:46 | Load |
| test.cpp:113:24:113:28 | begin | test.cpp:113:46:113:46 | Load |
| test.cpp:113:35:113:37 | arr indirection [end] | test.cpp:113:39:113:41 | end |
| test.cpp:113:39:113:41 | Load | test.cpp:110:9:110:14 | Store: ... = ... |
| test.cpp:113:39:113:41 | Load | test.cpp:110:9:110:14 | Store: ... = ... |
| test.cpp:113:39:113:41 | end | test.cpp:113:39:113:41 | Load |
| test.cpp:119:18:119:25 | call to mk_array [begin] | test.cpp:104:27:104:29 | arr [begin] |
| test.cpp:119:18:119:25 | call to mk_array [end] | test.cpp:104:27:104:29 | arr [end] |
| test.cpp:124:15:124:20 | call to malloc | test.cpp:125:5:125:17 | Store |
| test.cpp:124:15:124:20 | call to malloc | test.cpp:126:15:126:15 | Load |
| test.cpp:125:5:125:17 | Store | test.cpp:125:9:125:13 | arr indirection [post update] [begin] |
| test.cpp:125:9:125:13 | arr indirection [post update] [begin] | test.cpp:129:11:129:13 | arr indirection [begin] |
| test.cpp:125:9:125:13 | arr indirection [post update] [begin] | test.cpp:133:11:133:13 | arr indirection [begin] |
| test.cpp:125:9:125:13 | arr indirection [post update] [begin] | test.cpp:137:11:137:13 | arr indirection [begin] |
| test.cpp:129:11:129:13 | arr indirection [begin] | test.cpp:129:15:129:19 | begin |
| test.cpp:129:15:129:19 | begin | test.cpp:129:15:129:19 | Load |
| test.cpp:133:11:133:13 | arr indirection [begin] | test.cpp:133:15:133:19 | begin |
| test.cpp:133:15:133:19 | begin | test.cpp:133:15:133:19 | Load |
| test.cpp:137:11:137:13 | arr indirection [begin] | test.cpp:137:15:137:19 | begin |
| test.cpp:137:15:137:19 | begin | test.cpp:137:15:137:19 | Load |
| test.cpp:141:10:141:19 | VariableAddress indirection [begin] | test.cpp:150:20:150:29 | Call indirection [begin] |
| test.cpp:141:10:141:19 | VariableAddress indirection [begin] | test.cpp:180:19:180:28 | call to mk_array_p indirection [begin] |
| test.cpp:141:10:141:19 | VariableAddress indirection [end] | test.cpp:150:20:150:29 | Call indirection [end] |
| test.cpp:141:10:141:19 | VariableAddress indirection [end] | test.cpp:180:19:180:28 | call to mk_array_p indirection [end] |
| test.cpp:143:5:143:29 | Store | test.cpp:143:10:143:14 | Load indirection [post update] [begin] |
| test.cpp:143:10:143:14 | Load indirection [post update] [begin] | test.cpp:141:10:141:19 | VariableAddress indirection [begin] |
| test.cpp:143:10:143:14 | Load indirection [post update] [begin] | test.cpp:144:16:144:18 | Load indirection [begin] |
| test.cpp:143:18:143:23 | call to malloc | test.cpp:143:5:143:29 | Store |
| test.cpp:144:5:144:32 | Store | test.cpp:144:10:144:12 | Load indirection [post update] [end] |
| test.cpp:144:10:144:12 | Load indirection [post update] [end] | test.cpp:141:10:141:19 | VariableAddress indirection [end] |
| test.cpp:144:16:144:18 | Load indirection [begin] | test.cpp:144:21:144:25 | begin |
| test.cpp:144:16:144:32 | ... + ... | test.cpp:144:5:144:32 | Store |
| test.cpp:144:21:144:25 | Load | test.cpp:144:5:144:32 | Store |
| test.cpp:144:21:144:25 | Load | test.cpp:144:5:144:32 | Store |
| test.cpp:144:21:144:25 | Load | test.cpp:144:16:144:32 | ... + ... |
| test.cpp:144:21:144:25 | Load | test.cpp:144:16:144:32 | ... + ... |
| test.cpp:144:21:144:25 | begin | test.cpp:144:21:144:25 | Load |
| test.cpp:150:20:150:29 | Call indirection [begin] | test.cpp:152:20:152:22 | Load indirection [begin] |
| test.cpp:150:20:150:29 | Call indirection [begin] | test.cpp:156:20:156:22 | Load indirection [begin] |
| test.cpp:150:20:150:29 | Call indirection [begin] | test.cpp:160:20:160:22 | Load indirection [begin] |
| test.cpp:150:20:150:29 | Call indirection [end] | test.cpp:156:37:156:39 | Load indirection [end] |
| test.cpp:152:20:152:22 | Load indirection [begin] | test.cpp:152:25:152:29 | begin |
| test.cpp:152:20:152:22 | Load indirection [begin] | test.cpp:152:49:152:49 | Load |
| test.cpp:152:25:152:29 | begin | test.cpp:152:49:152:49 | Load |
| test.cpp:156:20:156:22 | Load indirection [begin] | test.cpp:156:25:156:29 | begin |
| test.cpp:156:20:156:22 | Load indirection [begin] | test.cpp:156:49:156:49 | Load |
| test.cpp:156:25:156:29 | begin | test.cpp:156:49:156:49 | Load |
| test.cpp:156:37:156:39 | Load indirection [end] | test.cpp:156:42:156:44 | end |
| test.cpp:156:42:156:44 | Load | test.cpp:157:9:157:14 | Store: ... = ... |
| test.cpp:156:42:156:44 | Load | test.cpp:157:9:157:14 | Store: ... = ... |
| test.cpp:156:42:156:44 | end | test.cpp:156:42:156:44 | Load |
| test.cpp:160:20:160:22 | Load indirection [begin] | test.cpp:160:25:160:29 | begin |
| test.cpp:160:20:160:22 | Load indirection [begin] | test.cpp:160:48:160:48 | Load |
| test.cpp:160:25:160:29 | begin | test.cpp:160:48:160:48 | Load |
| test.cpp:165:29:165:31 | arr indirection [begin] | test.cpp:166:20:166:22 | Load indirection [begin] |
| test.cpp:165:29:165:31 | arr indirection [begin] | test.cpp:170:20:170:22 | Load indirection [begin] |
| test.cpp:165:29:165:31 | arr indirection [begin] | test.cpp:174:20:174:22 | Load indirection [begin] |
| test.cpp:165:29:165:31 | arr indirection [end] | test.cpp:166:37:166:39 | Load indirection [end] |
| test.cpp:165:29:165:31 | arr indirection [end] | test.cpp:170:37:170:39 | Load indirection [end] |
| test.cpp:165:29:165:31 | arr indirection [end] | test.cpp:174:36:174:38 | Load indirection [end] |
| test.cpp:166:20:166:22 | Load indirection [begin] | test.cpp:166:25:166:29 | begin |
| test.cpp:166:20:166:22 | Load indirection [begin] | test.cpp:166:49:166:49 | Load |
| test.cpp:166:25:166:29 | begin | test.cpp:166:49:166:49 | Load |
| test.cpp:166:37:166:39 | Load indirection [end] | test.cpp:166:42:166:44 | end |
| test.cpp:166:42:166:44 | Load | test.cpp:171:9:171:14 | Store: ... = ... |
| test.cpp:166:42:166:44 | Load | test.cpp:171:9:171:14 | Store: ... = ... |
| test.cpp:166:42:166:44 | end | test.cpp:166:42:166:44 | Load |
| test.cpp:170:20:170:22 | Load indirection [begin] | test.cpp:170:25:170:29 | begin |
| test.cpp:170:20:170:22 | Load indirection [begin] | test.cpp:170:49:170:49 | Load |
| test.cpp:170:25:170:29 | begin | test.cpp:170:49:170:49 | Load |
| test.cpp:170:37:170:39 | Load indirection [end] | test.cpp:170:42:170:44 | end |
| test.cpp:170:42:170:44 | Load | test.cpp:171:9:171:14 | Store: ... = ... |
| test.cpp:170:42:170:44 | Load | test.cpp:171:9:171:14 | Store: ... = ... |
| test.cpp:170:42:170:44 | end | test.cpp:170:42:170:44 | Load |
| test.cpp:174:20:174:22 | Load indirection [begin] | test.cpp:174:25:174:29 | begin |
| test.cpp:174:20:174:22 | Load indirection [begin] | test.cpp:174:48:174:48 | Load |
| test.cpp:174:25:174:29 | begin | test.cpp:174:48:174:48 | Load |
| test.cpp:174:36:174:38 | Load indirection [end] | test.cpp:174:41:174:43 | end |
| test.cpp:174:41:174:43 | Load | test.cpp:171:9:171:14 | Store: ... = ... |
| test.cpp:174:41:174:43 | Load | test.cpp:171:9:171:14 | Store: ... = ... |
| test.cpp:174:41:174:43 | end | test.cpp:174:41:174:43 | Load |
| test.cpp:180:19:180:28 | call to mk_array_p indirection [begin] | test.cpp:165:29:165:31 | arr indirection [begin] |
| test.cpp:180:19:180:28 | call to mk_array_p indirection [end] | test.cpp:165:29:165:31 | arr indirection [end] |
| test.cpp:188:15:188:20 | call to malloc | test.cpp:189:15:189:15 | Load |
#select
| test.cpp:6:14:6:15 | Load: * ... | test.cpp:4:15:4:20 | call to malloc | test.cpp:6:14:6:15 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:4:15:4:20 | call to malloc | call to malloc | test.cpp:5:19:5:22 | size | size |
| test.cpp:8:14:8:21 | Load: * ... | test.cpp:4:15:4:20 | call to malloc | test.cpp:8:14:8:21 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 1. | test.cpp:4:15:4:20 | call to malloc | call to malloc | test.cpp:5:19:5:22 | size | size |
| test.cpp:8:14:8:21 | Load: * ... | test.cpp:4:15:4:20 | call to malloc | test.cpp:8:14:8:21 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:4:15:4:20 | call to malloc | call to malloc | test.cpp:5:19:5:22 | size | size |
| test.cpp:20:14:20:21 | Load: * ... | test.cpp:16:15:16:20 | call to malloc | test.cpp:20:14:20:21 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:16:15:16:20 | call to malloc | call to malloc | test.cpp:17:19:17:22 | size | size |
| test.cpp:30:14:30:15 | Load: * ... | test.cpp:28:15:28:20 | call to malloc | test.cpp:30:14:30:15 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:28:15:28:20 | call to malloc | call to malloc | test.cpp:29:20:29:27 | ... + ... | ... + ... |
| test.cpp:32:14:32:21 | Load: * ... | test.cpp:28:15:28:20 | call to malloc | test.cpp:32:14:32:21 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 1. | test.cpp:28:15:28:20 | call to malloc | call to malloc | test.cpp:29:20:29:27 | ... + ... | ... + ... |
| test.cpp:32:14:32:21 | Load: * ... | test.cpp:28:15:28:20 | call to malloc | test.cpp:32:14:32:21 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:28:15:28:20 | call to malloc | call to malloc | test.cpp:29:20:29:27 | ... + ... | ... + ... |
| test.cpp:42:14:42:15 | Load: * ... | test.cpp:40:15:40:20 | call to malloc | test.cpp:42:14:42:15 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:40:15:40:20 | call to malloc | call to malloc | test.cpp:41:20:41:27 | ... - ... | ... - ... |
| test.cpp:44:14:44:21 | Load: * ... | test.cpp:40:15:40:20 | call to malloc | test.cpp:44:14:44:21 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 1. | test.cpp:40:15:40:20 | call to malloc | call to malloc | test.cpp:41:20:41:27 | ... - ... | ... - ... |
| test.cpp:44:14:44:21 | Load: * ... | test.cpp:40:15:40:20 | call to malloc | test.cpp:44:14:44:21 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:40:15:40:20 | call to malloc | call to malloc | test.cpp:41:20:41:27 | ... - ... | ... - ... |
| test.cpp:67:9:67:14 | Store: ... = ... | test.cpp:52:19:52:24 | call to malloc | test.cpp:67:9:67:14 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:52:19:52:24 | call to malloc | call to malloc | test.cpp:53:20:53:23 | size | size |
| test.cpp:96:9:96:14 | Store: ... = ... | test.cpp:82:17:82:22 | call to malloc | test.cpp:96:9:96:14 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:82:17:82:22 | call to malloc | call to malloc | test.cpp:83:27:83:30 | size | size |
| test.cpp:110:9:110:14 | Store: ... = ... | test.cpp:82:17:82:22 | call to malloc | test.cpp:110:9:110:14 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:82:17:82:22 | call to malloc | call to malloc | test.cpp:83:27:83:30 | size | size |
| test.cpp:157:9:157:14 | Store: ... = ... | test.cpp:143:18:143:23 | call to malloc | test.cpp:157:9:157:14 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:143:18:143:23 | call to malloc | call to malloc | test.cpp:144:29:144:32 | size | size |
| test.cpp:171:9:171:14 | Store: ... = ... | test.cpp:143:18:143:23 | call to malloc | test.cpp:171:9:171:14 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:143:18:143:23 | call to malloc | call to malloc | test.cpp:144:29:144:32 | size | size |

Просмотреть файл

@ -0,0 +1 @@
experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql

Просмотреть файл

@ -0,0 +1,191 @@
char *malloc(int size);
void test1(int size) {
char* p = malloc(size);
char* q = p + size;
char a = *q; // BAD
char b = *(q - 1); // GOOD
char c = *(q + 1); // BAD
char d = *(q + size); // BAD [NOT DETECTED]
char e = *(q - size); // GOOD
char f = *(q + size + 1); // BAD [NOT DETECTED]
char g = *(q - size - 1); // GOOD
}
void test2(int size) {
char* p = malloc(size);
char* q = p + size - 1;
char a = *q; // GOOD
char b = *(q - 1); // GOOD
char c = *(q + 1); // BAD
char d = *(q + size); // BAD [NOT DETECTED]
char e = *(q - size); // GOOD
char f = *(q + size + 1); // BAD [NOT DETECTED]
char g = *(q - size - 1); // GOOD
}
void test3(int size) {
char* p = malloc(size + 1);
char* q = p + (size + 1);
char a = *q; // BAD
char b = *(q - 1); // GOOD
char c = *(q + 1); // BAD
char d = *(q + size); // BAD [NOT DETECTED]
char e = *(q - size); // GOOD
char f = *(q + size + 1); // BAD [NOT DETECTED]
char g = *(q - size - 1); // GOOD
}
void test4(int size) {
char* p = malloc(size - 1);
char* q = p + (size - 1);
char a = *q; // BAD
char b = *(q - 1); // GOOD
char c = *(q + 1); // BAD
char d = *(q + size); // BAD [NOT DETECTED]
char e = *(q - size); // GOOD
char f = *(q + size + 1); // BAD [NOT DETECTED]
char g = *(q - size - 1); // GOOD
}
char* mk_array(int size, char** end) {
char* begin = malloc(size);
*end = begin + size;
return begin;
}
void test5(int size) {
char* end;
char* begin = mk_array(size, &end);
for (char* p = begin; p != end; ++p) {
*p = 0; // GOOD
}
for (char* p = begin; p <= end; ++p) {
*p = 0; // BAD
}
for (char* p = begin; p < end; ++p) {
*p = 0; // GOOD
}
}
struct array_t {
char* begin;
char* end;
};
array_t mk_array(int size) {
array_t arr;
arr.begin = malloc(size);
arr.end = arr.begin + size;
return arr;
}
void test6(int size) {
array_t arr = mk_array(size);
for (char* p = arr.begin; p != arr.end; ++p) {
*p = 0; // GOOD
}
for (char* p = arr.begin; p <= arr.end; ++p) {
*p = 0; // BAD
}
for (char* p = arr.begin; p < arr.end; ++p) {
*p = 0; // GOOD
}
}
void test7_callee(array_t arr) {
for (char* p = arr.begin; p != arr.end; ++p) {
*p = 0; // GOOD
}
for (char* p = arr.begin; p <= arr.end; ++p) {
*p = 0; // BAD
}
for (char* p = arr.begin; p < arr.end; ++p) {
*p = 0; // GOOD
}
}
void test7(int size) {
test7_callee(mk_array(size));
}
void test8(int size) {
array_t arr;
char* p = malloc(size);
arr.begin = p;
arr.end = p + size;
for (int i = 0; i < arr.end - arr.begin; i++) {
*(arr.begin + i) = 0; // GOOD
}
for (int i = 0; i != arr.end - arr.begin; i++) {
*(arr.begin + i) = 0; // GOOD
}
for (int i = 0; i <= arr.end - arr.begin; i++) {
*(arr.begin + i) = 0; // BAD [NOT DETECTED]
}
}
array_t *mk_array_p(int size) {
array_t *arr = (array_t*) malloc(sizeof(array_t));
arr->begin = malloc(size);
arr->end = arr->begin + size;
return arr;
}
void test9(int size) {
array_t *arr = mk_array_p(size);
for (char* p = arr->begin; p != arr->end; ++p) {
*p = 0; // GOOD
}
for (char* p = arr->begin; p <= arr->end; ++p) {
*p = 0; // BAD
}
for (char* p = arr->begin; p < arr->end; ++p) {
*p = 0; // GOOD
}
}
void test10_callee(array_t *arr) {
for (char* p = arr->begin; p != arr->end; ++p) {
*p = 0; // GOOD
}
for (char* p = arr->begin; p <= arr->end; ++p) {
*p = 0; // BAD
}
for (char* p = arr->begin; p < arr->end; ++p) {
*p = 0; // GOOD
}
}
void test10(int size) {
test10_callee(mk_array_p(size));
}
void deref_plus_one(char* q) {
char a = *(q + 1); // BAD [NOT DETECTED]
}
void test11(unsigned size) {
char *p = malloc(size);
char *q = p + size - 1;
deref_plus_one(q);
}

Просмотреть файл

@ -179,7 +179,15 @@ The select clause of each alert query defines the alert message that is displaye
* The message should factually describe the problem that is being highlighted–it should not contain recommendations about how to fix the problem or value judgements.
* Program element references should be in 'single quotes' to distinguish them from ordinary words. Quotes are not needed around substitutions (`$@`).
* Avoid constant alert message strings and include some context, if possible. For example, `The class 'Foo' is duplicated as 'Bar'.` is preferable to `This class is duplicated here.`
* If a reference to the current location can't be avoided use "this location" instead of "here". For example, `Bad thing at this location.` is preferable to `Bad thing here.`. This avoids the "click here" anti-pattern.
* For path queries, if possible, try to follow the template: `This path depends on a [user-provided value].`, or alternatively (if the first option doesn't work) `[User-provided value] flows to this location and is used in a path.`.
* Taint tracking queries generally have a sink that "depends on" the source, and dataflow queries generally have a source that "flows to" the sink.
### Links in alert messages
* Where you reference another program element, link to it if possible using a substitution (`$@`). Links should be used inline in the sentence, rather than as parenthesised lists or appositions.
* Avoid using link texts that don't describe what they link to. For example, rewrite `This sensitive data is written to a logfile unescaped [here]` to `This sensitive data is [written to a logfile unescaped]`.
* Make link text as concise and precise as possible. For example, avoid starting a link text with an indefinite article (a, an). `Path construction depends on a [user-provided value]` is preferable to `Path construction depends on [a user-provided value]`. (Where the square brackets indicate a link.) See [the W3C guide on link texts](https://www.w3.org/WAI/WCAG22/Understanding/link-purpose-in-context.html) for further information.
* When a message contains multiple links, construct a sentence that has the most variable link (that is, the link with most targets) last. For further information, see [Defining the results of a query](https://codeql.github.com/docs/writing-codeql-queries/defining-the-results-of-a-query/).
For examples of select clauses and alert messages, see the query source files at the following pages:

Просмотреть файл

@ -29,5 +29,7 @@ module InsecureRandomness {
/** Holds if `sink` is a sink for this configuration with kind `kind`. */
predicate isSink(Sink sink, string kind) { kind = sink.getKind() }
override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
}
}

Просмотреть файл

@ -6,8 +6,11 @@ import go
/** Provides classes and predicates shared between the XSS queries. */
module SharedXss {
/** A data flow source for XSS vulnerabilities. */
abstract class Source extends DataFlow::Node { }
/**
* DEPRECATED: This class is not used.
* A data flow source for XSS vulnerabilities.
*/
abstract deprecated class Source extends DataFlow::Node { }
/** A data flow sink for XSS vulnerabilities. */
abstract class Sink extends DataFlow::Node {

Просмотреть файл

@ -0,0 +1,7 @@
---
category: deprecated
---
* The predicate `Annotation.getAValue()` has been deprecated because it might lead to obtaining the value of the wrong annotation element by accident. `getValue(string)` (or one of the value type specific predicates) should be used to explicitly specify the name of the annotation element.
* The predicate `Annotation.getAValue(string)` has been renamed to `getAnArrayValue(string)`.
* The predicate `SuppressWarningsAnnotation.getASuppressedWarningLiteral()` has been deprecated because it unnecessarily restricts the result type; `getASuppressedWarning()` should be used instead.
* The predicates `TargetAnnotation.getATargetExpression()` and `RetentionAnnotation.getRetentionPolicyExpression()` have been deprecated because getting the enum constant read expression is rarely useful, instead the corresponding predicates for getting the name of the referenced enum constants should be used.

Просмотреть файл

@ -0,0 +1,9 @@
---
category: feature
---
* The predicates of the CodeQL class `Annotation` have been improved:
* Convenience value type specific predicates have been added, such as `getEnumConstantValue(string)` or `getStringValue(string)`.
* Convenience predicates for elements with array values have been added, such as `getAnEnumConstantArrayValue(string)`. While the behavior of the existing predicates has not changed, usage of them should be reviewed (or replaced with the newly added predicate) to make sure they work correctly for elements with array values.
* Some internal CodeQL usage of the `Annotation` predicates has been adjusted and corrected; this might affect the results of some queries.
* New predicates have been added to the CodeQL class `Annotatable` to support getting declared and associated annotations. As part of that, `hasAnnotation()` has been changed to also consider inherited annotations, to be consistent with `hasAnnotation(string, string)` and `getAnAnnotation()`. The newly added predicate `hasDeclaredAnnotation()` can be used as replacement for the old functionality.
* New predicates have been added to the CodeQL class `AnnotationType` to simplify getting information about usage of JDK meta-annotations, such as `@Retention`.

Просмотреть файл

@ -216,7 +216,7 @@ private predicate fixedHasLocation(Top l, Location loc, File f) {
min(Location candidateLoc |
hasLocation(l, candidateLoc)
|
candidateLoc order by candidateLoc.getFile().toString()
candidateLoc order by candidateLoc.getFile().getAbsolutePath()
) and
not hasSourceLocation(l, _, _) and
locations_default(loc, f, _, _, _, _)

Просмотреть файл

@ -44,12 +44,100 @@ class Annotation extends @annotation, Expr {
result = this.getType().getAnnotationElement(name)
}
/** Gets a value of an annotation element. */
Expr getAValue() { filteredAnnotValue(this, _, result) }
/**
* DEPRECATED: Getting the value of _any_ annotation element is error-prone because
* it could lead to selecting the value of the wrong element by accident (for example
* when an annotation type is extended in the future). Prefer the predicate `getValue(string)`
* and explicitly specify the element name. Use `getValue(_)` if it is really desired to
* get the value of any element.
*
* Gets a value of an annotation element. This includes default values in case
* no explicit value is specified. For elements with an array value type this
* might have an `ArrayInit` as result. To properly handle array values, prefer
* the predicate `getAnArrayValue`.
*/
deprecated Expr getAValue() { filteredAnnotValue(this, _, result) }
/** Gets the value of the annotation element with the specified `name`. */
/**
* Gets the value of the annotation element with the specified `name`.
* This includes default values in case no explicit value is specified.
* For elements with an array value type this might get an `ArrayInit` instance.
* To properly handle array values, prefer the predicate `getAnArrayValue`.
*/
Expr getValue(string name) { filteredAnnotValue(this, this.getAnnotationElement(name), result) }
/**
* Gets the value of the annotation element, if its type is not an array.
* This guarantees that for consistency even elements of type array with a
* single value have no result, to prevent accidental error-prone usage.
*/
private Expr getNonArrayValue(string name) {
result = this.getValue(name) and
not this.getAnnotationElement(name).getType() instanceof Array
}
/**
* If the value type of the annotation element with the specified `name` is an enum type,
* gets the enum constant used as value for that element. This includes default values in
* case no explicit value is specified.
*
* If the element value type is an enum type array, use `getAnEnumConstantArrayValue`.
*/
EnumConstant getEnumConstantValue(string name) {
result = this.getNonArrayValue(name).(FieldRead).getField()
}
/**
* If the value type of the annotation element with the specified `name` is `String`,
* gets the string value used for that element. This includes default values in case no
* explicit value is specified.
*
* If the element value type is a string array, use `getAStringArrayValue`.
*/
string getStringValue(string name) {
// Uses CompileTimeConstantExpr instead of StringLiteral because this can for example
// be a read from a final variable as well.
result = this.getNonArrayValue(name).(CompileTimeConstantExpr).getStringValue()
}
/**
* If the value type of the annotation element with the specified `name` is `int` or
* a smaller integral type or `char`, gets the int value used for that element.
* This includes default values in case no explicit value is specified.
*
* If the element value type is an `int` array or an array of a smaller integral
* type or `char`, use `getAnIntArrayValue`.
*/
int getIntValue(string name) {
// Uses CompileTimeConstantExpr instead of IntegerLiteral because this can for example
// be a read from a final variable as well.
result = this.getNonArrayValue(name).(CompileTimeConstantExpr).getIntValue() and
// Verify that type is integral; ignore floating point elements with IntegerLiteral as value
this.getAnnotationElement(name).getType().hasName(["byte", "short", "int", "char"])
}
/**
* If the value type of the annotation element with the specified `name` is `boolean`,
* gets the boolean value used for that element. This includes default values in case
* no explicit value is specified.
*/
boolean getBooleanValue(string name) {
// Uses CompileTimeConstantExpr instead of BooleanLiteral because this can for example
// be a read from a final variable as well.
result = this.getNonArrayValue(name).(CompileTimeConstantExpr).getBooleanValue()
}
/**
* If the value type of the annotation element with the specified `name` is `java.lang.Class`,
* gets the type referred to by that `Class`. This includes default values in case no explicit
* value is specified.
*
* If the element value type is a `Class` array, use `getATypeArrayValue`.
*/
Type getTypeValue(string name) {
result = this.getNonArrayValue(name).(TypeLiteral).getReferencedType()
}
/** Gets the element being annotated. */
Element getTarget() { result = this.getAnnotatedElement() }
@ -60,16 +148,83 @@ class Annotation extends @annotation, Expr {
/**
* Gets a value of the annotation element with the specified `name`, which must be declared as an array
* type.
* type. This includes default values in case no explicit value is specified.
*
* If the annotation element is defined with an array initializer, then the returned value will
* be one of the elements of that array. Otherwise, the returned value will be the single
* expression defined for the value.
* If the annotation element is defined with an array initializer, then the result will be one of the
* elements of that array. Otherwise, the result will be the single expression used as value.
*/
Expr getAValue(string name) {
Expr getAnArrayValue(string name) { result = this.getArrayValue(name, _) }
/**
* DEPRECATED: Predicate has been renamed to `getAnArrayValue`
*/
deprecated Expr getAValue(string name) { result = this.getAnArrayValue(name) }
/**
* Gets a value of the annotation element with the specified `name`, which must be declared as an enum
* type array. This includes default values in case no explicit value is specified.
*
* If the annotation element is defined with an array initializer, then the result will be one of the
* elements of that array. Otherwise, the result will be the single expression used as value.
*/
EnumConstant getAnEnumConstantArrayValue(string name) {
result = this.getAnArrayValue(name).(FieldRead).getField()
}
/**
* Gets a value of the annotation element with the specified `name`, which must be declared as a string
* array. This includes default values in case no explicit value is specified.
*
* If the annotation element is defined with an array initializer, then the result will be one of the
* elements of that array. Otherwise, the result will be the single expression used as value.
*/
string getAStringArrayValue(string name) {
result = this.getAnArrayValue(name).(CompileTimeConstantExpr).getStringValue()
}
/**
* Gets a value of the annotation element with the specified `name`, which must be declared as an `int`
* array or an array of a smaller integral type or `char`. This includes default values in case no
* explicit value is specified.
*
* If the annotation element is defined with an array initializer, then the result will be one of the
* elements of that array. Otherwise, the result will be the single expression used as value.
*/
int getAnIntArrayValue(string name) {
result = this.getAnArrayValue(name).(CompileTimeConstantExpr).getIntValue() and
// Verify that type is integral; ignore floating point elements with IntegerLiteral as value
this.getAnnotationElement(name).getType().hasName(["byte[]", "short[]", "int[]", "char[]"])
}
/**
* Gets a value of the annotation element with the specified `name`, which must be declared as a `Class`
* array. This includes default values in case no explicit value is specified.
*
* If the annotation element is defined with an array initializer, then the result will be one of the
* elements of that array. Otherwise, the result will be the single expression used as value.
*/
Type getATypeArrayValue(string name) {
result = this.getAnArrayValue(name).(TypeLiteral).getReferencedType()
}
/**
* Gets the value at a given index of the annotation element with the specified `name`, which must be
* declared as an array type. This includes default values in case no explicit value is specified.
*
* If the annotation element is defined with an array initializer, then the result will be the element
* at the given index of that array, starting at 0. Otherwise, the result will be the single expression
* defined for the value and the `index` will be 0.
*/
Expr getArrayValue(string name, int index) {
this.getType().getAnnotationElement(name).getType() instanceof Array and
exists(Expr value | value = this.getValue(name) |
if value instanceof ArrayInit then result = value.(ArrayInit).getAnInit() else result = value
if value instanceof ArrayInit
then
// TODO: Currently reports incorrect index values in some cases, see https://github.com/github/codeql/issues/8645
result = value.(ArrayInit).getInit(index)
else (
index = 0 and result = value
)
)
}
@ -99,19 +254,86 @@ private predicate sourceAnnotValue(Annotation a, Method m, Expr val) {
/** An abstract representation of language elements that can be annotated. */
class Annotatable extends Element {
/** Holds if this element has an annotation. */
predicate hasAnnotation() { exists(Annotation a | a.getAnnotatedElement() = this) }
/**
* Holds if this element has an annotation, including inherited annotations.
* The retention policy of the annotation type is not considered.
*/
predicate hasAnnotation() { exists(this.getAnAnnotation()) }
/** Holds if this element has the specified annotation. */
/**
* Holds if this element has a declared annotation, excluding inherited annotations.
* The retention policy of the annotation type is not considered.
*/
predicate hasDeclaredAnnotation() { exists(this.getADeclaredAnnotation()) }
/**
* Holds if this element has the specified annotation, including inherited
* annotations. The retention policy of the annotation type is not considered.
*/
predicate hasAnnotation(string package, string name) {
exists(AnnotationType at | at = this.getAnAnnotation().getType() |
at.nestedName() = name and at.getPackage().getName() = package
)
}
/** Gets an annotation that applies to this element. */
/**
* Gets an annotation that applies to this element, including inherited annotations.
* The results only include _direct_ annotations; _indirect_ annotations, that is
* repeated annotations in an (implicit) container annotation, are not included.
* The retention policy of the annotation type is not considered.
*/
cached
Annotation getAnAnnotation() { result.getAnnotatedElement() = this }
Annotation getAnAnnotation() {
// This predicate is overridden by Class to consider inherited annotations
result = this.getADeclaredAnnotation()
}
/**
* Gets an annotation that is declared on this element, excluding inherited annotations.
* The retention policy of the annotation type is not considered.
*/
Annotation getADeclaredAnnotation() { result.getAnnotatedElement() = this }
/** Gets an _indirect_ (= repeated) annotation. */
private Annotation getAnIndirectAnnotation() {
// 'indirect' as defined by https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/reflect/AnnotatedElement.html
exists(AnnotationType t, Annotation containerAnn |
t = result.getType() and
containerAnn = this.getADeclaredAnnotation() and
containerAnn.getType() = t.getContainingAnnotationType()
|
result = containerAnn.getAnArrayValue("value")
)
}
private Annotation getADeclaredAssociatedAnnotation(AnnotationType t) {
// Direct or indirect annotation
result.getType() = t and
result = [this.getADeclaredAnnotation(), this.getAnIndirectAnnotation()]
}
private Annotation getAnAssociatedAnnotation(AnnotationType t) {
// 'associated' as defined by https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/reflect/AnnotatedElement.html
if exists(this.getADeclaredAssociatedAnnotation(t))
then result = this.getADeclaredAssociatedAnnotation(t)
else (
// Only if neither a direct nor an indirect annotation is present look for an inherited one
t.isInherited() and
// @Inherited only works for classes; cast to Annotatable is necessary because predicate is private
result = this.(Class).getASupertype().(Class).(Annotatable).getAnAssociatedAnnotation(t)
)
}
/**
* Gets an annotation _associated_ with this element, that is:
* - An annotation directly present on this element, or
* - An annotation indirectly present on this element (in the form of a repeated annotation), or
* - If an annotation of a type is neither directly nor indirectly present
* the result is an associated inherited annotation (recursively)
*
* The retention policy of the annotation type is not considered.
*/
Annotation getAnAssociatedAnnotation() { result = this.getAnAssociatedAnnotation(_) }
/**
* Holds if this or any enclosing `Annotatable` has a `@SuppressWarnings("<category>")`
@ -128,6 +350,11 @@ class Annotatable extends Element {
or
this.(NestedClass).getEnclosingType().suppressesWarningsAbout(category)
or
this.(LocalClassOrInterface)
.getLocalTypeDeclStmt()
.getEnclosingCallable()
.suppressesWarningsAbout(category)
or
this.(LocalVariableDecl).getCallable().suppressesWarningsAbout(category)
}
}
@ -146,10 +373,79 @@ class AnnotationType extends Interface {
/** Holds if this annotation type is annotated with the meta-annotation `@Inherited`. */
predicate isInherited() {
exists(Annotation ann |
ann.getAnnotatedElement() = this and
ann.getType().hasQualifiedName("java.lang.annotation", "Inherited")
)
this.getADeclaredAnnotation().getType().hasQualifiedName("java.lang.annotation", "Inherited")
}
/** Holds if this annotation type is annotated with the meta-annotation `@Documented`. */
predicate isDocumented() {
this.getADeclaredAnnotation().getType().hasQualifiedName("java.lang.annotation", "Documented")
}
/**
* Gets the retention policy of this annotation type, that is, the name of one of the
* enum constants of `java.lang.annotation.RetentionPolicy`. If this annotation type
* has no `@Retention` annotation, the result is `CLASS`.
*/
string getRetentionPolicy() {
if this.getADeclaredAnnotation() instanceof RetentionAnnotation
then result = this.getADeclaredAnnotation().(RetentionAnnotation).getRetentionPolicy()
else
// If not explicitly specified retention is CLASS
result = "CLASS"
}
/**
* Holds if the element type is a possible target for this annotation type.
* The `elementType` is the name of one of the `java.lang.annotation.ElementType`
* enum constants.
*
* If this annotation type has no `@Target` annotation, it is considered to be applicable
* in all declaration contexts. This matches the behavior of the latest Java versions
* but differs from the behavior of older Java versions. This predicate must only be
* called with names of `ElementType` enum constants; for other values it might hold
* erroneously.
*/
bindingset[elementType]
predicate isATargetType(string elementType) {
/*
* Note: Cannot use a predicate with string as result because annotation type without
* explicit @Target can be applied in all declaration contexts, requiring to hardcode
* element types here; then the results could become outdated if this predicate is not
* updated for future JDK versions, or it could have irritating results, e.g. RECORD_COMPONENT
* for a database created for Java 8.
*
* Could in theory read java.lang.annotation.ElementType constants from database, but might
* be brittle in case ElementType is not present in the database for whatever reason.
*/
if this.getADeclaredAnnotation() instanceof TargetAnnotation
then elementType = this.getADeclaredAnnotation().(TargetAnnotation).getATargetElementType()
else
/*
* Behavior for missing @Target annotation changed between Java versions. In older Java
* versions it allowed usage in most (but not all) declaration contexts. Then for Java 14
* JDK-8231435 changed it to allow usage in all declaration and type contexts. In Java 17
* it was changed by JDK-8261610 to only allow usage in all declaration contexts, but not
* in type contexts anymore. However, during these changes javac did not always comply with
* the specification, see for example JDK-8254023.
*
* For simplicity pretend the latest behavior defined by the JLS applied in all versions;
* that means any declaration context is allowed, but type contexts (represented by TYPE_USE,
* see JLS 17 section 9.6.4.1) are not allowed.
*/
elementType != "TYPE_USE"
}
/** Holds if this annotation type is annotated with the meta-annotation `@Repeatable`. */
predicate isRepeatable() { this.getADeclaredAnnotation() instanceof RepeatableAnnotation }
/**
* If this annotation type is annotated with the meta-annotation `@Repeatable`,
* gets the annotation type which acts as _containing annotation type_.
*/
AnnotationType getContainingAnnotationType() {
result = this.getADeclaredAnnotation().(RepeatableAnnotation).getContainingType()
}
}

Просмотреть файл

@ -71,7 +71,8 @@ predicate depends(RefType t, RefType dep) {
a.getAnnotatedElement().(Member).getDeclaringType() = t
|
usesType(a.getType(), dep) or
usesType(a.getAValue().getType(), dep)
usesType(a.getValue(_).getType(), dep) or
usesType(a.getAnArrayValue(_).getType(), dep)
)
or
// the type accessed in an `instanceof` expression in `t`.

Просмотреть файл

@ -90,7 +90,7 @@ predicate numDepends(RefType t, RefType dep, int value) {
|
elem = a and usesType(a.getType(), dep)
or
elem = a.getAValue() and
elem = [a.getValue(_), a.getAnArrayValue(_)] and
elem.getFile().getExtension() = "java" and
usesType(elem.(Expr).getType(), dep)
)

Просмотреть файл

@ -18,14 +18,16 @@ class OverrideAnnotation extends Annotation {
class SuppressWarningsAnnotation extends Annotation {
SuppressWarningsAnnotation() { this.getType().hasQualifiedName("java.lang", "SuppressWarnings") }
/** Gets the `StringLiteral` of a warning suppressed by this annotation. */
StringLiteral getASuppressedWarningLiteral() {
result = this.getAValue() or
result = this.getAValue().(ArrayInit).getAnInit()
}
/**
* DEPRECATED: This predicate restricts the results to `StringLiteral`; prefer `getASuppressedWarning()`
* to get the name of a suppressed warning.
*
* Gets the `StringLiteral` of a warning suppressed by this annotation.
*/
deprecated StringLiteral getASuppressedWarningLiteral() { result = this.getAnArrayValue("value") }
/** Gets the name of a warning suppressed by this annotation. */
string getASuppressedWarning() { result = this.getASuppressedWarningLiteral().getValue() }
string getASuppressedWarning() { result = this.getAStringArrayValue("value") }
}
/** A `@Target` annotation. */
@ -33,18 +35,15 @@ class TargetAnnotation extends Annotation {
TargetAnnotation() { this.getType().hasQualifiedName("java.lang.annotation", "Target") }
/**
* DEPRECATED: Getting the field access expression is rarely useful. Use `getATargetElementType()`
* to get the name of the target element.
*
* Gets a target expression within this annotation.
*
* For example, the field access `ElementType.FIELD` is a target expression in
* `@Target({ElementType.FIELD, ElementType.METHOD})`.
*/
Expr getATargetExpression() {
not result instanceof ArrayInit and
(
result = this.getAValue() or
result = this.getAValue().(ArrayInit).getAnInit()
)
}
deprecated Expr getATargetExpression() { result = this.getAnArrayValue("value") }
/**
* Gets the name of a target element type.
@ -52,14 +51,7 @@ class TargetAnnotation extends Annotation {
* For example, `METHOD` is the name of a target element type in
* `@Target({ElementType.FIELD, ElementType.METHOD})`.
*/
string getATargetElementType() {
exists(EnumConstant ec |
ec = this.getATargetExpression().(VarAccess).getVariable() and
ec.getDeclaringType().hasQualifiedName("java.lang.annotation", "ElementType")
|
result = ec.getName()
)
}
string getATargetElementType() { result = this.getAnEnumConstantArrayValue("value").getName() }
}
/** A `@Retention` annotation. */
@ -67,12 +59,15 @@ class RetentionAnnotation extends Annotation {
RetentionAnnotation() { this.getType().hasQualifiedName("java.lang.annotation", "Retention") }
/**
* DEPRECATED: Getting the field access expression is rarely useful. Use `getRetentionPolicy()`
* to get the name of the retention policy.
*
* Gets the retention policy expression within this annotation.
*
* For example, the field access `RetentionPolicy.RUNTIME` is the
* retention policy expression in `@Retention(RetentionPolicy.RUNTIME)`.
*/
Expr getRetentionPolicyExpression() { result = this.getValue("value") }
deprecated Expr getRetentionPolicyExpression() { result = this.getValue("value") }
/**
* Gets the name of the retention policy of this annotation.
@ -80,14 +75,18 @@ class RetentionAnnotation extends Annotation {
* For example, `RUNTIME` is the name of the retention policy
* in `@Retention(RetentionPolicy.RUNTIME)`.
*/
string getRetentionPolicy() {
exists(EnumConstant ec |
ec = this.getRetentionPolicyExpression().(VarAccess).getVariable() and
ec.getDeclaringType().hasQualifiedName("java.lang.annotation", "RetentionPolicy")
|
result = ec.getName()
)
}
string getRetentionPolicy() { result = this.getEnumConstantValue("value").getName() }
}
/** A `@Repeatable` annotation. */
class RepeatableAnnotation extends Annotation {
RepeatableAnnotation() { this.getType().hasQualifiedName("java.lang.annotation", "Repeatable") }
/**
* Gets the annotation type which acts as _containing type_, grouping multiple
* repeatable annotations together.
*/
AnnotationType getContainingType() { result = this.getTypeValue("value") }
}
/**
@ -119,11 +118,7 @@ abstract class NonReflectiveAnnotation extends Annotation { }
library class StandardNonReflectiveAnnotation extends NonReflectiveAnnotation {
StandardNonReflectiveAnnotation() {
exists(AnnotationType anntp | anntp = this.getType() |
anntp.hasQualifiedName("java.lang", "Override") or
anntp.hasQualifiedName("java.lang", "Deprecated") or
anntp.hasQualifiedName("java.lang", "SuppressWarnings") or
anntp.hasQualifiedName("java.lang", "SafeVarargs")
)
this.getType()
.hasQualifiedName("java.lang", ["Override", "Deprecated", "SuppressWarnings", "SafeVarargs"])
}
}

Просмотреть файл

@ -120,7 +120,7 @@ private newtype TPrintAstNode =
shouldPrint(lvde, _) and lvde.getParent() instanceof SingleLocalVarDeclParent
} or
TAnnotationsNode(Annotatable ann) {
shouldPrint(ann, _) and ann.hasAnnotation() and not partOfAnnotation(ann)
shouldPrint(ann, _) and ann.hasDeclaredAnnotation() and not partOfAnnotation(ann)
} or
TParametersNode(Callable c) { shouldPrint(c, _) and not c.hasNoParameters() } or
TBaseTypesNode(ClassOrInterface ty) { shouldPrint(ty, _) } or

Просмотреть файл

@ -161,15 +161,13 @@ class TestNGTestMethod extends Method {
exists(TestNGTestAnnotation testAnnotation |
testAnnotation = this.getAnAnnotation() and
// The data provider must have the same name as the referenced data provider
result.getDataProviderName() =
testAnnotation.getValue("dataProvider").(StringLiteral).getValue()
result.getDataProviderName() = testAnnotation.getStringValue("dataProvider")
|
// Either the data provider should be on the current class, or a supertype
this.getDeclaringType().getAnAncestor() = result.getDeclaringType()
or
// Or the data provider class should be declared
result.getDeclaringType() =
testAnnotation.getValue("dataProviderClass").(TypeLiteral).getReferencedType()
result.getDeclaringType() = testAnnotation.getTypeValue("dataProviderClass")
)
}
}
@ -227,9 +225,7 @@ class TestNGListenersAnnotation extends TestNGAnnotation {
/**
* Gets a listener defined in this annotation.
*/
TestNGListenerImpl getAListener() {
result = this.getAValue("value").(TypeLiteral).getReferencedType()
}
TestNGListenerImpl getAListener() { result = this.getATypeArrayValue("value") }
}
/**

Просмотреть файл

@ -60,7 +60,7 @@ class JaxbType extends Class {
this.getAnAnnotation() = a and
a.getType().(JaxbAnnotationType).hasName("XmlAccessorType")
|
result.getAnAccess() = a.getValue("value")
result = a.getEnumConstantValue("value")
)
}

Просмотреть файл

@ -64,5 +64,5 @@ class RunWithAnnotation extends Annotation {
/**
* Gets the runner that will be used.
*/
Type getRunner() { result = this.getValue("value").(TypeLiteral).getReferencedType() }
Type getRunner() { result = this.getTypeValue("value") }
}

Просмотреть файл

@ -296,11 +296,7 @@ class JaxRSProducesAnnotation extends JaxRSAnnotation {
/**
* Gets a declared content type that can be produced by this resource.
*/
Expr getADeclaredContentTypeExpr() {
result = this.getAValue() and not result instanceof ArrayInit
or
result = this.getAValue().(ArrayInit).getAnInit()
}
Expr getADeclaredContentTypeExpr() { result = this.getAnArrayValue("value") }
}
/** An `@Consumes` annotation that describes content types can be consumed by this resource. */

Просмотреть файл

@ -85,9 +85,7 @@ class IbatisSqlOperationAnnotation extends Annotation {
/**
* Gets this annotation's SQL statement string.
*/
string getSqlValue() {
result = this.getAValue("value").(CompileTimeConstantExpr).getStringValue()
}
string getSqlValue() { result = this.getAStringArrayValue("value") }
}
/**

Просмотреть файл

@ -33,12 +33,12 @@ class PersistentEntity extends RefType {
}
/**
* Gets the access type for this entity as defined by a `@javax.persistence.Access` annotation, if any.
* Gets the access type for this entity as defined by a `@javax.persistence.Access` annotation,
* if any, in lower case.
*/
string getAccessTypeFromAnnotation() {
exists(AccessAnnotation accessType | accessType = this.getAnAnnotation() |
result =
accessType.getValue("value").(FieldRead).getField().(EnumConstant).getName().toLowerCase()
result = accessType.getEnumConstantValue("value").getName().toLowerCase()
)
}
}

Просмотреть файл

@ -311,9 +311,7 @@ class SpringQualifierDefinitionAnnotation extends Annotation {
/**
* Gets the value of the qualifier field for this qualifier.
*/
string getQualifierValue() {
result = this.getValue("value").(CompileTimeConstantExpr).getStringValue()
}
string getQualifierValue() { result = this.getStringValue("value") }
}
/**
@ -325,9 +323,7 @@ class SpringQualifierAnnotation extends Annotation {
/**
* Gets the value of the qualifier field for this qualifier.
*/
string getQualifierValue() {
result = this.getValue("value").(CompileTimeConstantExpr).getStringValue()
}
string getQualifierValue() { result = this.getStringValue("value") }
/**
* Gets the bean definition in an XML file that this qualifier resolves to, if any.
@ -350,9 +346,7 @@ class SpringResourceAnnotation extends Annotation {
/**
* Gets the specified name value, if any.
*/
string getNameValue() {
result = this.getValue("name").(CompileTimeConstantExpr).getStringValue()
}
string getNameValue() { result = this.getStringValue("name") }
/**
* Gets the bean definition in an XML file that the resource resolves to, if any.

Просмотреть файл

@ -40,16 +40,10 @@ class SpringComponentScan extends Annotation {
*/
string getBasePackages() {
// "value" and "basePackages" are synonymous, and are simple strings
result = this.getAValue("basePackages").(StringLiteral).getValue()
result = this.getAStringArrayValue(["basePackages", "value"])
or
result = this.getAValue("value").(StringLiteral).getValue()
or
exists(TypeLiteral typeLiteral |
// Base package classes are type literals whose package should be considered a base package.
typeLiteral = this.getAValue("basePackageClasses")
|
result = typeLiteral.getReferencedType().(RefType).getPackage().getName()
)
// Base package classes are type literals whose package should be considered a base package.
result = this.getATypeArrayValue("basePackageClasses").(RefType).getPackage().getName()
}
}
@ -144,8 +138,7 @@ class SpringComponent extends RefType {
if exists(this.getComponentAnnotation().getValue("value"))
then
// If the name has been specified in the component annotation, use that.
result =
this.getComponentAnnotation().getValue("value").(CompileTimeConstantExpr).getStringValue()
result = this.getComponentAnnotation().getStringValue("value")
else
// Otherwise use the name of the class, with the initial letter lower cased.
exists(string name | name = this.getName() |
@ -204,7 +197,7 @@ class SpringComponent extends RefType {
.getType()
.hasQualifiedName("org.springframework.context.annotation", "Profile")
|
result = profileAnnotation.getAValue("value").(StringLiteral).getValue()
result = profileAnnotation.getAStringArrayValue("value")
)
}
}

Просмотреть файл

@ -154,9 +154,7 @@ class SpringRequestMappingMethod extends SpringControllerMethod {
}
/** Gets the "value" @RequestMapping annotation value, if present. */
string getValue() {
result = requestMappingAnnotation.getValue("value").(CompileTimeConstantExpr).getStringValue()
}
string getValue() { result = requestMappingAnnotation.getStringValue("value") }
/** Holds if this is considered an `@ResponseBody` method. */
predicate isResponseBody() {

Просмотреть файл

@ -34,5 +34,5 @@ class StrutsActionsAnnotation extends StrutsAnnotation {
/**
* Gets an Action annotation contained in this Actions annotation.
*/
StrutsActionAnnotation getAnAction() { result = this.getAValue("value") }
StrutsActionAnnotation getAnAction() { result = this.getAnArrayValue("value") }
}

Просмотреть файл

@ -23,7 +23,7 @@ class SuppressionAnnotation extends SuppressWarningsAnnotation {
string text;
SuppressionAnnotation() {
text = this.getASuppressedWarningLiteral().getValue() and
text = this.getASuppressedWarning() and
exists(getAnnotationText(text))
}

Просмотреть файл

@ -19,8 +19,5 @@ where
m.getNumberOfParameters() = 1 and
c.getArgument(0).getType() = p and
p.getATypeArgument() = t and
not exists(RetentionAnnotation a |
t.getAnAnnotation() = a and
a.getAValue().(VarAccess).getVariable().hasName("RUNTIME")
)
t.getRetentionPolicy() != "RUNTIME"
select c, "Call to isAnnotationPresent where no annotation has the RUNTIME retention policy."

Просмотреть файл

@ -47,8 +47,8 @@ class SpringControllerRequestMappingGetMethod extends SpringControllerGetMethod
.getType()
.hasQualifiedName("org.springframework.web.bind.annotation", "RequestMapping") and
(
this.getAnAnnotation().getValue("method").(VarAccess).getVariable().getName() = "GET" or
this.getAnAnnotation().getValue("method").(ArrayInit).getSize() = 0 //Java code example: @RequestMapping(value = "test")
this.getAnAnnotation().getAnEnumConstantArrayValue("method").getName() = "GET" or
not exists(this.getAnAnnotation().getAnArrayValue("method")) //Java code example: @RequestMapping(value = "test")
) and
not this.getAParamType().getName() = "MultipartFile"
}

Просмотреть файл

@ -4,6 +4,6 @@ from Field f, Annotation ann, Expr value, Expr valueChild
where
f.getDeclaringType().fromSource() and
ann = f.getAnAnnotation() and
value = ann.getAValue() and
value = ann.getValue(_) and
valueChild.getParent() = value
select f, ann, value, valueChild

Просмотреть файл

@ -0,0 +1,101 @@
declaredAnnotation
| Annotatable.java:8:16:8:40 | CustomInheritedAnnotation | Annotatable.java:7:5:7:14 | Inherited |
| Annotatable.java:14:11:14:22 | WithDeclared | Annotatable.java:12:5:12:21 | CustomAnnotation |
| Annotatable.java:14:11:14:22 | WithDeclared | Annotatable.java:13:5:13:38 | CustomInheritedAnnotation |
| Annotatable.java:17:14:17:31 | methodWithDeclared | Annotatable.java:16:9:16:49 | CustomInheritedAnnotation |
| Annotatable.java:22:14:22:31 | methodWithDeclared | Annotatable.java:21:9:21:17 | Override |
| Annotatable.java:30:11:30:41 | SubclassDeclaringSameAnnotation | Annotatable.java:29:5:29:37 | CustomInheritedAnnotation |
| Annotatable.java:35:15:35:35 | InterfaceWithDeclared | Annotatable.java:34:5:34:38 | CustomInheritedAnnotation |
| Annotatable.java:47:16:47:35 | RepeatableAnnotation | Annotatable.java:46:5:46:42 | Repeatable |
| Annotatable.java:52:16:52:43 | InheritedContainerAnnotation | Annotatable.java:51:5:51:14 | Inherited |
| Annotatable.java:58:16:58:44 | InheritedRepeatableAnnotation | Annotatable.java:56:5:56:14 | Inherited |
| Annotatable.java:58:16:58:44 | InheritedRepeatableAnnotation | Annotatable.java:57:5:57:51 | Repeatable |
| Annotatable.java:63:16:63:44 | InheritedContainerAnnotation2 | Annotatable.java:62:5:62:14 | Inherited |
| Annotatable.java:71:16:71:47 | NonInheritedRepeatableAnnotation | Annotatable.java:70:5:70:52 | Repeatable |
| Annotatable.java:78:11:78:30 | WithAssociatedSingle | Annotatable.java:75:5:75:33 | RepeatableAnnotation |
| Annotatable.java:78:11:78:30 | WithAssociatedSingle | Annotatable.java:76:5:76:42 | InheritedRepeatableAnnotation |
| Annotatable.java:78:11:78:30 | WithAssociatedSingle | Annotatable.java:77:5:77:45 | NonInheritedRepeatableAnnotation |
| Annotatable.java:86:11:86:30 | SubclassWithMultiple | Annotatable.class:0:0:0:0 | ContainerAnnotation |
| Annotatable.java:86:11:86:30 | SubclassWithMultiple | Annotatable.class:0:0:0:0 | InheritedContainerAnnotation |
| Annotatable.java:86:11:86:30 | SubclassWithMultiple | Annotatable.class:0:0:0:0 | InheritedContainerAnnotation2 |
| Annotatable.java:92:11:92:44 | SubclassOfSingleWithEmptyContainer | Annotatable.java:90:5:90:37 | InheritedContainerAnnotation |
| Annotatable.java:92:11:92:44 | SubclassOfSingleWithEmptyContainer | Annotatable.java:91:5:91:38 | InheritedContainerAnnotation2 |
| Annotatable.java:98:15:98:37 | InterfaceWithAssociated | Annotatable.class:0:0:0:0 | InheritedContainerAnnotation |
| Annotatable.java:113:11:113:32 | WithAssociatedMultiple | Annotatable.class:0:0:0:0 | ContainerAnnotation |
| Annotatable.java:113:11:113:32 | WithAssociatedMultiple | Annotatable.class:0:0:0:0 | InheritedContainerAnnotation |
| Annotatable.java:113:11:113:32 | WithAssociatedMultiple | Annotatable.class:0:0:0:0 | InheritedContainerAnnotation2 |
| Annotatable.java:116:14:116:39 | methodWithAssociatedSingle | Annotatable.java:115:9:115:53 | InheritedRepeatableAnnotation |
| Annotatable.java:121:14:121:33 | methodWithAssociated | Annotatable.class:0:0:0:0 | InheritedContainerAnnotation |
| Annotatable.java:126:14:126:39 | methodWithAssociatedSingle | Annotatable.java:125:9:125:17 | Override |
| Annotatable.java:129:14:129:33 | methodWithAssociated | Annotatable.java:128:9:128:17 | Override |
| Annotatable.java:138:11:138:28 | SubclassWithSingle | Annotatable.java:135:5:135:34 | RepeatableAnnotation |
| Annotatable.java:138:11:138:28 | SubclassWithSingle | Annotatable.java:136:5:136:43 | InheritedRepeatableAnnotation |
| Annotatable.java:138:11:138:28 | SubclassWithSingle | Annotatable.java:137:5:137:46 | NonInheritedRepeatableAnnotation |
| Annotatable.java:144:11:144:46 | SubclassOfMultipleWithEmptyContainer | Annotatable.java:142:5:142:37 | InheritedContainerAnnotation |
| Annotatable.java:144:11:144:46 | SubclassOfMultipleWithEmptyContainer | Annotatable.java:143:5:143:38 | InheritedContainerAnnotation2 |
| Annotatable.java:150:35:153:5 | {...} | Annotatable.java:151:9:151:53 | InheritedRepeatableAnnotation |
| Annotatable.java:150:35:153:5 | {...} | Annotatable.java:152:9:152:53 | InheritedRepeatableAnnotation |
| Annotatable.java:154:11:154:45 | ExplicitContainerAndSingleContained | Annotatable.java:148:5:148:44 | InheritedRepeatableAnnotation |
| Annotatable.java:154:11:154:45 | ExplicitContainerAndSingleContained | Annotatable.java:150:5:153:6 | InheritedContainerAnnotation |
| Annotatable.java:160:16:160:41 | NestedAnnotationContainer1 | Annotatable.java:159:5:159:14 | Inherited |
| Annotatable.java:166:16:166:32 | NestedAnnotation1 | Annotatable.java:164:5:164:14 | Inherited |
| Annotatable.java:166:16:166:32 | NestedAnnotation1 | Annotatable.java:165:5:165:49 | Repeatable |
| Annotatable.java:172:16:172:32 | NestedAnnotation2 | Annotatable.java:170:5:170:14 | Inherited |
| Annotatable.java:172:16:172:32 | NestedAnnotation2 | Annotatable.java:171:5:171:40 | Repeatable |
| Annotatable.java:182:11:182:30 | WithNestedAssociated | Annotatable.class:0:0:0:0 | NestedAnnotationContainer1 |
| Annotatable.java:182:11:182:30 | WithNestedAssociated | Annotatable.java:177:5:177:27 | NestedAnnotation2 |
| Annotatable.java:189:11:189:48 | WithNestedAssociatedExplicitContainers | Annotatable.class:0:0:0:0 | NestedAnnotationContainer1 |
annotationAdditional
| Annotatable.java:20:11:20:18 | Subclass | Annotatable.java:13:5:13:38 | CustomInheritedAnnotation |
| Annotatable.java:26:11:26:21 | SubSubclass | Annotatable.java:13:5:13:38 | CustomInheritedAnnotation |
| Annotatable.java:86:11:86:30 | SubclassWithMultiple | Annotatable.java:76:5:76:42 | InheritedRepeatableAnnotation |
| Annotatable.java:92:11:92:44 | SubclassOfSingleWithEmptyContainer | Annotatable.java:76:5:76:42 | InheritedRepeatableAnnotation |
| Annotatable.java:124:11:124:32 | WithAssociatedSubclass | Annotatable.class:0:0:0:0 | InheritedContainerAnnotation |
| Annotatable.java:124:11:124:32 | WithAssociatedSubclass | Annotatable.class:0:0:0:0 | InheritedContainerAnnotation2 |
| Annotatable.java:133:11:133:35 | WithAssociatedSubSubclass | Annotatable.class:0:0:0:0 | InheritedContainerAnnotation |
| Annotatable.java:133:11:133:35 | WithAssociatedSubSubclass | Annotatable.class:0:0:0:0 | InheritedContainerAnnotation2 |
| Annotatable.java:138:11:138:28 | SubclassWithSingle | Annotatable.class:0:0:0:0 | InheritedContainerAnnotation |
| Annotatable.java:138:11:138:28 | SubclassWithSingle | Annotatable.class:0:0:0:0 | InheritedContainerAnnotation2 |
| Annotatable.java:156:11:156:35 | ExplicitContainerSubclass | Annotatable.java:148:5:148:44 | InheritedRepeatableAnnotation |
| Annotatable.java:156:11:156:35 | ExplicitContainerSubclass | Annotatable.java:150:5:153:6 | InheritedContainerAnnotation |
| Annotatable.java:184:11:184:38 | WithNestedAssociatedSubclass | Annotatable.class:0:0:0:0 | NestedAnnotationContainer1 |
| Annotatable.java:184:11:184:38 | WithNestedAssociatedSubclass | Annotatable.java:177:5:177:27 | NestedAnnotation2 |
| Annotatable.java:191:11:191:56 | WithNestedAssociatedExplicitContainersSubclass | Annotatable.class:0:0:0:0 | NestedAnnotationContainer1 |
bugAnnotationAdditional
associatedAnnotationAdditional
| Annotatable.java:86:11:86:30 | SubclassWithMultiple | Annotatable.class:0:0:0:0 | InheritedRepeatableAnnotation |
| Annotatable.java:86:11:86:30 | SubclassWithMultiple | Annotatable.class:0:0:0:0 | InheritedRepeatableAnnotation |
| Annotatable.java:86:11:86:30 | SubclassWithMultiple | Annotatable.class:0:0:0:0 | NonInheritedRepeatableAnnotation |
| Annotatable.java:86:11:86:30 | SubclassWithMultiple | Annotatable.class:0:0:0:0 | NonInheritedRepeatableAnnotation |
| Annotatable.java:86:11:86:30 | SubclassWithMultiple | Annotatable.class:0:0:0:0 | RepeatableAnnotation |
| Annotatable.java:86:11:86:30 | SubclassWithMultiple | Annotatable.class:0:0:0:0 | RepeatableAnnotation |
| Annotatable.java:98:15:98:37 | InterfaceWithAssociated | Annotatable.class:0:0:0:0 | InheritedRepeatableAnnotation |
| Annotatable.java:98:15:98:37 | InterfaceWithAssociated | Annotatable.class:0:0:0:0 | InheritedRepeatableAnnotation |
| Annotatable.java:113:11:113:32 | WithAssociatedMultiple | Annotatable.class:0:0:0:0 | InheritedRepeatableAnnotation |
| Annotatable.java:113:11:113:32 | WithAssociatedMultiple | Annotatable.class:0:0:0:0 | InheritedRepeatableAnnotation |
| Annotatable.java:113:11:113:32 | WithAssociatedMultiple | Annotatable.class:0:0:0:0 | NonInheritedRepeatableAnnotation |
| Annotatable.java:113:11:113:32 | WithAssociatedMultiple | Annotatable.class:0:0:0:0 | NonInheritedRepeatableAnnotation |
| Annotatable.java:113:11:113:32 | WithAssociatedMultiple | Annotatable.class:0:0:0:0 | RepeatableAnnotation |
| Annotatable.java:113:11:113:32 | WithAssociatedMultiple | Annotatable.class:0:0:0:0 | RepeatableAnnotation |
| Annotatable.java:121:14:121:33 | methodWithAssociated | Annotatable.class:0:0:0:0 | InheritedRepeatableAnnotation |
| Annotatable.java:121:14:121:33 | methodWithAssociated | Annotatable.class:0:0:0:0 | InheritedRepeatableAnnotation |
| Annotatable.java:124:11:124:32 | WithAssociatedSubclass | Annotatable.class:0:0:0:0 | InheritedRepeatableAnnotation |
| Annotatable.java:124:11:124:32 | WithAssociatedSubclass | Annotatable.class:0:0:0:0 | InheritedRepeatableAnnotation |
| Annotatable.java:133:11:133:35 | WithAssociatedSubSubclass | Annotatable.class:0:0:0:0 | InheritedRepeatableAnnotation |
| Annotatable.java:133:11:133:35 | WithAssociatedSubSubclass | Annotatable.class:0:0:0:0 | InheritedRepeatableAnnotation |
| Annotatable.java:144:11:144:46 | SubclassOfMultipleWithEmptyContainer | Annotatable.class:0:0:0:0 | InheritedRepeatableAnnotation |
| Annotatable.java:144:11:144:46 | SubclassOfMultipleWithEmptyContainer | Annotatable.class:0:0:0:0 | InheritedRepeatableAnnotation |
| Annotatable.java:154:11:154:45 | ExplicitContainerAndSingleContained | Annotatable.java:151:9:151:53 | InheritedRepeatableAnnotation |
| Annotatable.java:154:11:154:45 | ExplicitContainerAndSingleContained | Annotatable.java:152:9:152:53 | InheritedRepeatableAnnotation |
| Annotatable.java:156:11:156:35 | ExplicitContainerSubclass | Annotatable.java:151:9:151:53 | InheritedRepeatableAnnotation |
| Annotatable.java:156:11:156:35 | ExplicitContainerSubclass | Annotatable.java:152:9:152:53 | InheritedRepeatableAnnotation |
| Annotatable.java:182:11:182:30 | WithNestedAssociated | Annotatable.class:0:0:0:0 | NestedAnnotation1 |
| Annotatable.java:182:11:182:30 | WithNestedAssociated | Annotatable.class:0:0:0:0 | NestedAnnotation1 |
| Annotatable.java:184:11:184:38 | WithNestedAssociatedSubclass | Annotatable.class:0:0:0:0 | NestedAnnotation1 |
| Annotatable.java:184:11:184:38 | WithNestedAssociatedSubclass | Annotatable.class:0:0:0:0 | NestedAnnotation1 |
| Annotatable.java:189:11:189:48 | WithNestedAssociatedExplicitContainers | Annotatable.class:0:0:0:0 | NestedAnnotation1 |
| Annotatable.java:189:11:189:48 | WithNestedAssociatedExplicitContainers | Annotatable.class:0:0:0:0 | NestedAnnotation1 |
| Annotatable.java:191:11:191:56 | WithNestedAssociatedExplicitContainersSubclass | Annotatable.class:0:0:0:0 | NestedAnnotation1 |
| Annotatable.java:191:11:191:56 | WithNestedAssociatedExplicitContainersSubclass | Annotatable.class:0:0:0:0 | NestedAnnotation1 |
associatedAnnotationNotInherited
| Annotatable.java:86:11:86:30 | SubclassWithMultiple | Annotatable.java:76:5:76:42 | InheritedRepeatableAnnotation |

Просмотреть файл

@ -0,0 +1,192 @@
import java.lang.annotation.Inherited;
import java.lang.annotation.Repeatable;
class Annotatable {
@interface CustomAnnotation {}
@Inherited
@interface CustomInheritedAnnotation {
String value();
}
@CustomAnnotation
@CustomInheritedAnnotation("base")
class WithDeclared {
// Annotations on methods are not inherited
@CustomInheritedAnnotation("base-method")
void methodWithDeclared() {}
}
class Subclass extends WithDeclared {
@Override
void methodWithDeclared() {}
}
// Inheritance from super-superclass
class SubSubclass extends Subclass {}
// Prevents inheriting annotation of same type
@CustomInheritedAnnotation("sub")
class SubclassDeclaringSameAnnotation extends WithDeclared {}
// Annotations on interfaces are not inherited
@CustomInheritedAnnotation("base")
interface InterfaceWithDeclared {}
interface ExtendingInterface extends InterfaceWithDeclared {}
class ImplementingInterface implements InterfaceWithDeclared {}
@interface ContainerAnnotation {
RepeatableAnnotation[] value();
}
@Repeatable(ContainerAnnotation.class)
@interface RepeatableAnnotation {
String value();
}
@Inherited
@interface InheritedContainerAnnotation {
InheritedRepeatableAnnotation[] value();
}
@Inherited
@Repeatable(InheritedContainerAnnotation.class)
@interface InheritedRepeatableAnnotation {
String value();
}
@Inherited
@interface InheritedContainerAnnotation2 {
NonInheritedRepeatableAnnotation[] value();
}
// Container is marked as @Inherited, but this annotation type is not
// This is allowed, but means that associated annotations will not be inherited,
// see java.lang.reflect.AnnotatedElement documentation
@Repeatable(InheritedContainerAnnotation2.class)
@interface NonInheritedRepeatableAnnotation {
String value();
}
@RepeatableAnnotation("base")
@InheritedRepeatableAnnotation("base")
@NonInheritedRepeatableAnnotation("base")
class WithAssociatedSingle {}
@RepeatableAnnotation("sub-1")
@RepeatableAnnotation("sub-2")
@InheritedRepeatableAnnotation("sub-1")
@InheritedRepeatableAnnotation("sub-2")
@NonInheritedRepeatableAnnotation("sub-1")
@NonInheritedRepeatableAnnotation("sub-2")
class SubclassWithMultiple extends WithAssociatedSingle {}
// Empty container annotations have no effect; annotations are inherited from superclass
@InheritedContainerAnnotation({})
@InheritedContainerAnnotation2({})
class SubclassOfSingleWithEmptyContainer extends WithAssociatedSingle {}
// Annotations on interfaces are not inherited
@InheritedRepeatableAnnotation("base-1")
@InheritedRepeatableAnnotation("base-2")
interface InterfaceWithAssociated {}
interface ExtendingInterfaceWithAssociated extends InterfaceWithAssociated {}
class ImplementingInterfaceWithAssociated implements InterfaceWithAssociated {}
@RepeatableAnnotation("base-1")
@RepeatableAnnotation("base-2")
@InheritedRepeatableAnnotation("base-1")
@InheritedRepeatableAnnotation("base-2")
// These annotations are not inherited, but their (implicit) container annotation
// is inherited
@NonInheritedRepeatableAnnotation("base-1")
@NonInheritedRepeatableAnnotation("base-2")
class WithAssociatedMultiple {
// Annotations on methods are not inherited
@InheritedRepeatableAnnotation("base-method")
void methodWithAssociatedSingle() {}
// Annotations on methods are not inherited
@InheritedRepeatableAnnotation("base-method-1")
@InheritedRepeatableAnnotation("base-method-2")
void methodWithAssociated() {}
}
class WithAssociatedSubclass extends WithAssociatedMultiple {
@Override
void methodWithAssociatedSingle() {}
@Override
void methodWithAssociated() {}
}
// Inheritance from super-superclass
class WithAssociatedSubSubclass extends WithAssociatedSubclass {}
@RepeatableAnnotation("sub-1")
@InheritedRepeatableAnnotation("sub-1")
@NonInheritedRepeatableAnnotation("sub-1")
class SubclassWithSingle extends WithAssociatedMultiple {}
// Empty container annotations have no effect; associated annotations are inherited from superclass
@InheritedContainerAnnotation({})
@InheritedContainerAnnotation2({})
class SubclassOfMultipleWithEmptyContainer extends WithAssociatedMultiple {}
// This annotation exists on its own without a container
@InheritedRepeatableAnnotation("single")
// TODO: Has currently spurious results for ArrayInit due to https://github.com/github/codeql/issues/8647
@InheritedContainerAnnotation({
@InheritedRepeatableAnnotation("container-1"),
@InheritedRepeatableAnnotation("container-2")
})
class ExplicitContainerAndSingleContained {}
class ExplicitContainerSubclass extends ExplicitContainerAndSingleContained {}
@Inherited
@interface NestedAnnotationContainer1 {
NestedAnnotation1[] value();
}
@Inherited
@Repeatable(NestedAnnotationContainer1.class)
@interface NestedAnnotation1 {
NestedAnnotation2[] value();
}
@Inherited
@Repeatable(NestedAnnotation1.class)
@interface NestedAnnotation2 {
String value();
}
// This annotation exists on its own without a container
@NestedAnnotation2("1")
// But these are nested inside an implicit @NestedAnnotationContainer1
// Nested repeated annotations (@NestedAnnotation2) are not considered associated
@NestedAnnotation1({@NestedAnnotation2("1-1"), @NestedAnnotation2("1-2")})
@NestedAnnotation1({@NestedAnnotation2("2-1"), @NestedAnnotation2("2-2")})
class WithNestedAssociated {}
class WithNestedAssociatedSubclass extends WithNestedAssociated {}
// Nested repeated annotations (@NestedAnnotation2) are not considered associated
@NestedAnnotation1({@NestedAnnotation2("1-1"), @NestedAnnotation2("1-2")})
@NestedAnnotation1({@NestedAnnotation2("2-1"), @NestedAnnotation2("2-2")})
class WithNestedAssociatedExplicitContainers {}
class WithNestedAssociatedExplicitContainersSubclass extends WithNestedAssociatedExplicitContainers {}
}

Просмотреть файл

@ -0,0 +1,34 @@
import java
class RelevantAnnotatable extends Annotatable {
RelevantAnnotatable() {
getCompilationUnit().hasName("Annotatable") and getCompilationUnit().fromSource()
}
}
query Annotation declaredAnnotation(RelevantAnnotatable a) { result = a.getADeclaredAnnotation() }
/** Note: Only has the annotations as result which are not also considered _declared_. */
query Annotation annotationAdditional(RelevantAnnotatable a) {
result = a.getAnAnnotation() and not result = a.getADeclaredAnnotation()
}
/** Sanity check to verify that `getADeclaredAnnotation()` is a subset of `getAnAnnotation()` */
query Annotation bugAnnotationAdditional(RelevantAnnotatable a) {
result = a.getADeclaredAnnotation() and not result = a.getAnAnnotation()
}
/** Note: Only has the annotations as result which are not part of `getAnAnnotation()`. */
query Annotation associatedAnnotationAdditional(RelevantAnnotatable a) {
result = a.getAnAssociatedAnnotation() and not result = a.getAnAnnotation()
}
/**
* Covers all results of `getAnAssociatedAnnotation()` which are not also a result of `getAnAnnotation()`.
* This should only be the case for a base class using an inheritable annotation `A` and a subclass which
* has an annotation `CA` of the container type of `A`. In that case `A` is not considered _associated_
* and the _indirect_ annotations from `CA` are considered instead.
*/
query Annotation associatedAnnotationNotInherited(RelevantAnnotatable a) {
result = a.getAnAnnotation() and not result = a.getAnAssociatedAnnotation()
}

Просмотреть файл

@ -0,0 +1,215 @@
value
| AnnotationValues.java:39:5:39:17 | SingleValues | annotationValue | AnnotationValues.class:0:0:0:0 | CustomAnnotation |
| AnnotationValues.java:39:5:39:17 | SingleValues | booleanValue | AnnotationValues.class:0:0:0:0 | false |
| AnnotationValues.java:39:5:39:17 | SingleValues | byteValue | AnnotationValues.class:0:0:0:0 | -1 |
| AnnotationValues.java:39:5:39:17 | SingleValues | charValue | AnnotationValues.class:0:0:0:0 | \uffff |
| AnnotationValues.java:39:5:39:17 | SingleValues | classValue | AnnotationValues.class:0:0:0:0 | AnnotationValues.class |
| AnnotationValues.java:39:5:39:17 | SingleValues | doubleValue | AnnotationValues.class:0:0:0:0 | -1.0 |
| AnnotationValues.java:39:5:39:17 | SingleValues | enumValue | AnnotationValues.class:0:0:0:0 | DEFAULT |
| AnnotationValues.java:39:5:39:17 | SingleValues | floatValue | AnnotationValues.class:0:0:0:0 | -1.0 |
| AnnotationValues.java:39:5:39:17 | SingleValues | intValue | AnnotationValues.class:0:0:0:0 | -1 |
| AnnotationValues.java:39:5:39:17 | SingleValues | longValue | AnnotationValues.class:0:0:0:0 | -1 |
| AnnotationValues.java:39:5:39:17 | SingleValues | shortValue | AnnotationValues.class:0:0:0:0 | -1 |
| AnnotationValues.java:39:5:39:17 | SingleValues | stringValue | AnnotationValues.class:0:0:0:0 | "\u0000" |
| AnnotationValues.java:42:5:55:5 | SingleValues | annotationValue | AnnotationValues.java:54:27:54:53 | CustomAnnotation |
| AnnotationValues.java:42:5:55:5 | SingleValues | booleanValue | AnnotationValues.java:49:24:49:27 | true |
| AnnotationValues.java:42:5:55:5 | SingleValues | byteValue | AnnotationValues.java:43:21:43:21 | 1 |
| AnnotationValues.java:42:5:55:5 | SingleValues | charValue | AnnotationValues.java:50:21:50:21 | 1 |
| AnnotationValues.java:42:5:55:5 | SingleValues | classValue | AnnotationValues.java:52:22:52:39 | SingleValues.class |
| AnnotationValues.java:42:5:55:5 | SingleValues | doubleValue | AnnotationValues.java:48:23:48:23 | 1 |
| AnnotationValues.java:42:5:55:5 | SingleValues | enumValue | AnnotationValues.java:53:21:53:32 | CustomEnum.A |
| AnnotationValues.java:42:5:55:5 | SingleValues | floatValue | AnnotationValues.java:47:22:47:22 | 1 |
| AnnotationValues.java:42:5:55:5 | SingleValues | intValue | AnnotationValues.java:45:20:45:20 | 1 |
| AnnotationValues.java:42:5:55:5 | SingleValues | longValue | AnnotationValues.java:46:21:46:21 | 1 |
| AnnotationValues.java:42:5:55:5 | SingleValues | shortValue | AnnotationValues.java:44:22:44:22 | 1 |
| AnnotationValues.java:42:5:55:5 | SingleValues | stringValue | AnnotationValues.java:51:23:51:25 | "a" |
| AnnotationValues.java:54:27:54:53 | CustomAnnotation | value | AnnotationValues.java:54:45:54:52 | "single" |
| AnnotationValues.java:58:5:71:5 | SingleValues | annotationValue | AnnotationValues.java:70:27:70:53 | CustomAnnotation |
| AnnotationValues.java:58:5:71:5 | SingleValues | booleanValue | AnnotationValues.java:65:24:65:30 | BOOLEAN |
| AnnotationValues.java:58:5:71:5 | SingleValues | byteValue | AnnotationValues.java:59:21:59:24 | BYTE |
| AnnotationValues.java:58:5:71:5 | SingleValues | charValue | AnnotationValues.java:66:21:66:24 | CHAR |
| AnnotationValues.java:58:5:71:5 | SingleValues | classValue | AnnotationValues.java:68:22:68:39 | SingleValues.class |
| AnnotationValues.java:58:5:71:5 | SingleValues | doubleValue | AnnotationValues.java:64:23:64:28 | DOUBLE |
| AnnotationValues.java:58:5:71:5 | SingleValues | enumValue | AnnotationValues.java:69:21:69:32 | CustomEnum.A |
| AnnotationValues.java:58:5:71:5 | SingleValues | floatValue | AnnotationValues.java:63:22:63:26 | FLOAT |
| AnnotationValues.java:58:5:71:5 | SingleValues | intValue | AnnotationValues.java:61:20:61:22 | INT |
| AnnotationValues.java:58:5:71:5 | SingleValues | longValue | AnnotationValues.java:62:21:62:24 | LONG |
| AnnotationValues.java:58:5:71:5 | SingleValues | shortValue | AnnotationValues.java:60:22:60:26 | SHORT |
| AnnotationValues.java:58:5:71:5 | SingleValues | stringValue | AnnotationValues.java:67:23:67:28 | STRING |
| AnnotationValues.java:70:27:70:53 | CustomAnnotation | value | AnnotationValues.java:70:45:70:52 | "single" |
| AnnotationValues.java:90:5:90:16 | ArrayValues | annotationValues | AnnotationValues.class:0:0:0:0 | {...} |
| AnnotationValues.java:90:5:90:16 | ArrayValues | booleanValues | AnnotationValues.class:0:0:0:0 | {...} |
| AnnotationValues.java:90:5:90:16 | ArrayValues | byteValues | AnnotationValues.class:0:0:0:0 | {...} |
| AnnotationValues.java:90:5:90:16 | ArrayValues | charValues | AnnotationValues.class:0:0:0:0 | {...} |
| AnnotationValues.java:90:5:90:16 | ArrayValues | classValues | AnnotationValues.class:0:0:0:0 | {...} |
| AnnotationValues.java:90:5:90:16 | ArrayValues | doubleValues | AnnotationValues.class:0:0:0:0 | {...} |
| AnnotationValues.java:90:5:90:16 | ArrayValues | enumValues | AnnotationValues.class:0:0:0:0 | {...} |
| AnnotationValues.java:90:5:90:16 | ArrayValues | floatValues | AnnotationValues.class:0:0:0:0 | {...} |
| AnnotationValues.java:90:5:90:16 | ArrayValues | intValues | AnnotationValues.class:0:0:0:0 | {...} |
| AnnotationValues.java:90:5:90:16 | ArrayValues | longValues | AnnotationValues.class:0:0:0:0 | {...} |
| AnnotationValues.java:90:5:90:16 | ArrayValues | shortValues | AnnotationValues.class:0:0:0:0 | {...} |
| AnnotationValues.java:90:5:90:16 | ArrayValues | stringValues | AnnotationValues.class:0:0:0:0 | {...} |
| AnnotationValues.java:93:5:106:5 | ArrayValues | annotationValues | AnnotationValues.java:105:28:105:54 | {...} |
| AnnotationValues.java:93:5:106:5 | ArrayValues | booleanValues | AnnotationValues.java:100:25:100:28 | true |
| AnnotationValues.java:93:5:106:5 | ArrayValues | byteValues | AnnotationValues.java:94:22:94:22 | 1 |
| AnnotationValues.java:93:5:106:5 | ArrayValues | charValues | AnnotationValues.java:101:22:101:24 | 'a' |
| AnnotationValues.java:93:5:106:5 | ArrayValues | classValues | AnnotationValues.java:103:23:103:39 | ArrayValues.class |
| AnnotationValues.java:93:5:106:5 | ArrayValues | doubleValues | AnnotationValues.java:99:24:99:24 | 1 |
| AnnotationValues.java:93:5:106:5 | ArrayValues | enumValues | AnnotationValues.java:104:22:104:33 | CustomEnum.A |
| AnnotationValues.java:93:5:106:5 | ArrayValues | floatValues | AnnotationValues.java:98:23:98:23 | 1 |
| AnnotationValues.java:93:5:106:5 | ArrayValues | intValues | AnnotationValues.java:96:21:96:21 | 1 |
| AnnotationValues.java:93:5:106:5 | ArrayValues | longValues | AnnotationValues.java:97:22:97:22 | 1 |
| AnnotationValues.java:93:5:106:5 | ArrayValues | shortValues | AnnotationValues.java:95:23:95:23 | 1 |
| AnnotationValues.java:93:5:106:5 | ArrayValues | stringValues | AnnotationValues.java:102:24:102:26 | "a" |
| AnnotationValues.java:105:28:105:54 | CustomAnnotation | value | AnnotationValues.java:105:46:105:53 | "single" |
| AnnotationValues.java:109:5:122:5 | ArrayValues | annotationValues | AnnotationValues.java:121:28:121:84 | {...} |
| AnnotationValues.java:109:5:122:5 | ArrayValues | booleanValues | AnnotationValues.java:116:25:116:40 | {...} |
| AnnotationValues.java:109:5:122:5 | ArrayValues | byteValues | AnnotationValues.java:110:22:110:30 | {...} |
| AnnotationValues.java:109:5:122:5 | ArrayValues | charValues | AnnotationValues.java:117:22:117:32 | {...} |
| AnnotationValues.java:109:5:122:5 | ArrayValues | classValues | AnnotationValues.java:119:23:119:61 | {...} |
| AnnotationValues.java:109:5:122:5 | ArrayValues | doubleValues | AnnotationValues.java:115:24:115:34 | {...} |
| AnnotationValues.java:109:5:122:5 | ArrayValues | enumValues | AnnotationValues.java:120:22:120:49 | {...} |
| AnnotationValues.java:109:5:122:5 | ArrayValues | floatValues | AnnotationValues.java:114:23:114:32 | {...} |
| AnnotationValues.java:109:5:122:5 | ArrayValues | intValues | AnnotationValues.java:112:21:112:28 | {...} |
| AnnotationValues.java:109:5:122:5 | ArrayValues | longValues | AnnotationValues.java:113:22:113:30 | {...} |
| AnnotationValues.java:109:5:122:5 | ArrayValues | shortValues | AnnotationValues.java:111:23:111:32 | {...} |
| AnnotationValues.java:109:5:122:5 | ArrayValues | stringValues | AnnotationValues.java:118:24:118:33 | {...} |
| AnnotationValues.java:121:29:121:54 | CustomAnnotation | value | AnnotationValues.java:121:47:121:53 | "first" |
| AnnotationValues.java:121:57:121:83 | CustomAnnotation | value | AnnotationValues.java:121:75:121:82 | "second" |
enumConstantValue
| AnnotationValues.java:39:5:39:17 | SingleValues | enumValue | AnnotationValues.java:14:9:14:15 | DEFAULT |
| AnnotationValues.java:42:5:55:5 | SingleValues | enumValue | AnnotationValues.java:15:9:15:9 | A |
| AnnotationValues.java:58:5:71:5 | SingleValues | enumValue | AnnotationValues.java:15:9:15:9 | A |
stringValue
| AnnotationValues.java:39:5:39:17 | SingleValues | stringValue | \u0000 |
| AnnotationValues.java:42:5:55:5 | SingleValues | stringValue | a |
| AnnotationValues.java:54:27:54:53 | CustomAnnotation | value | single |
| AnnotationValues.java:58:5:71:5 | SingleValues | stringValue | b |
| AnnotationValues.java:70:27:70:53 | CustomAnnotation | value | single |
| AnnotationValues.java:105:28:105:54 | CustomAnnotation | value | single |
| AnnotationValues.java:121:29:121:54 | CustomAnnotation | value | first |
| AnnotationValues.java:121:57:121:83 | CustomAnnotation | value | second |
intValue
| AnnotationValues.java:39:5:39:17 | SingleValues | byteValue | -1 |
| AnnotationValues.java:39:5:39:17 | SingleValues | charValue | 65535 |
| AnnotationValues.java:39:5:39:17 | SingleValues | intValue | -1 |
| AnnotationValues.java:39:5:39:17 | SingleValues | shortValue | -1 |
| AnnotationValues.java:42:5:55:5 | SingleValues | byteValue | 1 |
| AnnotationValues.java:42:5:55:5 | SingleValues | charValue | 1 |
| AnnotationValues.java:42:5:55:5 | SingleValues | intValue | 1 |
| AnnotationValues.java:42:5:55:5 | SingleValues | shortValue | 1 |
| AnnotationValues.java:58:5:71:5 | SingleValues | byteValue | 2 |
| AnnotationValues.java:58:5:71:5 | SingleValues | charValue | 98 |
| AnnotationValues.java:58:5:71:5 | SingleValues | intValue | 2 |
| AnnotationValues.java:58:5:71:5 | SingleValues | shortValue | 2 |
booleanValue
| AnnotationValues.java:39:5:39:17 | SingleValues | booleanValue | false |
| AnnotationValues.java:42:5:55:5 | SingleValues | booleanValue | true |
| AnnotationValues.java:58:5:71:5 | SingleValues | booleanValue | true |
typeValue
| AnnotationValues.java:39:5:39:17 | SingleValues | classValue | AnnotationValues.java:1:7:1:22 | AnnotationValues |
| AnnotationValues.java:42:5:55:5 | SingleValues | classValue | AnnotationValues.java:23:16:23:27 | SingleValues |
| AnnotationValues.java:58:5:71:5 | SingleValues | classValue | AnnotationValues.java:23:16:23:27 | SingleValues |
arrayValue
| AnnotationValues.java:90:5:90:16 | ArrayValues | annotationValues | 0 | AnnotationValues.class:0:0:0:0 | CustomAnnotation |
| AnnotationValues.java:90:5:90:16 | ArrayValues | booleanValues | 0 | AnnotationValues.class:0:0:0:0 | false |
| AnnotationValues.java:90:5:90:16 | ArrayValues | byteValues | 0 | AnnotationValues.class:0:0:0:0 | -1 |
| AnnotationValues.java:90:5:90:16 | ArrayValues | charValues | 0 | AnnotationValues.class:0:0:0:0 | \uffff |
| AnnotationValues.java:90:5:90:16 | ArrayValues | classValues | 0 | AnnotationValues.class:0:0:0:0 | AnnotationValues.class |
| AnnotationValues.java:90:5:90:16 | ArrayValues | doubleValues | 0 | AnnotationValues.class:0:0:0:0 | -1.0 |
| AnnotationValues.java:90:5:90:16 | ArrayValues | enumValues | 0 | AnnotationValues.class:0:0:0:0 | DEFAULT |
| AnnotationValues.java:90:5:90:16 | ArrayValues | floatValues | 0 | AnnotationValues.class:0:0:0:0 | -1.0 |
| AnnotationValues.java:90:5:90:16 | ArrayValues | intValues | 0 | AnnotationValues.class:0:0:0:0 | -1 |
| AnnotationValues.java:90:5:90:16 | ArrayValues | longValues | 0 | AnnotationValues.class:0:0:0:0 | -1 |
| AnnotationValues.java:90:5:90:16 | ArrayValues | shortValues | 0 | AnnotationValues.class:0:0:0:0 | -1 |
| AnnotationValues.java:90:5:90:16 | ArrayValues | stringValues | 0 | AnnotationValues.class:0:0:0:0 | "\u0000" |
| AnnotationValues.java:93:5:106:5 | ArrayValues | annotationValues | 0 | AnnotationValues.java:105:28:105:54 | CustomAnnotation |
| AnnotationValues.java:93:5:106:5 | ArrayValues | booleanValues | 0 | AnnotationValues.java:100:25:100:28 | true |
| AnnotationValues.java:93:5:106:5 | ArrayValues | byteValues | 0 | AnnotationValues.java:94:22:94:22 | 1 |
| AnnotationValues.java:93:5:106:5 | ArrayValues | charValues | 0 | AnnotationValues.java:101:22:101:24 | 'a' |
| AnnotationValues.java:93:5:106:5 | ArrayValues | classValues | 0 | AnnotationValues.java:103:23:103:39 | ArrayValues.class |
| AnnotationValues.java:93:5:106:5 | ArrayValues | doubleValues | 0 | AnnotationValues.java:99:24:99:24 | 1 |
| AnnotationValues.java:93:5:106:5 | ArrayValues | enumValues | 0 | AnnotationValues.java:104:22:104:33 | CustomEnum.A |
| AnnotationValues.java:93:5:106:5 | ArrayValues | floatValues | 0 | AnnotationValues.java:98:23:98:23 | 1 |
| AnnotationValues.java:93:5:106:5 | ArrayValues | intValues | 0 | AnnotationValues.java:96:21:96:21 | 1 |
| AnnotationValues.java:93:5:106:5 | ArrayValues | longValues | 0 | AnnotationValues.java:97:22:97:22 | 1 |
| AnnotationValues.java:93:5:106:5 | ArrayValues | shortValues | 0 | AnnotationValues.java:95:23:95:23 | 1 |
| AnnotationValues.java:93:5:106:5 | ArrayValues | stringValues | 0 | AnnotationValues.java:102:24:102:26 | "a" |
| AnnotationValues.java:109:5:122:5 | ArrayValues | annotationValues | 0 | AnnotationValues.java:121:29:121:54 | CustomAnnotation |
| AnnotationValues.java:109:5:122:5 | ArrayValues | annotationValues | 1 | AnnotationValues.java:121:57:121:83 | CustomAnnotation |
| AnnotationValues.java:109:5:122:5 | ArrayValues | booleanValues | 0 | AnnotationValues.class:0:0:0:0 | false |
| AnnotationValues.java:109:5:122:5 | ArrayValues | booleanValues | 1 | AnnotationValues.class:0:0:0:0 | true |
| AnnotationValues.java:109:5:122:5 | ArrayValues | booleanValues | -1 | AnnotationValues.java:116:26:116:30 | false |
| AnnotationValues.java:109:5:122:5 | ArrayValues | booleanValues | -2 | AnnotationValues.java:116:33:116:39 | BOOLEAN |
| AnnotationValues.java:109:5:122:5 | ArrayValues | byteValues | 0 | AnnotationValues.class:0:0:0:0 | 1 |
| AnnotationValues.java:109:5:122:5 | ArrayValues | byteValues | 1 | AnnotationValues.class:0:0:0:0 | 2 |
| AnnotationValues.java:109:5:122:5 | ArrayValues | byteValues | -1 | AnnotationValues.java:110:23:110:23 | 1 |
| AnnotationValues.java:109:5:122:5 | ArrayValues | byteValues | -2 | AnnotationValues.java:110:26:110:29 | BYTE |
| AnnotationValues.java:109:5:122:5 | ArrayValues | charValues | 0 | AnnotationValues.class:0:0:0:0 | a |
| AnnotationValues.java:109:5:122:5 | ArrayValues | charValues | 1 | AnnotationValues.class:0:0:0:0 | b |
| AnnotationValues.java:109:5:122:5 | ArrayValues | charValues | -1 | AnnotationValues.java:117:23:117:25 | 'a' |
| AnnotationValues.java:109:5:122:5 | ArrayValues | charValues | -2 | AnnotationValues.java:117:28:117:31 | CHAR |
| AnnotationValues.java:109:5:122:5 | ArrayValues | classValues | 0 | AnnotationValues.class:0:0:0:0 | SingleValues.class |
| AnnotationValues.java:109:5:122:5 | ArrayValues | classValues | 1 | AnnotationValues.class:0:0:0:0 | ArrayValues.class |
| AnnotationValues.java:109:5:122:5 | ArrayValues | classValues | -1 | AnnotationValues.java:119:24:119:41 | SingleValues.class |
| AnnotationValues.java:109:5:122:5 | ArrayValues | classValues | -2 | AnnotationValues.java:119:44:119:60 | ArrayValues.class |
| AnnotationValues.java:109:5:122:5 | ArrayValues | doubleValues | 0 | AnnotationValues.class:0:0:0:0 | 1.0 |
| AnnotationValues.java:109:5:122:5 | ArrayValues | doubleValues | 1 | AnnotationValues.class:0:0:0:0 | 2.0 |
| AnnotationValues.java:109:5:122:5 | ArrayValues | doubleValues | -1 | AnnotationValues.java:115:25:115:25 | 1 |
| AnnotationValues.java:109:5:122:5 | ArrayValues | doubleValues | -2 | AnnotationValues.java:115:28:115:33 | DOUBLE |
| AnnotationValues.java:109:5:122:5 | ArrayValues | enumValues | 0 | AnnotationValues.class:0:0:0:0 | A |
| AnnotationValues.java:109:5:122:5 | ArrayValues | enumValues | 1 | AnnotationValues.class:0:0:0:0 | B |
| AnnotationValues.java:109:5:122:5 | ArrayValues | enumValues | -1 | AnnotationValues.java:120:23:120:34 | CustomEnum.A |
| AnnotationValues.java:109:5:122:5 | ArrayValues | enumValues | -2 | AnnotationValues.java:120:37:120:48 | CustomEnum.B |
| AnnotationValues.java:109:5:122:5 | ArrayValues | floatValues | 0 | AnnotationValues.class:0:0:0:0 | 1.0 |
| AnnotationValues.java:109:5:122:5 | ArrayValues | floatValues | 1 | AnnotationValues.class:0:0:0:0 | 2.0 |
| AnnotationValues.java:109:5:122:5 | ArrayValues | floatValues | -1 | AnnotationValues.java:114:24:114:24 | 1 |
| AnnotationValues.java:109:5:122:5 | ArrayValues | floatValues | -2 | AnnotationValues.java:114:27:114:31 | FLOAT |
| AnnotationValues.java:109:5:122:5 | ArrayValues | intValues | 0 | AnnotationValues.class:0:0:0:0 | 1 |
| AnnotationValues.java:109:5:122:5 | ArrayValues | intValues | 1 | AnnotationValues.class:0:0:0:0 | 2 |
| AnnotationValues.java:109:5:122:5 | ArrayValues | intValues | -1 | AnnotationValues.java:112:22:112:22 | 1 |
| AnnotationValues.java:109:5:122:5 | ArrayValues | intValues | -2 | AnnotationValues.java:112:25:112:27 | INT |
| AnnotationValues.java:109:5:122:5 | ArrayValues | longValues | 0 | AnnotationValues.class:0:0:0:0 | 1 |
| AnnotationValues.java:109:5:122:5 | ArrayValues | longValues | 1 | AnnotationValues.class:0:0:0:0 | 2 |
| AnnotationValues.java:109:5:122:5 | ArrayValues | longValues | -1 | AnnotationValues.java:113:23:113:23 | 1 |
| AnnotationValues.java:109:5:122:5 | ArrayValues | longValues | -2 | AnnotationValues.java:113:26:113:29 | LONG |
| AnnotationValues.java:109:5:122:5 | ArrayValues | shortValues | 0 | AnnotationValues.class:0:0:0:0 | 1 |
| AnnotationValues.java:109:5:122:5 | ArrayValues | shortValues | 1 | AnnotationValues.class:0:0:0:0 | 2 |
| AnnotationValues.java:109:5:122:5 | ArrayValues | shortValues | -1 | AnnotationValues.java:111:24:111:24 | 1 |
| AnnotationValues.java:109:5:122:5 | ArrayValues | shortValues | -2 | AnnotationValues.java:111:27:111:31 | SHORT |
| AnnotationValues.java:109:5:122:5 | ArrayValues | stringValues | 0 | AnnotationValues.class:0:0:0:0 | "a" |
| AnnotationValues.java:109:5:122:5 | ArrayValues | stringValues | 1 | AnnotationValues.class:0:0:0:0 | "b" |
| AnnotationValues.java:109:5:122:5 | ArrayValues | stringValues | -1 | AnnotationValues.java:118:25:118:27 | "a" |
| AnnotationValues.java:109:5:122:5 | ArrayValues | stringValues | -2 | AnnotationValues.java:118:30:118:32 | "b" |
enumConstantArrayValue
| AnnotationValues.java:90:5:90:16 | ArrayValues | enumValues | AnnotationValues.java:14:9:14:15 | DEFAULT |
| AnnotationValues.java:93:5:106:5 | ArrayValues | enumValues | AnnotationValues.java:15:9:15:9 | A |
| AnnotationValues.java:109:5:122:5 | ArrayValues | enumValues | AnnotationValues.java:15:9:15:9 | A |
| AnnotationValues.java:109:5:122:5 | ArrayValues | enumValues | AnnotationValues.java:16:9:16:9 | B |
stringArrayValue
| AnnotationValues.java:90:5:90:16 | ArrayValues | stringValues | \u0000 |
| AnnotationValues.java:93:5:106:5 | ArrayValues | stringValues | a |
| AnnotationValues.java:109:5:122:5 | ArrayValues | stringValues | a |
| AnnotationValues.java:109:5:122:5 | ArrayValues | stringValues | b |
intArrayValue
| AnnotationValues.java:90:5:90:16 | ArrayValues | byteValues | -1 |
| AnnotationValues.java:90:5:90:16 | ArrayValues | charValues | 65535 |
| AnnotationValues.java:90:5:90:16 | ArrayValues | intValues | -1 |
| AnnotationValues.java:90:5:90:16 | ArrayValues | shortValues | -1 |
| AnnotationValues.java:93:5:106:5 | ArrayValues | byteValues | 1 |
| AnnotationValues.java:93:5:106:5 | ArrayValues | charValues | 97 |
| AnnotationValues.java:93:5:106:5 | ArrayValues | intValues | 1 |
| AnnotationValues.java:93:5:106:5 | ArrayValues | shortValues | 1 |
| AnnotationValues.java:109:5:122:5 | ArrayValues | byteValues | 1 |
| AnnotationValues.java:109:5:122:5 | ArrayValues | byteValues | 2 |
| AnnotationValues.java:109:5:122:5 | ArrayValues | charValues | 97 |
| AnnotationValues.java:109:5:122:5 | ArrayValues | charValues | 98 |
| AnnotationValues.java:109:5:122:5 | ArrayValues | intValues | 1 |
| AnnotationValues.java:109:5:122:5 | ArrayValues | intValues | 2 |
| AnnotationValues.java:109:5:122:5 | ArrayValues | shortValues | 1 |
| AnnotationValues.java:109:5:122:5 | ArrayValues | shortValues | 2 |
typeArrayValue
| AnnotationValues.java:90:5:90:16 | ArrayValues | classValues | AnnotationValues.java:1:7:1:22 | AnnotationValues |
| AnnotationValues.java:93:5:106:5 | ArrayValues | classValues | AnnotationValues.java:74:16:74:26 | ArrayValues |
| AnnotationValues.java:109:5:122:5 | ArrayValues | classValues | AnnotationValues.java:23:16:23:27 | SingleValues |
| AnnotationValues.java:109:5:122:5 | ArrayValues | classValues | AnnotationValues.java:74:16:74:26 | ArrayValues |

Просмотреть файл

@ -0,0 +1,37 @@
import java
class RelevantAnnotation extends Annotation {
RelevantAnnotation() {
getCompilationUnit().hasName("AnnotationValues") and getCompilationUnit().fromSource()
}
}
query Expr value(RelevantAnnotation a, string name) { result = a.getValue(name) }
query EnumConstant enumConstantValue(RelevantAnnotation a, string name) {
result = a.getEnumConstantValue(name)
}
query string stringValue(RelevantAnnotation a, string name) { result = a.getStringValue(name) }
query int intValue(RelevantAnnotation a, string name) { result = a.getIntValue(name) }
query boolean booleanValue(RelevantAnnotation a, string name) { result = a.getBooleanValue(name) }
query Type typeValue(RelevantAnnotation a, string name) { result = a.getTypeValue(name) }
query Expr arrayValue(RelevantAnnotation a, string name, int index) {
result = a.getArrayValue(name, index)
}
query EnumConstant enumConstantArrayValue(RelevantAnnotation a, string name) {
result = a.getAnEnumConstantArrayValue(name)
}
query string stringArrayValue(RelevantAnnotation a, string name) {
result = a.getAStringArrayValue(name)
}
query int intArrayValue(RelevantAnnotation a, string name) { result = a.getAnIntArrayValue(name) }
query Type typeArrayValue(RelevantAnnotation a, string name) { result = a.getATypeArrayValue(name) }

Просмотреть файл

@ -0,0 +1,13 @@
annotationType
| AnnotationType.java:11:16:11:34 | InheritedAnnotation | inherited | <any-target> | CLASS |
| AnnotationType.java:14:16:14:35 | DocumentedAnnotation | documented | <any-target> | CLASS |
| AnnotationType.java:16:16:16:34 | ContainerAnnotation | | <any-target> | CLASS |
| AnnotationType.java:21:16:21:35 | RepeatableAnnotation | repeatable | <any-target> | CLASS |
| AnnotationType.java:25:16:25:26 | EmptyTarget | | | CLASS |
| AnnotationType.java:28:16:28:27 | SingleTarget | | ANNOTATION_TYPE | CLASS |
| AnnotationType.java:43:16:43:25 | AllTargets | | ANNOTATION_TYPE,CONSTRUCTOR,FIELD,LOCAL_VARIABLE,METHOD,MODULE,PACKAGE,PARAMETER,RECORD_COMPONENT,TYPE_PARAMETER,TYPE_USE | CLASS |
| AnnotationType.java:47:16:47:29 | ClassRetention | | <any-target> | CLASS |
| AnnotationType.java:50:16:50:31 | RuntimeRetention | | <any-target> | RUNTIME |
| AnnotationType.java:53:16:53:30 | SourceRetention | | <any-target> | SOURCE |
containingAnnotationType
| AnnotationType.java:21:16:21:35 | RepeatableAnnotation | AnnotationType.java:16:16:16:34 | ContainerAnnotation |

Просмотреть файл

@ -0,0 +1,54 @@
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
class AnnotationType {
@Inherited
@interface InheritedAnnotation {}
@Documented
@interface DocumentedAnnotation {}
@interface ContainerAnnotation {
RepeatableAnnotation[] value();
}
@Repeatable(ContainerAnnotation.class)
@interface RepeatableAnnotation {}
@Target({})
@interface EmptyTarget {}
@Target(ElementType.ANNOTATION_TYPE)
@interface SingleTarget {}
@Target({
ElementType.ANNOTATION_TYPE,
ElementType.CONSTRUCTOR,
ElementType.FIELD,
ElementType.LOCAL_VARIABLE,
ElementType.METHOD,
ElementType.MODULE,
ElementType.PACKAGE,
ElementType.PARAMETER,
ElementType.RECORD_COMPONENT,
ElementType.TYPE_PARAMETER,
ElementType.TYPE_USE
})
@interface AllTargets {}
@Retention(RetentionPolicy.CLASS)
@interface ClassRetention {}
@Retention(RetentionPolicy.RUNTIME)
@interface RuntimeRetention {}
@Retention(RetentionPolicy.SOURCE)
@interface SourceRetention {}
}

Просмотреть файл

@ -0,0 +1,46 @@
import java
class RelevantAnnotationType extends AnnotationType {
RelevantAnnotationType() { getCompilationUnit().hasName("AnnotationType") }
}
query predicate annotationType(
RelevantAnnotationType t, string flagsString, string targets, string retentionPolicy
) {
flagsString =
concat(string s |
t.isInherited() and s = "inherited"
or
t.isDocumented() and s = "documented"
or
t.isRepeatable() and s = "repeatable"
|
s, "," order by s
) and
(
// Workaround to test if no explicit @Target is specified; in that case any string except
// TYPE_USE, which represents type contexts, is considered a target because it might be
// added to ElementType in a future JDK version
if t.isATargetType("<any-target>")
then
if t.isATargetType("TYPE_USE")
then targets = "BUG: Includes TYPE_USE"
else targets = "<any-target>"
else
targets =
concat(string s |
exists(EnumConstant elementType |
elementType.getDeclaringType().hasQualifiedName("java.lang.annotation", "ElementType") and
s = elementType.getName() and
t.isATargetType(s)
)
|
s, "," order by s
)
) and
retentionPolicy = t.getRetentionPolicy()
}
query AnnotationType containingAnnotationType(RelevantAnnotationType t) {
result = t.getContainingAnnotationType()
}

Просмотреть файл

@ -0,0 +1,124 @@
class AnnotationValues {
private static final byte BYTE = 2;
private static final short SHORT = 2;
private static final int INT = 2;
private static final long LONG = 2;
private static final float FLOAT = 2;
private static final double DOUBLE = 2;
private static final boolean BOOLEAN = true;
private static final char CHAR = 'b';
private static final String STRING = "b";
enum CustomEnum {
DEFAULT,
A,
B
}
@interface CustomAnnotation {
String value();
}
@interface SingleValues {
byte byteValue() default -1;
short shortValue() default -1;
int intValue() default -1;
long longValue() default -1;
float floatValue() default -1;
double doubleValue() default -1;
boolean booleanValue() default false;
char charValue() default '\uFFFF';
String stringValue() default "\0";
Class<?> classValue() default AnnotationValues.class;
CustomEnum enumValue() default CustomEnum.DEFAULT;
CustomAnnotation annotationValue() default @CustomAnnotation("default");
}
@SingleValues
private int singleValuesDefault;
@SingleValues(
byteValue = 1,
shortValue = 1,
intValue = 1,
longValue = 1,
floatValue = 1,
doubleValue = 1,
booleanValue = true,
charValue = 1,
stringValue = "a",
classValue = SingleValues.class,
enumValue = CustomEnum.A,
annotationValue = @CustomAnnotation("single")
)
private int singleValues;
@SingleValues(
byteValue = BYTE,
shortValue = SHORT,
intValue = INT,
longValue = LONG,
floatValue = FLOAT,
doubleValue = DOUBLE,
booleanValue = BOOLEAN,
charValue = CHAR,
stringValue = STRING,
classValue = SingleValues.class,
enumValue = CustomEnum.A,
annotationValue = @CustomAnnotation("single")
)
private int singleValuesConstants;
@interface ArrayValues {
byte[] byteValues() default -1;
short[] shortValues() default -1;
int[] intValues() default -1;
long[] longValues() default -1;
float[] floatValues() default -1;
double[] doubleValues() default -1;
boolean[] booleanValues() default false;
char[] charValues() default '\uFFFF';
String[] stringValues() default "\0";
Class<?>[] classValues() default AnnotationValues.class;
CustomEnum[] enumValues() default CustomEnum.DEFAULT;
CustomAnnotation[] annotationValues() default @CustomAnnotation("default");
}
@ArrayValues
private int arrayValuesDefault;
@ArrayValues(
byteValues = 1,
shortValues = 1,
intValues = 1,
longValues = 1,
floatValues = 1,
doubleValues = 1,
booleanValues = true,
charValues = 'a',
stringValues = "a",
classValues = ArrayValues.class,
enumValues = CustomEnum.A,
annotationValues = @CustomAnnotation("single")
)
private int arrayValuesSingleExpr;
@ArrayValues(
byteValues = {1, BYTE},
shortValues = {1, SHORT},
intValues = {1, INT},
longValues = {1, LONG},
floatValues = {1, FLOAT},
doubleValues = {1, DOUBLE},
booleanValues = {false, BOOLEAN},
charValues = {'a', CHAR},
stringValues = {"a", "b"},
classValues = {SingleValues.class, ArrayValues.class},
enumValues = {CustomEnum.A, CustomEnum.B},
annotationValues = {@CustomAnnotation("first"), @CustomAnnotation("second")}
)
private int arrayValues;
}

Просмотреть файл

@ -0,0 +1 @@
//semmle-extractor-options: --javac-args -source 16 -target 16

Просмотреть файл

@ -984,7 +984,7 @@ module TaintTracking {
*
* `<contains>` is one of: `contains`, `has`, `hasOwnProperty`
*
* Note that the `includes` method is covered by `StringInclusionSanitizer`.
* Note that the `includes` method is covered by `MembershipTestSanitizer`.
*/
class WhitelistContainmentCallSanitizer extends AdditionalSanitizerGuardNode,
DataFlow::MethodCallNode {
@ -1171,7 +1171,7 @@ module TaintTracking {
/**
* A check of form `x.indexOf(y) > 0` or similar, which sanitizes `y` in the "then" branch.
*
* The more typical case of `x.indexOf(y) >= 0` is covered by `StringInclusionSanitizer`.
* The more typical case of `x.indexOf(y) >= 0` is covered by `MembershipTestSanitizer`.
*/
class PositiveIndexOfSanitizer extends AdditionalSanitizerGuardNode, DataFlow::ValueNode {
MethodCallExpr indexOf;

Просмотреть файл

@ -18,32 +18,44 @@ import javascript
* A call that checks a property of some file.
*/
class FileCheck extends DataFlow::CallNode {
string member;
FileCheck() {
this =
NodeJSLib::FS::moduleMember([
"open", "openSync", "exists", "existsSync", "stat", "statSync", "lstat", "lstatSync",
"fstat", "fstatSync", "access", "accessSync"
]).getACall()
member =
[
"open", "openSync", "exists", "existsSync", "stat", "statSync", "lstat", "lstatSync",
"fstat", "fstatSync", "access", "accessSync"
] and
this = NodeJSLib::FS::moduleMember(member).getACall()
}
DataFlow::Node getPathArgument() { result = this.getArgument(0) }
/** Holds if this call is a simple existence check for a file. */
predicate isExistsCheck() { member = ["exists", "existsSync"] }
}
/**
* A call that modifies or otherwise interacts with a file.
*/
class FileUse extends DataFlow::CallNode {
string member;
FileUse() {
this =
NodeJSLib::FS::moduleMember([
// these are the six methods that accept file paths and file descriptors
"readFile", "readFileSync", "writeFile", "writeFileSync", "appendFile", "appendFileSync",
// don't use "open" after e.g. "access"
"open", "openSync"
]).getACall()
member =
[
// these are the six methods that accept file paths and file descriptors
"readFile", "readFileSync", "writeFile", "writeFileSync", "appendFile", "appendFileSync",
// don't use "open" after e.g. "access"
"open", "openSync"
] and
this = NodeJSLib::FS::moduleMember(member).getACall()
}
DataFlow::Node getPathArgument() { result = this.getArgument(0) }
/** Holds if this call reads from a file. */
predicate isFileRead() { member = ["readFile", "readFileSync"] }
}
/**
@ -101,5 +113,6 @@ from FileCheck check, FileUse use
where
checkAndUseOnSame(check, use) and
useAfterCheck(check, use) and
not (check.isExistsCheck() and use.isFileRead()) and // a read after an exists check is fine
not getAFileHandle(DataFlow::TypeTracker::end()).flowsTo(use.getPathArgument())
select use, "The file may have changed since it $@.", check, "was checked"

Просмотреть файл

@ -36,3 +36,8 @@ fs.access("myfile", (err) => {
// ....
});
});
const filePath3 = createFile();
if (fs.existsSync(filePath3)) {
fs.readFileSync(filePath3); // OK - a read after an existence check is OK
}

Просмотреть файл

@ -26,6 +26,14 @@ def codeql_workspace(repository_name = "codeql"):
sha256 = sha256,
)
http_archive(
name = "fishhook",
url = "https://github.com/facebook/fishhook/archive/aadc161ac3b80db07a9908851839a17ba63a9eb1.zip",
build_file = "@%s//swift/tools/fishhook:BUILD.fishhook.bazel" % repository_name,
strip_prefix = "fishhook-aadc161ac3b80db07a9908851839a17ba63a9eb1",
sha256 = "9f2cdee6dcc2039d4c47d25ab5141fe0678ce6ed27ef482cab17fe9fa38a30ce",
)
maybe(
repo_rule = http_archive,
name = "rules_pkg",

24
python/ql/lib/design.md Normal file
Просмотреть файл

@ -0,0 +1,24 @@
# The Python libraries
The Python libraries are a collection of libraries for analysing Python code.
Everythng can be imported by importing `python.qll`.
## The analysis layers
The analysis is built up in layers. the stack looks like this:
- AST (coms from the extractor)
- Control flow graph (CFG) (built by the extractor)
- SSA
- Call graph
- Data flow
## Avoiding non-monotonic recursion
Given the many interactivg layers, it is imprtant to decie which predicates are allowed to be mutually recursive in order to avoid non-monotonic recursion when negation is used to express the predicates.
As an example, we have defined local source as those whcih do not receive local flow. This means that the local flow relation is not allowed to be recursive with anything depending on local sources.
Some particular reatrictions to keep in mind:
- Typetracking needs to use a local flow step not including summaries
- Typetracking needs to use a call graph not including summaries

Просмотреть файл

@ -380,6 +380,21 @@ module API {
not m.matches("%.%")
}
/**
* Holds if an import of module `m` exists.
*
* This is determined without referring to `Node`,
* allowing this predicate to be used in a negative
* context when constructing new nodes.
*/
predicate moduleImportExists(string m) {
Impl::isImported(m) and
// restrict `moduleImport` so it will never give results for a dotted name. Note
// that we cannot move this logic to the `MkModuleImport` construction, since we
// need the intermediate API graph nodes for the prefixes in `import foo.bar.baz`.
not m.matches("%.%")
}
/** Gets a node corresponding to the built-in with the given name, if any. */
Node builtin(string n) { result = moduleImport("builtins").getMember(n) }
@ -605,14 +620,38 @@ module API {
*
* Ignores relative imports, such as `from ..foo.bar import baz`.
*/
private predicate imports(DataFlow::Node imp, string name) {
private predicate imports(DataFlow::CfgNode imp, string name) {
exists(PY::ImportExprNode iexpr |
imp.asCfgNode() = iexpr and
imp.getNode() = iexpr and
not iexpr.getNode().isRelative() and
name = iexpr.getNode().getImportedModuleName()
)
}
/**
* Holds if the module `name` is imported.
*
* This is determined syntactically.
*/
cached
predicate isImported(string name) {
// Ignore the following module name for Python 2, as we alias `__builtin__` to `builtins` elsewhere
(name != "__builtin__" or PY::major_version() = 3) and
(
exists(PY::ImportExpr iexpr |
not iexpr.isRelative() and
name = iexpr.getImportedModuleName()
)
or
// When we `import foo.bar.baz` we want to create API graph nodes also for the prefixes
// `foo` and `foo.bar`:
name = any(PY::ImportExpr e | not e.isRelative()).getAnImportedModuleName()
)
or
// The `builtins` module should always be implicitly available
name = "builtins"
}
private import semmle.python.dataflow.new.internal.Builtins
private import semmle.python.dataflow.new.internal.ImportStar
@ -631,7 +670,7 @@ module API {
*/
private TApiNode potential_import_star_base(PY::Scope s) {
exists(DataFlow::Node n |
n.asCfgNode() = ImportStar::potentialImportStarBase(s) and
n.(DataFlow::CfgNode).getNode() = ImportStar::potentialImportStarBase(s) and
use(result, n)
)
}
@ -653,17 +692,17 @@ module API {
or
// TODO: I had expected `DataFlow::AttrWrite` to contain the attribute writes from a dict, that's how JS works.
exists(PY::Dict dict, PY::KeyValuePair item |
dict = pred.asExpr() and
dict = pred.(DataFlow::ExprNode).getNode().getNode() and
dict.getItem(_) = item and
lbl = Label::member(item.getKey().(PY::StrConst).getS()) and
rhs.asExpr() = item.getValue()
rhs.(DataFlow::ExprNode).getNode().getNode() = item.getValue()
)
or
exists(PY::CallableExpr fn | fn = pred.asExpr() |
exists(PY::CallableExpr fn | fn = pred.(DataFlow::ExprNode).getNode().getNode() |
not fn.getInnerScope().isAsync() and
lbl = Label::return() and
exists(PY::Return ret |
rhs.asExpr() = ret.getValue() and
rhs.(DataFlow::ExprNode).getNode().getNode() = ret.getValue() and
ret.getScope() = fn.getInnerScope()
)
)
@ -716,9 +755,9 @@ module API {
// "benign" and let subclasses edges flow through anyway.
// see example in https://github.com/django/django/blob/c2250cfb80e27cdf8d098428824da2800a18cadf/tests/auth_tests/test_views.py#L40-L46
(
ref.asExpr() = clsExpr
ref.(DataFlow::ExprNode).getNode().getNode() = clsExpr
or
ref.asExpr() = clsExpr.getADecoratorCall()
ref.(DataFlow::ExprNode).getNode().getNode() = clsExpr.getADecoratorCall()
)
)
or
@ -731,7 +770,7 @@ module API {
)
or
exists(DataFlow::Node def, PY::CallableExpr fn |
rhs(base, def) and fn = trackDefNode(def).asExpr()
rhs(base, def) and fn = trackDefNode(def).(DataFlow::ExprNode).getNode().getNode()
|
exists(int i, int offset |
if exists(PY::Parameter p | p = fn.getInnerScope().getAnArg() and p.isSelf())
@ -739,18 +778,19 @@ module API {
else offset = 0
|
lbl = Label::parameter(i - offset) and
ref.asExpr() = fn.getInnerScope().getArg(i)
ref.(DataFlow::ExprNode).getNode().getNode() = fn.getInnerScope().getArg(i)
)
or
exists(string name, PY::Parameter param |
lbl = Label::keywordParameter(name) and
param = fn.getInnerScope().getArgByName(name) and
not param.isSelf() and
ref.asExpr() = param
ref.(DataFlow::ExprNode).getNode().getNode() = param
)
or
lbl = Label::selfParameter() and
ref.asExpr() = any(PY::Parameter p | p = fn.getInnerScope().getAnArg() and p.isSelf())
ref.(DataFlow::ExprNode).getNode().getNode() =
any(PY::Parameter p | p = fn.getInnerScope().getAnArg() and p.isSelf())
)
or
// Built-ins, treated as members of the module `builtins`
@ -762,7 +802,7 @@ module API {
base = potential_import_star_base(s) and
lbl =
Label::member(any(string name |
ImportStar::namePossiblyDefinedInImportStar(ref.asCfgNode(), name, s)
ImportStar::namePossiblyDefinedInImportStar(ref.(DataFlow::CfgNode).getNode(), name, s)
))
)
or
@ -854,7 +894,7 @@ module API {
DataFlow::LocalSourceNode trackUseNode(DataFlow::LocalSourceNode src) {
Stages::TypeTracking::ref() and
result = trackUseNode(src, DataFlow::TypeTracker::end()) and
not result instanceof DataFlow::ModuleVariableNode
result instanceof DataFlow::ExprNode
}
/**
@ -1044,7 +1084,7 @@ module API {
ApiLabel memberFromRef(DataFlow::AttrRef ref) {
result = member(ref.getAttributeName())
or
not exists(ref.getAttributeName()) and
ref.unknownAttribute() and
result = unknownMember()
}

Просмотреть файл

@ -0,0 +1,107 @@
/** Provides classes and predicates for defining flow summaries. */
private import python
private import semmle.python.dataflow.new.DataFlow
private import semmle.python.frameworks.data.ModelsAsData
private import semmle.python.ApiGraphs
private import internal.FlowSummaryImpl as Impl
private import internal.DataFlowUtil
private import internal.DataFlowPrivate
// import all instances below
private module Summaries {
private import semmle.python.Frameworks
}
class SummaryComponent = Impl::Public::SummaryComponent;
/** Provides predicates for constructing summary components. */
module SummaryComponent {
private import Impl::Public::SummaryComponent as SC
predicate parameter = SC::parameter/1;
predicate argument = SC::argument/1;
predicate content = SC::content/1;
/** Gets a summary component that represents a list element. */
SummaryComponent listElement() { result = content(any(ListElementContent c)) }
/** Gets a summary component that represents the return value of a call. */
SummaryComponent return() { result = SC::return(any(ReturnKind rk)) }
}
class SummaryComponentStack = Impl::Public::SummaryComponentStack;
/** Provides predicates for constructing stacks of summary components. */
module SummaryComponentStack {
private import Impl::Public::SummaryComponentStack as SCS
predicate singleton = SCS::singleton/1;
predicate push = SCS::push/2;
predicate argument = SCS::argument/1;
/** Gets a singleton stack representing the return value of a call. */
SummaryComponentStack return() { result = singleton(SummaryComponent::return()) }
}
/** A callable with a flow summary, identified by a unique string. */
abstract class SummarizedCallable extends LibraryCallable, Impl::Public::SummarizedCallable {
bindingset[this]
SummarizedCallable() { any() }
/**
* Same as
*
* ```ql
* propagatesFlow(
* SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue
* )
* ```
*
* but uses an external (string) representation of the input and output stacks.
*/
pragma[nomagic]
predicate propagatesFlowExt(string input, string output, boolean preservesValue) { none() }
}
class RequiredSummaryComponentStack = Impl::Public::RequiredSummaryComponentStack;
// // This gives access to getNodeFromPath, which is not constrained to `CallNode`s
// // as `resolvedSummaryBase` is.
// private import semmle.python.frameworks.data.internal.ApiGraphModels as AGM
//
// private class SummarizedCallableFromModel extends SummarizedCallable {
// string package;
// string type;
// string path;
// SummarizedCallableFromModel() {
// ModelOutput::relevantSummaryModel(package, type, path, _, _, _) and
// this = package + ";" + type + ";" + path
// }
// override CallCfgNode getACall() {
// exists(API::CallNode base |
// ModelOutput::resolvedSummaryBase(package, type, path, base) and
// result = base.getACall()
// )
// }
// override ArgumentNode getACallback() {
// exists(API::Node base |
// base = AGM::getNodeFromPath(package, type, path) and
// result = base.getAValueReachableFromSource()
// )
// }
// override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
// exists(string kind |
// ModelOutput::relevantSummaryModel(package, type, path, input, output, kind)
// |
// kind = "value" and
// preservesValue = true
// or
// kind = "taint" and
// preservesValue = false
// )
// }
// }

Просмотреть файл

@ -40,7 +40,7 @@ abstract class AttrRef extends Node {
or
exists(LocalSourceNode nodeFrom |
nodeFrom.flowsTo(this.getAttributeNameExpr()) and
attrName = nodeFrom.asExpr().(StrConst).getText()
attrName = nodeFrom.(CfgNode).getNode().getNode().(StrConst).getText()
)
}
@ -50,6 +50,9 @@ abstract class AttrRef extends Node {
* better results.
*/
abstract string getAttributeName();
/** Holds if a name could not be determined for this attribute. */
predicate unknownAttribute() { not exists(this.getAttributeName()) }
}
/**
@ -175,7 +178,7 @@ private class SetAttrCallAsAttrWrite extends AttrWrite, CfgNode {
override ExprNode getAttributeNameExpr() { result.asCfgNode() = node.getName() }
override string getAttributeName() {
result = this.getAttributeNameExpr().asExpr().(StrConst).getText()
result = this.getAttributeNameExpr().(CfgNode).getNode().getNode().(StrConst).getText()
}
}
@ -251,7 +254,7 @@ private class GetAttrCallAsAttrRead extends AttrRead, CfgNode {
override ExprNode getAttributeNameExpr() { result.asCfgNode() = node.getName() }
override string getAttributeName() {
result = this.getAttributeNameExpr().asExpr().(StrConst).getText()
result = this.getAttributeNameExpr().(CfgNode).getNode().getNode().(StrConst).getText()
}
}

Просмотреть файл

@ -60,9 +60,9 @@ module Builtins {
* Currently this is an over-approximation, and may not account for things like overwriting a
* built-in with a different value.
*/
DataFlow::Node likelyBuiltin(string name) {
DataFlow::CfgNode likelyBuiltin(string name) {
exists(Module m |
result.asCfgNode() =
result.getNode() =
any(NameNode n |
possible_builtin_accessed_in_module(n, name, m) and
not possible_builtin_defined_in_module(name, m)

Просмотреть файл

@ -7,15 +7,22 @@
private import python
private import DataFlowPublic
private import semmle.python.SpecialMethods
private import FlowSummaryImpl as FlowSummaryImpl
/** A parameter position represented by an integer. */
class ParameterPosition extends int {
ParameterPosition() { exists(any(DataFlowCallable c).getParameter(this)) }
/** Holds if this position represents a positional parameter at position `pos`. */
predicate isPositional(int pos) { this = pos } // with the current representation, all parameters are positional
}
/** An argument position represented by an integer. */
class ArgumentPosition extends int {
ArgumentPosition() { exists(any(DataFlowCall c).getArg(this)) }
ArgumentPosition() { this in [-2, -1] or exists(any(Call c).getArg(this)) }
/** Holds if this position represents a positional argument at position `pos`. */
predicate isPositional(int pos) { this = pos } // with the current representation, all arguments are positional
}
/** Holds if arguments at position `apos` match parameters at position `ppos`. */
@ -96,7 +103,7 @@ module ArgumentPassing {
* Used to limit the size of predicates.
*/
predicate connects(CallNode call, CallableValue callable) {
exists(DataFlowCall c |
exists(NormalCall c |
call = c.getNode() and
callable = c.getCallable().getCallableValue()
)
@ -268,6 +275,18 @@ module ArgumentPassing {
import ArgumentPassing
/** A callable defined in library code, identified by a unique string. */
abstract class LibraryCallable extends string {
bindingset[this]
LibraryCallable() { any() }
/** Gets a call to this library callable. */
abstract CallCfgNode getACall();
/** Gets a data-flow node, where this library callable is used as a call-back. */
abstract ArgumentNode getACallback();
}
/**
* IPA type for DataFlowCallable.
*
@ -282,27 +301,33 @@ newtype TDataFlowCallable =
callable instanceof ClassValue
} or
TLambda(Function lambda) { lambda.isLambda() } or
TModule(Module m)
TModule(Module m) or
TLibraryCallable(LibraryCallable callable)
/** A callable. */
abstract class DataFlowCallable extends TDataFlowCallable {
class DataFlowCallable extends TDataFlowCallable {
/** Gets a textual representation of this element. */
abstract string toString();
string toString() { result = "DataFlowCallable" }
/** Gets a call to this callable. */
abstract CallNode getACall();
CallNode getACall() { none() }
/** Gets the scope of this callable */
abstract Scope getScope();
Scope getScope() { none() }
/** Gets the specified parameter of this callable */
abstract NameNode getParameter(int n);
NameNode getParameter(int n) { none() }
/** Gets the name of this callable. */
abstract string getName();
string getName() { none() }
/** Gets a callable value for this callable, if one exists. */
abstract CallableValue getCallableValue();
/** Gets a callable value for this callable, if any. */
CallableValue getCallableValue() { none() }
/** Gets the underlying library callable, if any. */
LibraryCallable asLibraryCallable() { this = TLibraryCallable(result) }
Location getLocation() { none() }
}
/** A class representing a callable value. */
@ -343,6 +368,8 @@ class DataFlowLambda extends DataFlowCallable, TLambda {
override FunctionValue getCallableValue() {
result.getOrigin().getNode() = lambda.getDefinition()
}
Expr getDefinition() { result = lambda.getDefinition() }
}
/** A class representing the scope in which a `ModuleVariableNode` appears. */
@ -364,6 +391,27 @@ class DataFlowModuleScope extends DataFlowCallable, TModule {
override CallableValue getCallableValue() { none() }
}
class LibraryCallableValue extends DataFlowCallable, TLibraryCallable {
LibraryCallable callable;
LibraryCallableValue() { this = TLibraryCallable(callable) }
override string toString() { result = callable.toString() }
override CallNode getACall() { result = callable.getACall().getNode() }
/** Gets a data-flow node, where this library callable is used as a call-back. */
ArgumentNode getACallback() { result = callable.getACallback() }
override Scope getScope() { none() }
override NameNode getParameter(int n) { none() }
override string getName() { result = callable }
override LibraryCallable asLibraryCallable() { result = callable }
}
/**
* IPA type for DataFlowCall.
*
@ -379,90 +427,140 @@ class DataFlowModuleScope extends DataFlowCallable, TModule {
* TODO: Add `TClassMethodCall` mapping `cls` appropriately.
*/
newtype TDataFlowCall =
TFunctionCall(CallNode call) { call = any(FunctionValue f).getAFunctionCall() } or
/** Bound methods need to make room for the explicit self parameter */
TMethodCall(CallNode call) { call = any(FunctionValue f).getAMethodCall() } or
TClassCall(CallNode call) { call = any(ClassValue c | not c.isAbsent()).getACall() } or
TSpecialCall(SpecialMethodCallNode special)
/**
* Includes function calls, method calls, class calls and library calls.
* All these will be associated with a `CallNode`.
*/
TNormalCall(CallNode call) or
/**
* Includes calls to special methods.
* These will be associated with a `SpecialMethodCallNode`.
*/
TSpecialCall(SpecialMethodCallNode special) or
/** A synthesized call inside a summarized callable */
TSummaryCall(FlowSummaryImpl::Public::SummarizedCallable c, Node receiver) {
FlowSummaryImpl::Private::summaryCallbackRange(c, receiver)
}
/** A call. */
/** A call found in the program source (as opposed to a synthesised summary call). */
class TExtractedDataFlowCall = TSpecialCall or TNormalCall;
/** A call that is taken into account by the global data flow computation. */
abstract class DataFlowCall extends TDataFlowCall {
/** Gets a textual representation of this element. */
abstract string toString();
/** Get the callable to which this call goes. */
/** Get the callable to which this call goes, if such exists. */
abstract DataFlowCallable getCallable();
/**
* Gets the argument to this call that will be sent
* to the `n`th parameter of the callable.
* to the `n`th parameter of the callable, if any.
*/
abstract Node getArg(int n);
/** Get the control flow node representing this call. */
/** Get the control flow node representing this call, if any. */
abstract ControlFlowNode getNode();
/** Gets the enclosing callable of this call. */
abstract DataFlowCallable getEnclosingCallable();
/** Gets the location of this dataflow call. */
Location getLocation() { result = this.getNode().getLocation() }
abstract Location getLocation();
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
}
/** A call found in the program source (as opposed to a synthesised call). */
abstract class ExtractedDataFlowCall extends DataFlowCall, TExtractedDataFlowCall {
final override Location getLocation() { result = this.getNode().getLocation() }
abstract override DataFlowCallable getCallable();
abstract override Node getArg(int n);
abstract override ControlFlowNode getNode();
}
/** A call associated with a `CallNode`. */
class NormalCall extends ExtractedDataFlowCall, TNormalCall {
CallNode call;
NormalCall() { this = TNormalCall(call) }
override string toString() { result = call.toString() }
abstract override Node getArg(int n);
override CallNode getNode() { result = call }
abstract override DataFlowCallable getCallable();
override DataFlowCallable getEnclosingCallable() { result.getScope() = call.getNode().getScope() }
}
/**
* A call to a function/lambda.
* A call to a function.
* This excludes calls to bound methods, classes, and special methods.
* Bound method calls and class calls insert an argument for the explicit
* `self` parameter, and special method calls have special argument passing.
*/
class FunctionCall extends DataFlowCall, TFunctionCall {
CallNode call;
DataFlowCallable callable;
class FunctionCall extends NormalCall {
DataFlowCallableValue callable;
FunctionCall() {
this = TFunctionCall(call) and
call = any(FunctionValue f).getAFunctionCall() and
call = callable.getACall()
}
override string toString() { result = call.toString() }
override Node getArg(int n) { result = getArg(call, TNoShift(), callable.getCallableValue(), n) }
override DataFlowCallable getCallable() { result = callable }
}
/** A call to a lambda. */
class LambdaCall extends NormalCall {
DataFlowLambda callable;
LambdaCall() {
call = callable.getACall() and
callable = TLambda(any(Function f))
}
override Node getArg(int n) { result = getArg(call, TNoShift(), callable.getCallableValue(), n) }
override ControlFlowNode getNode() { result = call }
override DataFlowCallable getCallable() { result = callable }
override DataFlowCallable getEnclosingCallable() { result.getScope() = call.getNode().getScope() }
}
/**
* Represents a call to a bound method call.
* The node representing the instance is inserted as argument to the `self` parameter.
*/
class MethodCall extends DataFlowCall, TMethodCall {
CallNode call;
class MethodCall extends NormalCall {
FunctionValue bm;
MethodCall() {
this = TMethodCall(call) and
call = bm.getACall()
}
MethodCall() { call = bm.getAMethodCall() }
private CallableValue getCallableValue() { result = bm }
override string toString() { result = call.toString() }
override Node getArg(int n) {
n > 0 and result = getArg(call, TShiftOneUp(), this.getCallableValue(), n)
or
n = 0 and result = TCfgNode(call.getFunction().(AttrNode).getObject())
}
override ControlFlowNode getNode() { result = call }
override DataFlowCallable getCallable() { result = TCallableValue(this.getCallableValue()) }
override DataFlowCallable getEnclosingCallable() { result.getScope() = call.getScope() }
}
/**
@ -471,34 +569,27 @@ class MethodCall extends DataFlowCall, TMethodCall {
* That makes the call node be the post-update node holding the value of the object
* after the constructor has run.
*/
class ClassCall extends DataFlowCall, TClassCall {
CallNode call;
class ClassCall extends NormalCall {
ClassValue c;
ClassCall() {
this = TClassCall(call) and
not c.isAbsent() and
call = c.getACall()
}
private CallableValue getCallableValue() { c.getScope().getInitMethod() = result.getScope() }
override string toString() { result = call.toString() }
override Node getArg(int n) {
n > 0 and result = getArg(call, TShiftOneUp(), this.getCallableValue(), n)
or
n = 0 and result = TSyntheticPreUpdateNode(TCfgNode(call))
}
override ControlFlowNode getNode() { result = call }
override DataFlowCallable getCallable() { result = TCallableValue(this.getCallableValue()) }
override DataFlowCallable getEnclosingCallable() { result.getScope() = call.getScope() }
}
/** A call to a special method. */
class SpecialCall extends DataFlowCall, TSpecialCall {
class SpecialCall extends ExtractedDataFlowCall, TSpecialCall {
SpecialMethodCallNode special;
SpecialCall() { this = TSpecialCall(special) }
@ -518,8 +609,172 @@ class SpecialCall extends DataFlowCall, TSpecialCall {
}
}
/**
* A call to a summarized callable, a `LibraryCallable`.
*
* We currently exclude all resolved calls. This means that a call to, say, `map`, which
* is a `ClassCall`, cannot currently be given a summary.
* We hope to lift this restriction in the future and include all potential calls to summaries
* in this class.
*/
class LibraryCall extends NormalCall {
LibraryCall() {
// TODO: share this with `resolvedCall`
not (
call = any(DataFlowCallableValue cv).getACall()
or
call = any(DataFlowLambda l).getACall()
or
// TODO: this should be covered by `DataFlowCallableValue`, but a `ClassValue` is not a `CallableValue`.
call = any(ClassValue c).getACall()
)
}
// TODO: Implement Python calling convention?
override Node getArg(int n) { result = TCfgNode(call.getArg(n)) }
// We cannot refer to a `LibraryCallable` here,
// as that could in turn refer to type tracking.
// This call will be tied to a `LibraryCallable` via
// `getViableCallabe` when the global data flow is assembled.
override DataFlowCallable getCallable() { none() }
}
/**
* A synthesized call inside a callable with a flow summary.
*
* For example, in
* ```python
* map(lambda x: x + 1, [1, 2, 3])
* ```
*
* there is a synthesized call to the lambda argument inside `map`.
*/
class SummaryCall extends DataFlowCall, TSummaryCall {
private FlowSummaryImpl::Public::SummarizedCallable c;
private Node receiver;
SummaryCall() { this = TSummaryCall(c, receiver) }
/** Gets the data flow node that this call targets. */
Node getReceiver() { result = receiver }
override DataFlowCallable getEnclosingCallable() { result.asLibraryCallable() = c }
override DataFlowCallable getCallable() { none() }
override Node getArg(int n) { none() }
override ControlFlowNode getNode() { none() }
override string toString() { result = "[summary] call to " + receiver + " in " + c }
override Location getLocation() { none() }
}
/**
* The value of a parameter at function entry, viewed as a node in a data
* flow graph.
*/
abstract class ParameterNodeImpl extends Node {
abstract Parameter getParameter();
/**
* Holds if this node is the parameter of callable `c` at the
* (zero-based) index `i`.
*/
abstract predicate isParameterOf(DataFlowCallable c, int i);
}
/** A parameter for a library callable with a flow summary. */
class SummaryParameterNode extends ParameterNodeImpl, TSummaryParameterNode {
private FlowSummaryImpl::Public::SummarizedCallable sc;
private int pos;
SummaryParameterNode() { this = TSummaryParameterNode(sc, pos) }
override Parameter getParameter() { none() }
override predicate isParameterOf(DataFlowCallable c, int i) {
sc = c.asLibraryCallable() and i = pos
}
override DataFlowCallable getEnclosingCallable() { result.asLibraryCallable() = sc }
override string toString() { result = "parameter " + pos + " of " + sc }
// Hack to return "empty location"
override predicate hasLocationInfo(
string file, int startline, int startcolumn, int endline, int endcolumn
) {
file = "" and
startline = 0 and
startcolumn = 0 and
endline = 0 and
endcolumn = 0
}
}
/** A data-flow node used to model flow summaries. */
class SummaryNode extends Node, TSummaryNode {
private FlowSummaryImpl::Public::SummarizedCallable c;
private FlowSummaryImpl::Private::SummaryNodeState state;
SummaryNode() { this = TSummaryNode(c, state) }
override DataFlowCallable getEnclosingCallable() { result.asLibraryCallable() = c }
override string toString() { result = "[summary] " + state + " in " + c }
// Hack to return "empty location"
override predicate hasLocationInfo(
string file, int startline, int startcolumn, int endline, int endcolumn
) {
file = "" and
startline = 0 and
startcolumn = 0 and
endline = 0 and
endcolumn = 0
}
}
private class SummaryReturnNode extends SummaryNode, ReturnNode {
private ReturnKind rk;
SummaryReturnNode() { FlowSummaryImpl::Private::summaryReturnNode(this, rk) }
override ReturnKind getKind() { result = rk }
}
private class SummaryArgumentNode extends SummaryNode, ArgumentNode {
SummaryArgumentNode() { FlowSummaryImpl::Private::summaryArgumentNode(_, this, _) }
override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
FlowSummaryImpl::Private::summaryArgumentNode(call, this, pos)
}
}
private class SummaryPostUpdateNode extends SummaryNode, PostUpdateNode {
private Node pre;
SummaryPostUpdateNode() { FlowSummaryImpl::Private::summaryPostUpdateNode(this, pre) }
override Node getPreUpdateNode() { result = pre }
}
/** Gets a viable run-time target for the call `call`. */
DataFlowCallable viableCallable(DataFlowCall call) { result = call.getCallable() }
DataFlowCallable viableCallable(ExtractedDataFlowCall call) {
result = call.getCallable()
or
// A call to a library callable with a flow summary
// In this situation we can not resolve the callable from the call,
// as that would make data flow depend on type tracking.
// Instead we reolve the call from the summary.
exists(LibraryCallable callable |
result = TLibraryCallable(callable) and
call.getNode() = callable.getACall().getNode()
)
}
private newtype TReturnKind = TNormalReturnKind()
@ -533,26 +788,51 @@ class ReturnKind extends TReturnKind {
}
/** A data flow node that represents a value returned by a callable. */
class ReturnNode extends CfgNode {
Return ret;
// See `TaintTrackingImplementation::returnFlowStep`
ReturnNode() { node = ret.getValue().getAFlowNode() }
abstract class ReturnNode extends Node {
/** Gets the kind of this return node. */
ReturnKind getKind() { any() }
}
/** A data flow node that represents the output of a call. */
class OutNode extends CfgNode {
OutNode() { node instanceof CallNode }
/** A data flow node that represents a value returned by a callable. */
class ExtractedReturnNode extends ReturnNode, CfgNode {
// See `TaintTrackingImplementation::returnFlowStep`
ExtractedReturnNode() { node = any(Return ret).getValue().getAFlowNode() }
override ReturnKind getKind() { any() }
}
/** A data-flow node that represents the output of a call. */
abstract class OutNode extends Node {
/** Gets the underlying call, where this node is a corresponding output of kind `kind`. */
abstract DataFlowCall getCall(ReturnKind kind);
}
private module OutNodes {
/**
* A data-flow node that reads a value returned directly by a callable.
*/
class ExprOutNode extends OutNode, ExprNode {
private DataFlowCall call;
ExprOutNode() { call.(ExtractedDataFlowCall).getNode() = this.getNode() }
override DataFlowCall getCall(ReturnKind kind) {
result = call and
kind = kind
}
}
private class SummaryOutNode extends SummaryNode, OutNode {
SummaryOutNode() { FlowSummaryImpl::Private::summaryOutNode(_, this, _) }
override DataFlowCall getCall(ReturnKind kind) {
FlowSummaryImpl::Private::summaryOutNode(result, this, kind)
}
}
}
/**
* Gets a node that can read the value returned from `call` with return kind
* `kind`.
*/
OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) {
call.getNode() = result.getNode() and
kind = TNormalReturnKind()
}
OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) { call = result.getCall(kind) }

Просмотреть файл

@ -2,6 +2,7 @@ private import python
private import DataFlowPublic
private import semmle.python.essa.SsaCompute
private import semmle.python.dataflow.new.internal.ImportResolution
private import FlowSummaryImpl as FlowSummaryImpl
// Since we allow extra data-flow steps from modeled frameworks, we import these
// up-front, to ensure these are included. This provides a more seamless experience from
// a user point of view, since they don't need to know they need to import a specific
@ -21,7 +22,7 @@ import DataFlowDispatchPointsTo
DataFlowCallable nodeGetEnclosingCallable(Node n) { result = n.getEnclosingCallable() }
/** Holds if `p` is a `ParameterNode` of `c` with position `pos`. */
predicate isParameterNode(ParameterNode p, DataFlowCallable c, ParameterPosition pos) {
predicate isParameterNode(ParameterNodeImpl p, DataFlowCallable c, ParameterPosition pos) {
p.isParameterOf(c, pos)
}
@ -77,7 +78,7 @@ module SyntheticPreUpdateNode {
* that is mapped to the `self` parameter. That way, constructor calls represent the value of the
* object after the constructor (currently only `__init__`) has run.
*/
CfgNode objectCreationNode() { result.getNode().(CallNode) = any(ClassCall c).getNode() }
CfgNode objectCreationNode() { result.getNode() = any(ClassCall c).getNode() }
}
import SyntheticPreUpdateNode
@ -87,6 +88,8 @@ deprecated module syntheticPostUpdateNode = SyntheticPostUpdateNode;
/** A module collecting the different reasons for synthesising a post-update node. */
module SyntheticPostUpdateNode {
private import semmle.python.SpecialMethods
/** A post-update node is synthesized for all nodes which satisfy `NeedsSyntheticPostUpdateNode`. */
class SyntheticPostUpdateNode extends PostUpdateNode, TSyntheticPostUpdateNode {
NeedsSyntheticPostUpdateNode pre;
@ -136,6 +139,8 @@ module SyntheticPostUpdateNode {
Node argumentPreUpdateNode() {
result = any(FunctionCall c).getArg(_)
or
result = any(LambdaCall c).getArg(_)
or
// Avoid argument 0 of method calls as those have read post-update nodes.
exists(MethodCall c, int n | n > 0 | result = c.getArg(n))
or
@ -145,11 +150,18 @@ module SyntheticPostUpdateNode {
exists(ClassCall c, int n | n > 0 | result = c.getArg(n))
or
// any argument of any call that we have not been able to resolve
exists(CallNode call | not call = any(DataFlowCall c).getNode() |
exists(CallNode call | not resolvedCall(call) |
result.(CfgNode).getNode() in [call.getArg(_), call.getArgByName(_)]
)
}
/** Holds if `call` can be resolved as a normal call */
private predicate resolvedCall(CallNode call) {
call = any(DataFlowCallableValue cv).getACall()
or
call = any(DataFlowLambda l).getACall()
}
/** Gets the pre-update node associated with a store. This is used for when an object might have its value changed after a store. */
CfgNode storePreUpdateNode() {
exists(Attribute a |
@ -287,10 +299,22 @@ module EssaFlow {
* This is the local flow predicate that is used as a building block in global
* data flow.
*
* It includes flow steps from flow summaries.
*/
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
simpleLocalFlowStepForTypetracking(nodeFrom, nodeTo)
or
summaryFlowSteps(nodeFrom, nodeTo)
}
/**
* This is the local flow predicate that is used as a building block in
* type tracking, it does _not_ include steps from flow summaries.
*
* Local flow can happen either at import time, when the module is initialised
* or at runtime when callables in the module are called.
*/
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
predicate simpleLocalFlowStepForTypetracking(Node nodeFrom, Node nodeTo) {
// If there is local flow out of a node `node`, we want flow
// both out of `node` and any post-update node of `node`.
exists(Node node |
@ -326,6 +350,34 @@ predicate runtimeLocalFlowStep(Node nodeFrom, Node nodeTo) {
EssaFlow::essaFlowStep(nodeFrom, nodeTo)
}
predicate summaryFlowSteps(Node nodeFrom, Node nodeTo) {
// If there is local flow out of a node `node`, we want flow
// both out of `node` and any post-update node of `node`.
exists(Node node |
nodeFrom = update(node) and
(
importTimeSummaryFlowStep(node, nodeTo) or
runtimeSummaryFlowStep(node, nodeTo)
)
)
}
predicate importTimeSummaryFlowStep(Node nodeFrom, Node nodeTo) {
// As a proxy for whether statements can be executed at import time,
// we check if they appear at the top level.
// This will miss statements inside functions called from the top level.
isTopLevel(nodeFrom) and
isTopLevel(nodeTo) and
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom, nodeTo, true)
}
predicate runtimeSummaryFlowStep(Node nodeFrom, Node nodeTo) {
// Anything not at the top level can be executed at runtime.
not isTopLevel(nodeFrom) and
not isTopLevel(nodeTo) and
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom, nodeTo, true)
}
/** `ModuleVariable`s are accessed via jump steps at runtime. */
predicate runtimeJumpStep(Node nodeFrom, Node nodeTo) {
// Module variable read
@ -474,6 +526,8 @@ predicate storeStep(Node nodeFrom, Content c, Node nodeTo) {
matchStoreStep(nodeFrom, c, nodeTo)
or
any(Orm::AdditionalOrmSteps es).storeStep(nodeFrom, c, nodeTo)
or
FlowSummaryImpl::Private::Steps::summaryStoreStep(nodeFrom, c, nodeTo)
}
/**
@ -667,6 +721,8 @@ predicate readStep(Node nodeFrom, Content c, Node nodeTo) {
attributeReadStep(nodeFrom, c, nodeTo)
or
kwUnpackReadStep(nodeFrom, c, nodeTo)
or
FlowSummaryImpl::Private::Steps::summaryReadStep(nodeFrom, c, nodeTo)
}
/** Data flows from a sequence to a subscript of the sequence. */
@ -791,6 +847,8 @@ predicate clearsContent(Node n, Content c) {
matchClearStep(n, c)
or
attributeClearStep(n, c)
or
FlowSummaryImpl::Private::Steps::summaryClearsContent(n, c)
}
/**
@ -842,15 +900,38 @@ int accessPathLimit() { result = 5 }
predicate forceHighPrecision(Content c) { none() }
/** Holds if `n` should be hidden from path explanations. */
predicate nodeIsHidden(Node n) { none() }
predicate nodeIsHidden(Node n) {
n instanceof SummaryNode
or
n instanceof SummaryParameterNode
}
class LambdaCallKind = Unit;
/** Holds if `creation` is an expression that creates a lambda of kind `kind` for `c`. */
predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c) { none() }
predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c) {
// lambda
kind = kind and
creation.asExpr() = c.(DataFlowLambda).getDefinition()
or
// normal function
exists(FunctionDef def |
def.defines(creation.asVar().getSourceVariable()) and
def.getDefinedFunction() = c.(DataFlowCallableValue).getCallableValue().getScope()
)
or
// summarized function
exists(Call call |
creation.asExpr() = call.getAnArg() and
creation = c.(LibraryCallableValue).getACallback()
)
}
/** Holds if `call` is a lambda call of kind `kind` where `receiver` is the lambda expression. */
predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) { none() }
predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) {
receiver = call.(SummaryCall).getReceiver() and
exists(kind)
}
/** Extra data-flow steps needed for lambda flow analysis. */
predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) { none() }
@ -862,4 +943,6 @@ predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preserves
* One example would be to allow flow like `p.foo = p.bar;`, which is disallowed
* by default as a heuristic.
*/
predicate allowParameterReturnInSelf(ParameterNode p) { none() }
predicate allowParameterReturnInSelf(ParameterNode p) {
FlowSummaryImpl::Private::summaryAllowParameterReturnInSelf(p)
}

Просмотреть файл

@ -9,6 +9,7 @@ import Attributes
import LocalSources
private import semmle.python.essa.SsaCompute
private import semmle.python.dataflow.new.internal.ImportStar
private import FlowSummaryImpl as FlowSummaryImpl
/**
* IPA type for data flow nodes.
@ -100,7 +101,17 @@ newtype TNode =
//
// So for now we live with having these synthetic ORM nodes for _all_ classes, which
// is a bit wasteful, but we don't think it will hurt too much.
TSyntheticOrmModelNode(Class cls)
TSyntheticOrmModelNode(Class cls) or
TSummaryNode(
FlowSummaryImpl::Public::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNodeState state
) {
FlowSummaryImpl::Private::summaryNodeRange(c, state)
} or
TSummaryParameterNode(FlowSummaryImpl::Public::SummarizedCallable c, ParameterPosition pos) {
FlowSummaryImpl::Private::summaryParameterNodeRange(c, pos)
}
class TParameterNode = TCfgNode or TSummaryParameterNode;
/** Helper for `Node::getEnclosingCallable`. */
private DataFlowCallable getCallableScope(Scope s) {
@ -277,40 +288,56 @@ ExprNode exprNode(DataFlowExpr e) { result.getNode().getNode() = e }
* The value of a parameter at function entry, viewed as a node in a data
* flow graph.
*/
class ParameterNode extends CfgNode, LocalSourceNode {
class ParameterNode extends Node, TParameterNode instanceof ParameterNodeImpl {
/** Gets the parameter corresponding to this node, if any. */
final Parameter getParameter() { result = super.getParameter() }
}
/** A parameter node found in the source code (not in a summary). */
class ExtractedParameterNode extends ParameterNodeImpl, CfgNode {
//, LocalSourceNode {
ParameterDefinition def;
ParameterNode() {
ExtractedParameterNode() {
node = def.getDefiningNode() and
// Disregard parameters that we cannot resolve
// TODO: Make this unnecessary
exists(DataFlowCallable c | node = c.getParameter(_))
}
/**
* Holds if this node is the parameter of callable `c` at the
* (zero-based) index `i`.
*/
predicate isParameterOf(DataFlowCallable c, int i) { node = c.getParameter(i) }
override predicate isParameterOf(DataFlowCallable c, int i) { node = c.getParameter(i) }
override DataFlowCallable getEnclosingCallable() { this.isParameterOf(result, _) }
/** Gets the `Parameter` this `ParameterNode` represents. */
Parameter getParameter() { result = def.getParameter() }
override Parameter getParameter() { result = def.getParameter() }
}
class LocalSourceParameterNode extends ExtractedParameterNode, LocalSourceNode { }
/** Gets a node corresponding to parameter `p`. */
ParameterNode parameterNode(Parameter p) { result.getParameter() = p }
ExtractedParameterNode parameterNode(Parameter p) { result.getParameter() = p }
/** A data flow node that represents a call argument. */
class ArgumentNode extends Node {
ArgumentNode() { this = any(DataFlowCall c).getArg(_) }
abstract class ArgumentNode extends Node {
/** Holds if this argument occurs at the given position in the given call. */
predicate argumentOf(DataFlowCall call, int pos) { this = call.getArg(pos) }
abstract predicate argumentOf(DataFlowCall call, ArgumentPosition pos);
/** Gets the call in which this node is an argument. */
final DataFlowCall getCall() { this.argumentOf(result, _) }
/** Gets the call in which this node is an argument, if any. */
final ExtractedDataFlowCall getCall() { this.argumentOf(result, _) }
}
/** A data flow node that represents a call argument found in the source code. */
class ExtractedArgumentNode extends ArgumentNode {
ExtractedArgumentNode() { this = any(ExtractedDataFlowCall c).getArg(_) }
final override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
this.extractedArgumentOf(call, pos)
}
predicate extractedArgumentOf(ExtractedDataFlowCall call, ArgumentPosition pos) {
this = call.getArg(pos)
}
}
/**
@ -390,7 +417,7 @@ class ModuleVariableNode extends Node, TModuleVariableNode {
/** Gets an `EssaNode` that corresponds to an assignment of this global variable. */
EssaNode getAWrite() {
result.asVar().getDefinition().(EssaNodeDefinition).definedBy(var, any(DefinitionNode defn))
result.getVar().getDefinition().(EssaNodeDefinition).definedBy(var, any(DefinitionNode defn))
}
/** Gets the possible values of the variable at the end of import time */

Просмотреть файл

@ -5,12 +5,20 @@
private import python
private import DataFlowPrivate
import DataFlowPublic
private import FlowSummaryImpl as FlowSummaryImpl
/**
* Holds if data flows from `nodeFrom` to `nodeTo` in exactly one local
* (intra-procedural) step.
*/
predicate localFlowStep(Node nodeFrom, Node nodeTo) { simpleLocalFlowStep(nodeFrom, nodeTo) }
predicate localFlowStep(Node nodeFrom, Node nodeTo) {
simpleLocalFlowStep(nodeFrom, nodeTo)
or
// Simple flow through library code is included in the exposed local
// step relation, even though flow is technically inter-procedural.
// This is a convention followed across languages.
FlowSummaryImpl::Private::Steps::summaryThroughStepValue(nodeFrom, nodeTo, _)
}
/**
* Holds if data flows from `source` to `sink` in zero or more local

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,225 @@
/**
* Provides Python specific classes and predicates for defining flow summaries.
*
* Flow summaries are defined for callables that are not extracted.
* Such callables go by different names in different parts of our codebase:
*
* - in `FlowSummary.qll`, which is user facing, they are called `SummarizedCallable`s.
* These contain summaries, implemented by the user via the predicates `propagatesFlow` and `propagatesFlowExt`.
*
* - in the data flow layer, they are called `LibraryCallable`s (as in the Ruby codebase).
* These are identified by strings and has predicates for finding calls to them.
*
* Having both extracted and non-extracted callables means that we now have three types of calls:
* - Extracted calls to extracted callables, either `NormalCall` or `SpecialCall`. These are handled by standard data flow.
* - Extracted calls to non-extracted callables, `LibraryCall`. These are handled by loking up the relevant summary when the
* global data flwo graph is connected up via `getViableCallable`.
* - Non-extracted calls, `SummaryCall`. These are synthesised by the flow summary framework.
*
* The first two can be referred to as `ExtractedDataFlowCall`. In fact, `LibraryCall` is a subclass of `NormalCall`, where
* `getCallable` is set to `none()`. The member predicate `ExtractedDataFlowCall::getCallable` is _not_ the mechanism for
* call resolution in global data flow. That mechanism is `getViableCallable`.
* Resolving a call to a non-extracted callable goes via `LibraryCallable::getACall`, which may involve type tracking.
* To avoid that type tracking becomes mutualy recursive with data flow, type tracking must use a call graph not including summaries.
* Type tracking sees the callgraph given by `ExtractedDataFlowCall::getACallable`.
*
* We do not support summaries of special methods via the special methods framework,
* the summary would have to identify the call.
*
* We might, while we still extract the standard library, want to support flow summaries of
* extracted callables, so that we can model part of the standard library with flow summaries.
* For this to work, we have be careful with the enclosing callable predicate.
*/
private import python
private import DataFlowPrivate
private import DataFlowPublic
private import DataFlowImplCommon
private import FlowSummaryImpl::Private
private import FlowSummaryImpl::Public
private import semmle.python.dataflow.new.FlowSummary as FlowSummary
class SummarizedCallableBase = string;
/** View a `SummarizedCallable` as a `DataFlowCallable`. */
DataFlowCallable inject(SummarizedCallable c) { result.asLibraryCallable() = c }
/** Gets the parameter position of the instance parameter. */
ArgumentPosition instanceParameterPosition() { none() } // disables implicit summary flow to `this` for callbacks
/** Gets the synthesized summary data-flow node for the given values. */
Node summaryNode(SummarizedCallable c, SummaryNodeState state) { result = TSummaryNode(c, state) }
/** Gets the synthesized data-flow call for `receiver`. */
SummaryCall summaryDataFlowCall(Node receiver) { receiver = result.getReceiver() }
/** Gets the type of content `c`. */
DataFlowType getContentType(Content c) { any() }
/** Gets the return type of kind `rk` for callable `c`. */
bindingset[c, rk]
DataFlowType getReturnType(SummarizedCallable c, ReturnKind rk) { any() }
/**
* Gets the type of the `i`th parameter in a synthesized call that targets a
* callback of type `t`.
*/
bindingset[t, i]
DataFlowType getCallbackParameterType(DataFlowType t, int i) { any() }
/**
* Gets the return type of kind `rk` in a synthesized call that targets a
* callback of type `t`.
*/
DataFlowType getCallbackReturnType(DataFlowType t, ReturnKind rk) { any() }
/**
* Holds if an external flow summary exists for `c` with input specification
* `input`, output specification `output`, kind `kind`, and a flag `generated`
* stating whether the summary is autogenerated.
*/
predicate summaryElement(
FlowSummary::SummarizedCallable c, string input, string output, string kind, boolean generated
) {
exists(boolean preservesValue |
c.propagatesFlowExt(input, output, preservesValue) and
(if preservesValue = true then kind = "value" else kind = "taint") and
generated = false
)
}
/**
* Holds if a negative flow summary exists for `c`, which means that there is no
* flow through `c`. The flag `generated` states whether the summary is autogenerated.
* Note. Negative flow summaries has not been implemented for Python.
*/
predicate negativeSummaryElement(FlowSummary::SummarizedCallable c, boolean generated) { none() }
/**
* Gets the summary component for specification component `c`, if any.
*
* This covers all the Python-specific components of a flow summary.
*/
SummaryComponent interpretComponentSpecific(AccessPathToken c) {
c = "ListElement" and
result = FlowSummary::SummaryComponent::listElement()
}
/** Gets the textual representation of a summary component in the format used for flow summaries. */
string getComponentSpecificCsv(SummaryComponent sc) {
sc = TContentSummaryComponent(any(ListElementContent c)) and
result = "ListElement"
}
/** Gets the textual representation of a parameter position in the format used for flow summaries. */
string getParameterPositionCsv(ParameterPosition pos) { result = pos.toString() }
/** Gets the textual representation of an argument position in the format used for flow summaries. */
string getArgumentPositionCsv(ArgumentPosition pos) { result = pos.toString() }
/** Holds if input specification component `c` needs a reference. */
predicate inputNeedsReferenceSpecific(string c) { none() }
/** Holds if output specification component `c` needs a reference. */
predicate outputNeedsReferenceSpecific(string c) { none() }
/** Gets the return kind corresponding to specification `"ReturnValue"`. */
ReturnKind getReturnValueKind() { any() }
/**
* All definitions in this module are required by the shared implementation
* (for source/sink interpretation), but they are unused for Python, where
* we rely on API graphs instead.
*/
private module UnusedSourceSinkInterpretation {
/**
* Holds if an external source specification exists for `n` with output specification
* `output`, kind `kind`, and a flag `generated` stating whether the source specification is
* autogenerated.
*/
predicate sourceElement(AstNode n, string output, string kind, boolean generated) { none() }
/**
* Holds if an external sink specification exists for `n` with input specification
* `input`, kind `kind` and a flag `generated` stating whether the sink specification is
* autogenerated.
*/
predicate sinkElement(AstNode n, string input, string kind, boolean generated) { none() }
class SourceOrSinkElement = AstNode;
/** An entity used to interpret a source/sink specification. */
class InterpretNode extends AstNode_ {
// InterpretNode is going away, this is just a dummy implementation.
// However, we have some old location tests picking them up, so we
// explicitly define them to not exist.
InterpretNode() { none() }
/** Gets the element that this node corresponds to, if any. */
SourceOrSinkElement asElement() { none() }
/** Gets the data-flow node that this node corresponds to, if any. */
Node asNode() { none() }
/** Gets the call that this node corresponds to, if any. */
DataFlowCall asCall() { none() }
/** Gets the callable that this node corresponds to, if any. */
DataFlowCallable asCallable() { none() }
/** Gets the target of this call, if any. */
SourceOrSinkElement getCallTarget() { none() }
}
/** Provides additional sink specification logic. */
predicate interpretOutputSpecific(string c, InterpretNode mid, InterpretNode node) { none() }
/** Provides additional source specification logic. */
predicate interpretInputSpecific(string c, InterpretNode mid, InterpretNode node) { none() }
}
import UnusedSourceSinkInterpretation
module ParsePositions {
private import FlowSummaryImpl
private predicate isParamBody(string body) {
exists(AccessPathToken tok |
tok.getName() = "Parameter" and
body = tok.getAnArgument()
)
}
private predicate isArgBody(string body) {
exists(AccessPathToken tok |
tok.getName() = "Argument" and
body = tok.getAnArgument()
)
}
predicate isParsedParameterPosition(string c, int i) {
isParamBody(c) and
i = AccessPath::parseInt(c)
}
predicate isParsedArgumentPosition(string c, int i) {
isArgBody(c) and
i = AccessPath::parseInt(c)
}
}
/** Gets the argument position obtained by parsing `X` in `Parameter[X]`. */
ArgumentPosition parseParamBody(string s) {
exists(int i |
ParsePositions::isParsedParameterPosition(s, i) and
result.isPositional(i)
)
}
/** Gets the parameter position obtained by parsing `X` in `Argument[X]`. */
ParameterPosition parseArgBody(string s) {
exists(int i |
ParsePositions::isParsedArgumentPosition(s, i) and
result.isPositional(i)
)
}

Просмотреть файл

@ -244,7 +244,7 @@ class UnpackingAssignmentSequenceTarget extends UnpackingAssignmentTarget instan
*/
predicate iterableUnpackingAssignmentFlowStep(Node nodeFrom, Node nodeTo) {
exists(AssignmentTarget target |
nodeFrom.asExpr() = target.getValue() and
nodeFrom.(CfgNode).getNode().getNode() = target.getValue() and
nodeTo = TIterableSequenceNode(target)
)
}
@ -255,7 +255,7 @@ predicate iterableUnpackingAssignmentFlowStep(Node nodeFrom, Node nodeTo) {
*/
predicate iterableUnpackingForReadStep(CfgNode nodeFrom, Content c, Node nodeTo) {
exists(ForTarget target |
nodeFrom.asExpr() = target.getSource() and
nodeFrom.getNode().getNode() = target.getSource() and
target instanceof SequenceNode and
nodeTo = TIterableSequenceNode(target)
) and
@ -273,7 +273,7 @@ predicate iterableUnpackingForReadStep(CfgNode nodeFrom, Content c, Node nodeTo)
predicate iterableUnpackingTupleFlowStep(Node nodeFrom, Node nodeTo) {
exists(UnpackingAssignmentSequenceTarget target |
nodeFrom = TIterableSequenceNode(target) and
nodeTo.asCfgNode() = target
nodeTo.(CfgNode).getNode() = target
)
}
@ -305,7 +305,7 @@ predicate iterableUnpackingConvertingReadStep(Node nodeFrom, Content c, Node nod
predicate iterableUnpackingConvertingStoreStep(Node nodeFrom, Content c, Node nodeTo) {
exists(UnpackingAssignmentSequenceTarget target |
nodeFrom = TIterableElementNode(target) and
nodeTo.asCfgNode() = target and
nodeTo.(CfgNode).getNode() = target and
exists(int index | exists(target.getElement(index)) |
c.(TupleElementContent).getIndex() = index
)
@ -331,7 +331,7 @@ predicate iterableUnpackingElementReadStep(Node nodeFrom, Content c, Node nodeTo
not exists(target.getAnElement().(StarredNode)) and
starIndex = -1
|
nodeFrom.asCfgNode() = target and
nodeFrom.(CfgNode).getNode() = target and
element = target.getElement(index) and
(
if starIndex = -1 or index < starIndex

Просмотреть файл

@ -36,7 +36,7 @@ class LocalSourceNode extends Node {
LocalSourceNode() {
Stages::DataFlow::ref() and
this instanceof ExprNode and
not simpleLocalFlowStep(_, this)
not simpleLocalFlowStepForTypetracking(_, this)
or
// We include all module variable nodes, as these act as stepping stones between writes and
// reads of global variables. Without them, type tracking based on `LocalSourceNode`s would be

Просмотреть файл

@ -69,8 +69,8 @@ predicate matchSubjectFlowStep(Node nodeFrom, Node nodeTo) {
subject = match.getSubject() and
target = match.getCase(_).(Case).getPattern()
|
nodeFrom.asExpr() = subject and
nodeTo.asCfgNode().getNode() = target
nodeFrom.(CfgNode).getNode().getNode() = subject and
nodeTo.(CfgNode).getNode().getNode() = target
)
}
@ -84,12 +84,13 @@ predicate matchAsFlowStep(Node nodeFrom, Node nodeTo) {
// That way, information can propagate from the interior pattern to the alias.
//
// the subject flows to the interior pattern
nodeFrom.asCfgNode().getNode() = subject and
nodeTo.asCfgNode().getNode() = subject.getPattern()
nodeFrom.(CfgNode).getNode().getNode() = subject and
nodeTo.(CfgNode).getNode().getNode() = subject.getPattern()
or
// the interior pattern flows to the alias
nodeFrom.asCfgNode().getNode() = subject.getPattern() and
nodeTo.asVar().getDefinition().(PatternAliasDefinition).getDefiningNode().getNode() = alias
nodeFrom.(CfgNode).getNode().getNode() = subject.getPattern() and
nodeTo.(EssaNode).getVar().getDefinition().(PatternAliasDefinition).getDefiningNode().getNode() =
alias
)
}
@ -99,8 +100,8 @@ predicate matchAsFlowStep(Node nodeFrom, Node nodeTo) {
*/
predicate matchOrFlowStep(Node nodeFrom, Node nodeTo) {
exists(MatchOrPattern subject, Pattern pattern | pattern = subject.getAPattern() |
nodeFrom.asCfgNode().getNode() = subject and
nodeTo.asCfgNode().getNode() = pattern
nodeFrom.(CfgNode).getNode().getNode() = subject and
nodeTo.(CfgNode).getNode().getNode() = pattern
)
}
@ -110,8 +111,8 @@ predicate matchOrFlowStep(Node nodeFrom, Node nodeTo) {
*/
predicate matchLiteralFlowStep(Node nodeFrom, Node nodeTo) {
exists(MatchLiteralPattern pattern, Expr literal | literal = pattern.getLiteral() |
nodeFrom.asExpr() = literal and
nodeTo.asCfgNode().getNode() = pattern
nodeFrom.(CfgNode).getNode().getNode() = literal and
nodeTo.(CfgNode).getNode().getNode() = pattern
)
}
@ -121,8 +122,14 @@ predicate matchLiteralFlowStep(Node nodeFrom, Node nodeTo) {
*/
predicate matchCaptureFlowStep(Node nodeFrom, Node nodeTo) {
exists(MatchCapturePattern capture, Name var | capture.getVariable() = var |
nodeFrom.asCfgNode().getNode() = capture and
nodeTo.asVar().getDefinition().(PatternCaptureDefinition).getDefiningNode().getNode() = var
nodeFrom.(CfgNode).getNode().getNode() = capture and
nodeTo
.(EssaNode)
.getVar()
.getDefinition()
.(PatternCaptureDefinition)
.getDefiningNode()
.getNode() = var
)
}
@ -132,8 +139,8 @@ predicate matchCaptureFlowStep(Node nodeFrom, Node nodeTo) {
*/
predicate matchValueFlowStep(Node nodeFrom, Node nodeTo) {
exists(MatchValuePattern pattern, Expr value | value = pattern.getValue() |
nodeFrom.asExpr() = value and
nodeTo.asCfgNode().getNode() = pattern
nodeFrom.(CfgNode).getNode().getNode() = value and
nodeTo.(CfgNode).getNode().getNode() = pattern
)
}
@ -145,8 +152,8 @@ predicate matchSequenceReadStep(Node nodeFrom, Content c, Node nodeTo) {
exists(MatchSequencePattern subject, int index, Pattern element |
element = subject.getPattern(index)
|
nodeFrom.asCfgNode().getNode() = subject and
nodeTo.asCfgNode().getNode() = element and
nodeFrom.(CfgNode).getNode().getNode() = subject and
nodeTo.(CfgNode).getNode().getNode() = element and
(
// tuple content
c.(TupleElementContent).getIndex() = index
@ -173,7 +180,7 @@ predicate matchStarReadStep(Node nodeFrom, Content c, Node nodeTo) {
exists(MatchSequencePattern subject, int index, MatchStarPattern star |
star = subject.getPattern(index)
|
nodeFrom.asCfgNode().getNode() = subject and
nodeFrom.(CfgNode).getNode().getNode() = subject and
nodeTo = TStarPatternElementNode(star) and
(
// tuple content
@ -200,7 +207,7 @@ predicate matchStarReadStep(Node nodeFrom, Content c, Node nodeTo) {
predicate matchStarStoreStep(Node nodeFrom, Content c, Node nodeTo) {
exists(MatchStarPattern star |
nodeFrom = TStarPatternElementNode(star) and
nodeTo.asCfgNode().getNode() = star.getTarget() and
nodeTo.(CfgNode).getNode().getNode() = star.getTarget() and
c instanceof ListElementContent
)
}
@ -218,8 +225,8 @@ predicate matchMappingReadStep(Node nodeFrom, Content c, Node nodeTo) {
key = keyValue.getKey() and
value = keyValue.getValue()
|
nodeFrom.asCfgNode().getNode() = subject and
nodeTo.asCfgNode().getNode() = value and
nodeFrom.(CfgNode).getNode().getNode() = subject and
nodeTo.(CfgNode).getNode().getNode() = value and
c.(DictionaryElementContent).getKey() = key.getLiteral().(StrConst).getText()
)
}
@ -233,8 +240,8 @@ predicate matchMappingReadStep(Node nodeFrom, Content c, Node nodeTo) {
*/
predicate matchMappingFlowStep(Node nodeFrom, Node nodeTo) {
exists(MatchMappingPattern subject, MatchDoubleStarPattern dstar | dstar = subject.getAMapping() |
nodeFrom.asCfgNode().getNode() = subject and
nodeTo.asCfgNode().getNode() = dstar.getTarget()
nodeFrom.(CfgNode).getNode().getNode() = subject and
nodeTo.(CfgNode).getNode().getNode() = dstar.getTarget()
)
}
@ -251,7 +258,7 @@ predicate matchMappingClearStep(Node n, Content c) {
key = keyValue.getKey() and
dstar = subject.getAMapping()
|
n.asCfgNode().getNode() = dstar.getTarget() and
n.(CfgNode).getNode().getNode() = dstar.getTarget() and
c.(DictionaryElementContent).getKey() = key.getLiteral().(StrConst).getText()
)
}
@ -266,8 +273,8 @@ predicate matchClassReadStep(Node nodeFrom, Content c, Node nodeTo) {
attr = keyword.getAttribute() and
value = keyword.getValue()
|
nodeFrom.asCfgNode().getNode() = subject and
nodeTo.asCfgNode().getNode() = value and
nodeFrom.(CfgNode).getNode().getNode() = subject and
nodeTo.(CfgNode).getNode().getNode() = value and
c.(AttributeContent).getAttribute() = attr.getId()
)
}

Просмотреть файл

@ -11,7 +11,7 @@ class Node = DataFlowPublic::Node;
class TypeTrackingNode = DataFlowPublic::TypeTrackingNode;
predicate simpleLocalFlowStep = DataFlowPrivate::simpleLocalFlowStep/2;
predicate simpleLocalFlowStep = DataFlowPrivate::simpleLocalFlowStepForTypetracking/2;
predicate jumpStep = DataFlowPrivate::jumpStepSharedWithTypeTracker/2;
@ -35,16 +35,22 @@ string getPossibleContentName() {
*/
pragma[nomagic]
private DataFlowPrivate::DataFlowCallable getCallableForArgument(
DataFlowPublic::ArgumentNode nodeFrom, int i
DataFlowPublic::ExtractedArgumentNode nodeFrom, int i
) {
exists(DataFlowPrivate::DataFlowCall call |
nodeFrom.argumentOf(call, i) and
exists(DataFlowPrivate::ExtractedDataFlowCall call |
nodeFrom.extractedArgumentOf(call, i) and
result = call.getCallable()
)
}
/** Holds if `nodeFrom` steps to `nodeTo` by being passed as a parameter in a call. */
predicate callStep(DataFlowPublic::ArgumentNode nodeFrom, DataFlowPublic::ParameterNode nodeTo) {
/**
* Holds if `nodeFrom` steps to `nodeTo` by being passed as a parameter in a call.
*
* Flow into summarized library methods is not included, as that will lead to negative
* recursion (or, at best, terrible performance), since identifying calls to library
* methods is done using API graphs (which uses type tracking).
*/
predicate callStep(DataFlowPublic::ArgumentNode nodeFrom, DataFlowPrivate::ParameterNodeImpl nodeTo) {
// TODO: Support special methods?
exists(DataFlowPrivate::DataFlowCallable callable, int i |
callable = getCallableForArgument(nodeFrom, i) and
@ -54,8 +60,9 @@ predicate callStep(DataFlowPublic::ArgumentNode nodeFrom, DataFlowPublic::Parame
/** Holds if `nodeFrom` steps to `nodeTo` by being returned from a call. */
predicate returnStep(DataFlowPrivate::ReturnNode nodeFrom, Node nodeTo) {
exists(DataFlowPrivate::DataFlowCall call |
nodeFrom.getEnclosingCallable() = call.getCallable() and nodeTo.asCfgNode() = call.getNode()
exists(DataFlowPrivate::ExtractedDataFlowCall call |
nodeFrom.getEnclosingCallable() = call.getCallable() and
nodeTo.(DataFlowPublic::CfgNode).getNode() = call.getNode()
)
}

Просмотреть файл

@ -9,6 +9,7 @@ private import semmle.python.dataflow.new.TaintTracking
private import semmle.python.dataflow.new.RemoteFlowSources
private import semmle.python.Concepts
private import semmle.python.ApiGraphs
private import semmle.python.dataflow.new.FlowSummary
private import semmle.python.frameworks.PEP249
private import semmle.python.frameworks.internal.PoorMansFunctionResolution
private import semmle.python.frameworks.internal.SelfRefMixin
@ -3670,6 +3671,23 @@ private module StdlibPrivate {
override DataFlow::Node getAPathArgument() { result = this.getAnInput() }
}
/** A flow summary for `reversed`. */
class ReversedSummary extends SummarizedCallable {
ReversedSummary() { this = "builtins.reversed" }
override DataFlow::CallCfgNode getACall() { result = API::builtin("reversed").getACall() }
override DataFlow::ArgumentNode getACallback() {
result = API::builtin("reversed").getAValueReachableFromSource()
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
input = "Argument[0].ListElement" and
output = "ReturnValue.ListElement" and
preservesValue = true
}
}
}
// ---------------------------------------------------------------------------

Просмотреть файл

@ -26,14 +26,14 @@ import semmle.python.ApiGraphs::API as API
class Unit = PY::Unit;
// Re-export libraries needed by ApiGraphModels.qll
import semmle.python.frameworks.data.internal.AccessPathSyntax as AccessPathSyntax
import semmle.python.dataflow.new.internal.AccessPathSyntax as AccessPathSyntax
import semmle.python.dataflow.new.DataFlow::DataFlow as DataFlow
private import AccessPathSyntax
/**
* Holds if models describing `package` may be relevant for the analysis of this database.
*/
predicate isPackageUsed(string package) { exists(API::moduleImport(package)) }
predicate isPackageUsed(string package) { API::moduleImportExists(package) }
/** Gets a Python-specific interpretation of the `(package, type, path)` tuple after resolving the first `n` access path tokens. */
bindingset[package, type, path]

Просмотреть файл

@ -65,13 +65,17 @@ private class DefaultSafeExternalApi extends SafeExternalApi {
/** A node representing data being passed to an external API through a call. */
class ExternalApiDataNode extends DataFlow::Node {
DataFlowPrivate::DataFlowCall call;
DataFlowPrivate::DataFlowCallable callable;
int i;
ExternalApiDataNode() {
exists(call.getLocation().getFile().getRelativePath()) and
callable = call.getCallable() and
exists(DataFlowPrivate::DataFlowCall call |
exists(call.getLocation().getFile().getRelativePath())
|
callable = call.getCallable() and
// TODO: this ignores some complexity of keyword arguments (especially keyword-only args)
this = call.getArg(i)
) and
not any(SafeExternalApi safe).getSafeCallable() = callable and
exists(Value cv | cv = callable.getCallableValue() |
cv.isAbsent()
@ -82,8 +86,6 @@ class ExternalApiDataNode extends DataFlow::Node {
or
not exists(cv.(CallableValue).getScope().getLocation().getFile().getRelativePath())
) and
// TODO: this ignores some complexity of keyword arguments (especially keyword-only args)
this = call.getArg(i) and
// Not already modeled as a taint step
not exists(DataFlow::Node next | TaintTrackingPrivate::defaultAdditionalTaintStep(this, next)) and
// for `list.append(x)`, we have a additional taint step from x -> [post] list.

Просмотреть файл

@ -0,0 +1,33 @@
import python
import experimental.dataflow.TestUtil.FlowTest
import experimental.dataflow.testTaintConfig
private import semmle.python.dataflow.new.internal.PrintNode
class DataFlowTest extends FlowTest {
DataFlowTest() { this = "DataFlowTest" }
override string flowTag() { result = "flow" }
override predicate relevantFlow(DataFlow::Node source, DataFlow::Node sink) {
exists(TestConfiguration cfg | cfg.hasFlow(source, sink))
}
}
query predicate missingAnnotationOnSink(Location location, string error, string element) {
error = "ERROR, you should add `# $ MISSING: flow` annotation" and
exists(DataFlow::Node sink |
exists(DataFlow::CallCfgNode call |
// note: we only care about `SINK` and not `SINK_F`, so we have to reconstruct manually.
call.getFunction().asCfgNode().(NameNode).getId() = "SINK" and
(sink = call.getArg(_) or sink = call.getArgByName(_))
) and
location = sink.getLocation() and
element = prettyExpr(sink.asExpr()) and
not any(TestConfiguration config).hasFlow(_, sink) and
not exists(FalseNegativeExpectation missingResult |
missingResult.getTag() = "flow" and
missingResult.getLocation().getFile() = location.getFile() and
missingResult.getLocation().getStartLine() = location.getStartLine()
)
)
}

Просмотреть файл

@ -2,6 +2,7 @@ import python
import semmle.python.dataflow.new.DataFlow
import TestUtilities.InlineExpectationsTest
private import semmle.python.dataflow.new.internal.PrintNode
private import semmle.python.dataflow.new.internal.DataFlowPrivate as DataFlowPrivate
/**
* A routing test is designed to test that values are routed to the

Просмотреть файл

@ -12,7 +12,13 @@ class UnresolvedCallExpectations extends InlineExpectationsTest {
override predicate hasActualResult(Location location, string element, string tag, string value) {
exists(location.getFile().getRelativePath()) and
exists(CallNode call |
not exists(DataFlowPrivate::DataFlowCall dfc | dfc.getNode() = call) and
not exists(DataFlowPrivate::DataFlowCall dfc | dfc.getNode() = call |
// For every `CallNode`, there is a `DataFlowCall` in the form of a `NormalCall`.
// It does not really count, as it has some abstract overrides. For instance, it does not
// define `getCallable`, so checking for the existence of this guarantees that we are in a
// properly resolved call.
exists(dfc.getCallable())
) and
not call = API::builtin(_).getACall().asCfgNode() and
location = call.getLocation() and
tag = "unresolved_call" and

Просмотреть файл

@ -1,2 +1,3 @@
| file://:0:0:0:0 | parameter 0 of builtins.reversed |
| test.py:1:19:1:19 | ControlFlowNode for x |
| test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() |

Просмотреть файл

@ -1,2 +1,3 @@
| file://:0:0:0:0 | [summary] to write: return (return) in builtins.reversed |
| test.py:4:10:4:10 | ControlFlowNode for z |
| test.py:7:19:7:19 | ControlFlowNode for a |

Просмотреть файл

@ -1,3 +1,4 @@
| file://:0:0:0:0 | [summary] read: argument 0.List element in builtins.reversed | file://:0:0:0:0 | [summary] to write: return (return).List element in builtins.reversed |
| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:1:5:1:17 | GSSA Variable obfuscated_id |
| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id |
| test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id |

Просмотреть файл

@ -1,3 +1,4 @@
| file://:0:0:0:0 | [summary] read: argument 0.List element in builtins.reversed | file://:0:0:0:0 | [summary] to write: return (return).List element in builtins.reversed |
| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:1:5:1:17 | GSSA Variable obfuscated_id |
| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:1:5:1:17 | GSSA Variable obfuscated_id |
| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id |

Просмотреть файл

@ -1,3 +1,8 @@
| file://:0:0:0:0 | [summary] read: argument 0.List element in builtins.reversed | file://:0:0:0:0 | [summary] read: argument 0.List element in builtins.reversed |
| file://:0:0:0:0 | [summary] read: argument 0.List element in builtins.reversed | file://:0:0:0:0 | [summary] to write: return (return).List element in builtins.reversed |
| file://:0:0:0:0 | [summary] to write: return (return) in builtins.reversed | file://:0:0:0:0 | [summary] to write: return (return) in builtins.reversed |
| file://:0:0:0:0 | [summary] to write: return (return).List element in builtins.reversed | file://:0:0:0:0 | [summary] to write: return (return).List element in builtins.reversed |
| file://:0:0:0:0 | parameter 0 of builtins.reversed | file://:0:0:0:0 | parameter 0 of builtins.reversed |
| test.py:0:0:0:0 | GSSA Variable __name__ | test.py:0:0:0:0 | GSSA Variable __name__ |
| test.py:0:0:0:0 | GSSA Variable __package__ | test.py:0:0:0:0 | GSSA Variable __package__ |
| test.py:0:0:0:0 | GSSA Variable b | test.py:0:0:0:0 | GSSA Variable b |

Просмотреть файл

@ -1,3 +1,4 @@
| file://:0:0:0:0 | [summary] read: argument 0.List element in builtins.reversed | file://:0:0:0:0 | [summary] to write: return (return).List element in builtins.reversed |
| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:1:5:1:17 | GSSA Variable obfuscated_id |
| test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id |
| test.py:1:19:1:19 | ControlFlowNode for x | test.py:1:19:1:19 | SSA variable x |

Просмотреть файл

@ -1,3 +1,7 @@
| file://:0:0:0:0 | [summary] read: argument 0.List element in builtins.reversed |
| file://:0:0:0:0 | [summary] to write: return (return) in builtins.reversed |
| file://:0:0:0:0 | [summary] to write: return (return).List element in builtins.reversed |
| file://:0:0:0:0 | parameter 0 of builtins.reversed |
| test.py:0:0:0:0 | GSSA Variable __name__ |
| test.py:0:0:0:0 | GSSA Variable __package__ |
| test.py:0:0:0:0 | GSSA Variable b |

Просмотреть файл

@ -1,3 +1,7 @@
| file://:0:0:0:0 | [summary] read: argument 0.List element in builtins.reversed |
| file://:0:0:0:0 | [summary] to write: return (return) in builtins.reversed |
| file://:0:0:0:0 | [summary] to write: return (return).List element in builtins.reversed |
| file://:0:0:0:0 | parameter 0 of builtins.reversed |
| test.py:0:0:0:0 | GSSA Variable __name__ |
| test.py:0:0:0:0 | GSSA Variable __package__ |
| test.py:0:0:0:0 | GSSA Variable b |

Просмотреть файл

@ -31,7 +31,7 @@ try:
# `mypkg.foo` is a `missing module variable`, but `mypkg.subpkg.bar` is compeltely
# ignored.
import mypkg
mypkg.foo(42)
mypkg.subpkg.bar(43)
mypkg.foo(42) # $ call=mypkg.foo(..) qlclass=NormalCall
mypkg.subpkg.bar(43) # $ call=mypkg.subpkg.bar(..) qlclass=LibraryCall arg_0=43
except:
pass

Просмотреть файл

@ -1,8 +1,10 @@
| classes.py:14:17:14:60 | ControlFlowNode for Attribute() | classes.py:14:17:14:60 | ControlFlowNode for Attribute() |
| classes.py:45:16:45:35 | ControlFlowNode for Attribute() | classes.py:45:16:45:35 | ControlFlowNode for Attribute() |
| classes.py:60:17:60:27 | [pre objCreate] ControlFlowNode for With_init() | classes.py:54:18:54:21 | ControlFlowNode for self |
| classes.py:242:9:242:24 | ControlFlowNode for set() | classes.py:242:9:242:24 | ControlFlowNode for set() |
| classes.py:247:9:247:30 | ControlFlowNode for frozenset() | classes.py:247:9:247:30 | ControlFlowNode for frozenset() |
| classes.py:252:9:252:28 | ControlFlowNode for dict() | classes.py:252:9:252:28 | ControlFlowNode for dict() |
| classes.py:559:16:559:17 | ControlFlowNode for Str | classes.py:565:5:565:22 | ControlFlowNode for Subscript |
| classes.py:565:5:565:16 | ControlFlowNode for with_getitem | classes.py:555:21:555:24 | ControlFlowNode for self |
| classes.py:565:18:565:21 | ControlFlowNode for arg2 | classes.py:555:27:555:29 | ControlFlowNode for key |
| classes.py:581:5:581:16 | ControlFlowNode for with_setitem | classes.py:570:21:570:24 | ControlFlowNode for self |
@ -11,29 +13,68 @@
| classes.py:595:9:595:20 | ControlFlowNode for with_delitem | classes.py:586:21:586:24 | ControlFlowNode for self |
| classes.py:595:22:595:25 | ControlFlowNode for arg2 | classes.py:586:27:586:29 | ControlFlowNode for key |
| classes.py:618:16:618:28 | ControlFlowNode for Attribute() | classes.py:618:16:618:28 | ControlFlowNode for Attribute() |
| classes.py:659:15:659:18 | ControlFlowNode for self | classes.py:667:5:667:19 | ControlFlowNode for BinaryExpr |
| classes.py:661:16:661:19 | ControlFlowNode for self | classes.py:667:5:667:19 | ControlFlowNode for BinaryExpr |
| classes.py:667:5:667:12 | ControlFlowNode for with_add | classes.py:657:17:657:20 | ControlFlowNode for self |
| classes.py:667:5:667:12 | ControlFlowNode for with_add | classes.py:667:5:667:19 | ControlFlowNode for BinaryExpr |
| classes.py:667:16:667:19 | ControlFlowNode for arg2 | classes.py:657:23:657:27 | ControlFlowNode for other |
| classes.py:674:15:674:18 | ControlFlowNode for self | classes.py:682:5:682:19 | ControlFlowNode for BinaryExpr |
| classes.py:676:16:676:19 | ControlFlowNode for self | classes.py:682:5:682:19 | ControlFlowNode for BinaryExpr |
| classes.py:682:5:682:12 | ControlFlowNode for with_sub | classes.py:672:17:672:20 | ControlFlowNode for self |
| classes.py:682:5:682:12 | ControlFlowNode for with_sub | classes.py:682:5:682:19 | ControlFlowNode for BinaryExpr |
| classes.py:682:16:682:19 | ControlFlowNode for arg2 | classes.py:672:23:672:27 | ControlFlowNode for other |
| classes.py:689:15:689:18 | ControlFlowNode for self | classes.py:697:5:697:19 | ControlFlowNode for BinaryExpr |
| classes.py:691:16:691:19 | ControlFlowNode for self | classes.py:697:5:697:19 | ControlFlowNode for BinaryExpr |
| classes.py:697:5:697:12 | ControlFlowNode for with_mul | classes.py:687:17:687:20 | ControlFlowNode for self |
| classes.py:697:5:697:12 | ControlFlowNode for with_mul | classes.py:697:5:697:19 | ControlFlowNode for BinaryExpr |
| classes.py:697:16:697:19 | ControlFlowNode for arg2 | classes.py:687:23:687:27 | ControlFlowNode for other |
| classes.py:704:15:704:18 | ControlFlowNode for self | classes.py:712:5:712:22 | ControlFlowNode for BinaryExpr |
| classes.py:706:16:706:19 | ControlFlowNode for self | classes.py:712:5:712:22 | ControlFlowNode for BinaryExpr |
| classes.py:712:5:712:15 | ControlFlowNode for with_matmul | classes.py:702:20:702:23 | ControlFlowNode for self |
| classes.py:712:5:712:15 | ControlFlowNode for with_matmul | classes.py:712:5:712:22 | ControlFlowNode for BinaryExpr |
| classes.py:712:19:712:22 | ControlFlowNode for arg2 | classes.py:702:26:702:30 | ControlFlowNode for other |
| classes.py:719:15:719:18 | ControlFlowNode for self | classes.py:727:5:727:23 | ControlFlowNode for BinaryExpr |
| classes.py:721:16:721:19 | ControlFlowNode for self | classes.py:727:5:727:23 | ControlFlowNode for BinaryExpr |
| classes.py:727:5:727:16 | ControlFlowNode for with_truediv | classes.py:717:21:717:24 | ControlFlowNode for self |
| classes.py:727:5:727:16 | ControlFlowNode for with_truediv | classes.py:727:5:727:23 | ControlFlowNode for BinaryExpr |
| classes.py:727:20:727:23 | ControlFlowNode for arg2 | classes.py:717:27:717:31 | ControlFlowNode for other |
| classes.py:734:15:734:18 | ControlFlowNode for self | classes.py:742:5:742:25 | ControlFlowNode for BinaryExpr |
| classes.py:736:16:736:19 | ControlFlowNode for self | classes.py:742:5:742:25 | ControlFlowNode for BinaryExpr |
| classes.py:742:5:742:17 | ControlFlowNode for with_floordiv | classes.py:732:22:732:25 | ControlFlowNode for self |
| classes.py:742:5:742:17 | ControlFlowNode for with_floordiv | classes.py:742:5:742:25 | ControlFlowNode for BinaryExpr |
| classes.py:742:22:742:25 | ControlFlowNode for arg2 | classes.py:732:28:732:32 | ControlFlowNode for other |
| classes.py:749:15:749:18 | ControlFlowNode for self | classes.py:757:5:757:19 | ControlFlowNode for BinaryExpr |
| classes.py:751:16:751:19 | ControlFlowNode for self | classes.py:757:5:757:19 | ControlFlowNode for BinaryExpr |
| classes.py:757:5:757:12 | ControlFlowNode for with_mod | classes.py:747:17:747:20 | ControlFlowNode for self |
| classes.py:757:5:757:12 | ControlFlowNode for with_mod | classes.py:757:5:757:19 | ControlFlowNode for BinaryExpr |
| classes.py:757:16:757:19 | ControlFlowNode for arg2 | classes.py:747:23:747:27 | ControlFlowNode for other |
| classes.py:779:15:779:18 | ControlFlowNode for self | classes.py:793:5:793:20 | ControlFlowNode for BinaryExpr |
| classes.py:781:16:781:19 | ControlFlowNode for self | classes.py:793:5:793:20 | ControlFlowNode for BinaryExpr |
| classes.py:793:5:793:12 | ControlFlowNode for with_pow | classes.py:777:17:777:20 | ControlFlowNode for self |
| classes.py:793:5:793:12 | ControlFlowNode for with_pow | classes.py:793:5:793:20 | ControlFlowNode for BinaryExpr |
| classes.py:793:17:793:20 | ControlFlowNode for arg2 | classes.py:777:23:777:27 | ControlFlowNode for other |
| classes.py:800:15:800:18 | ControlFlowNode for self | classes.py:808:5:808:23 | ControlFlowNode for BinaryExpr |
| classes.py:802:16:802:19 | ControlFlowNode for self | classes.py:808:5:808:23 | ControlFlowNode for BinaryExpr |
| classes.py:808:5:808:15 | ControlFlowNode for with_lshift | classes.py:798:20:798:23 | ControlFlowNode for self |
| classes.py:808:5:808:15 | ControlFlowNode for with_lshift | classes.py:808:5:808:23 | ControlFlowNode for BinaryExpr |
| classes.py:808:20:808:23 | ControlFlowNode for arg2 | classes.py:798:26:798:30 | ControlFlowNode for other |
| classes.py:815:15:815:18 | ControlFlowNode for self | classes.py:823:5:823:23 | ControlFlowNode for BinaryExpr |
| classes.py:817:16:817:19 | ControlFlowNode for self | classes.py:823:5:823:23 | ControlFlowNode for BinaryExpr |
| classes.py:823:5:823:15 | ControlFlowNode for with_rshift | classes.py:813:20:813:23 | ControlFlowNode for self |
| classes.py:823:5:823:15 | ControlFlowNode for with_rshift | classes.py:823:5:823:23 | ControlFlowNode for BinaryExpr |
| classes.py:823:20:823:23 | ControlFlowNode for arg2 | classes.py:813:26:813:30 | ControlFlowNode for other |
| classes.py:830:15:830:18 | ControlFlowNode for self | classes.py:838:5:838:19 | ControlFlowNode for BinaryExpr |
| classes.py:832:16:832:19 | ControlFlowNode for self | classes.py:838:5:838:19 | ControlFlowNode for BinaryExpr |
| classes.py:838:5:838:12 | ControlFlowNode for with_and | classes.py:828:17:828:20 | ControlFlowNode for self |
| classes.py:838:5:838:12 | ControlFlowNode for with_and | classes.py:838:5:838:19 | ControlFlowNode for BinaryExpr |
| classes.py:838:16:838:19 | ControlFlowNode for arg2 | classes.py:828:23:828:27 | ControlFlowNode for other |
| classes.py:845:15:845:18 | ControlFlowNode for self | classes.py:853:5:853:19 | ControlFlowNode for BinaryExpr |
| classes.py:847:16:847:19 | ControlFlowNode for self | classes.py:853:5:853:19 | ControlFlowNode for BinaryExpr |
| classes.py:853:5:853:12 | ControlFlowNode for with_xor | classes.py:843:17:843:20 | ControlFlowNode for self |
| classes.py:853:5:853:12 | ControlFlowNode for with_xor | classes.py:853:5:853:19 | ControlFlowNode for BinaryExpr |
| classes.py:853:16:853:19 | ControlFlowNode for arg2 | classes.py:843:23:843:27 | ControlFlowNode for other |
| classes.py:860:15:860:18 | ControlFlowNode for self | classes.py:868:5:868:18 | ControlFlowNode for BinaryExpr |
| classes.py:862:16:862:19 | ControlFlowNode for self | classes.py:868:5:868:18 | ControlFlowNode for BinaryExpr |
| classes.py:868:5:868:11 | ControlFlowNode for with_or | classes.py:858:16:858:19 | ControlFlowNode for self |
| classes.py:868:5:868:11 | ControlFlowNode for with_or | classes.py:868:5:868:18 | ControlFlowNode for BinaryExpr |
| classes.py:868:15:868:18 | ControlFlowNode for arg2 | classes.py:858:22:858:26 | ControlFlowNode for other |

Просмотреть файл

@ -20,7 +20,7 @@ class CallGraphConfig extends DataFlow::Configuration {
node instanceof DataFlow::ParameterNode and
// exclude parameters to the SINK-functions
not exists(DataFlowPrivate::DataFlowCallable c |
node.(DataFlow::ParameterNode).isParameterOf(c, _) and
c.getParameter(_) = node.asCfgNode() and
c.getName().matches("SINK_")
)
}

Просмотреть файл

@ -0,0 +1,2 @@
missingAnnotationOnSink
failures

Просмотреть файл

@ -0,0 +1,3 @@
import python
private import TestSummaries
import experimental.dataflow.TestUtil.NormalTaintTrackingTest

Просмотреть файл

@ -0,0 +1,134 @@
private import python
private import semmle.python.dataflow.new.FlowSummary
private import semmle.python.ApiGraphs
/**
* This module ensures that the `callStep` predicate in
* our type tracker implelemtation does not refer to the
* `getACall` predicate on `SummarizedCallable`.
*/
module RecursionGuard {
private import semmle.python.dataflow.new.internal.TypeTrackerSpecific as TT
private class RecursionGuard extends SummarizedCallable {
RecursionGuard() { this = "RecursionGuard" }
override DataFlow::CallCfgNode getACall() {
result.getFunction().asCfgNode().(NameNode).getId() = this and
(TT::callStep(_, _) implies any())
}
override DataFlow::ArgumentNode getACallback() { result.asExpr().(Name).getId() = this }
}
}
private class SummarizedCallableIdentity extends SummarizedCallable {
SummarizedCallableIdentity() { this = "identity" }
override DataFlow::CallCfgNode getACall() {
result.getFunction().asCfgNode().(NameNode).getId() = this
}
override DataFlow::ArgumentNode getACallback() { result.asExpr().(Name).getId() = this }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
input = "Argument[0]" and
output = "ReturnValue" and
preservesValue = true
}
}
// For lambda flow to work, implement lambdaCall and lambdaCreation
private class SummarizedCallableApplyLambda extends SummarizedCallable {
SummarizedCallableApplyLambda() { this = "apply_lambda" }
override DataFlow::CallCfgNode getACall() {
result.getFunction().asCfgNode().(NameNode).getId() = this
}
override DataFlow::ArgumentNode getACallback() { result.asExpr().(Name).getId() = this }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
input = "Argument[1]" and
output = "Argument[0].Parameter[0]" and
preservesValue = true
or
input = "Argument[0].ReturnValue" and
output = "ReturnValue" and
preservesValue = true
}
}
private class SummarizedCallableReversed extends SummarizedCallable {
SummarizedCallableReversed() { this = "reversed" }
override DataFlow::CallCfgNode getACall() {
result.getFunction().asCfgNode().(NameNode).getId() = this
}
override DataFlow::ArgumentNode getACallback() { result.asExpr().(Name).getId() = this }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
input = "Argument[0].ListElement" and
output = "ReturnValue.ListElement" and
preservesValue = true
}
}
private class SummarizedCallableMap extends SummarizedCallable {
SummarizedCallableMap() { this = "list_map" }
override DataFlow::CallCfgNode getACall() {
result.getFunction().asCfgNode().(NameNode).getId() = this
}
override DataFlow::ArgumentNode getACallback() { result.asExpr().(Name).getId() = this }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
input = "Argument[1].ListElement" and
output = "Argument[0].Parameter[0]" and
preservesValue = true
or
input = "Argument[0].ReturnValue" and
output = "ReturnValue.ListElement" and
preservesValue = true
}
}
private class SummarizedCallableAppend extends SummarizedCallable {
SummarizedCallableAppend() { this = "append_to_list" }
override DataFlow::CallCfgNode getACall() {
result.getFunction().asCfgNode().(NameNode).getId() = this
}
override DataFlow::ArgumentNode getACallback() { result.asExpr().(Name).getId() = this }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
input = "Argument[0]" and
output = "ReturnValue" and
preservesValue = false
or
input = "Argument[1]" and
output = "ReturnValue.ListElement" and
preservesValue = true
}
}
private class SummarizedCallableJsonLoads extends SummarizedCallable {
SummarizedCallableJsonLoads() { this = "json.loads" }
override DataFlow::CallCfgNode getACall() {
result = API::moduleImport("json").getMember("loads").getACall()
}
override DataFlow::ArgumentNode getACallback() {
result = API::moduleImport("json").getMember("loads").getAValueReachableFromSource()
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
input = "Argument[0]" and
output = "ReturnValue.ListElement" and
preservesValue = true
}
}

Просмотреть файл

@ -0,0 +1,70 @@
edges
| summaries.py:32:11:32:26 | ControlFlowNode for identity() | summaries.py:33:6:33:12 | ControlFlowNode for tainted |
| summaries.py:32:20:32:25 | ControlFlowNode for SOURCE | summaries.py:32:11:32:26 | ControlFlowNode for identity() |
| summaries.py:36:18:36:54 | ControlFlowNode for apply_lambda() | summaries.py:37:6:37:19 | ControlFlowNode for tainted_lambda |
| summaries.py:36:48:36:53 | ControlFlowNode for SOURCE | summaries.py:36:18:36:54 | ControlFlowNode for apply_lambda() |
| summaries.py:44:25:44:32 | ControlFlowNode for List | summaries.py:45:6:45:20 | ControlFlowNode for Subscript |
| summaries.py:44:26:44:31 | ControlFlowNode for SOURCE | summaries.py:44:25:44:32 | ControlFlowNode for List |
| summaries.py:51:18:51:46 | ControlFlowNode for list_map() [List element] | summaries.py:52:6:52:19 | ControlFlowNode for tainted_mapped [List element] |
| summaries.py:51:38:51:45 | ControlFlowNode for List [List element] | summaries.py:51:18:51:46 | ControlFlowNode for list_map() [List element] |
| summaries.py:51:39:51:44 | ControlFlowNode for SOURCE | summaries.py:51:38:51:45 | ControlFlowNode for List [List element] |
| summaries.py:52:6:52:19 | ControlFlowNode for tainted_mapped [List element] | summaries.py:52:6:52:22 | ControlFlowNode for Subscript |
| summaries.py:57:27:57:63 | ControlFlowNode for list_map() [List element] | summaries.py:58:6:58:28 | ControlFlowNode for tainted_mapped_explicit [List element] |
| summaries.py:57:55:57:62 | ControlFlowNode for List [List element] | summaries.py:57:27:57:63 | ControlFlowNode for list_map() [List element] |
| summaries.py:57:56:57:61 | ControlFlowNode for SOURCE | summaries.py:57:55:57:62 | ControlFlowNode for List [List element] |
| summaries.py:58:6:58:28 | ControlFlowNode for tainted_mapped_explicit [List element] | summaries.py:58:6:58:31 | ControlFlowNode for Subscript |
| summaries.py:60:26:60:53 | ControlFlowNode for list_map() [List element] | summaries.py:61:6:61:27 | ControlFlowNode for tainted_mapped_summary [List element] |
| summaries.py:60:45:60:52 | ControlFlowNode for List [List element] | summaries.py:60:26:60:53 | ControlFlowNode for list_map() [List element] |
| summaries.py:60:46:60:51 | ControlFlowNode for SOURCE | summaries.py:60:45:60:52 | ControlFlowNode for List [List element] |
| summaries.py:61:6:61:27 | ControlFlowNode for tainted_mapped_summary [List element] | summaries.py:61:6:61:30 | ControlFlowNode for Subscript |
| summaries.py:63:16:63:41 | ControlFlowNode for append_to_list() [List element] | summaries.py:64:6:64:17 | ControlFlowNode for tainted_list [List element] |
| summaries.py:63:35:63:40 | ControlFlowNode for SOURCE | summaries.py:63:16:63:41 | ControlFlowNode for append_to_list() [List element] |
| summaries.py:64:6:64:17 | ControlFlowNode for tainted_list [List element] | summaries.py:64:6:64:20 | ControlFlowNode for Subscript |
| summaries.py:67:22:67:39 | ControlFlowNode for json_loads() [List element] | summaries.py:68:6:68:23 | ControlFlowNode for tainted_resultlist [List element] |
| summaries.py:67:33:67:38 | ControlFlowNode for SOURCE | summaries.py:67:22:67:39 | ControlFlowNode for json_loads() [List element] |
| summaries.py:67:33:67:38 | ControlFlowNode for SOURCE | summaries.py:68:6:68:26 | ControlFlowNode for Subscript |
| summaries.py:68:6:68:23 | ControlFlowNode for tainted_resultlist [List element] | summaries.py:68:6:68:26 | ControlFlowNode for Subscript |
nodes
| summaries.py:32:11:32:26 | ControlFlowNode for identity() | semmle.label | ControlFlowNode for identity() |
| summaries.py:32:20:32:25 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| summaries.py:33:6:33:12 | ControlFlowNode for tainted | semmle.label | ControlFlowNode for tainted |
| summaries.py:36:18:36:54 | ControlFlowNode for apply_lambda() | semmle.label | ControlFlowNode for apply_lambda() |
| summaries.py:36:48:36:53 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| summaries.py:37:6:37:19 | ControlFlowNode for tainted_lambda | semmle.label | ControlFlowNode for tainted_lambda |
| summaries.py:44:25:44:32 | ControlFlowNode for List | semmle.label | ControlFlowNode for List |
| summaries.py:44:26:44:31 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| summaries.py:45:6:45:20 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| summaries.py:51:18:51:46 | ControlFlowNode for list_map() [List element] | semmle.label | ControlFlowNode for list_map() [List element] |
| summaries.py:51:38:51:45 | ControlFlowNode for List [List element] | semmle.label | ControlFlowNode for List [List element] |
| summaries.py:51:39:51:44 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| summaries.py:52:6:52:19 | ControlFlowNode for tainted_mapped [List element] | semmle.label | ControlFlowNode for tainted_mapped [List element] |
| summaries.py:52:6:52:22 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| summaries.py:57:27:57:63 | ControlFlowNode for list_map() [List element] | semmle.label | ControlFlowNode for list_map() [List element] |
| summaries.py:57:55:57:62 | ControlFlowNode for List [List element] | semmle.label | ControlFlowNode for List [List element] |
| summaries.py:57:56:57:61 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| summaries.py:58:6:58:28 | ControlFlowNode for tainted_mapped_explicit [List element] | semmle.label | ControlFlowNode for tainted_mapped_explicit [List element] |
| summaries.py:58:6:58:31 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| summaries.py:60:26:60:53 | ControlFlowNode for list_map() [List element] | semmle.label | ControlFlowNode for list_map() [List element] |
| summaries.py:60:45:60:52 | ControlFlowNode for List [List element] | semmle.label | ControlFlowNode for List [List element] |
| summaries.py:60:46:60:51 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| summaries.py:61:6:61:27 | ControlFlowNode for tainted_mapped_summary [List element] | semmle.label | ControlFlowNode for tainted_mapped_summary [List element] |
| summaries.py:61:6:61:30 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| summaries.py:63:16:63:41 | ControlFlowNode for append_to_list() [List element] | semmle.label | ControlFlowNode for append_to_list() [List element] |
| summaries.py:63:35:63:40 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| summaries.py:64:6:64:17 | ControlFlowNode for tainted_list [List element] | semmle.label | ControlFlowNode for tainted_list [List element] |
| summaries.py:64:6:64:20 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| summaries.py:67:22:67:39 | ControlFlowNode for json_loads() [List element] | semmle.label | ControlFlowNode for json_loads() [List element] |
| summaries.py:67:33:67:38 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| summaries.py:68:6:68:23 | ControlFlowNode for tainted_resultlist [List element] | semmle.label | ControlFlowNode for tainted_resultlist [List element] |
| summaries.py:68:6:68:26 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
subpaths
invalidSpecComponent
#select
| summaries.py:33:6:33:12 | ControlFlowNode for tainted | summaries.py:32:20:32:25 | ControlFlowNode for SOURCE | summaries.py:33:6:33:12 | ControlFlowNode for tainted | $@ | summaries.py:32:20:32:25 | ControlFlowNode for SOURCE | ControlFlowNode for SOURCE |
| summaries.py:37:6:37:19 | ControlFlowNode for tainted_lambda | summaries.py:36:48:36:53 | ControlFlowNode for SOURCE | summaries.py:37:6:37:19 | ControlFlowNode for tainted_lambda | $@ | summaries.py:36:48:36:53 | ControlFlowNode for SOURCE | ControlFlowNode for SOURCE |
| summaries.py:45:6:45:20 | ControlFlowNode for Subscript | summaries.py:44:26:44:31 | ControlFlowNode for SOURCE | summaries.py:45:6:45:20 | ControlFlowNode for Subscript | $@ | summaries.py:44:26:44:31 | ControlFlowNode for SOURCE | ControlFlowNode for SOURCE |
| summaries.py:52:6:52:22 | ControlFlowNode for Subscript | summaries.py:51:39:51:44 | ControlFlowNode for SOURCE | summaries.py:52:6:52:22 | ControlFlowNode for Subscript | $@ | summaries.py:51:39:51:44 | ControlFlowNode for SOURCE | ControlFlowNode for SOURCE |
| summaries.py:58:6:58:31 | ControlFlowNode for Subscript | summaries.py:57:56:57:61 | ControlFlowNode for SOURCE | summaries.py:58:6:58:31 | ControlFlowNode for Subscript | $@ | summaries.py:57:56:57:61 | ControlFlowNode for SOURCE | ControlFlowNode for SOURCE |
| summaries.py:61:6:61:30 | ControlFlowNode for Subscript | summaries.py:60:46:60:51 | ControlFlowNode for SOURCE | summaries.py:61:6:61:30 | ControlFlowNode for Subscript | $@ | summaries.py:60:46:60:51 | ControlFlowNode for SOURCE | ControlFlowNode for SOURCE |
| summaries.py:64:6:64:20 | ControlFlowNode for Subscript | summaries.py:63:35:63:40 | ControlFlowNode for SOURCE | summaries.py:64:6:64:20 | ControlFlowNode for Subscript | $@ | summaries.py:63:35:63:40 | ControlFlowNode for SOURCE | ControlFlowNode for SOURCE |
| summaries.py:68:6:68:26 | ControlFlowNode for Subscript | summaries.py:67:33:67:38 | ControlFlowNode for SOURCE | summaries.py:68:6:68:26 | ControlFlowNode for Subscript | $@ | summaries.py:67:33:67:38 | ControlFlowNode for SOURCE | ControlFlowNode for SOURCE |

Просмотреть файл

@ -0,0 +1,68 @@
import sys
import os
sys.path.append(os.path.dirname(os.path.dirname((__file__))))
from testlib import expects
# These are defined so that we can evaluate the test code.
NONSOURCE = "not a source"
SOURCE = "source"
def is_source(x):
return x == "source" or x == b"source" or x == 42 or x == 42.0 or x == 42j
def SINK(x):
if is_source(x):
print("OK")
else:
print("Unexpected flow", x)
def SINK_F(x):
if is_source(x):
print("Unexpected flow", x)
else:
print("OK")
# Simple summary
tainted = identity(SOURCE)
SINK(tainted) # $ flow="SOURCE, l:-1 -> tainted"
# Lambda summary
tainted_lambda = apply_lambda(lambda x: x + 1, SOURCE)
SINK(tainted_lambda) # $ flow="SOURCE, l:-1 -> tainted_lambda"
# A lambda that breaks the flow
untainted_lambda = apply_lambda(lambda x: 1, SOURCE)
SINK_F(untainted_lambda)
# Collection summaries
tainted_list = reversed([SOURCE])
SINK(tainted_list[0]) # $ flow="SOURCE, l:-1 -> tainted_list[0]"
# Complex summaries
def add_colon(x):
return x + ":"
tainted_mapped = list_map(add_colon, [SOURCE])
SINK(tainted_mapped[0]) # $ flow="SOURCE, l:-1 -> tainted_mapped[0]"
def explicit_identity(x):
return x
tainted_mapped_explicit = list_map(explicit_identity, [SOURCE])
SINK(tainted_mapped_explicit[0]) # $ flow="SOURCE, l:-1 -> tainted_mapped_explicit[0]"
tainted_mapped_summary = list_map(identity, [SOURCE])
SINK(tainted_mapped_summary[0]) # $ flow="SOURCE, l:-1 -> tainted_mapped_summary[0]"
tainted_list = append_to_list([], SOURCE)
SINK(tainted_list[0]) # $ flow="SOURCE, l:-1 -> tainted_list[0]"
from json import loads as json_loads
tainted_resultlist = json_loads(SOURCE)
SINK(tainted_resultlist[0]) # $ flow="SOURCE, l:-1 -> tainted_resultlist[0]"

Просмотреть файл

@ -0,0 +1,21 @@
/**
* @kind path-problem
*/
import python
import semmle.python.dataflow.new.FlowSummary
import DataFlow::PathGraph
import semmle.python.dataflow.new.TaintTracking
import semmle.python.dataflow.new.internal.FlowSummaryImpl
import semmle.python.ApiGraphs
import experimental.dataflow.testTaintConfig
private import TestSummaries
query predicate invalidSpecComponent(SummarizedCallable sc, string s, string c) {
(sc.propagatesFlowExt(s, _, _) or sc.propagatesFlowExt(_, s, _)) and
Private::External::invalidSpecComponent(s, c)
}
from DataFlow::PathNode source, DataFlow::PathNode sink, TestConfiguration conf
where conf.hasFlowPath(source, sink)
select sink, source, sink, "$@", source, source.toString()

Просмотреть файл

@ -0,0 +1,51 @@
/**
* Configuration to test selected data flow
* Sources in the source code are denoted by the special name `SOURCE`,
* and sinks are denoted by arguments to the special function `SINK`.
* For example, given the test code
* ```python
* def test():
* s = SOURCE
* SINK(s)
* ```
* `SOURCE` will be a source and the second occurrence of `s` will be a sink.
*
* In order to test literals, alternative sources are defined for each type:
*
* for | use
* ----------
* string | `"source"`
* integer | `42`
* float | `42.0`
* complex | `42j` (not supported yet)
*/
private import python
import semmle.python.dataflow.new.DataFlow
import semmle.python.dataflow.new.TaintTracking
class TestConfiguration extends TaintTracking::Configuration {
TestConfiguration() { this = "TestConfiguration" }
override predicate isSource(DataFlow::Node node) {
node.(DataFlow::CfgNode).getNode().(NameNode).getId() = "SOURCE"
or
node.(DataFlow::CfgNode).getNode().getNode().(StrConst).getS() = "source"
or
node.(DataFlow::CfgNode).getNode().getNode().(IntegerLiteral).getN() = "42"
or
node.(DataFlow::CfgNode).getNode().getNode().(FloatLiteral).getN() = "42.0"
// No support for complex numbers
}
override predicate isSink(DataFlow::Node node) {
exists(CallNode call |
call.getFunction().(NameNode).getId() in ["SINK", "SINK_F"] and
node.(DataFlow::CfgNode).getNode() = call.getAnArg()
)
}
override predicate isSanitizerIn(DataFlow::Node node) { this.isSource(node) }
override int explorationLimit() { result = 5 }
}

Просмотреть файл

@ -1,5 +1,5 @@
import python
import semmle.python.frameworks.data.internal.AccessPathSyntax as AccessPathSyntax
import semmle.python.dataflow.new.internal.AccessPathSyntax as AccessPathSyntax
import semmle.python.frameworks.data.ModelsAsData
import semmle.python.dataflow.new.TaintTracking
import semmle.python.dataflow.new.DataFlow

Просмотреть файл

@ -1,5 +1,5 @@
import python
import semmle.python.frameworks.data.internal.AccessPathSyntax as AccessPathSyntax
import semmle.python.dataflow.new.internal.AccessPathSyntax as AccessPathSyntax
import semmle.python.frameworks.data.internal.ApiGraphModels as ApiGraphModels
import semmle.python.frameworks.data.ModelsAsData

Просмотреть файл

@ -0,0 +1,198 @@
/**
* @name Alert message style violation
* @description An alert message that doesn't follow the style guide is harder for end users to digest.
* See the style guide here: https://github.com/github/codeql/blob/main/docs/query-metadata-style-guide.md#alert-messages
* @kind problem
* @problem.severity warning
* @id ql/alert-message-style-violation
* @precision high
*/
import ql
/** Gets the `index`th part of the select statement. */
private AstNode getSelectPart(Select sel, int index) {
result =
rank[index](AstNode n, Location loc |
(
n.getParent*() = sel.getExpr(_) and loc = n.getLocation()
or
// the strings are behind a predicate call.
exists(Call c, Predicate target |
c.getParent*() = sel.getExpr(_) and loc = c.getLocation()
|
c.getTarget() = target and
(
target.getBody().(ComparisonFormula).getAnOperand() = n
or
exists(ClassPredicate sub | sub.overrides(target) |
sub.getBody().(ComparisonFormula).getAnOperand() = n
)
)
)
)
|
n
order by
loc.getStartLine(), loc.getStartColumn(), loc.getEndLine(), loc.getEndColumn(),
loc.getFile().getRelativePath()
)
}
/**
* Gets a string element that is the last part of the message, that doesn't end with a period.
*
* For example:
* ```CodeQL
* select foo(), "This is a description" // <- bad
*
* select foo(), "This is a description." // <- good
* ```
*/
String shouldHaveFullStop(Select sel) {
result =
max(AstNode str, int i |
str.getParent+() = sel.getExpr(1) and str = getSelectPart(sel, i)
|
str order by i
) and
not result.getValue().matches("%.") and
not result.getValue().matches("%?")
}
/**
* Gets a string element that is the first part of the message, that starts with a lower case letter.
*
* For example:
* ```CodeQL
* select foo(), "this is a description." // <- bad
*
* select foo(), "This is a description." // <- good
* ```
*/
String shouldStartCapital(Select sel) {
result =
min(AstNode str, int i |
str.getParent+() = sel.getExpr(1) and str = getSelectPart(sel, i)
|
str order by i
) and
result.getValue().regexpMatch("^[a-z].*")
}
/**
* Gets a string element that is used in a message that contains "here" or "this location".
*
* For example:
* ```CodeQL
* select foo(), "XSS happens here from using a unsafe value." // <- bad
*
* select foo(), "XSS from using a unsafe value." // <- good
* ```
*/
String avoidHere(string part) {
part = ["here", "this location"] and
(
result.getValue().regexpMatch(".*\\b" + part + "\\b.*") and
result = getSelectPart(_, _)
)
}
/**
* Avoid using an indefinite article ("a" or "an") in a link text.
*
* For example:
* ```CodeQL
* select foo(), "XSS from $@", val, "an unsafe value." // <- bad
*
* select foo(), "XSS from a $@", val, "unsafe value." // <- good
* ```
*
* See https://www.w3.org/WAI/WCAG22/Understanding/link-purpose-in-context.html for the W3C guideline on link text. a
*/
String avoidArticleInLinkText(Select sel) {
result = sel.getExpr((any(int i | i > 1))) and
result = getSelectPart(sel, _) and
result.getValue().regexpMatch("a|an .*")
}
/**
* Don't quote substitutions in a message.
*
* For example:
* ```CodeQL
* select foo(), "XSS from '$@'", val, "an unsafe value." // <- bad
*
* select foo(), "XSS from $@", val, "an unsafe value." // <- good
* ```
*/
String dontQuoteSubstitutions(Select sel) {
result = getSelectPart(sel, _) and
result.getValue().matches(["%'$@'%", "%\"$@\"%"])
}
/**
* Gets the kind of the path-query represented by `sel`.
* Either "data" for a dataflow query or "taint" for a taint-tracking query.
*/
private string getQueryKind(Select sel) {
exists(TypeExpr sup |
sup = sel.getVarDecl(_).getType().(ClassType).getDeclaration().getASuperType() and
sup.getResolvedType().(ClassType).getName() = "Configuration"
|
result = "data" and
sup.getModule().getName() = "DataFlow"
or
result = "taint" and
sup.getModule().getName() = "TaintTracking"
)
}
/**
* Gets a string element from a message that uses the wrong phrase for a path query.
* A dataflow query should use "flows to" and a taint-tracking query should use "depends on".
*/
String wrongFlowsPhrase(Select sel, string kind) {
result = getSelectPart(sel, _) and
kind = getQueryKind(sel) and
(
kind = "data" and
result.getValue().matches(["% depends %", "% depend %"])
or
kind = "taint" and
result.getValue().matches(["% flows to %", "% flow to %"])
)
}
from AstNode node, string msg
where
not node.getLocation().getFile().getAbsolutePath().matches("%/test/%") and
(
node = shouldHaveFullStop(_) and
msg = "Alert message should end with a full stop."
or
node = shouldStartCapital(_) and
msg = "Alert message should start with a capital letter."
or
exists(string part | node = avoidHere(part) |
part = "here" and
msg =
"Try to use a descriptive phrase instead of \"here\". Use \"this location\" if you can't get around mentioning the current location."
or
part = "this location" and
msg = "Try to more descriptive phrase instead of \"this location\" if possible."
)
or
node = avoidArticleInLinkText(_) and
msg = "Avoid starting a link text with an indefinite article."
or
node = dontQuoteSubstitutions(_) and
msg = "Don't quote substitutions in alert messages."
or
node = wrongFlowsPhrase(_, "data") and
msg = "Use \"flows to\" instead of \"depends on\" in data flow queries."
or
node = wrongFlowsPhrase(_, "taint") and
msg = "Use \"depends on\" instead of \"flows to\" in taint tracking queries."
)
select node, msg

Просмотреть файл

@ -63,14 +63,6 @@ module RegExpFlags {
root.getLiteral().isIgnoreCase()
}
/**
* Gets the flags for `root`, or the empty string if `root` has no flags.
*/
string getFlags(RegExpTerm root) {
root.isRootTerm() and
result = root.getLiteral().getFlags()
}
/**
* Holds if `root` has the `s` flag for multi-line matching.
*/

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше