mapbox-gl-native
mapbox-gl-native copied to clipboard
App crashes because of `uncaught exception of type std::out_of_range: unordered_map::at: key not found` when running XCUITests
When running XCUITests in Xcode MapBox GL Native SDK for iOS crashes. See stack trace:
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.2
* frame #0: 0x000000011622ab86 libc++abi.dylib`__cxa_throw
frame #1: 0x00000001101b3a74 Mapbox`std::__1::unordered_map<unsigned int, MGLAnnotationContext, std::__1::hash<unsigned int>, std::__1::equal_to<unsigned int>, std::__1::allocator<std::__1::pair<unsigned int const, MGLAnnotationContext> > >::at(this=<unavailable>, __k=<unavailable>) at unordered_map:1459 [opt]
frame #2: 0x00000001101b9ef4 Mapbox`::-[MGLMapView accessibilityElementForAnnotationWithTag:](self=0x00007f8115017a00, _cmd=<unavailable>, annotationTag=1) at MGLMapView.mm:2509 [opt]
frame #3: 0x00000001101b9796 Mapbox`::-[MGLMapView accessibilityElementAtIndex:](self=0x00007f8115017a00, _cmd=<unavailable>, index=1) at MGLMapView.mm:2448 [opt]
frame #4: 0x000000012fb27afd UIAccessibility`-[NSObject(AXPrivCategory) accessibilityEnumerateContainerElementsWithOptions:usingBlock:] + 608
frame #5: 0x000000012fb27c4c UIAccessibility`-[NSObject(AXPrivCategory) accessibilityEnumerateContainerElementsUsingBlock:] + 71
frame #6: 0x000000012fb5d565 UIAccessibility`-[NSObject(UIAccessibilityAutomation) _accessibilityUserTestingChildren] + 233
frame #7: 0x000000012f952b1a UIKit`-[UIViewAccessibility _accessibilityUserTestingChildren] + 85
frame #8: 0x000000012fb33168 UIAccessibility`-[NSObject(AXPrivCategory) accessibilityAttributeValue:] + 322
frame #9: 0x000000012fb5e135 UIAccessibility`-[NSObject(UIAccessibilityAutomation) _accessibilityUserTestingSnapshotDescendantsWithAttributes:maxDepth:maxChildren:maxArrayCount:] + 2613
frame #10: 0x000000012fb6004d UIAccessibility`-[NSObject(UIAccessibilityAutomation) _accessibilityUserTestingSnapshotWithOptions:] + 830
frame #11: 0x000000012fb321f3 UIAccessibility`-[NSObject(AXPrivCategory) accessibilityAttributeValue:forParameter:] + 9622
frame #12: 0x000000012fb10596 UIAccessibility`_copyParameterizedAttributeValueCallback + 202
frame #13: 0x0000000129f95320 AXRuntime`___AXXMIGCopyParameterizedAttributeValue_block_invoke + 66
frame #14: 0x0000000129f94b9f AXRuntime`_handleNonMainThreadCallback + 55
frame #15: 0x0000000129f9519d AXRuntime`_AXXMIGCopyParameterizedAttributeValue + 306
frame #16: 0x0000000129f9088d AXRuntime`AXUIElementCopyParameterizedAttributeValue + 511
frame #17: 0x0000000129f55869 XCTAutomationSupport`-[XCTAccessibilityFramework userTestingSnapshotForElement:options:error:] + 230
frame #18: 0x0000000129f5047d XCTAutomationSupport`-[XCTElementSnapshotRequest(PlatformImplementation) accessibilitySnapshotOrError:] + 745
frame #19: 0x0000000129f57660 XCTAutomationSupport`__56-[XCTElementSnapshotRequest loadSnapshotAndReturnError:]_block_invoke_2 + 64
frame #20: 0x0000000129f4bc64 XCTAutomationSupport`__XCTPerformOnMainRunLoop_block_invoke + 78
frame #21: 0x000000011476205c CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 12
frame #22: 0x000000011474683b CoreFoundation`__CFRunLoopDoBlocks + 203
frame #23: 0x000000011474663b CoreFoundation`__CFRunLoopRun + 2875
frame #24: 0x0000000114745889 CoreFoundation`CFRunLoopRunSpecific + 409
frame #25: 0x000000011a18c9c6 GraphicsServices`GSEventRunModal + 62
frame #26: 0x0000000110f325d6 UIKit`UIApplicationMain + 159
libc++abi.dylib: terminating with uncaught exception of type std::out_of_range: unordered_map::at: key not found
Platform: Xcode simulator for iPhone 6, running iOS 11.2 Mapbox SDK version: v3.7.3
Steps to trigger behavior
XCUITest which let the target app add annotations to the map and then check if the annotation are available on the map by using XCUIElement for MGLMapView
.
Expected behavior
No crash when running XCUITests
Actual behavior
Crash when running XCUITests
For now we have a "workaround" by adding a delay in the XCUITests before accessing the MGLMapView XCUIElement.
Unfortunately delay doesn't always help, although it will reduce the frequency of test failures. There's another hack, that will prevent app from crashing:
@interface MGLMapView (UITest)
- (id)accessibilityElementForAnnotationWithTag:(NSUInteger)annotationTag;
@end
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wincomplete-implementation"
@implementation MGLMapView (UITest)
@end
#pragma clang diagnostic pop
@implementation MGLMapViewSubclass (UITest)
- (id)accessibilityElementForAnnotationWithTag:(NSUInteger)annotationTag
{
@try {
return [super accessibilityElementForAnnotationWithTag:annotationTag];
}
@catch(...) {
return nil;
}
}
@end
This looks like a crash in the accessibility code that produces accessibility elements representing annotations on the map. MGLMapView also generates accessibility elements for features in the base map, such as POIs and roads. Since the lists of accessibility elements eventually get merged, adding annotations may lead to an edge case we don’t account for.
Just to make sure I’m reproducing the exact issue you’re running into:
- Do you reproduce this issue when the map is viewing a particular region, a particular style, or with a particular number of annotations?
- Is the user location view, compass, or scale bar visible?
I am also getting this crash. When the map is adding annotations and a user touches the map it crashes.
This is the line that’s throwing the exception:
https://github.com/mapbox/mapbox-gl-native/blob/9e96aa192321b778f6e4f83ff73d363e0259c248/platform/ios/src/MGLMapView.mm#L2512
There’s an assertion right above it that helpfully includes the annotation tag that can’t be found:
https://github.com/mapbox/mapbox-gl-native/blob/9e96aa192321b778f6e4f83ff73d363e0259c248/platform/ios/src/MGLMapView.mm#L2511
However, assertions are disabled in release builds. Based on the analyses in #8655 and #12103, as well as the bandaids in #8513 and #8588, it’s likely that this is a race condition between the code that adds the annotations and the feature querying code, exacerbated by how UIAccessibility asks for the number of accessibility elements long before potentially accessing them, by which the number of annotations may change.
As recommended in #8655, it would be great if mbgl were to expose completion callbacks for things that affect the number of annotations on the map; in the callbacks, we could post UIAccessibilityLayoutChangedNotification
. Short of that, we may have to settle for failing gracefully with a preflight check before calling at()
on the unordered_map
. Any nonexistent tag would product a dummy accessibility element, and there would potentially be unreachable annotations.
/cc @julianrex
We are also having a problem here. For now we're simply hiding the map during UI testing, which isn't ideal. Is there any update on a solution?
I'm seeing this crash on my project as well. Are there any indications that a fix is in the works? Have any of the bandaids mentioned above worked for anyone?
@CfiedlerIII this is currently under investigation. Are you seeing this just during testing or in production too?
@CfiedlerIII this is currently under investigation. Are you seeing this just during testing or in production too?
We're seeing this in testing and also production if the VoiceOver accessibility setting is activated.
For anyone still experiencing this issue. For my purposes, we don't have any need for the accessibility elements within the MGLMapView. Therefore, we dropped in the line self.mapView.accessibilityElementsHidden = true
to turn off accessibility for the MGLMapView. After making this change, cpu utilization with voice over enabled and memory usage were dropped significantly. Also, the UI Test suite was able to run again without issue.
Sorry, forgot about this thread, since the hack solved the problem for us. In case the information is still needed:
- Do you reproduce this issue when the map is viewing a particular region, a particular style, or with a particular number of annotations?
No, not really IIRC. I think the problem is with iOS UITests requesting accessibility information while it's not available yet.
- Is the user location view, compass, or scale bar visible?
The user location might be visible and in any case should be on the map, but (again IIRC) it wasn't about the user location rather markers or polylines.
However, assertions are disabled in release builds.
- which means the app won't crash immediately but all the logic after the assertion is based on the idea that the assertion criteria is fulfilled.
So generally speaking it's an undefined behaviour.
Also getting this crash, and preventing it by turning off accessibility :(
I had the same problem. I tried everything mentioned anywhere, but it didn't work. Here is a genuine solution.
You need to add xml file in android>app>res and then sync it.
consider watching this video, to know how to add xml file in your project - (but remember to just stop at the step where you have created the { provider_paths.xml } file, DO NOT FOLLOW THE WHOLE VIDEO. (only till 1:20)
https://www.youtube.com/watch?v=oKByKkrv_5Y&t=68s
hope it helps.
We have the same problem. (iOS Mapbox v6.0.0)
Not only for testing but also for normal builds.