Skip to content

Commit 9cc638b

Browse files
authored
Return an error when a DA entry is not correctly formatted (#1241)
It fixes #1231.
1 parent 6f83767 commit 9cc638b

File tree

1 file changed

+70
-10
lines changed

1 file changed

+70
-10
lines changed

src/parser.rs

Lines changed: 70 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)