[vm/bin] Improve fallback error message for process creation
Instead of just giving up try to give as much information as possible including error code, error returned by Dart_StringFromUtf8 and ascii portion of the OS error message. We are making this change because we are getting reports of ProcessException being thrown with "OS error message was a not a utf8 string." message. There is no way to reproduce these situations so instead we are going to add additional information into the fallback message to aid the investigation. TEST=tested manually by simulating fallback to the newly added code Bug: b/178383611 Change-Id: Idf528dc762723694145a15aa07320220e8af9bfc Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/181200 Commit-Queue: Vyacheslav Egorov <vegorov@google.com> Reviewed-by: Daco Harkes <dacoharkes@google.com>
This commit is contained in:
committed by
commit-bot@chromium.org
parent
0f371f2dba
commit
aed72ae8c8
@@ -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<char*>(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.
|
||||
|
||||
@@ -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<const uint8_t*>(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;
|
||||
|
||||
+22
-6
@@ -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<char*>(Dart_ScopeAllocate(len + 1));
|
||||
for (intptr_t i = 0; i < len; i++) {
|
||||
if (static_cast<uint8_t>(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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user