Panic on `&&` and `||` operators
bug: Logical operators &&
and ||
may panic if not followed by a command.
expect: syntax error.
related: none.
test case#1 code: input
ls &&||
test case#2 code: input
ls &&;
actual: output
[...]
thread 'main' panicked at 'begin <= end (6 <= 5) when slicing `ls &&||`', src/lib/parser/statement/splitter.rs:55:35
stack backtrace:
[...]
4: ion_shell::parser::statement::splitter::StatementSplitter::get_statement
5: <ion_shell::parser::statement::splitter::StatementSplitter as core::iter::traits::iterator::Iterator>::next
6: ion_shell::shell::flow::<impl ion_shell::shell::Shell>::on_command
7: ion::binary::InteractiveShell::exec
8: ion::binary::InteractiveShell::execute_interactive
9: ion::main
Abandon (core dumped)
expect: output
ion: syntax error: expected command, but found `||`
version: ion 1.0.0-alpha (x86_64-unknown-linux-gnu), rev 814ed5a8
interaction: none
According to backtrace, the bug came from src/lib/parser/statement/splitter.rs:55:35 which is :
fn get_statement(&self, start: usize, end: usize) -> StatementVariant<'a> {
if self.logical == LogicalOp::And {
StatementVariant::And(self.data[start + 1..end].trim())
^^^^^^^^^^^^^^^
} else if self.logical == LogicalOp::Or {
StatementVariant::Or(self.data[start + 1..end].trim())
} else {
StatementVariant::Default(self.data[start..end].trim())
}
}
called by src/lib/parser/statement/splitter.rs:160:42 and src/lib/parser/statement/splitter.rs:171:42 :
b';' if self.paren_level == 0 => {
let statement = self.get_statement(start, i);
^^^^^^^^^^^^^^^^^^^^^^^
self.logical = LogicalOp::None;
self.read = i + 1;
return match error {
Some(error) => Some(Err(error)),
None => Some(Ok(statement)),
};
}
b'&' | b'|' if self.paren_level == 0 && last == Some(character) => {
// Detecting if there is a 2nd `&` character
let statement = self.get_statement(start, i - 1);
^^^^^^^^^^^^^^^^^^^^^^^^^^^
self.logical = if character == b'&' { LogicalOp::And } else { LogicalOp::Or };
self.read = i + 1;
return match error {
Some(error) => Some(Err(error)),
None => Some(Ok(statement)),
};
}
_ => {}
}
last = Some(character);
}
On both calls, get_statement try to slice the command line with incorrect index.
If we pick test case#1, ls &&||
, start equals 5 but is added 1 and i equals 6 minus 1 which gives &"ls &&||"[6..5]
.
As I understand, syntax is checked along the command execution so a syntax error can be raised while Ion
has already executed N statements from a given command line. Ion could check if self.logical
is already
set to And or Or instead of None while performing &&
, ||
or ;
but it does not look quite right
and did not pass cargo test(infinity loop) when I tried to implement it.
I'm pretty new to Rust and it feels a bit overwhelming for now to find an elegant solution which does fit well
with Ion's codebase.
Thanks in advance for your help,
Aurélien