Skip to content

Commit bbc642c

Browse files
authored
Fix use-after-free in CommittingOps tracking (#8712)
1 parent 93bd594 commit bbc642c

File tree

5 files changed

+388
-14
lines changed

5 files changed

+388
-14
lines changed

ydb/core/tx/datashard/datashard_pipeline.cpp

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2274,11 +2274,15 @@ void TPipeline::AddCommittingOp(const TOperation::TPtr& op) {
22742274
if (!Self->IsMvccEnabled() || op->IsReadOnly())
22752275
return;
22762276

2277+
Y_VERIFY_S(!op->GetCommittingOpsVersion(),
2278+
"Trying to AddCommittingOp " << *op << " more than once");
2279+
22772280
TRowVersion version = Self->GetReadWriteVersions(op.Get()).WriteVersion;
22782281
if (op->IsImmediate())
22792282
CommittingOps.Add(op->GetTxId(), version);
22802283
else
22812284
CommittingOps.Add(version);
2285+
op->SetCommittingOpsVersion(version);
22822286
}
22832287

22842288
void TPipeline::RemoveCommittingOp(const TRowVersion& version) {
@@ -2288,13 +2292,13 @@ void TPipeline::RemoveCommittingOp(const TRowVersion& version) {
22882292
}
22892293

22902294
void TPipeline::RemoveCommittingOp(const TOperation::TPtr& op) {
2291-
if (!Self->IsMvccEnabled() || op->IsReadOnly())
2292-
return;
2293-
2294-
if (op->IsImmediate())
2295-
CommittingOps.Remove(op->GetTxId());
2296-
else
2297-
CommittingOps.Remove(TRowVersion(op->GetStep(), op->GetTxId()));
2295+
if (const auto& version = op->GetCommittingOpsVersion()) {
2296+
if (op->IsImmediate())
2297+
CommittingOps.Remove(op->GetTxId(), *version);
2298+
else
2299+
CommittingOps.Remove(*version);
2300+
op->ResetCommittingOpsVersion();
2301+
}
22982302
}
22992303

23002304
bool TPipeline::WaitCompletion(const TOperation::TPtr& op) const {

ydb/core/tx/datashard/datashard_pipeline.h

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -424,11 +424,13 @@ class TPipeline : TNonCopyable {
424424
ui64 Step;
425425
ui64 TxId;
426426
mutable ui32 Counter;
427+
mutable ui32 TxCounter;
427428

428429
TItem(const TRowVersion& from)
429430
: Step(from.Step)
430431
, TxId(from.TxId)
431432
, Counter(1u)
433+
, TxCounter(0u)
432434
{}
433435

434436
friend constexpr bool operator<(const TItem& a, const TItem& b) {
@@ -442,6 +444,7 @@ class TPipeline : TNonCopyable {
442444

443445
using TItemsSet = TSet<TItem>;
444446
using TTxIdMap = THashMap<ui64, TItemsSet::iterator>;
447+
445448
public:
446449
inline void Add(ui64 txId, TRowVersion version) {
447450
auto res = ItemsSet.emplace(version);
@@ -450,6 +453,7 @@ class TPipeline : TNonCopyable {
450453
auto res2 = TxIdMap.emplace(txId, res.first);
451454
Y_VERIFY_S(res2.second, "Unexpected duplicate immediate tx " << txId
452455
<< " committing at " << version);
456+
res.first->TxCounter += 1;
453457
}
454458

455459
inline void Add(TRowVersion version) {
@@ -458,17 +462,29 @@ class TPipeline : TNonCopyable {
458462
res.first->Counter += 1;
459463
}
460464

461-
inline void Remove(ui64 txId) {
462-
if (auto it = TxIdMap.find(txId); it != TxIdMap.end()) {
463-
if (--it->second->Counter == 0)
464-
ItemsSet.erase(it->second);
465-
TxIdMap.erase(it);
466-
}
465+
inline void Remove(ui64 txId, TRowVersion version) {
466+
auto it = TxIdMap.find(txId);
467+
Y_VERIFY_S(it != TxIdMap.end(), "Removing immediate tx " << txId << " " << version
468+
<< " does not match a previous Add");
469+
Y_VERIFY_S(TRowVersion(it->second->Step, it->second->TxId) == version, "Removing immediate tx " << txId << " " << version
470+
<< " does not match a previous Add " << TRowVersion(it->second->Step, it->second->TxId));
471+
Y_VERIFY_S(it->second->TxCounter > 0, "Removing immediate tx " << txId << " " << version
472+
<< " with a mismatching TxCounter");
473+
--it->second->TxCounter;
474+
if (--it->second->Counter == 0)
475+
ItemsSet.erase(it->second);
476+
TxIdMap.erase(it);
467477
}
468478

469479
inline void Remove(TRowVersion version) {
470-
if (auto it = ItemsSet.find(version); it != ItemsSet.end() && --it->Counter == 0)
480+
auto it = ItemsSet.find(version);
481+
Y_VERIFY_S(it != ItemsSet.end(), "Removing version " << version
482+
<< " does not match a previous Add");
483+
if (--it->Counter == 0) {
484+
Y_VERIFY_S(it->TxCounter == 0, "Removing version " << version
485+
<< " while TxCounter has active references, possible Add/Remove mismatch");
471486
ItemsSet.erase(it);
487+
}
472488
}
473489

474490
inline bool HasOpsBelow(TRowVersion upperBound) const {

0 commit comments

Comments
 (0)