| Index: lib/src/util/io.dart | 
| diff --git a/lib/src/util/io.dart b/lib/src/util/io.dart | 
| index cb35ed7c25a302d53e08aaa633f7b6fa60b27520..dbe34f4e01ff7965590232a7a83c39c58b672b53 100644 | 
| --- a/lib/src/util/io.dart | 
| +++ b/lib/src/util/io.dart | 
| @@ -14,6 +14,12 @@ import 'package:pub_semver/pub_semver.dart'; | 
| import '../backend/operating_system.dart'; | 
| import '../runner/application_exception.dart'; | 
|  | 
| +/// The ASCII code for a newline character. | 
| +const _newline = 0xA; | 
| + | 
| +/// The ASCII code for a carriage return character. | 
| +const _carriageReturn = 0xD; | 
| + | 
| /// The root directory of the Dart SDK. | 
| final String sdkDir = | 
| p.dirname(p.dirname(Platform.executable)); | 
| @@ -95,6 +101,30 @@ Future withTempDir(Future fn(String path)) { | 
| }); | 
| } | 
|  | 
| +/// Return a transformation of [input] with all null bytes removed. | 
| +/// | 
| +/// This works around the combination of issue 23295 and 22667 by removing null | 
| +/// bytes. This workaround can be removed when either of those are fixed in the | 
| +/// oldest supported SDK. | 
| +/// | 
| +/// It also somewhat works around issue 23303 by removing any carriage returns | 
| +/// that are followed by newlines, to ensure that carriage returns aren't | 
| +/// doubled up in the output. This can be removed when the issue is fixed in the | 
| +/// oldest supported SDk. | 
| +Stream<List<int>> santizeForWindows(Stream<List<int>> input) { | 
| +  if (!Platform.isWindows) return input; | 
| + | 
| +  return input.map((list) { | 
| +    var previous; | 
| +    return list.reversed.where((byte) { | 
| +      if (byte == 0) return false; | 
| +      if (byte == _carriageReturn && previous == _newline) return false; | 
| +      previous = byte; | 
| +      return true; | 
| +    }).toList().reversed.toList(); | 
| +  }); | 
| +} | 
| + | 
| /// Creates a URL string for [address]:[port]. | 
| /// | 
| /// Handles properly formatting IPv6 addresses. | 
|  |