diff --git a/runtime/bin/io_natives.cc b/runtime/bin/io_natives.cc index cbe0c837e1c5..8bbd2cd58602 100644 --- a/runtime/bin/io_natives.cc +++ b/runtime/bin/io_natives.cc @@ -40,6 +40,7 @@ namespace bin { V(Platform_PathSeparator, 0) \ V(Platform_LocalHostname, 0) \ V(Platform_ExecutableName, 0) \ + V(Platform_ResolvedExecutableName, 0) \ V(Platform_Environment, 0) \ V(Platform_ExecutableArguments, 0) \ V(Platform_PackageRoot, 0) \ diff --git a/runtime/bin/platform.cc b/runtime/bin/platform.cc index 2f55f9d695ce..0ed2bd364fd1 100644 --- a/runtime/bin/platform.cc +++ b/runtime/bin/platform.cc @@ -13,7 +13,7 @@ namespace dart { namespace bin { const char* Platform::executable_name_ = NULL; -bool Platform::executable_name_resolved_ = false; +const char* Platform::resolved_executable_name_ = NULL; const char* Platform::package_root_ = NULL; int Platform::script_index_ = 1; char** Platform::argv_ = NULL; @@ -51,6 +51,16 @@ void FUNCTION_NAME(Platform_ExecutableName)(Dart_NativeArguments args) { } +void FUNCTION_NAME(Platform_ResolvedExecutableName)(Dart_NativeArguments args) { + if (Platform::GetResolvedExecutableName() != NULL) { + Dart_SetReturnValue( + args, Dart_NewStringFromCString(Platform::GetResolvedExecutableName())); + } else { + Dart_SetReturnValue(args, Dart_Null()); + } +} + + void FUNCTION_NAME(Platform_ExecutableArguments)(Dart_NativeArguments args) { int end = Platform::GetScriptIndex(); char** argv = Platform::GetArgv(); diff --git a/runtime/bin/platform.h b/runtime/bin/platform.h index 6b81539da104..3d3c0f3135c8 100644 --- a/runtime/bin/platform.h +++ b/runtime/bin/platform.h @@ -46,15 +46,14 @@ class Platform { executable_name_ = executable_name; } static const char* GetExecutableName() { - if (!executable_name_resolved_) { + return executable_name_; + } + static const char* GetResolvedExecutableName() { + if (resolved_executable_name_ == NULL) { // Try to resolve the executable path using platform specific APIs. - char* path = Platform::ResolveExecutablePath(); - if (path != NULL) { - executable_name_ = path; - } - executable_name_resolved_ = true; + resolved_executable_name_ = Platform::ResolveExecutablePath(); } - return executable_name_; + return resolved_executable_name_; } // Stores and gets the package root. @@ -80,8 +79,8 @@ class Platform { private: // The path to the executable. static const char* executable_name_; - // State to indicate whether the executable name has been resolved. - static bool executable_name_resolved_; + // The path to the resolved executable. + static const char* resolved_executable_name_; static const char* package_root_; static int script_index_; diff --git a/runtime/bin/platform_macos.cc b/runtime/bin/platform_macos.cc index 702bf017806e..351a829db717 100644 --- a/runtime/bin/platform_macos.cc +++ b/runtime/bin/platform_macos.cc @@ -7,6 +7,7 @@ #include +#include "bin/file.h" #include "bin/platform.h" #include // NOLINT @@ -91,7 +92,10 @@ char* Platform::ResolveExecutablePath() { free(path); return NULL; } - return path; + // Return the canonical path as the returned path might contain symlinks. + char* canon_path = File::GetCanonicalPath(path); + free(path); + return canon_path; } } // namespace bin diff --git a/runtime/bin/platform_patch.dart b/runtime/bin/platform_patch.dart index fe1e90cec687..c917b54f77c2 100644 --- a/runtime/bin/platform_patch.dart +++ b/runtime/bin/platform_patch.dart @@ -10,6 +10,8 @@ patch class _Platform { native "Platform_OperatingSystem"; /* patch */ static _localHostname() native "Platform_LocalHostname"; /* patch */ static _executable() native "Platform_ExecutableName"; + /* patch */ static _resolvedExecutable() + native "Platform_ResolvedExecutableName"; /* patch */ static _environment() native "Platform_Environment"; /* patch */ static List _executableArguments() native "Platform_ExecutableArguments"; diff --git a/runtime/bin/platform_win.cc b/runtime/bin/platform_win.cc index afa924bab82e..d109c82dda07 100644 --- a/runtime/bin/platform_win.cc +++ b/runtime/bin/platform_win.cc @@ -5,6 +5,7 @@ #include "platform/globals.h" #if defined(TARGET_OS_WINDOWS) +#include "bin/file.h" #include "bin/platform.h" #include "bin/log.h" #include "bin/socket.h" @@ -97,7 +98,10 @@ char* Platform::ResolveExecutablePath() { } char* path = StringUtils::WideToUtf8(tmp_buffer); free(tmp_buffer); - return path; + // Return the canonical path as the returned path might contain symlinks. + char* canon_path = File::GetCanonicalPath(path); + free(path); + return canon_path; } } // namespace bin diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc index bc36704424b3..15ef1ad3e26d 100644 --- a/runtime/vm/dart_api_impl.cc +++ b/runtime/vm/dart_api_impl.cc @@ -3182,10 +3182,20 @@ DART_EXPORT Dart_TypedData_Type Dart_GetTypeOfExternalTypedData( Dart_Handle object) { TRACE_API_CALL(CURRENT_FUNC); intptr_t class_id = Api::ClassId(object); - if (RawObject::IsExternalTypedDataClassId(class_id) || - RawObject::IsTypedDataViewClassId(class_id)) { + if (RawObject::IsExternalTypedDataClassId(class_id)) { return GetType(class_id); } + if (RawObject::IsTypedDataViewClassId(class_id)) { + // Check if data object of the view is external. + Isolate* isolate = Isolate::Current(); + const Instance& view_obj = Api::UnwrapInstanceHandle(isolate, object); + ASSERT(!view_obj.IsNull()); + const Instance& data_obj = + Instance::Handle(isolate, TypedDataView::Data(view_obj)); + if (ExternalTypedData::IsExternalTypedData(data_obj)) { + return GetType(class_id); + } + } return Dart_TypedData_kInvalid; } diff --git a/sdk/lib/_internal/compiler/js_lib/io_patch.dart b/sdk/lib/_internal/compiler/js_lib/io_patch.dart index 8fbc6a7e9385..792b74ddc416 100644 --- a/sdk/lib/_internal/compiler/js_lib/io_patch.dart +++ b/sdk/lib/_internal/compiler/js_lib/io_patch.dart @@ -221,6 +221,10 @@ class _Platform { throw new UnsupportedError("Platform._executable"); } @patch + static _resolvedExecutable() { + throw new UnsupportedError("Platform._resolvedExecutable"); + } + @patch static List _executableArguments() { throw new UnsupportedError("Platform._executableArguments"); } diff --git a/sdk/lib/io/platform.dart b/sdk/lib/io/platform.dart index 6b86095d0615..9ad7b5668a70 100644 --- a/sdk/lib/io/platform.dart +++ b/sdk/lib/io/platform.dart @@ -131,13 +131,24 @@ class Platform { * Returns the path of the executable used to run the script in this * isolate. * - * If supported by the platform the returned path will be absolute. + * The path returned is the literal path used to run the script. This + * path might be relative or just be a name from which the executable + * was found by searching the `PATH`. * - * If the execution environment does not support [executable] an empty - * string is returned. + * To get the absolute path to the resolved executable use + * [resolvedExecutable]. */ static String get executable => _Platform.executable; + /** + * Returns the path of the executable used to run the script in this + * isolate after it has been resolved by the OS. + * + * This is the absolute path, with all symlinks resolved, to the + * executable used to run the script. + */ + static String get resolvedExecutable => _Platform.resolvedExecutable; + /** * Returns the absolute URI of the script being run in this * isolate. diff --git a/sdk/lib/io/platform_impl.dart b/sdk/lib/io/platform_impl.dart index 3883957ef0d8..6380e0d7c92f 100644 --- a/sdk/lib/io/platform_impl.dart +++ b/sdk/lib/io/platform_impl.dart @@ -10,6 +10,7 @@ class _Platform { external static String _operatingSystem(); external static _localHostname(); external static _executable(); + external static _resolvedExecutable(); /** * Retrieve the entries of the process environment. * @@ -31,6 +32,7 @@ class _Platform { external static String _version(); static String executable = _executable(); + static String resolvedExecutable = _resolvedExecutable(); static String packageRoot = _packageRoot(); // Cache the OS environemnt. This can be an OSError instance if diff --git a/tests/standalone/io/platform_executable_test.dart b/tests/standalone/io/platform_resolved_executable_test.dart similarity index 78% rename from tests/standalone/io/platform_executable_test.dart rename to tests/standalone/io/platform_resolved_executable_test.dart index 1b6bce377de3..b5ae47c1f341 100644 --- a/tests/standalone/io/platform_executable_test.dart +++ b/tests/standalone/io/platform_resolved_executable_test.dart @@ -35,7 +35,7 @@ void verify(String exePath, {String altPath}) { } var result = processResult.stdout.trim(); - expectEquals(Platform.executable, result); + expectEquals(Platform.resolvedExecutable, result); } void testDartExecShouldNotBeInCurrentDir() { @@ -60,23 +60,20 @@ void testShouldFailOutsidePath() { } void testShouldSucceedWithSourcePlatformExecutable() { - //print('*** Running normally'); - verify(Platform.executable); + verify(Platform.resolvedExecutable); } void testExeSymLinked(Directory dir) { var dirUri = new Uri.directory(dir.path); var link = new Link.fromUri(dirUri.resolve('dart_exe_link')); - link.createSync(Platform.executable); - //print('*** Creating a sym-link to the executable'); + link.createSync(Platform.resolvedExecutable); verify(link.path); } void testPathToDirWithExeSymLinked(Directory dir) { var dirUri = new Uri.directory(dir.path); var link = new Link.fromUri(dirUri.resolve('dart_exe_link')); - link.createSync(Platform.executable); - //print('*** Path to a directory that contains a sym-link to dart bin'); + link.createSync(Platform.resolvedExecutable); verify('dart_exe_link', altPath: dir.path); } @@ -87,14 +84,13 @@ void testExeDirSymLinked(Directory dir) { var linkDirUri = dirUri.resolve('dart_bin_dir_link'); var link = new Link.fromUri(linkDirUri); - var exeFile = new File(Platform.executable); + var exeFile = new File(Platform.resolvedExecutable); link.createSync(exeFile.parent.path); var linkedBin = new Uri.directory(linkDirUri.toFilePath()).resolve(platformExeName); - //print('*** Running in a sym-linked directory'); verify(linkedBin.toFilePath()); } @@ -104,19 +100,17 @@ void testPathPointsToSymLinkedSDKPath(Directory dir) { var linkDirUri = dirUri.resolve('dart_bin_dir_link'); var link = new Link.fromUri(linkDirUri); - var exeFile = new File(Platform.executable); + var exeFile = new File(Platform.resolvedExecutable); link.createSync(exeFile.parent.path); - //print('*** Path points to a sym-linked SDK dir'); verify(platformExeName, altPath: link.path); } void testPathToSDKDir() { - var exeFile = new File(Platform.executable); + var exeFile = new File(Platform.resolvedExecutable); var binDirPath = exeFile.parent.path; - //print('*** Running with PATH env set to environment - fixed in 16994 - thanks!'); verify(platformExeName, altPath: binDirPath); } @@ -130,24 +124,34 @@ void withTempDir(void test(Directory dir)) { } String get platformExeName { - var raw = new Uri.file(Platform.executable); + var raw = new Uri.file(Platform.resolvedExecutable); return raw.pathSegments.last; } String get scriptPath => Platform.script.toFilePath(); void main() { + // The same script is used for both running the tests and as for starting + // child verifying the value of Platform.resolvedExecutable. If the + // environment variable _SCRIPT_KEY is set this is a child process which + // should print the value of Platform.resolvedExecutable. if (Platform.environment.containsKey(_SCRIPT_KEY)) { - print(Platform.executable); + print(Platform.resolvedExecutable); return; } testDartExecShouldNotBeInCurrentDir(); testShouldSucceedWithSourcePlatformExecutable(); /// 00: ok - withTempDir(testExeSymLinked); /// 01: ok + // dart:io does not support linking to files in Windows. + if (!Platform.isWindows) { + withTempDir(testExeSymLinked); /// 01: ok + } withTempDir(testExeDirSymLinked); /// 02: ok testPathToSDKDir(); /// 03: ok withTempDir(testPathPointsToSymLinkedSDKPath); /// 04: ok - withTempDir(testPathToDirWithExeSymLinked); /// 05: ok + // dart:io does not support linking to files in Windows. + if (!Platform.isWindows) { + withTempDir(testPathToDirWithExeSymLinked); /// 05: ok + } testShouldFailOutsidePath(); /// 06: ok } diff --git a/tests/standalone/io/platform_test.dart b/tests/standalone/io/platform_test.dart index 269a4871a4e3..f07475061da1 100644 --- a/tests/standalone/io/platform_test.dart +++ b/tests/standalone/io/platform_test.dart @@ -24,15 +24,21 @@ test() { Expect.isTrue(hostname is String && hostname != ""); var environment = Platform.environment; Expect.isTrue(environment is Map); - Expect.isTrue(Platform.executable.contains('dart')); if (!Platform.isWindows) { - Expect.isTrue(Platform.executable.startsWith('/')); + Expect.isTrue(Platform.executable.endsWith('dart')); + Expect.isTrue(Platform.resolvedExecutable.endsWith('dart')); + } else { + Expect.isTrue(Platform.executable.endsWith('dart.exe')); + Expect.isTrue(Platform.resolvedExecutable.endsWith('dart.exe')); + } + if (!Platform.isWindows) { + Expect.isTrue(Platform.resolvedExecutable.startsWith('/')); } else { // This assumes that tests (both locally and on the bots) are // running off a location referred to by a drive letter. If a UNC // location is used or long names ("\\?\" prefix) is used this // needs to be fixed. - Expect.equals(Platform.executable.substring(1, 3), ':\\'); + Expect.equals(Platform.resolvedExecutable.substring(1, 3), ':\\'); } // Move directory to be sure script is correct. var oldDir = Directory.current; diff --git a/tests/standalone/standalone.status b/tests/standalone/standalone.status index f3868b775e11..68f560ad635e 100644 --- a/tests/standalone/standalone.status +++ b/tests/standalone/standalone.status @@ -17,15 +17,6 @@ javascript_compatibility_errors_test/none: Fail, OK # Not possible to exclude o package/package_isolate_test: Fail # Issue 12474 io/observatory_test: Fail -[ $runtime == vm && ($system == macos || $system == windows) ] -io/platform_executable_test/01: RuntimeError # Issue 16994 -io/platform_executable_test/02: RuntimeError # Issue 16994 -io/platform_executable_test/04: RuntimeError # Issue 16994 -io/platform_executable_test/05: RuntimeError # Issue 16994 - -[ $runtime == vm && $system == windows ] -io/platform_executable_test/06: RuntimeError # NEEDS TRIAGE (kevmoo) - [ $runtime == vm && $checked ] # These tests have type errors on purpose. io/process_invalid_arguments_test: Fail, OK @@ -167,6 +158,7 @@ package/package_test: CompileTimeError [ $system == windows ] io/skipping_dart2js_compilations_test: Fail # Issue 19551. verbose_gc_to_bmu_test: Skip +io/platform_resolved_executable_test/06: RuntimeError # Issue 23641 [ $arch != ia32 && $arch != x64 && $arch != simarm && $arch != simarmv5te && $mode == debug ] verified_mem_test: Skip # Not yet implemented. @@ -219,10 +211,10 @@ io/issue_22637_test: Crash # cannot handle async/sync*/async* functions io/link_test: Crash # Instance of 'TypeOperator': type check unimplemented for _Nullary. io/link_uri_test: Crash # Instance of 'TypeOperator': type check unimplemented for _Nullary. io/observatory_test: Crash # Instance of 'TypeOperator': type check unimplemented for _Nullary. -io/platform_executable_test/01: Crash # (try {test(tempDir);}finally {tempDir.deleteSync(recursive:true);}): try/finally -io/platform_executable_test/02: Crash # (try {test(tempDir);}finally {tempDir.deleteSync(recursive:true);}): try/finally -io/platform_executable_test/04: Crash # (try {test(tempDir);}finally {tempDir.deleteSync(recursive:true);}): try/finally -io/platform_executable_test/05: Crash # (try {test(tempDir);}finally {tempDir.deleteSync(recursive:true);}): try/finally +io/platform_resolved_executable_test/01: Crash # (try {test(tempDir);}finally {tempDir.deleteSync(recursive:true);}): try/finally +io/platform_resolved_executable_test/02: Crash # (try {test(tempDir);}finally {tempDir.deleteSync(recursive:true);}): try/finally +io/platform_resolved_executable_test/04: Crash # (try {test(tempDir);}finally {tempDir.deleteSync(recursive:true);}): try/finally +io/platform_resolved_executable_test/05: Crash # (try {test(tempDir);}finally {tempDir.deleteSync(recursive:true);}): try/finally io/platform_test: Crash # Instance of 'TypeOperator': type check unimplemented for _Nullary. io/process_invalid_arguments_test: Crash # Instance of 'TypeOperator': type check unimplemented for _Nullary. io/raw_datagram_socket_test: Crash # Unhandled node diff --git a/tools/VERSION b/tools/VERSION index 983e8a94e552..09befe88f9f0 100644 --- a/tools/VERSION +++ b/tools/VERSION @@ -28,4 +28,4 @@ MAJOR 1 MINOR 11 PATCH 0 PRERELEASE 5 -PRERELEASE_PATCH 2 +PRERELEASE_PATCH 3