@@ -9,7 +9,7 @@ use std::io::{self, Write};
99use std:: mem:: replace;
1010use std:: process:: { Child , Output } ;
1111
12- pub fn read2_abbreviated ( mut child : Child , exclude_from_len : & [ String ] ) -> io:: Result < Output > {
12+ pub fn read2_abbreviated ( mut child : Child , filter_paths_from_len : & [ String ] ) -> io:: Result < Output > {
1313 let mut stdout = ProcOutput :: new ( ) ;
1414 let mut stderr = ProcOutput :: new ( ) ;
1515
@@ -18,7 +18,7 @@ pub fn read2_abbreviated(mut child: Child, exclude_from_len: &[String]) -> io::R
1818 child. stdout . take ( ) . unwrap ( ) ,
1919 child. stderr . take ( ) . unwrap ( ) ,
2020 & mut |is_stdout, data, _| {
21- if is_stdout { & mut stdout } else { & mut stderr } . extend ( data, exclude_from_len ) ;
21+ if is_stdout { & mut stdout } else { & mut stderr } . extend ( data, filter_paths_from_len ) ;
2222 data. clear ( ) ;
2323 } ,
2424 ) ?;
@@ -29,23 +29,30 @@ pub fn read2_abbreviated(mut child: Child, exclude_from_len: &[String]) -> io::R
2929
3030const HEAD_LEN : usize = 160 * 1024 ;
3131const TAIL_LEN : usize = 256 * 1024 ;
32- const EXCLUDED_PLACEHOLDER_LEN : isize = 32 ;
32+
33+ // Whenever a path is filtered when counting the length of the output, we need to add some
34+ // placeholder length to ensure a compiler emitting only filtered paths doesn't cause a OOM.
35+ //
36+ // 32 was chosen semi-arbitrarily: it was the highest power of two that still allowed the test
37+ // suite to pass at the moment of implementing path filtering.
38+ const FILTERED_PATHS_PLACEHOLDER_LEN : usize = 32 ;
3339
3440enum ProcOutput {
35- Full { bytes : Vec < u8 > , excluded_len : isize } ,
41+ Full { bytes : Vec < u8 > , filtered_len : usize } ,
3642 Abbreviated { head : Vec < u8 > , skipped : usize , tail : Box < [ u8 ] > } ,
3743}
3844
3945impl ProcOutput {
4046 fn new ( ) -> Self {
41- ProcOutput :: Full { bytes : Vec :: new ( ) , excluded_len : 0 }
47+ ProcOutput :: Full { bytes : Vec :: new ( ) , filtered_len : 0 }
4248 }
4349
44- fn extend ( & mut self , data : & [ u8 ] , exclude_from_len : & [ String ] ) {
50+ fn extend ( & mut self , data : & [ u8 ] , filter_paths_from_len : & [ String ] ) {
4551 let new_self = match * self {
46- ProcOutput :: Full { ref mut bytes, ref mut excluded_len } => {
52+ ProcOutput :: Full { ref mut bytes, ref mut filtered_len } => {
4753 let old_len = bytes. len ( ) ;
4854 bytes. extend_from_slice ( data) ;
55+ * filtered_len += data. len ( ) ;
4956
5057 // We had problems in the past with tests failing only in some environments,
5158 // due to the length of the base path pushing the output size over the limit.
@@ -58,21 +65,25 @@ impl ProcOutput {
5865 // The compiler emitting only excluded strings is addressed by adding a
5966 // placeholder size for each excluded segment, which will eventually reach
6067 // the configured threshold.
61- for pattern in exclude_from_len {
62- let pattern_bytes = pattern . as_bytes ( ) ;
63- // We start matching `pattern_bytes - 1` into the previously loaded data,
64- // to account for the fact a pattern might be included across multiple
65- // `extend` calls. Starting from `- 1` avoids double-counting patterns .
66- let matches = ( & bytes[ ( old_len. saturating_sub ( pattern_bytes . len ( ) - 1 ) ) ..] )
67- . windows ( pattern_bytes . len ( ) )
68- . filter ( |window| window == & pattern_bytes )
68+ for path in filter_paths_from_len {
69+ let path_bytes = path . as_bytes ( ) ;
70+ // We start matching `path_bytes - 1` into the previously loaded data,
71+ // to account for the fact a path_bytes might be included across multiple
72+ // `extend` calls. Starting from `- 1` avoids double-counting paths .
73+ let matches = ( & bytes[ ( old_len. saturating_sub ( path_bytes . len ( ) - 1 ) ) ..] )
74+ . windows ( path_bytes . len ( ) )
75+ . filter ( |window| window == & path_bytes )
6976 . count ( ) ;
70- * excluded_len += matches as isize
71- * ( EXCLUDED_PLACEHOLDER_LEN - pattern_bytes. len ( ) as isize ) ;
77+ * filtered_len -= matches * path_bytes. len ( ) ;
78+
79+ // We can't just remove the length of the filtered path from the output lenght,
80+ // otherwise a compiler emitting only filtered paths would OOM compiletest. Add
81+ // a fixed placeholder length for each path to prevent that.
82+ * filtered_len += matches * FILTERED_PATHS_PLACEHOLDER_LEN ;
7283 }
7384
7485 let new_len = bytes. len ( ) ;
75- if ( new_len as isize + * excluded_len ) as usize <= HEAD_LEN + TAIL_LEN {
86+ if * filtered_len <= HEAD_LEN + TAIL_LEN {
7687 return ;
7788 }
7889
0 commit comments