Skip to content

[native_assets] Relative path resolution with symlinks #55410

@dcharkes

Description

@dcharkes

When native assets are looked up at runtime with a 'relative' path, the path is resolved against the platform script path:

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

However, if this platform script path contains symlinks, these are not resolved.

Consider the following directory structure.

* temp
  * foo
    * kernel-snapshot
    * my_asset.so
  * bar
    * baz -> ../foo/kernel-snapshot

Assuming the native assets mapping is ['relative', './my_asset.so'] for some asset, running dart /temp/bar/baz will try to look up the asset in /temp/bar/my_asset.so.

To fix this, we could resolve try to resolve symlinks in the platform script path before doing any relative path resolution.

The question is whether that is the right thing to do yes or no. Consider the following directory structure:

* temp
  * foo
    * kernel-snapshot
  * bar
    * baz -> ../foo/kernel-snapshot
    * my_asset.so

In this case, first resolving the symlinks would make the same resolution fail.

Given how common it is to symlink executables,

$ ls -lah /usr/bin/clang
lrwxrwxrwx 1 root root 24 Sep 13  2023 /usr/bin/clang -> ../lib/llvm-16/bin/clang

we should most likely not care about the latter case and resolve the symlinks eagerly.

Especially, in the case where we dart build exe, when we start building self-contained executable bundles.

To have consistency with executable bundles, and bundles with snapshots, we should do the same for snapshots.

Reproduction: https://dart-review.googlesource.com/c/sdk/+/361881/4

And for good measure, it should work on all operating systems:

  • Linux
  • MacOS
  • Windows

Metadata

Metadata

Assignees

Labels

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

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions