Skip to content

Commit 8d8faa7

Browse files
Clement Skaucommit-bot@chromium.org
Clement Skau
authored andcommitted
[SDK] Fixes loading appended snapshots when executed with PATH.
Loading of appended snapshots used to try read the executable itself via arg[0] which holds the "path" to the executable. However, when the executable is being invoked via PATH the "path" can be just the name of the executable with no actual path. This would cause the file reading to fail to find the file and therefore fail to read. This in turn caused standalone executables to fail to run when invoked via PATH. Bug: #38912 Change-Id: I08501661441db90ce6cff96a9337a5770ec3524d Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/121853 Commit-Queue: Clement Skau <[email protected]> Reviewed-by: Martin Kustermann <[email protected]>
1 parent c159993 commit 8d8faa7

9 files changed

+96
-28
lines changed

runtime/bin/file_android.cc

+7-3
Original file line numberDiff line numberDiff line change
@@ -597,11 +597,16 @@ intptr_t File::ReadLinkInto(const char* pathname,
597597
errno = ENOENT;
598598
return -1;
599599
}
600-
const size_t target_size =
600+
size_t target_size =
601601
TEMP_FAILURE_RETRY(readlink(pathname, result, result_size));
602602
if (target_size <= 0) {
603603
return -1;
604604
}
605+
// readlink returns non-zero terminated strings. Append.
606+
if (target_size < result_size) {
607+
result[target_size] = '\0';
608+
target_size++;
609+
}
605610
return target_size;
606611
}
607612

@@ -615,10 +620,9 @@ const char* File::ReadLink(const char* pathname) {
615620
if (target_size <= 0) {
616621
return NULL;
617622
}
618-
char* target_name = DartUtils::ScopedCString(target_size + 1);
623+
char* target_name = DartUtils::ScopedCString(target_size);
619624
ASSERT(target_name != NULL);
620625
memmove(target_name, target, target_size);
621-
target_name[target_size] = '\0';
622626
return target_name;
623627
}
624628

runtime/bin/file_linux.cc

+7-3
Original file line numberDiff line numberDiff line change
@@ -590,11 +590,16 @@ intptr_t File::ReadLinkInto(const char* pathname,
590590
errno = ENOENT;
591591
return -1;
592592
}
593-
const size_t target_size =
593+
size_t target_size =
594594
TEMP_FAILURE_RETRY(readlink(pathname, result, result_size));
595595
if (target_size <= 0) {
596596
return -1;
597597
}
598+
// readlink returns non-zero terminated strings. Append.
599+
if (target_size < result_size) {
600+
result[target_size] = '\0';
601+
target_size++;
602+
}
598603
return target_size;
599604
}
600605

@@ -608,10 +613,9 @@ const char* File::ReadLink(const char* pathname) {
608613
if (target_size <= 0) {
609614
return NULL;
610615
}
611-
char* target_name = DartUtils::ScopedCString(target_size + 1);
616+
char* target_name = DartUtils::ScopedCString(target_size);
612617
ASSERT(target_name != NULL);
613618
memmove(target_name, target, target_size);
614-
target_name[target_size] = '\0';
615619
return target_name;
616620
}
617621

runtime/bin/main.cc

+13-8
Original file line numberDiff line numberDiff line change
@@ -1083,16 +1083,21 @@ void main(int argc, char** argv) {
10831083
// snapshot, load and run that.
10841084
// Any arguments passed to such an executable are meant for the actual
10851085
// application so skip all Dart VM flag parsing.
1086-
app_snapshot = Snapshot::TryReadAppendedAppSnapshotElf(argv[0]);
1087-
if (app_snapshot != nullptr) {
1088-
script_name = argv[0];
10891086

1090-
// Store the executable name.
1091-
Platform::SetExecutableName(argv[0]);
1087+
const size_t kPathBufSize = PATH_MAX + 1;
1088+
char executable_path[kPathBufSize];
1089+
if (Platform::ResolveExecutablePathInto(executable_path, kPathBufSize) > 0) {
1090+
app_snapshot = Snapshot::TryReadAppendedAppSnapshotElf(executable_path);
1091+
if (app_snapshot != nullptr) {
1092+
script_name = argv[0];
1093+
1094+
// Store the executable name.
1095+
Platform::SetExecutableName(argv[0]);
10921096

1093-
// Parse out options to be passed to dart main.
1094-
for (int i = 1; i < argc; i++) {
1095-
dart_options.AddArgument(argv[i]);
1097+
// Parse out options to be passed to dart main.
1098+
for (int i = 1; i < argc; i++) {
1099+
dart_options.AddArgument(argv[i]);
1100+
}
10961101
}
10971102
}
10981103
#endif

runtime/bin/platform.h

+4-5
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,12 @@ class Platform {
6464

6565
static const char* ResolveExecutablePath();
6666

67-
// On Linux and Android this has the same effect as calling
68-
// ResolveExecutablePath except that Dart_ScopeAllocate is not called and that
69-
// the result goes into the given parameters.
70-
// On all other platforms it returns -1, i.e. doesn't work.
67+
// This has the same effect as calling ResolveExecutablePath except that
68+
// Dart_ScopeAllocate is not called and that the result goes into the given
69+
// parameters.
70+
// WARNING: On Fuchsia it returns -1, i.e. doesn't work.
7171
// Note that `result` should be pre-allocated with size `result_size`.
7272
// The return-value is the length read into `result` or -1 on failure.
73-
// The content of `result` is not guranteed to be null-terminated.
7473
static intptr_t ResolveExecutablePathInto(char* result, size_t result_size);
7574

7675
// Stores the executable name.

runtime/bin/platform_macos.cc

+12-1
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,18 @@ const char* Platform::ResolveExecutablePath() {
252252
}
253253

254254
intptr_t Platform::ResolveExecutablePathInto(char* result, size_t result_size) {
255-
return -1;
255+
// Get the required length of the buffer.
256+
uint32_t path_size = 0;
257+
if (_NSGetExecutablePath(nullptr, &path_size) == 0) {
258+
return -1;
259+
}
260+
if (path_size > result_size) {
261+
return -1;
262+
}
263+
if (_NSGetExecutablePath(result, &path_size) != 0) {
264+
return -1;
265+
}
266+
return path_size;
256267
}
257268

258269
void Platform::Exit(int exit_code) {

runtime/bin/platform_win.cc

+15-1
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ const char* Platform::ResolveExecutablePath() {
275275
// Ensure no last error before calling GetModuleFileNameW.
276276
SetLastError(ERROR_SUCCESS);
277277
// Get the required length of the buffer.
278-
int path_length = GetModuleFileNameW(NULL, tmp_buffer, kTmpBufferSize);
278+
GetModuleFileNameW(nullptr, tmp_buffer, kTmpBufferSize);
279279
if (GetLastError() != ERROR_SUCCESS) {
280280
return NULL;
281281
}
@@ -286,6 +286,20 @@ const char* Platform::ResolveExecutablePath() {
286286
}
287287

288288
intptr_t Platform::ResolveExecutablePathInto(char* result, size_t result_size) {
289+
// Ensure no last error before calling GetModuleFileNameW.
290+
SetLastError(ERROR_SUCCESS);
291+
const int kTmpBufferSize = 32768;
292+
wchar_t tmp_buffer[kTmpBufferSize];
293+
// Get the required length of the buffer.
294+
GetModuleFileNameW(nullptr, tmp_buffer, kTmpBufferSize);
295+
if (GetLastError() != ERROR_SUCCESS) {
296+
return -1;
297+
}
298+
WideToUtf8Scope wide_to_utf8_scope(tmp_buffer);
299+
if (wide_to_utf8_scope.length() <= result_size) {
300+
strncpy(result, wide_to_utf8_scope.utf8(), result_size);
301+
return wide_to_utf8_scope.length();
302+
}
289303
return -1;
290304
}
291305

runtime/platform/globals.h

+5
Original file line numberDiff line numberDiff line change
@@ -722,6 +722,11 @@ static inline void StoreUnaligned(T* ptr, T value) {
722722
#define STDERR_FILENO 2
723723
#endif
724724

725+
#ifndef PATH_MAX
726+
// Most platforms use PATH_MAX, but in Windows it's called MAX_PATH.
727+
#define PATH_MAX MAX_PATH
728+
#endif
729+
725730
} // namespace dart
726731

727732
#endif // RUNTIME_PLATFORM_GLOBALS_H_

runtime/tests/vm/dart/run_appended_aot_snapshot_test.dart

+29-4
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,10 @@ Future<void> main(List<String> args) async {
2222
'runtime', 'tests', 'vm', 'dart', 'run_appended_aot_snapshot_test.dart');
2323

2424
await withTempDir((String tmp) async {
25+
final String exeName = 'test.exe';
2526
final String dillPath = path.join(tmp, 'test.dill');
2627
final String aotPath = path.join(tmp, 'test.aot');
27-
final String exePath = path.join(tmp, 'test.exe');
28+
final String exePath = path.join(tmp, exeName);
2829

2930
{
3031
final result = await generateAotKernel(checkedInDartVM, genKernel,
@@ -51,8 +52,32 @@ Future<void> main(List<String> args) async {
5152
Expect.equals(result.stdout, '');
5253
}
5354

54-
final runResult =
55-
await runBinary('run appended aot snapshot', exePath, ['--child']);
56-
expectOutput('Hello, Appended AOT', runResult);
55+
{
56+
final runResult =
57+
await runBinary('run appended aot snapshot', exePath, ['--child']);
58+
expectOutput('Hello, Appended AOT', runResult);
59+
}
60+
61+
{
62+
// Test that it runs when invoked via PATH as well.
63+
Map<String, String> environment = {'PATH': tmp};
64+
final runResult = await runBinary(
65+
'run appended aot snapshot from PATH', exeName, ['--child'],
66+
environment: environment);
67+
expectOutput('Hello, Appended AOT', runResult);
68+
}
69+
70+
// Windows allows leaving out .exe. Make sure we can load that as well.
71+
if (Platform.isWindows) {
72+
final String exeNameWithoutExt =
73+
exeName.replaceFirst(new RegExp(r'.exe$'), '');
74+
Map<String, String> environment = {'PATH': tmp};
75+
final runResult = await runBinary(
76+
'run appended aot snapshot without extension',
77+
exeNameWithoutExt,
78+
['--child'],
79+
environment: environment);
80+
expectOutput('Hello, Appended AOT', runResult);
81+
}
5782
});
5883
}

runtime/tests/vm/dart/snapshot_test_helper.dart

+4-3
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,11 @@ Future<Result> runGenSnapshot(String prefix, List<String> arguments) {
7272
return runBinary(prefix, genSnapshot, arguments);
7373
}
7474

75-
Future<Result> runBinary(
76-
String prefix, String binary, List<String> arguments) async {
75+
Future<Result> runBinary(String prefix, String binary, List<String> arguments,
76+
{Map<String, String> environment}) async {
7777
print("+ $binary " + arguments.join(" "));
78-
final processResult = await Process.run(binary, arguments);
78+
final processResult =
79+
await Process.run(binary, arguments, environment: environment);
7980
final result =
8081
new Result('[$prefix] ${binary} ${arguments.join(' ')}', processResult);
8182

0 commit comments

Comments
 (0)