Revert "Disallow exiting from VM tests (#2640)" (#2652)

This reverts commit 86fcce24d18be9bcbd3f387681dcfc24d1517acd.

Using `IOOverrides` can cause observable behavior changes so this is a
breaking change. We will need to wait for a fix we can rely on in the
SDK before it's safe to roll this out.

https://github.com/dart-lang/sdk/issues/63418
diff --git a/pkgs/test/CHANGELOG.md b/pkgs/test/CHANGELOG.md
index b8e9d2d..7e369fa 100644
--- a/pkgs/test/CHANGELOG.md
+++ b/pkgs/test/CHANGELOG.md
@@ -10,7 +10,6 @@
   independent from any OS specific configuration. For instance a wide skip of
   all tests with OS `'windows'` would previously still run browser tests on
   windows, but will now skip all tests including browser tests.
-* Treat calls to `exit` as test failures in VM tests.
 * Use a DevTools URL instead of a defunct observatory URL.
 
 ## 1.31.1
diff --git a/pkgs/test/test/runner/subprocess_crash_test.dart b/pkgs/test/test/runner/subprocess_crash_test.dart
index b6e40df..e98f634 100644
--- a/pkgs/test/test/runner/subprocess_crash_test.dart
+++ b/pkgs/test/test/runner/subprocess_crash_test.dart
@@ -13,16 +13,16 @@
 void main() {
   setUpAll(precompileTestExecutable);
 
-  test('gracefully handles a non-exit crash', () async {
+  test('gracefully handles an early test suite exit', () async {
     await d.file('test.dart', '''
-      import 'dart:ffi';
+      import 'dart:io';
 
       import 'package:test/test.dart';
 
       void main() {
         test('runs', () {});
-        test('crashes', () {
-          Pointer.fromAddress(0).cast<Long>()[0] = 0;
+        test('exits', () {
+          exit(0);
         });
       }''').create();
 
@@ -30,7 +30,7 @@
     expect(
       test.stdout,
       containsInOrder([
-        '+1: [VM, Exe] crashes - did not complete [E]',
+        '+1: [VM, Exe] exits - did not complete [E]',
         '+1: Some tests failed.',
       ]),
     );
diff --git a/pkgs/test/test/runner/vm/runner_test.dart b/pkgs/test/test/runner/vm/runner_test.dart
deleted file mode 100644
index 7f795b6..0000000
--- a/pkgs/test/test/runner/vm/runner_test.dart
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright (c) 2026, 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.
-
-@TestOn('vm')
-library;
-
-import 'package:test/test.dart';
-import 'package:test_descriptor/test_descriptor.dart' as d;
-
-import '../../io.dart';
-
-void main() {
-  setUpAll(precompileTestExecutable);
-
-  group('fails gracefully if a test file calls exit(0)', () {
-    setUp(() async {
-      await d.file('test.dart', '''
-import 'dart:io';
-import 'package:test/test.dart';
-
-void main() {
-  test('exits', () {
-    exit(0);
-  });
-}
-''').create();
-    });
-
-    test('in a VM test', () async {
-      var test = await runTest(['test.dart']);
-
-      expect(test.stdout, containsInOrder(['exit(0) was called.']));
-      await test.shouldExit(1);
-    });
-
-    test('in a native test', () async {
-      var test = await runTest(['--compiler', 'exe', 'test.dart']);
-
-      expect(test.stdout, containsInOrder(['exit(0) was called.']));
-      await test.shouldExit(1);
-    });
-  });
-}
diff --git a/pkgs/test_core/CHANGELOG.md b/pkgs/test_core/CHANGELOG.md
index ef00a79..6907873 100644
--- a/pkgs/test_core/CHANGELOG.md
+++ b/pkgs/test_core/CHANGELOG.md
@@ -1,7 +1,6 @@
 ## 0.6.19-wip
 
 * Support using the OS platform selector to configure browser tests.
-* Treat calls to `exit` as test failures in VM tests.
 * Use a DevTools URL instead of a defunct observatory URL.
 
 ## 0.6.18
diff --git a/pkgs/test_core/lib/src/bootstrap/vm.dart b/pkgs/test_core/lib/src/bootstrap/vm.dart
index 034a0ab..a4eebe6 100644
--- a/pkgs/test_core/lib/src/bootstrap/vm.dart
+++ b/pkgs/test_core/lib/src/bootstrap/vm.dart
@@ -9,7 +9,6 @@
 
 import 'package:stream_channel/isolate_channel.dart';
 import 'package:stream_channel/stream_channel.dart';
-import 'package:test_api/hooks.dart';
 
 import '../runner/plugin/remote_platform_helpers.dart';
 import '../runner/plugin/shared_platform_helpers.dart';
@@ -20,12 +19,7 @@
     IsolateChannel<Object?>.connectSend(sendPort),
   );
   var testControlChannel = platformChannel.virtualChannel()
-    ..pipe(
-      IOOverrides.runWithIOOverrides(
-        () => serializeSuite(getMain),
-        _EarlyExitIOOverrides(),
-      ),
-    );
+    ..pipe(serializeSuite(getMain));
   platformChannel.sink.add(testControlChannel.id);
 
   platformChannel.stream.forEach((message) {
@@ -49,12 +43,7 @@
   var socket = await Socket.connect(args[0], int.parse(args[1]));
   var platformChannel = MultiChannel<Object?>(jsonSocketStreamChannel(socket));
   var testControlChannel = platformChannel.virtualChannel()
-    ..pipe(
-      IOOverrides.runWithIOOverrides(
-        () => serializeSuite(getMain),
-        _EarlyExitIOOverrides(),
-      ),
-    );
+    ..pipe(serializeSuite(getMain));
   platformChannel.sink.add(testControlChannel.id);
 
   unawaited(
@@ -65,10 +54,3 @@
     }),
   );
 }
-
-final class _EarlyExitIOOverrides extends IOOverrides {
-  @override
-  Never exit(int code) {
-    throw TestFailure('exit($code) was called.');
-  }
-}