Merge branch 'master' into rdmarsh/cpp/ir-callee-side-effects

This commit is contained in:
Robert Marsh
2019-11-14 11:09:13 -08:00
866 changed files with 26718 additions and 14387 deletions

View File

@@ -0,0 +1,68 @@
int source();
void sink(int);
bool guarded(int);
void bg_basic(int source) {
if (guarded(source)) {
sink(source); // no flow
} else {
sink(source); // flow
}
}
void bg_not(int source) {
if (!guarded(source)) {
sink(source); // flow
} else {
sink(source); // no flow
}
}
void bg_and(int source, bool arbitrary) {
if (guarded(source) && arbitrary) {
sink(source); // no flow
} else {
sink(source); // flow
}
}
void bg_or(int source, bool arbitrary) {
if (guarded(source) || arbitrary) {
sink(source); // flow
} else {
sink(source); // flow
}
}
void bg_return(int source) {
if (!guarded(source)) {
return;
}
sink(source); // no flow
}
struct XY {
int x, y;
};
void bg_stackstruct(XY s1, XY s2) {
s1.x = source();
if (guarded(s1.x)) {
sink(s1.x); // no flow
} else if (guarded(s1.y)) {
sink(s1.x); // flow
} else if (guarded(s2.y)) {
sink(s1.x); // flow
}
}
void bg_structptr(XY *p1, XY *p2) {
p1->x = source();
if (guarded(p1->x)) {
sink(p1->x); // no flow [FALSE POSITIVE in AST]
} else if (guarded(p1->y)) {
sink(p1->x); // flow [NOT DETECTED in IR]
} else if (guarded(p2->x)) {
sink(p1->x); // flow [NOT DETECTED in IR]
}
}

View File

