head	1.1;
branch	1.1.1;
access;
symbols
	netbsd-10-2-RELEASE:1.1.1.8
	netbsd-9-5-RELEASE:1.1.1.7
	netbsd-11-0-RELEASE:1.1.1.8
	netbsd-11-0-RC7:1.1.1.8
	netbsd-11-0-RC6:1.1.1.8
	netbsd-11-0-RC5:1.1.1.8
	netbsd-11-0-RC4:1.1.1.8
	netbsd-11-0-RC3:1.1.1.8
	netbsd-11-0-RC2:1.1.1.8
	netbsd-11-0-RC1:1.1.1.8
	perseant-exfatfs-base-20250801:1.1.1.8
	netbsd-11:1.1.1.8.0.10
	netbsd-11-base:1.1.1.8
	netbsd-10-1-RELEASE:1.1.1.8
	perseant-exfatfs-base-20240630:1.1.1.8
	perseant-exfatfs:1.1.1.8.0.8
	perseant-exfatfs-base:1.1.1.8
	netbsd-8-3-RELEASE:1.1.1.5
	netbsd-9-4-RELEASE:1.1.1.7
	netbsd-10-0-RELEASE:1.1.1.8
	netbsd-10-0-RC6:1.1.1.8
	netbsd-10-0-RC5:1.1.1.8
	netbsd-10-0-RC4:1.1.1.8
	netbsd-10-0-RC3:1.1.1.8
	netbsd-10-0-RC2:1.1.1.8
	netbsd-10-0-RC1:1.1.1.8
	netbsd-10:1.1.1.8.0.6
	netbsd-10-base:1.1.1.8
	netbsd-9-3-RELEASE:1.1.1.7
	cjep_sun2x:1.1.1.8.0.4
	cjep_sun2x-base:1.1.1.8
	cjep_staticlib_x-base1:1.1.1.8
	netbsd-9-2-RELEASE:1.1.1.7
	cjep_staticlib_x:1.1.1.8.0.2
	cjep_staticlib_x-base:1.1.1.8
	netbsd-9-1-RELEASE:1.1.1.7
	phil-wifi-20200421:1.1.1.8
	phil-wifi-20200411:1.1.1.8
	phil-wifi-20200406:1.1.1.8
	netbsd-8-2-RELEASE:1.1.1.5
	netbsd-9-0-RELEASE:1.1.1.7
	netbsd-9-0-RC2:1.1.1.7
	netbsd-9-0-RC1:1.1.1.7
	netbsd-9:1.1.1.7.0.2
	netbsd-9-base:1.1.1.7
	phil-wifi-20190609:1.1.1.7
	netbsd-8-1-RELEASE:1.1.1.5
	netbsd-8-1-RC1:1.1.1.5
	pgoyette-compat-merge-20190127:1.1.1.6.2.1
	pgoyette-compat-20190127:1.1.1.7
	pgoyette-compat-20190118:1.1.1.7
	pgoyette-compat-1226:1.1.1.7
	pgoyette-compat-1126:1.1.1.7
	pgoyette-compat-1020:1.1.1.7
	pgoyette-compat-0930:1.1.1.7
	pgoyette-compat-0906:1.1.1.7
	netbsd-7-2-RELEASE:1.1.1.2.6.1
	pgoyette-compat-0728:1.1.1.7
	clang-337282:1.1.1.7
	netbsd-8-0-RELEASE:1.1.1.5
	phil-wifi:1.1.1.6.0.4
	phil-wifi-base:1.1.1.6
	pgoyette-compat-0625:1.1.1.6
	netbsd-8-0-RC2:1.1.1.5
	pgoyette-compat-0521:1.1.1.6
	pgoyette-compat-0502:1.1.1.6
	pgoyette-compat-0422:1.1.1.6
	netbsd-8-0-RC1:1.1.1.5
	pgoyette-compat-0415:1.1.1.6
	pgoyette-compat-0407:1.1.1.6
	pgoyette-compat-0330:1.1.1.6
	pgoyette-compat-0322:1.1.1.6
	pgoyette-compat-0315:1.1.1.6
	netbsd-7-1-2-RELEASE:1.1.1.2.6.1
	pgoyette-compat:1.1.1.6.0.2
	pgoyette-compat-base:1.1.1.6
	netbsd-7-1-1-RELEASE:1.1.1.2.6.1
	clang-319952:1.1.1.6
	matt-nb8-mediatek:1.1.1.5.0.10
	matt-nb8-mediatek-base:1.1.1.5
	clang-309604:1.1.1.6
	perseant-stdc-iso10646:1.1.1.5.0.8
	perseant-stdc-iso10646-base:1.1.1.5
	netbsd-8:1.1.1.5.0.6
	netbsd-8-base:1.1.1.5
	prg-localcount2-base3:1.1.1.5
	prg-localcount2-base2:1.1.1.5
	prg-localcount2-base1:1.1.1.5
	prg-localcount2:1.1.1.5.0.4
	prg-localcount2-base:1.1.1.5
	pgoyette-localcount-20170426:1.1.1.5
	bouyer-socketcan-base1:1.1.1.5
	pgoyette-localcount-20170320:1.1.1.5
	netbsd-7-1:1.1.1.2.6.1.0.6
	netbsd-7-1-RELEASE:1.1.1.2.6.1
	netbsd-7-1-RC2:1.1.1.2.6.1
	clang-294123:1.1.1.5
	netbsd-7-nhusb-base-20170116:1.1.1.2.6.1
	bouyer-socketcan:1.1.1.5.0.2
	bouyer-socketcan-base:1.1.1.5
	clang-291444:1.1.1.5
	pgoyette-localcount-20170107:1.1.1.4
	netbsd-7-1-RC1:1.1.1.2.6.1
	pgoyette-localcount-20161104:1.1.1.4
	netbsd-7-0-2-RELEASE:1.1.1.2.6.1
	localcount-20160914:1.1.1.4
	netbsd-7-nhusb:1.1.1.2.6.1.0.4
	netbsd-7-nhusb-base:1.1.1.2.6.1
	clang-280599:1.1.1.4
	pgoyette-localcount-20160806:1.1.1.4
	pgoyette-localcount-20160726:1.1.1.4
	pgoyette-localcount:1.1.1.4.0.2
	pgoyette-localcount-base:1.1.1.4
	netbsd-7-0-1-RELEASE:1.1.1.2.6.1
	clang-261930:1.1.1.4
	netbsd-7-0:1.1.1.2.6.1.0.2
	netbsd-7-0-RELEASE:1.1.1.2.6.1
	netbsd-7-0-RC3:1.1.1.2.6.1
	netbsd-7-0-RC2:1.1.1.2.6.1
	netbsd-7-0-RC1:1.1.1.2.6.1
	clang-237755:1.1.1.3
	clang-232565:1.1.1.3
	clang-227398:1.1.1.3
	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.1
	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.15.21.26.08;	author joerg;	state Exp;
