Summary:public Create initial model of C++ std::shared_ptr. This means that infer will replace implementation of shared_ptr and the resulting binary will change. Make sure no one will run it by crashing any binary that includes that code. Reviewed By: jvillard Differential Revision: D2999948 fb-gh-sync-id: 5753559 shipit-source-id: 5753559master
parent
b2969820a4
commit
eb76a441f9
@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016 - present Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// this file exists in gcc headers and we need to capture those includes
|
||||||
|
#include <infer_model/begin_name_override.inc>
|
||||||
|
#include_next <bits/shared_ptr.h>
|
||||||
|
#include <infer_model/end_name_override.inc>
|
||||||
|
|
||||||
|
#include <infer_model/shared_ptr.h>
|
@ -0,0 +1,3 @@
|
|||||||
|
#define make_shared std__make_shared
|
||||||
|
#define shared_ptr std__shared_ptr
|
||||||
|
|
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016 - present Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <infer_model/portability.h>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
#define static_assert(...)
|
||||||
|
|
||||||
|
namespace infer_model {
|
||||||
|
// code compiled with infer headers is not supposed to be executed
|
||||||
|
struct AbortWhenRun {
|
||||||
|
AbortWhenRun() {
|
||||||
|
fprintf(stderr,
|
||||||
|
"!!! This program must not be run !!!\n"
|
||||||
|
"This code was compiled to be analyzed by Infer.\n"
|
||||||
|
"To run this program, recompile it without Infer.\n");
|
||||||
|
std::abort();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static AbortWhenRun a{};
|
||||||
|
}
|
@ -0,0 +1,2 @@
|
|||||||
|
#undef make_shared
|
||||||
|
#undef shared_ptr
|
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016 - present Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
// TODO set it in configure script instead
|
||||||
|
// This is hacky attempt to follow what folly does
|
||||||
|
// https://github.com/facebook/folly/blob/b1eb6819f3ffe6b645f39d505ca8ace3116b7873/folly/configure.ac#L232
|
||||||
|
#if !defined(INFER_USE_LIBCPP) && defined(__APPLE__)
|
||||||
|
#define INFER_USE_LIBCPP 1
|
||||||
|
#elif defined(FOLLY_USE_LIBCPP)
|
||||||
|
#define INFER_USE_LIBCPP 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Follow what folly does - gnu libstdc++ implementation is different from
|
||||||
|
// llvm's libc++. This way folly can forward declare decls from std library
|
||||||
|
// even when they are infer models
|
||||||
|
// https://github.com/facebook/folly/blob/b1eb6819f3ffe6b645f39d505ca8ace3116b7873/folly/Portability.h#L253-L255
|
||||||
|
#if INFER_USE_LIBCPP
|
||||||
|
#include <__config>
|
||||||
|
#define INFER_NAMESPACE_STD_BEGIN _LIBCPP_BEGIN_NAMESPACE_STD
|
||||||
|
#define INFER_NAMESPACE_STD_END _LIBCPP_END_NAMESPACE_STD
|
||||||
|
#else
|
||||||
|
#define INFER_NAMESPACE_STD_BEGIN namespace std {
|
||||||
|
#define INFER_NAMESPACE_STD_END }
|
||||||
|
#endif
|
@ -0,0 +1,235 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016 - present Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
// ASSERT that __cplusplus >= 201103L
|
||||||
|
|
||||||
|
#include <infer_model/common.h>
|
||||||
|
|
||||||
|
INFER_NAMESPACE_STD_BEGIN
|
||||||
|
|
||||||
|
// use inheritance to avoid compilation errors when using
|
||||||
|
// methods / non-member functions that are not modeled
|
||||||
|
// WARNING: sizeof(shared_ptr) = 24, not 16 - this may
|
||||||
|
// lead to compilation errors
|
||||||
|
template <class T>
|
||||||
|
class shared_ptr : public std__shared_ptr<T> {
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Conversion constructors to allow implicit conversions.
|
||||||
|
// it's here purely to avoid compilation errors
|
||||||
|
template <class Y,
|
||||||
|
typename = typename enable_if<is_convertible<Y*, T*>::value>::type>
|
||||||
|
shared_ptr(const std__shared_ptr<Y>& r) {}
|
||||||
|
|
||||||
|
template <class Y>
|
||||||
|
shared_ptr(const std__shared_ptr<Y>& r, T* p) noexcept {}
|
||||||
|
|
||||||
|
T* data;
|
||||||
|
|
||||||
|
// constructors:
|
||||||
|
constexpr shared_ptr() noexcept : data(nullptr) {}
|
||||||
|
|
||||||
|
shared_ptr(nullptr_t) : shared_ptr() {}
|
||||||
|
|
||||||
|
// Extra template argument is used to create constructors/assignment overloads
|
||||||
|
// for Y types where it's possible to convert Y* to T*.
|
||||||
|
// typename = typename enable_if<is_convertible<Y*, T*>::value>::type
|
||||||
|
// thanks to that, clang will not create some functions that would cause
|
||||||
|
// compilation errors. More info:
|
||||||
|
// http://en.cppreference.com/w/cpp/language/sfinae
|
||||||
|
template <class Y,
|
||||||
|
typename = typename enable_if<is_convertible<Y*, T*>::value>::type>
|
||||||
|
explicit shared_ptr(Y* p) {
|
||||||
|
data = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Y,
|
||||||
|
class D,
|
||||||
|
typename = typename enable_if<is_convertible<Y*, T*>::value>::type>
|
||||||
|
shared_ptr(Y* p, D d) : shared_ptr<T>(p) {}
|
||||||
|
|
||||||
|
template <class Y,
|
||||||
|
class D,
|
||||||
|
class A,
|
||||||
|
typename = typename enable_if<is_convertible<Y*, T*>::value>::type>
|
||||||
|
shared_ptr(Y* p, D d, A a) : shared_ptr<T>(p) {}
|
||||||
|
|
||||||
|
template <class D>
|
||||||
|
shared_ptr(nullptr_t p, D d) : shared_ptr<T>(p) {}
|
||||||
|
|
||||||
|
template <class D, class A>
|
||||||
|
shared_ptr(nullptr_t p, D d, A a) : shared_ptr<T>(p) {}
|
||||||
|
|
||||||
|
template <class Y>
|
||||||
|
shared_ptr(const shared_ptr<Y>& r, T* p) noexcept : data(nullptr) { /* TODO */
|
||||||
|
}
|
||||||
|
|
||||||
|
shared_ptr(const shared_ptr& r) noexcept
|
||||||
|
: shared_ptr<T>(r.data) { /* TODO - increase refcount*/
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Y,
|
||||||
|
typename = typename enable_if<is_convertible<Y*, T*>::value>::type>
|
||||||
|
shared_ptr(const shared_ptr<Y>& r) noexcept
|
||||||
|
: shared_ptr<T>(r.data) { /* TODO - increase refcount*/
|
||||||
|
}
|
||||||
|
|
||||||
|
shared_ptr(shared_ptr&& r) noexcept : shared_ptr<T>(r.data) {
|
||||||
|
r.data = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Y,
|
||||||
|
typename = typename enable_if<is_convertible<Y*, T*>::value>::type>
|
||||||
|
shared_ptr(shared_ptr<Y>&& r) noexcept : shared_ptr<T>(r.data) {
|
||||||
|
r.data = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Y,
|
||||||
|
typename = typename enable_if<is_convertible<Y*, T*>::value>::type>
|
||||||
|
explicit shared_ptr(const weak_ptr<Y>& r) {}
|
||||||
|
|
||||||
|
/* Because of implementation differences between libc++ and stdlibc++, don't
|
||||||
|
* define this constructor (it will be defined elsewhere in case of
|
||||||
|
* stdlibc++). Because it may be defined elsewhere, don't check whether Y*
|
||||||
|
* converts to T* - otherwise there might be compilation error (out-of-line
|
||||||
|
* definition).
|
||||||
|
* No definition here might cause compilation problems if project is
|
||||||
|
* using auto_ptrs with libc++ */
|
||||||
|
template <class Y>
|
||||||
|
shared_ptr(auto_ptr<Y>&& r); // {}
|
||||||
|
|
||||||
|
template <class Y,
|
||||||
|
class D,
|
||||||
|
typename = typename enable_if<is_convertible<Y*, T*>::value>::type>
|
||||||
|
shared_ptr(unique_ptr<Y, D>&& r) : shared_ptr<T>(r.release()) {}
|
||||||
|
|
||||||
|
// destructor:
|
||||||
|
~shared_ptr() { reset((T*)nullptr); }
|
||||||
|
|
||||||
|
// assignment:
|
||||||
|
shared_ptr& operator=(const shared_ptr& r) noexcept {
|
||||||
|
// shared_ptr<T>(r).swap(*this);
|
||||||
|
data = r.data;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Y,
|
||||||
|
typename = typename enable_if<is_convertible<Y*, T*>::value>::type>
|
||||||
|
shared_ptr& operator=(const shared_ptr<Y>& r) noexcept {
|
||||||
|
// shared_ptr<T>(r).swap(*this);
|
||||||
|
data = r.data;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
shared_ptr& operator=(shared_ptr&& r) noexcept {
|
||||||
|
// shared_ptr<T>(std::move(r)).swap(*this);
|
||||||
|
data = r.data;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Y,
|
||||||
|
typename = typename enable_if<is_convertible<Y*, T*>::value>::type>
|
||||||
|
shared_ptr& operator=(shared_ptr<Y>&& r) {
|
||||||
|
// shared_ptr<T>(std::move(r)).swap(*this);
|
||||||
|
data = r.data;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Y,
|
||||||
|
typename = typename enable_if<is_convertible<Y*, T*>::value>::type>
|
||||||
|
shared_ptr& operator=(auto_ptr<Y>&& r) { /* ?? */
|
||||||
|
}
|
||||||
|
template <class Y,
|
||||||
|
class D,
|
||||||
|
typename = typename enable_if<is_convertible<Y*, T*>::value>::type>
|
||||||
|
shared_ptr& operator=(unique_ptr<Y, D>&& r) {
|
||||||
|
// shared_ptr<T>(std::move(r)).swap(*this);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// modifiers:
|
||||||
|
void swap(shared_ptr& r) noexcept {
|
||||||
|
T* tmp = r.data;
|
||||||
|
r.data = data;
|
||||||
|
data = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset() noexcept { reset((T*)nullptr); }
|
||||||
|
|
||||||
|
template <class Y,
|
||||||
|
typename = typename enable_if<is_convertible<Y*, T*>::value>::type>
|
||||||
|
void reset(Y* p) {
|
||||||
|
/*
|
||||||
|
if (unique()) {
|
||||||
|
delete data;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
data = p;
|
||||||
|
// TODO adjust refcounts
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Y,
|
||||||
|
class D,
|
||||||
|
typename = typename enable_if<is_convertible<Y*, T*>::value>::type>
|
||||||
|
void reset(Y* p, D d) {
|
||||||
|
reset(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Y,
|
||||||
|
class D,
|
||||||
|
class A,
|
||||||
|
typename = typename enable_if<is_convertible<Y*, T*>::value>::type>
|
||||||
|
void reset(Y* p, D d, A a) {
|
||||||
|
reset(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
// observers:
|
||||||
|
T* get() const noexcept { return data; }
|
||||||
|
typename add_lvalue_reference<T>::type operator*() const noexcept {
|
||||||
|
return *data;
|
||||||
|
}
|
||||||
|
T* operator->() const noexcept { return data; }
|
||||||
|
long use_count() const noexcept { return 2; /* FIXME */ }
|
||||||
|
bool unique() const noexcept { return use_count() == 1; /* FIXME */ }
|
||||||
|
explicit operator bool() const noexcept { return (bool)data; }
|
||||||
|
template <class U>
|
||||||
|
bool owner_before(shared_ptr<U> const& b) const {
|
||||||
|
return true; /* FIXME - use non-det*/
|
||||||
|
}
|
||||||
|
template <class U>
|
||||||
|
bool owner_before(weak_ptr<U> const& b) const {
|
||||||
|
return true; /* FIXME - use non-det */
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct hash<shared_ptr<T>> : public hash<std__shared_ptr<T>> {};
|
||||||
|
|
||||||
|
// shared_ptr casts - call original functions but change return type to
|
||||||
|
// std::shared_ptr
|
||||||
|
template <class T, class U>
|
||||||
|
shared_ptr<T> static_pointer_cast(shared_ptr<U> const& r) noexcept {
|
||||||
|
return static_pointer_cast<T, U>((const std__shared_ptr<U>&)r);
|
||||||
|
}
|
||||||
|
template <class T, class U>
|
||||||
|
shared_ptr<T> dynamic_pointer_cast(shared_ptr<U> const& r) noexcept {
|
||||||
|
return dynamic_pointer_cast<T, U>((const std__shared_ptr<U>&)r);
|
||||||
|
}
|
||||||
|
template <class T, class U>
|
||||||
|
shared_ptr<T> const_pointer_cast(shared_ptr<U> const& r) noexcept {
|
||||||
|
return const_pointer_cast<T, U>((const std__shared_ptr<U>&)r);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T, class... Args>
|
||||||
|
shared_ptr<T> make_shared(Args&&... args) {
|
||||||
|
return shared_ptr<T>(new T(std::forward<Args>(args)...));
|
||||||
|
}
|
||||||
|
|
||||||
|
INFER_NAMESPACE_STD_END
|
@ -0,0 +1,13 @@
|
|||||||
|
|
||||||
|
#if __cplusplus >= 201103L
|
||||||
|
|
||||||
|
#include <infer_model/begin_name_override.inc>
|
||||||
|
#include_next <memory>
|
||||||
|
#include <infer_model/end_name_override.inc>
|
||||||
|
|
||||||
|
#include<infer_model/shared_ptr.h>
|
||||||
|
|
||||||
|
#else // __cplusplus < 201103L
|
||||||
|
// don't model memory for pre-C++11 code
|
||||||
|
#include_next <memory>
|
||||||
|
#endif
|
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016 - present Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct X {
|
||||||
|
int field;
|
||||||
|
int* getPtr() { return &field; }
|
||||||
|
int* getNull() { return nullptr; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SmartPtr {
|
||||||
|
SmartPtr() : data(nullptr) {}
|
||||||
|
X* data;
|
||||||
|
X* get() { return data; }
|
||||||
|
};
|
||||||
|
|
||||||
|
void smart_ptr_null_field_deref() {
|
||||||
|
SmartPtr p;
|
||||||
|
int f = p.get()->field;
|
||||||
|
}
|
||||||
|
|
||||||
|
void smart_ptr_null_method_deref() {
|
||||||
|
SmartPtr p;
|
||||||
|
int* f = p.get()->getPtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
void smart_ptr_null_method_deref2() {
|
||||||
|
SmartPtr p;
|
||||||
|
int* f = p.get()->getNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
void smart_ptr_ok_field_deref() {
|
||||||
|
SmartPtr p;
|
||||||
|
X x;
|
||||||
|
p.data = &x;
|
||||||
|
int f = p.get()->field;
|
||||||
|
}
|
||||||
|
|
||||||
|
void smart_ptr_ok_method_deref() {
|
||||||
|
SmartPtr p;
|
||||||
|
X x;
|
||||||
|
p.data = &x;
|
||||||
|
int* f = p.get()->getNull();
|
||||||
|
int* g = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void smart_ptr_result_method_null_deref() {
|
||||||
|
SmartPtr p;
|
||||||
|
X x;
|
||||||
|
p.data = &x;
|
||||||
|
int f = *(p.get()->getNull());
|
||||||
|
}
|
||||||
|
|
||||||
|
void smart_ptr_result_method_ok_deref() {
|
||||||
|
SmartPtr p;
|
||||||
|
X x;
|
||||||
|
p.data = &x;
|
||||||
|
int f = *(p.get()->getPtr());
|
||||||
|
}
|
@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016 - present Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
struct Base {
|
||||||
|
int* f1;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Derived : public Base {
|
||||||
|
int* f2;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::shared_ptr<Base> getFromBase1(Base* b) { return std::shared_ptr<Base>(b); }
|
||||||
|
|
||||||
|
std::shared_ptr<Base> getFromBase2(Base* b) {
|
||||||
|
std::shared_ptr<Base> result;
|
||||||
|
result = std::shared_ptr<Base>(b); // assignment operator
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Base> getFromDerived1(Derived* d) {
|
||||||
|
return std::shared_ptr<Base>(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Base> getFromDerived2(Derived* d) {
|
||||||
|
std::shared_ptr<Derived> sd(d);
|
||||||
|
return std::shared_ptr<Base>(sd);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Base> getFromDerived3(Derived* d) {
|
||||||
|
std::shared_ptr<Derived> sd(d);
|
||||||
|
std::shared_ptr<Base> result;
|
||||||
|
result = sd; // assignment operator
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void get_from_base1_nullptr_deref() { Base b = *(getFromBase1(nullptr)); }
|
||||||
|
|
||||||
|
void get_from_base2_nullptr_deref() { Base b = *(getFromBase2(nullptr)); }
|
||||||
|
|
||||||
|
void get_from_derived1_nullptr_deref() { Base b = *(getFromDerived1(nullptr)); }
|
||||||
|
|
||||||
|
void get_from_derived2_nullptr_deref() { Base b = *(getFromDerived2(nullptr)); }
|
||||||
|
|
||||||
|
void get_from_derived3_nullptr_deref() { Base b = *(getFromDerived3(nullptr)); }
|
||||||
|
|
||||||
|
void get_from_base1_null_f1_deref() {
|
||||||
|
Base b;
|
||||||
|
int v;
|
||||||
|
b.f1 = &v;
|
||||||
|
std::shared_ptr<Base> p = getFromBase1(&b);
|
||||||
|
b.f1 = nullptr;
|
||||||
|
int r = *(p->f1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void get_from_base2_null_f1_deref() {
|
||||||
|
Base b;
|
||||||
|
int v;
|
||||||
|
b.f1 = &v;
|
||||||
|
std::shared_ptr<Base> p = getFromBase2(&b);
|
||||||
|
b.f1 = nullptr;
|
||||||
|
int r = *(p->f1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void get_from_derived1_null_f1_deref() {
|
||||||
|
Derived b;
|
||||||
|
int v;
|
||||||
|
b.f1 = &v;
|
||||||
|
std::shared_ptr<Base> p = getFromDerived1(&b);
|
||||||
|
b.f1 = nullptr;
|
||||||
|
int r = *(p->f1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void get_from_derived2_null_f1_deref() {
|
||||||
|
Derived b;
|
||||||
|
int v;
|
||||||
|
b.f1 = &v;
|
||||||
|
std::shared_ptr<Base> p = getFromDerived2(&b);
|
||||||
|
b.f1 = nullptr;
|
||||||
|
int r = *(p->f1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void get_from_derived3_null_f1_deref() {
|
||||||
|
Derived b;
|
||||||
|
int v;
|
||||||
|
b.f1 = &v;
|
||||||
|
std::shared_ptr<Base> p = getFromDerived3(&b);
|
||||||
|
b.f1 = nullptr;
|
||||||
|
int r = *(p->f1);
|
||||||
|
}
|
@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016 - present Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
struct X {
|
||||||
|
int field;
|
||||||
|
int get() { return field; }
|
||||||
|
void set(int value) { field = value; }
|
||||||
|
};
|
||||||
|
|
||||||
|
int empty_ptr_access() {
|
||||||
|
std::shared_ptr<int> x;
|
||||||
|
int* p = x.get(); // no dereference
|
||||||
|
if (p) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int empty_ptr_deref() {
|
||||||
|
std::shared_ptr<int> x;
|
||||||
|
return *x;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nullptr_ptr_deref() {
|
||||||
|
std::shared_ptr<int> x(nullptr);
|
||||||
|
return *x;
|
||||||
|
}
|
||||||
|
|
||||||
|
int empty_ptr_field_deref() {
|
||||||
|
std::shared_ptr<X> x;
|
||||||
|
return x.get()->field;
|
||||||
|
}
|
||||||
|
|
||||||
|
int empty_ptr_field_deref2() {
|
||||||
|
std::shared_ptr<X> x;
|
||||||
|
return x->field;
|
||||||
|
}
|
||||||
|
|
||||||
|
int empty_ptr_method_deref() {
|
||||||
|
std::shared_ptr<X> x;
|
||||||
|
return x->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
int reset_ptr_null_deref() {
|
||||||
|
std::shared_ptr<int> x(new int);
|
||||||
|
x.reset();
|
||||||
|
return *x;
|
||||||
|
}
|
||||||
|
|
||||||
|
int reset_ptr_null_deref2() {
|
||||||
|
std::shared_ptr<int> x(new int);
|
||||||
|
x.reset(new int);
|
||||||
|
x.reset();
|
||||||
|
return *x;
|
||||||
|
}
|
||||||
|
|
||||||
|
int reset_ptr_ok_deref() {
|
||||||
|
std::shared_ptr<int> x;
|
||||||
|
x.reset(new int);
|
||||||
|
return *x;
|
||||||
|
}
|
||||||
|
|
||||||
|
int reset_ptr_ok_deref2() {
|
||||||
|
std::shared_ptr<int> x;
|
||||||
|
x.reset();
|
||||||
|
x.reset(new int);
|
||||||
|
return *x;
|
||||||
|
}
|
||||||
|
|
||||||
|
int shared_ptr_copy_null_deref() {
|
||||||
|
std::shared_ptr<int> p1;
|
||||||
|
std::shared_ptr<int> p2 = p1;
|
||||||
|
return *p2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int shared_ptr_assign_null_deref() {
|
||||||
|
std::shared_ptr<int> p1(new int);
|
||||||
|
std::shared_ptr<int> p2;
|
||||||
|
p1 = p2;
|
||||||
|
return *p1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int shared_ptr_copy_ok_deref() {
|
||||||
|
std::shared_ptr<int> p1(new int);
|
||||||
|
std::shared_ptr<int> p2 = p1;
|
||||||
|
return *p2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int shared_ptr_assign_ok_deref() {
|
||||||
|
std::shared_ptr<int> p1(new int);
|
||||||
|
std::shared_ptr<int> p2;
|
||||||
|
p2 = p1;
|
||||||
|
p1.reset();
|
||||||
|
return *p2;
|
||||||
|
}
|
@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016 - present Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package endtoend.cpp;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static utils.matchers.ResultContainsExactly.containsExactly;
|
||||||
|
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.ClassRule;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import utils.DebuggableTemporaryFolder;
|
||||||
|
import utils.InferException;
|
||||||
|
import utils.InferResults;
|
||||||
|
import utils.InferRunner;
|
||||||
|
|
||||||
|
public class BoxedPtrTest {
|
||||||
|
|
||||||
|
public static final String FILE =
|
||||||
|
"infer/tests/codetoanalyze/cpp/errors/npe/boxed_ptr.cpp";
|
||||||
|
|
||||||
|
private static ImmutableList<String> inferCmd;
|
||||||
|
|
||||||
|
public static final String NULL_DEREFERENCE = "NULL_DEREFERENCE";
|
||||||
|
|
||||||
|
@ClassRule
|
||||||
|
public static DebuggableTemporaryFolder folder =
|
||||||
|
new DebuggableTemporaryFolder();
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void runInfer() throws InterruptedException, IOException {
|
||||||
|
inferCmd = InferRunner.createCPPInferCommand(folder, FILE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenInferRunsNullDerefFunctionsErrorIsFound()
|
||||||
|
throws InterruptedException, IOException, InferException {
|
||||||
|
String[] procedures = {
|
||||||
|
"smart_ptr_null_field_deref",
|
||||||
|
"smart_ptr_null_method_deref",
|
||||||
|
"smart_ptr_null_method_deref2",
|
||||||
|
"smart_ptr_result_method_null_deref",
|
||||||
|
};
|
||||||
|
InferResults inferResults = InferRunner.runInferCPP(inferCmd);
|
||||||
|
assertThat(
|
||||||
|
"Results should contain divide by 0 error",
|
||||||
|
inferResults,
|
||||||
|
containsExactly(
|
||||||
|
NULL_DEREFERENCE,
|
||||||
|
FILE,
|
||||||
|
procedures
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016 - present Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package endtoend.cpp;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static utils.matchers.ResultContainsExactly.containsExactly;
|
||||||
|
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.ClassRule;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import utils.DebuggableTemporaryFolder;
|
||||||
|
import utils.InferException;
|
||||||
|
import utils.InferResults;
|
||||||
|
import utils.InferRunner;
|
||||||
|
|
||||||
|
public class SharedPtrConstructorsTest {
|
||||||
|
|
||||||
|
public static final String FILE =
|
||||||
|
"infer/tests/codetoanalyze/cpp/errors/smart_ptr/shared_ptr_constructors.cpp";
|
||||||
|
|
||||||
|
private static ImmutableList<String> inferCmd;
|
||||||
|
|
||||||
|
public static final String NULL_DEREFERENCE = "NULL_DEREFERENCE";
|
||||||
|
|
||||||
|
@ClassRule
|
||||||
|
public static DebuggableTemporaryFolder folder =
|
||||||
|
new DebuggableTemporaryFolder();
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void runInfer() throws InterruptedException, IOException {
|
||||||
|
inferCmd = InferRunner.createCPPInferCommand(folder, FILE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenInferRunsNullDerefFunctionsErrorIsFound()
|
||||||
|
throws InterruptedException, IOException, InferException {
|
||||||
|
String[] procedures = {
|
||||||
|
"get_from_base1_nullptr_deref",
|
||||||
|
"get_from_base2_nullptr_deref",
|
||||||
|
"get_from_derived1_nullptr_deref",
|
||||||
|
"get_from_derived2_nullptr_deref",
|
||||||
|
"get_from_derived3_nullptr_deref",
|
||||||
|
"get_from_base1_null_f1_deref",
|
||||||
|
"get_from_base2_null_f1_deref",
|
||||||
|
"get_from_derived1_null_f1_deref",
|
||||||
|
"get_from_derived2_null_f1_deref",
|
||||||
|
"get_from_derived3_null_f1_deref",
|
||||||
|
};
|
||||||
|
InferResults inferResults = InferRunner.runInferCPP(inferCmd);
|
||||||
|
assertThat(
|
||||||
|
"Results should contain divide by 0 error",
|
||||||
|
inferResults,
|
||||||
|
containsExactly(
|
||||||
|
NULL_DEREFERENCE,
|
||||||
|
FILE,
|
||||||
|
procedures
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016 - present Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package endtoend.cpp;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static utils.matchers.ResultContainsExactly.containsExactly;
|
||||||
|
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.ClassRule;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import utils.DebuggableTemporaryFolder;
|
||||||
|
import utils.InferException;
|
||||||
|
import utils.InferResults;
|
||||||
|
import utils.InferRunner;
|
||||||
|
|
||||||
|
public class SharedPtrDerefTest {
|
||||||
|
|
||||||
|
public static final String FILE =
|
||||||
|
"infer/tests/codetoanalyze/cpp/errors/smart_ptr/shared_ptr_deref.cpp";
|
||||||
|
|
||||||
|
private static ImmutableList<String> inferCmd;
|
||||||
|
|
||||||
|
public static final String NULL_DEREFERENCE = "NULL_DEREFERENCE";
|
||||||
|
|
||||||
|
@ClassRule
|
||||||
|
public static DebuggableTemporaryFolder folder =
|
||||||
|
new DebuggableTemporaryFolder();
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void runInfer() throws InterruptedException, IOException {
|
||||||
|
inferCmd = InferRunner.createCPPInferCommand(folder, FILE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenInferRunsNullDerefFunctionsErrorIsFound()
|
||||||
|
throws InterruptedException, IOException, InferException {
|
||||||
|
String[] procedures = {
|
||||||
|
"empty_ptr_deref",
|
||||||
|
"nullptr_ptr_deref",
|
||||||
|
"empty_ptr_field_deref",
|
||||||
|
"empty_ptr_field_deref2",
|
||||||
|
"empty_ptr_method_deref",
|
||||||
|
"reset_ptr_null_deref",
|
||||||
|
"reset_ptr_null_deref2",
|
||||||
|
"shared_ptr_copy_null_deref",
|
||||||
|
"shared_ptr_assign_null_deref",
|
||||||
|
};
|
||||||
|
InferResults inferResults = InferRunner.runInferCPP(inferCmd);
|
||||||
|
assertThat(
|
||||||
|
"Results should contain divide by 0 error",
|
||||||
|
inferResults,
|
||||||
|
containsExactly(
|
||||||
|
NULL_DEREFERENCE,
|
||||||
|
FILE,
|
||||||
|
procedures
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue