+
+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.
+
+
+
+
+Ensure that pointer dereferences are properly guarded to ensure that they cannot be used to read or write past the end of the allocation.
+
+
+
+The first example allocates a buffer of size size
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 end
variable before dereferencing it. This subtraction ensures that the write correctly updates the final byte of the allocation.
+
+
+
+
+
+CERT C Coding Standard:
+ARR30-C. Do not form or use out-of-bounds pointers or array subscripts.
+
+OWASP:
+Buffer Overflow.
+
+
+
+
diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql b/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql
new file mode 100644
index 00000000000..05327263386
--- /dev/null
+++ b/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql
@@ -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()
diff --git a/cpp/ql/test/experimental/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.expected b/cpp/ql/test/experimental/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.expected
index ea8c8f8f577..106313c8707 100644
--- a/cpp/ql/test/experimental/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.expected
+++ b/cpp/ql/test/experimental/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.expected
@@ -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 |
diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-119/OverrunWriteProductFlow.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-119/OverrunWriteProductFlow.expected
index 56ae4e59a9a..dedb1d72a38 100644
--- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-119/OverrunWriteProductFlow.expected
+++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-119/OverrunWriteProductFlow.expected
@@ -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 |
diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/array-access/ArrayAccessProductFlow.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/array-access/ArrayAccessProductFlow.expected
index 2564193fb2e..8b82181b9f7 100644
--- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/array-access/ArrayAccessProductFlow.expected
+++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/array-access/ArrayAccessProductFlow.expected
@@ -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 |
diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/array-access/test.cpp b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/array-access/test.cpp
index b3c4341f9b8..f35379db3e4 100644
--- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/array-access/test.cpp
+++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/array-access/test.cpp
@@ -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
}
}
diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.expected
new file mode 100644
index 00000000000..494713b124b
--- /dev/null
+++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.expected
@@ -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 |
diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.qlref b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.qlref
new file mode 100644
index 00000000000..76da29dc7a0
--- /dev/null
+++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.qlref
@@ -0,0 +1 @@
+experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql
diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/test.cpp b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/test.cpp
new file mode 100644
index 00000000000..809c348c0b0
--- /dev/null
+++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/test.cpp
@@ -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);
+}
\ No newline at end of file
diff --git a/docs/query-metadata-style-guide.md b/docs/query-metadata-style-guide.md
index 5660a08f72e..9b4b291a75a 100644
--- a/docs/query-metadata-style-guide.md
+++ b/docs/query-metadata-style-guide.md
@@ -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:
diff --git a/go/ql/lib/semmle/go/security/InsecureRandomness.qll b/go/ql/lib/semmle/go/security/InsecureRandomness.qll
index f2db5860073..6de3071b598 100644
--- a/go/ql/lib/semmle/go/security/InsecureRandomness.qll
+++ b/go/ql/lib/semmle/go/security/InsecureRandomness.qll
@@ -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 }
}
}
diff --git a/go/ql/lib/semmle/go/security/Xss.qll b/go/ql/lib/semmle/go/security/Xss.qll
index e9301646f77..98b6da02fe8 100644
--- a/go/ql/lib/semmle/go/security/Xss.qll
+++ b/go/ql/lib/semmle/go/security/Xss.qll
@@ -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 {
diff --git a/java/ql/lib/change-notes/2022-04-01-annotation-deprecations.md b/java/ql/lib/change-notes/2022-04-01-annotation-deprecations.md
new file mode 100644
index 00000000000..8c8046670a1
--- /dev/null
+++ b/java/ql/lib/change-notes/2022-04-01-annotation-deprecations.md
@@ -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.
diff --git a/java/ql/lib/change-notes/2022-04-01-annotation-features.md b/java/ql/lib/change-notes/2022-04-01-annotation-features.md
new file mode 100644
index 00000000000..3a2d6e2561c
--- /dev/null
+++ b/java/ql/lib/change-notes/2022-04-01-annotation-features.md
@@ -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`.
diff --git a/java/ql/lib/semmle/code/Location.qll b/java/ql/lib/semmle/code/Location.qll
index c906b9f2407..256b831a8ad 100644
--- a/java/ql/lib/semmle/code/Location.qll
+++ b/java/ql/lib/semmle/code/Location.qll
@@ -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, _, _, _, _)
diff --git a/java/ql/lib/semmle/code/java/Annotation.qll b/java/ql/lib/semmle/code/java/Annotation.qll
index 0b83d3b435e..28f994053a2 100644
--- a/java/ql/lib/semmle/code/java/Annotation.qll
+++ b/java/ql/lib/semmle/code/java/Annotation.qll
@@ -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("