Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GC can move TypedData after Dart_TypedDataAcquireData / Flaky SocketException: Send failed (OS Error: Bad address, errno = 14) in standalone_2/io/raw_datagram_socket_test #37256

Closed
alexmarkov opened this issue Jun 13, 2019 · 0 comments
Assignees
Labels
area-vm Use area-vm for VM related issues, including code coverage, and the AOT and JIT backends. crash Process exits with SIGSEGV, SIGABRT, etc. An unhandled exception is not a crash. gardening

Comments

@alexmarkov
Copy link
Contributor

Repro:

tools/build.py -a x64 -m debug runtime
tools/test.py --repeat 100 -n dartkb-mixed-linux-debug-x64 standalone_2/io/raw_datagram_socket_test
[01:22 |  37% | +   37 | -    0]
FAILED: dartkb-vm debug_x64 standalone_2/io/raw_datagram_socket_test
Expected: Pass
Actual: RuntimeError

--- Command "vm_compile_to_kernel []" (took 729ms):
DART_CONFIGURATION=DebugX64 /usr/local/google/home/alexmarkov/work/dart/sdk/pkg/vm/tool/gen_kernel --no-aot --platform=out/DebugX64/vm_platform_strong.dill -o /usr/local/google/home/alexmarkov/work/dart/sdk/out/DebugX64/generated_compilations/dartkb/tests_standalone_2_io_raw_datagram_socket_test/out.dill /usr/local/google/home/alexmarkov/work/dart/sdk/tests/standalone_2/io/raw_datagram_socket_test.dart --packages=/usr/local/google/home/alexmarkov/work/dart/sdk/.packages -Ddart.developer.causal_async_stacks=true --gen-bytecode --drop-ast --emit-bytecode-source-positions --emit-bytecode-local-var-info

exit code:
0

--- Command "vm" (took 781ms):
DART_CONFIGURATION=DebugX64 out/DebugX64/dart --enable_interpreter --ignore-unrecognized-flags --packages=/usr/local/google/home/alexmarkov/work/dart/sdk/.packages /usr/local/google/home/alexmarkov/work/dart/sdk/out/DebugX64/generated_compilations/dartkb/tests_standalone_2_io_raw_datagram_socket_test/out.dill

exit code:
255

stdout:
unittest-suite-wait-for-done

stderr:
Unhandled exception:
SocketException: Send failed (OS Error: Bad address, errno = 14), address = 127.0.0.1, port = 48495
#0      _rootHandleUncaughtError.<anonymous closure> (dart:async/zone.dart:1112:29)
#1      _microtaskLoop (dart:async/schedule_microtask.dart:41:21)
#2      _startMicrotaskLoop (dart:async/schedule_microtask.dart:50:5)
#3      _runPendingImmediateCallback (dart:isolate-patch/isolate_patch.dart:116:13)
#4      _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:173:5)

--- Re-run this test:
python tools/test.py -n dartkb-mixed-linux-debug-x64 standalone_2/io/raw_datagram_socket_test

The following happens:

  • native method Socket_SendTo calls Dart_TypedDataAcquireData to get a direct pointer to a data in the TypedData object.
  • Direct pointer to data is passed to sendto
  • GC is triggered and moves TypedData object, protects the memory
  • sento returns with an error (EFAULT) as it can't access buffer

As Dart_TypedDataAcquireData returns direct pointer to the contents of TypedData object, GC should be disabled until Dart_TypedDataReleaseData is called. But it doesn't happen.

Currently, GC can be called after acquiring direct pointer because:

  1. When leaving DARTSCOPE in Dart_TypedDataAcquireData, there is a safepoint when transitioning from VM state back to native state.
  2. While thread is in native state, it will not be blocked while GC is happening, so GC can theoretically run concurrently with native code between Dart_TypedDataAcquireData and Dart_TypedDataReleaseData.

The following additional asserts can be used to reproduce the error more regularly:

diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h
index 44bb9e6110..ef03c8343b 100644
--- a/runtime/vm/thread.h
+++ b/runtime/vm/thread.h
@@ -738,6 +738,7 @@ class Thread : public ThreadState {
   }
 
   void EnterSafepoint() {
+    ASSERT(no_safepoint_scope_depth() == 0);
     // First try a fast update of the thread state to indicate it is at a
     // safepoint.
     if (!TryEnterSafepoint()) {
@@ -767,6 +768,7 @@ class Thread : public ThreadState {
   }
 
   void CheckForSafepoint() {
+    ASSERT(no_safepoint_scope_depth() == 0);
     if (IsSafepointRequested()) {
       BlockForSafepoint();
     }

In order to fix this problem, we need to make sure that GC may not happen between Dart_TypedDataAcquireData and Dart_TypedDataReleaseData (if they are called for non-external TypedData).

This can be achieved by introducing a new thread state such as ThreadInNativeNoSafepoints. Safepoints could also take Thread::no_callback_scope_depth() into account.

/cc @rmacnak-google @a-siva @mkustermann

@alexmarkov alexmarkov added area-vm Use area-vm for VM related issues, including code coverage, and the AOT and JIT backends. gardening crash Process exits with SIGSEGV, SIGABRT, etc. An unhandled exception is not a crash. labels Jun 13, 2019
@a-siva a-siva self-assigned this Jun 14, 2019
dart-bot pushed a commit that referenced this issue Jun 19, 2019
…taAcquireData.

Bug: #37256
Change-Id: I1dcd2e32d8308c5a7169731169a048b8f1bfcc79
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/106023
Commit-Queue: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-vm Use area-vm for VM related issues, including code coverage, and the AOT and JIT backends. crash Process exits with SIGSEGV, SIGABRT, etc. An unhandled exception is not a crash. gardening
Projects
None yet
Development

No branches or pull requests

3 participants