@@ -90,7 +90,6 @@ impl StderrForwarder {
90
90
}
91
91
}
92
92
93
- #[ allow( clippy:: uninit_vec) ]
94
93
fn forward_available ( & mut self ) -> bool {
95
94
if let Some ( ( stderr, buffer) ) = self . inner . as_mut ( ) {
96
95
loop {
@@ -104,7 +103,7 @@ impl StderrForwarder {
104
103
let to_reserve = if self . is_non_blocking && !self . bytes_available_failed {
105
104
match crate :: parallel:: stderr:: bytes_available ( stderr) {
106
105
#[ cfg( windows) ]
107
- Ok ( 0 ) => return false ,
106
+ Ok ( 0 ) => break false ,
108
107
#[ cfg( unix) ]
109
108
Ok ( 0 ) => {
110
109
// On Unix, depending on the implementation, we may sometimes get 0 in a
@@ -120,7 +119,7 @@ impl StderrForwarder {
120
119
write_warning ( & buffer[ ..] ) ;
121
120
}
122
121
self . inner = None ;
123
- return true ;
122
+ break true ;
124
123
}
125
124
#[ cfg( unix) ]
126
125
Err ( _) => {
@@ -137,32 +136,21 @@ impl StderrForwarder {
137
136
} ;
138
137
buffer. reserve ( to_reserve) ;
139
138
140
- // SAFETY: 1) the length is set to the capacity, so we are never using memory beyond
141
- // the underlying buffer and 2) we always call `truncate` below to set the len back
142
- // to the initialized data.
143
- unsafe {
144
- buffer. set_len ( buffer. capacity ( ) ) ;
145
- }
146
- match stderr. read ( & mut buffer[ old_data_end..] ) {
139
+ // Safety: stderr.read only writes to the spare part of the buffer, it never reads from it
140
+ match stderr
141
+ . read ( unsafe { & mut * ( buffer. spare_capacity_mut ( ) as * mut _ as * mut [ u8 ] ) } )
142
+ {
147
143
Err ( err) if err. kind ( ) == std:: io:: ErrorKind :: WouldBlock => {
148
144
// No data currently, yield back.
149
- buffer. truncate ( old_data_end) ;
150
- return false ;
145
+ break false ;
151
146
}
152
147
Err ( err) if err. kind ( ) == std:: io:: ErrorKind :: Interrupted => {
153
148
// Interrupted, try again.
154
- buffer. truncate ( old_data_end) ;
155
- }
156
- Ok ( 0 ) | Err ( _) => {
157
- // End of stream: flush remaining data and bail.
158
- if old_data_end > 0 {
159
- write_warning ( & buffer[ ..old_data_end] ) ;
160
- }
161
- self . inner = None ;
162
- return true ;
149
+ continue ;
163
150
}
164
- Ok ( bytes_read) => {
165
- buffer. truncate ( old_data_end + bytes_read) ;
151
+ Ok ( bytes_read) if bytes_read != 0 => {
152
+ // Safety: bytes_read bytes is written to spare part of the buffer
153
+ unsafe { buffer. set_len ( old_data_end + bytes_read) } ;
166
154
let mut consumed = 0 ;
167
155
for line in buffer. split_inclusive ( |& b| b == b'\n' ) {
168
156
// Only forward complete lines, leave the rest in the buffer.
@@ -173,6 +161,19 @@ impl StderrForwarder {
173
161
}
174
162
buffer. drain ( ..consumed) ;
175
163
}
164
+ res => {
165
+ // End of stream: flush remaining data and bail.
166
+ if old_data_end > 0 {
167
+ write_warning ( & buffer[ ..old_data_end] ) ;
168
+ }
169
+ if let Err ( err) = res {
170
+ write_warning (
171
+ format ! ( "Failed to read from child stderr: {err}" ) . as_bytes ( ) ,
172
+ ) ;
173
+ }
174
+ self . inner . take ( ) ;
175
+ break true ;
176
+ }
176
177
}
177
178
}
178
179
} else {
0 commit comments