fix: do not increment current_included_range_index past included_range_count in __do_advance

This commit is contained in:
Amaan Qureshi 2023-08-25 18:28:27 -04:00 committed by Andrew Hlynskyi
parent 8e718fcb1c
commit a4ea4737ac
6 changed files with 95 additions and 1 deletions

View file

@ -5,6 +5,7 @@ mod helpers;
mod highlight_test;
mod language_test;
mod node_test;
mod parser_hang_test;
mod parser_test;
mod pathological_test;
mod query_test;

View file

@ -0,0 +1,61 @@
use pretty_assertions::assert_eq;
use tree_sitter::Parser;
use crate::{
generate::generate_parser_for_grammar,
tests::helpers::fixtures::{fixtures_dir, get_test_language},
};
#[test]
fn test_grammar_that_should_hang_and_not_segfault() {
use std::sync::mpsc;
let (tx, rx) = mpsc::channel();
std::thread::spawn(move || {
let (parser_name, parser_code) = generate_parser_for_grammar(
r#"
{
"name": "get_col_should_hang_not_crash",
"rules": {
"source_file": {
"type": "SEQ",
"members": [ { "type": "SYMBOL", "name": "test" } ]
}
},
"extras": [ { "type": "PATTERN", "value": "\\s" } ],
"externals": [ { "type": "SYMBOL", "name": "test" } ]
}
"#,
)
.unwrap();
let mut parser = Parser::new();
parser
.set_language(get_test_language(
&parser_name,
&parser_code,
Some(
fixtures_dir()
.join("test_grammars")
.join("get_col_should_hang_not_crash")
.as_path(),
),
))
.unwrap();
let code_that_should_hang = "\nHello";
parser.parse(code_that_should_hang, None).unwrap();
// Won't be reached
let _ = tx.send(());
});
// Ok signifies that it did not hang
// RecvTimeoutError::Disconnected signifies that the parser thread exited unexpectedly (crashed)
assert_eq!(
rx.recv_timeout(std::time::Duration::from_secs(5)),
Err(mpsc::RecvTimeoutError::Timeout)
);
}

View file

@ -172,7 +172,9 @@ static void ts_lexer__do_advance(Lexer *self, bool skip) {
self->current_position.bytes >= current_range->end_byte ||
current_range->end_byte == current_range->start_byte
) {
self->current_included_range_index++;
if (self->current_included_range_index < self->included_range_count) {
self->current_included_range_index++;
}
if (self->current_included_range_index < self->included_range_count) {
current_range++;
self->current_position = (Length) {

View file

@ -0,0 +1,13 @@
module.exports = grammar({
name: 'get_col_should_hang_not_crash',
externals: $ => [
$.test,
],
rules: {
source_file: $ => seq(
$.test
),
},
});

View file

@ -0,0 +1,17 @@
#include <tree_sitter/parser.h>
unsigned tree_sitter_get_col_should_hang_not_crash_external_scanner_serialize() { return 0; }
void tree_sitter_get_col_should_hang_not_crash_external_scanner_deserialize() {}
void *tree_sitter_get_col_should_hang_not_crash_external_scanner_create() { return NULL; }
void tree_sitter_get_col_should_hang_not_crash_external_scanner_destroy() {}
bool tree_sitter_get_col_should_hang_not_crash_external_scanner_scan(void *payload, TSLexer *lexer,
const bool *valid_symbols) {
while (true) {
lexer->advance(lexer, false);
lexer->get_column(lexer);
}
}