diff --git a/src/lib/unique-malloc-owner.hpp b/src/lib/unique-malloc-owner.hpp new file mode 100644 index 000000000..db83cb04a --- /dev/null +++ b/src/lib/unique-malloc-owner.hpp @@ -0,0 +1,86 @@ +/* + UNIQUE-MALLOC-OWNER.hpp - automatic management of C-malloced memory + + Copyright (C) Lumiera.org + 2014, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + + +/** @file unique-malloc-owner.hpp + ** Helper to deal with C-MALLOCed memory automatically. + ** This solution is a simple dress-up of std::unique_ptr, + ** mostly for the purpose of documenting the issue at the + ** usage site. + ** + ** @see cxx-demangle.cpp + ** @see UniqueMallocOwner_test + ** + */ + + +#ifndef UNIQUE_MALLOC_OWNER_H_ +#define UNIQUE_MALLOC_OWNER_H_ + + +#include "lib/error.hpp" + +#include + + +namespace lib { + + + /** + * Ownership token for a piece of heap memory allocated in plain-C style. + * This smart ptr takes ownership of the memory given at construction, + * to make sure it is deallocated properly with \c free(void*). + * Ownership can be transferred by move semantics. + * @remarks \c std::free is installed as deleter function, + * which means we're carrying along an additional pointer + */ + template + class UniqueMallocOwner + : public std::unique_ptr + { + using _Parent = std::unique_ptr; + + public: + explicit + UniqueMallocOwner(void* memory =nullptr) + : _Parent(static_cast(memory), std::free) + { } + + explicit + UniqueMallocOwner(X* alloc) + : _Parent(alloc, std::free) + { } + + + bool + empty() const + { + return ! bool(*this); + } + }; + + + + + +} // namespace lib +#endif /*UNIQUE_MALLOC_OWNER_HPP_*/ diff --git a/tests/15library.tests b/tests/15library.tests index 111c0e5b1..15146f939 100644 --- a/tests/15library.tests +++ b/tests/15library.tests @@ -441,11 +441,21 @@ return: 0 END +TEST "ownership of malloced data" UniqueMallocOwner_test < + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +* *****************************************************/ + + +#include "lib/test/run.hpp" +#include "lib/test/test-helper.hpp" +#include "lib/unique-malloc-owner.hpp" +#include "lib/util.hpp" + +#include +#include +#include + +using std::string; +using util::isnil; + + +namespace lib { +namespace test{ + + namespace { + + void* + mallocMess (size_t siz) + { + return malloc(siz); + } + } + + + + + + + + + /***************************************************************************//** + * @test Verify automatic management of memory originally allocated by C malloc. + * This situation typically arises when some plain-C function returns + * results in a heap allocated buffer, requiring the client to care + * for proper clean-up. To avoid creating a liability, we wrap the + * buffer into a smart pointer, which acts as ownership token + * and abstracts the specifics of clean-up. + * + * This test places a given (or random) string into a heap malloced + * buffer, and then pushes the "hot potato" of ownership responsibility + * around; another function checks the content of the buffer and consumes + * the token as a side-effect. At the end, there should be no memory leak + * and the ownership token should be empty. + * + * @see lib::UniqueMallocOwner + * @see lib::test::demangleCxx + */ + class UniqueMallocOwner_test : public Test + { + + using CharOwner = UniqueMallocOwner; + + virtual void + run (Arg args) + { + string probeString = isnil(args)? randStr(123) : args[0]; + auto hotPotato = place_into_malloced_buffer (probeString); + + CHECK (!isnil (hotPotato)); + verify_and_consume (std::move(hotPotato), probeString); + CHECK (isnil (hotPotato)); + } + + + CharOwner + place_into_malloced_buffer (string probeString) + { + CharOwner hotPotato(mallocMess (1 + probeString.length())); + std::strcpy(hotPotato.get(), probeString.c_str()); + return hotPotato; + } + + + void + verify_and_consume (CharOwner hotPotato, string refString) + { + CHECK (refString == hotPotato.get()); + + } // note sideeffect: hotPotato goes out of scope here... + }; + + + /** Register this test class... */ + LAUNCHER (UniqueMallocOwner_test, "unit common"); + + + +}} // namespace lib::test