Fix hang when separate-process test crashes (#2606)
diff --git a/pkgs/test/CHANGELOG.md b/pkgs/test/CHANGELOG.md
index 55abaf3..cd77a36 100644
--- a/pkgs/test/CHANGELOG.md
+++ b/pkgs/test/CHANGELOG.md
@@ -4,6 +4,7 @@
 * Change return type on the `body` callback argument to `group` to `void` from
   `dynamic`. This may surface cases where the group callback was erroneously
   returning an ignored value.
+* Fix a hang when a test run with `--compiler exe` crashes.
 * Require `analyzer: '>=8.0.0 <12.0.0'`
 
 ## 1.30.0
diff --git a/pkgs/test/test/runner/subprocess_crash_test.dart b/pkgs/test/test/runner/subprocess_crash_test.dart
new file mode 100644
index 0000000..e98f634
--- /dev/null
+++ b/pkgs/test/test/runner/subprocess_crash_test.dart
@@ -0,0 +1,39 @@
+// 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);
+
+  test('gracefully handles an early test suite exit', () async {
+    await d.file('test.dart', '''
+      import 'dart:io';
+
+      import 'package:test/test.dart';
+
+      void main() {
+        test('runs', () {});
+        test('exits', () {
+          exit(0);
+        });
+      }''').create();
+
+    var test = await runTest(['--compiler', 'exe', 'test.dart']);
+    expect(
+      test.stdout,
+      containsInOrder([
+        '+1: [VM, Exe] exits - did not complete [E]',
+        '+1: Some tests failed.',
+      ]),
+    );
+    await test.shouldExit(1);
+  });
+}
diff --git a/pkgs/test_core/CHANGELOG.md b/pkgs/test_core/CHANGELOG.md
index 78d3e1b..83a8423 100644
--- a/pkgs/test_core/CHANGELOG.md
+++ b/pkgs/test_core/CHANGELOG.md
@@ -4,6 +4,7 @@
 * Change return type on the `body` callback argument to `group` to `void` from
   `dynamic`. This may surface cases where the group callback was erroneously
   returning an ignored value.
+* Fix a hang when a test run with `--compiler exe` crashes.
 * Require `analyzer: '>=8.0.0 <12.0.0'`
 
 ## 0.6.16
diff --git a/pkgs/test_core/lib/src/runner/vm/platform.dart b/pkgs/test_core/lib/src/runner/vm/platform.dart
index 4ba3cad..d0e02af 100644
--- a/pkgs/test_core/lib/src/runner/vm/platform.dart
+++ b/pkgs/test_core/lib/src/runner/vm/platform.dart
@@ -76,6 +76,7 @@
       outerChannel = MultiChannel<Object?>(jsonSocketStreamChannel(socket));
       cleanupCallbacks
         ..add(serverSocket.close)
+        ..add(socket.destroy)
         ..add(process.kill);
     } else {
       var receivePort = ReceivePort();