Skip to content

Instantly share code, notes, and snippets.

@steipete
Last active December 8, 2022 15:47
Show Gist options
  • Star 16 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save steipete/e15b1fabffc7da7d49c92e3fbd06971a to your computer and use it in GitHub Desktop.
Save steipete/e15b1fabffc7da7d49c92e3fbd06971a to your computer and use it in GitHub Desktop.
Detect if a process runs under Rosetta 2 on Apple Silicon M1 or native. Works for macOS and iOS.
@objc(PSTArchitecture) class Architecture: NSObject {
/// Check if process runs under Rosetta 2.
///
/// Use to disable tests that use WebKit when running on Apple Silicon
/// FB8920323: Crash in WebKit memory allocator on Apple Silicon when iOS below 14
/// Crash is in JavaScriptCore: bmalloc::HeapConstants::HeapConstants(std::__1::lock_guard<bmalloc::Mutex> const&)
@objc class var isRosettaEmulated: Bool {
// Issue is specific to Simulator, not real devices
#if targetEnvironment(simulator)
return processIsTranslated() == EMULATED_EXECUTION
#else
return false
#endif
}
}
let NATIVE_EXECUTION = Int32(0)
let EMULATED_EXECUTION = Int32(1)
let UNKNOWN_EXECUTION = -Int32(1)
/// Test if the process runs natively or under Rosetta
/// https://developer.apple.com/forums/thread/652667?answerId=618217022&page=1#622923022
private func processIsTranslated() -> Int32 {
let key = "sysctl.proc_translated"
var ret = Int32(0)
var size: Int = 0
sysctlbyname(key, nil, &size, nil, 0)
let result = sysctlbyname(key, &ret, &size, nil, 0)
if result == -1 {
if errno == ENOENT {
return 0
}
return -1
}
return ret
}
@steipete
Copy link
Author

steipete commented Nov 29, 2020

This works around the WebKit/JavaScriptCore memory allocator issue mentioned in https://steipete.com/posts/apple-silicon-m1-a-developer-perspective/

Usage: (Our iOS PDF SDK offers a Reader Mode "liquid mode" to reformat PDF documents for small screens. Formatted text is extracted and displayed via WKWebView. This initializes WebKit and doesn't currently work on Apple Silicon when running on iOS < 14.)

final class ReaderViewTests: EarlGreyTestCase {

    func testReflowedDocumentContainsHTML() {
        guard !Architecture.isRosettaEmulated else { return }

		// Test Code
	}
}

A typical crash log looks like this:

Exception Type:        EXC_BREAKPOINT (SIGTRAP)
Exception Codes:       0x0000000000000002, 0x0000000000000000
Exception Note:        EXC_CORPSE_NOTIFY

Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0   <translation info unavailable>	0x0000000106cd964c ???
1   <translation info unavailable>	0x0000000106cd6330 ???
2   com.apple.JavaScriptCore      	0x0000000118d06a8d bmalloc::StaticPerProcess<bmalloc::HeapConstants>::getSlowCase() + 77
3   com.apple.JavaScriptCore      	0x0000000118d02dc8 bmalloc::Heap::Heap(bmalloc::HeapKind, std::__1::lock_guard<bmalloc::Mutex>&) + 56
4   com.apple.JavaScriptCore      	0x0000000118cff865 bmalloc::PerProcess<bmalloc::PerHeapKind<bmalloc::Heap> >::getSlowCase() + 181
5   com.apple.JavaScriptCore      	0x0000000118d000c5 bmalloc::PerHeapKindBase<bmalloc::Cache>::PerHeapKindBase<>() + 37
6   com.apple.JavaScriptCore      	0x0000000118cffae6 bmalloc::PerThread<bmalloc::PerHeapKind<bmalloc::Cache> >::getSlowCase() + 102
7   com.apple.JavaScriptCore      	0x0000000118cffba1 bmalloc::Cache::allocateSlowCaseNullCache(bmalloc::HeapKind, unsigned long) + 129
8   com.apple.JavaScriptCore      	0x0000000118cacf82 void std::__1::__call_once_proxy<std::__1::tuple<WTF::activeThreads()::$_3&&> >(void*) + 82
9   libc++.1.dylib                	0x000000010bed2c8a std::__1::__call_once(unsigned long volatile&, void*, void (*)(void*)) + 139
10  com.apple.JavaScriptCore      	0x0000000118cacf1c WTF::SignalHandlers::initialize() + 60
11  com.apple.JavaScriptCore      	0x0000000118cc4652 void std::__1::__call_once_proxy<std::__1::tuple<WTF::initializeThreading()::$_0&&> >(void*) + 34
12  libc++.1.dylib                	0x000000010bed2c8a std::__1::__call_once(unsigned long volatile&, void*, void (*)(void*)) + 139
13  com.apple.JavaScriptCore      	0x0000000118cc268c WTF::initializeThreading() + 60
14  com.apple.JavaScriptCore      	0x0000000119548dbc void std::__1::__call_once_proxy<std::__1::tuple<JSC::initializeThreading()::$_0&&> >(void*) + 12
15  libc++.1.dylib                	0x000000010bed2c8a std::__1::__call_once(unsigned long volatile&, void*, void (*)(void*)) + 139
16  com.apple.JavaScriptCore      	0x00000001195445fc JSC::initializeThreading() + 60
17  com.apple.WebKit              	0x000000013e245cfc WebKit::runInitializationCode(void*) + 19
18  libc++.1.dylib                	0x000000010bed2c8a std::__1::__call_once(unsigned long volatile&, void*, void (*)(void*)) + 139
19  com.apple.WebKit              	0x000000013e24284a WebKit::InitializeWebKit2() + 58

@mladenny
Copy link

You have a typo on row 19: UNKONWNUNKNOWN 😃

@steipete
Copy link
Author

@mladenny Thanks, fixed!

@faisalmemon
Copy link

@steipete I'd be most grateful if you could post the full crash dump, perhaps onto pastebin.com, because I am researching Rosetta 2 crashes with WebKit (and Safari) at the moment for my book (iOS Crash Dump Analysis).

@steipete
Copy link
Author

@Deco354
Copy link

Deco354 commented Jan 24, 2022

If you're implementing this yourself, don't omit the @objc and NSObject inheritance or you'll get a -1 result from processIsTranslated() every time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment