Skip to content

Commit 71b778c

Browse files
committed
Fix nullptr dereference bug in TList::RecursiveRemove()
When multiple threads are touching the list of cleanups, another thread can delete the object retrieved via TObjLink::GetObject(), and then when it is dereferenced in ob->TestBit(...) it causes a crash in ROOT. Stack trace: in TObject::TestBit (this=0x0, f=33554432) at TObject.h:159 ^^^ in TList::RecursiveRemove (this=0xb3c3e0, obj=0x7ff3547da6b0) at root/core/cont/src/TList.cxx:717 ^^^ in THashList::RecursiveRemove (this=0xb504b0, obj=0x7ff3547da6b0) at root/core/cont/src/THashList.cxx:286 in TObject::~TObject (this=0x7ff3547da6b0, __in_chrg=<optimized out>) at root/core/base/src/TObject.cxx:88
1 parent 11c2d85 commit 71b778c

File tree

1 file changed

+35
-35
lines changed

1 file changed

+35
-35
lines changed

core/cont/src/TList.cxx

Lines changed: 35 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -703,45 +703,45 @@ void TList::RecursiveRemove(TObject *obj)
703703

704704
if (!obj) return;
705705

706-
// When fCache is set and has no previous and next node, it represents
707-
// the node being cleared and/or deleted.
708-
if (fCache && fCache->fNext == 0 && fCache->fPrev == 0) {
709-
TObject *ob = fCache->GetObject();
710-
if (ob && ob->TestBit(kNotDeleted)) {
706+
// When fCache is set and has no previous and next node,
707+
// it represents the node being cleared and/or deleted.
708+
if (fCache && fCache->fNext == 0 && fCache->fPrev == 0)
709+
if (TObject *ob = fCache->GetObject())
710+
if (ob->TestBit(kNotDeleted))
711+
ob->RecursiveRemove(obj);
712+
713+
for (TObjLink *lnk = fFirst; lnk; lnk = lnk->Next()) {
714+
TObject *ob = lnk->GetObject();
715+
716+
// skip if deleted or being deleted
717+
if (!ob || !ob->TestBit(kNotDeleted))
718+
continue;
719+
720+
// not this object, but may contain this object
721+
if (!ob->IsEqual(obj)) {
711722
ob->RecursiveRemove(obj);
723+
continue;
712724
}
713-
}
714725

715-
TObjLink *lnk = fFirst;
716-
TObjLink *next = 0;
717-
while (lnk) {
718-
next = lnk->Next();
719-
TObject *ob = lnk->GetObject();
720-
if (ob->TestBit(kNotDeleted)) {
721-
if (ob->IsEqual(obj)) {
722-
if (lnk == fFirst) {
723-
fFirst = next;
724-
if (lnk == fLast)
725-
fLast = fFirst;
726-
else
727-
fFirst->fPrev = 0;
728-
DeleteLink(lnk);
729-
} else if (lnk == fLast) {
730-
fLast = lnk->Prev();
731-
fLast->fNext = 0;
732-
DeleteLink(lnk);
733-
} else {
734-
lnk->Prev()->fNext = next;
735-
lnk->Next()->fPrev = lnk->Prev();
736-
DeleteLink(lnk);
737-
}
738-
fSize--;
739-
fCache = 0;
740-
Changed();
741-
} else
742-
ob->RecursiveRemove(obj);
726+
// object found, remove it from the list
727+
if (lnk == fFirst) {
728+
fFirst = fFirst->Next();
729+
if (lnk == fLast)
730+
fLast = fFirst;
731+
else
732+
fFirst->fPrev = 0;
733+
} else if (lnk == fLast) {
734+
fLast = lnk->Prev();
735+
fLast->fNext = nullptr;
736+
} else {
737+
lnk->Prev()->fNext = lnk->Next();
738+
lnk->Next()->fPrev = lnk->Prev();
743739
}
744-
lnk = next;
740+
741+
fSize--;
742+
DeleteLink(lnk);
743+
fCache = nullptr;
744+
Changed();
745745
}
746746
}
747747

0 commit comments

Comments
 (0)