[cfe-dev] once_flag assumes zero-initialized memory
Richard Smith
richard at metafoo.co.uk
Thu Dec 20 19:22:44 PST 2012
On Thu, Dec 20, 2012 at 6:23 PM, Gordon Henriksen
<gordonhenriksen at me.com> wrote:
> libc++'s std::once_flag does not function if it is not initialized in zero-initialized memory.
This was fixed in r160604:
@@ -442,8 +442,8 @@
struct _LIBCPP_VISIBLE once_flag
{
_LIBCPP_INLINE_VISIBILITY
- // constexpr
- once_flag() {}
+ _LIBCPP_CONSTEXPR
+ once_flag() _NOEXCEPT : __state_(0) {}
> Please find a test attached. The C++11 standard specifically calls out dynamic allocation of once_flag in this example from §30.4.4.2:
>
> // object flag, member function
> class information {
> std::once_flag verified;
> void verifier();
>
> public:
> void verify() { std::call_once(verified,verifier); }
> };
>
> Here's a short example of the nonconforming behavior:
>
> $ cat call_once-dynamic.cpp
> #include <mutex>
> #include <type_traits>
> #include <cassert>
>
> int main() {
> std::aligned_storage<sizeof(std::once_flag),
> alignof(std::once_flag)>::type buffer;
> memset(&buffer, 0xff, sizeof(buffer));
> std::once_flag *flag = new ((void *) &buffer) std::once_flag;
>
> bool called = false;
> std::call_once(*flag, [&called]{ called = true; });
> assert(called && "once_flag is incompatible with dynamic allocation!");
>
> flag->~once_flag();
> }
> $ cat Makefile
> CXX = xcrun clang++
> CXXFLAGS = -std=c++11 -stdlib=libc++
>
> .PHONY: execute-test
> execute-test: call_once-dynamic
> @if ./call_once-dynamic; then echo pass; else echo fail; fi
>
> call_once-dynamic: call_once-dynamic.cpp
> xcrun clang++ -std=c++11 -stdlib=libc++ -o $@ $<
> $ make
> xcrun clang++ -std=c++11 -stdlib=libc++ -o call_once-dynamic call_once-dynamic.cpp
> Assertion failed: (called && "once_flag is incompatible with dynamic allocation!"), function main, file call_once-dynamic.cpp, line 13.
> /bin/sh: line 1: 45638 Abort trap: 6 ./call_once-dynamic
> fail
>
> For users, a workaround is as follows. I think this covers most core use cases, but isn't a perfect replacement for std::once_flag.
>
> class once_flag_libcpp_hack : public std::once_flag {
> public:
> once_flag_libcpp_hack() {
> memset(static_cast<std::once_flag*>(this), 0, sizeof(std::once_flag));
> }
> };
>
> namespace mycorp { typedef once_flag_libcpp_hack once_flag; }
>
> — Gordon
>
> _______________________________________________
> cfe-dev mailing list
> cfe-dev at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
>
More information about the cfe-dev
mailing list