mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 16:59:47 +00:00
[io] Fix a bug where Process.stdin.add exceptions could not be caught
Change-Id: I2383a74bfa6950ab8f8934087fb68218f06dd681 Bug:https://github.com/dart-lang/sdk/issues/48501 Tested: Unit test CoreLibraryReviewExempt: dart:io only Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/351380 Reviewed-by: Alexander Aprelev <aam@google.com> Commit-Queue: Brian Quinlan <bquinlan@google.com>
This commit is contained in:
parent
6ca01d0854
commit
9967075787
|
@ -282,6 +282,11 @@ base class _ProcessImpl extends _ProcessImplNativeWrapper implements _Process {
|
||||||
if (_modeHasStdio(_mode)) {
|
if (_modeHasStdio(_mode)) {
|
||||||
// stdin going to process.
|
// stdin going to process.
|
||||||
_stdin = new _StdSink(new _Socket._writePipe().._owner = this);
|
_stdin = new _StdSink(new _Socket._writePipe().._owner = this);
|
||||||
|
// Ignore errors if the `Process.stdin.done` future is not consumed.
|
||||||
|
// Developers catch errors writing to `Process.stdin` by consuming
|
||||||
|
// `Process.stdin.done` or calling `Process.stdin.flush()`.
|
||||||
|
_stdin!.done.ignore();
|
||||||
|
|
||||||
// stdout coming from process.
|
// stdout coming from process.
|
||||||
_stdout = new _StdStream(new _Socket._readPipe().._owner = this);
|
_stdout = new _StdStream(new _Socket._readPipe().._owner = this);
|
||||||
// stderr coming from process.
|
// stderr coming from process.
|
||||||
|
|
|
@ -492,6 +492,29 @@ abstract interface class Process {
|
||||||
Stream<List<int>> get stderr;
|
Stream<List<int>> get stderr;
|
||||||
|
|
||||||
/// The standard input stream of the process as an [IOSink].
|
/// The standard input stream of the process as an [IOSink].
|
||||||
|
///
|
||||||
|
/// `stdin` is implemented as a pipe between the parent process and the
|
||||||
|
/// spawned subprocess.
|
||||||
|
///
|
||||||
|
/// Data added to the [IOSink] (E.g. `Process.stdin.writeln('Hello!')`) is
|
||||||
|
/// written to to the pipe asynchronously.
|
||||||
|
///
|
||||||
|
/// Errors writing the data (e.g. due to the subprocess exiting) can be
|
||||||
|
/// caught by awaiting `Process.stdin.flush()`. For example:
|
||||||
|
///
|
||||||
|
/// ```dart
|
||||||
|
/// import 'dart:io';
|
||||||
|
///
|
||||||
|
/// main() async {
|
||||||
|
/// final process = await Process.start('false', const <String>[]);
|
||||||
|
/// process.stdin.writeln('Hello World\n'); // May already have exited.
|
||||||
|
/// try {
|
||||||
|
/// await process.stdin.flush();
|
||||||
|
/// } catch (e) {
|
||||||
|
/// print(e);
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
IOSink get stdin;
|
IOSink get stdin;
|
||||||
|
|
||||||
/// The process id of the process.
|
/// The process id of the process.
|
||||||
|
|
54
tests/standalone/io/process_stdin_broken_pipe_test.dart
Normal file
54
tests/standalone/io/process_stdin_broken_pipe_test.dart
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
// Copyright (c) 2024, 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.
|
||||||
|
//
|
||||||
|
// Verify that failing to write to `Process.stdin` results in an exception
|
||||||
|
// being thrown by `process.stdin.flush()` and `process.stdin.done`.
|
||||||
|
//
|
||||||
|
// See https://github.com/dart-lang/sdk/issues/48501
|
||||||
|
//
|
||||||
|
// VMOptions=
|
||||||
|
// VMOptions=--short_socket_read
|
||||||
|
// VMOptions=--short_socket_write
|
||||||
|
// VMOptions=--short_socket_read --short_socket_write
|
||||||
|
|
||||||
|
import "package:expect/expect.dart";
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:io';
|
||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
import "process_test_util.dart";
|
||||||
|
|
||||||
|
Future test(Process process) async {}
|
||||||
|
|
||||||
|
void main() async {
|
||||||
|
if (!Platform.isLinux && !Platform.isMacOS) {
|
||||||
|
print('test not supported on ${Platform.operatingSystem}');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final process = await Process.start('false', const <String>[]);
|
||||||
|
try {
|
||||||
|
for (var i = 0; i < 20; ++i) {
|
||||||
|
// Ensure that the pipe is broken while we are writing.
|
||||||
|
process.stdin.add([1, 2, 3]);
|
||||||
|
await Future.delayed(const Duration(milliseconds: 50));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await process.stdin.flush();
|
||||||
|
Expect.fail('await process.stdin.flush(): expected exception');
|
||||||
|
} on SocketException catch (e) {
|
||||||
|
Expect.equals(32, e.osError!.errorCode); // Broken pipe
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await process.stdin.done;
|
||||||
|
Expect.fail('await process.stdin.done: expected exception');
|
||||||
|
} on SocketException catch (e) {
|
||||||
|
Expect.equals(32, e.osError!.errorCode); // Broken pipe
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
process.kill();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue