Safer code for parsing commands

Fix some possible past the end of target string reads
Fixes #1310 (maybe, probably, who knows)
This commit is contained in:
Maxime Coste 2017-04-19 21:52:27 +01:00
parent 34bf8c23e1
commit 5103b15b84

View File

@ -51,10 +51,15 @@ public:
Reader(StringView s) : str{s}, pos{}, coord{} {} Reader(StringView s) : str{s}, pos{}, coord{} {}
[[gnu::always_inline]] [[gnu::always_inline]]
char operator*() const { return str[pos]; } char operator*() const
{
kak_assert(pos < str.length());
return str[pos];
}
Reader& operator++() Reader& operator++()
{ {
kak_assert(pos < str.length());
if (str[pos++] == '\n') if (str[pos++] == '\n')
{ {
++coord.line; ++coord.line;
@ -71,6 +76,7 @@ public:
[[gnu::always_inline]] [[gnu::always_inline]]
StringView substr_from(ByteCount start) const StringView substr_from(ByteCount start) const
{ {
kak_assert(start <= pos);
return str.substr(start, pos - start); return str.substr(start, pos - start);
} }
@ -207,6 +213,8 @@ Token parse_percent_token(Reader& reader)
if (throw_on_unterminated and not reader) if (throw_on_unterminated and not reader)
throw parse_error{format("expected a string delimiter after '%{}'", throw parse_error{format("expected a string delimiter after '%{}'",
type_name)}; type_name)};
else if (not reader)
return {};
Token::Type type = token_type<throw_on_unterminated>(type_name); Token::Type type = token_type<throw_on_unterminated>(type_name);
@ -310,9 +318,11 @@ TokenList parse(StringView line)
TokenList result; TokenList result;
Reader reader{line}; Reader reader{line};
while (reader) while (true)
{ {
skip_blanks_and_comments(reader); skip_blanks_and_comments(reader);
if (not reader)
break;
ByteCount start = reader.pos; ByteCount start = reader.pos;
auto coord = reader.coord; auto coord = reader.coord;
@ -340,12 +350,14 @@ TokenList parse(StringView line)
if (not str.empty()) if (not str.empty())
result.emplace_back(Token::Type::Raw, start, reader.pos, result.emplace_back(Token::Type::Raw, start, reader.pos,
coord, unescape(str, "%", '\\')); coord, unescape(str, "%", '\\'));
if (not reader or is_command_separator(*reader))
result.emplace_back(Token::Type::CommandSeparator,
reader.pos, reader.pos+1, coord);
} }
if (is_command_separator(*reader)) if (not reader)
result.emplace_back(Token::Type::CommandSeparator, break;
reader.pos, reader.pos+1, coord);
++reader; ++reader;
} }
return result; return result;