Files
sdk/runtime/bin/platform_macos.cc
T
Clement Skau 8d8faa7dea [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: https://github.com/dart-lang/sdk/issues/38912
Change-Id: I08501661441db90ce6cff96a9337a5770ec3524d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/121853
Commit-Queue: Clement Skau <cskau@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
2019-10-18 10:30:48 +00:00

284 lines
7.9 KiB
C++

// Copyright (c) 2012, 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 "platform/globals.h"
#if defined(HOST_OS_MACOS)
#include "bin/platform.h"
#include <CoreFoundation/CoreFoundation.h>
#if !HOST_OS_IOS
#include <crt_externs.h> // NOLINT
#endif // !HOST_OS_IOS
#include <errno.h> // NOLINT
#include <mach-o/dyld.h>
#include <signal.h> // NOLINT
#include <string.h> // NOLINT
#include <sys/resource.h> // NOLINT
#include <sys/sysctl.h> // NOLINT
#include <sys/types.h> // NOLINT
#include <sys/utsname.h> // NOLINT
#include <unistd.h> // NOLINT
#include "bin/console.h"
#include "bin/file.h"
namespace dart {
namespace bin {
const char* Platform::executable_name_ = NULL;
char* Platform::resolved_executable_name_ = NULL;
int Platform::script_index_ = 1;
char** Platform::argv_ = NULL;
static void segv_handler(int signal, siginfo_t* siginfo, void* context) {
Syslog::PrintErr(
"\n===== CRASH =====\n"
"si_signo=%s(%d), si_code=%d, si_addr=%p\n",
strsignal(siginfo->si_signo), siginfo->si_signo, siginfo->si_code,
siginfo->si_addr);
Dart_DumpNativeStackTrace(context);
Dart_PrepareToAbort();
abort();
}
bool Platform::Initialize() {
// Turn off the signal handler for SIGPIPE as it causes the process
// to terminate on writing to a closed pipe. Without the signal
// handler error EPIPE is set instead.
struct sigaction act = {};
act.sa_handler = SIG_IGN;
if (sigaction(SIGPIPE, &act, 0) != 0) {
perror("Setting signal handler failed");
return false;
}
// tcsetattr raises SIGTTOU if we try to set console attributes when
// backgrounded, which suspends the process. Ignoring the signal prevents
// us from being suspended and lets us fail gracefully instead.
sigset_t signal_mask;
sigemptyset(&signal_mask);
sigaddset(&signal_mask, SIGTTOU);
if (sigprocmask(SIG_BLOCK, &signal_mask, NULL) < 0) {
perror("Setting signal handler failed");
return false;
}
act.sa_flags = SA_SIGINFO;
act.sa_sigaction = &segv_handler;
if (sigemptyset(&act.sa_mask) != 0) {
perror("sigemptyset() failed.");
return false;
}
if (sigaddset(&act.sa_mask, SIGPROF) != 0) {
perror("sigaddset() failed");
return false;
}
if (sigaction(SIGSEGV, &act, NULL) != 0) {
perror("sigaction() failed.");
return false;
}
if (sigaction(SIGBUS, &act, NULL) != 0) {
perror("sigaction() failed.");
return false;
}
if (sigaction(SIGTRAP, &act, NULL) != 0) {
perror("sigaction() failed.");
return false;
}
if (sigaction(SIGILL, &act, NULL) != 0) {
perror("sigaction() failed.");
return false;
}
return true;
}
int Platform::NumberOfProcessors() {
int32_t cpus = -1;
size_t cpus_length = sizeof(cpus);
if (sysctlbyname("hw.logicalcpu", &cpus, &cpus_length, NULL, 0) == 0) {
return cpus;
} else {
// Failed, fallback to using sysconf.
return sysconf(_SC_NPROCESSORS_ONLN);
}
}
const char* Platform::OperatingSystem() {
#if HOST_OS_IOS
return "ios";
#else
return "macos";
#endif
}
const char* Platform::OperatingSystemVersion() {
struct utsname info;
int ret = uname(&info);
if (ret != 0) {
return NULL;
}
const char* kFormat = "%s %s %s";
int len =
snprintf(NULL, 0, kFormat, info.sysname, info.release, info.version);
if (len <= 0) {
return NULL;
}
char* result = DartUtils::ScopedCString(len + 1);
ASSERT(result != NULL);
len = snprintf(result, len + 1, kFormat, info.sysname, info.release,
info.version);
if (len <= 0) {
return NULL;
}
return result;
}
const char* Platform::LibraryPrefix() {
return "lib";
}
const char* Platform::LibraryExtension() {
return "dylib";
}
static const char* GetLocaleName() {
CFLocaleRef locale = CFLocaleCopyCurrent();
CFStringRef locale_string = CFLocaleGetIdentifier(locale);
CFIndex len = CFStringGetLength(locale_string);
CFIndex max_len =
CFStringGetMaximumSizeForEncoding(len, kCFStringEncodingUTF8) + 1;
char* result = reinterpret_cast<char*>(Dart_ScopeAllocate(max_len));
ASSERT(result != NULL);
bool success =
CFStringGetCString(locale_string, result, max_len, kCFStringEncodingUTF8);
CFRelease(locale);
if (!success) {
return NULL;
}
return result;
}
static const char* GetPreferredLanguageName() {
CFArrayRef languages = CFLocaleCopyPreferredLanguages();
CFIndex languages_length = CFArrayGetCount(languages);
if (languages_length < 1) {
CFRelease(languages);
return NULL;
}
CFTypeRef item =
reinterpret_cast<CFTypeRef>(CFArrayGetValueAtIndex(languages, 0));
CFTypeID item_type = CFGetTypeID(item);
ASSERT(item_type == CFStringGetTypeID());
CFStringRef language = reinterpret_cast<CFStringRef>(item);
CFIndex len = CFStringGetLength(language);
CFIndex max_len =
CFStringGetMaximumSizeForEncoding(len, kCFStringEncodingUTF8) + 1;
char* result = reinterpret_cast<char*>(Dart_ScopeAllocate(max_len));
ASSERT(result != NULL);
bool success =
CFStringGetCString(language, result, max_len, kCFStringEncodingUTF8);
CFRelease(languages);
if (!success) {
return NULL;
}
return result;
}
const char* Platform::LocaleName() {
// First see if there is a preferred language. If not, return the
// current locale name.
const char* preferred_language = GetPreferredLanguageName();
return (preferred_language != NULL) ? preferred_language : GetLocaleName();
}
bool Platform::LocalHostname(char* buffer, intptr_t buffer_length) {
return gethostname(buffer, buffer_length) == 0;
}
char** Platform::Environment(intptr_t* count) {
#if HOST_OS_IOS
// TODO(zra,chinmaygarde): On iOS, environment variables are seldom used. Wire
// this up if someone needs it. In the meantime, we return an empty array.
char** result;
result = reinterpret_cast<char**>(Dart_ScopeAllocate(1 * sizeof(*result)));
if (result == NULL) {
return NULL;
}
result[0] = NULL;
*count = 0;
return result;
#else
// Using environ directly is only safe as long as we do not
// provide access to modifying environment variables.
// On MacOS you have to do a bit of magic to get to the
// environment strings.
char** environ = *(_NSGetEnviron());
intptr_t i = 0;
char** tmp = environ;
while (*(tmp++) != NULL) {
i++;
}
*count = i;
char** result;
result = reinterpret_cast<char**>(Dart_ScopeAllocate(i * sizeof(*result)));
for (intptr_t current = 0; current < i; current++) {
result[current] = environ[current];
}
return result;
#endif
}
const char* Platform::GetExecutableName() {
return executable_name_;
}
const char* Platform::ResolveExecutablePath() {
// Get the required length of the buffer.
uint32_t path_size = 0;
if (_NSGetExecutablePath(NULL, &path_size) == 0) {
return NULL;
}
// Allocate buffer and get executable path.
char* path = DartUtils::ScopedCString(path_size);
if (_NSGetExecutablePath(path, &path_size) != 0) {
return NULL;
}
// Return the canonical path as the returned path might contain symlinks.
const char* canon_path = File::GetCanonicalPath(NULL, path);
return canon_path;
}
intptr_t Platform::ResolveExecutablePathInto(char* result, size_t result_size) {
// Get the required length of the buffer.
uint32_t path_size = 0;
if (_NSGetExecutablePath(nullptr, &path_size) == 0) {
return -1;
}
if (path_size > result_size) {
return -1;
}
if (_NSGetExecutablePath(result, &path_size) != 0) {
return -1;
}
return path_size;
}
void Platform::Exit(int exit_code) {
Console::RestoreConfig();
Dart_PrepareToAbort();
exit(exit_code);
}
void Platform::SetCoreDumpResourceLimit(int value) {
rlimit limit = {static_cast<rlim_t>(value), static_cast<rlim_t>(value)};
setrlimit(RLIMIT_CORE, &limit);
}
} // namespace bin
} // namespace dart
#endif // defined(HOST_OS_MACOS)