brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.1 KiB · 00dbbf2 Raw
253 lines · cpp
1// RUN: %clang_analyze_cc1 -verify -analyzer-output=text %s \2// RUN:   -analyzer-checker=core \3// RUN:   -analyzer-checker=cplusplus \4// RUN:   -analyzer-checker=unix5 6#include "Inputs/system-header-simulator-for-malloc.h"7 8//===----------------------------------------------------------------------===//9// unique_ptr test cases 10//===----------------------------------------------------------------------===//11namespace unique_ptr_tests {12 13// Custom unique_ptr implementation for testing14template <typename T>15struct unique_ptr {16  T* ptr;17  unique_ptr(T* p) : ptr(p) {}18  ~unique_ptr() {19    // This destructor intentionally doesn't delete 'ptr' to validate that the20    // heuristic trusts that smart pointers (based on their class name) will21    // release the pointee even if it doesn't understand their destructor.22  }23  unique_ptr(unique_ptr&& other) : ptr(other.ptr) { other.ptr = nullptr; }24  T* get() const { return ptr; }25};26 27template <typename T, typename... Args>28unique_ptr<T> make_unique(Args&&... args) {29  return unique_ptr<T>(new T(args...));30}31 32// Test 1: Check that we report leaks for malloc when passing smart pointers33void add_unique_ptr(unique_ptr<int> ptr) {34  // The unique_ptr destructor will be called when ptr goes out of scope35}36 37void test_malloc_with_smart_ptr() {38  void *ptr = malloc(4); // expected-note {{Memory is allocated}}39 40  add_unique_ptr(make_unique<int>(1));41  (void)ptr;42  // expected-warning@+1 {{Potential leak of memory pointed to by 'ptr'}} expected-note@+1 {{Potential leak of memory pointed to by 'ptr'}}43}44 45// Test 2: Check that we don't report leaks for unique_ptr in temporary objects46struct Foo { 47  unique_ptr<int> i;48};49 50void add_foo(Foo foo) {51  // The unique_ptr destructor will be called when foo goes out of scope52}53 54void test_temporary_object() {55  // No warning should be emitted for this - the memory is managed by unique_ptr 56  // in the temporary Foo object, which will properly clean up the memory57  add_foo({make_unique<int>(1)});58}59 60// Test 3: Check that we don't report leaks for smart pointers in base class fields61struct Base {62  unique_ptr<int> base_ptr;63  Base() : base_ptr(nullptr) {}64  Base(unique_ptr<int>&& ptr) : base_ptr(static_cast<unique_ptr<int>&&>(ptr)) {}65};66 67struct Derived : public Base {68  int derived_field;69  Derived() : Base(), derived_field(0) {}70  Derived(unique_ptr<int>&& ptr, int field) : Base(static_cast<unique_ptr<int>&&>(ptr)), derived_field(field) {}71};72 73void add_derived(Derived derived) {74  // The unique_ptr destructor will be called when derived goes out of scope75  // This should include the base_ptr field from the base class76}77 78void test_base_class_smart_ptr() {79  // No warning should be emitted for this - the memory is managed by unique_ptr 80  // in the base class field of the temporary Derived object81  add_derived(Derived(make_unique<int>(1), 42));82}83 84// Test 4: Check that we don't report leaks for multiple owning arguments85struct SinglePtr {86  unique_ptr<int> ptr;87  SinglePtr(unique_ptr<int>&& p) : ptr(static_cast<unique_ptr<int>&&>(p)) {}88};89 90struct MultiPtr {91  unique_ptr<int> ptr1;92  unique_ptr<int> ptr2;93  unique_ptr<int> ptr3;94  95  MultiPtr(unique_ptr<int>&& p1, unique_ptr<int>&& p2, unique_ptr<int>&& p3)96    : ptr1(static_cast<unique_ptr<int>&&>(p1))97    , ptr2(static_cast<unique_ptr<int>&&>(p2))98    , ptr3(static_cast<unique_ptr<int>&&>(p3)) {}99};100 101void addMultiple(SinglePtr single, MultiPtr multi) {102  // All unique_ptr destructors will be called when the objects go out of scope103  // This tests handling of multiple by-value arguments with smart pointer fields104}105 106void test_multiple_owning_args() {107  // No warning should be emitted - all memory is properly managed by unique_ptr108  // in the temporary objects, which will properly clean up the memory109  addMultiple(110    SinglePtr(make_unique<int>(1)),111    MultiPtr(make_unique<int>(2), make_unique<int>(3), make_unique<int>(4))112  );113}114 115// Test 5: Check that we DO report leaks for raw pointers in mixed ownership scenarios116struct MixedOwnership {117  unique_ptr<int> smart_ptr;  // Should NOT leak (smart pointer managed)118  int *raw_ptr;               // Should leak (raw pointer)119 120  MixedOwnership() : smart_ptr(make_unique<int>(1)), raw_ptr(new int(42)) {} // expected-note {{Memory is allocated}}121};122 123void consume(MixedOwnership obj) {124  // The unique_ptr destructor will be called when obj goes out of scope125  // But raw_ptr will leak!126}127 128void test_mixed_ownership() {129  // This should report a leak for raw_ptr but not for smart_ptr130  consume(MixedOwnership()); // expected-note {{Calling default constructor for 'MixedOwnership'}} expected-note {{Returning from default constructor for 'MixedOwnership'}}131} // expected-warning {{Potential memory leak}} expected-note {{Potential memory leak}}132 133// Test 6: Check that we handle direct smart pointer constructor calls correctly134void test_direct_constructor() {135  // Direct constructor call - should not leak136  int* raw_ptr = new int(42);137  unique_ptr<int> smart(raw_ptr); // This should escape the raw_ptr symbol138  // No leak should be reported here since smart pointer takes ownership139}140 141void test_mixed_direct_constructor() {142  int* raw1 = new int(1); 143  int* raw2 = new int(2); // expected-note {{Memory is allocated}}144  145  unique_ptr<int> smart(raw1); // This should escape raw1146  // raw2 should leak since it's not managed by any smart pointer147  int x = *raw2; // expected-warning {{Potential leak of memory pointed to by 'raw2'}} expected-note {{Potential leak of memory pointed to by 'raw2'}}148}149 150// Test 7: Multiple memory owning arguments - demonstrates addTransition API usage151void addMultipleOwningArgs(152  unique_ptr<int> ptr1,153  unique_ptr<int> ptr2, 154  unique_ptr<int> ptr3155) {156  // All unique_ptr destructors will be called when arguments go out of scope157  // This tests handling of multiple smart pointer parameters in a single call158}159 160void test_multiple_memory_owning_arguments() {161  // No warning should be emitted - all memory is properly managed by unique_ptr162  // This test specifically exercises the addTransition API with multiple owning arguments163  addMultipleOwningArgs(164    make_unique<int>(1),165    make_unique<int>(2), 166    make_unique<int>(3)167  );168}169 170} // namespace unique_ptr_tests171 172//===----------------------------------------------------------------------===//173// Variadic constructor test cases174//===----------------------------------------------------------------------===//175namespace variadic_constructor_tests {176 177// Variadic constructor - test for potential out-of-bounds access178// This is the only test in this namespace and tests a scenario where Call.getNumArgs() > CD->getNumParams()179// We use a synthetic unique_ptr here to activate the specific logic in the MallocChecker that will test out of bounds180template <typename T>181struct unique_ptr {182  T* ptr;183 184  // Constructor with ellipsis - can receive more arguments than parameters  185  unique_ptr(T* p, ...) : ptr(p) {}186 187  ~unique_ptr() {188    // This destructor intentionally doesn't delete 'ptr' to validate that the189    // heuristic trusts that smart pointers (based on their class name) will190    // release the pointee even if it doesn't understand their destructor.191  }192};193 194void process_variadic_smart_ptr(unique_ptr<int> ptr) {195  // Function body doesn't matter for this test196}197 198void test_variadic_constructor_bounds() {199  void *malloc_ptr = malloc(4); // expected-note {{Memory is allocated}}200  201  // This call creates a smart pointer with more arguments than formal parameters202  // The constructor has 1 formal parameter (T* p) plus ellipsis, but we pass multiple args203  // This should trigger the bounds checking issue in handleSmartPointerConstructorArguments204  int* raw_ptr = new int(42);205  process_variadic_smart_ptr(unique_ptr<int>(raw_ptr, 1, 2, 3, 4, 5));206  207  (void)malloc_ptr;208} // expected-warning {{Potential leak of memory pointed to by 'malloc_ptr'}}209  // expected-note@-1 {{Potential leak of memory pointed to by 'malloc_ptr'}}210 211} // namespace variadic_constructor_tests212 213//===----------------------------------------------------------------------===//214// shared_ptr test cases215//===----------------------------------------------------------------------===//216namespace shared_ptr_tests {217 218// Custom shared_ptr implementation for testing219template <typename T>220struct shared_ptr {221  T* ptr;222  shared_ptr(T* p) : ptr(p) {}223  ~shared_ptr() {224    // This destructor intentionally doesn't delete 'ptr' to validate that the225    // heuristic trusts that smart pointers (based on their class name) will226    // release the pointee even if it doesn't understand their destructor.227  }228  shared_ptr(shared_ptr&& other) : ptr(other.ptr) { other.ptr = nullptr; }229  T* get() const { return ptr; }230};231 232template <typename T, typename... Args>233shared_ptr<T> make_shared(Args&&... args) {234  return shared_ptr<T>(new T(args...));235}236 237// Test 1: Check that we don't report leaks for shared_ptr in temporary objects238struct Foo { 239  shared_ptr<int> i;240};241 242void add_foo(Foo foo) {243  // The shared_ptr destructor will be called when foo goes out of scope244}245 246void test_temporary_object() {247  // No warning should be emitted for this - the memory is managed by shared_ptr 248  // in the temporary Foo object, which will properly clean up the memory249  add_foo({make_shared<int>(1)});250}251 252} // namespace shared_ptr_tests253