592e5c144a
This CL introduces an `IsolateData::asset_base_path` which contains the fully resolved base path used for assets which are loaded with a relative path. (Resolving both PATHEXT and symlinks.) The asset base path is now only resolved once, instead of on every relative asset load. The asset base path is now eagerly resolved. To prevent existing error messages for files not existing changing in `dartdev` and `Isolate.spawnUri`, files not existing errors are ignored. To prevent `tests/standalone/io/named_pipe_script_test.dart` from failing, failing to canonicalize a file path is treated as no asset base path rather than reporting a failure. TEST=pkg/dartdev/test/native_assets/*.dart Bug: https://github.com/dart-lang/sdk/issues/60946 Change-Id: I79a9144d220dfb3e54311725d41f8f91c88db3a1 Cq-Include-Trybots: luci.dart.try:pkg-linux-debug-try,pkg-linux-release-arm64-try,pkg-linux-release-try,pkg-mac-release-try,pkg-mac-release-arm64-try,pkg-win-release-arm64-try,pkg-win-release-try,vm-aot-dyn-linux-debug-x64-try,vm-aot-android-release-arm64c-try,vm-aot-linux-debug-x64-try,vm-aot-mac-debug-arm64-try,vm-aot-win-debug-arm64-try,vm-aot-optimization-level-linux-release-x64-try,vm-aot-obfuscate-linux-release-x64-try,vm-msan-linux-release-x64-try,vm-asan-linux-release-x64-try,vm-linux-release-x64-try,vm-linux-debug-x64-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/435421 Commit-Queue: Daco Harkes <dacoharkes@google.com> Reviewed-by: Martin Kustermann <kustermann@google.com>
228 lines
7.2 KiB
C++
228 lines
7.2 KiB
C++
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
#include "include/bin/native_assets_api.h"
|
|
|
|
#include <cstring>
|
|
|
|
#include "platform/globals.h"
|
|
#include "platform/utils.h"
|
|
|
|
#if defined(DART_HOST_OS_WINDOWS)
|
|
#include <Psapi.h>
|
|
#include <Windows.h>
|
|
#include <combaseapi.h>
|
|
#include <stdio.h>
|
|
#include <tchar.h>
|
|
#endif
|
|
#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_MACOS) || \
|
|
defined(DART_HOST_OS_ANDROID) || defined(DART_HOST_OS_FUCHSIA)
|
|
#include <dlfcn.h>
|
|
#endif
|
|
|
|
#include "bin/uri.h"
|
|
|
|
namespace dart {
|
|
namespace bin {
|
|
|
|
#define SET_ERROR_MSG(error_msg, format, ...) \
|
|
intptr_t len = snprintf(nullptr, 0, format, __VA_ARGS__); \
|
|
char* msg = reinterpret_cast<char*>(malloc(len + 1)); \
|
|
snprintf(msg, len + 1, format, __VA_ARGS__); \
|
|
*error_msg = msg
|
|
|
|
#if defined(DART_TARGET_OS_WINDOWS)
|
|
// Replaces back slashes with forward slashes in place.
|
|
static void ReplaceBackSlashes(char* cstr) {
|
|
const intptr_t length = strlen(cstr);
|
|
for (int i = 0; i < length; i++) {
|
|
cstr[i] = cstr[i] == '\\' ? '/' : cstr[i];
|
|
}
|
|
}
|
|
|
|
// Replaces forward slashes with back slashes in place.
|
|
static void ReplaceForwardSlashes(char* cstr) {
|
|
const intptr_t length = strlen(cstr);
|
|
for (int i = 0; i < length; i++) {
|
|
cstr[i] = cstr[i] == '/' ? '\\' : cstr[i];
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// If an error occurs populates |error| (if provided) with an error message
|
|
// (caller must free this message when it is no longer needed).
|
|
static void* LoadDynamicLibrary(const char* library_file,
|
|
bool search_dll_load_dir = false,
|
|
char** error = nullptr) {
|
|
char* utils_error = nullptr;
|
|
void* handle = Utils::LoadDynamicLibrary(library_file, search_dll_load_dir,
|
|
&utils_error);
|
|
if (utils_error != nullptr) {
|
|
if (error != nullptr) {
|
|
SET_ERROR_MSG(error, "Failed to load dynamic library '%s': %s",
|
|
library_file != nullptr ? library_file : "<process>",
|
|
utils_error);
|
|
}
|
|
free(utils_error);
|
|
}
|
|
return handle;
|
|
}
|
|
|
|
#if defined(DART_HOST_OS_WINDOWS)
|
|
// On windows, nullptr signals trying a lookup in all loaded modules.
|
|
const nullptr_t kWindowsDynamicLibraryProcessPtr = nullptr;
|
|
#endif
|
|
|
|
static void WrapError(const char* path, char** error) {
|
|
if (*error != nullptr) {
|
|
char* inner_error = *error;
|
|
SET_ERROR_MSG(error, "Failed to load dynamic library '%s': %s", path,
|
|
inner_error);
|
|
free(inner_error);
|
|
}
|
|
}
|
|
|
|
static void WrapErrorRelative(const char* path,
|
|
const char* base_path,
|
|
char** error) {
|
|
if (*error != nullptr) {
|
|
char* inner_error = *error;
|
|
SET_ERROR_MSG(error,
|
|
"Failed to load dynamic library '%s' relative to '%s': %s",
|
|
path, base_path, inner_error);
|
|
free(inner_error);
|
|
}
|
|
}
|
|
|
|
void* NativeAssets::DlopenAbsolute(const char* path, char** error) {
|
|
// If we'd want to be strict, it should not take into account include paths.
|
|
void* handle =
|
|
LoadDynamicLibrary(path, /* search_dll_load_dir= */ true, error);
|
|
WrapError(path, error);
|
|
return handle;
|
|
}
|
|
|
|
void* NativeAssets::DlopenRelative(const char* path,
|
|
const char* base_path,
|
|
char** error) {
|
|
if (base_path == nullptr) {
|
|
SET_ERROR_MSG(
|
|
error, "Failed to resolve relative path '%s', no base path provided.",
|
|
path);
|
|
return nullptr;
|
|
}
|
|
void* handle = nullptr;
|
|
|
|
#if defined(DART_TARGET_OS_WINDOWS)
|
|
char* path_copy = strdup(path);
|
|
char* base_path_copy = strdup(base_path);
|
|
ReplaceBackSlashes(path_copy);
|
|
ReplaceBackSlashes(base_path_copy);
|
|
auto target_path = ResolvePath(path_copy, base_path_copy);
|
|
free(path_copy);
|
|
free(base_path_copy);
|
|
#else
|
|
auto target_path = ResolvePath(path, base_path);
|
|
#endif
|
|
if (!target_path) {
|
|
SET_ERROR_MSG(error, "Failed to resolve '%s' relative to '%s'.", path,
|
|
base_path);
|
|
} else {
|
|
#if defined(DART_TARGET_OS_WINDOWS)
|
|
ReplaceForwardSlashes(target_path.get());
|
|
#endif
|
|
handle = LoadDynamicLibrary(target_path.get(),
|
|
/* search_dll_load_dir= */ true, error);
|
|
}
|
|
WrapErrorRelative(path, base_path, error);
|
|
return handle;
|
|
}
|
|
|
|
void* NativeAssets::DlopenSystem(const char* path, char** error) {
|
|
// Should take into account LD_PATH etc.
|
|
void* handle =
|
|
LoadDynamicLibrary(path, /* search_dll_load_dir= */ false, error);
|
|
WrapError(path, error);
|
|
return handle;
|
|
}
|
|
|
|
void* NativeAssets::DlopenProcess(char** error) {
|
|
#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_MACOS) || \
|
|
defined(DART_HOST_OS_ANDROID) || defined(DART_HOST_OS_FUCHSIA)
|
|
return RTLD_DEFAULT;
|
|
#else
|
|
return kWindowsDynamicLibraryProcessPtr;
|
|
#endif
|
|
}
|
|
|
|
void* NativeAssets::DlopenExecutable(char** error) {
|
|
return LoadDynamicLibrary(nullptr, /* search_dll_load_dir= */ false, error);
|
|
}
|
|
|
|
#if defined(DART_HOST_OS_WINDOWS)
|
|
void* co_task_mem_allocated = nullptr;
|
|
|
|
// If an error occurs populates |error| with an error message
|
|
// (caller must free this message when it is no longer needed).
|
|
void* LookupSymbolInProcess(const char* symbol, char** error) {
|
|
// Force loading ole32.dll.
|
|
if (co_task_mem_allocated == nullptr) {
|
|
co_task_mem_allocated = CoTaskMemAlloc(sizeof(intptr_t));
|
|
CoTaskMemFree(co_task_mem_allocated);
|
|
}
|
|
|
|
HANDLE current_process =
|
|
OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE,
|
|
GetCurrentProcessId());
|
|
if (current_process == nullptr) {
|
|
SET_ERROR_MSG(error, "Failed to open current process.");
|
|
return nullptr;
|
|
}
|
|
|
|
HMODULE modules[1024];
|
|
DWORD cb_needed;
|
|
if (EnumProcessModules(current_process, modules, sizeof(modules),
|
|
&cb_needed) != 0) {
|
|
for (intptr_t i = 0; i < (cb_needed / sizeof(HMODULE)); i++) {
|
|
if (auto result =
|
|
reinterpret_cast<void*>(GetProcAddress(modules[i], symbol))) {
|
|
CloseHandle(current_process);
|
|
return result;
|
|
}
|
|
}
|
|
}
|
|
CloseHandle(current_process);
|
|
|
|
SET_ERROR_MSG(
|
|
error, "None of the loaded modules contained the requested symbol '%s'.",
|
|
symbol);
|
|
return nullptr;
|
|
}
|
|
#endif
|
|
|
|
// If an error occurs populates |error| with an error message
|
|
// (caller must free this message when it is no longer needed).
|
|
static void* ResolveSymbol(void* handle, const char* symbol, char** error) {
|
|
#if defined(DART_HOST_OS_WINDOWS)
|
|
if (handle == kWindowsDynamicLibraryProcessPtr) {
|
|
return LookupSymbolInProcess(symbol, error);
|
|
}
|
|
#endif
|
|
return Utils::ResolveSymbolInDynamicLibrary(handle, symbol, error);
|
|
}
|
|
|
|
void* NativeAssets::Dlsym(void* handle, const char* symbol, char** error) {
|
|
void* const result = ResolveSymbol(handle, symbol, error);
|
|
if (*error != nullptr) {
|
|
char* inner_error = *error;
|
|
SET_ERROR_MSG(error, "Failed to lookup symbol '%s': %s", symbol,
|
|
inner_error);
|
|
free(inner_error);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
} // namespace bin
|
|
} // namespace dart
|