// RUN: %clang_analyze_cc1 -w -analyzer-checker=core,alpha.deadcode.UnreachableCode,alpha.core.CastSize,unix.Malloc,cplusplus.NewDelete -analyzer-store=region -verify %s
// RUN: %clang_analyze_cc1 -triple i386-unknown-linux-gnu -w -analyzer-checker=core,alpha.deadcode.UnreachableCode,alpha.core.CastSize,unix.Malloc,cplusplus.NewDelete -analyzer-store=region -verify %s
// RUN: %clang_analyze_cc1 -w -analyzer-checker=core,alpha.deadcode.UnreachableCode,alpha.core.CastSize,unix.Malloc,cplusplus.NewDelete -analyzer-store=region -DTEST_INLINABLE_ALLOCATORS -verify %s
// RUN: %clang_analyze_cc1 -triple i386-unknown-linux-gnu -w -analyzer-checker=core,alpha.deadcode.UnreachableCode,alpha.core.CastSize,unix.Malloc,cplusplus.NewDelete -analyzer-store=region -DTEST_INLINABLE_ALLOCATORS -verify %s

#include "Inputs/system-header-simulator-cxx.h"

typedef __typeof(sizeof(int)) size_t;
void *malloc(size_t);
void free(void *);
void *realloc(void *ptr, size_t size);
void *calloc(size_t nmemb, size_t size);
char *strdup(const char *s);

void checkThatMallocCheckerIsRunning() {
  malloc(4);
} // expected-warning{{leak}}

// Test for radar://11110132.
struct Foo {
    mutable void* m_data;
    Foo(void* data) : m_data(data) {}
};
Foo aFunction() {
    return malloc(10);
}

// Assume that functions which take a function pointer can free memory even if
// they are defined in system headers and take the const pointer to the
// allocated memory. (radar://11160612)
// Test default parameter.
int const_ptr_and_callback_def_param(int, const char*, int n, void(*)(void*) = free);
void r11160612_3() {
  char *x = (char*)malloc(12);
  const_ptr_and_callback_def_param(0, x, 12);
}

int const_ptr_and_callback_def_param_null(int, const char*, int n, void(*)(void*) = 0);
void r11160612_no_callback() {
  char *x = (char*)malloc(12);
  const_ptr_and_callback_def_param_null(0, x, 12);
} // expected-warning{{leak}}

// Test member function pointer.
struct CanFreeMemory {
  static void myFree(void*);
};
//This is handled because we look at the type of the parameter(not argument).
void r11160612_3(CanFreeMemory* p) {
  char *x = (char*)malloc(12);
  const_ptr_and_callback_def_param(0, x, 12, p->myFree);
}


namespace PR13751 {
  class OwningVector {
    void **storage;
    size_t length;
  public:
    OwningVector();
    ~OwningVector();
    void push_back(void *Item) {
      storage[length++] = Item;
    }
  };

  void testDestructors() {
    OwningVector v;
    v.push_back(malloc(4));
    // no leak warning; freed in destructor
  }
}

struct X { void *a; };

struct X get() {
  struct X result;
  result.a = malloc(4);
  return result; // no-warning
}

// Ensure that regions accessible through a LazyCompoundVal trigger region escape.
// Malloc checker used to report leaks for the following two test cases.
struct Property {
  char* getterName;
  Property(char* n)
  : getterName(n) {}

};
void append(Property x);

void appendWrapper(char *getterName) {
  append(Property(getterName));
}
void foo(const char* name) {
  char* getterName = strdup(name);
  appendWrapper(getterName); // no-warning
}

struct NestedProperty {
  Property prop;
  NestedProperty(Property p)
  : prop(p) {}
};
void appendNested(NestedProperty x);

void appendWrapperNested(char *getterName) {
  appendNested(NestedProperty(Property(getterName)));
}
void fooNested(const char* name) {
  char* getterName = strdup(name);
  appendWrapperNested(getterName); // no-warning
}

namespace PR31226 {
  struct b2 {
    int f;
  };

  struct b1 : virtual b2 {
    void m();
  };

  struct d : b1, b2 {
  };

  void f() {
    d *p = new d();
    p->m(); // no-crash // no-warning
  }
}

// Allow __cxa_demangle to escape.
char* test_cxa_demangle(const char* sym) {
  size_t funcnamesize = 256;
  char* funcname = (char*)malloc(funcnamesize);
  int status;
  char* ret = abi::__cxa_demangle(sym, funcname, &funcnamesize, &status);
  if (status == 0) {
    funcname = ret;
  }
  return funcname; // no-warning
}

namespace argument_leak {
class A {
  char *name;

public:
  char *getName() {
    if (!name) {
      name = static_cast<char *>(malloc(10));
    }
    return name;
  }
  ~A() {
    if (name) {
      delete[] name;
    }
  }
};

void test(A a) {
  (void)a.getName();
}
} // namespace argument_leak
