Version 2.14.0-175.0.dev
Merge commit 'be893fdf275788d3e65487fa67084f7f301a3b2b' into 'dev'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 13329a7..069fea5e1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,6 +14,11 @@
daylight saving changes that are not precisely one hour.
(No change on the Web which uses the JavaScript `Date` object.)
+#### `dart:ffi`
+
+* Adds the `DynamicLibrary.providesSymbol` function to check whether a symbol
+ is available in a dynamic library.
+
#### `dart:io`
* BREAKING CHANGE (for pre-migrated null safe code):
diff --git a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.expect b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.expect
index b92f5af..385e300 100644
--- a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.expect
@@ -25,4 +25,4 @@
Constructor coverage from constants:
org-dartlang-testcase:///ffi_struct_inline_array.dart:
-- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:135:9)
+- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:136:9)
diff --git a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.transformed.expect
index d480c5f..157a41b 100644
--- a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.transformed.expect
@@ -52,4 +52,4 @@
Constructor coverage from constants:
org-dartlang-testcase:///ffi_struct_inline_array.dart:
-- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:135:9)
+- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:136:9)
diff --git a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.weak.expect b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.weak.expect
index 792f6e0..8e37bb2 100644
--- a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.weak.expect
@@ -25,4 +25,4 @@
Constructor coverage from constants:
org-dartlang-testcase:///ffi_struct_inline_array.dart:
-- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:135:9)
+- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:136:9)
diff --git a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.weak.transformed.expect
index 1097538..dedc171 100644
--- a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.weak.transformed.expect
@@ -52,4 +52,4 @@
Constructor coverage from constants:
org-dartlang-testcase:///ffi_struct_inline_array.dart:
-- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:135:9)
+- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:136:9)
diff --git a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.expect b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.expect
index 7c27f0b..0275472 100644
--- a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.expect
@@ -33,4 +33,4 @@
Constructor coverage from constants:
org-dartlang-testcase:///ffi_struct_inline_array_multi_dimensional.dart:
-- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:135:9)
+- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:136:9)
diff --git a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.transformed.expect
index 6978f30..bb7ab61a 100644
--- a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.transformed.expect
@@ -84,4 +84,4 @@
Constructor coverage from constants:
org-dartlang-testcase:///ffi_struct_inline_array_multi_dimensional.dart:
-- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:135:9)
+- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:136:9)
diff --git a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.weak.expect b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.weak.expect
index 7831122..8045c2f 100644
--- a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.weak.expect
@@ -33,4 +33,4 @@
Constructor coverage from constants:
org-dartlang-testcase:///ffi_struct_inline_array_multi_dimensional.dart:
-- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:135:9)
+- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:136:9)
diff --git a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.weak.transformed.expect
index 3cdfa2e..1ba5718 100644
--- a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.weak.transformed.expect
@@ -84,4 +84,4 @@
Constructor coverage from constants:
org-dartlang-testcase:///ffi_struct_inline_array_multi_dimensional.dart:
-- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:135:9)
+- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:136:9)
diff --git a/runtime/lib/ffi_dynamic_library.cc b/runtime/lib/ffi_dynamic_library.cc
index 3935a54..eb8e74b 100644
--- a/runtime/lib/ffi_dynamic_library.cc
+++ b/runtime/lib/ffi_dynamic_library.cc
@@ -99,8 +99,8 @@
defined(HOST_OS_ANDROID) || defined(HOST_OS_FUCHSIA)
dlerror(); // Clear any errors.
void* pointer = dlsym(handle, symbol);
- if (pointer == nullptr) {
- char* error = dlerror();
+ char* error = dlerror();
+ if (error != nullptr) {
const String& msg = String::Handle(
String::NewFormatted("Failed to lookup symbol (%s)", error));
Exceptions::ThrowArgumentError(msg);
@@ -147,4 +147,32 @@
return Integer::NewFromUint64(handle);
}
+static bool SymbolExists(void* handle, const char* symbol) {
+#if defined(HOST_OS_LINUX) || defined(HOST_OS_MACOS) || \
+ defined(HOST_OS_ANDROID) || defined(HOST_OS_FUCHSIA)
+ dlerror(); // Clear previous error, if any.
+ dlsym(handle, symbol);
+ // Checking whether dlsym returns a nullptr is not enough, as the value of
+ // the symbol could actually be NULL. Check the error condition instead.
+ return dlerror() == nullptr;
+#elif defined(HOST_OS_WINDOWS)
+ return GetProcAddress(reinterpret_cast<HMODULE>(handle), symbol) != nullptr;
+#else
+ const Array& args = Array::Handle(Array::New(1));
+ args.SetAt(0,
+ String::Handle(String::New(
+ "The dart:ffi library is not available on this platform.")));
+ Exceptions::ThrowByType(Exceptions::kUnsupported, args);
+#endif
+}
+
+DEFINE_NATIVE_ENTRY(Ffi_dl_providesSymbol, 0, 2) {
+ GET_NON_NULL_NATIVE_ARGUMENT(DynamicLibrary, dlib, arguments->NativeArgAt(0));
+ GET_NON_NULL_NATIVE_ARGUMENT(String, argSymbolName,
+ arguments->NativeArgAt(1));
+
+ void* handle = dlib.GetHandle();
+ return Bool::Get(SymbolExists(handle, argSymbolName.ToCString())).ptr();
+}
+
} // namespace dart
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index 5965209..5237e60 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -402,6 +402,7 @@
V(Ffi_dl_open, 1) \
V(Ffi_dl_lookup, 2) \
V(Ffi_dl_getHandle, 1) \
+ V(Ffi_dl_providesSymbol, 2) \
V(Ffi_asExternalTypedData, 2) \
V(Ffi_dl_processLibrary, 0) \
V(Ffi_dl_executableLibrary, 0) \
diff --git a/sdk/lib/_internal/vm/lib/ffi_dynamic_library_patch.dart b/sdk/lib/_internal/vm/lib/ffi_dynamic_library_patch.dart
index 5482890..2966149 100644
--- a/sdk/lib/_internal/vm/lib/ffi_dynamic_library_patch.dart
+++ b/sdk/lib/_internal/vm/lib/ffi_dynamic_library_patch.dart
@@ -30,6 +30,9 @@
Pointer<T> lookup<T extends NativeType>(String symbolName)
native "Ffi_dl_lookup";
+ @patch
+ bool providesSymbol(String symbolName) native "Ffi_dl_providesSymbol";
+
// TODO(dacoharkes): Expose this to users, or extend Pointer?
// https://github.com/dart-lang/sdk/issues/35881
int getHandle() native "Ffi_dl_getHandle";
diff --git a/sdk/lib/ffi/dynamic_library.dart b/sdk/lib/ffi/dynamic_library.dart
index e39e53c..0a4ee2e 100644
--- a/sdk/lib/ffi/dynamic_library.dart
+++ b/sdk/lib/ffi/dynamic_library.dart
@@ -39,9 +39,15 @@
/// [dlsym(3)](https://man7.org/linux/man-pages/man3/dlsym.3.html) system
/// call.
///
- /// The symbol must be provided by the dynamic library.
+ /// The symbol must be provided by the dynamic library. To check whether
+ /// the library provides such symbol, use [hasSymbol].
external Pointer<T> lookup<T extends NativeType>(String symbolName);
+ /// Checks whether this dynamic library provides a symbol with the given
+ /// name.
+ @Since('2.14')
+ external bool providesSymbol(String symbolName);
+
/// Dynamic libraries are equal if they load the same library.
external bool operator ==(Object other);
diff --git a/sdk/lib/ffi/ffi.dart b/sdk/lib/ffi/ffi.dart
index 26177e8..e82e567 100644
--- a/sdk/lib/ffi/ffi.dart
+++ b/sdk/lib/ffi/ffi.dart
@@ -11,6 +11,7 @@
*/
library dart.ffi;
+import 'dart:_internal' show Since;
import 'dart:isolate';
import 'dart:typed_data';
diff --git a/tests/ffi/has_symbol_test.dart b/tests/ffi/has_symbol_test.dart
new file mode 100644
index 0000000..858de9c
--- /dev/null
+++ b/tests/ffi/has_symbol_test.dart
@@ -0,0 +1,34 @@
+// Copyright (c) 2021, 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.
+//
+// SharedObjects=ffi_test_functions
+
+import 'dart:ffi';
+import 'dart:io';
+
+import 'package:expect/expect.dart';
+
+import 'ffi_test_helpers.dart';
+
+void main() {
+ testHasSymbol();
+}
+
+void testHasSymbol() {
+ Expect.isTrue(ffiTestFunctions.providesSymbol('ReturnMaxUint8'));
+ Expect.isFalse(ffiTestFunctions.providesSymbol('SymbolNotInLibrary'));
+
+ if (Platform.isMacOS ||
+ Platform.isIOS ||
+ Platform.isAndroid ||
+ Platform.isLinux) {
+ DynamicLibrary p = DynamicLibrary.process();
+ Expect.isTrue(p.providesSymbol('dlopen'));
+ Expect.isFalse(p.providesSymbol('symbol_that_does_not_exist_in_process'));
+ }
+
+ DynamicLibrary e = DynamicLibrary.executable();
+ Expect.isTrue(e.providesSymbol('Dart_Invoke'));
+ Expect.isFalse(e.providesSymbol('symbol_that_does_not_exist_in_executable'));
+}
diff --git a/tests/ffi_2/has_symbol_test.dart b/tests/ffi_2/has_symbol_test.dart
new file mode 100644
index 0000000..11c1de10e
--- /dev/null
+++ b/tests/ffi_2/has_symbol_test.dart
@@ -0,0 +1,36 @@
+// Copyright (c) 2021, 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.
+//
+// SharedObjects=ffi_test_functions
+
+// @dart=2.9
+
+import 'dart:ffi';
+import 'dart:io';
+
+import 'package:expect/expect.dart';
+
+import 'ffi_test_helpers.dart';
+
+void main() {
+ testHasSymbol();
+}
+
+void testHasSymbol() {
+ Expect.isTrue(ffiTestFunctions.providesSymbol('ReturnMaxUint8'));
+ Expect.isFalse(ffiTestFunctions.providesSymbol('SymbolNotInLibrary'));
+
+ if (Platform.isMacOS ||
+ Platform.isIOS ||
+ Platform.isAndroid ||
+ Platform.isLinux) {
+ DynamicLibrary p = DynamicLibrary.process();
+ Expect.isTrue(p.providesSymbol('dlopen'));
+ Expect.isFalse(p.providesSymbol('symbol_that_does_not_exist_in_process'));
+ }
+
+ DynamicLibrary e = DynamicLibrary.executable();
+ Expect.isTrue(e.providesSymbol('Dart_Invoke'));
+ Expect.isFalse(e.providesSymbol('symbol_that_does_not_exist_in_executable'));
+}
diff --git a/tools/VERSION b/tools/VERSION
index 4e385a8..931f10d 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 14
PATCH 0
-PRERELEASE 174
+PRERELEASE 175
PRERELEASE_PATCH 0
\ No newline at end of file