From 437037e8c6bb990333281febe5648dacfcf2b576 Mon Sep 17 00:00:00 2001 From: Avril Date: Sat, 12 Mar 2022 18:32:17 +0000 Subject: [PATCH] Fix segfault in `opaque_handle` copy testing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fortune for opaque_handle's current commit: Curse − 凶 --- include/opaque.hh | 19 ++++---- src/main.cpp | 120 +++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 124 insertions(+), 15 deletions(-) diff --git a/include/opaque.hh b/include/opaque.hh index 93ce8ab..0cc9cab 100644 --- a/include/opaque.hh +++ b/include/opaque.hh @@ -44,7 +44,7 @@ struct opaque_handle final { : _impl(std::exchange(move._impl, nullptr)){} inline opaque_handle(const opaque_handle& copy) : _impl(copy._impl - ? std::addressof(copy._impl->clone()) //(copy._impl->try_clone() ?: throw opaque_not_copyable{}) + ? copy._impl->try_clone() //(copy._impl->try_clone() ?: throw opaque_not_copyable{}) : nullptr){} constexpr ~opaque_handle() @@ -177,13 +177,13 @@ constexpr inline opaque_handle make_opaque_handle(T* data, const HandleF& handle struct object_handler final : opaque_handle_impl { constexpr object_handler(const object_handler& c) noexcept(is_nothrow) - : data(c.handler(data, opaque_handle_operation::Clone)) + : data(c.handler(c.data, opaque_handle_operation::Clone)) , handler(c.handler){} constexpr object_handler(object_handler&& m) noexcept : data(std::exchange(m.data, nullptr)) , handler(m.handler){} - constexpr object_handler(T* data, const HandleF& handler) noexcept - : data(data) + constexpr explicit object_handler(T* _data, const HandleF& handler) noexcept + : data(_data) , handler(handler){} constexpr virtual ~object_handler() //noexcept(is_nothrow) @@ -215,15 +215,16 @@ constexpr inline opaque_handle make_opaque_handle(T* data, HandleF&& handler) no struct object_handler final : opaque_handle_impl { - constexpr object_handler(const object_handler& c) noexcept(is_nothrow && std::is_nothrow_copy_constructible_v) requires(std::is_copy_constructible_v) - : data(c.handler(data, opaque_handle_operation::Clone)) + constexpr object_handler(const object_handler& c) + noexcept(is_nothrow && std::is_nothrow_copy_constructible_v) requires(std::is_copy_constructible_v) + : data(c.handler(c.data, opaque_handle_operation::Clone)) , handler(c.handler){} constexpr object_handler(object_handler&& m) noexcept : data(std::exchange(m.data, nullptr)) , handler(std::move(m.handler)){} - constexpr object_handler(T* data, HandleF&& handler) noexcept(is_nothrow_ctor) - : data(data) + constexpr explicit object_handler(T* _data, HandleF&& handler) noexcept(is_nothrow_ctor) + : data(_data) , handler(std::move(handler)){} constexpr virtual ~object_handler() //noexcept(is_nothrow) @@ -266,7 +267,7 @@ constexpr inline opaque_handle make_opaque_handle(T* data) noexcept constexpr object_handler(object_handler&& m) noexcept : data(std::exchange(m.data, nullptr)){} - constexpr object_handler(T* data) noexcept + constexpr explicit object_handler(T* data) noexcept : data(data){} constexpr virtual ~object_handler() //noexcept(is_nothrow) diff --git a/src/main.cpp b/src/main.cpp index a0ee203..b92770c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,8 +1,21 @@ +//#define _GNU_SOURCE +#include +#include #include + #include #include "../include/opaque.hh" +static void s_puts(const auto& string) +{ + std::string_view str{string}; +#ifdef DIRECT_WRITE + write(1, str.data(), str.size()); +#else + printf("%.*s", (int)str.size(), str.data()); +#endif +} static void print_view(std::string_view ptr) { @@ -37,15 +50,26 @@ enum class moh_hck { /// Example using `make_opaque_handle`, like would be done for a C interface template -void use_moh() +static void use_moh() { std::string* str = new std::string(__PRETTY_FUNCTION__); + constexpr auto v_print = [](const opaque_handle& v) { + print(*v); + { + auto copied = v; + s_puts("(copied)"); + print(*copied); + s_puts("(moved)"); + print(*std::move(copied)); + } + }; + if constexpr(Create != moh_hck::Owned) { constexpr auto _h = [](std::string* ptr, auto op) noexcept { if(ptr) { switch(op) { - case opaque_handle_operation::Clone: return new std::string(*ptr); + case opaque_handle_operation::Clone: return new std::string(std::as_const(*ptr)); case opaque_handle_operation::Delete: delete ptr; break; } } @@ -54,22 +78,59 @@ void use_moh() if constexpr(Create == moh_hck::Template) { const opaque_handle v{make_opaque_handle(str)}; - print(*v); + v_print(v); } else /*if constexpr(Create == moh_hck::Ref)*/ { const opaque_handle v{make_opaque_handle(str, _h)}; - print(*v); + v_print(v); } } else { const opaque_handle v{make_opaque_handle(str, [](std::string* ptr, auto op) noexcept { if(ptr) { switch(op) { - case opaque_handle_operation::Clone: return new std::string(*ptr); + case opaque_handle_operation::Clone: return new std::string(std::as_const(*ptr)); case opaque_handle_operation::Delete: delete ptr; break; } } return static_cast(nullptr); })}; - print(*v); + v_print(v); + } + s_puts("---\n"); +} + +// Testing a hypothetical C interface +extern "C" { + struct c_struct_example; + + c_struct_example* cs_create(const c_struct_example* __restrict__ from); + void cs_free(c_struct_example* p); + + void cs_print(const c_struct_example* p); +} + +static void use_c_struct() +{ + using type = c_struct_example; + auto* allocp = cs_create(nullptr); + + const opaque_handle v{make_opaque_handle(allocp, [](auto* ptr, auto op) noexcept { + if(ptr) { + switch(op) { + case opaque_handle_operation::Clone: return cs_create(ptr); + case opaque_handle_operation::Delete: cs_free(ptr); break; + } + } + return static_cast(nullptr); + })}; + + s_puts("> "); + cs_print(v); + { + auto copied = v; + s_puts("(copied)> "); + cs_print(copied); + s_puts("(moved)> "); + cs_print(std::move(copied)); } } @@ -85,5 +146,52 @@ int main() use_moh(); use_moh(); use_moh(); + + puts("\nUsing a C interface struct:"); + use_c_struct(); return 0; } + +extern "C" { + struct c_struct_example { + int i,j; + size_t sz; + char buf[256]; + }; + + c_struct_example* cs_create(const c_struct_example* __restrict__ from) + { + auto* ptr = reinterpret_cast(aligned_alloc(alignof(c_struct_example), sizeof(c_struct_example))); + //memset(ptr, 0, sizeof(c_struct_example); + if(!from) { + ptr->i = 10; + ptr->j = 11; + snprintf(ptr->buf, 256, "Hello from C interface"); + } else { + //memcpy(ptr, from, sizeof(c_struct_example)); + *ptr = *from; + + ptr->i +=1; + ptr->j -=1; + snprintf(ptr->buf, 256, "Hello from copied C interface (from %p)", from); + } + return ptr; + } + + void cs_print(const c_struct_example* p) + { +#ifdef DIRECT_WRITE + char ibuf[512]; + size_t n = snprintf(ibuf, 512, "%s: (%d, %d)", p->buf, p->i, p->j); + write(1, ibuf, n < sizeof(ibuf) ? n : 511); + write(1, "\n", 1); +#else + printf("%s: (%d, %d)\n", p->buf, p->i, p->j); +#endif + } + + void cs_free(c_struct_example* p) + { + free(p); + } +}