Files
codeql/cpp/ql/test/query-tests/Critical/MemoryFreed/test_free.cpp
Geoffrey White 4aea4c0323 C++: Simple fix.
2024-07-31 14:46:25 +01:00

429 lines
7.9 KiB
C++

void *malloc(int);
void free(void *);
bool condition();
void use(void*);
void *realloc(void*, unsigned long);
int strlen(char*);
int asprintf(char ** strp, const char * fmt, ...);
void* test_double_free1(int *a) {
free(a); // GOOD
a[5] = 5; // BAD
*a = 5; // BAD
free(a); // BAD
a = (int*) malloc(8);
free(a); // GOOD
a = (int*) malloc(8);
if (!a) free(a);
return a;
}
void test_double_free_aliasing(void *a, void* b) {
free(a); // GOOD
a = b;
free(a); // GOOD
free(b); // BAD [NOT DETECTED]
}
void test_dominance1(void *a) {
free(a);
if (condition()) free(a); // BAD
}
void test_dominance2(void *a) {
free(a);
if (condition()) a = malloc(10);
if (condition()) free(a); // BAD
}
void test_post_dominance1(int *a)
{
if (condition()) free(a);
if (condition()) a[2] = 5; // BAD [NOT DETECTED]
if (condition()) free(a); // BAD [NOT DETECTED]
a[2] = 5; // BAD
free(a); // BAD
}
void test_post_dominance2(void *a) {
if (condition()) free(a);
free(a); // BAD
}
void test_post_dominance3(void *a) {
if (condition()) free(a);
a = malloc(10);
free(a); // GOOD
}
void test_use_after_free6(int *a, int *b) {
free(a);
a=b;
free(b);
if (condition()) a[0] = 5; // BAD [NOT DETECTED]
}
void test_use_after_free7(int *a) {
a[0] = 42;
free(a);
if (a[3]) { // BAD
free(a); // BAD
}
}
class A {
public:
void f();
};
void test_new1() {
A *a = new A();
delete(a);
a->f(); // BAD
delete(a); // BAD
}
void test_dereference1(A *a) {
a->f(); // GOOD
free(a);
a->f(); // BAD
}
void* use_after_free(void *a) {
free(a);
use(a); // BAD
return a; // BAD
}
void test_realloc1(void *a) {
free(a);
void *b = realloc(a, sizeof(a)*3); // BAD [NOT DETECTED by cpp/double-free]
free(a); // BAD
free(b); // GOOD
}
void* test_realloc2(char *a) {
void *b = realloc(a, strlen(a)+3); // GOOD
// From the man page on return values from realloc and reallocarray:
// "If these functions fail, the original block is left untouched; it is not freed or moved."
if (!b) {
free(a); // GOOD
}
free(b); // GOOD
}
void test_realloc3(void *a) {
void *b = realloc(a, 100);
if (b) free(b); // GOOD
if (!b) {
free(a); // GOOD
}
}
void test_ptr_deref(void ** a) {
free(*a);
*a = malloc(10);
free(*a); // GOOD
free(*a); // BAD
*a = malloc(10);
free(a[0]); // GOOD
free(a[1]); // GOOD
}
struct list {
struct list *next;
void* data;
};
void test_loop1(struct list ** list_ptr) {
struct list *next;
while (*list_ptr) { // GOOD
free((*list_ptr)->data); // GOOD
next = (*list_ptr)->next; // GOOD
free(*list_ptr); // GOOD
*list_ptr = next; // GOOD
}
free(list_ptr); // GOOD
}
void test_use_after_free8(struct list * a) {
if (condition()) free(a);
a->data = malloc(10); // BAD
free(a); // BAD
}
void test_loop2(char ** a) {
while (*a) { // GOOD
free(*a); // GOOD
a++;
}
free(a); // GOOD
}
void* test_realloc4() {
void *a = 0;
void *b = realloc(a, 10); // BAD for cpp/memory-never-freed
if (!b) { return a; }
return b;
}
void test_sizeof(int *a) {
free(a);
int x = sizeof(a[0]); // GOOD
}
void call_by_reference(char * &a);
int custom_alloc_func(char ** a);
void test_reassign(char *a) {
free(a); // GOOD
asprintf(&a, "Hello world"); // GOOD
free(a); //GOOD
call_by_reference(a); // GOOD
free(a); // GOOD
int v;
if (v = custom_alloc_func(&a)) return;
free(a); // GOOD
}
char* test_return1(char *a) {
int ret = condition();
if (!ret) free(a);
return (ret ? a : 0);
}
char* test_return2(char *a) {
int ret = condition();
if (!ret) free(a);
if (ret) return a;
else return 0;
}
void test_condition1(char *a) {
free(a);
if (asprintf(&a, "Hello world") || condition());
free(a); //GOOD
if (condition() || asprintf(&a, "Hello world"));
free(a); // BAD
}
void test_condition2(char *a) {
free(a);
if (condition()) a = (char*) malloc(10);
else custom_alloc_func(&a);
free(a); // GOOD
}
void* test_return1(void *a) {
free(a);
return a;
}
void MmFreePagesFromMdl(void*);
void ExFreePool(void*);
void test_ms_free(void * memory_descriptor_list) {
MmFreePagesFromMdl(memory_descriptor_list); //GOOD
ExFreePool(memory_descriptor_list); // GOOD
}
void test_loop3(char ** a, char ** b) {
if (*a) {
free(*a);
a++;
}
use(*a); // GOOD [FALSE POSITIVE]
for (;*b; b++) {
free(*b);
}
use(*b); // GOOD [FALSE POSITIVE]
}
void test_deref(char **a) {
free(*a);
use(*a); // GOOD [FALSE POSITIVE]
}
// Refs
void test_ref(char *&p) {
free(p);
p = (char *)malloc(sizeof(char)*10);
use(p); // GOOD
free(p); // GOOD
}
void test_ref_delete(int *&p) {
delete p;
p = new int;
use(p); // GOOD
delete p; // GOOD
}
void test_free_assign() {
void *a = malloc(10);
void *b;
free(b = a); // GOOD
}
struct MyStruct {
char* buf;
};
void test_free_struct(MyStruct* s) {
free(s->buf);
char c = s->buf[0]; // BAD
}
void test_free_struct2(MyStruct s) {
free(s.buf);
char c = s.buf[0]; // BAD
}
void test_free_struct3(MyStruct s) {
char* buf = s.buf;
free(buf);
char c = s.buf[0]; // BAD [FALSE NEGATIVE]
}
void test_free_struct4(char* buf, MyStruct s) {
free(buf);
s.buf = buf;
char c = s.buf[0]; // BAD
}
void g_free (void*);
void test_g_free(char* buf) {
g_free(buf);
g_free(buf); // BAD
}
// inspired by real world FPs
void test_goto() {
int *a = (int *)malloc(sizeof(int));
*a = 1; // GOOD
if (condition())
{
delete a;
goto after;
}
*a = 1; // GOOD
if (condition())
{
delete a;
}
*a = 1; // BAD (use after free)
delete a; // BAD (double free)
after:
*a = 1; // BAD (use after free)
}
void test_reassign() {
int *a = (int *)malloc(sizeof(int));
*a = 1; // GOOD
delete a;
*a = 1; // BAD (use after free)
a = (int *)malloc(sizeof(int));
*a = 1; // GOOD
delete a;
}
struct PtrContainer {
int *ptr;
};
void test_array(PtrContainer *containers) {
delete containers[0].ptr; // GOOD
delete containers[1].ptr; // GOOD
delete containers[2].ptr; // GOOD
delete containers[2].ptr; // BAD (double free) [NOT DETECTED]
}
struct E {
struct EC {
int* a;
} ec[2];
};
void test(E* e) {
free(e->ec[0].a);
free(e->ec[1].a); // GOOD
}
// ---
void test_return_by_parameter(int **out_i, MyStruct **out_ms) {
int *a = (int *)malloc(sizeof(int)); // GOOD (freed)
int *b = (int *)malloc(sizeof(int)); // GOOD (out parameter)
int *d = (int *)malloc(sizeof(int)); // BAD (not freed)
MyStruct *e = (MyStruct *)malloc(sizeof(MyStruct)); // GOOD (freed)
MyStruct *f = (MyStruct *)malloc(sizeof(MyStruct)); // GOOD (out parameter)
MyStruct *h = (MyStruct *)malloc(sizeof(MyStruct)); // BAD (not freed)
free(a);
*out_i = b;
free(e);
*out_ms = f;
}
void test_return_by_parameter_caller() {
int *i;
MyStruct *s;
test_return_by_parameter(&i, &s);
free(i);
free(s);
}
// ---
class HasGetterAndFree {
public:
HasGetterAndFree() {
buffer = malloc(1024);
}
~HasGetterAndFree() {
free(buffer);
}
void *getBuffer() {
return buffer;
}
void *buffer;
};
class HasGetterNoFree {
public:
HasGetterNoFree() {
buffer = malloc(1024);
}
void *getBuffer() {
return buffer;
}
void *buffer;
};
void testHasGetter() {
HasGetterAndFree hg;
void *buffer = hg.getBuffer(); // GOOD (freed in destructor)
HasGetterNoFree hg2;
void *buffer2 = hg2.getBuffer(); // GOOD (freed below)
free(buffer2);
HasGetterNoFree hg3;
void *buffer3 = hg3.getBuffer(); // BAD (not freed) [NOT DETECTED]
}