[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