Skip to content

Commit

Permalink
fix: Infinite loop on invalid preprocessor operands
Browse files Browse the repository at this point in the history
  • Loading branch information
slavek-kucera authored Dec 6, 2024
1 parent 190db1f commit 815ef61
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 15 deletions.
4 changes: 4 additions & 0 deletions clients/vscode-hlasmplugin/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## ****Unreleased****

#### Fixed

- Infinite loop on invalid preprocessor operands

## [1.15.1](https://github.com/eclipse-che4z/che-che4z-lsp-for-hlasm/compare/1.15.0...1.15.1) (2024-11-22)

#### Fixed
Expand Down
35 changes: 20 additions & 15 deletions parser_library/src/processing/preprocessors/preprocessor_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,33 +24,34 @@

namespace hlasm_plugin::parser_library::processing {
namespace {
size_t get_quoted_string_end(std::string_view s)
size_t get_quoted_string_end(std::string_view s, size_t last_quote)
{
auto closing_quote = std::string_view::npos;

s.remove_prefix(1);
while (closing_quote == std::string_view::npos)
do
{
closing_quote = s.find_first_of("'");
last_quote = s.find_first_of("'", last_quote + 1);

if (closing_quote == std::string_view::npos || closing_quote == s.length() - 1
|| s[closing_quote + 1] != '\'') // ignore double quotes
if (last_quote == std::string_view::npos || last_quote == s.length() - 1
|| s[last_quote + 1] != '\'') // ignore double quotes
break;
++last_quote;
} while (last_quote != std::string_view::npos);

s = s.substr(closing_quote + 1);
closing_quote = std::string_view::npos;
}

return closing_quote;
return last_quote;
}

size_t get_argument_length(std::string_view s)
{
auto string_end_pos = std::string_view::npos;
if (auto string_start_pos = s.find_first_of("'"); string_start_pos != std::string_view::npos)
string_end_pos = get_quoted_string_end(s);
string_end_pos = get_quoted_string_end(s, string_start_pos);

if (string_end_pos == std::string_view::npos)
return s.length();

return string_end_pos == std::string_view::npos ? s.length() : s.find_first_of(")", string_end_pos) + 1;
if (const auto rpar = s.find_first_of(")", string_end_pos); rpar != std::string_view::npos)
return rpar + 1;

return s.length();
}

std::string_view extract_operand_and_argument(std::string_view s)
Expand All @@ -66,8 +67,12 @@ std::string_view extract_operand_and_argument(std::string_view s)
return s.substr(0, separator_pos);

if (parenthesis > separator_pos)
{
if (separator_pos + 1 == parenthesis && s[separator_pos] == ',')
return s.substr(0, separator_pos);
if (auto prev_char = s.find_last_not_of(separators, parenthesis - 1); prev_char > separator_pos)
return s.substr(0, separator_pos);
}

return s.substr(0, get_argument_length(s));
}
Expand Down
41 changes: 41 additions & 0 deletions parser_library/test/processing/preprocessor_utils_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,3 +160,44 @@ TEST(preprocessor_utils, operand_parsing_multiple_multiline_continue)

EXPECT_EQ(processing::get_operands_list(input, 0, get_range_provider(input.length(), 0, 15)), expected);
}

TEST(preprocessor_utils, invalid_operands)
{
std::string_view input = "X,(',''";

std::vector<semantics::preproc_details::name_range> expected {
{ "X", range(position(0, 0), position(0, 1)) },
{ "(',''", range(position(0, 2), position(0, 7)) },
};

const auto result = processing::get_operands_list(input, 0, get_range_provider(input.length(), 0, 15));

EXPECT_EQ(result, expected);
}

TEST(preprocessor_utils, no_op_name)
{
std::string_view input = "X,(Y)";

std::vector<semantics::preproc_details::name_range> expected {
{ "X", range(position(0, 0), position(0, 1)) },
{ "(Y)", range(position(0, 2), position(0, 5)) },
};

const auto result = processing::get_operands_list(input, 0, get_range_provider(input.length(), 0, 15));

EXPECT_EQ(result, expected);
}

TEST(preprocessor_utils, invalid_missing_rpar)
{
std::string_view input = "X' (, '";

std::vector<semantics::preproc_details::name_range> expected {
{ "X'(,'", range(position(0, 0), position(0, 7)) },
};

const auto result = processing::get_operands_list(input, 0, get_range_provider(input.length(), 0, 15));

EXPECT_EQ(result, expected);
}

0 comments on commit 815ef61

Please sign in to comment.