diff --git a/cpp/ql/test/query-tests/Critical/MemoryFreed/DoubleFree.expected b/cpp/ql/test/query-tests/Critical/MemoryFreed/DoubleFree.expected index 893f1c7e79a..e839947c7b5 100644 --- a/cpp/ql/test/query-tests/Critical/MemoryFreed/DoubleFree.expected +++ b/cpp/ql/test/query-tests/Critical/MemoryFreed/DoubleFree.expected @@ -12,6 +12,22 @@ edges | test_free.cpp:152:27:152:27 | pointer to free output argument | test_free.cpp:154:10:154:10 | a | provenance | | | test_free.cpp:207:10:207:10 | pointer to free output argument | test_free.cpp:209:10:209:10 | a | provenance | | | test_free.cpp:301:12:301:14 | pointer to g_free output argument | test_free.cpp:302:12:302:14 | buf | provenance | | +| test_free.cpp:319:16:319:16 | pointer to operator delete output argument | test_free.cpp:322:12:322:12 | a | provenance | | +| test_free.cpp:343:12:343:24 | *access to array [post update] [ptr] | test_free.cpp:344:12:344:24 | *access to array [ptr] | provenance | | +| test_free.cpp:343:12:343:24 | *access to array [post update] [ptr] | test_free.cpp:345:12:345:24 | *access to array [ptr] | provenance | | +| test_free.cpp:343:12:343:24 | *access to array [post update] [ptr] | test_free.cpp:346:12:346:24 | *access to array [ptr] | provenance | | +| test_free.cpp:343:26:343:28 | pointer to operator delete output argument | test_free.cpp:343:12:343:24 | *access to array [post update] [ptr] | provenance | | +| test_free.cpp:344:12:344:24 | *access to array [post update] [ptr] | test_free.cpp:345:12:345:24 | *access to array [ptr] | provenance | | +| test_free.cpp:344:12:344:24 | *access to array [post update] [ptr] | test_free.cpp:346:12:346:24 | *access to array [ptr] | provenance | | +| test_free.cpp:344:12:344:24 | *access to array [ptr] | test_free.cpp:344:26:344:28 | ptr | provenance | | +| test_free.cpp:344:26:344:28 | pointer to operator delete output argument | test_free.cpp:344:12:344:24 | *access to array [post update] [ptr] | provenance | | +| test_free.cpp:345:12:345:24 | *access to array [post update] [ptr] | test_free.cpp:346:12:346:24 | *access to array [ptr] | provenance | | +| test_free.cpp:345:12:345:24 | *access to array [ptr] | test_free.cpp:345:26:345:28 | ptr | provenance | | +| test_free.cpp:345:12:345:24 | *access to array [ptr] | test_free.cpp:345:26:345:28 | ptr | provenance | | +| test_free.cpp:345:26:345:28 | pointer to operator delete output argument | test_free.cpp:345:12:345:24 | *access to array [post update] [ptr] | provenance | | +| test_free.cpp:346:12:346:24 | *access to array [ptr] | test_free.cpp:346:26:346:28 | ptr | provenance | | +| test_free.cpp:346:12:346:24 | *access to array [ptr] | test_free.cpp:346:26:346:28 | ptr | provenance | | +| test_free.cpp:346:12:346:24 | *access to array [ptr] | test_free.cpp:346:26:346:28 | ptr | provenance | | nodes | test_free.cpp:11:10:11:10 | pointer to free output argument | semmle.label | pointer to free output argument | | test_free.cpp:14:10:14:10 | a | semmle.label | a | @@ -39,6 +55,26 @@ nodes | test_free.cpp:209:10:209:10 | a | semmle.label | a | | test_free.cpp:301:12:301:14 | pointer to g_free output argument | semmle.label | pointer to g_free output argument | | test_free.cpp:302:12:302:14 | buf | semmle.label | buf | +| test_free.cpp:319:16:319:16 | pointer to operator delete output argument | semmle.label | pointer to operator delete output argument | +| test_free.cpp:322:12:322:12 | a | semmle.label | a | +| test_free.cpp:343:12:343:24 | *access to array [post update] [ptr] | semmle.label | *access to array [post update] [ptr] | +| test_free.cpp:343:26:343:28 | pointer to operator delete output argument | semmle.label | pointer to operator delete output argument | +| test_free.cpp:344:12:344:24 | *access to array [post update] [ptr] | semmle.label | *access to array [post update] [ptr] | +| test_free.cpp:344:12:344:24 | *access to array [ptr] | semmle.label | *access to array [ptr] | +| test_free.cpp:344:26:344:28 | pointer to operator delete output argument | semmle.label | pointer to operator delete output argument | +| test_free.cpp:344:26:344:28 | ptr | semmle.label | ptr | +| test_free.cpp:345:12:345:24 | *access to array [post update] [ptr] | semmle.label | *access to array [post update] [ptr] | +| test_free.cpp:345:12:345:24 | *access to array [ptr] | semmle.label | *access to array [ptr] | +| test_free.cpp:345:12:345:24 | *access to array [ptr] | semmle.label | *access to array [ptr] | +| test_free.cpp:345:26:345:28 | pointer to operator delete output argument | semmle.label | pointer to operator delete output argument | +| test_free.cpp:345:26:345:28 | ptr | semmle.label | ptr | +| test_free.cpp:345:26:345:28 | ptr | semmle.label | ptr | +| test_free.cpp:346:12:346:24 | *access to array [ptr] | semmle.label | *access to array [ptr] | +| test_free.cpp:346:12:346:24 | *access to array [ptr] | semmle.label | *access to array [ptr] | +| test_free.cpp:346:12:346:24 | *access to array [ptr] | semmle.label | *access to array [ptr] | +| test_free.cpp:346:26:346:28 | ptr | semmle.label | ptr | +| test_free.cpp:346:26:346:28 | ptr | semmle.label | ptr | +| test_free.cpp:346:26:346:28 | ptr | semmle.label | ptr | subpaths #select | test_free.cpp:14:10:14:10 | a | test_free.cpp:11:10:11:10 | pointer to free output argument | test_free.cpp:14:10:14:10 | a | Memory pointed to by $@ may already have been freed by $@. | test_free.cpp:14:10:14:10 | a | a | test_free.cpp:11:5:11:8 | call to free | call to free | @@ -54,3 +90,10 @@ subpaths | test_free.cpp:154:10:154:10 | a | test_free.cpp:152:27:152:27 | pointer to free output argument | test_free.cpp:154:10:154:10 | a | Memory pointed to by $@ may already have been freed by $@. | test_free.cpp:154:10:154:10 | a | a | test_free.cpp:152:22:152:25 | call to free | call to free | | test_free.cpp:209:10:209:10 | a | test_free.cpp:207:10:207:10 | pointer to free output argument | test_free.cpp:209:10:209:10 | a | Memory pointed to by $@ may already have been freed by $@. | test_free.cpp:209:10:209:10 | a | a | test_free.cpp:207:5:207:8 | call to free | call to free | | test_free.cpp:302:12:302:14 | buf | test_free.cpp:301:12:301:14 | pointer to g_free output argument | test_free.cpp:302:12:302:14 | buf | Memory pointed to by $@ may already have been freed by $@. | test_free.cpp:302:12:302:14 | buf | buf | test_free.cpp:301:5:301:10 | call to g_free | call to g_free | +| test_free.cpp:322:12:322:12 | a | test_free.cpp:319:16:319:16 | pointer to operator delete output argument | test_free.cpp:322:12:322:12 | a | Memory pointed to by $@ may already have been freed by $@. | test_free.cpp:322:12:322:12 | a | a | test_free.cpp:319:9:319:16 | delete | delete | +| test_free.cpp:344:26:344:28 | ptr | test_free.cpp:343:26:343:28 | pointer to operator delete output argument | test_free.cpp:344:26:344:28 | ptr | Memory pointed to by $@ may already have been freed by $@. | test_free.cpp:344:26:344:28 | ptr | ptr | test_free.cpp:343:5:343:28 | delete | delete | +| test_free.cpp:345:26:345:28 | ptr | test_free.cpp:343:26:343:28 | pointer to operator delete output argument | test_free.cpp:345:26:345:28 | ptr | Memory pointed to by $@ may already have been freed by $@. | test_free.cpp:345:26:345:28 | ptr | ptr | test_free.cpp:343:5:343:28 | delete | delete | +| test_free.cpp:345:26:345:28 | ptr | test_free.cpp:344:26:344:28 | pointer to operator delete output argument | test_free.cpp:345:26:345:28 | ptr | Memory pointed to by $@ may already have been freed by $@. | test_free.cpp:345:26:345:28 | ptr | ptr | test_free.cpp:344:5:344:28 | delete | delete | +| test_free.cpp:346:26:346:28 | ptr | test_free.cpp:343:26:343:28 | pointer to operator delete output argument | test_free.cpp:346:26:346:28 | ptr | Memory pointed to by $@ may already have been freed by $@. | test_free.cpp:346:26:346:28 | ptr | ptr | test_free.cpp:343:5:343:28 | delete | delete | +| test_free.cpp:346:26:346:28 | ptr | test_free.cpp:344:26:344:28 | pointer to operator delete output argument | test_free.cpp:346:26:346:28 | ptr | Memory pointed to by $@ may already have been freed by $@. | test_free.cpp:346:26:346:28 | ptr | ptr | test_free.cpp:344:5:344:28 | delete | delete | +| test_free.cpp:346:26:346:28 | ptr | test_free.cpp:345:26:345:28 | pointer to operator delete output argument | test_free.cpp:346:26:346:28 | ptr | Memory pointed to by $@ may already have been freed by $@. | test_free.cpp:346:26:346:28 | ptr | ptr | test_free.cpp:345:5:345:28 | delete | delete | diff --git a/cpp/ql/test/query-tests/Critical/MemoryFreed/MemoryFreed.expected b/cpp/ql/test/query-tests/Critical/MemoryFreed/MemoryFreed.expected index 2e5f59ae0d2..46e30cedf3e 100644 --- a/cpp/ql/test/query-tests/Critical/MemoryFreed/MemoryFreed.expected +++ b/cpp/ql/test/query-tests/Critical/MemoryFreed/MemoryFreed.expected @@ -104,6 +104,15 @@ | test_free.cpp:293:8:293:10 | buf | | test_free.cpp:301:12:301:14 | buf | | test_free.cpp:302:12:302:14 | buf | +| test_free.cpp:313:16:313:16 | a | +| test_free.cpp:319:16:319:16 | a | +| test_free.cpp:322:12:322:12 | a | +| test_free.cpp:331:12:331:12 | a | +| test_free.cpp:335:12:335:12 | a | +| test_free.cpp:343:26:343:28 | ptr | +| test_free.cpp:344:26:344:28 | ptr | +| test_free.cpp:345:26:345:28 | ptr | +| test_free.cpp:346:26:346:28 | ptr | | virtual.cpp:18:10:18:10 | a | | virtual.cpp:19:10:19:10 | c | | virtual.cpp:38:10:38:10 | b | diff --git a/cpp/ql/test/query-tests/Critical/MemoryFreed/UseAfterFree.expected b/cpp/ql/test/query-tests/Critical/MemoryFreed/UseAfterFree.expected index 815ad8e6fa5..7625783731a 100644 --- a/cpp/ql/test/query-tests/Critical/MemoryFreed/UseAfterFree.expected +++ b/cpp/ql/test/query-tests/Critical/MemoryFreed/UseAfterFree.expected @@ -25,6 +25,11 @@ edges | test_free.cpp:294:3:294:3 | *s [post update] [buf] | test_free.cpp:295:12:295:12 | *s [buf] | provenance | | | test_free.cpp:294:3:294:13 | ... = ... | test_free.cpp:294:3:294:3 | *s [post update] [buf] | provenance | | | test_free.cpp:295:12:295:12 | *s [buf] | test_free.cpp:295:14:295:16 | buf | provenance | | +| test_free.cpp:313:16:313:16 | pointer to operator delete output argument | test_free.cpp:324:5:324:6 | * ... | provenance | | +| test_free.cpp:319:16:319:16 | pointer to operator delete output argument | test_free.cpp:321:5:321:6 | * ... | provenance | | +| test_free.cpp:319:16:319:16 | pointer to operator delete output argument | test_free.cpp:324:5:324:6 | * ... | provenance | | +| test_free.cpp:322:12:322:12 | pointer to operator delete output argument | test_free.cpp:324:5:324:6 | * ... | provenance | | +| test_free.cpp:331:12:331:12 | pointer to operator delete output argument | test_free.cpp:332:5:332:6 | * ... | provenance | | nodes | test_free.cpp:11:10:11:10 | pointer to free output argument | semmle.label | pointer to free output argument | | test_free.cpp:12:5:12:5 | a | semmle.label | a | @@ -66,6 +71,15 @@ nodes | test_free.cpp:294:3:294:13 | ... = ... | semmle.label | ... = ... | | test_free.cpp:295:12:295:12 | *s [buf] | semmle.label | *s [buf] | | test_free.cpp:295:14:295:16 | buf | semmle.label | buf | +| test_free.cpp:313:16:313:16 | pointer to operator delete output argument | semmle.label | pointer to operator delete output argument | +| test_free.cpp:319:16:319:16 | pointer to operator delete output argument | semmle.label | pointer to operator delete output argument | +| test_free.cpp:321:5:321:6 | * ... | semmle.label | * ... | +| test_free.cpp:322:12:322:12 | pointer to operator delete output argument | semmle.label | pointer to operator delete output argument | +| test_free.cpp:324:5:324:6 | * ... | semmle.label | * ... | +| test_free.cpp:324:5:324:6 | * ... | semmle.label | * ... | +| test_free.cpp:324:5:324:6 | * ... | semmle.label | * ... | +| test_free.cpp:331:12:331:12 | pointer to operator delete output argument | semmle.label | pointer to operator delete output argument | +| test_free.cpp:332:5:332:6 | * ... | semmle.label | * ... | subpaths #select | test_free.cpp:12:5:12:5 | a | test_free.cpp:11:10:11:10 | pointer to free output argument | test_free.cpp:12:5:12:5 | a | Memory may have been previously freed by $@. | test_free.cpp:11:5:11:8 | call to free | call to free | @@ -84,3 +98,8 @@ subpaths | test_free.cpp:278:15:278:17 | buf | test_free.cpp:277:8:277:13 | pointer to free output argument | test_free.cpp:278:15:278:17 | buf | Memory may have been previously freed by $@. | test_free.cpp:277:3:277:6 | call to free | call to free | | test_free.cpp:283:14:283:16 | buf | test_free.cpp:282:8:282:12 | pointer to free output argument | test_free.cpp:283:14:283:16 | buf | Memory may have been previously freed by $@. | test_free.cpp:282:3:282:6 | call to free | call to free | | test_free.cpp:295:14:295:16 | buf | test_free.cpp:293:8:293:10 | pointer to free output argument | test_free.cpp:295:14:295:16 | buf | Memory may have been previously freed by $@. | test_free.cpp:293:3:293:6 | call to free | call to free | +| test_free.cpp:321:5:321:6 | * ... | test_free.cpp:319:16:319:16 | pointer to operator delete output argument | test_free.cpp:321:5:321:6 | * ... | Memory may have been previously freed by $@. | test_free.cpp:319:9:319:16 | delete | delete | +| test_free.cpp:324:5:324:6 | * ... | test_free.cpp:313:16:313:16 | pointer to operator delete output argument | test_free.cpp:324:5:324:6 | * ... | Memory may have been previously freed by $@. | test_free.cpp:313:9:313:16 | delete | delete | +| test_free.cpp:324:5:324:6 | * ... | test_free.cpp:319:16:319:16 | pointer to operator delete output argument | test_free.cpp:324:5:324:6 | * ... | Memory may have been previously freed by $@. | test_free.cpp:319:9:319:16 | delete | delete | +| test_free.cpp:324:5:324:6 | * ... | test_free.cpp:322:12:322:12 | pointer to operator delete output argument | test_free.cpp:324:5:324:6 | * ... | Memory may have been previously freed by $@. | test_free.cpp:322:5:322:12 | delete | delete | +| test_free.cpp:332:5:332:6 | * ... | test_free.cpp:331:12:331:12 | pointer to operator delete output argument | test_free.cpp:332:5:332:6 | * ... | Memory may have been previously freed by $@. | test_free.cpp:331:5:331:12 | delete | delete | diff --git a/cpp/ql/test/query-tests/Critical/MemoryFreed/test_free.cpp b/cpp/ql/test/query-tests/Critical/MemoryFreed/test_free.cpp index 8bffcad2856..e0da5ea74ad 100644 --- a/cpp/ql/test/query-tests/Critical/MemoryFreed/test_free.cpp +++ b/cpp/ql/test/query-tests/Critical/MemoryFreed/test_free.cpp @@ -264,9 +264,9 @@ void test_ref_delete(int *&p) { } void test_free_assign() { - void *a = malloc(10); + void *a = malloc(10); void *b; - free(b = a); // GOOD + free(b = a); // GOOD } struct MyStruct { @@ -300,4 +300,48 @@ void g_free (void*); void test_g_free(char* buf) { g_free(buf); g_free(buf); // BAD -} \ No newline at end of file +} + +// 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 [FALSE POSITIVE] + delete containers[2].ptr; // GOOD [FALSE POSITIVE] + delete containers[2].ptr; // BAD (double free) +}