From 903fb0f1a6c339c44ee1b39eecbe913daaef61b4 Mon Sep 17 00:00:00 2001 From: Martin Bektchiev Date: Tue, 18 Feb 2020 16:53:32 +0200 Subject: [PATCH 1/2] tests: Fix ApiIterator test to ignore blacklisted symbol `getBlacklistedRusage_info_v0` shouldn't be called as its return type is excluded from metadata. --- tests/TestRunner/app/ApiTests.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/TestRunner/app/ApiTests.js b/tests/TestRunner/app/ApiTests.js index 86f669a70..beec98323 100644 --- a/tests/TestRunner/app/ApiTests.js +++ b/tests/TestRunner/app/ApiTests.js @@ -817,7 +817,8 @@ describe(module.id, function () { // according to SDK headers kCFAllocatorUseContext is of type id, but in fact it is not if (name == "kCFAllocatorUseContext" || name == "JSExport" || - name == "kSCNetworkInterfaceIPv4") { + name == "kSCNetworkInterfaceIPv4" || + name == "getBlacklistedRusage_info_v0") { return; } From 9796e380226a2566009f0da2448f816421bf9d8d Mon Sep 17 00:00:00 2001 From: Martin Bektchiev Date: Tue, 18 Feb 2020 16:57:33 +0200 Subject: [PATCH 2/2] fix(runtime): Unload frameworks in SymbolLoader::load * Use NSBundle to load bundles instead of `CFBundleLoadExecutable` * Do not attempt load a bundle more times than it is needed * Unload the bundle if it's state was previously unloaded. Sometimes framework bundles use resource bundles of the same name and keeping the framework loaded breaks them. OTH, loading and unloading a framework bundle is sufficient for its. executable code to be registered with the Objective-C runtime. --- src/NativeScript/SymbolLoader.mm | 39 ++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/src/NativeScript/SymbolLoader.mm b/src/NativeScript/SymbolLoader.mm index 3abf8b36c..3adcf0e6e 100644 --- a/src/NativeScript/SymbolLoader.mm +++ b/src/NativeScript/SymbolLoader.mm @@ -24,7 +24,8 @@ class CFBundleSymbolResolver : public SymbolResolver { public: CFBundleSymbolResolver(WTF::RetainPtr bundle) - : _bundle(bundle) { + : _bundle(bundle) + , _loaded(false) { } virtual void* loadFunctionSymbol(const char* symbolName) override { @@ -38,10 +39,39 @@ } virtual bool load() override { - CFErrorRef error = nullptr; - bool loaded = CFBundleLoadExecutableAndReturnError(this->_bundle.get(), &error); + if (this->_loaded) { + return true; + } + + // Use NSBundle for loading because of the following statement in the docs: + // For most of its methods, NSBundle simply calls the appropriate CFBundle routine to do its work, + // but loading code is different. Because CFBundle does not handle Objective-C symbols, NSBundle has + // to use a different mechanism for loading code. NSBundle interacts with the Objective-C runtime + // system to correctly load and register all Cocoa classes and other executable code in the bundle + // executable file. + // See https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/LoadingCode/Concepts/CFNSBundle.html + + NSURL* url = (__bridge NSURL*)CFBundleCopyBundleURL(this->_bundle.get()); + NSBundle* bundle = [NSBundle bundleWithURL:url]; + [url release]; + + bool wasLoaded = bundle.loaded; + NSError* error = nullptr; + bool loaded = [bundle loadAndReturnError:&error]; + + if (loaded) { + this->_loaded = true; + if (!wasLoaded) { + // Unload the bundle if it was not previously loaded. Sometimes framework bundles use + // resource bundles of the same name and keeping the framework loaded as a bundle + // breaks them. OTH, loading and unloading a framework bundle is sufficient for its + // executable code to be registered with the Objective-C runtime. + [bundle unload]; + } + } + if (error) { - dataLogF("%s\n", [[(NSError*)error localizedDescription] UTF8String]); + dataLogF("%s\n", [[error localizedDescription] UTF8String]); } return loaded; @@ -49,6 +79,7 @@ virtual bool load() override { private: WTF::RetainPtr _bundle; + bool _loaded; }; class DlSymbolResolver : public SymbolResolver {