From ada6b817613b2fc74ac8ac83cbf2c04ccd874a1e Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Wed, 20 Dec 2023 13:24:16 +0000 Subject: [PATCH] [vm/ffi] Improve error messages on Windows Use `FormatMessageA` to allocate an English description of an error code. Previously, only the error code itself was shown. Closes https://github.com/dart-lang/sdk/issues/52790 TEST=tests/ffi/dylib_open_test.dart Cq-Include-Trybots: luci.dart.try:vm-win-debug-x64-try,vm-win-debug-x64c-try,vm-aot-win-debug-x64c-try,vm-aot-asan-linux-release-x64-try,vm-asan-linux-release-x64-try Change-Id: Iccae6c763fb16d4bb999b9c260fcfea9c5de276b Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/328420 Reviewed-by: Daco Harkes Reviewed-by: Alexander Markov Commit-Queue: Daco Harkes --- runtime/platform/utils.cc | 19 ++++++++++++++++++- tests/ffi/dylib_open_test.dart | 31 +++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 tests/ffi/dylib_open_test.dart diff --git a/runtime/platform/utils.cc b/runtime/platform/utils.cc index d6b4471294c..e7179ed8040 100644 --- a/runtime/platform/utils.cc +++ b/runtime/platform/utils.cc @@ -267,7 +267,24 @@ static void GetLastErrorAsString(char** error) { *error = status != nullptr ? strdup(status) : nullptr; #elif defined(DART_HOST_OS_WINDOWS) const int status = GetLastError(); - *error = status != 0 ? Utils::SCreate("error code %i", status) : nullptr; + if (status != 0) { + char* description = nullptr; + int length = FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, status, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), + reinterpret_cast(&description), 0, nullptr); + if (length == 0) { + // Seems like there is no message for this error code. + *error = Utils::SCreate("error code %i", status); + } else { + *error = Utils::SCreate("%s (error code: %i)", description, status); + } + + LocalFree(description); + } else { + *error = nullptr; + } #else *error = Utils::StrDup("loading dynamic libraries is not supported"); #endif diff --git a/tests/ffi/dylib_open_test.dart b/tests/ffi/dylib_open_test.dart new file mode 100644 index 00000000000..02da551aac3 --- /dev/null +++ b/tests/ffi/dylib_open_test.dart @@ -0,0 +1,31 @@ +// Copyright (c) 2023, 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. + +import 'dart:ffi'; +import 'dart:io'; + +import 'package:expect/expect.dart'; + +import 'dylib_utils.dart'; + +void main() { + testDoesNotExist(); +} + +void testDoesNotExist() { + final exception = Expect.throws( + () => DynamicLibrary.open(dylibName('doesnotexist1234'))); + + if (Platform.isWindows) { + Expect.contains( + 'The specified module could not be found.', exception.message); + Expect.contains('(error code: 126)', exception.message); + } else if (Platform.isLinux) { + Expect.contains('cannot open shared object file: No such file or directory', + exception.message); + } else if (Platform.isMacOS) { + Expect.contains('libdoesnotexist1234.dylib', exception.message); + Expect.contains('no such file', exception.message); + } +}