From 6d750390afcbd7487e1f83e086eb59f26b44ae84 Mon Sep 17 00:00:00 2001 From: Andrew Noyes Date: Tue, 13 May 2025 10:48:19 -0400 Subject: [PATCH] Check for stack overflow --- src/test.cpp | 101 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 61 insertions(+), 40 deletions(-) diff --git a/src/test.cpp b/src/test.cpp index 5d4141e..b230401 100644 --- a/src/test.cpp +++ b/src/test.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -427,7 +428,9 @@ struct Parser2 { // Returns false to reject [[nodiscard]] bool parse() { - stack.push_back(N_VALUE); + if (!push({N_VALUE})) { + return false; + } nextToken(); return keepGoing(this); } @@ -437,6 +440,8 @@ struct Parser2 { Parser2(Parser2 &&) = delete; Parser2 &operator=(Parser2 &&) = delete; + static constexpr int kMaxStackSize = 1 << 10; + private: // Helpers void maybeSkipWs() { @@ -499,24 +504,25 @@ private: void printStack() { printf("token: %s\n", symbolNames[currentToken]); - for (auto s : stack) { - printf("%s ", symbolNames[s]); + for (int i = 0; i < stackPtr - stack; ++i) { + printf("%s ", symbolNames[stack[i]]); } printf("\n"); } + PRESERVE_NONE static bool tokenMatch(Parser2 *self) { + self->pop(); + self->nextToken(); + MUSTTAIL return keepGoing(self); + } + PRESERVE_NONE static bool keepGoing(Parser2 *self) { // self->printStack(); - if (self->stack.empty()) { + if (self->empty()) { assert(self->currentToken == T_EOF); return true; } - if (self->stack.back() == self->currentToken) { - self->stack.pop_back(); - self->nextToken(); - MUSTTAIL return keepGoing(self); - } - MUSTTAIL return table[self->stack.back()][self->currentToken](self); + MUSTTAIL return table[*(self->stackPtr - 1)][self->currentToken](self); } PRESERVE_NONE static bool reject(Parser2 *) { return false; } @@ -524,11 +530,10 @@ private: assert(self->currentToken == T_LBRACE); self->callbacks->on_begin_object(self->data); self->nextToken(); - self->stack.pop_back(); - self->stack.push_back(N_OBJECT_MAYBE_CONTINUE); - self->stack.push_back(N_VALUE); - self->stack.push_back(T_COLON); - self->stack.push_back(T_STRING); + self->pop(); + if (!self->push({T_STRING, T_COLON, N_VALUE, N_OBJECT_MAYBE_CONTINUE})) { + return false; + } MUSTTAIL return keepGoing(self); } PRESERVE_NONE static bool atom(Parser2 *self) { @@ -545,54 +550,55 @@ private: self->callbacks->on_end_number(self->data); } self->nextToken(); - self->stack.pop_back(); + self->pop(); MUSTTAIL return keepGoing(self); } PRESERVE_NONE static bool string(Parser2 *self) { assert(self->currentToken == T_STRING); self->nextToken(); - self->stack.pop_back(); + self->pop(); MUSTTAIL return keepGoing(self); } PRESERVE_NONE static bool array(Parser2 *self) { assert(self->currentToken == T_LBRACKET); self->callbacks->on_begin_array(self->data); self->nextToken(); - self->stack.pop_back(); - self->stack.push_back(N_ARRAY_MAYBE_CONTINUE); - self->stack.push_back(N_VALUE); + self->pop(); + if (!self->push({N_VALUE, N_ARRAY_MAYBE_CONTINUE})) { + return false; + } MUSTTAIL return keepGoing(self); } PRESERVE_NONE static bool continueArray(Parser2 *self) { assert(self->currentToken == T_COMMA); self->nextToken(); - self->stack.pop_back(); - self->stack.push_back(N_ARRAY_MAYBE_CONTINUE); - self->stack.push_back(N_VALUE); + self->pop(); + if (!self->push({N_VALUE, N_ARRAY_MAYBE_CONTINUE})) { + return false; + } MUSTTAIL return keepGoing(self); } PRESERVE_NONE static bool continueObject(Parser2 *self) { assert(self->currentToken == T_COMMA); self->nextToken(); - self->stack.pop_back(); - self->stack.push_back(N_OBJECT_MAYBE_CONTINUE); - self->stack.push_back(N_VALUE); - self->stack.push_back(T_COLON); - self->stack.push_back(T_STRING); + self->pop(); + if (!self->push({T_STRING, T_COLON, N_VALUE, N_OBJECT_MAYBE_CONTINUE})) { + return false; + } MUSTTAIL return keepGoing(self); } PRESERVE_NONE static bool finishArray(Parser2 *self) { assert(self->currentToken == T_RBRACKET); self->callbacks->on_end_array(self->data); self->nextToken(); - self->stack.pop_back(); + self->pop(); MUSTTAIL return keepGoing(self); } PRESERVE_NONE static bool finishObject(Parser2 *self) { assert(self->currentToken == T_RBRACE); self->callbacks->on_end_object(self->data); self->nextToken(); - self->stack.pop_back(); + self->pop(); MUSTTAIL return keepGoing(self); } @@ -614,7 +620,7 @@ private: /*T_EOF*/ { /*T_INVALID*/ reject, - /*T_EOF*/ reject, + /*T_EOF*/ tokenMatch, /*T_LBRACE*/ reject, /*T_RBRACE*/ reject, /*T_COMMA*/ reject, @@ -628,7 +634,7 @@ private: { /*T_INVALID*/ reject, /*T_EOF*/ reject, - /*T_LBRACE*/ reject, + /*T_LBRACE*/ tokenMatch, /*T_RBRACE*/ reject, /*T_COMMA*/ reject, /*T_ATOM*/ reject, @@ -642,7 +648,7 @@ private: /*T_INVALID*/ reject, /*T_EOF*/ reject, /*T_LBRACE*/ reject, - /*T_RBRACE*/ reject, + /*T_RBRACE*/ tokenMatch, /*T_COMMA*/ reject, /*T_ATOM*/ reject, /*T_STRING*/ reject, @@ -656,7 +662,7 @@ private: /*T_EOF*/ reject, /*T_LBRACE*/ reject, /*T_RBRACE*/ reject, - /*T_COMMA*/ reject, + /*T_COMMA*/ tokenMatch, /*T_ATOM*/ reject, /*T_STRING*/ reject, /*T_LBRACKET*/ reject, @@ -670,7 +676,7 @@ private: /*T_LBRACE*/ reject, /*T_RBRACE*/ reject, /*T_COMMA*/ reject, - /*T_ATOM*/ reject, + /*T_ATOM*/ tokenMatch, /*T_STRING*/ reject, /*T_LBRACKET*/ reject, /*T_RBRACKET*/ reject, @@ -684,7 +690,7 @@ private: /*T_RBRACE*/ reject, /*T_COMMA*/ reject, /*T_ATOM*/ reject, - /*T_STRING*/ reject, + /*T_STRING*/ tokenMatch, /*T_LBRACKET*/ reject, /*T_RBRACKET*/ reject, /*T_COLON*/ reject, @@ -698,7 +704,7 @@ private: /*T_COMMA*/ reject, /*T_ATOM*/ reject, /*T_STRING*/ reject, - /*T_LBRACKET*/ reject, + /*T_LBRACKET*/ tokenMatch, /*T_RBRACKET*/ reject, /*T_COLON*/ reject, }, @@ -712,7 +718,7 @@ private: /*T_ATOM*/ reject, /*T_STRING*/ reject, /*T_LBRACKET*/ reject, - /*T_RBRACKET*/ reject, + /*T_RBRACKET*/ tokenMatch, /*T_COLON*/ reject, }, /*T_COLON*/ @@ -726,7 +732,7 @@ private: /*T_STRING*/ reject, /*T_LBRACKET*/ reject, /*T_RBRACKET*/ reject, - /*T_COLON*/ reject, + /*T_COLON*/ tokenMatch, }, /*N_VALUE*/ { @@ -853,7 +859,22 @@ private: int len; const Callbacks *const callbacks; void *const data; - std::vector stack; + Symbol stack[kMaxStackSize]; + Symbol *stackPtr = stack; + bool empty() { return stackPtr == stack; } + void pop() { + assert(!empty()); + --stackPtr; + } + [[nodiscard]] bool push(std::initializer_list symbols) { + if (stackPtr >= std::end(stack) - symbols.size()) [[unlikely]] { + return false; + } + for (int i = symbols.size() - 1; i >= 0; --i) { + *stackPtr++ = *(symbols.begin() + i); + } + return true; + } }; const std::string json = R"({