head	1.1;
branch	1.1.1;
access;
symbols
	netbsd-11-0-RC6:1.1.1.5
	netbsd-11-0-RC5:1.1.1.5
	netbsd-11-0-RC4:1.1.1.5
	netbsd-11-0-RC3:1.1.1.5
	netbsd-11-0-RC2:1.1.1.5
	netbsd-11-0-RC1:1.1.1.5
	perseant-exfatfs-base-20250801:1.1.1.5
	netbsd-11:1.1.1.5.0.10
	netbsd-11-base:1.1.1.5
	netbsd-10-1-RELEASE:1.1.1.5
	perseant-exfatfs-base-20240630:1.1.1.5
	perseant-exfatfs:1.1.1.5.0.8
	perseant-exfatfs-base:1.1.1.5
	netbsd-8-3-RELEASE:1.1.1.2
	netbsd-9-4-RELEASE:1.1.1.4
	netbsd-10-0-RELEASE:1.1.1.5
	netbsd-10-0-RC6:1.1.1.5
	netbsd-10-0-RC5:1.1.1.5
	netbsd-10-0-RC4:1.1.1.5
	netbsd-10-0-RC3:1.1.1.5
	netbsd-10-0-RC2:1.1.1.5
	netbsd-10-0-RC1:1.1.1.5
	netbsd-10:1.1.1.5.0.6
	netbsd-10-base:1.1.1.5
	netbsd-9-3-RELEASE:1.1.1.4
	cjep_sun2x:1.1.1.5.0.4
	cjep_sun2x-base:1.1.1.5
	cjep_staticlib_x-base1:1.1.1.5
	netbsd-9-2-RELEASE:1.1.1.4
	cjep_staticlib_x:1.1.1.5.0.2
	cjep_staticlib_x-base:1.1.1.5
	netbsd-9-1-RELEASE:1.1.1.4
	phil-wifi-20200421:1.1.1.5
	phil-wifi-20200411:1.1.1.5
	phil-wifi-20200406:1.1.1.5
	netbsd-8-2-RELEASE:1.1.1.2
	netbsd-9-0-RELEASE:1.1.1.4
	netbsd-9-0-RC2:1.1.1.4
	netbsd-9-0-RC1:1.1.1.4
	netbsd-9:1.1.1.4.0.2
	netbsd-9-base:1.1.1.4
	phil-wifi-20190609:1.1.1.4
	netbsd-8-1-RELEASE:1.1.1.2
	netbsd-8-1-RC1:1.1.1.2
	pgoyette-compat-merge-20190127:1.1.1.3.2.1
	pgoyette-compat-20190127:1.1.1.4
	pgoyette-compat-20190118:1.1.1.4
	pgoyette-compat-1226:1.1.1.4
	pgoyette-compat-1126:1.1.1.4
	pgoyette-compat-1020:1.1.1.4
	pgoyette-compat-0930:1.1.1.4
	pgoyette-compat-0906:1.1.1.4
	netbsd-7-2-RELEASE:1.1.1.2
	pgoyette-compat-0728:1.1.1.4
	clang-337282:1.1.1.4
	netbsd-8-0-RELEASE:1.1.1.2
	phil-wifi:1.1.1.3.0.4
	phil-wifi-base:1.1.1.3
	pgoyette-compat-0625:1.1.1.3
	netbsd-8-0-RC2:1.1.1.2
	pgoyette-compat-0521:1.1.1.3
	pgoyette-compat-0502:1.1.1.3
	pgoyette-compat-0422:1.1.1.3
	netbsd-8-0-RC1:1.1.1.2
	pgoyette-compat-0415:1.1.1.3
	pgoyette-compat-0407:1.1.1.3
	pgoyette-compat-0330:1.1.1.3
	pgoyette-compat-0322:1.1.1.3
	pgoyette-compat-0315:1.1.1.3
	netbsd-7-1-2-RELEASE:1.1.1.2
	pgoyette-compat:1.1.1.3.0.2
	pgoyette-compat-base:1.1.1.3
	netbsd-7-1-1-RELEASE:1.1.1.2
	clang-319952:1.1.1.3
	matt-nb8-mediatek:1.1.1.2.0.26
	matt-nb8-mediatek-base:1.1.1.2
	clang-309604:1.1.1.3
	perseant-stdc-iso10646:1.1.1.2.0.24
	perseant-stdc-iso10646-base:1.1.1.2
	netbsd-8:1.1.1.2.0.22
	netbsd-8-base:1.1.1.2
	prg-localcount2-base3:1.1.1.2
	prg-localcount2-base2:1.1.1.2
	prg-localcount2-base1:1.1.1.2
	prg-localcount2:1.1.1.2.0.20
	prg-localcount2-base:1.1.1.2
	pgoyette-localcount-20170426:1.1.1.2
	bouyer-socketcan-base1:1.1.1.2
	pgoyette-localcount-20170320:1.1.1.2
	netbsd-7-1:1.1.1.2.0.18
	netbsd-7-1-RELEASE:1.1.1.2
	netbsd-7-1-RC2:1.1.1.2
	clang-294123:1.1.1.2
	netbsd-7-nhusb-base-20170116:1.1.1.2
	bouyer-socketcan:1.1.1.2.0.16
	bouyer-socketcan-base:1.1.1.2
	clang-291444:1.1.1.2
	pgoyette-localcount-20170107:1.1.1.2
	netbsd-7-1-RC1:1.1.1.2
	pgoyette-localcount-20161104:1.1.1.2
	netbsd-7-0-2-RELEASE:1.1.1.2
	localcount-20160914:1.1.1.2
	netbsd-7-nhusb:1.1.1.2.0.14
	netbsd-7-nhusb-base:1.1.1.2
	clang-280599:1.1.1.2
	pgoyette-localcount-20160806:1.1.1.2
	pgoyette-localcount-20160726:1.1.1.2
	pgoyette-localcount:1.1.1.2.0.12
	pgoyette-localcount-base:1.1.1.2
	netbsd-7-0-1-RELEASE:1.1.1.2
	clang-261930:1.1.1.2
	netbsd-7-0:1.1.1.2.0.10
	netbsd-7-0-RELEASE:1.1.1.2
	netbsd-7-0-RC3:1.1.1.2
	netbsd-7-0-RC2:1.1.1.2
	netbsd-7-0-RC1:1.1.1.2
	clang-237755:1.1.1.2
	clang-232565:1.1.1.2
	clang-227398:1.1.1.2
	tls-maxphys-base:1.1.1.2
	tls-maxphys:1.1.1.2.0.8
	netbsd-7:1.1.1.2.0.6
	netbsd-7-base:1.1.1.2
	clang-215315:1.1.1.2
	clang-209886:1.1.1.2
	yamt-pagecache:1.1.1.2.0.4
	yamt-pagecache-base9:1.1.1.2
	tls-earlyentropy:1.1.1.2.0.2
	tls-earlyentropy-base:1.1.1.2
	riastradh-xf86-video-intel-2-7-1-pre-2-21-15:1.1.1.2
	riastradh-drm2-base3:1.1.1.2
	clang-202566:1.1.1.2
	clang-201163:1.1.1.2
	clang-199312:1.1.1.2
	clang-198450:1.1.1.2
	clang-196603:1.1.1.1
	clang-195771:1.1.1.1
	LLVM:1.1.1;
