diff options
author | Alastair Donaldson <alastair.donaldson@imperial.ac.uk> | 2022-07-26 17:56:04 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-07-26 17:56:04 +0300 |
commit | 388ce0ee64b393c02843fb7469647069c89ab5da (patch) | |
tree | 17d2c0d0cabe1c8629b807590c4ea61712321213 | |
parent | e4cfa190dfa144f1db5bcca2a6b11a6ba429824d (diff) |
spirv-as: Avoid recursion when skipping whitespace (#4866)
Excessive whitespace can lead to stack overflow during parsing as each
character of skipped whitespace involves a recursive call. An
iterative solution avoids this.
Fixes #4729.
-rw-r--r-- | source/text_handler.cpp | 43 | ||||
-rw-r--r-- | test/text_advance_test.cpp | 9 |
2 files changed, 31 insertions, 21 deletions
diff --git a/source/text_handler.cpp b/source/text_handler.cpp index fe12a26e3..15c1741f6 100644 --- a/source/text_handler.cpp +++ b/source/text_handler.cpp @@ -62,28 +62,29 @@ spv_result_t advanceLine(spv_text text, spv_position position) { // parameters, its the users responsibility to ensure these are non null. spv_result_t advance(spv_text text, spv_position position) { // NOTE: Consume white space, otherwise don't advance. - if (position->index >= text->length) return SPV_END_OF_STREAM; - switch (text->str[position->index]) { - case '\0': - return SPV_END_OF_STREAM; - case ';': - if (spv_result_t error = advanceLine(text, position)) return error; - return advance(text, position); - case ' ': - case '\t': - case '\r': - position->column++; - position->index++; - return advance(text, position); - case '\n': - position->column = 0; - position->line++; - position->index++; - return advance(text, position); - default: - break; + while (true) { + if (position->index >= text->length) return SPV_END_OF_STREAM; + switch (text->str[position->index]) { + case '\0': + return SPV_END_OF_STREAM; + case ';': + if (spv_result_t error = advanceLine(text, position)) return error; + continue; + case ' ': + case '\t': + case '\r': + position->column++; + position->index++; + continue; + case '\n': + position->column = 0; + position->line++; + position->index++; + continue; + default: + return SPV_SUCCESS; + } } - return SPV_SUCCESS; } // Fetches the next word from the given text stream starting from the given diff --git a/test/text_advance_test.cpp b/test/text_advance_test.cpp index 9de77a836..0d23ab1c1 100644 --- a/test/text_advance_test.cpp +++ b/test/text_advance_test.cpp @@ -130,5 +130,14 @@ TEST(TextAdvance, SkipOverCRLFs) { EXPECT_EQ(2u, pos.line); EXPECT_EQ(4u, pos.index); } + +TEST(TextAdvance, HandleLotsOfWhitespace) { + std::string lots_of_spaces(10000, ' '); + lots_of_spaces += "Word"; + const auto pos = PositionAfterAdvance(lots_of_spaces.c_str()); + EXPECT_EQ(10000u, pos.column); + EXPECT_EQ(0u, pos.line); + EXPECT_EQ(10000u, pos.index); +} } // namespace } // namespace spvtools |