SERVER-123337 ScopedDebugInfo integrity checks (#51070) (#51099)

Co-authored-by: Alex Li <alex.li@mongodb.com>
Co-authored-by: Ryan Berryhill <ryan.berryhill@mongodb.com>
Co-authored-by: Guillaume Racicot <guillaume.racicot@mongodb.com>
Co-authored-by: Alex Li <alex.li@mongodb.com>
Co-authored-by: Ryan Berryhill <ryan.berryhill@mongodb.com>
Co-authored-by: Guillaume Racicot <guillaume.racicot@mongodb.com>
GitOrigin-RevId: c30d29c3fb72d0e33f5af5a5e2639597c16e7c6e
This commit is contained in:
Billy Donahue 2026-04-03 13:02:57 -04:00 committed by MongoDB Bot
parent 442ae3df3b
commit b0a421a6ae
4 changed files with 96 additions and 15 deletions

View File

@ -57,10 +57,9 @@ namespace mongo {
// Used by `logScopedDebugInfo` below to determine if we should log anything.
Atomic<bool> shouldLogScopedDebugInfoInAssertUtil{true};
void setDiagnosticLoggingInAssertUtil(bool newVal) {
shouldLogScopedDebugInfoInAssertUtil.store(newVal);
}
namespace {
Atomic<bool> gScopedDebugInfoStackEnabled{true};
void logScopedDebugInfo() {
if (!shouldLogScopedDebugInfoInAssertUtil.load()) {
return;
@ -97,6 +96,18 @@ MONGO_COMPILER_NORETURN void callAbort() {
}
} // namespace
void setDiagnosticLoggingInAssertUtil(bool newVal) {
shouldLogScopedDebugInfoInAssertUtil.store(newVal);
}
void setScopedDebugInfoStackEnabled(bool newVal) {
gScopedDebugInfoStackEnabled.store(newVal);
}
bool getScopedDebugInfoStackEnabled() {
return gScopedDebugInfoStackEnabled.loadRelaxed();
}
AssertionCount assertionCount;
AssertionCount::AssertionCount() : regular(0), warning(0), msg(0), user(0), rollovers(0) {}
@ -367,6 +378,8 @@ std::vector<std::string> ScopedDebugInfoStack::getAll() {
std::vector<std::string> r;
r.reserve(_stack.size());
const auto initialData = _stack.data();
const auto initialSize = _stack.size();
for (const auto& e : _stack) {
try {
r.push_back(e->toString());
@ -376,6 +389,8 @@ std::vector<std::string> ScopedDebugInfoStack::getAll() {
"label"_attr = e->label(),
"error"_attr = describeActiveException());
}
invariant(_stack.data() == initialData);
invariant(_stack.size() == initialSize);
}
return r;

View File

@ -64,6 +64,12 @@ namespace MONGO_MOD_PUB mongo {
*/
MONGO_MOD_PRIVATE void setDiagnosticLoggingInAssertUtil(bool newVal);
/**
* Whether ScopedDebugInfoStack is ever accessed by ScopedDebugInfo.
*/
MONGO_MOD_PRIVATE void setScopedDebugInfoStackEnabled(bool newVal);
MONGO_MOD_PRIVATE bool getScopedDebugInfoStackEnabled();
class MONGO_MOD_NEEDS_REPLACEMENT AssertionCount {
public:
AssertionCount();
@ -142,7 +148,6 @@ public:
return _status.extraInfo<ErrorDetail>();
}
// TODO(modularity): We should provide a way for modules to own their options parsers.
MONGO_MOD_NEEDS_REPLACEMENT static inline AtomicWord<bool> traceExceptions{false};
/**
@ -876,11 +881,34 @@ public:
virtual StringData label() const = 0;
};
void push(const Rec* rec) {
_stack.push_back(rec);
ScopedDebugInfoStack() {
_stack.reserve(64);
}
void pop() {
~ScopedDebugInfoStack() {
_checkConsistentSize();
invariant(_stack.empty());
}
void push(const Rec* rec) {
invariant(_loggingDepth == 0);
_checkConsistentSize();
_stack.push_back(rec);
++_pushes;
}
const Rec* pop() {
invariant(_loggingDepth == 0);
_checkConsistentSize();
invariant(!_stack.empty());
const Rec* popped = std::exchange(_stack.back(), {});
_stack.pop_back();
++_pops;
return popped;
}
size_t size() const {
return _stack.size();
}
/**
@ -893,8 +921,16 @@ public:
std::vector<std::string> getAll();
private:
void _checkConsistentSize() const {
auto sz = _stack.size();
invariant(_pushes == sz + _pops,
fmt::format("pushes={}, pops={}, size={}", _pushes, _pops, sz));
}
std::vector<const Rec*> _stack;
int _loggingDepth = 0;
size_t _pushes = 0;
size_t _pops = 0;
};
/** Each thread has its own stack of scoped debug info. */
@ -930,18 +966,25 @@ inline ScopedDebugInfoStack& scopedDebugInfoStack() {
template <typename T>
class ScopedDebugInfo {
public:
ScopedDebugInfo(
StringData label,
T v,
error_details::ScopedDebugInfoStack* stack = &error_details::scopedDebugInfoStack())
ScopedDebugInfo(StringData label, T v)
: ScopedDebugInfo{label, std::move(v), _defaultStack()} {}
ScopedDebugInfo(StringData label, T v, error_details::ScopedDebugInfoStack* stack)
: label(label), v(std::move(v)), stack(stack) {
stack->push(&rec);
if (stack) {
stack->push(&rec);
}
}
~ScopedDebugInfo() {
stack->pop();
if (stack) {
auto popped = stack->pop();
invariant(popped == &rec);
}
}
ScopedDebugInfo(const ScopedDebugInfo&) noexcept = delete;
ScopedDebugInfo& operator=(const ScopedDebugInfo&) noexcept = delete;
ScopedDebugInfo(const ScopedDebugInfo&) = delete;
ScopedDebugInfo& operator=(const ScopedDebugInfo&) = delete;
private:
struct ThisRec : error_details::ScopedDebugInfoStack::Rec {
@ -955,6 +998,12 @@ private:
const ScopedDebugInfo* owner;
};
static error_details::ScopedDebugInfoStack* _defaultStack() {
if (!getScopedDebugInfoStackEnabled())
return {};
return &error_details::scopedDebugInfoStack();
}
StringData label;
T v;
error_details::ScopedDebugInfoStack* stack;

View File

@ -41,11 +41,13 @@ MONGO_INITIALIZER(SetUpDiagnosticLoggingStatus)(InitializerContext*) {
bool signalHandlerLoggingVal = signalHandlerUsesDiagnosticLogging.load();
setDiagnosticLoggingInSignalHandlers(startUpVal && signalHandlerLoggingVal);
setDiagnosticLoggingInAssertUtil(startUpVal);
setScopedDebugInfoStackEnabled(startUpVal);
}
Status onUpdateEnableDiagnosticLogging(bool newValue) {
setDiagnosticLoggingInSignalHandlers(newValue);
setDiagnosticLoggingInAssertUtil(newValue);
setScopedDebugInfoStackEnabled(newValue);
return Status::OK();
}

View File

@ -802,5 +802,20 @@ TEST(AssertUtils, FailuresAreNotConstexpr) {
}()));
}
TEST(ScopedDebugInfoStack, Enabled) {
ASSERT(getScopedDebugInfoStackEnabled());
ASSERT_EQ(error_details::scopedDebugInfoStack().size(), 0);
ScopedDebugInfo scopedInfo("test", "hello");
ASSERT_EQ(error_details::scopedDebugInfoStack().size(), 1);
}
TEST(ScopedDebugInfoStack, Disabled) {
RAIIServerParameterControllerForTest knobController("enableDiagnosticLogging", false);
ASSERT(!getScopedDebugInfoStackEnabled());
ASSERT_EQ(error_details::scopedDebugInfoStack().size(), 0);
ScopedDebugInfo scopedInfo("test", "hello");
ASSERT_EQ(error_details::scopedDebugInfoStack().size(), 0);
}
} // namespace
} // namespace mongo