| // RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,unix.MismatchedDeallocator,cplusplus.NewDelete -std=c++11 -verify %s | |
| // RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,unix.MismatchedDeallocator,cplusplus.NewDelete,cplusplus.NewDeleteLeaks -DLEAKS -std=c++11 -verify %s | |
| #include "Inputs/system-header-simulator-for-malloc.h" | |
| //-------------------------------------------------- | |
| // Check that unix.Malloc catches all types of bugs. | |
| //-------------------------------------------------- | |
| void testMallocDoubleFree() { | |
| int *p = (int *)malloc(sizeof(int)); | |
| free(p); | |
| free(p); // expected-warning{{Attempt to release already released memory}} | |
| } | |
| void testMallocLeak() { | |
| int *p = (int *)malloc(sizeof(int)); | |
| } // expected-warning{{Potential leak of memory pointed to by 'p'}} | |
| void testMallocUseAfterFree() { | |
| int *p = (int *)malloc(sizeof(int)); | |
| free(p); | |
| int j = *p; // expected-warning{{Use of memory after it is released}} | |
| } | |
| void testMallocBadFree() { | |
| int i; | |
| free(&i); // expected-warning{{Argument to 'free()' is the address of the local variable 'i', which is not memory allocated by 'malloc()'}} | |
| } | |
| void testMallocOffsetFree() { | |
| int *p = (int *)malloc(sizeof(int)); | |
| free(++p); // expected-warning{{Argument to 'free()' is offset by 4 bytes from the start of memory allocated by 'malloc()'}} | |
| } | |
| //----------------------------------------------------------------- | |
| // Check that unix.MismatchedDeallocator catches all types of bugs. | |
| //----------------------------------------------------------------- | |
| void testMismatchedDeallocator() { | |
| int *x = (int *)malloc(sizeof(int)); | |
| delete x; // expected-warning{{Memory allocated by 'malloc()' should be deallocated by 'free()', not 'delete'}} | |
| } | |
| //---------------------------------------------------------------- | |
| // Check that alpha.cplusplus.NewDelete catches all types of bugs. | |
| //---------------------------------------------------------------- | |
| void testNewDoubleFree() { | |
| int *p = new int; | |
| delete p; | |
| delete p; // expected-warning{{Attempt to release already released memory}} | |
| } | |
| void testNewLeak() { | |
| int *p = new int; | |
| } | |
| #ifdef LEAKS | |
| // expected-warning@-2 {{Potential leak of memory pointed to by 'p'}} | |
| #endif | |
| void testNewUseAfterFree() { | |
| int *p = (int *)operator new(0); | |
| delete p; | |
| int j = *p; // expected-warning{{Use of memory after it is released}} | |
| } | |
| void testNewBadFree() { | |
| int i; | |
| delete &i; // expected-warning{{Argument to 'delete' is the address of the local variable 'i', which is not memory allocated by 'new'}} | |
| } | |
| void testNewOffsetFree() { | |
| int *p = new int; | |
| operator delete(++p); // expected-warning{{Argument to 'operator delete' is offset by 4 bytes from the start of memory allocated by 'new'}} | |
| } | |
| //---------------------------------------------------------------- | |
| // Test that we check for free errors on escaped pointers. | |
| //---------------------------------------------------------------- | |
| void changePtr(int **p); | |
| static int *globalPtr; | |
| void changePointee(int *p); | |
| void testMismatchedChangePtrThroughCall() { | |
| int *p = (int*)malloc(sizeof(int)*4); | |
| changePtr(&p); | |
| delete p; // no-warning the value of the pointer might have changed | |
| } | |
| void testMismatchedChangePointeeThroughCall() { | |
| int *p = (int*)malloc(sizeof(int)*4); | |
| changePointee(p); | |
| delete p; // expected-warning{{Memory allocated by 'malloc()' should be deallocated by 'free()', not 'delete'}} | |
| } | |
| void testShouldReportDoubleFreeNotMismatched() { | |
| int *p = (int*)malloc(sizeof(int)*4); | |
| globalPtr = p; | |
| free(p); | |
| delete globalPtr; // expected-warning {{Attempt to release already released memory}} | |
| } | |
| int *allocIntArray(unsigned c) { | |
| return new int[c]; | |
| } | |
| void testMismatchedChangePointeeThroughAssignment() { | |
| int *arr = allocIntArray(4); | |
| globalPtr = arr; | |
| delete arr; // expected-warning{{Memory allocated by 'new[]' should be deallocated by 'delete[]', not 'delete'}} | |
| } |