Merge branch 'master' into strcpy-fixups

This commit is contained in:
Jonas Jensen
2019-01-24 10:51:51 +01:00
committed by GitHub
1074 changed files with 32857 additions and 32773 deletions

View File

@@ -3,6 +3,8 @@ unexpectedOperand
duplicateOperand
missingPhiOperand
instructionWithoutSuccessor
ambiguousSuccessors
unexplainedLoop
unnecessaryPhiInstruction
operandAcrossFunctions
instructionWithoutUniqueBlock

View File

@@ -3,6 +3,8 @@ unexpectedOperand
duplicateOperand
missingPhiOperand
instructionWithoutSuccessor
ambiguousSuccessors
unexplainedLoop
unnecessaryPhiInstruction
operandAcrossFunctions
instructionWithoutUniqueBlock

View File

@@ -3,6 +3,8 @@ unexpectedOperand
duplicateOperand
missingPhiOperand
instructionWithoutSuccessor
ambiguousSuccessors
unexplainedLoop
unnecessaryPhiInstruction
operandAcrossFunctions
instructionWithoutUniqueBlock

File diff suppressed because it is too large Load Diff

View File

@@ -1,35 +0,0 @@
// query-type: graph
import cpp
import semmle.code.cpp.controlflow.internal.CFG
class DestructorCallEnhanced extends DestructorCall {
override string toString() {
if exists(this.getQualifier().(VariableAccess).getTarget().getName())
then result = "call to " + this.getQualifier().(VariableAccess).getTarget().getName() + "." + this.getTarget().getName()
else result = super.toString()
}
}
string scope(ControlFlowNode x) {
if exists(x.getControlFlowScope().getQualifiedName())
then result = x.getControlFlowScope().getQualifiedName()
else result = "<no scope>"
}
predicate isNode(boolean isEdge, ControlFlowNode x, ControlFlowNode y, string label) {
isEdge = false and x = y and label = x.toString()
}
predicate isSuccessor(boolean isEdge, ControlFlowNode x, ControlFlowNode y, string label) {
exists(string truelabel, string falselabel |
isEdge = true
and qlCFGSuccessor(x, y)
and if qlCFGTrueSuccessor(x, y) then truelabel = "T" else truelabel = ""
and if qlCFGFalseSuccessor(x, y) then falselabel = "F" else falselabel = ""
and label = truelabel + falselabel)
}
from boolean isEdge, ControlFlowNode x, ControlFlowNode y, string label
where isNode(isEdge, x, y, label) or isSuccessor(isEdge, x, y, label)
select scope(x), isEdge, x, y, label

View File

@@ -36,3 +36,23 @@ void destructor_catch() {
HasDtor d2 = { 0 };
}
}
namespace cond_destruct {
struct C {
C();
C(const C&) = delete;
~C();
int getInt() const;
void *data;
};
int f(int x) {
C local;
const C &ref = x ? (const C&)C() : (const C&)local;
return ref.getInt();
// If `x` was true, `ref` refers to a temporary object whose lifetime was
// extended to coincide with `ref`. Before the function returns, it
// should destruct `ref` if and only if the first branch was taken in the
// ?: expression.
}
}

View File

@@ -0,0 +1,70 @@
template <typename T>
class vector {
public:
T& operator[](int);
const T& operator[](int) const;
};
int test1(vector<int> vec, int b) {
int x = -1;
if (b) {
x = vec[3];
}
return x;
}
// Regression test for ODASA-6013.
int test2(int x) {
int x0 = static_cast<char>(x);
return x0;
}
// Tests for conversion to bool
bool test3(bool b, int x, int y) {
// The purpose the assignments to `x` below is to generate a lot of
// potential upper and lower bounds for `x`, so that the logic in
// boolConversionLowerBound and boolConversionUpperBound gets exercized.
if (y == 0) {
x = 0;
}
if (y == -1) {
x = -1;
}
if (y == 1) {
x = 1;
}
if (y == -128) {
x = -128;
}
if (y == 128) {
x = 128;
}
if (y == -1024) {
x = -1024;
}
if (y == 1024) {
x = 1024;
}
int t = 0;
if (x == 0) {
bool xb = (bool)x; // (bool)x == false
t += (int)xb;
}
if (x > 0) {
bool xb = (bool)x; // (bool)x == true
t += (int)xb;
}
if (x < 0) {
bool xb = (bool)x; // (bool)x == true
t += (int)xb;
}
bool xb = (bool)x; // Value of (bool)x is unknown.
t += (int)xb;
return b || (bool)t;
}

View File

