diff options
author | Drew Paroski <drew.paroski@mongodb.com> | 2021-12-27 20:46:32 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-12-28 21:49:45 +0000 |
commit | 6888896c6ee5a38f6648647e8a7d288d286f44ad (patch) | |
tree | b54677e3b0b0ffc93ef8106b498e731641fdccb9 | |
parent | 073d0a252ed3e820e685fe227779400881df17bf (diff) | |
download | mongo-6888896c6ee5a38f6648647e8a7d288d286f44ad.tar.gz |
SERVER-62146 [SBE] Fix use-after-free bug with $arrayElemAt, $first, and $last
(cherry picked from commit 168086cae37581eeaa7513bfa3976cf554ffc79a)
(cherry picked from commit e7234e51120edcc9bd67f0e0890c48b27df39397)
-rw-r--r-- | src/mongo/db/query/sbe_stage_builder_expression.cpp | 27 |
1 files changed, 21 insertions, 6 deletions
diff --git a/src/mongo/db/query/sbe_stage_builder_expression.cpp b/src/mongo/db/query/sbe_stage_builder_expression.cpp index ee06018885f..4eb3537b626 100644 --- a/src/mongo/db/query/sbe_stage_builder_expression.cpp +++ b/src/mongo/db/query/sbe_stage_builder_expression.cpp @@ -271,8 +271,14 @@ void buildArrayAccessByConstantIndex(ExpressionVisitorContext* context, int32_t index) { context->ensureArity(1); - auto array = context->popExpr(); - + // It's important that we project the array to a slot here. If we didn't do this, then the + // view of the array element could potentially outlive the array itself (which could result + // in use-after-free bugs). + auto [arraySlot, stage] = projectEvalExpr(context->popEvalExpr(), + context->extractCurrentEvalStage(), + context->planNodeId, + context->state.slotIdGenerator); + auto array = makeVariable(arraySlot); auto frameId = context->state.frameId(); auto binds = sbe::makeEs(std::move(array)); sbe::EVariable arrayRef{frameId, 0}; @@ -288,8 +294,8 @@ void buildArrayAccessByConstantIndex(ExpressionVisitorContext* context, exprName + " argument must be an array")}, makeFunction("getElement", arrayRef.clone(), std::move(indexExpr))); - context->pushExpr( - sbe::makeE<sbe::ELocalBind>(frameId, std::move(binds), std::move(resultExpr))); + context->pushExpr(sbe::makeE<sbe::ELocalBind>(frameId, std::move(binds), std::move(resultExpr)), + std::move(stage)); } /** @@ -887,7 +893,15 @@ public: _context->ensureArity(2); auto index = _context->popExpr(); - auto array = _context->popExpr(); + + // It's important that we project the array to a slot here. If we didn't do this, then the + // view of the array element could potentially outlive the array itself (which could result + // in use-after-free bugs). + auto [arraySlot, stage] = projectEvalExpr(_context->popEvalExpr(), + _context->extractCurrentEvalStage(), + _context->planNodeId, + _context->state.slotIdGenerator); + auto array = makeVariable(arraySlot); auto frameId = _context->state.frameId(); auto binds = sbe::makeEs(std::move(array), std::move(index)); @@ -928,7 +942,8 @@ public: makeFunction("getElement", arrayRef.clone(), std::move(int32Index))); _context->pushExpr( - sbe::makeE<sbe::ELocalBind>(frameId, std::move(binds), std::move(arrayElemAtExpr))); + sbe::makeE<sbe::ELocalBind>(frameId, std::move(binds), std::move(arrayElemAtExpr)), + std::move(stage)); } void visit(const ExpressionFirst* expr) final { buildArrayAccessByConstantIndex(_context, expr->getOpName(), 0); |