Reviewed By: akotulski Differential Revision: D5398162 fbshipit-source-id: bf61516master
parent
5784357322
commit
30e1f4295b
@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright (c) 2017 - 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/common.h>
|
||||
#include <infer_model/infer_traits.h>
|
||||
|
||||
unsigned long int __infer_nondet_unsigned_long_int();
|
||||
|
||||
INFER_NAMESPACE_STD_BEGIN
|
||||
|
||||
// forward declaration because it is used here
|
||||
template <class T>
|
||||
class shared_ptr;
|
||||
|
||||
// Ideally: : public std__weak_ptr<T>
|
||||
// use inheritance to avoid compilation errors when using
|
||||
// methods / non-member functions that are not modeled
|
||||
// Currently not inherited because it leads to Symexec_memory_error
|
||||
|
||||
template <class T>
|
||||
class weak_ptr {
|
||||
|
||||
template <class>
|
||||
friend class weak_ptr;
|
||||
|
||||
// WARNING: if sizeof(weak_ptr) becomes different than 16, it may
|
||||
// lead to compilation errors
|
||||
T* ptr;
|
||||
void* __ignore;
|
||||
|
||||
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>
|
||||
weak_ptr(const std__weak_ptr<Y>& r) {}
|
||||
|
||||
// constructors:
|
||||
constexpr weak_ptr() noexcept { ptr = nullptr; }
|
||||
|
||||
template <class Y,
|
||||
typename = typename enable_if<is_convertible<Y*, T*>::value>::type>
|
||||
weak_ptr(const shared_ptr<Y>& r) noexcept {
|
||||
ptr = r.get();
|
||||
}
|
||||
|
||||
weak_ptr(const weak_ptr& r) noexcept { ptr = r.ptr; }
|
||||
|
||||
template <class Y,
|
||||
typename = typename enable_if<is_convertible<Y*, T*>::value>::type>
|
||||
weak_ptr(const weak_ptr<Y>& r) noexcept {
|
||||
ptr = r.ptr;
|
||||
}
|
||||
|
||||
weak_ptr(weak_ptr&& r) noexcept {
|
||||
ptr = r.ptr;
|
||||
r.ptr = nullptr;
|
||||
}
|
||||
|
||||
template <class Y,
|
||||
typename = typename enable_if<is_convertible<Y*, T*>::value>::type>
|
||||
weak_ptr(weak_ptr<Y>&& r) noexcept {
|
||||
ptr = r.ptr;
|
||||
r.ptr = nullptr;
|
||||
}
|
||||
|
||||
// destructor:
|
||||
~weak_ptr() { ptr = nullptr; }
|
||||
|
||||
// assignment:
|
||||
weak_ptr& operator=(const weak_ptr& r) noexcept {
|
||||
// weak_ptr<T>(r).swap(*this);
|
||||
ptr = r.ptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class Y,
|
||||
typename = typename enable_if<is_convertible<Y*, T*>::value>::type>
|
||||
weak_ptr& operator=(const weak_ptr<Y>& r) noexcept {
|
||||
// weak_ptr<T>(r).swap(*this);
|
||||
ptr = r.ptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class Y,
|
||||
typename = typename enable_if<is_convertible<Y*, T*>::value>::type>
|
||||
weak_ptr& operator=(const shared_ptr<Y>& r) noexcept {
|
||||
// weak_ptr<T>(r).swap(*this);
|
||||
ptr = r.get();
|
||||
return *this;
|
||||
}
|
||||
|
||||
weak_ptr& operator=(weak_ptr&& r) noexcept {
|
||||
// shared_ptr<T>(std::move(r)).swap(*this);
|
||||
ptr = r.ptr;
|
||||
r.ptr = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class Y,
|
||||
typename = typename enable_if<is_convertible<Y*, T*>::value>::type>
|
||||
weak_ptr& operator=(weak_ptr<Y>&& r) {
|
||||
// weak_ptr<T>(std::move(r)).swap(*this);
|
||||
ptr = r.ptr;
|
||||
r.ptr = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// modifiers:
|
||||
void swap(weak_ptr& r) noexcept {
|
||||
T* tmp = ptr;
|
||||
ptr = r.ptr;
|
||||
r.ptr = tmp;
|
||||
}
|
||||
|
||||
void reset() noexcept {
|
||||
// weak_ptr().swap(*this);
|
||||
ptr = nullptr;
|
||||
}
|
||||
|
||||
// observers:
|
||||
long use_count() const noexcept {
|
||||
if (ptr) {
|
||||
return __infer_nondet_unsigned_long_int();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool expired() const noexcept { return use_count() <= 0; }
|
||||
|
||||
shared_ptr<T> lock() const noexcept {
|
||||
if (use_count() > 0) {
|
||||
return shared_ptr<T>(ptr);
|
||||
}
|
||||
return shared_ptr<T>();
|
||||
}
|
||||
|
||||
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 owner_less;
|
||||
|
||||
template <class T>
|
||||
struct owner_less<weak_ptr<T>>
|
||||
: binary_function<weak_ptr<T>, weak_ptr<T>, bool> {
|
||||
typedef bool result_type;
|
||||
bool operator()(weak_ptr<T> const& x, weak_ptr<T> const& y) const {
|
||||
return x.owner_before(y);
|
||||
}
|
||||
|
||||
bool operator()(shared_ptr<T> const& x, weak_ptr<T> const& y) const {
|
||||
return x.owner_before(y);
|
||||
}
|
||||
|
||||
bool operator()(weak_ptr<T> const& x, shared_ptr<T> const& y) const {
|
||||
return x.owner_before(y);
|
||||
}
|
||||
};
|
||||
|
||||
INFER_NAMESPACE_STD_END
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2017 - 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>
|
||||
|
||||
/* Compilation tests */
|
||||
|
||||
namespace shared_ptr_conv_from_derived {
|
||||
/*
|
||||
shared_ptr conversion does not work if inheritance is not public
|
||||
*/
|
||||
class Base {};
|
||||
class Derived : public Base {};
|
||||
class Q {
|
||||
protected:
|
||||
std::shared_ptr<Base> m_;
|
||||
|
||||
public:
|
||||
void setM(std::shared_ptr<Base> m) { m_ = std::move(m); }
|
||||
};
|
||||
class P {
|
||||
std::shared_ptr<Derived> m_;
|
||||
Q q_;
|
||||
void u() { q_.setM(m_); }
|
||||
};
|
||||
}
|
@ -0,0 +1,256 @@
|
||||
/*
|
||||
* Copyright (c) 2017 - 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>
|
||||
|
||||
extern "C" {
|
||||
void __infer_fail(char*);
|
||||
}
|
||||
|
||||
namespace weak_ptr_constructors {
|
||||
|
||||
struct Base {
|
||||
int* f1;
|
||||
Base(int* f1 = nullptr) : f1(f1) {}
|
||||
};
|
||||
|
||||
struct Derived : public Base {
|
||||
int* f2;
|
||||
Derived(int* f1 = nullptr) : Base(f1) {}
|
||||
};
|
||||
|
||||
std::weak_ptr<Base> empty() { return std::weak_ptr<Base>(); }
|
||||
|
||||
std::weak_ptr<Base> fromWeakBaseConstr(std::weak_ptr<Base> b) {
|
||||
return std::weak_ptr<Base>(b);
|
||||
}
|
||||
|
||||
std::weak_ptr<Base> fromWeakBaseAssign(std::weak_ptr<Base> b) {
|
||||
std::weak_ptr<Base> result;
|
||||
result = b;
|
||||
return result;
|
||||
}
|
||||
|
||||
std::weak_ptr<Base> fromWeakDerivedConstr(std::weak_ptr<Derived> d) {
|
||||
return std::weak_ptr<Base>(d);
|
||||
}
|
||||
|
||||
std::weak_ptr<Base> fromWeakDerivedAssign(std::weak_ptr<Derived> d) {
|
||||
std::weak_ptr<Base> result;
|
||||
result = d;
|
||||
return result;
|
||||
}
|
||||
|
||||
std::weak_ptr<Base> fromSharedBaseConstr(std::shared_ptr<Base> b) {
|
||||
return std::weak_ptr<Base>(b);
|
||||
}
|
||||
|
||||
std::weak_ptr<Base> fromSharedBaseAssign(std::shared_ptr<Base> b) {
|
||||
std::weak_ptr<Base> result;
|
||||
result = b;
|
||||
return result;
|
||||
}
|
||||
|
||||
std::weak_ptr<Base> fromSharedDerivedConstr(std::shared_ptr<Derived> d) {
|
||||
return std::weak_ptr<Base>(d);
|
||||
}
|
||||
|
||||
std::weak_ptr<Base> fromSharedDerivedConstr2(std::shared_ptr<Derived> d) {
|
||||
std::weak_ptr<Derived> sd(d);
|
||||
return std::weak_ptr<Base>(sd);
|
||||
}
|
||||
|
||||
std::weak_ptr<Base> fromSharedDerivedAssign(std::shared_ptr<Derived> d) {
|
||||
std::weak_ptr<Derived> sd(d);
|
||||
std::weak_ptr<Base> result;
|
||||
result = sd;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
namespace weak_ptr_derefs {
|
||||
using namespace weak_ptr_constructors;
|
||||
|
||||
int safeGetFromEmpty_good() {
|
||||
auto w = empty();
|
||||
auto s = w.lock();
|
||||
while (!s)
|
||||
;
|
||||
return *s->f1; // never reached
|
||||
}
|
||||
|
||||
std::shared_ptr<Base> safeGet(std::weak_ptr<Base> p) {
|
||||
auto s = p.lock();
|
||||
while (!s)
|
||||
;
|
||||
return s;
|
||||
}
|
||||
|
||||
int safeGetFromWeakBaseConstr_bad(int v) {
|
||||
auto b = std::make_shared<Base>(&v);
|
||||
auto s = safeGet(fromWeakBaseConstr(std::weak_ptr<Base>(b)));
|
||||
b->f1 = nullptr;
|
||||
return *s->f1;
|
||||
}
|
||||
|
||||
int safeGetFromWeakBaseAssign_bad(int v) {
|
||||
auto b = std::make_shared<Base>(&v);
|
||||
auto s = safeGet(fromWeakBaseAssign(std::weak_ptr<Base>(b)));
|
||||
b->f1 = nullptr;
|
||||
return *s->f1;
|
||||
}
|
||||
|
||||
int safeGetFromWeakDerivedConstr_bad(int v) {
|
||||
auto d = std::make_shared<Derived>(&v);
|
||||
auto s = safeGet(fromWeakDerivedConstr(std::weak_ptr<Derived>(d)));
|
||||
d->f1 = nullptr;
|
||||
return *s->f1;
|
||||
}
|
||||
|
||||
int safeGetFromWeakDerivedAssign_bad(int v) {
|
||||
auto d = std::make_shared<Derived>(&v);
|
||||
auto s = safeGet(fromWeakDerivedAssign(std::weak_ptr<Derived>(d)));
|
||||
d->f1 = nullptr;
|
||||
return *s->f1;
|
||||
}
|
||||
|
||||
int safeGetFromSharedBaseConstr_bad(int v) {
|
||||
auto b = std::make_shared<Base>(&v);
|
||||
auto s = safeGet(fromSharedBaseConstr(b));
|
||||
b->f1 = nullptr;
|
||||
return *s->f1;
|
||||
}
|
||||
|
||||
int safeGetFromSharedBaseAssign_bad(int v) {
|
||||
auto b = std::make_shared<Base>(&v);
|
||||
auto s = safeGet(fromSharedBaseAssign(b));
|
||||
b->f1 = nullptr;
|
||||
return *s->f1;
|
||||
}
|
||||
|
||||
int safeGetFromSharedDerivedConstr_bad(int v) {
|
||||
auto b = std::make_shared<Derived>(&v);
|
||||
auto s = safeGet(fromSharedDerivedConstr(b));
|
||||
b->f1 = nullptr;
|
||||
return *s->f1;
|
||||
}
|
||||
|
||||
int safeGetFromSharedDerivedConstr2_bad(int v) {
|
||||
auto b = std::make_shared<Derived>(&v);
|
||||
auto s = safeGet(fromSharedDerivedConstr2(b));
|
||||
b->f1 = nullptr;
|
||||
return *s->f1;
|
||||
}
|
||||
|
||||
int safeGetFromSharedDerivedAssign_bad(int v) {
|
||||
auto b = std::make_shared<Derived>(&v);
|
||||
auto s = safeGet(fromSharedDerivedAssign(b));
|
||||
b->f1 = nullptr;
|
||||
return *s->f1;
|
||||
}
|
||||
}
|
||||
|
||||
namespace weak_ptr_modifiers {
|
||||
|
||||
void reset(std::weak_ptr<int>& p) { p.reset(); }
|
||||
|
||||
void swap(std::weak_ptr<int>& p) {
|
||||
std::weak_ptr<int> q;
|
||||
q.swap(p);
|
||||
}
|
||||
}
|
||||
|
||||
namespace weak_ptr_observers {
|
||||
using namespace weak_ptr_constructors;
|
||||
|
||||
long use_count(std::weak_ptr<int>& p) { return p.use_count(); }
|
||||
|
||||
void use_count_empty_bad() {
|
||||
std::weak_ptr<int> p;
|
||||
if (p.use_count() == 0) {
|
||||
__infer_fail("use_count on empty weak_ptr is 0");
|
||||
}
|
||||
}
|
||||
|
||||
void use_count_after_reset_bad(std::weak_ptr<int>& p) {
|
||||
p.reset();
|
||||
if (p.use_count() == 0) {
|
||||
__infer_fail("use_count after weak_ptr reset is 0");
|
||||
}
|
||||
}
|
||||
|
||||
bool expired(std::weak_ptr<int>& p) { return p.expired(); }
|
||||
|
||||
void expired_empty_bad() {
|
||||
std::weak_ptr<int> p;
|
||||
if (p.expired()) {
|
||||
__infer_fail("expired on empty weak_ptr is true");
|
||||
}
|
||||
}
|
||||
|
||||
void expired_after_reset_bad(std::weak_ptr<int>& p) {
|
||||
p.reset();
|
||||
if (p.expired()) {
|
||||
__infer_fail("expired after weak_ptr reset is true");
|
||||
}
|
||||
}
|
||||
|
||||
void expired_after_swap_bad(std::weak_ptr<int>& p) {
|
||||
std::weak_ptr<int> q;
|
||||
q.swap(p);
|
||||
if (p.expired()) {
|
||||
__infer_fail("expired after weak_ptr swap with empty is true");
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<int> lock(std::weak_ptr<int>& p) { return p.lock(); }
|
||||
|
||||
void empty_weak_lock_returns_null_bad() {
|
||||
std::weak_ptr<int> p;
|
||||
auto s = p.lock();
|
||||
int _ = *s.get();
|
||||
}
|
||||
|
||||
void expired_means_null_bad(std::weak_ptr<int>& p) {
|
||||
if (p.expired()) {
|
||||
auto s = p.lock();
|
||||
int _ = *s.get();
|
||||
}
|
||||
}
|
||||
|
||||
void lock_can_be_null_bad(std::weak_ptr<int>& p) {
|
||||
auto s = p.lock();
|
||||
int _ = *s.get();
|
||||
}
|
||||
|
||||
int safe_deref_good(std::weak_ptr<int>& p) {
|
||||
if (auto s = p.lock()) {
|
||||
return *s.get();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::shared_ptr<int> shared_still_in_scope_good_FP() {
|
||||
/* It's not a big issue to FP in this case.
|
||||
Code should not be written like that anyway. */
|
||||
auto s = std::make_shared<int>();
|
||||
auto p = std::weak_ptr<int>(s);
|
||||
auto s2 = p.lock();
|
||||
auto _ = *s2.get();
|
||||
return s;
|
||||
}
|
||||
|
||||
bool owner_before(std::weak_ptr<Base>& p, std::weak_ptr<Base>& q) {
|
||||
return p.owner_before(q);
|
||||
}
|
||||
|
||||
bool owner_before(std::weak_ptr<Base>& p, std::shared_ptr<Derived>& q) {
|
||||
return p.owner_before(q);
|
||||
}
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) 2017 - 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 <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
|
||||
/* Compilation tests */
|
||||
|
||||
namespace weak_ptr_lock_repro_small {
|
||||
template <class T>
|
||||
std::shared_ptr<T> joinT(std::shared_ptr<T> x) {
|
||||
return x;
|
||||
};
|
||||
|
||||
void foo(std::weak_ptr<int> p) {
|
||||
auto self = p.lock();
|
||||
std::shared_ptr<int> x = joinT(self);
|
||||
}
|
||||
}
|
||||
|
||||
namespace weak_ptr_lock_repro_large {
|
||||
|
||||
class S {
|
||||
public:
|
||||
template <typename T>
|
||||
std::shared_ptr<T> joinT(std::shared_ptr<T> s);
|
||||
};
|
||||
|
||||
class DCC {
|
||||
public:
|
||||
const std::shared_ptr<S>& s();
|
||||
};
|
||||
|
||||
class DC {};
|
||||
|
||||
class CDM {
|
||||
public:
|
||||
std::shared_ptr<DC> gdc(std::function<DCC()>);
|
||||
};
|
||||
|
||||
class RDC : DC {
|
||||
public:
|
||||
static std::shared_ptr<RDC> create(std::function<DCC()> cf);
|
||||
|
||||
private:
|
||||
const std::shared_ptr<CDM> cdm;
|
||||
mutable std::function<std::shared_ptr<DC>()> dcf;
|
||||
};
|
||||
|
||||
std::shared_ptr<RDC> RDC::create(std::function<DCC()> cf) {
|
||||
auto dc = std::make_shared<RDC>();
|
||||
dc->dcf =
|
||||
[ cf = std::move(cf),
|
||||
weakSelf = std::weak_ptr<RDC>(dc) ]() mutable->std::shared_ptr<DC> {
|
||||
if (auto self = weakSelf.lock()) {
|
||||
return self->cdm->gdc([&]() mutable {
|
||||
auto c = cf();
|
||||
c.s()->joinT(self);
|
||||
return c;
|
||||
});
|
||||
}
|
||||
return nullptr;
|
||||
};
|
||||
return dc;
|
||||
}
|
||||
}
|
||||
|
||||
namespace weak_ptr_owner_less {
|
||||
class K {};
|
||||
class V {};
|
||||
class C {
|
||||
using S = std::set<std::weak_ptr<K>, std::owner_less<std::weak_ptr<K>>>;
|
||||
std::
|
||||
map<std::weak_ptr<K>, std::weak_ptr<V>, std::owner_less<std::weak_ptr<K>>>
|
||||
m;
|
||||
S s;
|
||||
#ifdef INFER_USE_LIBCPP
|
||||
/* requires Clang headers */
|
||||
std::unordered_map<K, S> u;
|
||||
#endif
|
||||
};
|
||||
}
|
Loading…
Reference in new issue