Skip to content

Commit 74f2d4b

Browse files
committed
[vm/ffi] Error on invoking callback from leaf call
All callbacks flow via the single runtime entry, so we add a check there. TEST=tests/ffi/function_callbacks_leaf_test.dart (The transition verification in https://dart-review.googlesource.com/c/sdk/+/407021 doesn't catch the error. The callbacks already transitioned before reaching the generated code in that CL.) Closes: #60021 Change-Id: Ia6bf8af186c9c8c5a66cffa537d80421467330d4 Cq-Include-Trybots: dart/try:vm-aot-android-release-arm64c-try,vm-aot-android-release-arm_x64-try,vm-aot-asan-linux-release-x64-try,vm-aot-linux-debug-x64-try,vm-aot-linux-debug-x64c-try,vm-aot-mac-release-arm64-try,vm-aot-mac-release-x64-try,vm-aot-msan-linux-release-x64-try,vm-aot-obfuscate-linux-release-x64-try,vm-aot-optimization-level-linux-release-x64-try,vm-aot-tsan-linux-release-x64-try,vm-aot-ubsan-linux-release-x64-try,vm-aot-win-debug-arm64-try,vm-aot-win-debug-x64-try,vm-aot-win-debug-x64c-try,vm-appjit-linux-debug-x64-try,vm-asan-linux-release-arm64-try,vm-asan-linux-release-x64-try,vm-checked-mac-release-arm64-try,vm-ffi-android-debug-arm-try,vm-ffi-android-debug-arm64c-try,vm-ffi-qemu-linux-release-arm-try,vm-ffi-qemu-linux-release-riscv64-try,vm-fuchsia-release-arm64-try,vm-fuchsia-release-x64-try,vm-linux-debug-ia32-try,vm-linux-debug-x64-try,vm-linux-debug-x64c-try,vm-mac-debug-arm64-try,vm-mac-debug-x64-try,vm-msan-linux-release-arm64-try,vm-msan-linux-release-x64-try,vm-reload-linux-debug-x64-try,vm-reload-rollback-linux-debug-x64-try,vm-tsan-linux-release-arm64-try,vm-tsan-linux-release-x64-try,vm-ubsan-linux-release-arm64-try,vm-ubsan-linux-release-x64-try,vm-win-debug-arm64-try,vm-win-debug-x64-try,vm-win-debug-x64c-try,vm-win-release-ia32-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/407023 Commit-Queue: Daco Harkes <[email protected]> Reviewed-by: Liam Appelbe <[email protected]> Reviewed-by: Slava Egorov <[email protected]>
1 parent 5984cc8 commit 74f2d4b

File tree

3 files changed

+68
-1
lines changed

3 files changed

+68
-1
lines changed

runtime/vm/runtime_entry.cc

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4413,7 +4413,9 @@ extern "C" Thread* DLRT_GetFfiCallbackMetadata(
44134413
Isolate* current_isolate = nullptr;
44144414
if (current_thread != nullptr) {
44154415
current_isolate = current_thread->isolate();
4416-
ASSERT(current_thread->execution_state() == Thread::kThreadInNative);
4416+
if (current_thread->execution_state() != Thread::kThreadInNative) {
4417+
FATAL("Cannot invoke native callback from a leaf call.");
4418+
}
44174419
current_thread->ExitSafepoint();
44184420
current_thread->set_execution_state(Thread::kThreadInVM);
44194421
}
@@ -4460,6 +4462,9 @@ extern "C" Thread* DLRT_GetFfiCallbackMetadata(
44604462
if (current_thread->isolate() != target_isolate) {
44614463
FATAL("Cannot invoke native callback from a different isolate.");
44624464
}
4465+
if (current_thread->execution_state() != Thread::kThreadInNative) {
4466+
FATAL("Cannot invoke native callback from a leaf call.");
4467+
}
44634468

44644469
// Set the execution state to VM while waiting for the safepoint to end.
44654470
// This isn't strictly necessary but enables tests to check that we're not

tests/ffi/ffi.status

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ vmspecific_native_finalizer_isolate_groups_test: Skip # SpawnUri not available o
5454
[ $system == fuchsia ]
5555
async_void_function_callbacks_test/*: Skip # Test harness doesn't support multitest with Fuchsia
5656
ffi_induce_a_crash_test/*: Skip # Test harness doesn't support multitest with Fuchsia
57+
function_callbacks_leaf_test: SkipByDesign # Needs access to Dart executable
5758
function_callbacks_many_test/*: Skip # Test harness doesn't support multitest with Fuchsia
5859
function_callbacks_structs_by_value_generated_test/*: Skip # Test harness doesn't support multitest with Fuchsia
5960
function_callbacks_structs_by_value_native_callable_generated_test/*: Skip # Test harness doesn't support multitest with Fuchsia
@@ -71,6 +72,7 @@ vmspecific_pointer_load_il_test: SkipByDesign # Not bloating the Fuchsia test pa
7172
regress_47594_test: Skip # DynamicLibrary.process() is not available on Windows.
7273

7374
[ $qemu ]
75+
function_callbacks_leaf_test: SkipByDesign # Needs access to Dart executable
7476
native_assets/*: SkipByDesign # Only intended to run on host oses with AOT binaries available, not available on QEMU.
7577

7678
[ $simulator ]
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'dart:ffi';
6+
import 'dart:io';
7+
8+
import 'dylib_utils.dart';
9+
10+
final ffiTestFunctions = dlopenPlatformSpecific('ffi_test_functions');
11+
12+
typedef SimpleAdditionType = Void Function(Int32, Int32);
13+
14+
void simpleAddition(int x, int y) {
15+
print("simpleAddition($x, $y)");
16+
}
17+
18+
void main(List<String> arguments) async {
19+
if (arguments.isEmpty) {
20+
for (int i in [1, 2, 3]) {
21+
final result = Process.runSync(Platform.resolvedExecutable, [
22+
Platform.script.toFilePath(),
23+
'$i',
24+
]);
25+
if (result.exitCode == 0) {
26+
throw 'Expected non-0 exit code: ${result.exitCode}';
27+
}
28+
if (!result.stderr.contains(
29+
'Cannot invoke native callback from a leaf call.',
30+
)) {
31+
throw "Expected stderr to contain 'Cannot invoke native callback from a leaf call.': ${result.stderr}";
32+
}
33+
}
34+
return;
35+
}
36+
final Pointer<NativeFunction<SimpleAdditionType>> callbackPointer;
37+
switch (arguments.single) {
38+
case "1":
39+
callbackPointer = Pointer.fromFunction<SimpleAdditionType>(
40+
simpleAddition,
41+
);
42+
case "2":
43+
callbackPointer =
44+
NativeCallable<SimpleAdditionType>.isolateLocal(
45+
simpleAddition,
46+
).nativeFunction;
47+
case "3":
48+
callbackPointer =
49+
NativeCallable<SimpleAdditionType>.listener(
50+
simpleAddition,
51+
).nativeFunction;
52+
default:
53+
throw "Unknown";
54+
}
55+
final function = callbackPointer.asFunction<void Function(int, int)>(
56+
isLeaf: true,
57+
);
58+
function(3, 4);
59+
print('We should have crashed by now.');
60+
}

0 commit comments

Comments
 (0)