locks; strict;
comment	@// @;


1.1
date	2013.11.28.14.14.57;	author joerg;	state Exp;
branches
	1.1.1.1;
next	;
commitid	ow8OybrawrB1f3fx;

1.1.1.1
date	2013.11.28.14.14.57;	author joerg;	state Exp;
branches;
next	1.1.1.2;
commitid	ow8OybrawrB1f3fx;

1.1.1.2
date	2014.01.05.15.39.54;	author joerg;	state Exp;
branches
	1.1.1.2.4.1
	1.1.1.2.8.1;
next	1.1.1.3;
commitid	wh3aCSIWykURqWjx;

1.1.1.3
date	2017.08.01.19.34.40;	author joerg;	state Exp;
branches
	1.1.1.3.2.1
	1.1.1.3.4.1;
next	1.1.1.4;
commitid	pMuDy65V0VicSx1A;

1.1.1.4
date	2018.07.17.18.31.46;	author joerg;	state Exp;
branches;
next	1.1.1.5;
commitid	wDzL46ALjrCZgwKA;

1.1.1.5
date	2019.11.13.22.19.39;	author joerg;	state dead;
branches;
next	;
commitid	QD8YATxuNG34YJKB;

1.1.1.2.4.1
date	2014.01.05.15.39.54;	author yamt;	state dead;
branches;
next	1.1.1.2.4.2;
commitid	WSrDtL5nYAUyiyBx;

1.1.1.2.4.2
date	2014.05.22.16.18.34;	author yamt;	state Exp;
branches;
next	;
commitid	WSrDtL5nYAUyiyBx;

1.1.1.2.8.1
date	2014.01.05.15.39.54;	author tls;	state dead;
branches;
next	1.1.1.2.8.2;
commitid	jTnpym9Qu0o4R1Nx;

1.1.1.2.8.2
date	2014.08.19.23.47.35;	author tls;	state Exp;
branches;
next	;
commitid	jTnpym9Qu0o4R1Nx;

1.1.1.3.2.1
date	2018.07.28.04.33.28;	author pgoyette;	state Exp;
branches;
next	;
commitid	1UP1xAIUxv1ZgRLA;

1.1.1.3.4.1
date	2019.06.10.21.45.35;	author christos;	state Exp;
branches;
next	1.1.1.3.4.2;
commitid	jtc8rnCzWiEEHGqB;

1.1.1.3.4.2
date	2020.04.13.07.46.50;	author martin;	state dead;
branches;
next	;
commitid	X01YhRUPVUDaec4C;


desc
@@


1.1
log
@Initial revision
@
text
@// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-store region -std=c++11 -verify %s
#include "Inputs/system-header-simulator-cxx.h"

void clang_analyzer_eval(bool);

typedef __typeof__(sizeof(int)) size_t;
extern "C" void *malloc(size_t);
extern "C" void free(void *);

int someGlobal;

class SomeClass {
public:
  void f(int *p);
};

void testImplicitlyDeclaredGlobalNew() {
  if (someGlobal != 0)
    return;

  // This used to crash because the global operator new is being implicitly
  // declared and it does not have a valid source location. (PR13090)
  void *x = ::operator new(0);
  ::operator delete(x);

  // Check that the new/delete did not invalidate someGlobal;
  clang_analyzer_eval(someGlobal == 0); // expected-warning{{TRUE}}
}

void *testPlacementNew() {
  int *x = (int *)malloc(sizeof(int));
  *x = 1;
  clang_analyzer_eval(*x == 1); // expected-warning{{TRUE}};

  void *y = new (x) int;
  clang_analyzer_eval(x == y); // expected-warning{{TRUE}};
  clang_analyzer_eval(*x == 1); // expected-warning{{UNKNOWN}};

  return y;
}

