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/values/slot.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"
namespace mongo {
@@ -66,4 +68,15 @@ TEST(CodeFragmentTest, TestPushOwnedAccessorVal) {
ASSERT(res.tag() == testTag);
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

View File

@@ -36,6 +36,8 @@
#include "mongo/db/exec/sbe/vm/vm.h"
#include "mongo/db/query/collation/collation_index_key.h"
#include <algorithm>
#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kQuery
#if defined(_MSC_VER)
@@ -255,110 +257,127 @@ void ByteCode::runLambdaInternal(const CodeFragment* code, int64_t position) {
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) {
#if USE_THREADED_INTERPRETER
// Very important this in sync with Instruction::Tags.
static constexpr void* dispatchTable[std::numeric_limits<decltype(Instruction::tag)>::max() +
1] = {&&do_pushConstVal,
&&do_pushAccessVal,
&&do_pushOwnedAccessorVal,
&&do_pushEnvAccessorVal,
&&do_pushMoveVal,
&&do_pushLocalVal,
&&do_pushMoveLocalVal,
&&do_pushOneArgLambda,
&&do_pushTwoArgLambda,
&&do_pop,
&&do_swap,
&&do_makeOwn,
constexpr DispatchTable dispatchTable =
defaultInitializeDispatchTable(&&do_lastInstruction,
{&&do_pushConstVal,
&&do_pushAccessVal,
&&do_pushOwnedAccessorVal,
&&do_pushEnvAccessorVal,
&&do_pushMoveVal,
&&do_pushLocalVal,
&&do_pushMoveLocalVal,
&&do_pushOneArgLambda,
&&do_pushTwoArgLambda,
&&do_pop,
&&do_swap,
&&do_makeOwn,
&&do_add,
&&do_sub,
&&do_mul,
&&do_div,
&&do_idiv,
&&do_mod,
&&do_negate,
&&do_numConvert,
&&do_add,
&&do_sub,
&&do_mul,
&&do_div,
&&do_idiv,
&&do_mod,
&&do_negate,
&&do_numConvert,
&&do_logicNot,
&&do_logicNot,
&&do_less,
&&do_lessEq,
&&do_greater,
&&do_greaterEq,
&&do_eq,
&&do_neq,
&&do_less,
&&do_lessEq,
&&do_greater,
&&do_greaterEq,
&&do_eq,
&&do_neq,
&&do_cmp3w,
&&do_cmp3w,
&&do_collLess,
&&do_collLessEq,
&&do_collGreater,
&&do_collGreaterEq,
&&do_collEq,
&&do_collNeq,
&&do_collCmp3w,
&&do_collLess,
&&do_collLessEq,
&&do_collGreater,
&&do_collGreaterEq,
&&do_collEq,
&&do_collNeq,
&&do_collCmp3w,
&&do_fillEmpty,
&&do_fillEmptyImm,
&&do_getField,
&&do_getFieldImm,
&&do_getElement,
&&do_collComparisonKey,
&&do_getFieldOrElement,
&&do_traverseP,
&&do_traversePImm,
&&do_traverseF,
&&do_traverseFImm,
&&do_magicTraverseF,
&&do_setField,
&&do_getArraySize,
&&do_fillEmpty,
&&do_fillEmptyImm,
&&do_getField,
&&do_getFieldImm,
&&do_getElement,
&&do_collComparisonKey,
&&do_getFieldOrElement,
&&do_traverseP,
&&do_traversePImm,
&&do_traverseF,
&&do_traverseFImm,
&&do_magicTraverseF,
&&do_setField,
&&do_getArraySize,
&&do_aggSum,
&&do_aggCount,
&&do_aggMin,
&&do_aggMax,
&&do_aggFirst,
&&do_aggLast,
&&do_aggSum,
&&do_aggCount,
&&do_aggMin,
&&do_aggMax,
&&do_aggFirst,
&&do_aggLast,
&&do_aggCollMin,
&&do_aggCollMax,
&&do_aggCollMin,
&&do_aggCollMax,
&&do_exists,
&&do_isNull,
&&do_isObject,
&&do_isArray,
&&do_isInList,
&&do_isString,
&&do_isNumber,
&&do_isBinData,
&&do_isDate,
&&do_isNaN,
&&do_isInfinity,
&&do_isRecordId,
&&do_isMinKey,
&&do_isMaxKey,
&&do_isTimestamp,
&&do_isKeyString,
&&do_typeMatchImm,
&&do_exists,
&&do_isNull,
&&do_isObject,
&&do_isArray,
&&do_isInList,
&&do_isString,
&&do_isNumber,
&&do_isBinData,
&&do_isDate,
&&do_isNaN,
&&do_isInfinity,
&&do_isRecordId,
&&do_isMinKey,
&&do_isMaxKey,
&&do_isTimestamp,
&&do_isKeyString,
&&do_typeMatchImm,
&&do_function,
&&do_functionSmall,
&&do_function,
&&do_functionSmall,
&&do_jmp,
&&do_jmpTrue,
&&do_jmpFalse,
&&do_jmpNothing,
&&do_jmpNotNothing,
&&do_ret,
&&do_allocStack,
&&do_jmp,
&&do_jmpTrue,
&&do_jmpFalse,
&&do_jmpNothing,
&&do_jmpNotNothing,
&&do_ret,
&&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
auto pcPointer = code->instrs().data() + position;
@@ -1472,6 +1491,15 @@ void ByteCode::runInternal(const CodeFragment* code, int64_t position) {
valueBlockApplyLambda(code);
}
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
#else
}