forked from OSchip/llvm-project
195 lines
6.8 KiB
C++
195 lines
6.8 KiB
C++
// 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
|