[cfe-dev] once_flag assumes zero-initialized memory

Gordon Henriksen gordonhenriksen at me.com
Thu Dec 20 19:38:49 PST 2012


Awesome. I'll set my workaround up to phase out when Apple ships the fix.

Thanks,
Gordon

On 2012-12-20, at 20:22, Richard Smith wrote:

> 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