// 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(); namespace memory_allocated_in_fn_call { void sink(int *P) { } // ownership-note {{Returning without deallocating memory or storing the pointer for later deallocation}} void foo() { sink(new int(5)); // expected-note {{Memory is allocated}} // ownership-note@-1 {{Calling 'sink'}} // ownership-note@-2 {{Returning from 'sink'}} } // expected-warning {{Potential memory leak [cplusplus.NewDeleteLeaks]}} // expected-note@-1 {{Potential memory leak}} } // namespace memory_allocated_in_fn_call namespace memory_passed_to_fn_call { 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 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 // TODO: We don't want a note here. sink() doesn't seem like a function that // even attempts to take care of any memory ownership problems. namespace memory_passed_into_fn_that_doesnt_intend_to_free { void sink(int *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_into_fn_that_doesnt_intend_to_free 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