Mirrored from https://github.com/CesiumGS/cesium-unreal/issues/1712
What happened?
Hope this is the right place for a potential bug report. Upon quick-launching my app to Android, I receive the following on or immediately after the UE splash:
Fatal error: FMallocBinned Attempt to GetAllocationSizeExternal an unrecognized pointer
The level fails to load when any CES tileset is added, notably when loading from CES Ion and an ellipsoid.
I am new to Android development, but I have had success launching without a CES tileset. Maybe this is an issue with the latest version of CES (2.17.0) for UE (5.6)?
See the attached the abd logcat file.
MDP_pixel8pro_crash.txt
Environment
Cesium for Unreal version: 2.17.0
Unreal Engine Version: 5.6
Operating System: Windows 11
Reproduction steps
Create new UE project on 5.6 and install CES 2.17.0
Add CES 3D Tileset to level (Google, World Terrain, …)
Quick-deploy to Android device
See crash on or immediately after UE splash, before level load
Supporting evidence
See prior logcat file.
Hi @CoulterMDP , thanks for reporting this, and for the detailed steps to reproduce.
I can reproduce this on my Pixel 6 Pro, but I don’t know yet what causes it. The good news is that doing a full package of the game for the device works fine. It seems to only be the Quick Launch that has this crash at startup.
I wrote an issue for it here:
opened 03:40AM - 04 Aug 25 UTC
bug
Originally reported here, with detailed steps to reproduce:
https://community.ce… sium.com/t/android-fatal-fmallocbinned-attempt-getallocationsizeexternal-unrecognized-pointer-ces-2-17-0-ue-5-6/42329
I can reproduce the crash on Quick Launch, but (fortunately?) it runs fine when doing a full package.
Very interesting. I didn’t think to create a full package! Good to know this is reproducible and good luck to your team in figuring this out. Wish I could provide a solution
Hi Kevin. I tried the full package and I get the same error when launching it off of my device. I’ve attached the latest logcat for your reference. I’ve also been getting a prompt to enable storage permissions, but those permissions can’t be given on my android version. This was before the same error occurred again. Anyways, I’m going to be trying some fixes over the next week. I’ll keep you updated.
MDP_pixel8pro_crash_packaged.zip (101.7 KB)
Hmm interesting. Can you try doing a full package of the Cesium for Unreal Samples project, and see if you have the same problem? That’s what I tried, and it worked ok for me.
I created a fresh CesiumForUnrealSamples project and used the project launcher 2 times:
Streamed to device
Installed on device
Both crashed for the same reasons. I’ve trimmed the logs a little.
I’ll keep mirroring these posts to the GitHub repo. Thanks for your help so far.
There recently have been reports about stringstream causing trouble in 5.6 (with the exact error message that can be seen here), e.g. at c++ - How to build an Android app using Unreal Engine 5.6 so I can use std::stringstream without crashing? - Stack Overflow - now, given the complexity of … *points in all directions* … this, it doesn’t have to be related, but that code there could be a “baseline test”, in some sense…
You’re probably on to something there, @Marco13 . Perhaps we need a workaround on Android similar to this one on iOS:
opened 08:32AM - 07 Feb 25 UTC
bug
Mentioned on the community forum here:
https://community.cesium.com/t/solved-ios… -apps-distributed-to-the-app-store-crash/29401
https://community.cesium.com/t/issues-with-cesium-in-ue5-4-on-ios/37756/3
Packaging a game and running it on an iPhone from Xcode works fine. But if we create an "archive" (ipa) and then run that on the device, it crashes very quickly after showing the splash screen. The immediate cause of the crash is that a std::string's destructor is called, and the memory it holds was not allocated by the standard `operator new`. That's because it was allocated from Cesium3DTileset.cpp, which, being compiled in the usual Unreal way, overrides `operator new` with its own custom allocator.
The fundamental problem is that the `basic_string` constructor that gets called is found in our Unreal game, so it uses Unreal's custom allocator, while the `basic_string` destructor is found in `libc++.dylib`, so it uses the standard allocator.
> Rant: this is why overriding operator new and delete is a terrible idea. Think you can get better performance with a custom allocator? Well, ok, I'm skeptical that that's true if it's a general purpose allocator, but go ahead if you want to try. But call your custom allocator explicitly from your code. Overriding the global new and delete makes it pretty much impossible for dynamically-allocated objects to cross .dll/.so/.dylib boundaries. Which maybe doesn't sound _too_ bad, until you consider that "objects" includes std::string, and ".dll/.so/.dylib" includes libc++.so/.dylib. It's pretty much just dumb luck that this works on other platforms where the C++ standard library is dynamically linked.
I spent a lot of time trying to understand why the constructor/destructor end up coming from two different places. Based on stepping through the disassembly with the xcode debugger (with the app running on the iPhone), I can see:
* Neither the constructor not the destructor are inlined. Both are actual function calls.
* The constructor implementation is found in our app binary.
* The destructor implementation is found in libc++.dylib.
Why does this happen? Well, in Apple's libc++ (taken from iOS SDK v18.2), the relevant std::string constructor is declared/defined like this:
```
template <__enable_if_t<__is_allocator<_Allocator>::value, int> = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(const _CharT* __s) {
// ...
}
```
The destructor looks like this:
```
inline _LIBCPP_CONSTEXPR_SINCE_CXX20 ~basic_string() {
// ...
}
```
So the constructor has `_LIBCPP_HIDE_FROM_ABI`. Among other things, that adds the `__exclude_from_explicit_instantiation__` attribute. Here's the clang docs on what that means:
https://clang.llvm.org/docs/AttributeReference.html#exclude-from-explicit-instantiation
Long story short, methods marked with this attribute will be implicitly instantiated in every translation unit (cpp file) where they're used. Never will an implementation from libc++.dylib be used. That's consistent with what I'm seeing. Why? I have no idea!
Meanwhile, the destructor is declared `inline`. Well, it's not getting inlined. If it were, there wouldn't be a problem, because both the constructor and destructor would then use Unreal's allocator. But no, it's not inlined, despite that fact that it's declared inline. That's a little odd, but not shocking. For one thing, I reckon that `inline` here doesn't actually do anything at all, because the method implementation is found inside the class definition in this case, which implies `inline`. And second, `inline` is doesn't actually mean inline, cause C++ is like that. See here:
https://en.cppreference.com/w/cpp/language/inline
> The original intent of the inline keyword was to serve as an indicator to the optimizer that [inline substitution of a function](https://en.wikipedia.org/wiki/inline_expansion) is preferred over function call, that is, instead of executing the function call CPU instruction to transfer control to the function body, a copy of the function body is executed without generating the call. This avoids overhead created by the function call (passing the arguments and retrieving the result) but it may result in a larger executable as the code for the function has to be repeated multiple times.
>
> Since inline substitution is unobservable in the standard semantics, compilers are free to use inline substitution for any function that's not marked inline, and are free to generate function calls to any function marked inline. Those optimization choices do not change the rules regarding multiple definitions and shared statics listed above.
So clang isn't necessarily doing anything wrong by not inlining the destructor. 🤷
Alright, so the compiler is doing what it should, and it's easy to see why that causes a crash. The problem is either in Unreal Engine or in libc++, or in any case the interaction between the two of them. What can we do about it? Well, one solution is to tell Unreal not to use a custom allocator. This is done by defining `FORCE_ANSI_ALLOCATOR=1`. That reportedly worked in older versions of Unreal Engine, but not in newer ones (I haven't tried myself). It's not surprising that there would be problems when compiling the plugin and app with the ANSI allocator and the rest of Unreal Engine with its own allocator. Perhaps compiling all of Unreal Engine with ANSI would work, but that's a drastic step for people that just want to package their game for iOS.
I'm low on other ideas. Perhaps there are some compiler flag tweaks that would cause that destructor to get inlined. But even if we found such a solution, it feels precarious. Or go the other way, and construct all of our strings with a custom STL allocator that is guaranteed not to use Unreal's custom new/delete functions. But the allocator is part of std::string's type, so we'd basically have to specify it everywhere in cesium-native's public API.
Can we statically-link the C++ runtime library on iOS?
What other possibilities am I missing?
That is, perhaps Unreal Build Tool is over-aggressively stripping symbols from the built executable, breaking its own custom allocator.
Hi guys. Any updates on this by chance?
HI
Also looking for a solution to this problem
I also encountered the same problem. Could you please tell me how you solved it?