diff --git a/runtime/bin/dartutils.cc b/runtime/bin/dartutils.cc index 50283d35f27..41fb6f83b7a 100644 --- a/runtime/bin/dartutils.cc +++ b/runtime/bin/dartutils.cc @@ -758,6 +758,22 @@ Dart_Handle DartUtils::NewInternalError(const char* message) { return NewDartExceptionWithMessage(kCoreLibURL, "_InternalError", message); } +Dart_Handle DartUtils::NewStringFormatted(const char* format, ...) { + va_list args; + va_start(args, format); + intptr_t len = vsnprintf(NULL, 0, format, args); + va_end(args); + + char* buffer = reinterpret_cast(Dart_ScopeAllocate(len + 1)); + MSAN_UNPOISON(buffer, (len + 1)); + va_list args2; + va_start(args2, format); + vsnprintf(buffer, (len + 1), format, args2); + va_end(args2); + + return NewString(buffer); +} + bool DartUtils::SetOriginalWorkingDirectory() { // If we happen to re-initialize the Dart VM multiple times, make sure to free // the old string (allocated by getcwd()) before setting a new one. diff --git a/runtime/bin/dartutils.h b/runtime/bin/dartutils.h index 66da23f0fec..f7f1d8db44c 100644 --- a/runtime/bin/dartutils.h +++ b/runtime/bin/dartutils.h @@ -195,13 +195,16 @@ class DartUtils { const char* message, Dart_Handle os_error); - // Create a new Dart String object from a C String. + // Create a new Dart String object from a UTF8 encoded C String. static Dart_Handle NewString(const char* str) { ASSERT(str != NULL); return Dart_NewStringFromUTF8(reinterpret_cast(str), strlen(str)); } + // Create a new Dart String object from a formatted string. + static Dart_Handle NewStringFormatted(const char* format, ...); + // Allocate length bytes for a C string with Dart_ScopeAllocate. static char* ScopedCString(intptr_t length) { char* result = NULL; diff --git a/runtime/bin/process.cc b/runtime/bin/process.cc index 727b18fd259..914a5f8c10b 100644 --- a/runtime/bin/process.cc +++ b/runtime/bin/process.cc @@ -164,13 +164,29 @@ void FUNCTION_NAME(Process_Start)(Dart_NativeArguments args) { result = DartUtils::SetIntegerField(status_handle, "_errorCode", error_code); ThrowIfError(result); - Dart_Handle val = DartUtils::NewString(os_error_message != NULL - ? os_error_message - : "Cannot get error message"); + + const char* error_message = (os_error_message != NULL) + ? os_error_message + : "Failed to get error message"; + Dart_Handle val = DartUtils::NewString(error_message); if (Dart_IsError(val)) { - // If conversion of the OS error message to a Dart string fails, fall back - // on a stock message. - val = DartUtils::NewString("OS error message was a not a utf8 string."); + // Try to clean the message from non-ASCII characters. + const intptr_t len = strlen(error_message); + char* ascii_message = + reinterpret_cast(Dart_ScopeAllocate(len + 1)); + for (intptr_t i = 0; i < len; i++) { + if (static_cast(error_message[i]) < 0x80) { + ascii_message[i] = error_message[i]; + } else { + ascii_message[i] = '?'; + } + } + ascii_message[len] = '\0'; + + val = DartUtils::NewStringFormatted( + "Failed to start %s. OS returned an error (code %d) which can't be " + "fully converted to Dart string (%s): %s", + path, error_code, Dart_GetError(val), ascii_message); } result = Dart_SetField(status_handle, DartUtils::NewString("_errorMessage"), val); diff --git a/runtime/bin/process_linux.cc b/runtime/bin/process_linux.cc index dc8d50092ce..7c816373a3a 100644 --- a/runtime/bin/process_linux.cc +++ b/runtime/bin/process_linux.cc @@ -399,6 +399,8 @@ class ProcessStarter { } private: + static constexpr int kErrorBufferSize = 1024; + int CreatePipes() { int result; result = TEMP_FAILURE_RETRY(pipe2(exec_control_, O_CLOEXEC)); @@ -705,9 +707,8 @@ class ProcessStarter { } void SetChildOsErrorMessage() { - const int kBufferSize = 1024; - char* error_message = DartUtils::ScopedCString(kBufferSize); - Utils::StrError(errno, error_message, kBufferSize); + char* error_message = DartUtils::ScopedCString(kErrorBufferSize); + Utils::StrError(errno, error_message, kErrorBufferSize); *os_error_message_ = error_message; } @@ -715,9 +716,9 @@ class ProcessStarter { // In the case of failure in the child process write the errno and // the OS error message to the exec control pipe and exit. int child_errno = errno; - const int kBufferSize = 1024; - char error_buf[kBufferSize]; - char* os_error_message = Utils::StrError(errno, error_buf, kBufferSize); + char error_buf[kErrorBufferSize]; + char* os_error_message = + Utils::StrError(errno, error_buf, kErrorBufferSize); int bytes_written = FDUtils::WriteToBlocking(exec_control_[1], &child_errno, sizeof(child_errno)); if (bytes_written == sizeof(child_errno)) { @@ -741,11 +742,10 @@ class ProcessStarter { } void ReadChildError() { - const int kMaxMessageSize = 256; - char* message = DartUtils::ScopedCString(kMaxMessageSize); + char* message = DartUtils::ScopedCString(kErrorBufferSize); if (message != NULL) { - FDUtils::ReadFromBlocking(exec_control_[0], message, kMaxMessageSize); - message[kMaxMessageSize - 1] = '\0'; + FDUtils::ReadFromBlocking(exec_control_[0], message, kErrorBufferSize); + message[kErrorBufferSize - 1] = '\0'; *os_error_message_ = message; } else { // Could not get error message. It will be NULL.