Skip to content

Commit 8db7006

Browse files
committed
fix all the overruns.
1 parent 340e0ba commit 8db7006

File tree

6 files changed

+121
-32
lines changed

6 files changed

+121
-32
lines changed

fuzz/fuzz_targets/all_options.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ struct FuzzExtensionOptions {
5454
subscript: bool,
5555
subtext: bool,
5656
cjk_friendly_emphasis: bool,
57+
highlight: bool,
58+
// non-bool below
5759
header_ids: bool,
5860
front_matter_delimiter: bool,
5961
image_url_rewriter: bool,
@@ -88,6 +90,8 @@ impl FuzzExtensionOptions {
8890
subscript: self.subscript,
8991
subtext: self.subtext,
9092
cjk_friendly_emphasis: self.cjk_friendly_emphasis,
93+
highlight: self.highlight,
94+
// non-bool below
9195
header_ids: if self.header_ids {
9296
Some("user-content-".into())
9397
} else {

src/html.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1622,9 +1622,10 @@ fn tagfilter(literal: &str) -> bool {
16221622
for t in TAGFILTER_BLACKLIST.iter() {
16231623
if lc.starts_with(t) {
16241624
let j = i + t.len();
1625-
return isspace(bytes[j])
1626-
|| bytes[j] == b'>'
1627-
|| (bytes[j] == b'/' && bytes.len() >= j + 2 && bytes[j + 1] == b'>');
1625+
let Some(&b) = bytes.get(j) else {
1626+
return false;
1627+
};
1628+
return isspace(b) || b == b'>' || (b == b'/' && bytes.get(j + 1) == Some(&b'>'));
16281629
}
16291630
}
16301631

src/parser/mod.rs

Lines changed: 65 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ pub fn parse_document<'a>(arena: &'a Arena<'a>, md: &str, options: &Options) ->
5656

5757
pub struct Parser<'a, 'o, 'c> {
5858
arena: &'a Arena<'a>,
59+
options: &'o Options<'c>,
5960
refmap: RefMap,
6061
footnote_defs: inlines::FootnoteDefs<'a>,
6162
root: Node<'a>,
@@ -73,7 +74,6 @@ pub struct Parser<'a, 'o, 'c> {
7374
curline_end_col: usize,
7475
last_line_length: usize,
7576
total_size: usize,
76-
options: &'o Options<'c>,
7777
}
7878

7979
/// A reference link's resolved details.
@@ -100,6 +100,7 @@ where
100100
fn new(arena: &'a Arena<'a>, root: Node<'a>, options: &'o Options<'c>) -> Self {
101101
Parser {
102102
arena,
103+
options,
103104
refmap: RefMap::new(),
104105
footnote_defs: inlines::FootnoteDefs::new(),
105106
root,
@@ -117,7 +118,6 @@ where
117118
curline_end_col: 0,
118119
last_line_length: 0,
119120
total_size: 0,
120-
options,
121121
}
122122
}
123123

@@ -371,17 +371,24 @@ where
371371
}
372372

373373
self.indent = self.first_nonspace_column - self.column;
374-
self.blank = self.first_nonspace < line.len()
375-
&& strings::is_line_end_char(bytes[self.first_nonspace]);
374+
self.blank = bytes
375+
.get(self.first_nonspace)
376+
.map_or(true, |&b| strings::is_line_end_char(b));
376377
}
377378

378379
fn parse_block_quote_prefix(&mut self, line: &str) -> bool {
379380
let bytes = line.as_bytes();
380381
let indent = self.indent;
381-
if indent <= 3 && bytes[self.first_nonspace] == b'>' && self.is_not_greentext(line) {
382+
if indent <= 3
383+
&& bytes.get(self.first_nonspace) == Some(&b'>')
384+
&& self.is_not_greentext(line)
385+
{
382386
self.advance_offset(line, indent + 1, true);
383387

384-
if strings::is_space_or_tab(bytes[self.offset]) {
388+
if bytes
389+
.get(self.offset)
390+
.map_or(false, |&b| strings::is_space_or_tab(b))
391+
{
385392
self.advance_offset(line, 1, true);
386393
}
387394

@@ -393,7 +400,10 @@ where
393400

394401
fn is_not_greentext(&self, line: &str) -> bool {
395402
!self.options.extension.greentext
396-
|| strings::is_space_or_tab(line.as_bytes()[self.first_nonspace + 1])
403+
|| line
404+
.as_bytes()
405+
.get(self.first_nonspace + 1)
406+
.map_or(false, |&b| strings::is_space_or_tab(b))
397407
}
398408

399409
fn parse_node_item_prefix(&mut self, line: &str, container: Node<'a>, nl: &NodeList) -> bool {
@@ -456,7 +466,7 @@ where
456466
}
457467

458468
let bytes = line.as_bytes();
459-
let matched = if self.indent <= 3 && bytes[self.first_nonspace] == fence_char {
469+
let matched = if self.indent <= 3 && bytes.get(self.first_nonspace) == Some(&fence_char) {
460470
scanners::close_code_fence(&line[self.first_nonspace..]).unwrap_or(0)
461471
} else {
462472
0
@@ -472,7 +482,11 @@ where
472482
}
473483

474484
let mut i = fence_offset;
475-
while i > 0 && strings::is_space_or_tab(bytes[self.offset]) {
485+
while i > 0
486+
&& bytes
487+
.get(self.offset)
488+
.map_or(false, |&b| strings::is_space_or_tab(b))
489+
{
476490
self.advance_offset(line, 1, true);
477491
i -= 1;
478492
}
@@ -515,7 +529,7 @@ where
515529
};
516530

517531
let bytes = line.as_bytes();
518-
let matched = if self.indent <= 3 && bytes[self.first_nonspace] == b'>' {
532+
let matched = if self.indent <= 3 && bytes.get(self.first_nonspace) == Some(&b'>') {
519533
scanners::close_multiline_block_quote_fence(&line[self.first_nonspace..]).unwrap_or(0)
520534
} else {
521535
0
@@ -540,7 +554,11 @@ where
540554
}
541555

542556
let mut i = fence_offset;
543-
while i > 0 && strings::is_space_or_tab(bytes[self.offset]) {
557+
while i > 0
558+
&& bytes
559+
.get(self.offset)
560+
.map_or(false, |&b| strings::is_space_or_tab(b))
561+
{
544562
self.advance_offset(line, 1, true);
545563
i -= 1;
546564
}
@@ -586,14 +604,16 @@ where
586604
}
587605
}
588606

589-
// Compute a candidate end position for the container by looking
590-
// at its deepest-last descendant. Return it only if it has a
591-
// non-zero column; the caller can fall back to the container's
592-
// start position if desired.
593-
if let Some(mut last_desc) = container.last_child() {
594-
while let Some(ld) = last_desc.last_child() {
595-
last_desc = ld;
596-
}
607+
// Compute a candidate end position for the container by looking at
608+
// its last child. Return it only if it has a non-zero column; the
609+
// caller can fall back to the container's start position if desired.
610+
//
611+
// We originally looked at the deepest-last descendant, but there
612+
// may be intermediate containers that are larger than it, which we
613+
// should use instead. If looking just at the last child isn't
614+
// enough in some circumstances, we should consider using the widest
615+
// of the last descendants.
616+
if let Some(last_desc) = container.last_child() {
597617
let last_end = last_desc.data().sourcepos.end;
598618
if last_end.column != 0 {
599619
return Some(last_end);
@@ -695,7 +715,8 @@ where
695715
}
696716

697717
fn detect_alert(&self, line: &str) -> Option<AlertType> {
698-
if self.options.extension.alerts && line.as_bytes()[self.first_nonspace] == b'>' {
718+
if self.options.extension.alerts && line.as_bytes().get(self.first_nonspace) == Some(&b'>')
719+
{
699720
scanners::alert_start(&line[self.first_nonspace..])
700721
} else {
701722
None
@@ -1033,7 +1054,11 @@ where
10331054

10341055
let offset = self.first_nonspace + matched - self.offset;
10351056
self.advance_offset(line, offset, false);
1036-
if strings::is_space_or_tab(line.as_bytes()[self.offset]) {
1057+
if line
1058+
.as_bytes()
1059+
.get(self.offset)
1060+
.map_or(false, |&b| strings::is_space_or_tab(b))
1061+
{
10371062
self.advance_offset(line, 1, true);
10381063
}
10391064

@@ -1172,12 +1197,20 @@ where
11721197
(self.partially_consumed_tab, self.offset, self.column);
11731198

11741199
let bytes = line.as_bytes();
1175-
while self.column - save_column <= 5 && strings::is_space_or_tab(bytes[self.offset]) {
1200+
while self.column - save_column <= 5
1201+
&& bytes
1202+
.get(self.offset)
1203+
.map_or(false, |&b| strings::is_space_or_tab(b))
1204+
{
11761205
self.advance_offset(line, 1, true);
11771206
}
11781207

11791208
let i = self.column - save_column;
1180-
if !(1..5).contains(&i) || strings::is_line_end_char(bytes[self.offset]) {
1209+
if !(1..5).contains(&i)
1210+
|| bytes
1211+
.get(self.offset)
1212+
.map_or(false, |&b| strings::is_line_end_char(b))
1213+
{
11811214
nl.padding = matched + 1;
11821215
self.offset = save_offset;
11831216
self.column = save_column;
@@ -1559,8 +1592,11 @@ where
15591592
_ => false,
15601593
} {
15611594
ast.sourcepos.end = (self.line_number, self.curline_end_col).into();
1562-
} else if matches!(ast.value, NodeValue::ThematicBreak) {
1563-
// sourcepos.end set during opening.
1595+
} else if matches!(
1596+
ast.value,
1597+
NodeValue::ThematicBreak | NodeValue::TableRow(..) | NodeValue::Table(..)
1598+
) {
1599+
// sourcepos.end set by itself or managed below.
15641600
} else {
15651601
ast.sourcepos.end = (self.line_number - 1, self.last_line_length).into();
15661602
}
@@ -1630,7 +1666,7 @@ where
16301666
}
16311667
nl.tight = self.determine_list_tight(node);
16321668
}
1633-
NodeValue::FootnoteDefinition(_) => {
1669+
NodeValue::Table(..) | NodeValue::FootnoteDefinition(_) => {
16341670
if let Some(candidate_end) = self.fix_zero_end_columns(node) {
16351671
ast.sourcepos.end = candidate_end;
16361672
}
@@ -2134,6 +2170,9 @@ fn parse_list_marker(
21342170
let mut i = pos;
21352171
while strings::is_space_or_tab(bytes[i]) {
21362172
i += 1;
2173+
if i == bytes.len() {
2174+
return None;
2175+
}
21372176
}
21382177
if strings::is_line_end_char(bytes[i]) {
21392178
return None;

src/parser/table.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -166,9 +166,7 @@ fn try_opening_row<'a>(
166166
NodeValue::TableRow(false),
167167
sourcepos.start.column,
168168
);
169-
{
170-
new_row.data_mut().sourcepos.end.column = sourcepos.end.column;
171-
}
169+
new_row.data_mut().sourcepos.end.column = parser.curline_end_col;
172170

173171
let mut i = 0;
174172
let mut last_column = sourcepos.start.column;

src/strings.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,9 @@ pub fn remove_trailing_blank_lines_slice(line: &str) -> &str {
126126

127127
fn remove_trailing_blank_lines_ix(line: &str) -> usize {
128128
let line_bytes = line.as_bytes();
129+
if line.len() == 0 {
130+
return 0;
131+
}
129132
let mut i = line.len() - 1;
130133
loop {
131134
let c = line_bytes[i];

src/tests/fuzz.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,3 +496,47 @@ fn tasklist_and_escapes_do_not_play() {
496496
])
497497
);
498498
}
499+
500+
#[test]
501+
fn dont_try_this_at_home() {
502+
assert_ast_match!(
503+
[extension.alerts, extension.table, parse.ignore_setext],
504+
"\u{3}\n--\nT",
505+
(document (1:1-3:1) [
506+
(table (1:1-3:1) [
507+
(table_row (1:1-1:1) [
508+
(table_cell (1:1-1:1) [
509+
(text (1:1-1:1) "\u{3}")
510+
])
511+
])
512+
(table_row (3:1-3:1) [
513+
(table_cell (3:1-3:1) [
514+
(text (3:1-3:1) "T")
515+
])
516+
])
517+
])
518+
])
519+
);
520+
}
521+
522+
#[test]
523+
fn cargo_run_no_cargo_road() {
524+
assert_ast_match!(
525+
[],
526+
"\t",
527+
(document (1:1-1:1))
528+
);
529+
}
530+
531+
#[test]
532+
fn oye_siri_prende_las_luces() {
533+
assert_ast_match!(
534+
[],
535+
"* ",
536+
(document (1:1-1:2) [
537+
(list (1:1-1:2) [
538+
(item (1:1-1:2))
539+
])
540+
])
541+
);
542+
}

0 commit comments

Comments
 (0)