[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