branches
	1.1.1.2.4.1
	1.1.1.2.6.1
	1.1.1.2.8.1;
next	1.1.1.3;
commitid	NQXlzzA0SPkc5glx;

1.1.1.3
date	2015.01.29.19.57.33;	author joerg;	state Exp;
branches;
next	1.1.1.4;
commitid	mlISSizlPKvepX7y;

1.1.1.4
date	2016.02.27.22.10.19;	author joerg;	state Exp;
branches
	1.1.1.4.2.1;
next	1.1.1.5;
commitid	tIimz3oDlh1NpBWy;

1.1.1.5
date	2017.01.11.10.37.06;	author joerg;	state Exp;
branches;
next	1.1.1.6;
commitid	CNnUNfII1jgNmxBz;

1.1.1.6
date	2017.08.01.19.34.37;	author joerg;	state Exp;
branches
	1.1.1.6.2.1
	1.1.1.6.4.1;
next	1.1.1.7;
commitid	pMuDy65V0VicSx1A;

1.1.1.7
date	2018.07.17.18.31.46;	author joerg;	state Exp;
branches;
next	1.1.1.8;
commitid	wDzL46ALjrCZgwKA;

1.1.1.8
date	2019.11.13.22.19.38;	author joerg;	state dead;
branches;
next	;
commitid	QD8YATxuNG34YJKB;

1.1.1.2.4.1
date	2014.01.15.21.26.08;	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.6.1
date	2015.06.04.20.04.31;	author snj;	state Exp;
branches;
next	;
commitid	yRnjq9fueSo6n9oy;

1.1.1.2.8.1
date	2014.01.15.21.26.08;	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.34;	author tls;	state Exp;
branches;
next	;
commitid	jTnpym9Qu0o4R1Nx;

1.1.1.4.2.1
date	2017.03.20.06.52.47;	author pgoyette;	state Exp;
branches;
next	;
commitid	jjw7cAwgyKq7RfKz;

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

1.1.1.6.4.1
date	2019.06.10.21.45.34;	author christos;	state Exp;
branches;
next	1.1.1.6.4.2;
commitid	jtc8rnCzWiEEHGqB;

1.1.1.6.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,cplusplus.NewDelete -std=c++11 -fblocks -verify %s
// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.cplusplus.NewDeleteLeaks -DLEAKS -std=c++11 -fblocks -verify %s
#include "Inputs/system-header-simulator-cxx.h"

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

//------------------
// check for leaks
//------------------

//----- Standard non-placement operators
void testGlobalOpNew() {
  void *p = operator new(0);
}
#ifdef LEAKS
// expected-warning@@-2{{Potential leak of memory pointed to by 'p'}}
#endif

void testGlobalOpNewArray() {
  void *p = operator new[](0);
}
#ifdef LEAKS
// expected-warning@@-2{{Potential leak of memory pointed to by 'p'}}
#endif

void testGlobalNewExpr() {
  int *p = new int;
}
#ifdef LEAKS
// expected-warning@@-2{{Potential leak of memory pointed to by 'p'}}
#endif

void testGlobalNewExprArray() {
  int *p = new int[0];
}
#ifdef LEAKS
// expected-warning@@-2{{Potential leak of memory pointed to by 'p'}}
#endif

//----- Standard nothrow placement operators
void testGlobalNoThrowPlacementOpNewBeforeOverload() {
  void *p = operator new(0, std::nothrow);
}
#ifdef LEAKS
// expected-warning@@-2{{Potential leak of memory pointed to by 'p'}}
#endif

void testGlobalNoThrowPlacementExprNewBeforeOverload() {
  int *p = new(std::nothrow) int;
}
#ifdef LEAKS
// expected-warning@@-2{{Potential leak of memory pointed to by 'p'}}
#endif

