mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 09:58:32 +00:00
[vm/ffi] Adds transition information to FFI leaf calls.
This change sets `top_exit_frame_info` and `vmtag` on FFI leaf calls. We have to set this info on the thread so that the stack walker can interpret the frame correctly. Without it, anyone trying to walk the stack during an FFI leaf call - like the profiler - will misinterpret the top frame and cause a segfault. TEST=Added regression test. Bug: https://github.com/dart-lang/sdk/issues/47594 Change-Id: If83aeab194aa0213aee82558bb9541cd7294a935 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/220360 Reviewed-by: Slava Egorov <vegorov@google.com> Commit-Queue: Clement Skau <cskau@google.com>
This commit is contained in:
parent
3d34ec1dbf
commit
bd4a27ff81
|
@ -1448,7 +1448,23 @@ void FfiCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
}
|
||||
|
||||
if (is_leaf_) {
|
||||
#if !defined(PRODUCT)
|
||||
// Set the thread object's top_exit_frame_info and VMTag to enable the
|
||||
// profiler to determine that thread is no longer executing Dart code.
|
||||
__ StoreToOffset(FPREG, THR,
|
||||
compiler::target::Thread::top_exit_frame_info_offset());
|
||||
__ StoreToOffset(branch, THR, compiler::target::Thread::vm_tag_offset());
|
||||
#endif
|
||||
|
||||
__ blx(branch);
|
||||
|
||||
#if !defined(PRODUCT)
|
||||
__ LoadImmediate(temp1, compiler::target::Thread::vm_tag_dart_id());
|
||||
__ StoreToOffset(temp1, THR, compiler::target::Thread::vm_tag_offset());
|
||||
__ LoadImmediate(temp1, 0);
|
||||
__ StoreToOffset(temp1, THR,
|
||||
compiler::target::Thread::top_exit_frame_info_offset());
|
||||
#endif
|
||||
} else {
|
||||
// We need to copy the return address up into the dummy stack frame so the
|
||||
// stack walker will know which safepoint to use.
|
||||
|
|
|
@ -1270,6 +1270,14 @@ void FfiCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
}
|
||||
|
||||
if (is_leaf_) {
|
||||
#if !defined(PRODUCT)
|
||||
// Set the thread object's top_exit_frame_info and VMTag to enable the
|
||||
// profiler to determine that thread is no longer executing Dart code.
|
||||
__ StoreToOffset(FPREG, THR,
|
||||
compiler::target::Thread::top_exit_frame_info_offset());
|
||||
__ StoreToOffset(branch, THR, compiler::target::Thread::vm_tag_offset());
|
||||
#endif
|
||||
|
||||
// We are entering runtime code, so the C stack pointer must be restored
|
||||
// from the stack limit to the top of the stack.
|
||||
__ mov(R25, CSP);
|
||||
|
@ -1280,6 +1288,13 @@ void FfiCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
// Restore the Dart stack pointer.
|
||||
__ mov(SP, CSP);
|
||||
__ mov(CSP, R25);
|
||||
|
||||
#if !defined(PRODUCT)
|
||||
__ LoadImmediate(temp1, compiler::target::Thread::vm_tag_dart_id());
|
||||
__ StoreToOffset(temp1, THR, compiler::target::Thread::vm_tag_offset());
|
||||
__ StoreToOffset(ZR, THR,
|
||||
compiler::target::Thread::top_exit_frame_info_offset());
|
||||
#endif
|
||||
} else {
|
||||
// We need to copy a dummy return address up into the dummy stack frame so
|
||||
// the stack walker will know which safepoint to use.
|
||||
|
|
|
@ -1052,7 +1052,24 @@ void FfiCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
}
|
||||
|
||||
if (is_leaf_) {
|
||||
#if !defined(PRODUCT)
|
||||
// Set the thread object's top_exit_frame_info and VMTag to enable the
|
||||
// profiler to determine that thread is no longer executing Dart code.
|
||||
__ movl(compiler::Address(
|
||||
THR, compiler::target::Thread::top_exit_frame_info_offset()),
|
||||
FPREG);
|
||||
__ movl(compiler::Assembler::VMTagAddress(), branch);
|
||||
#endif
|
||||
|
||||
__ call(branch);
|
||||
|
||||
#if !defined(PRODUCT)
|
||||
__ movl(compiler::Assembler::VMTagAddress(),
|
||||
compiler::Immediate(compiler::target::Thread::vm_tag_dart_id()));
|
||||
__ movl(compiler::Address(
|
||||
THR, compiler::target::Thread::top_exit_frame_info_offset()),
|
||||
compiler::Immediate(0));
|
||||
#endif
|
||||
} else {
|
||||
// We need to copy a dummy return address up into the dummy stack frame so
|
||||
// the stack walker will know which safepoint to use. Unlike X64, there's no
|
||||
|
|
|
@ -1240,7 +1240,24 @@ void FfiCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
}
|
||||
|
||||
if (is_leaf_) {
|
||||
#if !defined(PRODUCT)
|
||||
// Set the thread object's top_exit_frame_info and VMTag to enable the
|
||||
// profiler to determine that thread is no longer executing Dart code.
|
||||
__ movq(compiler::Address(
|
||||
THR, compiler::target::Thread::top_exit_frame_info_offset()),
|
||||
FPREG);
|
||||
__ movq(compiler::Assembler::VMTagAddress(), target_address);
|
||||
#endif
|
||||
|
||||
__ CallCFunction(target_address, /*restore_rsp=*/true);
|
||||
|
||||
#if !defined(PRODUCT)
|
||||
__ movq(compiler::Assembler::VMTagAddress(),
|
||||
compiler::Immediate(compiler::target::Thread::vm_tag_dart_id()));
|
||||
__ movq(compiler::Address(
|
||||
THR, compiler::target::Thread::top_exit_frame_info_offset()),
|
||||
compiler::Immediate(0));
|
||||
#endif
|
||||
} else {
|
||||
// We need to copy a dummy return address up into the dummy stack frame so
|
||||
// the stack walker will know which safepoint to use. RIP points to the
|
||||
|
|
22
tests/ffi/regress_47594_test.dart
Normal file
22
tests/ffi/regress_47594_test.dart
Normal file
|
@ -0,0 +1,22 @@
|
|||
// 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.
|
||||
//
|
||||
// Regression test for http://dartbug.com/47594.
|
||||
// FFI leaf calls did not mark the thread for the transition and would cause
|
||||
// the stack walker to segfault when it was unable to interpret the frame.
|
||||
//
|
||||
// VMOptions=--deterministic --enable-vm-service --profiler
|
||||
|
||||
import 'dart:ffi';
|
||||
|
||||
import 'package:ffi/ffi.dart';
|
||||
|
||||
final strerror = DynamicLibrary.process()
|
||||
.lookupFunction<Pointer<Utf8> Function(Int32), Pointer<Utf8> Function(int)>(
|
||||
'strerror',
|
||||
isLeaf: true);
|
||||
|
||||
void main() {
|
||||
for (var i = 0; i < 10000; i++) strerror(0).toDartString();
|
||||
}
|
22
tests/ffi_2/regress_47594_test.dart
Normal file
22
tests/ffi_2/regress_47594_test.dart
Normal file
|
@ -0,0 +1,22 @@
|
|||
// 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.
|
||||
//
|
||||
// Regression test for http://dartbug.com/47594.
|
||||
// FFI leaf calls did not mark the thread for the transition and would cause
|
||||
// the stack walker to segfault when it was unable to interpret the frame.
|
||||
//
|
||||
// VMOptions=--deterministic --enable-vm-service --profiler
|
||||
|
||||
import 'dart:ffi';
|
||||
|
||||
import 'package:ffi/ffi.dart';
|
||||
|
||||
final strerror = DynamicLibrary.process()
|
||||
.lookupFunction<Pointer<Utf8> Function(Int32), Pointer<Utf8> Function(int)>(
|
||||
'strerror',
|
||||
isLeaf: true);
|
||||
|
||||
void main() {
|
||||
for (var i = 0; i < 10000; i++) strerror(0).toDartString();
|
||||
}
|
Loading…
Reference in a new issue