llvm/clang/test/Analysis/malloc.cpp

// RUN: %clang_analyze_cc1 -w -verify %s \
// RUN:   -analyzer-checker=core \
// RUN:   -analyzer-checker=alpha.deadcode.UnreachableCode \
// RUN:   -analyzer-checker=alpha.core.CastSize \
// RUN:   -analyzer-checker=unix.Malloc \
// RUN:   -analyzer-checker=cplusplus.NewDelete \
// RUN:   -analyzer-checker=optin.taint.TaintPropagation \
// RUN:   -analyzer-checker=optin.taint.TaintedAlloc

// RUN: %clang_analyze_cc1 -w -verify %s \
// RUN:   -triple i386-unknown-linux-gnu \
// RUN:   -analyzer-checker=core \
// RUN:   -analyzer-checker=alpha.deadcode.UnreachableCode \
// RUN:   -analyzer-checker=alpha.core.CastSize \
// RUN:   -analyzer-checker=unix.Malloc \
// RUN:   -analyzer-checker=cplusplus.NewDelete \
// RUN:   -analyzer-checker=optin.taint.TaintPropagation \
// RUN:   -analyzer-checker=optin.taint.TaintedAlloc

// RUN: %clang_analyze_cc1 -w -verify %s -DTEST_INLINABLE_ALLOCATORS \
// RUN:   -analyzer-checker=core \
// RUN:   -analyzer-checker=alpha.deadcode.UnreachableCode \
// RUN:   -analyzer-checker=alpha.core.CastSize \
// RUN:   -analyzer-checker=unix.Malloc \
// RUN:   -analyzer-checker=cplusplus.NewDelete \
// RUN:   -analyzer-checker=optin.taint.TaintPropagation \
// RUN:   -analyzer-checker=optin.taint.TaintedAlloc

// RUN: %clang_analyze_cc1 -w -verify %s -DTEST_INLINABLE_ALLOCATORS \
// RUN:   -triple i386-unknown-linux-gnu \
// RUN:   -analyzer-checker=core \
// RUN:   -analyzer-checker=alpha.deadcode.UnreachableCode \
// RUN:   -analyzer-checker=alpha.core.CastSize \
// RUN:   -analyzer-checker=unix.Malloc \
// RUN:   -analyzer-checker=cplusplus.NewDelete \
// RUN:   -analyzer-checker=optin.taint.TaintPropagation \
// RUN:   -analyzer-checker=optin.taint.TaintedAlloc

#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);
int scanf( const char* format, ... );

void taintAlloc() {
  size_t size = 0;
  scanf("%zu", &size);
  int *ptr = new int[size];// expected-warning{{Memory allocation function is called with a tainted (potentially attacker controlled) value}}
  delete[] ptr;
}

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

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.
// 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

#define ZERO_SIZE_PTR ((void *)16)

void test_delete_ZERO_SIZE_PTR() {
  int *Ptr = (int *)ZERO_SIZE_PTR;
  // ZERO_SIZE_PTR is specially handled but only for malloc family
  delete Ptr; // expected-warning{{Argument to 'delete' is a constant address (16)}}
}

namespace pr46253_class {
class a {
  void *realloc(int, bool = false) { realloc(1); } // no-crash
};
} // namespace pr46253_class

namespace pr46253_retty{
void realloc(void *ptr, size_t size) { realloc(ptr, size); } // no-crash
} // namespace pr46253_retty

namespace pr46253_paramty{
void *realloc(void **ptr, size_t size) { realloc(ptr, size); } // no-crash
} // namespace pr46253_paramty

namespace pr46253_paramty2{
void *realloc(void *ptr, int size) { realloc(ptr, size); } // no-crash
} // namespace pr46253_paramty2

namespace pr81597 {
struct S {};
struct T {
  void free(const S& s);
};
void f(T& t) {
  S s;
  t.free(s); // no-warning: This is not the free you are looking for...
}
} // namespace pr81597