//----- Standard pointer placement operators
void testGlobalPointerPlacementNew() {
  int i;

  void *p1 = operator new(0, &i); // no warn

  void *p2 = operator new[](0, &i); // no warn

  int *p3 = new(&i) int; // no warn

  int *p4 = new(&i) int[0]; // no warn
}

//----- Other cases
void testNewMemoryIsInHeap() {
  int *p = new int;
  if (global != p) // condition is always true as 'p' wraps a heap region that 
                   // is different from a region wrapped by 'global'
    global = p; // pointer escapes
}

struct PtrWrapper {
  int *x;

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

void testNewInvalidationPlacement(PtrWrapper *w) {
  // Ensure that we don't consider this a leak.
  new (w) PtrWrapper(new int); // no warn
}

//---------------
// other checks
//---------------

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

void f(int *p1, int *p2 = 0, int *p3 = 0);
void g(SomeClass &c, ...);

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

void testUseMiddleArgAfterDelete(int *p) {
  delete p;
  f(0, p); // expected-warning{{Use of memory after it is freed}}
}

void testUseLastArgAfterDelete(int *p) {
  delete p;
  f(0, 0, p); // expected-warning{{Use of memory after it is freed}}
}

void testUseSeveralArgsAfterDelete(int *p) {
  delete p;
  f(p, p, p); // expected-warning{{Use of memory after it is freed}}
}

void testUseRefArgAfterDelete(SomeClass &c) {
  delete &c;
  g(c); // expected-warning{{Use of memory after it is freed}}
}

void testVariadicArgAfterDelete() {
  SomeClass c;
  int *p = new int;
  delete p;
  g(c, 0, p); // expected-warning{{Use of memory after it is freed}}
}

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

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

void testDeleteAlloca() {
  int *p = (int *)__builtin_alloca(sizeof(int));
  delete p; // expected-warning{{Memory allocated by alloca() should not be deallocated}}
}

void testDoubleDelete() {
  int *p = new int;
  delete p;
  delete p; // expected-warning{{Attempt to free released memory}}
}

void testExprDeleteArg() {
  int i;
  delete &i; // expected-warning{{Argument to 'delete' is the address of the local variable 'i', which is not memory allocated by 'new'}}
}

void testExprDeleteArrArg() {
  int i;
  delete[] &i; // expected-warning{{Argument to 'delete[]' is the address of the local variable 'i', which is not memory allocated by 'new[]'}}
}

void testAllocDeallocNames() {
  int *p = new(std::nothrow) int[1];
  delete[] (++p); // expected-warning{{Argument to 'delete[]' is offset by 4 bytes from the start of memory allocated by 'new[]'}}
}

//--------------------------------
// Test escape of newed const pointer. Note, a const pointer can be deleted.
//--------------------------------
struct StWithConstPtr {
  const int *memp;
};
void escape(const int &x);
void escapeStruct(const StWithConstPtr &x);
void escapePtr(const StWithConstPtr *x);
void escapeVoidPtr(const void *x);

void testConstEscape() {
  int *p = new int(1);
  escape(*p);
} // no-warning

void testConstEscapeStruct() {
  StWithConstPtr *St = new StWithConstPtr();
  escapeStruct(*St);
} // no-warning

void testConstEscapeStructPtr() {
  StWithConstPtr *St = new StWithConstPtr();
  escapePtr(St);
} // no-warning

void testConstEscapeMember() {
  StWithConstPtr St;
  St.memp = new int(2);
  escapeVoidPtr(St.memp);
} // no-warning

void testConstEscapePlacementNew() {
  int *x = (int *)malloc(sizeof(int));
  void *y = new (x) int;
  escapeVoidPtr(y);
} // no-warning

//============== Test Uninitialized delete delete[]========================
void testUninitDelete() {
  int *x;
  int * y = new int;
  delete y;
  delete x; // expected-warning{{Argument to 'delete' is uninitialized}}
}

void testUninitDeleteArray() {
  int *x;
  int * y = new int[5];
  delete[] y;
  delete[] x; // expected-warning{{Argument to 'delete[]' is uninitialized}}
}

void testUninitFree() {
  int *x;
  free(x); // expected-warning{{Function call argument is an uninitialized value}}
}

void testUninitDeleteSink() {
  int *x;
  delete x; // expected-warning{{Argument to 'delete' is uninitialized}}
  (*(volatile int *)0 = 1); // no warn
}

void testUninitDeleteArraySink() {
  int *x;
  delete[] x; // expected-warning{{Argument to 'delete[]' is uninitialized}}
  (*(volatile int *)0 = 1); // no warn
}

namespace reference_count {
  class control_block {
    unsigned count;
  public:
    control_block() : count(0) {}
    void retain() { ++count; }
    int release() { return --count; }
  };

  template <typename T>
  class shared_ptr {
    T *p;
    control_block *control;

  public:
    shared_ptr() : p(0), control(0) {}
    explicit shared_ptr(T *p) : p(p), control(new control_block) {
      control->retain();
    }
    shared_ptr(shared_ptr &other) : p(other.p), control(other.control) {
      if (control)
          control->retain();
    }
    ~shared_ptr() {
      if (control && control->release() == 0) {
        delete p;
        delete control;
      }
    };

    T &operator *() {
      return *p;
    };

    void swap(shared_ptr &other) {
      T *tmp = p;
      p = other.p;
      other.p = tmp;

      control_block *ctrlTmp = control;
      control = other.control;
      other.control = ctrlTmp;
    }
  };

  void testSingle() {
    shared_ptr<int> a(new int);
    *a = 1;
  }

  void testDouble() {
    shared_ptr<int> a(new int);
    shared_ptr<int> b = a;
    *a = 1;
  }

  void testInvalidated() {
    shared_ptr<int> a(new int);
    shared_ptr<int> b = a;
    *a = 1;

    extern void use(shared_ptr<int> &);
    use(b);
  }

  void testNestedScope() {
    shared_ptr<int> a(new int);
    {
      shared_ptr<int> b = a;
    }
    *a = 1;
  }

  void testSwap() {
    shared_ptr<int> a(new int);
    shared_ptr<int> b;
    shared_ptr<int> c = a;
    shared_ptr<int>(c).swap(b);
  }

  void testUseAfterFree() {
    int *p = new int;
    {
      shared_ptr<int> a(p);
      shared_ptr<int> b = a;
    }

    // FIXME: We should get a warning here, but we don't because we've
    // conservatively modeled ~shared_ptr.
    *p = 1;
  }
}

// Test double delete
class DerefClass{
public:
  int *x;
  DerefClass() {}
  ~DerefClass() {*x = 1;} //expected-warning {{Use of memory after it is freed}}
};

void testDoubleDeleteClassInstance() {
  DerefClass *foo = new DerefClass();
  delete foo;
  delete foo; // FIXME: We should ideally report warning here instead of inside the destructor.
}

class EmptyClass{
public:
  EmptyClass() {}
  ~EmptyClass() {}
};

void testDoubleDeleteEmptyClass() {
  EmptyClass *foo = new EmptyClass();
  delete foo;
  delete foo;  //expected-warning {{Attempt to free released memory}}
}
@


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


1.1.1.2
log
@Import Clang 3.5svn r199312
@
text
@d341 1
a341 1
  ~DerefClass() {*x = 1;}
d347 1
a347 1
  delete foo; // expected-warning {{Attempt to delete released memory}}
d359 1
a359 1
  delete foo;  // expected-warning {{Attempt to delete released memory}}
@


1.1.1.2.6.1
log
@Update LLVM to 3.6.1, requested by joerg in ticket 824.
@
text
@d2 1
a2 1
// RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus.NewDeleteLeaks -DLEAKS -std=c++11 -fblocks -verify %s
@


1.1.1.3
log
@Import Clang 3.6RC1 r227398.
@
text
@d2 1
a2 1
// RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus.NewDeleteLeaks -DLEAKS -std=c++11 -fblocks -verify %s
@


1.1.1.4
log
@Import Clang 3.8.0rc3 r261930.
@
text
@a89 24
//-----------------------------------------
// check for usage of zero-allocated memory
//-----------------------------------------

void testUseZeroAlloc1() {
  int *p = (int *)operator new(0);
  *p = 1; // expected-warning {{Use of zero-allocated memory}}
  delete p;
}

int testUseZeroAlloc2() {
  int *p = (int *)operator new[](0);
  return p[0]; // expected-warning {{Use of zero-allocated memory}}
  delete[] p;
}

void f(int);

void testUseZeroAlloc3() {
  int *p = new int[0];
  f(*p); // expected-warning {{Use of zero-allocated memory}}
  delete[] p;
}

d147 5
@


1.1.1.4.2.1
log
@Sync with HEAD
@
text
@a379 16

struct Base {
  virtual ~Base() {}
};

struct Derived : Base {
};

Base *allocate() {
  return new Derived;
}

void shouldNotReportLeak() {
  Derived *p = (Derived *)allocate();
  delete p;
}
@


1.1.1.5
log
@Import Clang pre-4.0.0 r291444.
@
text
@a379 16

struct Base {
  virtual ~Base() {}
};

struct Derived : Base {
};

Base *allocate() {
  return new Derived;
}

void shouldNotReportLeak() {
  Derived *p = (Derived *)allocate();
  delete p;
}
@


1.1.1.6
log
@Import clang r309604 from branches/release_50
@
text
@d1 2
a2 2
// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDelete -std=c++11 -fblocks -verify %s
// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDeleteLeaks -DLEAKS -std=c++11 -fblocks -verify %s
d247 1
a247 1
  free(x); // expected-warning{{1st function call argument is an uninitialized value}}
@


1.1.1.6.4.1
log
@Sync with HEAD
@
text
@a2 7
// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDelete -std=c++11 -fblocks -analyzer-config c++-allocator-inlining=true -verify %s
// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDeleteLeaks -DLEAKS -std=c++11 -fblocks -analyzer-config c++-allocator-inlining=true -verify %s
// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDelete -std=c++11 -fblocks -DTEST_INLINABLE_ALLOCATORS -verify %s
// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDeleteLeaks -DLEAKS -std=c++11 -fblocks -DTEST_INLINABLE_ALLOCATORS -verify %s
// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDelete -std=c++11 -fblocks -analyzer-config c++-allocator-inlining=true -DTEST_INLINABLE_ALLOCATORS -verify %s
// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDeleteLeaks -DLEAKS -std=c++11 -fblocks -analyzer-config c++-allocator-inlining=true -DTEST_INLINABLE_ALLOCATORS -verify %s

d48 1
a48 3
#ifndef TEST_INLINABLE_ALLOCATORS
// expected-warning@@-3{{Potential leak of memory pointed to by 'p'}}
#endif
d55 1
a55 3
#ifndef TEST_INLINABLE_ALLOCATORS
// expected-warning@@-3{{Potential leak of memory pointed to by 'p'}}
#endif
d189 1
a189 4
  delete[] (++p);
#ifndef TEST_INLINABLE_ALLOCATORS
  // expected-warning@@-2{{Argument to 'delete[]' is offset by 4 bytes from the start of memory allocated by 'new[]'}}
#endif
@


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


1.1.1.6.2.1
log
@Sync with HEAD
@
text
@a2 7
// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDelete -std=c++11 -fblocks -analyzer-config c++-allocator-inlining=true -verify %s
// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDeleteLeaks -DLEAKS -std=c++11 -fblocks -analyzer-config c++-allocator-inlining=true -verify %s
// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDelete -std=c++11 -fblocks -DTEST_INLINABLE_ALLOCATORS -verify %s
// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDeleteLeaks -DLEAKS -std=c++11 -fblocks -DTEST_INLINABLE_ALLOCATORS -verify %s
// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDelete -std=c++11 -fblocks -analyzer-config c++-allocator-inlining=true -DTEST_INLINABLE_ALLOCATORS -verify %s
// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDeleteLeaks -DLEAKS -std=c++11 -fblocks -analyzer-config c++-allocator-inlining=true -DTEST_INLINABLE_ALLOCATORS -verify %s

d48 1
a48 3
#ifndef TEST_INLINABLE_ALLOCATORS
// expected-warning@@-3{{Potential leak of memory pointed to by 'p'}}
#endif
d55 1
a55 3
#ifndef TEST_INLINABLE_ALLOCATORS
// expected-warning@@-3{{Potential leak of memory pointed to by 'p'}}
#endif
d189 1
a189 4
  delete[] (++p);
#ifndef TEST_INLINABLE_ALLOCATORS
  // expected-warning@@-2{{Argument to 'delete[]' is offset by 4 bytes from the start of memory allocated by 'new[]'}}
#endif
@


1.1.1.7
log
@Import clang r337282 from trunk
@
text
@a2 7
// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDelete -std=c++11 -fblocks -analyzer-config c++-allocator-inlining=true -verify %s
// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDeleteLeaks -DLEAKS -std=c++11 -fblocks -analyzer-config c++-allocator-inlining=true -verify %s
// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDelete -std=c++11 -fblocks -DTEST_INLINABLE_ALLOCATORS -verify %s
// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDeleteLeaks -DLEAKS -std=c++11 -fblocks -DTEST_INLINABLE_ALLOCATORS -verify %s
// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDelete -std=c++11 -fblocks -analyzer-config c++-allocator-inlining=true -DTEST_INLINABLE_ALLOCATORS -verify %s
// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDeleteLeaks -DLEAKS -std=c++11 -fblocks -analyzer-config c++-allocator-inlining=true -DTEST_INLINABLE_ALLOCATORS -verify %s

d48 1
a48 3
#ifndef TEST_INLINABLE_ALLOCATORS
// expected-warning@@-3{{Potential leak of memory pointed to by 'p'}}
#endif
d55 1
a55 3
#ifndef TEST_INLINABLE_ALLOCATORS
// expected-warning@@-3{{Potential leak of memory pointed to by 'p'}}
#endif
d189 1
a189 4
  delete[] (++p);
#ifndef TEST_INLINABLE_ALLOCATORS
  // expected-warning@@-2{{Argument to 'delete[]' is offset by 4 bytes from the start of memory allocated by 'new[]'}}
#endif
@


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


1.1.1.2.8.1
log
@file NewDelete-checker-test.cpp was added on branch tls-maxphys on 2014-08-19 23:47:34 +0000
@
text
@d1 360
@


1.1.1.2.8.2
log
@Rebase to HEAD as of a few days ago.
@
text
@a0 360
// RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus.NewDelete -std=c++11 -fblocks -verify %s
// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.cplusplus.NewDeleteLeaks -DLEAKS -std=c++11 -fblocks -verify %s
#include "Inputs/system-header-simulator-cxx.h"

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

//------------------
// check for leaks
//------------------

//----- Standard non-placement operators
void testGlobalOpNew() {
  void *p = operator new(0);
}
#ifdef LEAKS
// expected-warning@@-2{{Potential leak of memory pointed to by 'p'}}
#endif

void testGlobalOpNewArray() {
  void *p = operator new[](0);
}
#ifdef LEAKS
// expected-warning@@-2{{Potential leak of memory pointed to by 'p'}}
#endif

void testGlobalNewExpr() {
  int *p = new int;
}
#ifdef LEAKS
// expected-warning@@-2{{Potential leak of memory pointed to by 'p'}}
#endif

void testGlobalNewExprArray() {
  int *p = new int[0];
}
#ifdef LEAKS
// expected-warning@@-2{{Potential leak of memory pointed to by 'p'}}
#endif

//----- Standard nothrow placement operators
void testGlobalNoThrowPlacementOpNewBeforeOverload() {
  void *p = operator new(0, std::nothrow);
}
#ifdef LEAKS
// expected-warning@@-2{{Potential leak of memory pointed to by 'p'}}
#endif

void testGlobalNoThrowPlacementExprNewBeforeOverload() {
  int *p = new(std::nothrow) int;
}
#ifdef LEAKS
// expected-warning@@-2{{Potential leak of memory pointed to by 'p'}}
#endif

//----- Standard pointer placement operators
void testGlobalPointerPlacementNew() {
  int i;

  void *p1 = operator new(0, &i); // no warn

  void *p2 = operator new[](0, &i); // no warn

  int *p3 = new(&i) int; // no warn

  int *p4 = new(&i) int[0]; // no warn
}

//----- Other cases
void testNewMemoryIsInHeap() {
  int *p = new int;
  if (global != p) // condition is always true as 'p' wraps a heap region that 
                   // is different from a region wrapped by 'global'
    global = p; // pointer escapes
}

struct PtrWrapper {
  int *x;

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

void testNewInvalidationPlacement(PtrWrapper *w) {
  // Ensure that we don't consider this a leak.
  new (w) PtrWrapper(new int); // no warn
}

//---------------
// other checks
//---------------

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

void f(int *p1, int *p2 = 0, int *p3 = 0);
void g(SomeClass &c, ...);

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

void testUseMiddleArgAfterDelete(int *p) {
  delete p;
  f(0, p); // expected-warning{{Use of memory after it is freed}}
}

void testUseLastArgAfterDelete(int *p) {
  delete p;
  f(0, 0, p); // expected-warning{{Use of memory after it is freed}}
}

void testUseSeveralArgsAfterDelete(int *p) {
  delete p;
  f(p, p, p); // expected-warning{{Use of memory after it is freed}}
}

void testUseRefArgAfterDelete(SomeClass &c) {
  delete &c;
  g(c); // expected-warning{{Use of memory after it is freed}}
}

void testVariadicArgAfterDelete() {
  SomeClass c;
  int *p = new int;
  delete p;
  g(c, 0, p); // expected-warning{{Use of memory after it is freed}}
}

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

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

void testDeleteAlloca() {
  int *p = (int *)__builtin_alloca(sizeof(int));
  delete p; // expected-warning{{Memory allocated by alloca() should not be deallocated}}
}

void testDoubleDelete() {
  int *p = new int;
  delete p;
  delete p; // expected-warning{{Attempt to free released memory}}
}

void testExprDeleteArg() {
  int i;
  delete &i; // expected-warning{{Argument to 'delete' is the address of the local variable 'i', which is not memory allocated by 'new'}}
}

void testExprDeleteArrArg() {
  int i;
  delete[] &i; // expected-warning{{Argument to 'delete[]' is the address of the local variable 'i', which is not memory allocated by 'new[]'}}
}

void testAllocDeallocNames() {
  int *p = new(std::nothrow) int[1];
  delete[] (++p); // expected-warning{{Argument to 'delete[]' is offset by 4 bytes from the start of memory allocated by 'new[]'}}
}

//--------------------------------
// Test escape of newed const pointer. Note, a const pointer can be deleted.
//--------------------------------
struct StWithConstPtr {
  const int *memp;
};
void escape(const int &x);
void escapeStruct(const StWithConstPtr &x);
void escapePtr(const StWithConstPtr *x);
void escapeVoidPtr(const void *x);

void testConstEscape() {
  int *p = new int(1);
  escape(*p);
} // no-warning

void testConstEscapeStruct() {
  StWithConstPtr *St = new StWithConstPtr();
  escapeStruct(*St);
} // no-warning

void testConstEscapeStructPtr() {
  StWithConstPtr *St = new StWithConstPtr();
  escapePtr(St);
} // no-warning

void testConstEscapeMember() {
  StWithConstPtr St;
  St.memp = new int(2);
  escapeVoidPtr(St.memp);
} // no-warning

void testConstEscapePlacementNew() {
  int *x = (int *)malloc(sizeof(int));
  void *y = new (x) int;
  escapeVoidPtr(y);
} // no-warning

//============== Test Uninitialized delete delete[]========================
void testUninitDelete() {
  int *x;
  int * y = new int;
  delete y;
  delete x; // expected-warning{{Argument to 'delete' is uninitialized}}
}

void testUninitDeleteArray() {
  int *x;
  int * y = new int[5];
  delete[] y;
  delete[] x; // expected-warning{{Argument to 'delete[]' is uninitialized}}
}

void testUninitFree() {
  int *x;
  free(x); // expected-warning{{Function call argument is an uninitialized value}}
}

void testUninitDeleteSink() {
  int *x;
  delete x; // expected-warning{{Argument to 'delete' is uninitialized}}
  (*(volatile int *)0 = 1); // no warn
}

void testUninitDeleteArraySink() {
  int *x;
  delete[] x; // expected-warning{{Argument to 'delete[]' is uninitialized}}
  (*(volatile int *)0 = 1); // no warn
}

namespace reference_count {
  class control_block {
    unsigned count;
  public:
    control_block() : count(0) {}
    void retain() { ++count; }
    int release() { return --count; }
  };

