Skip to content

Commit 20672ac

Browse files
authored
Merge pull request #17110 from geoffw0/memfree
C++: Improve cpp/memory-may-not-be-freed
2 parents 06a4f90 + c172b94 commit 20672ac

File tree

5 files changed

+84
-2
lines changed

5 files changed

+84
-2
lines changed

cpp/ql/src/Critical/MemoryMayNotBeFreed.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ predicate allocCallOrIndirect(Expr e) {
3939
allocCallOrIndirect(rtn.getExpr())
4040
or
4141
// return variable assigned with alloc
42-
exists(Variable v |
42+
exists(StackVariable v |
4343
v = rtn.getExpr().(VariableAccess).getTarget() and
4444
allocCallOrIndirect(v.getAnAssignedValue()) and
4545
not assignedToFieldOrGlobal(v, _)
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* Fixed false positives in the `cpp/memory-may-not-be-freed` ("Memory may not be freed") query involving class methods that returned an allocated field of that class being misidentified as allocators.

cpp/ql/test/query-tests/Critical/MemoryFreed/MemoryFreed.expected

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,12 @@
120120
| test_free.cpp:346:26:346:28 | ptr |
121121
| test_free.cpp:356:19:356:19 | a |
122122
| test_free.cpp:357:19:357:19 | a |
123+
| test_free.cpp:370:10:370:10 | a |
124+
| test_free.cpp:373:10:373:10 | e |
125+
| test_free.cpp:382:10:382:10 | i |
126+
| test_free.cpp:383:10:383:10 | s |
127+
| test_free.cpp:395:14:395:19 | buffer |
128+
| test_free.cpp:424:10:424:16 | buffer2 |
123129
| virtual.cpp:18:10:18:10 | a |
124130
| virtual.cpp:19:10:19:10 | c |
125131
| virtual.cpp:38:10:38:10 | b |

cpp/ql/test/query-tests/Critical/MemoryFreed/MemoryNeverFreed.expected

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,5 @@
1414
| test_free.cpp:167:15:167:21 | call to realloc | This memory is never freed. |
1515
| test_free.cpp:253:14:253:19 | call to malloc | This memory is never freed. |
1616
| test_free.cpp:261:6:261:12 | new | This memory is never freed. |
17+
| test_free.cpp:365:21:365:26 | call to malloc | This memory is never freed. |
18+
| test_free.cpp:368:31:368:36 | call to malloc | This memory is never freed. |

cpp/ql/test/query-tests/Critical/MemoryFreed/test_free.cpp

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,4 +355,74 @@ struct E {
355355
void test(E* e) {
356356
free(e->ec[0].a);
357357
free(e->ec[1].a); // GOOD
358-
}
358+
}
359+
360+
// ---
361+
362+
void test_return_by_parameter(int **out_i, MyStruct **out_ms) {
363+
int *a = (int *)malloc(sizeof(int)); // GOOD (freed)
364+
int *b = (int *)malloc(sizeof(int)); // GOOD (out parameter)
365+
int *d = (int *)malloc(sizeof(int)); // BAD (not freed)
366+
MyStruct *e = (MyStruct *)malloc(sizeof(MyStruct)); // GOOD (freed)
367+
MyStruct *f = (MyStruct *)malloc(sizeof(MyStruct)); // GOOD (out parameter)
368+
MyStruct *h = (MyStruct *)malloc(sizeof(MyStruct)); // BAD (not freed)
369+
370+
free(a);
371+
*out_i = b;
372+
373+
free(e);
374+
*out_ms = f;
375+
}
376+
377+
void test_return_by_parameter_caller() {
378+
int *i;
379+
MyStruct *s;
380+
381+
test_return_by_parameter(&i, &s);
382+
free(i);
383+
free(s);
384+
}
385+
386+
// ---
387+
388+
class HasGetterAndFree {
389+
public:
390+
HasGetterAndFree() {
391+
buffer = malloc(1024);
392+
}
393+
394+
~HasGetterAndFree() {
395+
free(buffer);
396+
}
397+
398+
void *getBuffer() {
399+
return buffer;
400+
}
401+
402+
void *buffer;
403+
};
404+
405+
class HasGetterNoFree {
406+
public:
407+
HasGetterNoFree() {
408+
buffer = malloc(1024);
409+
}
410+
411+
void *getBuffer() {
412+
return buffer;
413+
}
414+
415+
void *buffer;
416+
};
417+
418+
void testHasGetter() {
419+
HasGetterAndFree hg;
420+
void *buffer = hg.getBuffer(); // GOOD (freed in destructor)
421+
422+
HasGetterNoFree hg2;
423+
void *buffer2 = hg2.getBuffer(); // GOOD (freed below)
424+
free(buffer2);
425+
426+
HasGetterNoFree hg3;
427+
void *buffer3 = hg3.getBuffer(); // BAD (not freed) [NOT DETECTED]
428+
}

0 commit comments

Comments
 (0)