Skip to content

fix(runtime): Unload framework bundles in SymbolLoader::load #1257

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 19, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 35 additions & 4 deletions src/NativeScript/SymbolLoader.mm
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
class CFBundleSymbolResolver : public SymbolResolver {
public:
CFBundleSymbolResolver(WTF::RetainPtr<CFBundleRef> bundle)
: _bundle(bundle) {
: _bundle(bundle)
, _loaded(false) {
}

virtual void* loadFunctionSymbol(const char* symbolName) override {
Expand All @@ -38,17 +39,47 @@
}

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;
}

private:
WTF::RetainPtr<CFBundleRef> _bundle;
bool _loaded;
};

class DlSymbolResolver : public SymbolResolver {
Expand Down
3 changes: 2 additions & 1 deletion tests/TestRunner/app/ApiTests.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down