  template <typename T>
  class shared_ptr {
    T *p;
    control_block *control;

  public:
    shared_ptr() : p(0), control(0) {}
    explicit shared_ptr(T *p) : p(p), control(new control_block) {
      control->retain();
    }
    shared_ptr(shared_ptr &other) : p(other.p), control(other.control) {
      if (control)
          control->retain();
    }
    ~shared_ptr() {
      if (control && control->release() == 0) {
        delete p;
        delete control;
      }
    };

    T &operator *() {
      return *p;
    };

    void swap(shared_ptr &other) {
      T *tmp = p;
      p = other.p;
      other.p = tmp;

      control_block *ctrlTmp = control;
      control = other.control;
      other.control = ctrlTmp;
    }
  };

  void testSingle() {
    shared_ptr<int> a(new int);
    *a = 1;
  }

  void testDouble() {
    shared_ptr<int> a(new int);
    shared_ptr<int> b = a;
    *a = 1;
  }

  void testInvalidated() {
    shared_ptr<int> a(new int);
    shared_ptr<int> b = a;
    *a = 1;

    extern void use(shared_ptr<int> &);
    use(b);
  }

  void testNestedScope() {
    shared_ptr<int> a(new int);
    {
      shared_ptr<int> b = a;
    }
    *a = 1;
  }

