C++: Port dataflow/dataflow-tests to inline expectations test library.

This commit is contained in:
Cornelius Riemenschneider
2020-11-27 16:03:15 +01:00
parent 89a4cff5f8
commit 644a0fac98
16 changed files with 178 additions and 331 deletions

View File

@@ -6,13 +6,13 @@ void bg_basic(int source) {
if (guarded(source)) {
sink(source); // no flow
} else {
sink(source); // flow
sink(source); // $ ast,ir
}
}
void bg_not(int source) {
if (!guarded(source)) {
sink(source); // flow
sink(source); // $ ast,ir
} else {
sink(source); // no flow
}
@@ -22,15 +22,15 @@ void bg_and(int source, bool arbitrary) {
if (guarded(source) && arbitrary) {
sink(source); // no flow
} else {
sink(source); // flow
sink(source); // $ ast,ir
}
}
void bg_or(int source, bool arbitrary) {
if (guarded(source) || arbitrary) {
sink(source); // flow
sink(source); // $ ast,ir
} else {
sink(source); // flow
sink(source); // $ ast,ir
}
}
@@ -48,21 +48,21 @@ struct XY {
void bg_stackstruct(XY s1, XY s2) {
s1.x = source();
if (guarded(s1.x)) {
sink(s1.x); // no flow [FALSE POSITIVE in AST]
sink(s1.x); // $ SPURIOUS: ast
} else if (guarded(s1.y)) {
sink(s1.x); // flow
sink(s1.x); // $ ast,ir
} else if (guarded(s2.y)) {
sink(s1.x); // flow
sink(s1.x); // $ ast,ir
}
}
void bg_structptr(XY *p1, XY *p2) {
p1->x = source();
if (guarded(p1->x)) {
sink(p1->x); // no flow [FALSE POSITIVE in AST]
sink(p1->x); // $ SPURIOUS: ast
} else if (guarded(p1->y)) {
sink(p1->x); // flow
sink(p1->x); // $ ast,ir
} else if (guarded(p2->x)) {
sink(p1->x); // flow
sink(p1->x); // $ ast,ir
}
}

View File

@@ -1,5 +1,6 @@
import cpp
import semmle.code.cpp.dataflow.DataFlow
import TestUtilities.InlineExpectationsTest
/**
* A `BarrierGuard` that stops flow to all occurrences of `x` within statement

View File

@@ -1,6 +1,7 @@
import cpp
import semmle.code.cpp.ir.dataflow.DataFlow
import semmle.code.cpp.ir.IR
import TestUtilities.InlineExpectationsTest
/**
* A `BarrierGuard` that stops flow to all occurrences of `x` within statement
@@ -24,9 +25,6 @@ class TestAllocationConfig extends DataFlow::Configuration {
source.asExpr().(FunctionCall).getTarget().getName() = "source"
or
source.asParameter().getName().matches("source%")
or
// Track uninitialized variables
exists(source.asUninitialized())
}
override predicate isSink(DataFlow::Node sink) {

View File

@@ -9,7 +9,7 @@ void sink(int);
// this result and be forced to write a better test if the function signature
// detection should improve.
void calleeAcrossLinkTargets(long x) {
sink(x);
sink(x); // $ ast,ir
}
void calleeAcrossLinkTargets(int x); // no body

View File

@@ -15,39 +15,38 @@ void following_pointers(
twoIntFields *sourceStruct1_ptr,
int (*sourceFunctionPointer)())
{
sink(sourceArray1); // flow
sink(sourceArray1); // $ ast,ir
sink(sourceArray1[0]); // no flow
sink(*sourceArray1); // no flow
sink(&sourceArray1); // flow (should probably be taint only)
sink(&sourceArray1); // $ ast // [should probably taint only]
sink(sourceStruct1.m1); // no flow
sink(sourceStruct1_ptr->m1); // no flow
sink(sourceStruct1_ptr->getFirst()); // no flow
sourceStruct1_ptr->m1 = source();
sink(sourceStruct1_ptr->m1); // flow
sink(sourceStruct1_ptr->getFirst()); // flow
sink(sourceStruct1_ptr->m1); // $ ast,ir
sink(sourceStruct1_ptr->getFirst()); // $ ast,ir
sink(sourceStruct1_ptr->m2); // no flow
sink(sourceStruct1.m1); // no flow
twoIntFields s = { source(), source() };
sink(s.m2); // flow
sink(s.m2); // $ ast,ir
twoIntFields sArray[1] = { { source(), source() } };
// TODO: fix this like above
sink(sArray[0].m2); // flow (AST dataflow misses this due to limitations of the analysis)
sink(sArray[0].m2); // $ ir MISSING: ast
twoIntFields sSwapped = { .m2 = source(), .m1 = 0 };
sink(sSwapped.m2); // flow
sink(sSwapped.m2); // $ ast,ir
sink(sourceFunctionPointer()); // no flow
int stackArray[2] = { source(), source() };
stackArray[0] = source();
sink(stackArray); // flow
sink(stackArray); // $ ast MISSING: ir
}

View File

@@ -8,7 +8,7 @@ struct Top {
virtual void isSink(int x) { }
virtual int notSource1() { return source(); }
virtual int notSource2() { return source(); }
virtual void notSink(int x) { sink(x); }
virtual void notSink(int x) { sink(x); } // $ SPURIOUS: ast,ir=37:19 ast,ir=45:18
};
// This class has the correct behavior for just the functions ending in 2.
@@ -20,7 +20,7 @@ struct Middle : Top {
// 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); }
void isSink(int x) override { sink(x); } // $ ir=33:18 ir=41:17 ir=69:15 ir=73:14 ir=81:13 MISSING: ast=33:18 ast=41:17 ast=69:15 ast=73:14 ast=81:13
int notSource1() override { return 0; }
void notSink(int x) override { }
};
@@ -28,21 +28,21 @@ struct Bottom : Middle {
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->isSource1()); // $ ir MISSING: ast
sink(topPtr->isSource2()); // $ ir MISSING: ast
topPtr->isSink(source()); // causing a MISSING for ast
sink(topPtr->notSource1()); // no flow [FALSE POSITIVE]
sink(topPtr->notSource2()); // no flow [FALSE POSITIVE]
topPtr->notSink(source()); // no flow [FALSE POSITIVE]
sink(topPtr->notSource1()); // $ SPURIOUS: ast,ir
sink(topPtr->notSource2()); // $ SPURIOUS: ast,ir
topPtr->notSink(source()); // causing SPURIOUS for ast,ir
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.isSource1()); // $ ir MISSING: ast
sink(topRef.isSource2()); // $ ir MISSING: ast
topRef.isSink(source()); // causing a MISSING for ast
sink(topRef.notSource1()); // no flow [FALSE POSITIVE]
sink(topRef.notSource2()); // no flow [FALSE POSITIVE]
topRef.notSink(source()); // no flow [FALSE POSITIVE]
sink(topRef.notSource1()); // $ SPURIOUS: ast,ir
sink(topRef.notSource2()); // $ SPURIOUS: ast,ir
topRef.notSink(source()); // causing SPURIOUS for ast,ir
}
Top *globalBottom, *globalMiddle;
@@ -52,10 +52,10 @@ Top *readGlobalBottom() {
}
void DispatchThroughGlobal() {
sink(globalBottom->isSource1()); // flow [NOT DETECTED by AST]
sink(globalBottom->isSource1()); // $ ir MISSING: ast
sink(globalMiddle->isSource1()); // no flow
sink(readGlobalBottom()->isSource1()); // flow [NOT DETECTED by AST]
sink(readGlobalBottom()->isSource1()); // $ ir MISSING: ast
globalBottom = new Bottom();
globalMiddle = new Middle();
@@ -66,11 +66,11 @@ Top *allocateBottom() {
}
void callSinkByPointer(Top *top) {
top->isSink(source()); // flow [NOT DETECTED by AST]
top->isSink(source()); // leads to MISSING from ast
}
void callSinkByReference(Top &top) {
top.isSink(source()); // flow [NOT DETECTED by AST]
top.isSink(source()); // leads to MISSING from ast
}
void globalVirtualDispatch() {
@@ -78,7 +78,7 @@ void globalVirtualDispatch() {
callSinkByReference(*allocateBottom());
Top *x = allocateBottom();
x->isSink(source()); // flow [NOT DETECTED by AST]
x->isSink(source()); // $ MISSING: ast,ir
}
Top *identity(Top *top) {
@@ -86,14 +86,14 @@ Top *identity(Top *top) {
}
void callIdentityFunctions(Top *top, Bottom *bottom) {
identity(bottom)->isSink(source()); // flow [NOT DETECTED]
identity(bottom)->isSink(source()); // $ MISSING: ast,ir
identity(top)->isSink(source()); // now flow
}
using SinkFunctionType = void (*)(int);
void callSink(int x) {
sink(x);
sink(x); // $ ir=107:17 ir=140:8 ir=144:8 MISSING: ast=107:17 ast=140:8 ast=144:8
}
SinkFunctionType returnCallSink() {
@@ -104,7 +104,7 @@ void testFunctionPointer(SinkFunctionType maybeCallSink, SinkFunctionType dontCa
if (b) {
maybeCallSink = returnCallSink();
}
maybeCallSink(source()); // flow [NOT DETECTED by AST]
maybeCallSink(source());
dontCallSink(source()); // no flow
}
@@ -126,8 +126,8 @@ namespace virtual_inheritance {
// get flow from a `Middle` value to the call qualifier.
Top *topPtr = bottomPtr, &topRef = bottomRef;
sink(topPtr->isSource()); // flow [NOT DETECTED]
sink(topRef.isSource()); // flow [NOT DETECTED]
sink(topPtr->isSource()); // $ MISSING: ast,ir
sink(topRef.isSource()); // $ MISSING: ast,ir
}
}
@@ -170,6 +170,6 @@ void set_global_union_field_u_f() {
void test_call_sink_through_union_2() {
set_global_union_field_u_f();
call_sink_through_union_field_u_f(u2.u.f); // flow [NOT DETECTED]
call_sink_through_union_field_u_g(u2.u.g); // flow [NOT DETECTED]
call_sink_through_union_field_u_f(u2.u.f); // $ MISSING: ast,ir
call_sink_through_union_field_u_g(u2.u.g); // $ MISSING: ast,ir
}

View File

@@ -3,20 +3,20 @@ void sink(int);
void throughLocal() {
int local = source();
sink(local); // flow
sink(local); // $ ast,ir
}
int flowTestGlobal1 = 0;
void readWriteGlobal1() {
sink(flowTestGlobal1); // flow
sink(flowTestGlobal1); // $ ir MISSING: ast
flowTestGlobal1 = source();
}
static int flowTestGlobal2 = 0;
void readGlobal2() {
sink(flowTestGlobal2); // flow
sink(flowTestGlobal2); // $ ir MISSING: ast
}
void writeGlobal2() {

View File

@@ -11,37 +11,37 @@ void test_lambdas()
int w = 0;
auto a = [t, u]() -> int {
sink(t); // flow from source()
sink(t); // $ ast,ir
sink(u);
return t;
};
sink(a()); // flow from source()
sink(a()); // $ ast,ir
auto b = [&] {
sink(t); // flow from source()
sink(t); // $ ast MISSING: ir
sink(u);
v = source(); // (v is reference captured)
};
b();
sink(v); // flow from source() [NOT DETECTED]
sink(v); // $ MISSING: ast,ir
auto c = [=] {
sink(t); // flow from source()
sink(t); // $ ast,ir
sink(u);
};
c();
auto d = [](int a, int b) {
sink(a); // flow from source()
sink(a); // $ ast,ir
sink(b);
};
d(t, u);
auto e = [](int &a, int &b, int &c) {
sink(a); // flow from source()
sink(a); // $ ast,ir
sink(b);
c = source();
};
e(t, u, w);
sink(w); // flow from source()
sink(w); // $ ast,ir
}

View File

@@ -53,16 +53,16 @@ namespace withoutFields {
int x1, x2, x3, x4;
assignWrapper(x1, source());
sink(x1); // flow [FALSE POSITIVE from uninitialized]
sink(x1); // $ ast=55:23 ir SPURIOUS: ast=53:9
notAssign(x2, source());
sink(x2); // no flow [FALSE POSITIVE from uninitialized, FALSE POSITIVE by IR]
sink(x2); // $ SPURIOUS: ast,ir
sourceToParamWrapper(x3);
sink(x3); // flow [FALSE POSITIVE from uninitialized]
sink(x3); // $ ast=29:11 ir SPURIOUS: ast=53:17
notSource(x4);
sink(x4); // no flow [FALSE POSITIVE from uninitialized, FALSE POSITIVE by IR]
sink(x4); // $ SPURIOUS: ast,ir
}
}
@@ -120,15 +120,15 @@ namespace withFields {
Int x1, x2, x3, x4;
assignWrapper(x1, source());
sink(x1.val); // flow
sink(x1.val); // $ ast,ir
notAssign(x2, source());
sink(x2.val); // no flow [FALSE POSITIVE]
sink(x2.val); // $ SPURIOUS: ast,ir
sourceToParamWrapper(x3);
sink(x3.val); // flow
sink(x3.val); // $ ast,ir
notSource(x4);
sink(x4.val); // no flow [FALSE POSITIVE]
sink(x4.val); // $ SPURIOUS: ast,ir
}
}

View File

@@ -4,15 +4,15 @@ void sink(int); void sink(const int *); void sink(int **);
void intraprocedural_with_local_flow() {
int t2;
int t1 = source();
sink(t1); // tainted
sink(t1); // $ ast,ir
t2 = t1;
sink(t1); // tainted
sink(t2); // tainted
sink(t1); // $ ast,ir
sink(t2); // $ ast,ir
if (t1) {
t2 = 0;
sink(t2); // clean
}
sink(t2); // tainted
sink(t2); // $ ast,ir
t1 = 0;
while (false) {
@@ -23,12 +23,12 @@ void intraprocedural_with_local_flow() {
for (int i = 0; i < t1; i++) {
t1 = t2;
}
sink(t1); // tainted
sink(t1); // $ ast,ir
}
static void callee(int t, int c) {
sink(t); // tainted (from first call in caller() function)
sink(c); // tainted (from second call in caller() function)
sink(t); // $ ast,ir // (from first call in caller() function)
sink(c); // $ ast,ir // (from second call in caller() function)
}
void caller() {
@@ -55,7 +55,7 @@ void branching(bool b) {
}
sink(t); // tainted
sink(t); // $ ast,ir
}
}
@@ -68,12 +68,12 @@ void identityOperations(int* source1) {
int* x2 = const_cast<int*>(x1);
int* x3 = (x2);
const int* x4 = (const int *)x3;
sink(x4);
sink(x4); // $ ast,ir
}
void trackUninitialized() {
void trackUninitialized() { // NOTE: uninitialized tracking for IR dataflow is deprecated
int u1;
sink(u1); // tainted
sink(u1); // $ ast
u1 = 2;
sink(u1); // clean
@@ -81,15 +81,15 @@ void trackUninitialized() {
sink(i1); // clean
int u2;
sink(i1 ? u2 : 1); // tainted
sink(i1 ? u2 : 1); // $ ast
i1 = u2;
sink(i1); // tainted
sink(i1); // $ ast
}
void local_references(int &source1, int clean1) {
sink(source1); // tainted
sink(source1); // $ ast,ir
source1 = clean1;
sink(source1); // clean
sink(source1); // $ SPURIOUS: ir
// The next two test cases show that the analysis does not understand the "&"
// on the type at all. It does not understand that the initialization creates
@@ -100,14 +100,14 @@ void local_references(int &source1, int clean1) {
int t = source();
int &ref = t;
t = clean1;
sink(ref); // clean (FALSE POSITIVE)
sink(ref); // $ SPURIOUS: ast
}
{
int t = clean1;
int &ref = t;
t = source();
sink(ref); // tainted (FALSE NEGATIVE)
sink(ref); // $ ir MISSING: ast
}
}
@@ -137,11 +137,11 @@ int returnParameter(int p) {
void callReturnParameter() {
int x = returnParameter(source());
int y = x;
sink(y); // tainted due to above source
sink(y); // $ ast,ir
}
int returnSourceParameter(int s) {
sink(s); // tainted
sink(s); // $ ast,ir // from line 151
return s; // considered clean unless the caller passes taint into the parameter source
}
@@ -149,12 +149,12 @@ void callReturnSourceParameter() {
int x = returnSourceParameter(0);
sink(x); // clean
int y = returnSourceParameter(source());
sink(y); // tainted
sink(y); // $ ast,ir
}
int returnSourceParameter2(int s) {
int x = s;
sink(x); // tainted
sink(x); // $ ast,ir // from line 164
return x; // considered clean unless the caller passes taint into the parameter source
}
@@ -162,7 +162,7 @@ void callReturnSourceParameter2() {
int x = returnSourceParameter2(0);
sink(x); // clean
int y = returnSourceParameter2(source());
sink(y); // tainted
sink(y); // $ ast,ir
}
// Tests for non-parameter sources returned to a function call
@@ -175,7 +175,7 @@ int returnSource() {
void callReturnSource() {
int x = returnSource();
int y = x;
sink(y); // tainted
sink(y); // $ ast,ir
}
// TESTS WITH BARRIERS: none of these should have results
@@ -257,13 +257,13 @@ namespace NestedTests {
}
void level2(int x) {
sink(x); // tainted from call to level1() but not from call to safelevel1()
sink(x); // $ ast,ir // tainted from call to level1() but not from call to safelevel1()
}
};
class FlowThroughFunctionReturn {
void level0() {
int x = level1(source());
sink(x); // tainted
sink(x); // $ ast,ir
x = safelevel1(source());
sink(x); // no longer tainted
}
@@ -286,7 +286,7 @@ namespace NestedTests {
class FlowOutOfFunction {
void level0() {
int x = level1();
sink(x); // tainted
sink(x); // $ ast,ir
x = safelevel1();
sink(x); // no longer tainted
}
@@ -315,7 +315,7 @@ namespace NestedTests {
}
void g(int p) {
int x = h(p);
sink(x); // tainted from f
sink(x); // $ ast,ir // tainted from f
int y = h(0);
sink(y); // clean
f();
@@ -336,17 +336,17 @@ namespace FlowThroughGlobals {
int f() {
sink(globalVar); // tainted or clean? Not sure.
taintGlobal();
sink(globalVar); // tainted (FALSE NEGATIVE)
sink(globalVar); // $ MISSING: ast,ir
}
int calledAfterTaint() {
sink(globalVar); // tainted (FALSE NEGATIVE)
sink(globalVar); // $ MISSING: ast,ir
}
int taintAndCall() {
globalVar = source();
calledAfterTaint();
sink(globalVar); // tainted
sink(globalVar); // $ ast MISSING: ir
}
}
@@ -362,17 +362,17 @@ class FlowThroughFields {
int f() {
sink(field); // tainted or clean? Not sure.
taintField();
sink(field); // tainted [NOT DETECTED with IR]
sink(field); // $ ast MISSING: ir
}
int calledAfterTaint() {
sink(field); // tainted
sink(field); // $ ast,ir
}
int taintAndCall() {
field = source();
calledAfterTaint();
sink(field); // tainted
sink(field); // $ ast,ir
}
};
@@ -382,30 +382,30 @@ void *memcpy(void *dest, const void *src, size_t count);
void flowThroughMemcpy_ssa_with_local_flow(int source1) {
int tmp = 0;
memcpy(&tmp, &source1, sizeof tmp);
sink(tmp); // tainted
sink(tmp); // $ ast,ir
}
void flowThroughMemcpy_blockvar_with_local_flow(int source1, int b) {
int tmp = 0;
int *capture = &tmp;
memcpy(&tmp, &source1, sizeof tmp);
sink(tmp); // tainted
sink(tmp); // $ ast,ir
if (b) {
sink(tmp); // tainted
sink(tmp); // $ ast,ir
}
}
void cleanedByMemcpy_ssa(int clean1) { // currently modeled with BlockVar, not SSA
int tmp;
memcpy(&tmp, &clean1, sizeof tmp);
sink(tmp); // clean [FALSE POSITIVE]
sink(tmp); // $ SPURIOUS: ast
}
void cleanedByMemcpy_blockvar(int clean1) {
int tmp;
int *capture = &tmp;
memcpy(&tmp, &clean1, sizeof tmp);
sink(tmp); // clean [FALSE POSITIVE]
sink(tmp); // $ SPURIOUS: ast
}
void intRefSource(int &ref_source);
@@ -415,39 +415,39 @@ void intArraySource(int ref_source[], size_t len);
void intRefSourceCaller() {
int local;
intRefSource(local);
sink(local); // tainted
sink(local); // $ ast=416:7 ast=417:16 MISSING: ir
}
void intPointerSourceCaller() {
int local;
intPointerSource(&local);
sink(local); // tainted
sink(local); // $ ast=422:7 ast=423:20 MISSING: ir
}
void intPointerSourceCaller2() {
int local[1];
intPointerSource(local);
sink(local); // tainted
sink(*local); // tainted
sink(local); // $ ast=428:7 ast=429:20 MISSING: ir
sink(*local); // $ ast=428:7 ast=429:20 MISSING: ir
}
void intArraySourceCaller() {
int local;
intArraySource(&local, 1);
sink(local); // tainted
sink(local); // $ ast=435:7 ast=436:18 MISSING: ir
}
void intArraySourceCaller2() {
int local[2];
intArraySource(local, 2);
sink(local); // tainted
sink(*local); // tainted
sink(local); // $ ast=441:7 ast=442:18 MISSING: ir
sink(*local); // $ ast=441:7 ast=442:18 MISSING: ir
}
///////////////////////////////////////////////////////////////////////////////
void throughStmtExpr(int source1, int clean1) {
sink( ({ source1; }) ); // tainted
sink( ({ source1; }) ); // $ ast,ir
sink( ({ clean1; }) ); // clean
int local = ({
@@ -458,7 +458,7 @@ void throughStmtExpr(int source1, int clean1) {
tmp = clean1;
tmp;
});
sink(local); // tainted
sink(local); // $ ast,ir
}
void intOutparamSource(int *p) {
@@ -468,5 +468,5 @@ void intOutparamSource(int *p) {
void viaOutparam() {
int x = 0;
intOutparamSource(&x);
sink(x); // tainted
}
sink(x); // $ ast,ir
}

View File

@@ -1,100 +0,0 @@
| 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:51:13:51:13 | x | BarrierGuard.cpp:49:10:49:15 | call to 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 |
| clang.cpp:29:27:29:28 | m1 | clang.cpp:28:27:28:32 | call to source |
| 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 |
| clang.cpp:51:8:51:17 | stackArray | clang.cpp:50:19:50:24 | 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 |
| globals.cpp:6:10:6:14 | local | globals.cpp:5:17:5:22 | 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 |
| lambdas.cpp:29:3:29:6 | t | lambdas.cpp:8:10:8:15 | call to source |
| lambdas.cpp:35:8:35:8 | a | lambdas.cpp:8:10:8:15 | call to source |
| lambdas.cpp:41:8:41:8 | a | lambdas.cpp:8:10:8:15 | call to source |
| lambdas.cpp:46:7:46:7 | w | lambdas.cpp:43:7:43:12 | call to source |
| ref.cpp:56:10:56:11 | x1 | ref.cpp:53:9:53:10 | x1 |
| ref.cpp:56:10:56:11 | x1 | ref.cpp:55:23:55:28 | call to source |
| ref.cpp:59:10:59:11 | x2 | ref.cpp:53:13:53:14 | x2 |
| ref.cpp:62:10:62:11 | x3 | ref.cpp:29:11:29:16 | call to source |
| ref.cpp:62:10:62:11 | x3 | ref.cpp:53:17:53:18 | x3 |
| ref.cpp:65:10:65:11 | x4 | ref.cpp:53:21:53:22 | x4 |
| ref.cpp:123:13:123:15 | val | ref.cpp:122:23:122:28 | call to source |
| ref.cpp:126:13:126:15 | val | ref.cpp:125:19:125:24 | call to source |
| ref.cpp:129:13:129:15 | val | ref.cpp:94:15:94:20 | call to source |
| ref.cpp:132:13:132:15 | val | ref.cpp:109:15:109:20 | call to source |
| test.cpp:7:8:7:9 | t1 | test.cpp:6:12:6:17 | call to source |
| test.cpp:9:8:9:9 | t1 | test.cpp:6:12:6:17 | call to source |
| test.cpp:10:8:10:9 | t2 | test.cpp:6:12:6:17 | call to source |
| test.cpp:15:8:15:9 | t2 | test.cpp:6:12:6:17 | call to source |
| test.cpp:26:8:26:9 | t1 | test.cpp:6:12:6:17 | call to source |
| test.cpp:30:8:30:8 | t | test.cpp:35:10:35:15 | call to source |
| test.cpp:31:8:31:8 | c | test.cpp:36:13:36:18 | call to source |
| test.cpp:58:10:58:10 | t | test.cpp:50:14:50:19 | call to source |
| test.cpp:71:8:71:9 | x4 | test.cpp:66:30:66:36 | source1 |
| test.cpp:76:8:76:9 | u1 | test.cpp:75:7:75:8 | u1 |
| test.cpp:84:8:84:18 | ... ? ... : ... | test.cpp:83:7:83:8 | u2 |
| test.cpp:86:8:86:9 | i1 | test.cpp:83:7:83:8 | u2 |
| test.cpp:90:8:90:14 | source1 | test.cpp:89:28:89:34 | source1 |
| test.cpp:103:10:103:12 | ref | test.cpp:100:13:100:18 | call to source |
| test.cpp:140:8:140:8 | y | test.cpp:138:27:138:32 | call to source |
| test.cpp:144:8:144:8 | s | test.cpp:151:33:151:38 | call to source |
| test.cpp:152:8:152:8 | y | test.cpp:151:33:151:38 | call to source |
| test.cpp:157:8:157:8 | x | test.cpp:164:34:164:39 | call to source |
| test.cpp:165:8:165:8 | y | test.cpp:164:34:164:39 | call to source |
| test.cpp:178:8:178:8 | y | test.cpp:171:11:171:16 | call to source |
| test.cpp:260:12:260:12 | x | test.cpp:245:14:245:19 | call to source |
| test.cpp:266:12:266:12 | x | test.cpp:265:22:265:27 | call to source |
| test.cpp:289:14:289:14 | x | test.cpp:305:17:305:22 | call to source |
| test.cpp:318:7:318:7 | x | test.cpp:314:4:314:9 | call to source |
| test.cpp:349:10:349:18 | globalVar | test.cpp:347:17:347:22 | call to source |
| test.cpp:365:10:365:14 | field | test.cpp:359:13:359:18 | call to source |
| test.cpp:369:10:369:14 | field | test.cpp:373:13:373:18 | call to source |
| test.cpp:375:10:375:14 | field | test.cpp:373:13:373:18 | call to source |
| test.cpp:385:8:385:10 | tmp | test.cpp:382:48:382:54 | source1 |
| test.cpp:392:8:392:10 | tmp | test.cpp:388:53:388:59 | source1 |
| test.cpp:394:10:394:12 | tmp | test.cpp:388:53:388:59 | source1 |
| test.cpp:401:8:401:10 | tmp | test.cpp:399:7:399:9 | tmp |
| test.cpp:408:8:408:10 | tmp | test.cpp:405:7:405:9 | tmp |
| test.cpp:418:8:418:12 | local | test.cpp:416:7:416:11 | local |
| test.cpp:418:8:418:12 | local | test.cpp:417:16:417:20 | ref arg local |
| test.cpp:424:8:424:12 | local | test.cpp:422:7:422:11 | local |
| test.cpp:424:8:424:12 | local | test.cpp:423:20:423:25 | ref arg & ... |
| test.cpp:430:8:430:12 | local | test.cpp:428:7:428:11 | local |
| test.cpp:430:8:430:12 | local | test.cpp:429:20:429:24 | ref arg local |
| test.cpp:431:8:431:13 | * ... | test.cpp:428:7:428:11 | local |
| test.cpp:431:8:431:13 | * ... | test.cpp:429:20:429:24 | ref arg local |
| test.cpp:437:8:437:12 | local | test.cpp:435:7:435:11 | local |
| test.cpp:437:8:437:12 | local | test.cpp:436:18:436:23 | ref arg & ... |
| test.cpp:443:8:443:12 | local | test.cpp:441:7:441:11 | local |
| test.cpp:443:8:443:12 | local | test.cpp:442:18:442:22 | ref arg local |
| test.cpp:444:8:444:13 | * ... | test.cpp:441:7:441:11 | local |
| test.cpp:444:8:444:13 | * ... | test.cpp:442:18:442:22 | ref arg local |
| test.cpp:450:9:450:22 | (statement expression) | test.cpp:449:26:449:32 | source1 |
| test.cpp:461:8:461:12 | local | test.cpp:449:26:449:32 | source1 |
| test.cpp:471:8:471:8 | x | test.cpp:465:8:465:13 | call to source |
| true_upon_entry.cpp:21:8:21:8 | x | true_upon_entry.cpp:17:11:17:16 | call to source |
| true_upon_entry.cpp:29:8:29:8 | x | true_upon_entry.cpp:27:9:27:14 | call to source |
| true_upon_entry.cpp:39:8:39:8 | x | true_upon_entry.cpp:33:11:33:16 | call to source |
| true_upon_entry.cpp:49:8:49:8 | x | true_upon_entry.cpp:43:11:43:16 | call to source |
| true_upon_entry.cpp:57:8:57:8 | x | true_upon_entry.cpp:54:11:54:16 | call to source |
| true_upon_entry.cpp:78:8:78:8 | x | true_upon_entry.cpp:70:11:70:16 | call to source |
| true_upon_entry.cpp:86:8:86:8 | x | true_upon_entry.cpp:83:11:83:16 | call to source |

View File

@@ -1,5 +1,27 @@
import DataflowTestCommon
from DataFlow::Node sink, DataFlow::Node source, TestAllocationConfig cfg
where cfg.hasFlow(source, sink)
select sink, source
class ASTDataFlowTest extends InlineExpectationsTest {
ASTDataFlowTest() { this = "ASTDataFlowTest" }
override string getARelevantTag() { result = "ast" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
exists(DataFlow::Node source, DataFlow::Node sink, TestAllocationConfig conf, int n |
tag = "ast" and
conf.hasFlow(source, sink) and
n = strictcount(DataFlow::Node otherSource | conf.hasFlow(otherSource, sink)) and
(
n = 1 and value = ""
or
// If there is more than one source for this sink
// we specify the source location explicitly.
n > 1 and
value =
source.getLocation().getStartLine().toString() + ":" +
source.getLocation().getStartColumn()
) and
location = sink.getLocation() and
element = sink.toString()
)
}
}

View File

@@ -1,95 +0,0 @@
| 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: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 | (int)... | acrossLinkTargets.cpp:19:27:19:32 | 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 | (const int *)... | clang.cpp:12:9:12:20 | sourceArray1 |
| clang.cpp:18:8:18:19 | sourceArray1 | clang.cpp:12:9:12:20 | sourceArray1 |
| clang.cpp:29:27:29:28 | m1 | clang.cpp:28:27:28:32 | call to source |
| 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:41:18:41:19 | m2 | clang.cpp:39:42:39:47 | 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:23:38:23:38 | x | dispatch.cpp:33:18:33:23 | call to source |
| dispatch.cpp:23:38:23:38 | x | dispatch.cpp:41:17:41:22 | call to source |
| dispatch.cpp:23:38:23:38 | x | dispatch.cpp:69:15:69:20 | call to source |
| dispatch.cpp:23:38:23:38 | x | dispatch.cpp:73:14:73:19 | call to source |
| dispatch.cpp:23:38:23:38 | x | dispatch.cpp:81:13:81:18 | call to source |
| dispatch.cpp:31:16:31:24 | call to isSource1 | dispatch.cpp:22:37:22:42 | call to source |
| dispatch.cpp:32:16:32:24 | call to isSource2 | dispatch.cpp:16:37:16:42 | 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:39:15:39:23 | call to isSource1 | dispatch.cpp:22:37:22:42 | call to source |
| dispatch.cpp:40:15:40:23 | call to isSource2 | dispatch.cpp:16:37:16: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 |
| dispatch.cpp:55:22:55:30 | call to isSource1 | dispatch.cpp:22:37:22:42 | call to source |
| dispatch.cpp:58:28:58:36 | call to isSource1 | dispatch.cpp:22:37:22:42 | call to source |
| dispatch.cpp:96:8:96:8 | x | dispatch.cpp:107:17:107:22 | call to source |
| dispatch.cpp:96:8:96:8 | x | dispatch.cpp:140:8:140:13 | call to source |
| dispatch.cpp:96:8:96:8 | x | dispatch.cpp:144:8:144:13 | call to source |
| globals.cpp:6:10:6:14 | local | globals.cpp:5:17:5:22 | call to source |
| globals.cpp:12:10:12:24 | flowTestGlobal1 | globals.cpp:13:23:13:28 | call to source |
| globals.cpp:19:10:19:24 | flowTestGlobal2 | globals.cpp:23:23:23:28 | 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:29:3:29:6 | t | lambdas.cpp:8:10:8:15 | call to source |
| lambdas.cpp:35:8:35:8 | a | lambdas.cpp:8:10:8:15 | call to source |
| lambdas.cpp:41:8:41:8 | (reference dereference) | lambdas.cpp:8:10:8:15 | call to source |
| lambdas.cpp:46:7:46:7 | w | lambdas.cpp:43:7:43:12 | call to source |
| ref.cpp:56:10:56:11 | x1 | ref.cpp:55:23:55:28 | call to source |
| ref.cpp:59:10:59:11 | x2 | ref.cpp:58:19:58:24 | call to source |
| ref.cpp:62:10:62:11 | x3 | ref.cpp:29:11:29:16 | call to source |
| ref.cpp:65:10:65:11 | x4 | ref.cpp:44:11:44:16 | call to source |
| ref.cpp:123:13:123:15 | val | ref.cpp:122:23:122:28 | call to source |
| ref.cpp:126:13:126:15 | val | ref.cpp:125:19:125:24 | call to source |
| ref.cpp:129:13:129:15 | val | ref.cpp:94:15:94:20 | call to source |
| ref.cpp:132:13:132:15 | val | ref.cpp:109:15:109:20 | call to source |
| test.cpp:7:8:7:9 | t1 | test.cpp:6:12:6:17 | call to source |
| test.cpp:9:8:9:9 | t1 | test.cpp:6:12:6:17 | call to source |
| test.cpp:10:8:10:9 | t2 | test.cpp:6:12:6:17 | call to source |
| test.cpp:15:8:15:9 | t2 | test.cpp:6:12:6:17 | call to source |
| test.cpp:26:8:26:9 | t1 | test.cpp:6:12:6:17 | call to source |
| test.cpp:30:8:30:8 | t | test.cpp:35:10:35:15 | call to source |
| test.cpp:31:8:31:8 | c | test.cpp:36:13:36:18 | call to source |
| test.cpp:58:10:58:10 | t | test.cpp:50:14:50:19 | call to source |
| test.cpp:71:8:71:9 | x4 | test.cpp:66:30:66:36 | source1 |
| test.cpp:90:8:90:14 | source1 | test.cpp:89:28:89:34 | source1 |
| test.cpp:92:8:92:14 | source1 | test.cpp:89:28:89:34 | source1 |
| test.cpp:110:10:110:12 | (reference dereference) | test.cpp:109:9:109:14 | call to source |
| test.cpp:140:8:140:8 | y | test.cpp:138:27:138:32 | call to source |
| test.cpp:144:8:144:8 | s | test.cpp:151:33:151:38 | call to source |
| test.cpp:152:8:152:8 | y | test.cpp:151:33:151:38 | call to source |
| test.cpp:157:8:157:8 | x | test.cpp:164:34:164:39 | call to source |
| test.cpp:165:8:165:8 | y | test.cpp:164:34:164:39 | call to source |
| test.cpp:178:8:178:8 | y | test.cpp:171:11:171:16 | call to source |
| test.cpp:260:12:260:12 | x | test.cpp:245:14:245:19 | call to source |
| test.cpp:266:12:266:12 | x | test.cpp:265:22:265:27 | call to source |
| test.cpp:289:14:289:14 | x | test.cpp:305:17:305:22 | call to source |
| test.cpp:318:7:318:7 | x | test.cpp:314:4:314:9 | call to source |
| test.cpp:369:10:369:14 | field | test.cpp:373:13:373:18 | call to source |
| test.cpp:375:10:375:14 | field | test.cpp:373:13:373:18 | call to source |
| test.cpp:385:8:385:10 | tmp | test.cpp:382:48:382:54 | source1 |
| test.cpp:392:8:392:10 | tmp | test.cpp:388:53:388:59 | source1 |
| test.cpp:394:10:394:12 | tmp | test.cpp:388:53:388:59 | source1 |
| test.cpp:450:9:450:22 | (statement expression) | test.cpp:449:26:449:32 | source1 |
| test.cpp:461:8:461:12 | local | test.cpp:449:26:449:32 | source1 |
| test.cpp:471:8:471:8 | x | test.cpp:465:8:465:13 | call to source |
| true_upon_entry.cpp:13:8:13:8 | x | true_upon_entry.cpp:9:11:9:16 | call to source |
| true_upon_entry.cpp:21:8:21:8 | x | true_upon_entry.cpp:17:11:17:16 | call to source |
| true_upon_entry.cpp:29:8:29:8 | x | true_upon_entry.cpp:27:9:27:14 | call to source |
| true_upon_entry.cpp:39:8:39:8 | x | true_upon_entry.cpp:33:11:33:16 | call to source |
| true_upon_entry.cpp:49:8:49:8 | x | true_upon_entry.cpp:43:11:43:16 | call to source |
| true_upon_entry.cpp:57:8:57:8 | x | true_upon_entry.cpp:54:11:54:16 | call to source |
| true_upon_entry.cpp:66:8:66:8 | x | true_upon_entry.cpp:62:11:62:16 | call to source |
| true_upon_entry.cpp:78:8:78:8 | x | true_upon_entry.cpp:70:11:70:16 | call to source |
| true_upon_entry.cpp:86:8:86:8 | x | true_upon_entry.cpp:83:11:83:16 | call to source |
| true_upon_entry.cpp:105:8:105:8 | x | true_upon_entry.cpp:98:11:98:16 | call to source |

View File

@@ -1,5 +1,27 @@
import IRDataflowTestCommon
from DataFlow::Node sink, DataFlow::Node source, TestAllocationConfig cfg
where cfg.hasFlow(source, sink)
select sink, source
class IRDataFlowTest extends InlineExpectationsTest {
IRDataFlowTest() { this = "IRDataFlowTest" }
override string getARelevantTag() { result = "ir" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
exists(DataFlow::Node source, DataFlow::Node sink, TestAllocationConfig conf, int n |
tag = "ir" and
conf.hasFlow(source, sink) and
n = strictcount(DataFlow::Node otherSource | conf.hasFlow(otherSource, sink)) and
(
n = 1 and value = ""
or
// If there is more than one source for this sink
// we specify the source location explicitly.
n > 1 and
value =
source.getLocation().getStartLine().toString() + ":" +
source.getLocation().getStartColumn()
) and
location = sink.getLocation() and
element = sink.toString()
)
}
}

View File

@@ -10,7 +10,7 @@ int test1() {
for (int i = 0; i < 10; i++) {
x = 0;
}
sink(x); // GOOD (x always overwritten)
sink(x); // $ SPURIOUS: ir
}
int test2(int iterations) {
@@ -18,7 +18,7 @@ int test2(int iterations) {
for (int i = 0; i < iterations; i++) {
x = 0;
}
sink(x); // BAD
sink(x); // $ ast,ir
}
int test3() {
@@ -26,7 +26,7 @@ int test3() {
for (int i = 0; i < 10; i++) {
x = source();
}
sink(x); // BAD
sink(x); // $ ast,ir
}
int test4() {
@@ -36,7 +36,7 @@ int test4() {
break;
x = 0;
}
sink(x); // BAD
sink(x); // $ ast,ir
}
int test5() {
@@ -46,7 +46,7 @@ int test5() {
continue;
x = 0;
}
sink(x); // BAD
sink(x); // $ ast,ir
}
int test6() {
@@ -54,7 +54,7 @@ int test6() {
int x = source();
for (int i = 0; i < 10 && (y = 1); i++) {
}
sink(x); // BAD
sink(x); // $ ast,ir
}
int test7() {
@@ -63,7 +63,7 @@ int test7() {
for (int i = 0; i < 10 && (y = 1); i++) {
x = 0;
}
sink(x); // GOOD
sink(x); // $ SPURIOUS: ir
}
int test8() {
@@ -75,7 +75,7 @@ int test8() {
// jump out of the condition, not just the last one.
for (int i = 0; i < 10 && (x = 1); i++) {
}
sink(x); // GOOD [false positive]
sink(x); // $ SPURIOUS: ast,ir
}
int test9() {
@@ -83,14 +83,14 @@ int test9() {
int x = source();
for (int i = 0; (y = 1) && i < 10; i++) {
}
sink(x); // BAD
sink(x); // $ ast,ir
}
int test10() {
int x = source();
for (int i = 0; (x = 1) && i < 10; i++) {
}
sink(x); // GOOD
sink(x); // no flow
}
int test10(int b, int d) {
@@ -102,5 +102,5 @@ int test10(int b, int d) {
x = 0;
L:
}
sink(x); // BAD
sink(x); // $ ir MISSING: ast
}