From 0e874252a859ef44e1554e4c609efacf5a570945 Mon Sep 17 00:00:00 2001 From: Ludovic 'Archivist' Lagouardette Date: Tue, 28 Apr 2020 12:08:42 +0200 Subject: [PATCH] Optional typesafety (found bug with asan) --- Makefile | 5 ++- include/gp/memory.hpp | 4 +- include/gp/optional.hpp | 90 +++++++++++++++++++++++++++++++---------- 3 files changed, 75 insertions(+), 24 deletions(-) diff --git a/Makefile b/Makefile index c112d61..5e8d9e0 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,12 @@ CXX= clang++-8 -CXXFLAGS= --std=c++17 -O0 -pthread -DFUZZ_STRENGTH=500000 \ +CXXFLAGS= --std=c++17 -O0 -pthread -DFUZZ_STRENGTH=500000 -pedantic -Werror \ + -fsanitize=address -fno-omit-frame-pointer \ -Wno-unknown-attributes \ -g -fprofile-instr-generate -fcoverage-mapping all: tests tests: bin/tests - LLVM_PROFILE_FILE="./bin/tests.profraw" ./bin/tests + LLVM_PROFILE_FILE="./bin/tests.profraw" ASAN_SYMBOLIZER_PATH=/usr/bin/llvm-symbolizer ./bin/tests @llvm-profdata merge -sparse ./bin/tests.profraw -o ./bin/tests.profdata @llvm-cov report ./bin/tests -instr-profile=./bin/tests.profdata include/*.hpp include/gp/*.hpp include/gp/algorithm/*.hpp include/gp/allocator/*.hpp @llvm-cov report ./bin/tests -instr-profile=./bin/tests.profdata include/*.hpp include/gp/*.hpp include/gp/algorithm/*.hpp include/gp/allocator/*.hpp | tail -n 1 | tr -s " " | sed -e 's/ /,/g' -- | awk -F "," '{print $$9}' | sed -e 's/^/Untested lines: /g' diff --git a/include/gp/memory.hpp b/include/gp/memory.hpp index 0aae5cc..793b2e3 100644 --- a/include/gp/memory.hpp +++ b/include/gp/memory.hpp @@ -4,6 +4,7 @@ #include // XXX: THIS FILE SHOULD BE REMOVED, AS SHOULD ALL DEPENDENCIES ON THE C-ALLOCATOR AS IS +/* namespace gp{ template> class default_memory_allocator @@ -54,4 +55,5 @@ void* operator new(size_t sz) void operator delete (void* ptr) noexcept { gp_config::memory_module::memory_deallocator(ptr); -} \ No newline at end of file +} +*/ \ No newline at end of file diff --git a/include/gp/optional.hpp b/include/gp/optional.hpp index 000ec54..5bc585a 100644 --- a/include/gp/optional.hpp +++ b/include/gp/optional.hpp @@ -39,7 +39,7 @@ namespace gp{ new(buffer) T(gp::move(value)); } - optional operator=(nullopt_t) { + optional& operator=(nullopt_t) { if(ready) { ((T*)buffer)->~T(); ready = false; @@ -47,7 +47,7 @@ namespace gp{ return *this; } - optional operator=(T& value) { + optional& operator=(T& value) { if(ready) { *(T*)buffer = value; } else { @@ -57,7 +57,7 @@ namespace gp{ return *this; } - optional operator=(T&& value) { + optional& operator=(T&& value) { if(ready) { *(T*)buffer = gp::move(value); } else { @@ -92,7 +92,7 @@ namespace gp{ template class optional{ bool ready = false; - void* ptr; + T* ptr; public: constexpr optional() : ready{false} @@ -102,50 +102,92 @@ namespace gp{ : ready{false} {} - // TODO: Add typesafe generic assignment - constexpr optional(T& value) + template + constexpr optional(U& value) : ready{true} { - ptr = (void*)new T(value); // TODO: Use allocators + ptr = new U(value); // TODO: Use allocators } - // TODO: Add typesafe generic assignment - constexpr optional(T&& value) + template + constexpr optional(U&& value) : ready{true} { - ptr = (void*)new T(gp::move(value)); // TODO: Use allocators + ptr = new U(gp::move(value)); // TODO: Use allocators } - optional operator=(nullopt_t) { + optional& operator=(nullopt_t) { if(ready) { - delete (T*)ptr; + delete ptr; ready = false; } return *this; } - // TODO: Add typesafe generic assignment - optional operator=(T& value) { + template + optional& operator=(U& value) { if(ready) { - *(T*)ptr = value; + if constexpr (std::is_same_v) { + *ptr = value; + } else { + delete ptr; // TODO: Use allocators + ptr = new U(value); // TODO: Use allocators + } } else { ready = true; - ptr = (void*)new T(value); // TODO: Use allocators + ptr = new U(value); // TODO: Use allocators } return *this; } - // TODO: Add typesafe generic assignment - optional operator=(T&& value) { + template + optional& operator=(U&& value) { if(ready) { - *(T*)ptr = gp::move(value); + if constexpr (std::is_same_v) { + *ptr = gp::move(value); + } else { + delete ptr; // TODO: Use allocators + ptr = new U(gp::move(value)); // TODO: Use allocators + } } else { ready = true; - ptr = (void*)new T(gp::move(value)); // TODO: Use allocators + ptr = new U(gp::move(value)); // TODO: Use allocators } return *this; } + template<> + optional& operator=(optional& value) { + if(ready) { + *ptr = value; + } else { + ready = true; + ptr = new optional(value.value()); // TODO: Use allocators + } + return *this; + } + + template<> + optional& operator=(optional&& value){ + if(ready) { + delete ptr; // TODO: Use allocators + } + if(value.ready) { + ptr = value.ptr; + value.ready = false; + ready = true; + return *this; + } else { + ready = false; + return *this; + } + } + + operator T&() { + gp_config::assertion(ready, "bad optional access"); + return *ptr; + } + constexpr bool has_value() { return ready; @@ -162,7 +204,13 @@ namespace gp{ } else { gp_config::assertion(ready, "bad optional access"); } - return *reinterpret_cast(ptr); + return *ptr; + } + + ~optional() { + if(ready) { + delete ptr; // TODO: Use allocators + } } }; } \ No newline at end of file