  void testSwap() {
    shared_ptr<int> a(new int);
    shared_ptr<int> b;
    shared_ptr<int> c = a;
    shared_ptr<int>(c).swap(b);
  }

  void testUseAfterFree() {
    int *p = new int;
    {
      shared_ptr<int> a(p);
      shared_ptr<int> b = a;
    }

    // FIXME: We should get a warning here, but we don't because we've
    // conservatively modeled ~shared_ptr.
    *p = 1;
  }
}

// Test double delete
class DerefClass{
public:
  int *x;
  DerefClass() {}
  ~DerefClass() {*x = 1;}
};

void testDoubleDeleteClassInstance() {
  DerefClass *foo = new DerefClass();
  delete foo;
  delete foo; // expected-warning {{Attempt to delete released memory}}
}

class EmptyClass{
public:
  EmptyClass() {}
  ~EmptyClass() {}
};

void testDoubleDeleteEmptyClass() {
  EmptyClass *foo = new EmptyClass();
  delete foo;
  delete foo;  // expected-warning {{Attempt to delete released memory}}
}
@


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


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 360
// RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus.NewDelete -std=c++11 -fblocks -verify %s
// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.cplusplus.NewDeleteLeaks -DLEAKS -std=c++11 -fblocks -verify %s
#include "Inputs/system-header-simulator-cxx.h"

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

//------------------
// check for leaks
//------------------

//----- Standard non-placement operators
void testGlobalOpNew() {
  void *p = operator new(0);
}
#ifdef LEAKS
// expected-warning@@-2{{Potential leak of memory pointed to by 'p'}}
#endif

void testGlobalOpNewArray() {
  void *p = operator new[](0);
}
#ifdef LEAKS
// expected-warning@@-2{{Potential leak of memory pointed to by 'p'}}
#endif

void testGlobalNewExpr() {
  int *p = new int;
}
#ifdef LEAKS
// expected-warning@@-2{{Potential leak of memory pointed to by 'p'}}
#endif

void testGlobalNewExprArray() {
  int *p = new int[0];
}
#ifdef LEAKS
// expected-warning@@-2{{Potential leak of memory pointed to by 'p'}}
#endif

//----- Standard nothrow placement operators
void testGlobalNoThrowPlacementOpNewBeforeOverload() {
  void *p = operator new(0, std::nothrow);
}
#ifdef LEAKS
// expected-warning@@-2{{Potential leak of memory pointed to by 'p'}}
#endif

void testGlobalNoThrowPlacementExprNewBeforeOverload() {
  int *p = new(std::nothrow) int;
}
#ifdef LEAKS
// expected-warning@@-2{{Potential leak of memory pointed to by 'p'}}
#endif

//----- Standard pointer placement operators
void testGlobalPointerPlacementNew() {
  int i;

  void *p1 = operator new(0, &i); // no warn

  void *p2 = operator new[](0, &i); // no warn

  int *p3 = new(&i) int; // no warn

  int *p4 = new(&i) int[0]; // no warn
}

//----- Other cases
void testNewMemoryIsInHeap() {
  int *p = new int;
  if (global != p) // condition is always true as 'p' wraps a heap region that 
                   // is different from a region wrapped by 'global'
    global = p; // pointer escapes
}

struct PtrWrapper {
  int *x;

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

void testNewInvalidationPlacement(PtrWrapper *w) {
  // Ensure that we don't consider this a leak.
  new (w) PtrWrapper(new int); // no warn
}

//---------------
// other checks
//---------------

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

void f(int *p1, int *p2 = 0, int *p3 = 0);
void g(SomeClass &c, ...);

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

void testUseMiddleArgAfterDelete(int *p) {
  delete p;
  f(0, p); // expected-warning{{Use of memory after it is freed}}
}

void testUseLastArgAfterDelete(int *p) {
  delete p;
  f(0, 0, p); // expected-warning{{Use of memory after it is freed}}
}

void testUseSeveralArgsAfterDelete(int *p) {
  delete p;
  f(p, p, p); // expected-warning{{Use of memory after it is freed}}
}

void testUseRefArgAfterDelete(SomeClass &c) {
  delete &c;
  g(c); // expected-warning{{Use of memory after it is freed}}
}

void testVariadicArgAfterDelete() {
  SomeClass c;
  int *p = new int;
  delete p;
  g(c, 0, p); // expected-warning{{Use of memory after it is freed}}
}

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

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

void testDeleteAlloca() {
  int *p = (int *)__builtin_alloca(sizeof(int));
  delete p; // expected-warning{{Memory allocated by alloca() should not be deallocated}}
}

void testDoubleDelete() {
  int *p = new int;
  delete p;
  delete p; // expected-warning{{Attempt to free released memory}}
}

void testExprDeleteArg() {
  int i;
  delete &i; // expected-warning{{Argument to 'delete' is the address of the local variable 'i', which is not memory allocated by 'new'}}
}

void testExprDeleteArrArg() {
  int i;
  delete[] &i; // expected-warning{{Argument to 'delete[]' is the address of the local variable 'i', which is not memory allocated by 'new[]'}}
}

void testAllocDeallocNames() {
  int *p = new(std::nothrow) int[1];
  delete[] (++p); // expected-warning{{Argument to 'delete[]' is offset by 4 bytes from the start of memory allocated by 'new[]'}}
}

//--------------------------------
// Test escape of newed const pointer. Note, a const pointer can be deleted.
//--------------------------------
struct StWithConstPtr {
  const int *memp;
};
void escape(const int &x);
void escapeStruct(const StWithConstPtr &x);
void escapePtr(const StWithConstPtr *x);
void escapeVoidPtr(const void *x);

void testConstEscape() {
  int *p = new int(1);
  escape(*p);
} // no-warning

void testConstEscapeStruct() {
  StWithConstPtr *St = new StWithConstPtr();
  escapeStruct(*St);
} // no-warning

void testConstEscapeStructPtr() {
  StWithConstPtr *St = new StWithConstPtr();
  escapePtr(St);
} // no-warning

void testConstEscapeMember() {
  StWithConstPtr St;
  St.memp = new int(2);
  escapeVoidPtr(St.memp);
} // no-warning

void testConstEscapePlacementNew() {
  int *x = (int *)malloc(sizeof(int));
  void *y = new (x) int;
  escapeVoidPtr(y);
} // no-warning

//============== Test Uninitialized delete delete[]========================
void testUninitDelete() {
  int *x;
  int * y = new int;
  delete y;
  delete x; // expected-warning{{Argument to 'delete' is uninitialized}}
}

void testUninitDeleteArray() {
  int *x;
  int * y = new int[5];
  delete[] y;
  delete[] x; // expected-warning{{Argument to 'delete[]' is uninitialized}}
}

void testUninitFree() {
  int *x;
  free(x); // expected-warning{{Function call argument is an uninitialized value}}
}

void testUninitDeleteSink() {
  int *x;
  delete x; // expected-warning{{Argument to 'delete' is uninitialized}}
  (*(volatile int *)0 = 1); // no warn
}

void testUninitDeleteArraySink() {
  int *x;
  delete[] x; // expected-warning{{Argument to 'delete[]' is uninitialized}}
  (*(volatile int *)0 = 1); // no warn
}

namespace reference_count {
  class control_block {
    unsigned count;
  public:
    control_block() : count(0) {}
    void retain() { ++count; }
    int release() { return --count; }
  };

