SERVER-119194 Default initialize SBE VM dispatch table to lastInstruc… (#48867)

GitOrigin-RevId: dcf4dad12c450670a512d1c0807ab316c768ff4d
This commit is contained in:
Evan Bergeron
2026-03-06 17:19:55 -05:00
committed by MongoDB Bot
parent 54ff814ae2
commit af5ca36132
2 changed files with 128 additions and 87 deletions

View File

@@ -31,6 +31,8 @@
#include "mongo/db/exec/sbe/expressions/runtime_environment.h" #include "mongo/db/exec/sbe/expressions/runtime_environment.h"
#include "mongo/db/exec/sbe/values/slot.h" #include "mongo/db/exec/sbe/values/slot.h"
#include "mongo/db/exec/sbe/vm/vm.h" #include "mongo/db/exec/sbe/vm/vm.h"
#include "mongo/db/exec/sbe/vm/vm_instruction.h"
#include "mongo/unittest/death_test.h"
#include "mongo/unittest/unittest.h" #include "mongo/unittest/unittest.h"
namespace mongo { namespace mongo {
@@ -66,4 +68,15 @@ TEST(CodeFragmentTest, TestPushOwnedAccessorVal) {
ASSERT(res.tag() == testTag); ASSERT(res.tag() == testTag);
ASSERT(res.value() == testValue); ASSERT(res.value() == testValue);
} }
DEATH_TEST(SBEVMBytecodeValidationDeathTest,
InvalidOpcodeTriggersUnreachable,
"SBE lastInstruction VM opcode") {
constexpr uint8_t kInvalidOpcode = static_cast<uint8_t>(sbe::vm::Instruction::lastInstruction);
sbe::vm::CodeFragment code;
code.instrs().resize(1, kInvalidOpcode);
sbe::vm::ByteCode interpreter;
interpreter.run(&code);
}
} // namespace mongo } // namespace mongo

View File

@@ -36,6 +36,8 @@
#include "mongo/db/exec/sbe/vm/vm.h" #include "mongo/db/exec/sbe/vm/vm.h"
#include "mongo/db/query/collation/collation_index_key.h" #include "mongo/db/query/collation/collation_index_key.h"
#include <algorithm>
#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kQuery #define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kQuery
#if defined(_MSC_VER) #if defined(_MSC_VER)
@@ -255,110 +257,127 @@ void ByteCode::runLambdaInternal(const CodeFragment* code, int64_t position) {
popAndReleaseStack(); popAndReleaseStack();
} }
namespace {
using DispatchTable = std::array<void*, std::numeric_limits<decltype(Instruction::tag)>::max() + 1>;
constexpr DispatchTable defaultInitializeDispatchTable(void* lastInstructionAddr,
DispatchTable initial) {
DispatchTable ret{};
std::fill(ret.begin() + Instruction::lastInstruction, ret.end(), lastInstructionAddr);
for (auto i = 0; i < Instruction::lastInstruction; i++) {
ret[i] = initial[i];
}
return ret;
};
} // namespace
void ByteCode::runInternal(const CodeFragment* code, int64_t position) { void ByteCode::runInternal(const CodeFragment* code, int64_t position) {
#if USE_THREADED_INTERPRETER #if USE_THREADED_INTERPRETER
// Very important this in sync with Instruction::Tags. // Very important this in sync with Instruction::Tags.
static constexpr void* dispatchTable[std::numeric_limits<decltype(Instruction::tag)>::max() + constexpr DispatchTable dispatchTable =
1] = {&&do_pushConstVal, defaultInitializeDispatchTable(&&do_lastInstruction,
&&do_pushAccessVal, {&&do_pushConstVal,
&&do_pushOwnedAccessorVal, &&do_pushAccessVal,
&&do_pushEnvAccessorVal, &&do_pushOwnedAccessorVal,
&&do_pushMoveVal, &&do_pushEnvAccessorVal,
&&do_pushLocalVal, &&do_pushMoveVal,
&&do_pushMoveLocalVal, &&do_pushLocalVal,
&&do_pushOneArgLambda, &&do_pushMoveLocalVal,
&&do_pushTwoArgLambda, &&do_pushOneArgLambda,
&&do_pop, &&do_pushTwoArgLambda,
&&do_swap, &&do_pop,
&&do_makeOwn, &&do_swap,
&&do_makeOwn,
&&do_add, &&do_add,
&&do_sub, &&do_sub,
&&do_mul, &&do_mul,
&&do_div, &&do_div,
&&do_idiv, &&do_idiv,
&&do_mod, &&do_mod,
&&do_negate, &&do_negate,
&&do_numConvert, &&do_numConvert,
&&do_logicNot, &&do_logicNot,
&&do_less, &&do_less,
&&do_lessEq, &&do_lessEq,
&&do_greater, &&do_greater,
&&do_greaterEq, &&do_greaterEq,
&&do_eq, &&do_eq,
&&do_neq, &&do_neq,
&&do_cmp3w, &&do_cmp3w,
&&do_collLess, &&do_collLess,
&&do_collLessEq, &&do_collLessEq,
&&do_collGreater, &&do_collGreater,
&&do_collGreaterEq, &&do_collGreaterEq,
&&do_collEq, &&do_collEq,
&&do_collNeq, &&do_collNeq,
&&do_collCmp3w, &&do_collCmp3w,
&&do_fillEmpty, &&do_fillEmpty,
&&do_fillEmptyImm, &&do_fillEmptyImm,
&&do_getField, &&do_getField,
&&do_getFieldImm, &&do_getFieldImm,
&&do_getElement, &&do_getElement,
&&do_collComparisonKey, &&do_collComparisonKey,
&&do_getFieldOrElement, &&do_getFieldOrElement,
&&do_traverseP, &&do_traverseP,
&&do_traversePImm, &&do_traversePImm,
&&do_traverseF, &&do_traverseF,
&&do_traverseFImm, &&do_traverseFImm,
&&do_magicTraverseF, &&do_magicTraverseF,
&&do_setField, &&do_setField,
&&do_getArraySize, &&do_getArraySize,
&&do_aggSum, &&do_aggSum,
&&do_aggCount, &&do_aggCount,
&&do_aggMin, &&do_aggMin,
&&do_aggMax, &&do_aggMax,
&&do_aggFirst, &&do_aggFirst,
&&do_aggLast, &&do_aggLast,
&&do_aggCollMin, &&do_aggCollMin,
&&do_aggCollMax, &&do_aggCollMax,
&&do_exists, &&do_exists,
&&do_isNull, &&do_isNull,
&&do_isObject, &&do_isObject,
&&do_isArray, &&do_isArray,
&&do_isInList, &&do_isInList,
&&do_isString, &&do_isString,
&&do_isNumber, &&do_isNumber,
&&do_isBinData, &&do_isBinData,
&&do_isDate, &&do_isDate,
&&do_isNaN, &&do_isNaN,
&&do_isInfinity, &&do_isInfinity,
&&do_isRecordId, &&do_isRecordId,
&&do_isMinKey, &&do_isMinKey,
&&do_isMaxKey, &&do_isMaxKey,
&&do_isTimestamp, &&do_isTimestamp,
&&do_isKeyString, &&do_isKeyString,
&&do_typeMatchImm, &&do_typeMatchImm,
&&do_function, &&do_function,
&&do_functionSmall, &&do_functionSmall,
&&do_jmp, &&do_jmp,
&&do_jmpTrue, &&do_jmpTrue,
&&do_jmpFalse, &&do_jmpFalse,
&&do_jmpNothing, &&do_jmpNothing,
&&do_jmpNotNothing, &&do_jmpNotNothing,
&&do_ret, &&do_ret,
&&do_allocStack, &&do_allocStack,
&&do_fail, &&do_fail,
&&do_dateTruncImm, &&do_dateTruncImm,
&&do_valueBlockApplyLambda}; &&do_valueBlockApplyLambda});
static_assert(std::none_of(
dispatchTable.begin(), dispatchTable.end(), [](void* p) { return p == nullptr; }));
#endif #endif
auto pcPointer = code->instrs().data() + position; auto pcPointer = code->instrs().data() + position;
@@ -1472,6 +1491,15 @@ void ByteCode::runInternal(const CodeFragment* code, int64_t position) {
valueBlockApplyLambda(code); valueBlockApplyLambda(code);
} }
DISPATCH(); DISPATCH();
INSTRUCTION(lastInstruction) {
// Invalid opcode; log and kill the process. Field names are PII, so only log opcode tags.
LOGV2_ERROR(11919400,
"Invalid SBE VM bytecode",
"bytecode in hexadecimal"_attr = hexblob::encode(
code->instrs().data(), code->instrs().size() * sizeof(uint8_t)));
tasserted(11919401, "SBE lastInstruction VM opcode");
}
DISPATCH();
#if USE_THREADED_INTERPRETER #if USE_THREADED_INTERPRETER
#else #else
} }