void *operator new(size_t, size_t, int *);
void *testCustomNew() {
  int x[1] = {1};
  clang_analyzer_eval(*x == 1); // expected-warning{{TRUE}};

  void *y = new (0, x) int;
  clang_analyzer_eval(*x == 1); // expected-warning{{UNKNOWN}};

  return y; // no-warning
}

void *operator new(size_t, void *, void *);
void *testCustomNewMalloc() {
  int *x = (int *)malloc(sizeof(int));

  // Should be no-warning (the custom allocator could have freed x).
  void *y = new (0, x) int; // no-warning

  return y;
}

void testScalarInitialization() {
  int *n = new int(3);
  clang_analyzer_eval(*n == 3); // expected-warning{{TRUE}}

  new (n) int();
  clang_analyzer_eval(*n == 0); // expected-warning{{TRUE}}

  new (n) int{3};
  clang_analyzer_eval(*n == 3); // expected-warning{{TRUE}}

  new (n) int{};
  clang_analyzer_eval(*n == 0); // expected-warning{{TRUE}}
}

struct PtrWrapper {
  int *x;

  PtrWrapper(int *input) : x(input) {}
};

PtrWrapper *testNewInvalidation() {
  // Ensure that we don't consider this a leak.
  return new PtrWrapper(static_cast<int *>(malloc(4))); // no-warning
}

void testNewInvalidationPlacement(PtrWrapper *w) {
  // Ensure that we don't consider this a leak.
  new (w) PtrWrapper(static_cast<int *>(malloc(4))); // no-warning
}

int **testNewInvalidationScalar() {
  // Ensure that we don't consider this a leak.
  return new (int *)(static_cast<int *>(malloc(4))); // no-warning
}

void testNewInvalidationScalarPlacement(int **p) {
  // Ensure that we don't consider this a leak.
  new (p) (int *)(static_cast<int *>(malloc(4))); // no-warning
}

void testCacheOut(PtrWrapper w) {
  extern bool coin();
  if (coin())
    w.x = 0;
  new (&w.x) (int*)(0); // we cache out here; don't crash
}

void testUseAfter(int *p) {
  SomeClass *c = new SomeClass;
  free(p);
  c->f(p); // expected-warning{{Use of memory after it is freed}}
  delete c;
}

//--------------------------------------------------------------------
// Check for intersection with other checkers from MallocChecker.cpp 
// bounded with unix.Malloc
//--------------------------------------------------------------------

// new/delete oparators are subjects of cplusplus.NewDelete.
void testNewDeleteNoWarn() {
  int i;
  delete &i; // no-warning

  int *p1 = new int;
  delete ++p1; // no-warning

  int *p2 = new int;
  delete p2;
  delete p2; // no-warning

  int *p3 = new int; // no-warning
}

// unix.Malloc does not know about operators new/delete.
void testDeleteMallocked() {
  int *x = (int *)malloc(sizeof(int));
  delete x; // FIXME: Shoud detect pointer escape and keep silent after 'delete' is modeled properly.
} // expected-warning{{Potential leak of memory pointed to by 'x'}}

void testDeleteOpAfterFree() {
  int *p = (int *)malloc(sizeof(int));
  free(p);
  operator delete(p); // expected-warning{{Use of memory after it is freed}}
}

void testDeleteAfterFree() {
  int *p = (int *)malloc(sizeof(int));
  free(p);
  delete p; // expected-warning{{Use of memory after it is freed}}
}

void testStandardPlacementNewAfterFree() {
  int *p = (int *)malloc(sizeof(int));
  free(p);
  p = new(p) int; // expected-warning{{Use of memory after it is freed}}
}

void testCustomPlacementNewAfterFree() {
  int *p = (int *)malloc(sizeof(int));
  free(p);
  p = new(0, p) int; // expected-warning{{Use of memory after it is freed}}
}

void testUsingThisAfterDelete() {
  SomeClass *c = new SomeClass;
  delete c;
  c->f(0); // no-warning
}

void testAggregateNew() {
  struct Point { int x, y; };
  new Point{1, 2}; // no crash

  Point p;
  new (&p) Point{1, 2}; // no crash
  clang_analyzer_eval(p.x == 1); // expected-warning{{TRUE}}
  clang_analyzer_eval(p.y == 2); // expected-warning{{TRUE}}
}

//--------------------------------
// Incorrectly-modelled behavior
//--------------------------------

int testNoInitialization() {
  int *n = new int;

  // Should warn that *n is uninitialized.
  if (*n) { // no-warning
    delete n;
    return 0;
  }
  delete n;
  return 1;
}

int testNoInitializationPlacement() {
  int n;
  new (&n) int;

  // Should warn that n is uninitialized.
  if (n) { // no-warning
    return 0;
  }
  return 1;
}

// Test modelling destructor call on call to delete
class IntPair{
public:
  int x;
  int y;
  IntPair() {};
  ~IntPair() {x = x/y;}; //expected-warning {{Division by zero}}
};

void testCallToDestructor() {
  IntPair *b = new IntPair();
  b->x = 1;
  b->y = 0;
  delete b; // This results in divide by zero in destructor
}

// Test Deleting a value that's passed as an argument.
class DerefClass{
public:
  int *x;
  DerefClass() {};
  ~DerefClass() {*x = 1;}; //expected-warning {{Dereference of null pointer (loaded from field 'x')}}
};

void testDestCall(DerefClass *arg) {
  delete arg;
}

void test_delete_dtor_Arg() {
  DerefClass *pair = new DerefClass();
  pair->x = 0;
  testDestCall(pair);
}

