Hi all, I'm filing this bug after exhausting many other options. I'm running a wasm binary with link time optimization and have tried running with ASSERTIONS, SAFE_HEAP, STACK_OVERFLOW_CHECK, and --memoryprofiler on emscripten. I've also run with an address sanitizer (`--copt=-fsanitize=address --linkopt=-fsanitize=address`), both in native and wasm builds. This bug reproes 100% of the time on iOS Safari, but not on Android, native Mac OS, or desktop Chrome + Safari But, on to the bug. Here you can see we take two references (o1 and o2) to the same object in a vector: ``` class Object { ... uint32_t id() const { return id_; } ... uint32_t id_ = 0; }; std::vector<Object> objs_; void f() { auto &o1 = objs_.at(idx); ... auto &o2 = objs_.at(idx); ... if (std::addressof(o1) == std::addressof(o2) && o1.id() != o2.id()) { printf("Same object but different values! (%p and %p) (%zu and &zu)", &o1, &o2, o1.id(), o2.id()); } ... } ``` We then check if their address is the same but the value of `id()`, which is a trivial accessor for a primitive field, is different - which it is: ``` Same object but different values! (0xb472c8 and 0xb472c8) (3676866271 and 0) ``` The worst part about this bug is that it manifests itself when I change seemingly unrelated code, specifically changing a destructor from an empty user-defined destructor `~Foo() {}`, to a default destructor `~Foo() = default;`. I've diff-ed the bitcode before link time optimization with both destructors, and they are the same. So it seems perhaps somewhere in LTO there is a memory issue being introduced. As an extra hurdle, this bug is resistant to inspection. If I try to print out the memory around o1 and o2, then the bug no longer occurs. ``` for (int i = 0; i < 128; ++i) { printf("%02x ", (unsigned char*)&o1 + i); } ``` The impact of this bug is that our program is crashing because later when we access `o2.id()`, the value is zero. I have not been able to recreate this with a minimal repro case, but posting this in the hope others have seem something similar or have suggestions on investigating further. Details: - iOS Safari - C++ wasm with link time optimization - emsdk-sdk-2.0.27 - llvm 8ae5e0b154ae18a78f73c0aef58356002b8ff0d7
Thank you for the report! Could you please share a test case (one that can be simply open in Safari to observe the problem)?
Sure, here a link to a repro: https://8w.8thwall.app/safari-memory-bug. I've run it on an iPhone 12 Pro running iOS 15.0.1 and an iPhone 6S Plus running iOS 14.8. You should accept camera permissions and then wave the phone around for ~5 seconds to trigger the crash, upon which you'll see a screen saying "Oops, something went wrong!". If you connect to Safari and look at console logs you can then see logs. I've slightly modified the code above to instead be: ``` void f() { ... auto &o1 = objs_.at(idx); ... auto &o2 = objs_.at(idx); .... printf(" (1) First we check if o1 and o2 have the same address but different values:\n"); if (std::addressof(o1) == std::addressof(o2) && o1.id() != o2.id()) { printf(" (1) Same address but different values! o1: %p, o1.id(): %u | o2: %p, o2.id(): %u\n", &o1, o1.id(), &o2, o2.id()); } else if (std::addressof(o1) == std::addressof(o2)) { printf(" (1) Same address and same values. o1: %p, o1.id(): %u | o2: %p, o2.id(): %u\n", &o1, o1.id(), &o2, o2.id()); } printf(" (2) Now lets print out the addresses and ids of o1 and o2:\n"); printf(" (2) o1: %p, o1.id(): %u | o2: %p, o2.id(): %u\n", &o1, o1.id(), &o2, o2.id()); printf(" (3) Now check again if o1 and o2 have the same address but different values:\n"); if (std::addressof(o1) == std::addressof(o2) && o1.id() != o2.id()) { printf(" (3) Same address but different values! o1: %p, o1.id(): %u | o2: %p, o2.id(): %u\n", &o1, o1.id(), &o2, o2.id()); } else if (std::addressof(o1) == std::addressof(o2)) { printf(" (3) Same address and same values. o1: %p, o1.id(): %u | o2: %p, o2.id(): %u\n", &o1, o1.id(), &o2, o2.id()); } ``` The result is that on the camera frame that crashes you will see: ``` (1) First we check if o1 and o2 have the same address but different values: (1) Same address and same values. o1: 0xb392d8, o1.id(): 4240949120 | o2: 0xb392d8, o2.id(): 4240949120 (2) Now lets print out the addresses and ids of o1 and o2: (2) o1: 0xb392d8, o1.id(): 4240949120 | o2: 0xb392d8, o2.id(): 0 (3) Now check again if o1 and o2 have the same address but different values: (3) Same address but different values! o1: 0xb392d8, o1.id(): 4240949120 | o2: 0xb392d8, o2.id(): 0 ```
<rdar://problem/84258798>