From 388ce0ee64b393c02843fb7469647069c89ab5da Mon Sep 17 00:00:00 2001 From: Alastair Donaldson Date: Tue, 26 Jul 2022 15:56:04 +0100 Subject: [PATCH] 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. --- source/text_handler.cpp | 43 +++++++++++++++++++------------------- 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 fe12a26e..15c1741f 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 9de77a83..0d23ab1c 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