  template <typename T>
  class shared_ptr {
    T *p;
    control_block *control;

  public:
    shared_ptr() : p(0), control(0) {}
    explicit shared_ptr(T *p) : p(p), control(new control_block) {
      control->retain();
    }
    shared_ptr(shared_ptr &other) : p(other.p), control(other.control) {
      if (control)
          control->retain();
    }
    ~shared_ptr() {
      if (control && control->release() == 0) {
        delete p;
        delete control;
      }
    };

    T &operator *() {
      return *p;
    };

    void swap(shared_ptr &other) {
      T *tmp = p;
      p = other.p;
      other.p = tmp;

      control_block *ctrlTmp = control;
      control = other.control;
      other.control = ctrlTmp;
    }
  };

  void testSingle() {
    shared_ptr<int> a(new int);
    *a = 1;
  }

  void testDouble() {
    shared_ptr<int> a(new int);
    shared_ptr<int> b = a;
    *a = 1;
  }

  void testInvalidated() {
    shared_ptr<int> a(new int);
    shared_ptr<int> b = a;
    *a = 1;

    extern void use(shared_ptr<int> &);
    use(b);
  }

  void testNestedScope() {
    shared_ptr<int> a(new int);
    {
      shared_ptr<int> b = a;
    }
    *a = 1;
  }

  void testSwap() {
    shared_ptr<int> a(new int);
    shared_ptr<int> b;
    shared_ptr<int> c = a;
    shared_ptr<int>(c).swap(b);
  }

  void testUseAfterFree() {
    int *p = new int;
    {
      shared_ptr<int> a(p);
      shared_ptr<int> b = a;
    }

    // FIXME: We should get a warning here, but we don't because we've
    // conservatively modeled ~shared_ptr.
    *p = 1;
  }
}

// Test double delete
class DerefClass{
public:
  int *x;
  DerefClass() {}
  ~DerefClass() {*x = 1;}
};

void testDoubleDeleteClassInstance() {
  DerefClass *foo = new DerefClass();
  delete foo;
  delete foo; // expected-warning {{Attempt to delete released memory}}
}

class EmptyClass{
public:
  EmptyClass() {}
  ~EmptyClass() {}
};

void testDoubleDeleteEmptyClass() {
  EmptyClass *foo = new EmptyClass();
  delete foo;
  delete foo;  // expected-warning {{Attempt to delete released memory}}
}
@