@@ -0,0 +1,56 @@
| test.cpp:10:10:10:10 | Store: x | test.cpp:6:15:6:15 | InitializeParameter: x | 0 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 |
| test.cpp:10:10:10:10 | Store: x | test.cpp:6:22:6:22 | InitializeParameter: y | 0 | false | CompareLT: ... < ... | test.cpp:7:7:7:11 | test.cpp:7:7:7:11 |
| test.cpp:10:10:10:10 | Store: x | test.cpp:6:22:6:22 | InitializeParameter: y | 0 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 |
| test.cpp:20:10:20:10 | Store: x | test.cpp:14:15:14:15 | InitializeParameter: x | -2 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 |
| test.cpp:20:10:20:10 | Store: x | test.cpp:14:22:14:22 | InitializeParameter: y | -2 | false | CompareLT: ... < ... | test.cpp:15:7:15:11 | test.cpp:15:7:15:11 |
| test.cpp:27:10:27:10 | Load: i | file://:0:0:0:0 | 0 | 0 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 |
| test.cpp:27:10:27:10 | Load: i | test.cpp:24:15:24:15 | InitializeParameter: x | -1 | true | CompareLT: ... < ... | test.cpp:26:14:26:18 | test.cpp:26:14:26:18 |
| test.cpp:30:10:30:10 | Load: i | file://:0:0:0:0 | 0 | 1 | false | CompareGT: ... > ... | test.cpp:29:14:29:18 | test.cpp:29:14:29:18 |
| test.cpp:30:10:30:10 | Load: i | test.cpp:24:15:24:15 | InitializeParameter: x | 0 | true | NoReason | file://:0:0:0:0 | file://:0:0:0:0 |
| test.cpp:30:10:30:10 | Load: i | test.cpp:26:14:26:14 | Phi: i | 0 | true | CompareLT: ... < ... | test.cpp:26:14:26:18 | test.cpp:26:14:26:18 |
| test.cpp:33:10:33:10 | Load: i | file://:0:0:0:0 | 0 | 0 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 |
| test.cpp:33:10:33:10 | Load: i | test.cpp:24:15:24:15 | InitializeParameter: x | 1 | true | CompareLT: ... < ... | test.cpp:32:14:32:22 | test.cpp:32:14:32:22 |
| test.cpp:33:10:33:10 | Load: i | test.cpp:26:14:26:14 | Phi: i | 1 | true | CompareLT: ... < ... | test.cpp:32:14:32:22 | test.cpp:32:14:32:22 |
| test.cpp:33:10:33:10 | Load: i | test.cpp:29:14:29:14 | Phi: i | 0 | false | CompareGT: ... > ... | test.cpp:29:14:29:18 | test.cpp:29:14:29:18 |
| test.cpp:40:10:40:14 | Load: begin | test.cpp:38:16:38:20 | InitializeParameter: begin | 0 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 |
| test.cpp:40:10:40:14 | Load: begin | test.cpp:38:28:38:30 | InitializeParameter: end | -1 | true | CompareLT: ... < ... | test.cpp:39:10:39:20 | test.cpp:39:10:39:20 |
| test.cpp:49:12:49:12 | Load: x | test.cpp:46:22:46:22 | InitializeParameter: y | -1 | true | CompareLT: ... < ... | test.cpp:48:9:48:13 | test.cpp:48:9:48:13 |
| test.cpp:49:12:49:12 | Load: x | test.cpp:46:29:46:29 | InitializeParameter: z | -2 | true | CompareLT: ... < ... | test.cpp:48:9:48:13 | test.cpp:48:9:48:13 |
| test.cpp:54:12:54:12 | Load: x | test.cpp:46:22:46:22 | InitializeParameter: y | -1 | true | CompareLT: ... < ... | test.cpp:52:7:52:11 | test.cpp:52:7:52:11 |
| test.cpp:62:10:62:13 | Load: iter | test.cpp:60:17:60:17 | InitializeParameter: p | 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 | InitializeParameter: p | 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 | Convert: (char *)... | -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 | InitializeParameter: p | 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 | InitializeParameter: p | 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 | Phi: iter | -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 | Convert: (char *)... | -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 | InitializeParameter: x | -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 | InitializeParameter: y | -1 | true | CompareLT: ... < ... | test.cpp:76:20:76:24 | test.cpp:76:20:76:24 |
| test.cpp:85:10:85:10 | Load: x | file://:0:0:0:0 | 0 | 2 | false | CompareGT: ... > ... | test.cpp:84:7:84:11 | test.cpp:84:7:84:11 |
| test.cpp:87:10:87:10 | Load: x | file://:0:0:0:0 | 0 | 1 | true | CompareGT: ... > ... | test.cpp:84:7:84:11 | test.cpp:84:7:84:11 |
| test.cpp:90:10:90:10 | Load: x | file://:0:0:0:0 | 0 | 1 | false | CompareGE: ... >= ... | test.cpp:89:7:89:12 | test.cpp:89:7:89:12 |
| test.cpp:92:10:92:10 | Load: x | file://:0:0:0:0 | 0 | 0 | true | CompareGE: ... >= ... | test.cpp:89:7:89:12 | test.cpp:89:7:89:12 |
| test.cpp:95:10:95:10 | Load: x | file://:0:0:0:0 | 0 | 0 | true | CompareLT: ... < ... | test.cpp:94:7:94:11 | test.cpp:94:7:94:11 |
| test.cpp:97:10:97:10 | Load: x | file://:0:0:0:0 | 0 | 1 | false | CompareLT: ... < ... | test.cpp:94:7:94:11 | test.cpp:94:7:94:11 |
| test.cpp:100:10:100:10 | Load: x | file://:0:0:0:0 | 0 | 1 | true | CompareLE: ... <= ... | test.cpp:99:7:99:12 | test.cpp:99:7:99:12 |
| test.cpp:102:10:102:10 | Load: x | file://:0:0:0:0 | 0 | 2 | false | CompareLE: ... <= ... | test.cpp:99:7:99:12 | test.cpp:99:7:99:12 |
| test.cpp:107:5:107:10 | Phi: test10 | test.cpp:114:3:114:6 | Phi: call to sink | -1 | true | CompareLT: ... < ... | test.cpp:115:18:115:22 | test.cpp:115:18:115:22 |
| test.cpp:140:10:140:10 | Store: i | file://:0:0:0:0 | 0 | 1 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 |
| test.cpp:140:10:140:10 | Store: i | test.cpp:135:16:135:16 | InitializeParameter: x | 0 | false | CompareLT: ... < ... | test.cpp:139:11:139:15 | test.cpp:139:11:139:15 |
| test.cpp:140:10:140:10 | Store: i | test.cpp:138:5:138:5 | Phi: i | 1 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 |
| test.cpp:140:10:140:10 | Store: i | test.cpp:138:5:138:5 | Phi: i | 1 | true | NoReason | file://:0:0:0:0 | file://:0:0:0:0 |
| test.cpp:156:12:156:12 | Load: x | test.cpp:153:23:153:23 | InitializeParameter: y | -1 | false | CompareEQ: ... == ... | test.cpp:155:9:155:16 | test.cpp:155:9:155:16 |
| test.cpp:156:12:156:12 | Load: x | test.cpp:153:23:153:23 | InitializeParameter: y | -1 | true | CompareEQ: ... == ... | test.cpp:155:9:155:16 | test.cpp:155:9:155:16 |
| test.cpp:156:12:156:12 | Load: x | test.cpp:153:23:153:23 | InitializeParameter: y | -1 | true | CompareLT: ... < ... | test.cpp:154:6:154:10 | test.cpp:154:6:154:10 |
| test.cpp:158:12:158:12 | Load: x | test.cpp:153:23:153:23 | InitializeParameter: y | -2 | true | CompareEQ: ... == ... | test.cpp:155:9:155:16 | test.cpp:155:9:155:16 |
| test.cpp:158:12:158:12 | Load: x | test.cpp:153:23:153:23 | InitializeParameter: y | -2 | true | CompareLT: ... < ... | test.cpp:154:6:154:10 | test.cpp:154:6:154:10 |
| test.cpp:161:12:161:12 | Load: x | test.cpp:153:23:153:23 | InitializeParameter: y | -2 | true | CompareLT: ... < ... | test.cpp:154:6:154:10 | test.cpp:154:6:154:10 |
| test.cpp:161:12:161:12 | Load: x | test.cpp:153:23:153:23 | InitializeParameter: y | -2 | true | CompareNE: ... != ... | test.cpp:160:9:160:16 | test.cpp:160:9:160:16 |
| test.cpp:163:12:163:12 | Load: x | test.cpp:153:23:153:23 | InitializeParameter: y | -1 | false | CompareNE: ... != ... | test.cpp:160:9:160:16 | test.cpp:160:9:160:16 |
| test.cpp:163:12:163:12 | Load: x | test.cpp:153:23:153:23 | InitializeParameter: y | -1 | true | CompareLT: ... < ... | test.cpp:154:6:154:10 | test.cpp:154:6:154:10 |
| test.cpp:163:12:163:12 | Load: x | test.cpp:153:23:153:23 | InitializeParameter: y | -1 | true | CompareNE: ... != ... | test.cpp:160:9:160:16 | test.cpp:160:9:160:16 |
| test.cpp:167:12:167:12 | Load: x | test.cpp:153:23:153:23 | InitializeParameter: y | 0 | false | CompareLT: ... < ... | test.cpp:154:6:154:10 | test.cpp:154:6:154:10 |
| test.cpp:167:12:167:12 | Load: x | test.cpp:153:23:153:23 | InitializeParameter: y | 1 | false | CompareEQ: ... == ... | test.cpp:166:9:166:16 | test.cpp:166:9:166:16 |
| test.cpp:167:12:167:12 | Load: x | test.cpp:153:23:153:23 | InitializeParameter: y | 1 | true | CompareEQ: ... == ... | test.cpp:166:9:166:16 | test.cpp:166:9:166:16 |
| test.cpp:169:12:169:12 | Load: x | test.cpp:153:23:153:23 | InitializeParameter: y | 0 | false | CompareLT: ... < ... | test.cpp:154:6:154:10 | test.cpp:154:6:154:10 |

