| // RUN: %clang_analyze_cc1 -verify -analyzer-output=text %s \ | 
 | // RUN:   -analyzer-checker=core \ | 
 | // RUN:   -analyzer-checker=cplusplus \ | 
 | // RUN:   -analyzer-checker=unix \ | 
 | // RUN:   -analyzer-config \ | 
 | // RUN:     unix.DynamicMemoryModeling:AddNoOwnershipChangeNotes=false | 
 |  | 
 | // RUN: %clang_analyze_cc1 -verify=expected,ownership -analyzer-output=text %s \ | 
 | // RUN:   -analyzer-checker=core \ | 
 | // RUN:   -analyzer-checker=cplusplus \ | 
 | // RUN:   -analyzer-checker=unix \ | 
 | // RUN:   -analyzer-config \ | 
 | // RUN:     unix.DynamicMemoryModeling:AddNoOwnershipChangeNotes=true | 
 |  | 
 | #include "Inputs/system-header-simulator-for-malloc.h" | 
 |  | 
 | //===----------------------------------------------------------------------===// | 
 | // Report for which we expect NoOwnershipChangeVisitor to add a new note. | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | bool coin(); | 
 |  | 
 | // TODO: AST analysis of sink would reveal that it doesn't intent to free the | 
 | // allocated memory, but in this instance, its also the only function with | 
 | // the ability to do so, we should see a note here. | 
 | namespace memory_allocated_in_fn_call { | 
 |  | 
 | void sink(int *P) { | 
 | } | 
 |  | 
 | void foo() { | 
 |   sink(new int(5)); // expected-note {{Memory is allocated}} | 
 | } // expected-warning {{Potential memory leak [cplusplus.NewDeleteLeaks]}} | 
 | // expected-note@-1 {{Potential memory leak}} | 
 |  | 
 | } // namespace memory_allocated_in_fn_call | 
 |  | 
 | // Realize that sink() intends to deallocate memory, assume that it should've | 
 | // taken care of the leaked object as well. | 
 | namespace memory_passed_to_fn_call_delete { | 
 |  | 
 | void sink(int *P) { | 
 |   if (coin()) // ownership-note {{Assuming the condition is false}} | 
 |               // ownership-note@-1 {{Taking false branch}} | 
 |     delete P; | 
 | } // ownership-note {{Returning without deallocating memory or storing the pointer for later deallocation}} | 
 |  | 
 | void foo() { | 
 |   int *ptr = new int(5); // expected-note {{Memory is allocated}} | 
 |   sink(ptr);             // ownership-note {{Calling 'sink'}} | 
 |                          // ownership-note@-1 {{Returning from 'sink'}} | 
 | } // expected-warning {{Potential leak of memory pointed to by 'ptr' [cplusplus.NewDeleteLeaks]}} | 
 | // expected-note@-1 {{Potential leak}} | 
 |  | 
 | } // namespace memory_passed_to_fn_call_delete | 
 |  | 
 | namespace memory_passed_to_fn_call_free { | 
 |  | 
 | void sink(int *P) { | 
 |   if (coin()) // ownership-note {{Assuming the condition is false}} | 
 |               // ownership-note@-1 {{Taking false branch}} | 
 |     free(P); | 
 | } // ownership-note {{Returning without deallocating memory or storing the pointer for later deallocation}} | 
 |  | 
 | void foo() { | 
 |   int *ptr = (int *)malloc(sizeof(int)); // expected-note {{Memory is allocated}} | 
 |   sink(ptr);                             // ownership-note {{Calling 'sink'}} | 
 |                                          // ownership-note@-1 {{Returning from 'sink'}} | 
 | } // expected-warning {{Potential leak of memory pointed to by 'ptr' [unix.Malloc]}} | 
 | // expected-note@-1 {{Potential leak}} | 
 |  | 
 | } // namespace memory_passed_to_fn_call_free | 
 |  | 
 | // Function pointers cannot be resolved syntactically. | 
 | namespace memory_passed_to_fn_call_free_through_fn_ptr { | 
 | void (*freeFn)(void *) = free; | 
 |  | 
 | void sink(int *P) { | 
 |   if (coin()) | 
 |     freeFn(P); | 
 | } | 
 |  | 
 | void foo() { | 
 |   int *ptr = (int *)malloc(sizeof(int)); // expected-note {{Memory is allocated}} | 
 |   sink(ptr); | 
 | } // expected-warning {{Potential leak of memory pointed to by 'ptr' [unix.Malloc]}} | 
 | // expected-note@-1 {{Potential leak}} | 
 |  | 
 | } // namespace memory_passed_to_fn_call_free_through_fn_ptr | 
 |  | 
 | namespace memory_shared_with_ptr_of_shorter_lifetime { | 
 |  | 
 | void sink(int *P) { | 
 |   int *Q = P; | 
 |   if (coin()) // ownership-note {{Assuming the condition is false}} | 
 |               // ownership-note@-1 {{Taking false branch}} | 
 |     delete P; | 
 |   (void)Q; | 
 | } // ownership-note {{Returning without deallocating memory or storing the pointer for later deallocation}} | 
 |  | 
 | void foo() { | 
 |   int *ptr = new int(5); // expected-note {{Memory is allocated}} | 
 |   sink(ptr);             // ownership-note {{Calling 'sink'}} | 
 |                          // ownership-note@-1 {{Returning from 'sink'}} | 
 | } // expected-warning {{Potential leak of memory pointed to by 'ptr' [cplusplus.NewDeleteLeaks]}} | 
 | // expected-note@-1 {{Potential leak}} | 
 |  | 
 | } // namespace memory_shared_with_ptr_of_shorter_lifetime | 
 |  | 
 | //===----------------------------------------------------------------------===// | 
 | // Report for which we *do not* expect NoOwnershipChangeVisitor add a new note, | 
 | // nor do we want it to. | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | namespace memory_not_passed_to_fn_call { | 
 |  | 
 | void sink(int *P) { | 
 |   if (coin()) | 
 |     delete P; | 
 | } | 
 |  | 
 | void foo() { | 
 |   int *ptr = new int(5); // expected-note {{Memory is allocated}} | 
 |   int *q = nullptr; | 
 |   sink(q); | 
 |   (void)ptr; | 
 | } // expected-warning {{Potential leak of memory pointed to by 'ptr' [cplusplus.NewDeleteLeaks]}} | 
 | // expected-note@-1 {{Potential leak}} | 
 |  | 
 | } // namespace memory_not_passed_to_fn_call | 
 |  | 
 | namespace memory_shared_with_ptr_of_same_lifetime { | 
 |  | 
 | void sink(int *P, int **Q) { | 
 |   // NOTE: Not a job of NoOwnershipChangeVisitor, but maybe this could be | 
 |   // highlighted still? | 
 |   *Q = P; | 
 | } | 
 |  | 
 | void foo() { | 
 |   int *ptr = new int(5); // expected-note {{Memory is allocated}} | 
 |   int *q = nullptr; | 
 |   sink(ptr, &q); | 
 | } // expected-warning {{Potential leak of memory pointed to by 'q' [cplusplus.NewDeleteLeaks]}} | 
 | // expected-note@-1 {{Potential leak}} | 
 |  | 
 | } // namespace memory_shared_with_ptr_of_same_lifetime | 
 |  | 
 | namespace memory_passed_into_fn_that_doesnt_intend_to_free { | 
 |  | 
 | void sink(int *P) { | 
 | } | 
 |  | 
 | void foo() { | 
 |   int *ptr = new int(5); // expected-note {{Memory is allocated}} | 
 |   sink(ptr); | 
 | } // expected-warning {{Potential leak of memory pointed to by 'ptr' [cplusplus.NewDeleteLeaks]}} | 
 | // expected-note@-1 {{Potential leak}} | 
 |  | 
 | } // namespace memory_passed_into_fn_that_doesnt_intend_to_free | 
 |  | 
 | namespace memory_passed_into_fn_that_doesnt_intend_to_free2 { | 
 |  | 
 | void bar(); | 
 |  | 
 | void sink(int *P) { | 
 |   // Correctly realize that calling bar() doesn't mean that this function would | 
 |   // like to deallocate anything. | 
 |   bar(); | 
 | } | 
 |  | 
 | void foo() { | 
 |   int *ptr = new int(5); // expected-note {{Memory is allocated}} | 
 |   sink(ptr); | 
 | } // expected-warning {{Potential leak of memory pointed to by 'ptr' [cplusplus.NewDeleteLeaks]}} | 
 | // expected-note@-1 {{Potential leak}} | 
 |  | 
 | } // namespace memory_passed_into_fn_that_doesnt_intend_to_free2 | 
 |  | 
 | namespace refkind_from_unoallocated_to_allocated { | 
 |  | 
 | // RefKind of the symbol changed from nothing to Allocated. We don't want to | 
 | // emit notes when the RefKind changes in the stack frame. | 
 | static char *malloc_wrapper_ret() { | 
 |   return (char *)malloc(12); // expected-note {{Memory is allocated}} | 
 | } | 
 | void use_ret() { | 
 |   char *v; | 
 |   v = malloc_wrapper_ret(); // expected-note {{Calling 'malloc_wrapper_ret'}} | 
 |                             // expected-note@-1 {{Returned allocated memory}} | 
 | } // expected-warning {{Potential leak of memory pointed to by 'v' [unix.Malloc]}} | 
 | // expected-note@-1 {{Potential leak of memory pointed to by 'v'}} | 
 |  | 
 | } // namespace refkind_from_unoallocated_to_allocated | 
 |  | 
 | // Check that memory leak is reported against a symbol if the last place it's | 
 | // mentioned is a base region of a lazy compound value, as the program cannot | 
 | // possibly free that memory. | 
 | namespace symbol_reaper_lifetime { | 
 | struct Nested { | 
 |   int buf[2]; | 
 | }; | 
 | struct Wrapping { | 
 |   Nested data; | 
 | }; | 
 |  | 
 | Nested allocateWrappingAndReturnNested() { | 
 |   // expected-note@+1 {{Memory is allocated}} | 
 |   Wrapping const* p = new Wrapping(); | 
 |   // expected-warning@+2 {{Potential leak of memory pointed to by 'p'}} | 
 |   // expected-note@+1    {{Potential leak of memory pointed to by 'p'}} | 
 |   return p->data; | 
 | } | 
 |  | 
 | void caller() { | 
 |   // expected-note@+1 {{Calling 'allocateWrappingAndReturnNested'}} | 
 |   Nested n = allocateWrappingAndReturnNested(); | 
 |   (void)n; | 
 | } // no-warning: No potential memory leak here, because that's been already reported. | 
 | } // namespace symbol_reaper_lifetime |