//Deleting the address of a local variable, null pointer
void abort(void) __attribute__((noreturn));

class NoReturnDtor {
public:
  NoReturnDtor() {}
  ~NoReturnDtor() {abort();}
};

void test_delete_dtor_LocalVar() {
  NoReturnDtor test;
  delete &test; // no warn or crash
}

class DerivedNoReturn:public NoReturnDtor {
public:
  DerivedNoReturn() {};
  ~DerivedNoReturn() {};
};

void testNullDtorDerived() {
  DerivedNoReturn *p = new DerivedNoReturn();
  delete p; // Calls the base destructor which aborts, checked below
  clang_analyzer_eval(true); // no warn
}

//Deleting a non class pointer should not crash/warn
void test_var_delete() {
  int *v = new int;
  delete v;  // no crash/warn
  clang_analyzer_eval(true); // expected-warning{{TRUE}}
}

void testDeleteNull() {
  NoReturnDtor *foo = 0;
  delete foo; // should not call destructor, checked below
  clang_analyzer_eval(true); // expected-warning{{TRUE}}
}

void testNullAssigneddtor() {
  NoReturnDtor *p = 0;
  NoReturnDtor *s = p;
  delete s; // should not call destructor, checked below
  clang_analyzer_eval(true); // expected-warning{{TRUE}}
}

void deleteArg(NoReturnDtor *test) {
  delete test;
}

void testNulldtorArg() {
  NoReturnDtor *p = 0;
  deleteArg(p);
  clang_analyzer_eval(true); // expected-warning{{TRUE}}
}

void testDeleteUnknown(NoReturnDtor *foo) {
  delete foo; // should assume non-null and call noreturn destructor
  clang_analyzer_eval(true); // no-warning
}

void testArrayNull() {
  NoReturnDtor *fooArray = 0;
  delete[] fooArray; // should not call destructor, checked below
  clang_analyzer_eval(true); // expected-warning{{TRUE}}
}

void testArrayDestr() {
  NoReturnDtor *p = new NoReturnDtor[2];
  delete[] p; // Calls the base destructor which aborts, checked below
  //TODO: clang_analyzer_eval should not be called
  clang_analyzer_eval(true); // expected-warning{{TRUE}}
}

// Invalidate Region even in case of default destructor
class InvalidateDestTest {
public:
  int x;
  int *y;
  ~InvalidateDestTest();
};

int test_member_invalidation() {

  //test invalidation of member variable
  InvalidateDestTest *test = new InvalidateDestTest();
  test->x = 5;
  int *k = &(test->x);
  clang_analyzer_eval(*k == 5); // expected-warning{{TRUE}}
  delete test;
  clang_analyzer_eval(*k == 5); // expected-warning{{UNKNOWN}}

  //test invalidation of member pointer
  int localVar = 5;
  test = new InvalidateDestTest();
  test->y = &localVar;
  delete test;
  clang_analyzer_eval(localVar == 5); // expected-warning{{UNKNOWN}}

  // Test aray elements are invalidated.
  int Var1 = 5;
  int Var2 = 5;
  InvalidateDestTest *a = new InvalidateDestTest[2];
  a[0].y = &Var1;
  a[1].y = &Var2;
  delete[] a;
  clang_analyzer_eval(Var1 == 5); // expected-warning{{UNKNOWN}}
  clang_analyzer_eval(Var2 == 5); // expected-warning{{UNKNOWN}}
  return 0;
}
@


1.1.1.1
log
@Import Clang 3.4rc1 r195771.
@
text
@@


1.1.1.2
log
@Import clang 3.5svn r198450.
@
text
@d270 1
a270 1
//Deleting a non-class pointer should not crash/warn
@


1.1.1.3
log
@Import clang r309604 from branches/release_50
@
text
@d1 1
a1 1
// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-store region -std=c++11 -verify %s
@


1.1.1.3.4.1
log
@Sync with HEAD
@
text
@a1 1
// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-store region -std=c++11 -DTEST_INLINABLE_ALLOCATORS -verify %s
d37 1
a37 1
  clang_analyzer_eval(*x == 1); // expected-warning{{TRUE}};
d140 1
a140 1
  delete x; // FIXME: Should detect pointer escape and keep silent after 'delete' is modeled properly.
