From 6ab859ccd52cc991b0efef305de1e5a828413f8f Mon Sep 17 00:00:00 2001 From: Jonathan Roelofs Date: Sun, 26 Jan 2020 17:24:50 -0700 Subject: [PATCH 1/2] sandbox implementation of shared_ptr --- Makefile | 2 +- shared.h | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ undo.h | 6 ++-- 3 files changed, 100 insertions(+), 3 deletions(-) create mode 100644 shared.h diff --git a/Makefile b/Makefile index b0ca37f..25a975e 100644 --- a/Makefile +++ b/Makefile @@ -7,4 +7,4 @@ clean: undo: undo.cpp @mkdir -p bin - clang++ undo.cpp -o bin/undo --std=c++14 + clang++ undo.cpp -o bin/undo --std=c++14 -O0 -g -fsanitize=address,undefined diff --git a/shared.h b/shared.h new file mode 100644 index 0000000..24724cc --- /dev/null +++ b/shared.h @@ -0,0 +1,95 @@ +#ifndef SHARED_H +#define SHARED_H + +#include +#include +#include +#include + +namespace sandbox { + +static int retain_count = 0; +static int release_count = 0; + +template +struct shared_ptr { + struct control_block { + template + control_block(U *u_, size_t c_) : t(u_), strong_count(u_) {} + + control_block(T *t_, size_t c_) : t(t_), strong_count(c_) {} + T *t; + size_t strong_count; + }; + + template explicit shared_ptr(U *u) + : cb(new control_block(static_cast(u), 0)) { + retain(cb); + } + + shared_ptr(const shared_ptr &rhs) : cb(rhs.cb) { + retain(cb); + } + + template + shared_ptr(shared_ptr &&rhs) { + // FIXME: this seems like an ugly hack / potential UB. + cb = reinterpret_cast(rhs.cb); + retain(cb); + } + + shared_ptr &operator=(const shared_ptr &rhs) { + if (this != &rhs) { + release(cb); + cb = rhs.cb; + retain(cb); + } + return *this; + } + + ~shared_ptr() { + release(cb); + } + + void release(control_block *&cb) { + //printf("release %d\n", release_count++); + + if (cb->strong_count--) + return; + + assert(cb->strong_count == 0 && "releasing, but there are still referers"); + + delete cb->t; + cb->t = nullptr; + + delete cb; + cb = nullptr; + } + + void retain(control_block *cb) { + //printf("retain %d\n", retain_count++); + + cb->strong_count++; + } + + T *operator->() { + assert(cb && cb->strong_count && "dereferencing without a pointee"); + return cb->t; + } + + const T *operator->() const { + assert(cb && cb->strong_count && "dereferencing without a pointee"); + return cb->t; + } + + control_block *cb; +}; + +template +shared_ptr make_shared(Args... args) { + return shared_ptr(new T(std::forward(args)...)); +} + +} + +#endif diff --git a/undo.h b/undo.h index 281afa8..34542ec 100644 --- a/undo.h +++ b/undo.h @@ -6,6 +6,8 @@ * https://www.youtube.com/watch?v=bIhUE5uUFOA */ +#include "shared.h" + #include #include #include @@ -17,7 +19,7 @@ void draw(const T &t, std::ostream &out, size_t position); class object_t { public: template - object_t(T x) : self_(std::make_shared>(std::move(x))) {} + object_t(T x) : self_(sandbox::make_shared>(std::move(x))) {} friend void draw(const object_t &x, std::ostream &out, size_t position) { x.self_->draw_(out, position); @@ -39,7 +41,7 @@ class object_t { T data_; }; - std::shared_ptr self_; + sandbox::shared_ptr self_; }; using document_t = std::vector; From eee93b832233bf285cd9eca0f06b9780ab7e7e75 Mon Sep 17 00:00:00 2001 From: Jonathan Roelofs Date: Thu, 5 Mar 2020 16:37:26 -0700 Subject: [PATCH 2/2] Fix leak --- shared.h | 41 ++++++++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/shared.h b/shared.h index 24724cc..5511c1a 100644 --- a/shared.h +++ b/shared.h @@ -8,16 +8,36 @@ namespace sandbox { -static int retain_count = 0; -static int release_count = 0; +#if DEBUG_RETAIN +static int cb_count = 0; +#endif template struct shared_ptr { struct control_block { template - control_block(U *u_, size_t c_) : t(u_), strong_count(u_) {} + control_block(U *u_, size_t c_) : t(u_), strong_count(u_) + { +#if DEBUG_RETAIN + printf("CB #%d ctor\n", id = ++cb_count); +#endif + } + + control_block(T *t_, size_t c_) : t(t_), strong_count(c_) { +#if DEBUG_RETAIN + printf("CB #%d ctor\n", id = ++cb_count); +#endif + } + + ~control_block() { +#if DEBUG_RETAIN + printf("CB #%d dtor\n", id = cb_count--); +#endif + } - control_block(T *t_, size_t c_) : t(t_), strong_count(c_) {} +#if DEBUG_RETAIN + int id; +#endif T *t; size_t strong_count; }; @@ -52,9 +72,11 @@ struct shared_ptr { } void release(control_block *&cb) { - //printf("release %d\n", release_count++); +#if DEBUG_RETAIN + printf("release %d --> %zu\n", cb->id, cb->strong_count); +#endif - if (cb->strong_count--) + if (--cb->strong_count) return; assert(cb->strong_count == 0 && "releasing, but there are still referers"); @@ -67,9 +89,10 @@ struct shared_ptr { } void retain(control_block *cb) { - //printf("retain %d\n", retain_count++); - cb->strong_count++; +#if DEBUG_RETAIN + printf("retain %d --> %zu\n", cb->id, cb->strong_count); +#endif } T *operator->() { @@ -92,4 +115,4 @@ shared_ptr make_shared(Args... args) { } -#endif +#endif \ No newline at end of file