Check for stack overflow

This commit is contained in:
2025-05-13 10:48:19 -04:00
parent ae2ad167b9
commit 6d750390af

View File

@@ -3,6 +3,7 @@
#include <cstdio> #include <cstdio>
#include <cstring> #include <cstring>
#include <initializer_list>
#include <string> #include <string>
#include <utility> #include <utility>
@@ -427,7 +428,9 @@ struct Parser2 {
// Returns false to reject // Returns false to reject
[[nodiscard]] bool parse() { [[nodiscard]] bool parse() {
stack.push_back(N_VALUE); if (!push({N_VALUE})) {
return false;
}
nextToken(); nextToken();
return keepGoing(this); return keepGoing(this);
} }
@@ -437,6 +440,8 @@ struct Parser2 {
Parser2(Parser2 &&) = delete; Parser2(Parser2 &&) = delete;
Parser2 &operator=(Parser2 &&) = delete; Parser2 &operator=(Parser2 &&) = delete;
static constexpr int kMaxStackSize = 1 << 10;
private: private:
// Helpers // Helpers
void maybeSkipWs() { void maybeSkipWs() {
@@ -499,24 +504,25 @@ private:
void printStack() { void printStack() {
printf("token: %s\n", symbolNames[currentToken]); printf("token: %s\n", symbolNames[currentToken]);
for (auto s : stack) { for (int i = 0; i < stackPtr - stack; ++i) {
printf("%s ", symbolNames[s]); printf("%s ", symbolNames[stack[i]]);
} }
printf("\n"); printf("\n");
} }
PRESERVE_NONE static bool keepGoing(Parser2 *self) { PRESERVE_NONE static bool tokenMatch(Parser2 *self) {
// self->printStack(); self->pop();
if (self->stack.empty()) {
assert(self->currentToken == T_EOF);
return true;
}
if (self->stack.back() == self->currentToken) {
self->stack.pop_back();
self->nextToken(); self->nextToken();
MUSTTAIL return keepGoing(self); MUSTTAIL return keepGoing(self);
} }
MUSTTAIL return table[self->stack.back()][self->currentToken](self);
PRESERVE_NONE static bool keepGoing(Parser2 *self) {
// self->printStack();
if (self->empty()) {
assert(self->currentToken == T_EOF);
return true;
}
MUSTTAIL return table[*(self->stackPtr - 1)][self->currentToken](self);
} }
PRESERVE_NONE static bool reject(Parser2 *) { return false; } PRESERVE_NONE static bool reject(Parser2 *) { return false; }
@@ -524,11 +530,10 @@ private:
assert(self->currentToken == T_LBRACE); assert(self->currentToken == T_LBRACE);
self->callbacks->on_begin_object(self->data); self->callbacks->on_begin_object(self->data);
self->nextToken(); self->nextToken();
self->stack.pop_back(); self->pop();
self->stack.push_back(N_OBJECT_MAYBE_CONTINUE); if (!self->push({T_STRING, T_COLON, N_VALUE, N_OBJECT_MAYBE_CONTINUE})) {
self->stack.push_back(N_VALUE); return false;
self->stack.push_back(T_COLON); }
self->stack.push_back(T_STRING);
MUSTTAIL return keepGoing(self); MUSTTAIL return keepGoing(self);
} }
PRESERVE_NONE static bool atom(Parser2 *self) { PRESERVE_NONE static bool atom(Parser2 *self) {
@@ -545,54 +550,55 @@ private:
self->callbacks->on_end_number(self->data); self->callbacks->on_end_number(self->data);
} }
self->nextToken(); self->nextToken();
self->stack.pop_back(); self->pop();
MUSTTAIL return keepGoing(self); MUSTTAIL return keepGoing(self);
} }
PRESERVE_NONE static bool string(Parser2 *self) { PRESERVE_NONE static bool string(Parser2 *self) {
assert(self->currentToken == T_STRING); assert(self->currentToken == T_STRING);
self->nextToken(); self->nextToken();
self->stack.pop_back(); self->pop();
MUSTTAIL return keepGoing(self); MUSTTAIL return keepGoing(self);
} }
PRESERVE_NONE static bool array(Parser2 *self) { PRESERVE_NONE static bool array(Parser2 *self) {
assert(self->currentToken == T_LBRACKET); assert(self->currentToken == T_LBRACKET);
self->callbacks->on_begin_array(self->data); self->callbacks->on_begin_array(self->data);
self->nextToken(); self->nextToken();
self->stack.pop_back(); self->pop();
self->stack.push_back(N_ARRAY_MAYBE_CONTINUE); if (!self->push({N_VALUE, N_ARRAY_MAYBE_CONTINUE})) {
self->stack.push_back(N_VALUE); return false;
}
MUSTTAIL return keepGoing(self); MUSTTAIL return keepGoing(self);
} }
PRESERVE_NONE static bool continueArray(Parser2 *self) { PRESERVE_NONE static bool continueArray(Parser2 *self) {
assert(self->currentToken == T_COMMA); assert(self->currentToken == T_COMMA);
self->nextToken(); self->nextToken();
self->stack.pop_back(); self->pop();
self->stack.push_back(N_ARRAY_MAYBE_CONTINUE); if (!self->push({N_VALUE, N_ARRAY_MAYBE_CONTINUE})) {
self->stack.push_back(N_VALUE); return false;
}
MUSTTAIL return keepGoing(self); MUSTTAIL return keepGoing(self);
} }
PRESERVE_NONE static bool continueObject(Parser2 *self) { PRESERVE_NONE static bool continueObject(Parser2 *self) {
assert(self->currentToken == T_COMMA); assert(self->currentToken == T_COMMA);
self->nextToken(); self->nextToken();
self->stack.pop_back(); self->pop();
self->stack.push_back(N_OBJECT_MAYBE_CONTINUE); if (!self->push({T_STRING, T_COLON, N_VALUE, N_OBJECT_MAYBE_CONTINUE})) {
self->stack.push_back(N_VALUE); return false;
self->stack.push_back(T_COLON); }
self->stack.push_back(T_STRING);
MUSTTAIL return keepGoing(self); MUSTTAIL return keepGoing(self);
} }
PRESERVE_NONE static bool finishArray(Parser2 *self) { PRESERVE_NONE static bool finishArray(Parser2 *self) {
assert(self->currentToken == T_RBRACKET); assert(self->currentToken == T_RBRACKET);
self->callbacks->on_end_array(self->data); self->callbacks->on_end_array(self->data);
self->nextToken(); self->nextToken();
self->stack.pop_back(); self->pop();
MUSTTAIL return keepGoing(self); MUSTTAIL return keepGoing(self);
} }
PRESERVE_NONE static bool finishObject(Parser2 *self) { PRESERVE_NONE static bool finishObject(Parser2 *self) {
assert(self->currentToken == T_RBRACE); assert(self->currentToken == T_RBRACE);
self->callbacks->on_end_object(self->data); self->callbacks->on_end_object(self->data);
self->nextToken(); self->nextToken();
self->stack.pop_back(); self->pop();
MUSTTAIL return keepGoing(self); MUSTTAIL return keepGoing(self);
} }
@@ -614,7 +620,7 @@ private:
/*T_EOF*/ /*T_EOF*/
{ {
/*T_INVALID*/ reject, /*T_INVALID*/ reject,
/*T_EOF*/ reject, /*T_EOF*/ tokenMatch,
/*T_LBRACE*/ reject, /*T_LBRACE*/ reject,
/*T_RBRACE*/ reject, /*T_RBRACE*/ reject,
/*T_COMMA*/ reject, /*T_COMMA*/ reject,
@@ -628,7 +634,7 @@ private:
{ {
/*T_INVALID*/ reject, /*T_INVALID*/ reject,
/*T_EOF*/ reject, /*T_EOF*/ reject,
/*T_LBRACE*/ reject, /*T_LBRACE*/ tokenMatch,
/*T_RBRACE*/ reject, /*T_RBRACE*/ reject,
/*T_COMMA*/ reject, /*T_COMMA*/ reject,
/*T_ATOM*/ reject, /*T_ATOM*/ reject,
@@ -642,7 +648,7 @@ private:
/*T_INVALID*/ reject, /*T_INVALID*/ reject,
/*T_EOF*/ reject, /*T_EOF*/ reject,
/*T_LBRACE*/ reject, /*T_LBRACE*/ reject,
/*T_RBRACE*/ reject, /*T_RBRACE*/ tokenMatch,
/*T_COMMA*/ reject, /*T_COMMA*/ reject,
/*T_ATOM*/ reject, /*T_ATOM*/ reject,
/*T_STRING*/ reject, /*T_STRING*/ reject,
@@ -656,7 +662,7 @@ private:
/*T_EOF*/ reject, /*T_EOF*/ reject,
/*T_LBRACE*/ reject, /*T_LBRACE*/ reject,
/*T_RBRACE*/ reject, /*T_RBRACE*/ reject,
/*T_COMMA*/ reject, /*T_COMMA*/ tokenMatch,
/*T_ATOM*/ reject, /*T_ATOM*/ reject,
/*T_STRING*/ reject, /*T_STRING*/ reject,
/*T_LBRACKET*/ reject, /*T_LBRACKET*/ reject,
@@ -670,7 +676,7 @@ private:
/*T_LBRACE*/ reject, /*T_LBRACE*/ reject,
/*T_RBRACE*/ reject, /*T_RBRACE*/ reject,
/*T_COMMA*/ reject, /*T_COMMA*/ reject,
/*T_ATOM*/ reject, /*T_ATOM*/ tokenMatch,
/*T_STRING*/ reject, /*T_STRING*/ reject,
/*T_LBRACKET*/ reject, /*T_LBRACKET*/ reject,
/*T_RBRACKET*/ reject, /*T_RBRACKET*/ reject,
@@ -684,7 +690,7 @@ private:
/*T_RBRACE*/ reject, /*T_RBRACE*/ reject,
/*T_COMMA*/ reject, /*T_COMMA*/ reject,
/*T_ATOM*/ reject, /*T_ATOM*/ reject,
/*T_STRING*/ reject, /*T_STRING*/ tokenMatch,
/*T_LBRACKET*/ reject, /*T_LBRACKET*/ reject,
/*T_RBRACKET*/ reject, /*T_RBRACKET*/ reject,
/*T_COLON*/ reject, /*T_COLON*/ reject,
@@ -698,7 +704,7 @@ private:
/*T_COMMA*/ reject, /*T_COMMA*/ reject,
/*T_ATOM*/ reject, /*T_ATOM*/ reject,
/*T_STRING*/ reject, /*T_STRING*/ reject,
/*T_LBRACKET*/ reject, /*T_LBRACKET*/ tokenMatch,
/*T_RBRACKET*/ reject, /*T_RBRACKET*/ reject,
/*T_COLON*/ reject, /*T_COLON*/ reject,
}, },
@@ -712,7 +718,7 @@ private:
/*T_ATOM*/ reject, /*T_ATOM*/ reject,
/*T_STRING*/ reject, /*T_STRING*/ reject,
/*T_LBRACKET*/ reject, /*T_LBRACKET*/ reject,
/*T_RBRACKET*/ reject, /*T_RBRACKET*/ tokenMatch,
/*T_COLON*/ reject, /*T_COLON*/ reject,
}, },
/*T_COLON*/ /*T_COLON*/
@@ -726,7 +732,7 @@ private:
/*T_STRING*/ reject, /*T_STRING*/ reject,
/*T_LBRACKET*/ reject, /*T_LBRACKET*/ reject,
/*T_RBRACKET*/ reject, /*T_RBRACKET*/ reject,
/*T_COLON*/ reject, /*T_COLON*/ tokenMatch,
}, },
/*N_VALUE*/ /*N_VALUE*/
{ {
@@ -853,7 +859,22 @@ private:
int len; int len;
const Callbacks *const callbacks; const Callbacks *const callbacks;
void *const data; void *const data;
std::vector<Symbol> stack; Symbol stack[kMaxStackSize];
Symbol *stackPtr = stack;
bool empty() { return stackPtr == stack; }
void pop() {
assert(!empty());
--stackPtr;
}
[[nodiscard]] bool push(std::initializer_list<Symbol> 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"({ const std::string json = R"({