[libcxx-dev] Potential issue on ARM32 processors with taking a reference of a newly-inserted map value

Chris Watts via libcxx-dev libcxx-dev at lists.llvm.org
Thu Nov 7 03:15:58 PST 2019


There shouldn't be any uninitialized reads here, as State should be
value-initialized:

If an insertion is performed, the mapped value is value-initialized
> <https://en.cppreference.com/w/cpp/language/value_initialization> (default-constructed
> for class types, zero-initialized otherwise) and a reference to it is
> returned.


Indeed, this problem also exists if the members of the struct are all
assigned default values in the definition:

struct State {
    size_t a = 0;
    boost::posix_time::ptime b = boost::posix_time::microsec_
clock::universal_time();
    bool c = false;
    bool d = false;
};

On Thu, 7 Nov 2019 at 00:37, Eric Fiselier <eric at efcs.ca> wrote:

> You're reading from uninitialized memory. That's undefined behavior.
>
> On Wed, Nov 6, 2019, 9:17 AM Chris Watts via libcxx-dev <
> libcxx-dev at lists.llvm.org> wrote:
>
>> Hi, I'm new here. Fixed an interesting segfault today. Here's how it goes.
>>
>> I have a std::map of the following struct:
>>
>> struct State {
>>     size_t a;
>>     boost::posix_time::ptime b;
>>     bool c;
>>     bool d;
>> };
>> std::map<std::string, State> myMap;
>>
>> Then I do a find-or-create operation and take a reference to the result:
>>
>> std::string key = arbitraryString();
>> State& s = myMap[key];
>>
>> Now, as long as I only touch the first two members of the struct, all is
>> rosy.
>> s.a++;
>> s.b = boost::posix_time::microsec_clock::universal_time();
>>
>> But I found that as soon as I touched `s.c` or `s.d`, a segfault occurs
>> at `State& s = myMap[key];`:
>>
>> if (!s.c) { ... // Eventually causes a segfault at the assignment of s.
>> Before the segfault, the value of s.c is often random data and not the
>> expected value.
>>
>> While this segfault is spurious, it is frequent enough to reproduce
>> reliably.
>> Unfortunately, this may be impractical to reproduce for many of you as it
>> only crashed on two of our armv7 hosts: a Motorola G6, and a Samsung J6.
>> arm64 hosts appear to be unaffected.
>>
>> My suspicion is that a temporary struct is being created with
>> `myMap[key]`, and the reference of that is being returned before it is
>> added to the map, but the memory is invalidated shortly after.
>>
>> It could be related to caching/register optimization, as the issue
>> doesn't happen if `State::c` and `State::d` are declared before `
>> State::a`.
>>
>> The issue doesn't occur in `std::unordered_map`.
>>
>> Clang details:
>> Android (5220042 based on r346389c) clang version 8.0.7 (
>> https://android.googlesource.com/toolchain/clang
>> b55f2d4ebfd35bf643d27dbca1bb228957008617) (
>> https://android.googlesource.com/toolchain/llvm
>> 3c393fe7a7e13b0fba4ac75a01aa683d7a5b11cd) (based on LLVM 8.0.7svn)
>> Target: armv7a-unknown-linux-android29
>> Thread model: posix
>>
>> libc++ details:
>> Actually I really don't know how to get this. Help:
>> ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64/bin/arm-linux-androideabi-readelf
>> -a ./ndk-bundle/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a/libc++.so.28
>> readelf: Error:
>> ./ndk-bundle/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a/libc++.so.28:
>> Failed to read file header
>>
>> Is anyone able to confirm? What more information do I need to collect?
>> _______________________________________________
>> libcxx-dev mailing list
>> libcxx-dev at lists.llvm.org
>> https://lists.llvm.org/cgi-bin/mailman/listinfo/libcxx-dev
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/libcxx-dev/attachments/20191107/f341fc58/attachment.html>


More information about the libcxx-dev mailing list