@@ -1,6 +1,20 @@
import cpp
import semmle.code.cpp.dataflow.DataFlow
/**
* A `BarrierGuard` that stops flow to all occurrences of `x` within statement
* S in `if (guarded(x)) S`.
*/
// This is tested in `BarrierGuard.cpp`.
class TestBarrierGuard extends DataFlow::BarrierGuard {
TestBarrierGuard() { this.(FunctionCall).getTarget().getName() = "guarded" }
override predicate checks(Expr checked, boolean isTrue) {
checked = this.(FunctionCall).getArgument(0) and
isTrue = true
}
}
/** Common data flow configuration to be used by tests. */
class TestAllocationConfig extends DataFlow::Configuration {
TestAllocationConfig() { this = "TestAllocationConfig" }
@@ -26,4 +40,6 @@ class TestAllocationConfig extends DataFlow::Configuration {
override predicate isBarrier(DataFlow::Node barrier) {
barrier.asExpr().(VariableAccess).getTarget().hasName("barrier")
}
override predicate isBarrierGuard(DataFlow::BarrierGuard bg) { bg instanceof TestBarrierGuard }
}

View File

@@ -1,5 +1,20 @@
import cpp
import semmle.code.cpp.ir.dataflow.DataFlow
import semmle.code.cpp.ir.IR
/**
* A `BarrierGuard` that stops flow to all occurrences of `x` within statement
* S in `if (guarded(x)) S`.
*/
// This is tested in `BarrierGuard.cpp`.
class TestBarrierGuard extends DataFlow::BarrierGuard {
TestBarrierGuard() { this.(CallInstruction).getStaticCallTarget().getName() = "guarded" }
override predicate checks(Instruction checked, boolean isTrue) {
checked = this.(CallInstruction).getPositionalArgument(0) and
isTrue = true
}
}
/** Common data flow configuration to be used by tests. */
class TestAllocationConfig extends DataFlow::Configuration {
@@ -24,4 +39,6 @@ class TestAllocationConfig extends DataFlow::Configuration {
override predicate isBarrier(DataFlow::Node barrier) {
barrier.asExpr().(VariableAccess).getTarget().hasName("barrier")
}
override predicate isBarrierGuard(DataFlow::BarrierGuard bg) { bg instanceof TestBarrierGuard }
}

View File

@@ -0,0 +1,46 @@
int source();
void sink(int);
// This class has the opposite behavior of what the member function names suggest.
struct Top {
virtual int isSource1() { return 0; }
virtual int isSource2() { return 0; }
virtual void isSink(int x) { }
virtual int notSource1() { return source(); }
virtual int notSource2() { return source(); }
virtual void notSink(int x) { sink(x); }
};
// This class has the correct behavior for just the functions ending in 2.
struct Middle : Top {
int isSource2() override { return source(); }
int notSource2() override { return 0; }
};
// This class has all the behavior suggested by the function names.
struct Bottom : Middle {
int isSource1() override { return source(); }
void isSink(int x) override { sink(x); }
int notSource1() override { return 0; }
void notSink(int x) override { }
};
void VirtualDispatch(Bottom *bottomPtr, Bottom &bottomRef) {
Top *topPtr = bottomPtr, &topRef = bottomRef;
sink(topPtr->isSource1()); // flow [NOT DETECTED by AST]
sink(topPtr->isSource2()); // flow [NOT DETECTED by AST]
topPtr->isSink(source()); // flow [NOT DETECTED by AST]
sink(topPtr->notSource1()); // no flow [FALSE POSITIVE]
sink(topPtr->notSource2()); // no flow [FALSE POSITIVE]
topPtr->notSink(source()); // no flow [FALSE POSITIVE]
sink(topRef.isSource1()); // flow [NOT DETECTED by AST]
sink(topRef.isSource2()); // flow [NOT DETECTED by AST]
topRef.isSink(source()); // flow [NOT DETECTED by AST]
sink(topRef.notSource1()); // no flow [FALSE POSITIVE]
sink(topRef.notSource2()); // no flow [FALSE POSITIVE]
topRef.notSink(source()); // no flow [FALSE POSITIVE]
}

View File

@@ -1,3 +1,13 @@
| BarrierGuard.cpp:9:10:9:15 | source | BarrierGuard.cpp:5:19:5:24 | source |
| BarrierGuard.cpp:15:10:15:15 | source | BarrierGuard.cpp:13:17:13:22 | source |
| BarrierGuard.cpp:25:10:25:15 | source | BarrierGuard.cpp:21:17:21:22 | source |
| BarrierGuard.cpp:31:10:31:15 | source | BarrierGuard.cpp:29:16:29:21 | source |
| BarrierGuard.cpp:33:10:33:15 | source | BarrierGuard.cpp:29:16:29:21 | source |
| BarrierGuard.cpp:53:13:53:13 | x | BarrierGuard.cpp:49:10:49:15 | call to source |
| BarrierGuard.cpp:55:13:55:13 | x | BarrierGuard.cpp:49:10:49:15 | call to source |
| BarrierGuard.cpp:62:14:62:14 | x | BarrierGuard.cpp:60:11:60:16 | call to source |
| BarrierGuard.cpp:64:14:64:14 | x | BarrierGuard.cpp:60:11:60:16 | call to source |
| BarrierGuard.cpp:66:14:66:14 | x | BarrierGuard.cpp:60:11:60:16 | call to source |
| acrossLinkTargets.cpp:12:8:12:8 | x | acrossLinkTargets.cpp:19:27:19:32 | call to source |
| clang.cpp:18:8:18:19 | sourceArray1 | clang.cpp:12:9:12:20 | sourceArray1 |
| clang.cpp:22:8:22:20 | & ... | clang.cpp:12:9:12:20 | sourceArray1 |
@@ -5,6 +15,12 @@
| clang.cpp:30:27:30:34 | call to getFirst | clang.cpp:28:27:28:32 | call to source |
| clang.cpp:37:10:37:11 | m2 | clang.cpp:34:32:34:37 | call to source |
| clang.cpp:45:17:45:18 | m2 | clang.cpp:43:35:43:40 | call to source |
| dispatch.cpp:11:38:11:38 | x | dispatch.cpp:37:19:37:24 | call to source |
| dispatch.cpp:11:38:11:38 | x | dispatch.cpp:45:18:45:23 | call to source |
| dispatch.cpp:35:16:35:25 | call to notSource1 | dispatch.cpp:9:37:9:42 | call to source |
| dispatch.cpp:36:16:36:25 | call to notSource2 | dispatch.cpp:10:37:10:42 | call to source |
| dispatch.cpp:43:15:43:24 | call to notSource1 | dispatch.cpp:9:37:9:42 | call to source |
| dispatch.cpp:44:15:44:24 | call to notSource2 | dispatch.cpp:10:37:10:42 | call to source |
| lambdas.cpp:14:3:14:6 | t | lambdas.cpp:8:10:8:15 | call to source |
| lambdas.cpp:18:8:18:8 | call to operator() | lambdas.cpp:8:10:8:15 | call to source |
| lambdas.cpp:21:3:21:6 | t | lambdas.cpp:8:10:8:15 | call to source |

View File

@@ -1,8 +1,17 @@
| BarrierGuard.cpp:60:11:60:16 | BarrierGuard.cpp:62:14:62:14 | AST only |
| BarrierGuard.cpp:60:11:60:16 | BarrierGuard.cpp:64:14:64:14 | AST only |
| BarrierGuard.cpp:60:11:60:16 | BarrierGuard.cpp:66:14:66:14 | AST only |
| clang.cpp:12:9:12:20 | clang.cpp:18:8:18:19 | AST only |
| clang.cpp:12:9:12:20 | clang.cpp:22:8:22:20 | AST only |
| clang.cpp:28:27:28:32 | clang.cpp:29:27:29:28 | AST only |
| clang.cpp:28:27:28:32 | clang.cpp:30:27:30:34 | AST only |
| clang.cpp:39:42:39:47 | clang.cpp:41:18:41:19 | IR only |
| dispatch.cpp:16:37:16:42 | dispatch.cpp:32:16:32:24 | IR only |
| dispatch.cpp:16:37:16:42 | dispatch.cpp:40:15:40:23 | IR only |
| dispatch.cpp:22:37:22:42 | dispatch.cpp:31:16:31:24 | IR only |
| dispatch.cpp:22:37:22:42 | dispatch.cpp:39:15:39:23 | IR only |
| dispatch.cpp:33:18:33:23 | dispatch.cpp:23:38:23:38 | IR only |
| dispatch.cpp:41:17:41:22 | dispatch.cpp:23:38:23:38 | IR only |
| lambdas.cpp:8:10:8:15 | lambdas.cpp:14:3:14:6 | AST only |
| lambdas.cpp:8:10:8:15 | lambdas.cpp:18:8:18:8 | AST only |
| lambdas.cpp:8:10:8:15 | lambdas.cpp:21:3:21:6 | AST only |

View File

@@ -1,8 +1,27 @@
| BarrierGuard.cpp:9:10:9:15 | Load: source | BarrierGuard.cpp:5:19:5:24 | InitializeParameter: source |
| BarrierGuard.cpp:15:10:15:15 | Load: source | BarrierGuard.cpp:13:17:13:22 | InitializeParameter: source |
| BarrierGuard.cpp:25:10:25:15 | Load: source | BarrierGuard.cpp:21:17:21:22 | InitializeParameter: source |
| BarrierGuard.cpp:31:10:31:15 | Load: source | BarrierGuard.cpp:29:16:29:21 | InitializeParameter: source |
| BarrierGuard.cpp:33:10:33:15 | Load: source | BarrierGuard.cpp:29:16:29:21 | InitializeParameter: source |
| BarrierGuard.cpp:53:13:53:13 | Load: x | BarrierGuard.cpp:49:10:49:15 | Call: call to source |
| BarrierGuard.cpp:55:13:55:13 | Load: x | BarrierGuard.cpp:49:10:49:15 | Call: call to source |
| acrossLinkTargets.cpp:12:8:12:8 | Convert: (int)... | acrossLinkTargets.cpp:19:27:19:32 | Call: call to source |
| acrossLinkTargets.cpp:12:8:12:8 | Load: x | acrossLinkTargets.cpp:19:27:19:32 | Call: call to source |
| clang.cpp:37:10:37:11 | Load: m2 | clang.cpp:34:32:34:37 | Call: call to source |
| clang.cpp:41:18:41:19 | Load: m2 | clang.cpp:39:42:39:47 | Call: call to source |
| clang.cpp:45:17:45:18 | Load: m2 | clang.cpp:43:35:43:40 | Call: call to source |
| dispatch.cpp:11:38:11:38 | Load: x | dispatch.cpp:37:19:37:24 | Call: call to source |
| dispatch.cpp:11:38:11:38 | Load: x | dispatch.cpp:45:18:45:23 | Call: call to source |
| dispatch.cpp:23:38:23:38 | Load: x | dispatch.cpp:33:18:33:23 | Call: call to source |
| dispatch.cpp:23:38:23:38 | Load: x | dispatch.cpp:41:17:41:22 | Call: call to source |
| dispatch.cpp:31:16:31:24 | Call: call to isSource1 | dispatch.cpp:22:37:22:42 | Call: call to source |
| dispatch.cpp:32:16:32:24 | Call: call to isSource2 | dispatch.cpp:16:37:16:42 | Call: call to source |
| dispatch.cpp:35:16:35:25 | Call: call to notSource1 | dispatch.cpp:9:37:9:42 | Call: call to source |
| dispatch.cpp:36:16:36:25 | Call: call to notSource2 | dispatch.cpp:10:37:10:42 | Call: call to source |
| dispatch.cpp:39:15:39:23 | Call: call to isSource1 | dispatch.cpp:22:37:22:42 | Call: call to source |
| dispatch.cpp:40:15:40:23 | Call: call to isSource2 | dispatch.cpp:16:37:16:42 | Call: call to source |
| dispatch.cpp:43:15:43:24 | Call: call to notSource1 | dispatch.cpp:9:37:9:42 | Call: call to source |
| dispatch.cpp:44:15:44:24 | Call: call to notSource2 | dispatch.cpp:10:37:10:42 | Call: call to source |
| test.cpp:7:8:7:9 | Load: t1 | test.cpp:6:12:6:17 | Call: call to source |
| test.cpp:9:8:9:9 | Load: t1 | test.cpp:6:12:6:17 | Call: call to source |
| test.cpp:10:8:10:9 | Load: t2 | test.cpp:6:12:6:17 | Call: call to source |