View File

@@ -0,0 +1,25 @@
import semmle.code.cpp.rangeanalysis.RangeAnalysis
import semmle.code.cpp.ir.IR
import semmle.code.cpp.controlflow.IRGuards
import semmle.code.cpp.ir.ValueNumbering
query predicate instructionBounds(Instruction i, Bound b, int delta, boolean upper, Reason reason,
Location reasonLoc)
{
(
i.getAUse() instanceof ArgumentOperand
or
i.getAUse() instanceof ReturnValueOperand
) and
(
upper = true and
delta = min(int d | boundedInstruction(i, b, d, upper, reason))
or
upper = false and
delta = max(int d | boundedInstruction(i, b, d, upper, reason))
) and
not valueNumber(b.getInstruction()) = valueNumber(i)
and if reason instanceof CondReason
then reasonLoc = reason.(CondReason).getCond().getLocation()
else reasonLoc instanceof UnknownDefaultLocation
}

View File

@@ -1,70 +1,172 @@
template <typename T>
class vector {
public:
T& operator[](int);
const T& operator[](int) const;
};
int test1(vector<int> vec, int b) {
int x = -1;
if (b) {
x = vec[3];
void sink(...);
int source();
// Guards, inference, critical edges
int test1(int x, int y) {
if (x < y) {
x = y;
}
return x;
}
// Regression test for ODASA-6013.
int test2(int x) {
int x0 = static_cast<char>(x);
return x0;
// Bounds mergers at phi nodes
int test2(int x, int y) {
if (x < y) {
x = y;
} else {
x = x-2;
}
return x;
}
// Tests for conversion to bool
bool test3(bool b, int x, int y) {
// The purpose the assignments to `x` below is to generate a lot of
// potential upper and lower bounds for `x`, so that the logic in
// boolConversionLowerBound and boolConversionUpperBound gets exercized.
if (y == 0) {
x = 0;
// for loops
int test3(int x) {
int i;
for(i = 0; i < x; i++) {
sink(i);
}
if (y == -1) {
x = -1;
for(i = x; i > 0; i--) {
sink(i);
}
if (y == 1) {
x = 1;
for(i = 0; i < x + 2; i++) {
sink(i);
}
}
// pointer bounds
int test4(int *begin, int *end) {
while (begin < end) {
sink(begin);
begin++;
}
}
// bound propagation through conditionals
int test5(int x, int y, int z) {
if (y < z) {
if (x < y) {
sink(x);
}
}
if (x < y) {
if (y < z) {
sink(x); // x < z is not inferred here
}
}
}
// pointer arithmetic and sizes
void test6(int *p) {
for (char *iter = (char *)p; iter < (char *)(p+1); iter++) {
sink(iter);
}
char *end = (char *)(p+1);
for (char *iter = (char *)p; iter < end; iter++) {
sink(iter);
}
}
// inference from equality
int test8(int x, int y) {
int *p = new int[x];
if (x == y) {
for(int i = 0; i < y; ++i) {
sink(i);
}
}
}
// >, >=, <=
void test9(int x) {
if (x > 1) {
sink(x);
} else {
sink(x);
}
if (x >= 1) {
sink(x);
} else {
sink(x);
}
if (x < 1) {
sink(x);
} else {
sink(x);
}
if (x <= 1) {
sink(x);
} else {
sink(x);
}
}
// Phi nodes as bounds
int test10(int y, int z, bool use_y) {
int x;
if(use_y) {
x = y;
} else {
x = z;
}
sink();
for(int i = 0; i < x; i++) {
return i;
}
}
// Irreducible CFGs
int test11(int y, int x) {
int i = 0;
if (x < y) {
x = y;
} else {
goto inLoop;
}
for(i = 0; i < x; i++) {
inLoop:
sink(i);
}
}
// do-while
int test12(int x) {
int i = 0;
do {
i++;
} while(i < x);
return i;
}
// do while false
int test13(int x) {
int i = 0;
do {
i++;
} while(false);
return i;
}
// unequal bound narrowing
int test14(int x, int y) {
if(x < y) {
if (x == y-1) {
sink(x);
} else {
sink(x);
}
if (x != y-1) {
sink(x);
} else {
sink(x);
}
} else {
if (y == x-1) {
sink(x);
} else {
sink(x);
}
}
if (y == -128) {
x = -128;
}
if (y == 128) {
x = 128;
}
if (y == -1024) {
x = -1024;
}
if (y == 1024) {
x = 1024;
}
int t = 0;
if (x == 0) {
bool xb = (bool)x; // (bool)x == false
t += (int)xb;
}
if (x > 0) {
bool xb = (bool)x; // (bool)x == true
t += (int)xb;
}
if (x < 0) {
bool xb = (bool)x; // (bool)x == true
t += (int)xb;
}
bool xb = (bool)x; // Value of (bool)x is unknown.
t += (int)xb;
return b || (bool)t;
}

View File

@@ -65,9 +65,9 @@
| test.c:34:5:34:14 | Store: ... += ... | positive |
| test.c:34:14:34:14 | Load: i | positive |
| test.c:36:10:36:14 | Load: total | positive |
| test.c:36:10:36:18 | Add: ... + ... | positive |
| test.c:36:10:36:18 | Store: ... + ... | positive |
| test.c:36:18:36:18 | Load: i | positive |
| test.c:36:10:36:18 | Add: ... + ... | positive strictlyPositive |
| test.c:36:10:36:18 | Store: ... + ... | positive strictlyPositive |
| test.c:36:18:36:18 | Load: i | positive strictlyPositive |
| test.c:42:15:42:15 | Load: i | positive |
| test.c:42:15:42:15 | Phi: i | positive |
| test.c:42:15:42:15 | Phi: i | positive |
@@ -81,9 +81,9 @@
| test.c:43:5:43:14 | Store: ... += ... | positive |
| test.c:43:14:43:14 | Load: i | positive |
| test.c:45:10:45:14 | Load: total | positive |
| test.c:45:10:45:18 | Add: ... + ... | positive |
| test.c:45:10:45:18 | Store: ... + ... | positive |
| test.c:45:18:45:18 | Load: i | positive |
| test.c:45:10:45:18 | Add: ... + ... | positive strictlyPositive |
| test.c:45:10:45:18 | Store: ... + ... | positive strictlyPositive |
| test.c:45:18:45:18 | Load: i | positive strictlyPositive |
| test.c:51:15:51:15 | Load: i | positive |
| test.c:51:15:51:15 | Phi: i | positive |
| test.c:51:15:51:15 | Phi: i | positive |
@@ -448,10 +448,10 @@
| test.c:343:5:343:7 | Constant: ... ++ | positive strictlyPositive |
| test.c:343:5:343:7 | Load: ... ++ | positive |
| test.c:343:5:343:7 | Store: ... ++ | positive strictlyPositive |
| test.c:345:3:345:7 | Store: ... = ... | positive |
| test.c:345:7:345:7 | Load: i | positive |
| test.c:345:3:345:7 | Store: ... = ... | positive strictlyPositive |
| test.c:345:7:345:7 | Load: i | positive strictlyPositive |
| test.c:346:7:346:7 | Load: x | positive |
| test.c:347:9:347:9 | Load: d | positive |
| test.c:347:9:347:9 | Load: d | positive strictlyPositive |
| test.c:348:14:348:14 | Constant: 1 | positive strictlyPositive |
| test.c:348:14:348:14 | Store: 1 | positive strictlyPositive |
| test.c:355:42:355:42 | InitializeParameter: x | positive |
@@ -674,6 +674,8 @@
| test.cpp:45:12:45:15 | Constant: 1024 | positive strictlyPositive |
| test.cpp:46:5:46:12 | Store: ... = ... | positive strictlyPositive |
| test.cpp:46:9:46:12 | Constant: 1024 | positive strictlyPositive |
| test.cpp:57:21:57:21 | Load: x | positive strictlyPositive |
| test.cpp:62:21:62:21 | Load: x | negative strictlyNegative |
| test.cpp:69:10:69:21 | Constant: ... \|\| ... | positive strictlyPositive |
| test.cpp:69:10:69:21 | Load: ... \|\| ... | positive |
| test.cpp:69:10:69:21 | Phi: ... \|\| ... | positive |

View File

@@ -365,7 +365,7 @@ test.cpp:
# 53| Block 1
# 53| m1_0(unsigned int) = Phi : from 0:m0_11, from 8:m8_4
# 53| valnum = unique
# 53| valnum = m1_0
# 53| r1_1(glval<char *>) = VariableAddress[str] :
# 53| valnum = r0_3
# 53| r1_2(char *) = Load : r1_1, m0_4
@@ -395,11 +395,11 @@ test.cpp:
# 56| Block 3
# 56| m3_0(char *) = Phi : from 2:m2_3, from 5:m5_4
# 56| valnum = unique
# 56| valnum = m3_0
# 56| r3_1(glval<char *>) = VariableAddress[ptr] :
# 56| valnum = r0_7
# 56| r3_2(char *) = Load : r3_1, m3_0
# 56| valnum = unique
# 56| valnum = m3_0
# 56| r3_3(char) = Load : r3_2, m0_1
# 56| valnum = unique
# 56| r3_4(int) = Convert : r3_3
@@ -422,7 +422,7 @@ test.cpp:
# 56| r4_0(glval<char *>) = VariableAddress[ptr] :
# 56| valnum = r0_7
# 56| r4_1(char *) = Load : r4_0, m3_0
# 56| valnum = unique
# 56| valnum = m3_0
# 56| r4_2(char) = Load : r4_1, m0_1
# 56| valnum = unique
# 56| r4_3(int) = Convert : r4_2
@@ -439,7 +439,7 @@ test.cpp:
# 56| r5_0(glval<char *>) = VariableAddress[ptr] :
# 56| valnum = r0_7
# 56| r5_1(char *) = Load : r5_0, m3_0
# 56| valnum = unique
# 56| valnum = m3_0
# 56| r5_2(int) = Constant[1] :
# 56| valnum = unique
# 56| r5_3(char *) = PointerAdd[1] : r5_1, r5_2
@@ -452,7 +452,7 @@ test.cpp:
# 59| r6_0(glval<char *>) = VariableAddress[ptr] :
# 59| valnum = r0_7
# 59| r6_1(char *) = Load : r6_0, m3_0
# 59| valnum = unique
# 59| valnum = m3_0
# 59| r6_2(char) = Load : r6_1, m0_1
# 59| valnum = unique
# 59| r6_3(int) = Convert : r6_2
@@ -473,7 +473,7 @@ test.cpp:
# 62| r8_0(glval<unsigned int>) = VariableAddress[result] :
# 62| valnum = r0_9
# 62| r8_1(unsigned int) = Load : r8_0, m1_0
# 62| valnum = unique
# 62| valnum = m1_0
# 62| r8_2(unsigned int) = Constant[1] :
# 62| valnum = unique
# 62| r8_3(unsigned int) = Add : r8_1, r8_2
@@ -489,9 +489,9 @@ test.cpp:
# 65| r9_2(glval<unsigned int>) = VariableAddress[result] :
# 65| valnum = r0_9
# 65| r9_3(unsigned int) = Load : r9_2, m1_0
# 65| valnum = r9_3
# 65| valnum = m1_0
# 65| m9_4(unsigned int) = Store : r9_1, r9_3
# 65| valnum = r9_3
# 65| valnum = m1_0
# 49| r9_5(glval<unsigned int>) = VariableAddress[#return] :
# 49| valnum = r9_1
# 49| v9_6(void) = ReturnValue : r9_5, m9_4
@@ -639,15 +639,15 @@ test.cpp:
# 88| Block 3
# 88| m3_0(int) = Phi : from 1:m1_3, from 2:m2_3
# 88| valnum = unique
# 88| valnum = m3_0
# 88| r3_1(glval<int>) = VariableAddress[#temp88:7] :
# 88| valnum = r1_2
# 88| r3_2(int) = Load : r3_1, m3_0
# 88| valnum = r3_2
# 88| valnum = m3_0
# 88| r3_3(glval<int>) = VariableAddress[v] :
# 88| valnum = r0_9
# 88| m3_4(int) = Store : r3_3, r3_2
# 88| valnum = r3_2
# 88| valnum = m3_0
# 89| v3_5(void) = NoOp :
# 84| v3_6(void) = ReturnVoid :
# 84| v3_7(void) = UnmodeledUse : mu*

View File

@@ -44,3 +44,11 @@ void myFunction2(mySmallStruct *a, myLargeStruct *b) // GOOD
void myFunction3(mySmallStruct &a, myLargeStruct &b) // GOOD
{
}
struct CustomAssignmentOp {
// GOOD: it's an accepted pattern to implement copy assignment via copy and
// swap. This delegates the resource management involved in copying to the
// copy constructor so that logic only has to be written once.
CustomAssignmentOp &operator=(CustomAssignmentOp rhs);
char data[4096];
};

View File

@@ -1,3 +1,6 @@
| test2.cpp:37:1:37:39 | // int myFunction() { return myValue; } | This comment appears to contain commented-out code |
| test2.cpp:39:1:39:45 | // int myFunction() const { return myValue; } | This comment appears to contain commented-out code |
| test2.cpp:41:1:41:54 | // int myFunction() const noexcept { return myValue; } | This comment appears to contain commented-out code |
| test.c:2:1:2:22 | // commented out code; | This comment appears to contain commented-out code |
| test.c:4:1:7:8 | // some; | This comment appears to contain commented-out code |
| test.c:9:1:13:8 | // also; | This comment appears to contain commented-out code |

View File

@@ -0,0 +1,41 @@
/*
* This sentence contains a semicolon;
* however, this doesn't make it code.
*/
// This sentence contains a semicolon;
// however, this doesn't make it code.
/* Mention a ';' */
/* Mention a '{' */
/* JSON example: {"foo":"bar"} */
/* JSON example in backticks: `{"foo":"bar"}` */
/* JSON example in quotes: '{"foo":"bar"}' */
/*
* Code example: `return 0;`.
*/
// Code example:
//
// return 0;
// Code example:
//
// ```
// return 0;
// ```
// { 1, 2, 3, 4 }
// Example: { 1, 2, 3, 4 }
// int myFunction() { return myValue; }
// int myFunction() const { return myValue; }
// int myFunction() const noexcept { return myValue; }

View File

@@ -0,0 +1,9 @@
| test.cpp:33:6:33:13 | call to getFloat | Return value of type float is implicitly converted to bool here. |
| test.cpp:35:13:35:20 | call to getFloat | Return value of type float is implicitly converted to int here. |
| test.cpp:38:6:38:14 | call to getDouble | Return value of type double is implicitly converted to bool here. |
| test.cpp:40:13:40:21 | call to getDouble | Return value of type double is implicitly converted to int here. |
| test.cpp:43:6:43:12 | call to getMyLD | Return value of type long double is implicitly converted to bool here. |
| test.cpp:45:13:45:19 | call to getMyLD | Return value of type long double is implicitly converted to int here. |
| test.cpp:101:10:101:12 | call to pow | Return value of type double is implicitly converted to int here. |
| test.cpp:103:10:103:12 | call to pow | Return value of type double is implicitly converted to int here. |
| test.cpp:105:10:105:12 | call to pow | Return value of type double is implicitly converted to int here. |

View File

@@ -0,0 +1 @@
Likely Bugs/Conversion/LossyFunctionResultCast.ql

View File

@@ -0,0 +1,131 @@
typedef long double MYLD;
bool getBool();
int getInt();
float getFloat();
double getDouble();
MYLD getMyLD();
float *getFloatPtr();
float &getFloatRef();
const float &getConstFloatRef();
void setPosInt(int x);
void setPosFloat(float x);
double round(double x);
float roundf(float x);
void test1()
{
// simple
if (getBool())
{
setPosInt(getBool());
setPosFloat(getBool());
}
if (getInt())
{
setPosInt(getInt());
setPosFloat(getInt());
}
if (getFloat()) // BAD
{
setPosInt(getFloat()); // BAD
setPosFloat(getFloat());
}
if (getDouble()) // BAD
{
setPosInt(getDouble()); // BAD
setPosFloat(getDouble());
}
if (getMyLD()) // BAD
{
setPosInt(getMyLD()); // BAD
setPosFloat(getMyLD());
}
if (getFloatPtr())
{
// ...
}
if (getFloatRef()) // BAD [NOT DETECTED]
{
setPosInt(getFloatRef()); // BAD [NOT DETECTED]
setPosFloat(getFloatRef());
}
if (getConstFloatRef()) // BAD [NOT DETECTED]
{
setPosInt(getConstFloatRef()); // BAD [NOT DETECTED]
setPosFloat(getConstFloatRef());
}
// explicit cast
if ((bool)getInt())
{
setPosInt(getInt());
setPosFloat((float)getInt());
}
if ((bool)getFloat())
{
setPosInt((int)getFloat());
setPosFloat(getFloat());
}
// explicit rounding
if (roundf(getFloat()))
{
setPosInt(roundf(getFloat()));
setPosFloat(roundf(getFloat()));
}
if (round(getDouble()))
{
setPosInt(round(getDouble()));
setPosFloat(round(getDouble()));
}
}
double pow(double x, double y);
int test2(double v, double w, int n)
{
switch (n)
{
case 1:
return pow(2, v); // GOOD
case 2:
return pow(10, v); // GOOD
case 3:
return pow(2.5, v); // BAD
case 4:
return pow(v, 2); // BAD
case 5:
return pow(v, w); // BAD
};
}
double myRound1(double v)
{
return round(v);
}
double myRound2(double v)
{
double result = round(v);
return result;
}
double myRound3(double v)
{
return (v > 0) ? round(v) : 0;
}
void test3()
{
int i = myRound1(1.5); // GOOD
int j = myRound2(2.5); // GOOD
int k = myRound3(3.5); // GOOD
}

View File

@@ -64,3 +64,45 @@ void testFunc2()
MyAssignable v1, v2;
v2 = v1;
}
namespace std {
typedef unsigned long size_t;
}
void* operator new (std::size_t size, void* ptr) noexcept;
struct Base {
Base() { }
Base &operator=(const Base &rhs) {
return *this;
}
virtual ~Base() { }
};
struct Derived : Base {
Derived &operator=(const Derived &rhs) {
if (&rhs == this) {
return *this;
}
// In case base class has data, now or in the future, copy that first.
Base::operator=(rhs); // GOOD
this->m_x = rhs.m_x;
return *this;
}
int m_x;
};
void use_Base() {
Base base_buffer[1];
Base *base = new(&base_buffer[0]) Base();
// In case the destructor does something, now or in the future, call it. It
// won't get called automatically because the object was allocated with
// placement new.
base->~Base(); // GOOD (because the call has void type)
}

View File

@@ -4,3 +4,4 @@
| test.cpp:30:25:30:35 | sizeof(int) | Suspicious sizeof offset in a pointer arithmetic expression. The type of the pointer is int *. |
| test.cpp:38:30:38:40 | sizeof(int) | Suspicious sizeof offset in a pointer arithmetic expression. The type of the pointer is int *. |
| test.cpp:61:27:61:37 | sizeof(int) | Suspicious sizeof offset in a pointer arithmetic expression. The type of the pointer is int *. |
| test.cpp:89:43:89:55 | sizeof(MyABC) | Suspicious sizeof offset in a pointer arithmetic expression. The type of the pointer is myInt *const. |

View File

@@ -64,3 +64,32 @@ void test7(int i) {
v = *(int *)(voidPointer + i); // GOOD (actually rather dubious, but this could be correct code)
v = *(int *)(voidPointer + (i * sizeof(int))); // GOOD
}
typedef unsigned long size_t;
void *malloc(size_t size);
class MyABC
{
public:
int a, b, c;
};
typedef unsigned char myChar;
typedef unsigned int myInt;
class MyTest8Class
{
public:
MyTest8Class() :
myCharsPointer((myChar *)malloc(sizeof(MyABC) * 2)),
myIntsPointer((myInt *)malloc(sizeof(MyABC) * 2))
{
myChar *secondPtr = myCharsPointer + sizeof(MyABC); // GOOD
myInt *secondPtrInt = myIntsPointer + sizeof(MyABC); // BAD
}
private:
myChar * const myCharsPointer;
myInt * const myIntsPointer;
};

View File

@@ -10,6 +10,7 @@
| DeleteThis.cpp:60:3:60:24 | ... = ... | Resource ptr14 is acquired by class MyClass3 but not released anywhere in this class. |
| DeleteThis.cpp:127:3:127:20 | ... = ... | Resource d is acquired by class MyClass9 but not released anywhere in this class. |
| ExternalOwners.cpp:49:3:49:20 | ... = ... | Resource a is acquired by class MyScreen but not released anywhere in this class. |
| Lambda.cpp:24:3:24:21 | ... = ... | Resource r4 is acquired by class testLambda but not released anywhere in this class. |
| ListDelete.cpp:21:3:21:21 | ... = ... | Resource first is acquired by class MyThingColection but not released anywhere in this class. |
| NoDestructor.cpp:23:3:23:20 | ... = ... | Resource n is acquired by class MyClass5 but not released anywhere in this class. |
| PlacementNew.cpp:36:3:36:36 | ... = ... | Resource p1 is acquired by class MyTestForPlacementNew but not released anywhere in this class. |

View File

@@ -0,0 +1,56 @@
class testLambda
{
public:
testLambda()
{
r1 = new char[4096]; // GOOD
deleter1 = [](char *r) {
delete [] r;
};
r2 = new char[4096]; // GOOD
auto deleter2 = [this]() {
delete [] r2;
};
deleter2();
r3 = new char[4096]; // GOOD
auto deleter3 = [&r = r3]() {
delete [] r;
};
deleter3();
r4 = new char[4096]; // BAD
r5 = new char[4096]; // GOOD
deleter5 = &deleter_for_r5;
r6 = new char[4096]; // GOOD
deleter6 = &testLambda::deleter_for_r6;
}
static void deleter_for_r5(char *r)
{
delete [] r;
}
void deleter_for_r6()
{
delete [] r6;
}
~testLambda()
{
deleter1(r1);
deleter5(r5);
((*this).*deleter6)();
}
private:
char *r1, *r2, *r3, *r4, *r5, *r6;
void (*deleter1)(char *r);
void (*deleter5)(char *r);
void (testLambda::*deleter6)();
};