MapboxCoreMaps Crashes
Environment
- Xcode version: 14.3.1
- iOS version: 17.0.3, 17.1.0, 16.3.1, 16.0.0
- Devices affected: iPhone 13 Pro, iPhone 14, iPhone 13, iPhone 14 Pro Max, iPhone 11 etc.
- Maps SDK Version: 10.16.1
Observed behavior and steps to reproduce
Crash from MapboxCoreMaps with message
Pure virtual function called!
pure-virtual-function-stack-trace.txt
We also see in crashlytics a lot of crashes from MapboxCoreMaps with messages
malloc: Heap corruption detected, free list is damaged at 0x280bf9200 *** Incorrect guard value: 10749975056
and
malloc: Incorrect checksum for freed object 0x116208c00: probably modified after being freed. Corrupt value: 0x1160c5600
with different stack traces. Example: incorrect-checksum-stack-trace.txt
Expected behavior
no crashes
Notes / preliminary analysis
We migrated from Mapbox v6. At the time, around 10% of users, who updated or downloaded brand new version, experience some of these crashes. Unfortunately, I was unable to reproduce it on any of my devices.
It looks like all the crashes are about accessing released objects memory somewhere inside MapboxCoreMaps
I will be grateful for any help here
Hi @Ogerets , thank you for the report! I've created an internal ticket to investigate this https://mapbox.atlassian.net/browse/MAPSNAT-1591
@persidskiy Hi, I have an update on the issue It turned out the issue appears when we update layers concurrently. Unfortunately, I couldn't find in the docs any info about thread safety of provided functions.
Could you provide some information in this regard, please?
We were not updating layers on the main thread, since for some of them the updateLayers functions hungs UI really badly (was not the case at Mapbox v6 though).
I did benchmarks of MapboxMaps.Style.updateLayer function for our style. The bottleneck appears to be the parsing of old layer properties on line 168 (see attached screenshot). It takes up to 200 ms for our FillExtrusionLayer.
It's a big deal on the main thread. It would be great to have the option to execute this on a background one.
Also, I am not aware of Mapbox v6 implementation of updating layers, but we didn't have this issue there with the same layers configuration on the main thread.
@persidskiy Sorry for bothering you, but this issue is blocking us. Is there anything else I can do to help investigate the issue?
@Ogerets Do you have the style or layer configs that can be used to replicate this?
We were not updating layers on the main thread
Working on the non-main thread is an undefined behavior for SDK.
It takes up to 200 ms for our
FillExtrusionLayer.
@Ogerets the updateLayer is known to be slow. Unfortunately, this is our only solution with strong typed API for v10 and v11.
The good news is that you can update fields with another less convenient API. This one would skip all iOS SDK checks and calculations and report an update to the engine:
try mapView.mapboxMap.setLayerProperty(for: layer.id,
property: "fill-extrusion-height",
value: NSNumber(value: 10))
There are a few caveats:
- This type of API accepts only Objective-C objects (NSNumber, NSString, NSDictionary and NSArray) so you can't just pass an Int or Double
- Some types like UIColor need an extra conversion to string representation under-the-hood
- Codable CustomKeys enums are internal at the moment so you would need to copy-paste declarations
@OdNairy, thank you for the response
Do you have the style or layer configs that can be used to replicate this?
The layer is being created locally. I'll gather and send you a sample code of it and the tileset.
This is our only solution with strong typed API for v10
Shouldn't moving all expensive mappings to the non-main thread and leaving everything else on the main thread solve the issue? It looks like a quick and easy solution. Could be an alternative to the existing function.
You can update fields with another less convenient API
Thank you for the tip, I will look into it
Shouldn't moving all expensive mappings to the non-main thread and leaving everything else on the main thread solve the issue?
Sounds reasonable
Thank you for the tip, I will look into it
Another tip over the Objective-C objects – you can use a weird but working solution by converting swift objects (including Mapbox Maps ones) to the Data with JSONEncoder and convert them back with the JSONSerialization class.
Sounds reasonable
Tested a very crude implementation (see screenshot), and it solves the issue! Looks like a much better and easier approach than Obj-C API. I wonder if the fetching old layer properties on line 169 could be moved to the global thread as well.
It could be implemented using modern concurrency or some Mapbox internal queue management (saw runtime logs about it). Is there a chance it could be done by the Mapbox Team in the near future?
I'll gather and send you a sample code of it and the tileset.
Here is our tileset
Here's a stripped code we use for the layer which cause the issue mapbox_issue.zip
The code is more for inspecting than compiling. I apologize we couldn't find time to make a full sample project reproducing the issue