@@ -191,9 +191,19 @@ pub fn parse_lcov(
191191 }
192192
193193 let key = iter
194- . take_while ( |& & c| c != b':' )
195- . fold ( * c as u32 , |r, & x| r * ( 1 << 8 ) + u32:: from ( x) ) ;
196- match key {
194+ . take_while ( |& & c| c. is_ascii_uppercase ( ) )
195+ . try_fold ( * c as u32 , |r, & x| {
196+ r. checked_mul ( 1 << 8 ) ?. checked_add ( u32:: from ( x) )
197+ } ) ;
198+
199+ if key. is_none ( ) {
200+ return Err ( ParserError :: InvalidRecord ( format ! (
201+ "Invalid key at line {}" ,
202+ line
203+ ) ) ) ;
204+ }
205+
206+ match key. unwrap ( ) {
197207 SF => {
198208 // SF:string
199209 cur_file = Some (
@@ -204,9 +214,19 @@ pub fn parse_lcov(
204214 }
205215 DA => {
206216 // DA:uint,int
217+ if let Some ( c) = iter. peek ( ) {
218+ if !c. is_ascii_digit ( ) {
219+ return Err ( ParserError :: InvalidRecord ( format ! (
220+ "DA at line {}" ,
221+ line
222+ ) ) ) ;
223+ }
224+ }
225+
207226 let line_no = iter
208- . take_while ( |& & c| c != b',' )
227+ . take_while ( |& & c| c. is_ascii_digit ( ) )
209228 . fold ( 0 , |r, & x| r * 10 + u32:: from ( x - b'0' ) ) ;
229+
210230 if iter. peek ( ) . is_none ( ) {
211231 return Err ( ParserError :: InvalidRecord ( format ! ( "DA at line {}" , line) ) ) ;
212232 }
@@ -215,7 +235,7 @@ pub fn parse_lcov(
215235 iter. take_while ( |& & c| c != b'\n' ) . last ( ) ;
216236 0
217237 } else {
218- iter. take_while ( |& & c| c != b'\n' && c != b'\r' )
238+ iter. take_while ( |& & c| c. is_ascii_digit ( ) )
219239 . fold ( u64:: from ( * c - b'0' ) , |r, & x| {
220240 r * 10 + u64:: from ( x - b'0' )
221241 } )
@@ -227,8 +247,16 @@ pub fn parse_lcov(
227247 }
228248 FN => {
229249 // FN:int,string
250+ if let Some ( c) = iter. peek ( ) {
251+ if !c. is_ascii_digit ( ) {
252+ return Err ( ParserError :: InvalidRecord ( format ! (
253+ "FN at line {}" ,
254+ line
255+ ) ) ) ;
256+ }
257+ }
230258 let start = iter
231- . take_while ( |& & c| c != b',' )
259+ . take_while ( |& & c| c. is_ascii_digit ( ) )
232260 . fold ( 0 , |r, & x| r * 10 + u32:: from ( x - b'0' ) ) ;
233261 if iter. peek ( ) . is_none ( ) {
234262 return Err ( ParserError :: InvalidRecord ( format ! ( "FN at line {}" , line) ) ) ;
@@ -255,8 +283,16 @@ pub fn parse_lcov(
255283 }
256284 FNDA => {
257285 // FNDA:int,string
286+ if let Some ( c) = iter. peek ( ) {
287+ if !c. is_ascii_digit ( ) {
288+ return Err ( ParserError :: InvalidRecord ( format ! (
289+ "FNDA at line {}" ,
290+ line
291+ ) ) ) ;
292+ }
293+ }
258294 let executed = iter
259- . take_while ( |& & c| c != b',' )
295+ . take_while ( |& & c| c. is_ascii_digit ( ) )
260296 . fold ( 0 , |r, & x| r * 10 + u64:: from ( x - b'0' ) ) ;
261297 if iter. peek ( ) . is_none ( ) {
262298 return Err ( ParserError :: InvalidRecord ( format ! (
@@ -280,8 +316,16 @@ pub fn parse_lcov(
280316 BRDA => {
281317 // BRDA:int,int,int,int or -
282318 if branch_enabled {
319+ if let Some ( c) = iter. peek ( ) {
320+ if !c. is_ascii_digit ( ) {
321+ return Err ( ParserError :: InvalidRecord ( format ! (
322+ "BRDA at line {}" ,
323+ line
324+ ) ) ) ;
325+ }
326+ }
283327 let line_no = iter
284- . take_while ( |& & c| c != b',' )
328+ . take_while ( |& & c| c. is_ascii_digit ( ) )
285329 . fold ( 0 , |r, & x| r * 10 + u32:: from ( x - b'0' ) ) ;
286330 if iter. peek ( ) . is_none ( ) {
287331 return Err ( ParserError :: InvalidRecord ( format ! (
@@ -290,7 +334,7 @@ pub fn parse_lcov(
290334 ) ) ) ;
291335 }
292336 let _block_number = iter
293- . take_while ( |& & c| c != b',' )
337+ . take_while ( |& & c| c. is_ascii_digit ( ) )
294338 . fold ( 0 , |r, & x| r * 10 + u64:: from ( x - b'0' ) ) ;
295339 if iter. peek ( ) . is_none ( ) {
296340 return Err ( ParserError :: InvalidRecord ( format ! (
@@ -299,7 +343,7 @@ pub fn parse_lcov(
299343 ) ) ) ;
300344 }
301345 let branch_number = iter
302- . take_while ( |& & c| c != b',' )
346+ . take_while ( |& & c| c. is_ascii_digit ( ) )
303347 . fold ( 0 , |r, & x| r * 10 + u32:: from ( x - b'0' ) ) ;
304348 if iter. peek ( ) . is_none ( ) {
305349 return Err ( ParserError :: InvalidRecord ( format ! (
@@ -1208,6 +1252,22 @@ mod tests {
12081252 assert ! ( result. is_err( ) ) ;
12091253 }
12101254
1255+ #[ allow( non_snake_case) ]
1256+ #[ test]
1257+ fn test_lcov_parser_empty_DA_record ( ) {
1258+ let buf = "DA:152,4
1259+ DA:153,4
1260+ DA:154,8
1261+ DA:156,12
1262+ DA
1263+ TN:http_3a_2f_2fweb_2dplatform_2etest_3a8000_2freferrer_2dpolicy_2fgen_2fsrcdoc_2dinherit_2emeta_2funset_2fiframe_2dtag_2ehttp_2ehtml_2c_20about_3ablank"
1264+ . as_bytes ( ) . to_vec ( ) ;
1265+ let result = parse_lcov ( buf, true ) ;
1266+ assert ! ( result. is_err( ) ) ;
1267+ let error = result. unwrap_err ( ) ;
1268+ assert_eq ! ( error. to_string( ) , "Invalid record: 'DA at line 5'" ) ;
1269+ }
1270+
12111271 #[ test]
12121272 fn test_parser ( ) {
12131273 let results = parse_gcov ( Path :: new ( "./test/prova.gcov" ) ) . unwrap ( ) ;
0 commit comments