From 0fd08a994899e4b017ff7cec0a3edb0e3951b438 Mon Sep 17 00:00:00 2001 From: sin-ack Date: Sun, 27 Oct 2024 10:59:22 +0000 Subject: [PATCH] parser: Avoid reading after the end of shunting yard stack We would previously do this: - Erase items from the buffer - Read the items we just erased This is a mistake because the vector might have resized itself after the erase call. This would cause assertion errors with the GNU STL. We now instead read the offsets we want to read from before performing the erase. There may be other occurrences of this, but I've only hit these cases when compiling Xonotic. --- parser.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/parser.cpp b/parser.cpp index a59191c2..32b37fb9 100644 --- a/parser.cpp +++ b/parser.cpp @@ -377,10 +377,10 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) if (!op->operands) return true; - sy->out.erase(sy->out.end() - op->operands, sy->out.end()); + size_t start_offset = sy->out.size() - op->operands; for (i = 0; i < op->operands; ++i) { - exprs[i] = sy->out[sy->out.size()+i].out; - blocks[i] = sy->out[sy->out.size()+i].block; + exprs[i] = sy->out[start_offset+i].out; + blocks[i] = sy->out[start_offset+i].block; if (exprs[i]->m_vtype == TYPE_NOEXPR && !(i != 0 && op->id == opid2('?',':')) && @@ -393,6 +393,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) (void)!compile_warning(exprs[i]->m_context, WARN_DEBUG, "expression %u\n", (unsigned int)i); } } + sy->out.erase(sy->out.end() - op->operands, sy->out.end()); if (blocks[0] && blocks[0]->m_exprs.empty() && op->id != opid1(',')) { compile_error(ctx, "internal error: operator cannot be applied on empty blocks"); @@ -1205,8 +1206,10 @@ static bool parser_close_call(parser_t *parser, shunt *sy) size_t fid; size_t paramcount, i; bool fold = true; + lex_ctx_t ctx; fid = sy->ops.back().off; + ctx = sy->ops.back().ctx; sy->ops.pop_back(); /* out[fid] is the function @@ -1292,7 +1295,7 @@ static bool parser_close_call(parser_t *parser, shunt *sy) } fold_leave: - call = ast_call::make(sy->ops[sy->ops.size()].ctx, fun); + call = ast_call::make(ctx, fun); if (!call) return false;