26
26
use libfuzzer_sys:: fuzz_target;
27
27
28
28
use std:: fmt:: Debug ;
29
- use std:: io:: Read ;
29
+ use std:: io:: { BufRead , BufReader , Cursor , Seek } ;
30
30
31
31
mod smal_buf {
32
+ use std:: io:: { BufRead , Cursor , Read , Seek } ;
32
33
33
- use std:: io:: Read ;
34
-
35
- /// A reader that reads at most `n` bytes.
36
- pub struct SmalBuf < R : Read > {
37
- inner : R ,
38
- cap : usize ,
34
+ /// A reader that returns at most 1 byte in a single call to `read`.
35
+ pub struct SmalBuf {
36
+ inner : Cursor < Vec < u8 > > ,
39
37
}
40
38
41
- impl < R : Read > SmalBuf < R > {
42
- pub fn new ( inner : R , cap : usize ) -> Self {
43
- SmalBuf { inner, cap }
39
+ impl SmalBuf {
40
+ pub fn new ( inner : Vec < u8 > ) -> Self {
41
+ SmalBuf {
42
+ inner : Cursor :: new ( inner) ,
43
+ }
44
44
}
45
45
}
46
46
47
- impl < R : Read > Read for SmalBuf < R > {
47
+ impl Read for SmalBuf {
48
48
fn read ( & mut self , buf : & mut [ u8 ] ) -> std:: io:: Result < usize > {
49
- let len = buf. len ( ) . min ( self . cap ) ;
50
- self . inner . read ( & mut buf[ ..len] )
49
+ if buf. is_empty ( ) {
50
+ return Ok ( 0 ) ;
51
+ }
52
+ self . inner . read ( & mut buf[ ..1 ] )
53
+ }
54
+ }
55
+ impl BufRead for SmalBuf {
56
+ fn fill_buf ( & mut self ) -> std:: io:: Result < & [ u8 ] > {
57
+ let buf = self . inner . fill_buf ( ) ?;
58
+ Ok ( & buf[ ..buf. len ( ) . min ( 1 ) ] )
59
+ }
60
+
61
+ fn consume ( & mut self , amt : usize ) {
62
+ self . inner . consume ( amt) ;
63
+ }
64
+ }
65
+ impl Seek for SmalBuf {
66
+ fn seek ( & mut self , pos : std:: io:: SeekFrom ) -> std:: io:: Result < u64 > {
67
+ self . inner . seek ( pos)
51
68
}
52
69
}
53
70
}
54
71
55
72
mod intermittent_eofs {
56
73
57
74
use std:: cell:: Cell ;
58
- use std:: io:: Read ;
75
+ use std:: io:: { BufRead , Read , Seek } ;
59
76
use std:: rc:: Rc ;
60
77
61
78
/// A reader that returns `std::io::ErrorKind::UnexpectedEof` errors in every other read.
62
79
/// EOFs can be temporarily disabled and re-enabled later using the associated `EofController`.
63
- pub struct IntermittentEofs < R : Read > {
80
+ pub struct IntermittentEofs < R : BufRead + Seek > {
64
81
inner : R ,
65
82
66
83
/// Controls whether intermittent EOFs happen at all.
@@ -71,7 +88,7 @@ mod intermittent_eofs {
71
88
eof_soon : bool ,
72
89
}
73
90
74
- impl < R : Read > IntermittentEofs < R > {
91
+ impl < R : BufRead + Seek > IntermittentEofs < R > {
75
92
pub fn new ( inner : R ) -> Self {
76
93
Self {
77
94
inner,
@@ -85,7 +102,7 @@ mod intermittent_eofs {
85
102
}
86
103
}
87
104
88
- impl < R : Read > Read for IntermittentEofs < R > {
105
+ impl < R : BufRead + Seek > Read for IntermittentEofs < R > {
89
106
fn read ( & mut self , buf : & mut [ u8 ] ) -> std:: io:: Result < usize > {
90
107
if self . controller . are_intermittent_eofs_enabled ( ) && self . eof_soon {
91
108
self . eof_soon = false ;
@@ -101,6 +118,20 @@ mod intermittent_eofs {
101
118
inner_result
102
119
}
103
120
}
121
+ impl < R : BufRead + Seek > BufRead for IntermittentEofs < R > {
122
+ fn fill_buf ( & mut self ) -> std:: io:: Result < & [ u8 ] > {
123
+ self . inner . fill_buf ( )
124
+ }
125
+
126
+ fn consume ( & mut self , amt : usize ) {
127
+ self . inner . consume ( amt) ;
128
+ }
129
+ }
130
+ impl < R : BufRead + Seek > Seek for IntermittentEofs < R > {
131
+ fn seek ( & mut self , pos : std:: io:: SeekFrom ) -> std:: io:: Result < u64 > {
132
+ self . inner . seek ( pos)
133
+ }
134
+ }
104
135
105
136
pub struct EofController {
106
137
are_intermittent_eofs_enabled : Cell < bool > ,
@@ -141,18 +172,24 @@ fuzz_target!(|data: &[u8]| {
141
172
let _ = test_data( data) ;
142
173
} ) ;
143
174
175
+ trait BufReadSeek : BufRead + Seek { }
176
+ impl < T > BufReadSeek for T where T : BufRead + Seek { }
177
+
144
178
#[ inline( always) ]
145
179
fn test_data < ' a > ( data : & ' a [ u8 ] ) -> Result < ( ) , ( ) > {
146
- let baseline_reader = Box :: new ( data) ;
147
- let byte_by_byte_reader = Box :: new ( smal_buf:: SmalBuf :: new ( data, 1 ) ) ;
180
+ let baseline_reader = Box :: new ( Cursor :: new ( data) ) ;
181
+ let byte_by_byte_reader = Box :: new ( smal_buf:: SmalBuf :: new ( data. to_owned ( ) ) ) ;
148
182
let intermittent_eofs_reader = Box :: new ( intermittent_eofs:: IntermittentEofs :: new (
149
- smal_buf:: SmalBuf :: new ( data, 1 ) ,
183
+ smal_buf:: SmalBuf :: new ( data. to_owned ( ) ) ,
150
184
) ) ;
151
185
let intermittent_eofs_controller = intermittent_eofs_reader. controller ( ) ;
152
- let data_readers: Vec < Box < dyn Read + ' a > > = vec ! [
153
- baseline_reader,
154
- byte_by_byte_reader,
155
- intermittent_eofs_reader,
186
+
187
+ // `Decoder` used to internally wrap the provided reader with a `BufReader`. Now that it has
188
+ // been removed, fuzzing would be far too slow if we didn't use a BufReader here.
189
+ let data_readers: Vec < BufReader < Box < dyn BufReadSeek > > > = vec ! [
190
+ BufReader :: new( baseline_reader) ,
191
+ BufReader :: new( byte_by_byte_reader) ,
192
+ BufReader :: new( intermittent_eofs_reader) ,
156
193
] ;
157
194
158
195
let decoders = data_readers
@@ -196,8 +233,14 @@ fn test_data<'a>(data: &'a [u8]) -> Result<(), ()> {
196
233
. zip ( buffers. iter_mut ( ) )
197
234
. enumerate ( )
198
235
. map ( |( i, ( png_reader, buffer) ) | {
199
- let eof_controller = if i == 2 { Some ( & intermittent_eofs_controller) } else { None } ;
200
- retry_after_eofs ( eof_controller, || png_reader. next_frame ( buffer. as_mut_slice ( ) ) )
236
+ let eof_controller = if i == 2 {
237
+ Some ( & intermittent_eofs_controller)
238
+ } else {
239
+ None
240
+ } ;
241
+ retry_after_eofs ( eof_controller, || {
242
+ png_reader. next_frame ( buffer. as_mut_slice ( ) )
243
+ } )
201
244
} )
202
245
. assert_all_results_are_consistent ( )
203
246
. collect :: < Result < Vec < _ > , _ > > ( )
@@ -222,7 +265,7 @@ fn retry_after_eofs<T>(
222
265
}
223
266
}
224
267
}
225
- } ,
268
+ }
226
269
_ => ( ) ,
227
270
}
228
271
break result;
0 commit comments