d203 2
a204 1
  if (n) { // expected-warning{{Branch condition evaluates to a garbage value}}
a276 18
void test_array_delete() {
  class C {
  public:
    ~C() {}
  };

  auto c1 = new C[2][3];
  delete[] c1; // no-crash // no-warning

  C c2[4];
  // FIXME: Should warn.
  delete[] &c2; // no-crash

  C c3[7][6];
  // FIXME: Should warn.
  delete[] &c3; // no-crash
}

d314 1
a314 1
   //TODO: clang_analyzer_eval should not be called
@


1.1.1.3.4.2
log
@Mostly merge changes from HEAD upto 20200411
@
text
@@


1.1.1.3.2.1
log
@Sync with HEAD
@
text
@a1 1
// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-store region -std=c++11 -DTEST_INLINABLE_ALLOCATORS -verify %s
d37 1
a37 1
  clang_analyzer_eval(*x == 1); // expected-warning{{TRUE}};
d140 1
a140 1
  delete x; // FIXME: Should detect pointer escape and keep silent after 'delete' is modeled properly.
d203 2
a204 1
  if (n) { // expected-warning{{Branch condition evaluates to a garbage value}}
a276 18
void test_array_delete() {
  class C {
  public:
    ~C() {}
  };

  auto c1 = new C[2][3];
  delete[] c1; // no-crash // no-warning

  C c2[4];
  // FIXME: Should warn.
  delete[] &c2; // no-crash

  C c3[7][6];
  // FIXME: Should warn.
  delete[] &c3; // no-crash
}

d314 1
a314 1
   //TODO: clang_analyzer_eval should not be called
@


1.1.1.4
log
@Import clang r337282 from trunk
@
text
@a1 1
// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-store region -std=c++11 -DTEST_INLINABLE_ALLOCATORS -verify %s
d37 1
a37 1
  clang_analyzer_eval(*x == 1); // expected-warning{{TRUE}};
d140 1
a140 1
  delete x; // FIXME: Should detect pointer escape and keep silent after 'delete' is modeled properly.
d203 2
a204 1
  if (n) { // expected-warning{{Branch condition evaluates to a garbage value}}
a276 18
void test_array_delete() {
  class C {
  public:
    ~C() {}
  };

  auto c1 = new C[2][3];
  delete[] c1; // no-crash // no-warning

  C c2[4];
  // FIXME: Should warn.
  delete[] &c2; // no-crash

  C c3[7][6];
  // FIXME: Should warn.
  delete[] &c3; // no-crash
}

d314 1
a314 1
   //TODO: clang_analyzer_eval should not be called
@


1.1.1.5
log
@Mark old LLVM instance as dead.
@
text
@@


1.1.1.2.8.1
log
@file new.cpp was added on branch tls-maxphys on 2014-08-19 23:47:35 +0000
@
text
@d1 353
@


1.1.1.2.8.2
log
@Rebase to HEAD as of a few days ago.
@
text
@a0 353
// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-store region -std=c++11 -verify %s
#include "Inputs/system-header-simulator-cxx.h"

void clang_analyzer_eval(bool);

typedef __typeof__(sizeof(int)) size_t;
extern "C" void *malloc(size_t);
extern "C" void free(void *);

int someGlobal;

class SomeClass {
public:
  void f(int *p);
};

void testImplicitlyDeclaredGlobalNew() {
  if (someGlobal != 0)
    return;

  // This used to crash because the global operator new is being implicitly
  // declared and it does not have a valid source location. (PR13090)
  void *x = ::operator new(0);
  ::operator delete(x);

  // Check that the new/delete did not invalidate someGlobal;
  clang_analyzer_eval(someGlobal == 0); // expected-warning{{TRUE}}
}

void *testPlacementNew() {
  int *x = (int *)malloc(sizeof(int));
  *x = 1;
  clang_analyzer_eval(*x == 1); // expected-warning{{TRUE}};

  void *y = new (x) int;
  clang_analyzer_eval(x == y); // expected-warning{{TRUE}};
  clang_analyzer_eval(*x == 1); // expected-warning{{UNKNOWN}};

  return y;
}

void *operator new(size_t, size_t, int *);
void *testCustomNew() {
  int x[1] = {1};
  clang_analyzer_eval(*x == 1); // expected-warning{{TRUE}};

  void *y = new (0, x) int;
  clang_analyzer_eval(*x == 1); // expected-warning{{UNKNOWN}};

  return y; // no-warning
}

void *operator new(size_t, void *, void *);
void *testCustomNewMalloc() {
  int *x = (int *)malloc(sizeof(int));

  // Should be no-warning (the custom allocator could have freed x).
  void *y = new (0, x) int; // no-warning

  return y;
}

void testScalarInitialization() {
  int *n = new int(3);
  clang_analyzer_eval(*n == 3); // expected-warning{{TRUE}}

  new (n) int();
  clang_analyzer_eval(*n == 0); // expected-warning{{TRUE}}

  new (n) int{3};
  clang_analyzer_eval(*n == 3); // expected-warning{{TRUE}}

  new (n) int{};
  clang_analyzer_eval(*n == 0); // expected-warning{{TRUE}}
}

struct PtrWrapper {
  int *x;

  PtrWrapper(int *input) : x(input) {}
};

PtrWrapper *testNewInvalidation() {
  // Ensure that we don't consider this a leak.
  return new PtrWrapper(static_cast<int *>(malloc(4))); // no-warning
}

void testNewInvalidationPlacement(PtrWrapper *w) {
  // Ensure that we don't consider this a leak.
  new (w) PtrWrapper(static_cast<int *>(malloc(4))); // no-warning
}

int **testNewInvalidationScalar() {
  // Ensure that we don't consider this a leak.
  return new (int *)(static_cast<int *>(malloc(4))); // no-warning
}

void testNewInvalidationScalarPlacement(int **p) {
  // Ensure that we don't consider this a leak.
  new (p) (int *)(static_cast<int *>(malloc(4))); // no-warning
}

void testCacheOut(PtrWrapper w) {
  extern bool coin();
  if (coin())
    w.x = 0;
  new (&w.x) (int*)(0); // we cache out here; don't crash
}

void testUseAfter(int *p) {
  SomeClass *c = new SomeClass;
  free(p);
  c->f(p); // expected-warning{{Use of memory after it is freed}}
  delete c;
}

//--------------------------------------------------------------------
// Check for intersection with other checkers from MallocChecker.cpp 
// bounded with unix.Malloc
//--------------------------------------------------------------------

// new/delete oparators are subjects of cplusplus.NewDelete.
void testNewDeleteNoWarn() {
  int i;
  delete &i; // no-warning

  int *p1 = new int;
  delete ++p1; // no-warning

  int *p2 = new int;
  delete p2;
  delete p2; // no-warning

  int *p3 = new int; // no-warning
}

// unix.Malloc does not know about operators new/delete.
void testDeleteMallocked() {
  int *x = (int *)malloc(sizeof(int));
  delete x; // FIXME: Shoud detect pointer escape and keep silent after 'delete' is modeled properly.
} // expected-warning{{Potential leak of memory pointed to by 'x'}}

void testDeleteOpAfterFree() {
  int *p = (int *)malloc(sizeof(int));
  free(p);
  operator delete(p); // expected-warning{{Use of memory after it is freed}}
}

void testDeleteAfterFree() {
  int *p = (int *)malloc(sizeof(int));
  free(p);
  delete p; // expected-warning{{Use of memory after it is freed}}
}

void testStandardPlacementNewAfterFree() {
  int *p = (int *)malloc(sizeof(int));
  free(p);
  p = new(p) int; // expected-warning{{Use of memory after it is freed}}
}

void testCustomPlacementNewAfterFree() {
  int *p = (int *)malloc(sizeof(int));
  free(p);
  p = new(0, p) int; // expected-warning{{Use of memory after it is freed}}
}

void testUsingThisAfterDelete() {
  SomeClass *c = new SomeClass;
  delete c;
  c->f(0); // no-warning
}

void testAggregateNew() {
  struct Point { int x, y; };
  new Point{1, 2}; // no crash

  Point p;
  new (&p) Point{1, 2}; // no crash
  clang_analyzer_eval(p.x == 1); // expected-warning{{TRUE}}
  clang_analyzer_eval(p.y == 2); // expected-warning{{TRUE}}
}

//--------------------------------
// Incorrectly-modelled behavior
//--------------------------------

int testNoInitialization() {
  int *n = new int;

  // Should warn that *n is uninitialized.
  if (*n) { // no-warning
    delete n;
    return 0;
  }
  delete n;
  return 1;
}

int testNoInitializationPlacement() {
  int n;
  new (&n) int;

  // Should warn that n is uninitialized.
  if (n) { // no-warning
    return 0;
  }
  return 1;
}

// Test modelling destructor call on call to delete
class IntPair{
public:
  int x;
  int y;
  IntPair() {};
  ~IntPair() {x = x/y;}; //expected-warning {{Division by zero}}
};

void testCallToDestructor() {
  IntPair *b = new IntPair();
  b->x = 1;
  b->y = 0;
  delete b; // This results in divide by zero in destructor
}

// Test Deleting a value that's passed as an argument.
class DerefClass{
public:
  int *x;
  DerefClass() {};
  ~DerefClass() {*x = 1;}; //expected-warning {{Dereference of null pointer (loaded from field 'x')}}
};

void testDestCall(DerefClass *arg) {
  delete arg;
}

void test_delete_dtor_Arg() {
  DerefClass *pair = new DerefClass();
  pair->x = 0;
  testDestCall(pair);
}

//Deleting the address of a local variable, null pointer
void abort(void) __attribute__((noreturn));

class NoReturnDtor {
public:
  NoReturnDtor() {}
  ~NoReturnDtor() {abort();}
};

void test_delete_dtor_LocalVar() {
  NoReturnDtor test;
  delete &test; // no warn or crash
}

class DerivedNoReturn:public NoReturnDtor {
public:
  DerivedNoReturn() {};
  ~DerivedNoReturn() {};
};

void testNullDtorDerived() {
  DerivedNoReturn *p = new DerivedNoReturn();
  delete p; // Calls the base destructor which aborts, checked below
  clang_analyzer_eval(true); // no warn
}

//Deleting a non-class pointer should not crash/warn
void test_var_delete() {
  int *v = new int;
  delete v;  // no crash/warn
  clang_analyzer_eval(true); // expected-warning{{TRUE}}
}

void testDeleteNull() {
  NoReturnDtor *foo = 0;
  delete foo; // should not call destructor, checked below
  clang_analyzer_eval(true); // expected-warning{{TRUE}}
}

void testNullAssigneddtor() {
  NoReturnDtor *p = 0;
  NoReturnDtor *s = p;
  delete s; // should not call destructor, checked below
  clang_analyzer_eval(true); // expected-warning{{TRUE}}
}

void deleteArg(NoReturnDtor *test) {
  delete test;
}

void testNulldtorArg() {
  NoReturnDtor *p = 0;
  deleteArg(p);
  clang_analyzer_eval(true); // expected-warning{{TRUE}}
}

void testDeleteUnknown(NoReturnDtor *foo) {
  delete foo; // should assume non-null and call noreturn destructor
  clang_analyzer_eval(true); // no-warning
}

void testArrayNull() {
  NoReturnDtor *fooArray = 0;
  delete[] fooArray; // should not call destructor, checked below
  clang_analyzer_eval(true); // expected-warning{{TRUE}}
}

void testArrayDestr() {
  NoReturnDtor *p = new NoReturnDtor[2];
  delete[] p; // Calls the base destructor which aborts, checked below
  //TODO: clang_analyzer_eval should not be called
  clang_analyzer_eval(true); // expected-warning{{TRUE}}
}

// Invalidate Region even in case of default destructor
class InvalidateDestTest {
public:
  int x;
  int *y;
  ~InvalidateDestTest();
};

int test_member_invalidation() {

  //test invalidation of member variable
  InvalidateDestTest *test = new InvalidateDestTest();
  test->x = 5;
  int *k = &(test->x);
  clang_analyzer_eval(*k == 5); // expected-warning{{TRUE}}
  delete test;
  clang_analyzer_eval(*k == 5); // expected-warning{{UNKNOWN}}

  //test invalidation of member pointer
  int localVar = 5;
  test = new InvalidateDestTest();
  test->y = &localVar;
  delete test;
  clang_analyzer_eval(localVar == 5); // expected-warning{{UNKNOWN}}

  // Test aray elements are invalidated.
  int Var1 = 5;
  int Var2 = 5;
  InvalidateDestTest *a = new InvalidateDestTest[2];
  a[0].y = &Var1;
  a[1].y = &Var2;
  delete[] a;
  clang_analyzer_eval(Var1 == 5); // expected-warning{{UNKNOWN}}
  clang_analyzer_eval(Var2 == 5); // expected-warning{{UNKNOWN}}
  return 0;
}
@


1.1.1.2.4.1
log
@file new.cpp was added on branch yamt-pagecache on 2014-05-22 16:18:34 +0000
@
text
@d1 353
@


1.1.1.2.4.2
log
@sync with head.

for a reference, the tree before this commit was tagged
as yamt-pagecache-tag8.

this commit was splitted into small chunks to avoid
a limitation of cvs.  ("Protocol error: too many arguments")
@
text
@a0 353
// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-store region -std=c++11 -verify %s
#include "Inputs/system-header-simulator-cxx.h"

void clang_analyzer_eval(bool);

typedef __typeof__(sizeof(int)) size_t;
extern "C" void *malloc(size_t);
extern "C" void free(void *);

int someGlobal;

class SomeClass {
public:
  void f(int *p);
};

void testImplicitlyDeclaredGlobalNew() {
  if (someGlobal != 0)
    return;

  // This used to crash because the global operator new is being implicitly
  // declared and it does not have a valid source location. (PR13090)
  void *x = ::operator new(0);
  ::operator delete(x);

  // Check that the new/delete did not invalidate someGlobal;
  clang_analyzer_eval(someGlobal == 0); // expected-warning{{TRUE}}
}

void *testPlacementNew() {
  int *x = (int *)malloc(sizeof(int));
  *x = 1;
  clang_analyzer_eval(*x == 1); // expected-warning{{TRUE}};

  void *y = new (x) int;
  clang_analyzer_eval(x == y); // expected-warning{{TRUE}};
  clang_analyzer_eval(*x == 1); // expected-warning{{UNKNOWN}};

  return y;
}

void *operator new(size_t, size_t, int *);
void *testCustomNew() {
  int x[1] = {1};
  clang_analyzer_eval(*x == 1); // expected-warning{{TRUE}};

  void *y = new (0, x) int;
  clang_analyzer_eval(*x == 1); // expected-warning{{UNKNOWN}};

  return y; // no-warning
}

void *operator new(size_t, void *, void *);
void *testCustomNewMalloc() {
  int *x = (int *)malloc(sizeof(int));

  // Should be no-warning (the custom allocator could have freed x).
  void *y = new (0, x) int; // no-warning

  return y;
}

void testScalarInitialization() {
  int *n = new int(3);
  clang_analyzer_eval(*n == 3); // expected-warning{{TRUE}}

  new (n) int();
  clang_analyzer_eval(*n == 0); // expected-warning{{TRUE}}

  new (n) int{3};
  clang_analyzer_eval(*n == 3); // expected-warning{{TRUE}}

  new (n) int{};
  clang_analyzer_eval(*n == 0); // expected-warning{{TRUE}}
}

struct PtrWrapper {
  int *x;

  PtrWrapper(int *input) : x(input) {}
};

PtrWrapper *testNewInvalidation() {
  // Ensure that we don't consider this a leak.
  return new PtrWrapper(static_cast<int *>(malloc(4))); // no-warning
}

void testNewInvalidationPlacement(PtrWrapper *w) {
  // Ensure that we don't consider this a leak.
  new (w) PtrWrapper(static_cast<int *>(malloc(4))); // no-warning
}

int **testNewInvalidationScalar() {
  // Ensure that we don't consider this a leak.
  return new (int *)(static_cast<int *>(malloc(4))); // no-warning
}

void testNewInvalidationScalarPlacement(int **p) {
  // Ensure that we don't consider this a leak.
  new (p) (int *)(static_cast<int *>(malloc(4))); // no-warning
}

void testCacheOut(PtrWrapper w) {
  extern bool coin();
  if (coin())
    w.x = 0;
  new (&w.x) (int*)(0); // we cache out here; don't crash
}

void testUseAfter(int *p) {
  SomeClass *c = new SomeClass;
  free(p);
  c->f(p); // expected-warning{{Use of memory after it is freed}}
  delete c;
}

//--------------------------------------------------------------------
// Check for intersection with other checkers from MallocChecker.cpp 
// bounded with unix.Malloc
//--------------------------------------------------------------------

// new/delete oparators are subjects of cplusplus.NewDelete.
void testNewDeleteNoWarn() {
  int i;
  delete &i; // no-warning

  int *p1 = new int;
  delete ++p1; // no-warning

  int *p2 = new int;
  delete p2;
  delete p2; // no-warning

  int *p3 = new int; // no-warning
}

// unix.Malloc does not know about operators new/delete.
void testDeleteMallocked() {
  int *x = (int *)malloc(sizeof(int));
  delete x; // FIXME: Shoud detect pointer escape and keep silent after 'delete' is modeled properly.
} // expected-warning{{Potential leak of memory pointed to by 'x'}}

void testDeleteOpAfterFree() {
  int *p = (int *)malloc(sizeof(int));
  free(p);
  operator delete(p); // expected-warning{{Use of memory after it is freed}}
}

void testDeleteAfterFree() {
  int *p = (int *)malloc(sizeof(int));
  free(p);
  delete p; // expected-warning{{Use of memory after it is freed}}
}

void testStandardPlacementNewAfterFree() {
  int *p = (int *)malloc(sizeof(int));
  free(p);
  p = new(p) int; // expected-warning{{Use of memory after it is freed}}
}

void testCustomPlacementNewAfterFree() {
  int *p = (int *)malloc(sizeof(int));
  free(p);
  p = new(0, p) int; // expected-warning{{Use of memory after it is freed}}
}

void testUsingThisAfterDelete() {
  SomeClass *c = new SomeClass;
  delete c;
  c->f(0); // no-warning
}

void testAggregateNew() {
  struct Point { int x, y; };
  new Point{1, 2}; // no crash

  Point p;
  new (&p) Point{1, 2}; // no crash
  clang_analyzer_eval(p.x == 1); // expected-warning{{TRUE}}
  clang_analyzer_eval(p.y == 2); // expected-warning{{TRUE}}
}

//--------------------------------
// Incorrectly-modelled behavior
//--------------------------------

int testNoInitialization() {
  int *n = new int;

  // Should warn that *n is uninitialized.
  if (*n) { // no-warning
    delete n;
    return 0;
  }
  delete n;
  return 1;
}

int testNoInitializationPlacement() {
  int n;
  new (&n) int;

  // Should warn that n is uninitialized.
  if (n) { // no-warning
    return 0;
  }
  return 1;
}

// Test modelling destructor call on call to delete
class IntPair{
public:
  int x;
  int y;
  IntPair() {};
  ~IntPair() {x = x/y;}; //expected-warning {{Division by zero}}
};

void testCallToDestructor() {
  IntPair *b = new IntPair();
  b->x = 1;
  b->y = 0;
  delete b; // This results in divide by zero in destructor
}

// Test Deleting a value that's passed as an argument.
class DerefClass{
public:
  int *x;
  DerefClass() {};
  ~DerefClass() {*x = 1;}; //expected-warning {{Dereference of null pointer (loaded from field 'x')}}
};

void testDestCall(DerefClass *arg) {
  delete arg;
}

void test_delete_dtor_Arg() {
  DerefClass *pair = new DerefClass();
  pair->x = 0;
  testDestCall(pair);
}

//Deleting the address of a local variable, null pointer
void abort(void) __attribute__((noreturn));

class NoReturnDtor {
public:
  NoReturnDtor() {}
  ~NoReturnDtor() {abort();}
};

void test_delete_dtor_LocalVar() {
  NoReturnDtor test;
  delete &test; // no warn or crash
}

class DerivedNoReturn:public NoReturnDtor {
public:
  DerivedNoReturn() {};
  ~DerivedNoReturn() {};
};

void testNullDtorDerived() {
  DerivedNoReturn *p = new DerivedNoReturn();
  delete p; // Calls the base destructor which aborts, checked below
  clang_analyzer_eval(true); // no warn
}

//Deleting a non-class pointer should not crash/warn
void test_var_delete() {
  int *v = new int;
  delete v;  // no crash/warn
  clang_analyzer_eval(true); // expected-warning{{TRUE}}
}

void testDeleteNull() {
  NoReturnDtor *foo = 0;
  delete foo; // should not call destructor, checked below
  clang_analyzer_eval(true); // expected-warning{{TRUE}}
}

void testNullAssigneddtor() {
  NoReturnDtor *p = 0;
  NoReturnDtor *s = p;
  delete s; // should not call destructor, checked below
  clang_analyzer_eval(true); // expected-warning{{TRUE}}
}

void deleteArg(NoReturnDtor *test) {
  delete test;
}

void testNulldtorArg() {
  NoReturnDtor *p = 0;
  deleteArg(p);
  clang_analyzer_eval(true); // expected-warning{{TRUE}}
}

void testDeleteUnknown(NoReturnDtor *foo) {
  delete foo; // should assume non-null and call noreturn destructor
  clang_analyzer_eval(true); // no-warning
}

void testArrayNull() {
  NoReturnDtor *fooArray = 0;
  delete[] fooArray; // should not call destructor, checked below
  clang_analyzer_eval(true); // expected-warning{{TRUE}}
}

void testArrayDestr() {
  NoReturnDtor *p = new NoReturnDtor[2];
  delete[] p; // Calls the base destructor which aborts, checked below
  //TODO: clang_analyzer_eval should not be called
  clang_analyzer_eval(true); // expected-warning{{TRUE}}
}

// Invalidate Region even in case of default destructor
class InvalidateDestTest {
public:
  int x;
  int *y;
  ~InvalidateDestTest();
};

int test_member_invalidation() {

  //test invalidation of member variable
  InvalidateDestTest *test = new InvalidateDestTest();
  test->x = 5;
  int *k = &(test->x);
  clang_analyzer_eval(*k == 5); // expected-warning{{TRUE}}
  delete test;
  clang_analyzer_eval(*k == 5); // expected-warning{{UNKNOWN}}

  //test invalidation of member pointer
  int localVar = 5;
  test = new InvalidateDestTest();
  test->y = &localVar;
  delete test;
  clang_analyzer_eval(localVar == 5); // expected-warning{{UNKNOWN}}

  // Test aray elements are invalidated.
  int Var1 = 5;
  int Var2 = 5;
  InvalidateDestTest *a = new InvalidateDestTest[2];
  a[0].y = &Var1;
  a[1].y = &Var2;
  delete[] a;
  clang_analyzer_eval(Var1 == 5); // expected-warning{{UNKNOWN}}
  clang_analyzer_eval(Var2 == 5); // expected-warning{{UNKNOWN}}
  return 0;
}
@


