Files
codeql/cpp/ql/test/library-tests/controlflow/guards/test.cpp
Mathias Vorreiter Pedersen b2269fb5f5 C++: Add more tests.
2025-09-24 19:06:02 +01:00

419 lines
6.1 KiB
C++

class X
{
public:
void set();
};
class Y
{
public:
Y* f();
const X* get() const { return 0; }
X* get() { return 0; }
};
Y* Y::f()
{
if ( get() )
get()->set();
return 0;
}
class Error {
public:
Error() {}
};
bool getABool();
void doSomething(int x) {
if (x == -1) {
throw new Error();
}
}
void doSomethingElse(int x);
bool testWithCatch0(int v)
{
try
{
if( getABool() )
{
doSomething(v);
return true;
}
}
catch(Error &e)
{
doSomethingElse(v);
}
return false;
}
void use1(int);
void use2(int);
void use3(int);
void test_switches_simple(int i) {
switch(i) {
case 0:
use1(i);
break;
case 1:
use2(i);
/* NOTE: fallthrough */
case 2:
use3(i);
}
}
void test_switches_range(int i) {
switch(i) {
case 0 ... 10:
use1(i);
break;
case 11 ... 20:
use2(i);
}
}
void test_switches_default(int i) {
switch(i) {
default:
use1(i);
}
}
void use(...);
void pointer_comparison(char* c) {
if(c) {
use(c);
}
}
void implicit_float_comparison(float f) {
if(f) {
use(f);
}
}
void explicit_float_comparison(float f) {
if(f != 0.0f) {
use(f);
}
}
void int_float_comparison(int i) {
if(i != 0.0f) {
use(i);
}
}
int source();
bool safe(int);
void test(bool b)
{
int x;
if (b)
{
x = source();
if (!safe(x)) return;
}
use(x);
}
void binary_test_builtin_expected(int a, int b) {
if(__builtin_expect(a == b + 42, 0)) {
use(a);
}
if(__builtin_expect(a != b + 42, 0)) {
use(a);
}
}
void unary_test_builtin_expected(int a) {
if(__builtin_expect(a == 42, 0)) {
use(a);
}
if(__builtin_expect(a != 42, 0)) {
use(a);
}
}
void test_with_reference(bool& b, int a) {
b = a < 10;
if(!b) {
use(a);
}
}
void test_with_negated_binary_equality(int a, int b) {
bool c = a != b;
if (!c) {
}
}
void test_with_negated_unary_relational(int a) {
bool b = a > 10;
if (!b) {
}
}
void test_with_negated_binary_relational(int a, int b) {
bool c = a > b;
if (!c) {
}
}
void test_logical_and(bool b1, bool b2) {
if(!(b1 && b2)) {
use(b1);
use(b2);
} else {
// b1 = true and b2 = true
use(b1);
use(b2);
}
}
void test_logical_or(bool b1, bool b2) {
if(!(b1 || b2)) {
// b1 = false and b2 = false
use(b1);
use(b2);
} else {
use(b1);
use(b2);
}
}
struct Mystruct {
int i;
float f;
};
int test_types(signed char sc, unsigned long ul, float f, double d, bool b, Mystruct &ms) {
int ctr = 0;
if (sc == 0) {
ctr++;
}
if (sc == 0x0) {
ctr++;
}
if (ul == 0) {
ctr++;
}
if (f == 0) {
ctr++;
}
if (f == 0.0) {
ctr++;
}
if (d == 0) {
ctr++;
}
if (b == 0) {
ctr++;
}
if (b == false) {
ctr++;
}
if (ms.i == 0) {
ctr++;
}
if (ms.f == 0) {
ctr++;
}
if (ms.i == 0 && ms.f == 0 && ms.i == 0) {
ctr++;
}
}
void test_cmp_implies(int a, int b) {
if((a == b) == 0) {
} else {
}
if((a == b) != 0) {
} else {
}
if((a != b) == 0) {
} else {
}
if((a != b) != 0) {
} else {
}
if((a < b) == 0) {
} else {
}
if((a < b) != 0) {
} else {
}
}
void test_cmp_implies_unary(int a) {
if((a == 42) == 0) {
} else {
}
if((a == 42) != 0) {
} else {
}
if((a != 42) == 0) {
} else {
}
if((a != 42) != 0) {
} else {
}
if((a < 42) == 0) {
} else {
}
if((a < 42) != 0) {
} else {
}
}
int foo();
void test_constant_value_and_case_range(bool b)
{
int x = foo();
if (b)
{
x = 42;
}
switch (x)
{
case 40 ... 50:
// should not be guarded by `foo() = 40..50`
use(x);
}
}
void chk();
bool testNotNull1(void* input) {
return input != nullptr;
}
void test_ternary(void* y) {
int x = testNotNull1(y) ? 42 : 0;
if (x != 0) {
chk(); // $ guarded='... ? ... : ...:not 0' guarded='42:not 0' guarded='call to testNotNull1:true' guarded='x != 0:true' guarded='x:not 0' guarded='y:not null'
}
}
bool testNotNull2(void* input) {
if (input == nullptr) return false;
return true;
}
int getNumOrDefault(int* number) {
return number == nullptr ? 0 : *number;
}
char returnAIfNoneAreNull(char* s1, char* s2) {
if (!s1 || !s2) return '\0';
return 'a';
}
enum class Status { SUCCESS = 1, FAILURE = 2 };
Status testEnumWrapper(bool flag) {
return flag ? Status::SUCCESS : Status::FAILURE;
}
void testWrappers(void* p, int* i, char* s, bool b) {
if (testNotNull1(p)) {
chk(); // $ guarded='p:not null' guarded='call to testNotNull1:true'
} else {
chk(); // $ guarded=p:null guarded='call to testNotNull1:false'
}
if (testNotNull2(p)) {
chk(); // $ guarded='call to testNotNull2:true' MISSING: guarded='p:not null'
} else {
chk(); // $ guarded='call to testNotNull2:false'
}
if (0 == getNumOrDefault(i)) {
chk(); // $ guarded='0 == call to getNumOrDefault:true' guarded='call to getNumOrDefault:0'
} else {
chk(); // $ guarded='0 == call to getNumOrDefault:false' guarded='call to getNumOrDefault:not 0' guarded='i:not null'
}
if ('\0' == returnAIfNoneAreNull(s, "suffix")) {
chk(); // $ guarded='0 == call to returnAIfNoneAreNull:true' guarded='call to returnAIfNoneAreNull:0'
} else {
chk(); // $ guarded='0 == call to returnAIfNoneAreNull:false' guarded='call to returnAIfNoneAreNull:not 0' MISSING: guarded='s:not null'
}
switch (testEnumWrapper(b)) {
case Status::SUCCESS:
chk(); // $ guarded='call to testEnumWrapper=SUCCESS:true' guarded='call to testEnumWrapper:1' guarded=b:true
break;
case Status::FAILURE:
chk(); // $ guarded='call to testEnumWrapper=FAILURE:true' guarded='call to testEnumWrapper:2' guarded=b:false
break;
}
}
void ensureNotNull(void* o) {
if (!o) throw 42;
}
void testExceptionWrapper(void* s) {
chk(); // nothing guards here
ensureNotNull(s);
chk(); // $ MISSING: guarded='call to ensureNotNull:no exception' guarded='s:not null'
}