mirror of
https://github.com/github/codeql.git
synced 2026-04-29 02:35:15 +02:00
Merge branch 'master' into strcpy-fixups
This commit is contained in:
@@ -3,6 +3,8 @@ unexpectedOperand
|
||||
duplicateOperand
|
||||
missingPhiOperand
|
||||
instructionWithoutSuccessor
|
||||
ambiguousSuccessors
|
||||
unexplainedLoop
|
||||
unnecessaryPhiInstruction
|
||||
operandAcrossFunctions
|
||||
instructionWithoutUniqueBlock
|
||||
|
||||
@@ -3,6 +3,8 @@ unexpectedOperand
|
||||
duplicateOperand
|
||||
missingPhiOperand
|
||||
instructionWithoutSuccessor
|
||||
ambiguousSuccessors
|
||||
unexplainedLoop
|
||||
unnecessaryPhiInstruction
|
||||
operandAcrossFunctions
|
||||
instructionWithoutUniqueBlock
|
||||
|
||||
@@ -3,6 +3,8 @@ unexpectedOperand
|
||||
duplicateOperand
|
||||
missingPhiOperand
|
||||
instructionWithoutSuccessor
|
||||
ambiguousSuccessors
|
||||
unexplainedLoop
|
||||
unnecessaryPhiInstruction
|
||||
operandAcrossFunctions
|
||||
instructionWithoutUniqueBlock
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
@@ -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.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 |
|
||||
@@ -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
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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*
|
||||
|
||||
@@ -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];
|
||||
};
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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; }
|
||||
@@ -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. |
|
||||
@@ -0,0 +1 @@
|
||||
Likely Bugs/Conversion/LossyFunctionResultCast.ql
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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. |
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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. |
|
||||
|
||||
@@ -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)();
|
||||
};
|
||||
Reference in New Issue
Block a user