Skip to content

[vm/ffi] Native assets dylib handles should be cached #55519

@dcharkes

Description

@dcharkes

static void* FfiResolveAsset(Thread* const thread,
const Array& asset_location,
const String& symbol,
char** error) {
Zone* const zone = thread->zone();
const auto& asset_type =
String::Cast(Object::Handle(zone, asset_location.At(0)));
String& path = String::Handle(zone);
if (asset_type.Equals(Symbols::absolute()) ||
asset_type.Equals(Symbols::relative()) ||
asset_type.Equals(Symbols::system())) {
path = String::RawCast(asset_location.At(1));
}
void* handle = nullptr;
if (asset_type.Equals(Symbols::absolute())) {
handle = LoadDynamicLibrary(path.ToCString(), error);
} else if (asset_type.Equals(Symbols::relative())) {
const auto& platform_script_uri = String::Handle(
zone,
String::NewFormatted(
"%s%s", file_schema,
String::Handle(zone, GetPlatformScriptPath(thread)).ToCString()));
const char* target_uri = nullptr;
char* path_cstr = path.ToMallocCString();
#if defined(DART_TARGET_OS_WINDOWS)
ReplaceBackSlashes(path_cstr);
#endif
const bool resolved =
ResolveUri(path_cstr, platform_script_uri.ToCString(), &target_uri);
free(path_cstr);
if (!resolved) {
*error = OS::SCreate(/*use malloc*/ nullptr,
"Failed to resolve '%s' relative to '%s'.",
path.ToCString(), platform_script_uri.ToCString());
} else {
const char* target_path = target_uri + file_schema_length;
handle = LoadDynamicLibrary(target_path, error);
}
} else if (asset_type.Equals(Symbols::system())) {
handle = LoadDynamicLibrary(path.ToCString(), error);
} else if (asset_type.Equals(Symbols::process())) {
#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_MACOS) || \
defined(DART_HOST_OS_ANDROID) || defined(DART_HOST_OS_FUCHSIA)
handle = RTLD_DEFAULT;
#else
handle = kWindowsDynamicLibraryProcessPtr;
#endif
} else if (asset_type.Equals(Symbols::executable())) {
handle = LoadDynamicLibrary(nullptr, error);
} else {
UNREACHABLE();
}
if (*error != nullptr) {
char* inner_error = *error;
*error = OS::SCreate(/*use malloc*/ nullptr,
"Failed to load dynamic library '%s': %s",
path.ToCString(), inner_error);
free(inner_error);
} else {
void* const result = ResolveSymbol(handle, symbol.ToCString(), error);
if (*error != nullptr) {
char* inner_error = *error;
*error = OS::SCreate(/*use malloc*/ nullptr,
"Failed to lookup symbol '%s': %s",
symbol.ToCString(), inner_error);
free(inner_error);
} else {
return result;
}
}
ASSERT(*error != nullptr);
return nullptr;
}

Currently, @Natives resolve their asset and symbol in one step. If the asset is a dynamic library, the handle to this library is not cached, so dlopen is called again.

In the implementation of dlopen this seems to not be a problem, it returns the same handle and increases the ref count.

However, this will pose a problem once we would like to dlclose on isolate group shutdown.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-vmUse area-vm for VM related issues, including code coverage, and the AOT and JIT backends.library-ffi

    Type

    No type

    Projects

    Status

    No status

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions