Logo ROOT  
Reference Guide
TCheckHashRecursiveRemoveConsistency.h
Go to the documentation of this file.
1 // @(#)root/meta:$Id$
2 // Author: Rene Brun 07/01/95
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 #ifndef ROOT_TCheckHashRecursiveRemoveConsistency
13 #define ROOT_TCheckHashRecursiveRemoveConsistency
14 
15 #include "TBaseClass.h"
16 #include "TClass.h"
17 #include "TError.h"
18 #include "TMethod.h"
19 
20 #include <list>
21 #include <utility>
22 #include <iostream>
23 #include <mutex>
24 
25 //////////////////////////////////////////////////////////////////////////
26 // //
27 // TCheckHashRecursiveRemoveConsistency //
28 // //
29 // Utility class to discover whether a class that overload //
30 // TObject::Hash also (as required) calls RecursiveRemove in its //
31 // destructor. //
32 // //
33 //////////////////////////////////////////////////////////////////////////
34 
35 namespace ROOT {
36 namespace Internal {
37 
38 class TCheckHashRecursiveRemoveConsistency : public TObject {
39 public:
40  struct Value {
43  };
44  using Value_t = Value; // std::pair<ULong_t, TObject*>;
45 
46  std::list<Value> fCont;
47  std::mutex fMutex;
48 
49 public:
50  // Default constructor. Adds object to the list of
51  // cleanups.
53  {
55  gROOT->GetListOfCleanups()->Add(this);
56  }
57 
58  // Destructor. This class does not overload
59  // Hash so it can rely on the base class to call
60  // RecursiveRemove (and hence remove this from the list
61  // of cleanups).
63  {
64  // ... unless the mechanism is disabled in which case
65  // we need to do it explicitly.
66  if (!gROOT->MustClean())
67  gROOT->GetListOfCleanups()->Remove(this);
68  }
69 
70  void Add(TObject *obj)
71  {
72  obj->SetBit(kMustCleanup);
73  auto hashValue = obj->Hash(); // This might/will take the ROOT lock.
74 
75  std::unique_lock<std::mutex> lock(fMutex);
76  fCont.push_back(Value_t{hashValue, obj});
77  }
78 
79  void RecursiveRemove(TObject *obj)
80  {
81  // Since we use std::list, a remove (from another thread)
82  // would invalidate out iterator and taking the write lock
83  // 'only' inside the loop would suspend this thread and lead
84  // another reader or write go on; consequently we would need
85  // to re-find the object we are wanting to remove.
86  std::unique_lock<std::mutex> lock(fMutex);
87 
88  // std::cout << "Recursive Remove called for: " << obj << '\n';
89  for (auto p = fCont.begin(); p != fCont.end(); ++p) {
90  if (p->fObjectPtr == obj) {
91  // std::cout << " Found object with hash = " << p->fRecordedHash << '\n';
92  // std::cout << " Current hash = " << obj->Hash() << '\n';
93  if (p->fRecordedHash == obj->Hash())
94  fCont.erase(p);
95  // else
96  // std::cout << " Error: the recorded hash and the one returned by Hash are distinct.\n";
97  break;
98  }
99  }
100  }
101 
102  void SlowRemove(TObject *obj)
103  {
104  std::unique_lock<std::mutex> lock(fMutex);
105 
106  for (auto p = fCont.begin(); p != fCont.end(); ++p) {
107  if (p->fObjectPtr == obj) {
108  fCont.erase(p);
109  break;
110  }
111  }
112  }
113 
114  enum EResult {
118  };
119 
121  {
122  if (!classRef.HasDefaultConstructor() || classRef.Property() & kIsAbstract)
123  return kInconclusive; // okay that's probably a false negative ...
124 
125  auto size = fCont.size();
126  TObject *obj = (TObject *)classRef.DynamicCast(TObject::Class(), classRef.New(TClass::kDummyNew));
127  if (!obj || (!gROOT->MustClean() && obj->TestBit(kIsReferenced) && obj->GetUniqueID() != 0)) {
128  // Clean up is disable and the object is such that we wont be able to 'mark' it
129  // as needing a clean up anyway, so we can not actually test it.
130  return kInconclusive;
131  }
133  Add(obj);
134  delete obj;
135 
136  if (fCont.size() != size) {
137  // std::cerr << "Error: old= " << size << " new=" << fCont.size() << '\n';
138  // std::cerr << "Error " << classRef.GetName() <<
139  // " or one of its base classes override TObject::Hash but does not call TROOT::CallRecursiveRemoveIfNeeded
140  // in its destructor.\n";
141  SlowRemove(obj);
142  return kInconsistent;
143  } else {
144  return kConsistent;
145  }
146  }
147 
149  {
150 
151  if (classRef.HasLocalHashMember() && CheckRecursiveRemove(classRef) != kConsistent) {
152  return &classRef;
153  }
154 
155  for (auto base : ROOT::Detail::TRangeStaticCast<TBaseClass>(classRef.GetListOfBases())) {
156  TClass *baseCl = base->GetClassPointer();
157  TClass *res = FindMissingRecursiveRemove(*baseCl);
158  if (res)
159  return res;
160  }
161  return nullptr;
162  }
163 
164  bool VerifyRecursiveRemove(const char *classname)
165  {
166  TClass *classPtr = TClass::GetClass(classname);
167  if (classPtr)
168  return VerifyRecursiveRemove(*classPtr);
169  else
170  return true;
171  }
172 
174  {
175  // Use except if the class is non-default/abstract and HasLocalHashMember.
176  if (classRef.fRuntimeProperties) {
177  // We already did this testing for this class.
178  return classRef.HasConsistentHashMember() ? kConsistent : kInconsistent;
179  }
180 
181  if (classRef.HasLocalHashMember())
182  return CheckRecursiveRemove(classRef);
183 
184  EResult baseResult = kConsistent;
185  for (auto base : ROOT::Detail::TRangeStaticCast<TBaseClass>(classRef.GetListOfBases())) {
186  TClass *baseCl = base->GetClassPointer();
187 
188  if (baseCl->HasLocalHashMember() &&
189  (!baseCl->HasDefaultConstructor() || baseCl->Property() & kIsAbstract))
190  {
191  // We won't be able to check the base class, we need to (try) to check
192  // this class even-though it does not have a local HashMember.
193  return CheckRecursiveRemove(classRef);
194  }
195  auto baseConsistency = HasConsistentHashMember(*baseCl);
196  if (baseConsistency == kInconsistent) {
197  baseResult = kInconsistent;
198  } else if (baseConsistency == kInconclusive) {
199  return CheckRecursiveRemove(classRef);
200  }
201  }
202  return baseResult;
203  }
204 
205  bool VerifyRecursiveRemove(TClass &classRef)
206  {
207  // If the class does not inherit from TObject, the setup is always 'correct'
208  // (or more exactly does not matter).
209  if (!classRef.IsTObject())
210  return true;
211 
212  if (classRef.HasLocalHashMember() &&
213  (!classRef.HasDefaultConstructor() || classRef.Property() & kIsAbstract))
214  // We won't be able to check, so assume the worst but don't issue any
215  // error message.
216  return false;
217 
218  if (HasConsistentHashMember(classRef) != kConsistent) {
219  TClass *failing = FindMissingRecursiveRemove(classRef);
220 
221  // Because ClassDefInline does not yet support class template on all platforms,
222  // we have no ClassDef and thus can not get a good message from TObject::Error.
223  constexpr const char *funcName = "ROOT::Internal::TCheckHashRecursiveRemoveConsistency::CheckRecursiveRemove";
224  if (failing) {
225  ::Error(funcName,
226  "The class %s overrides TObject::Hash but does not call TROOT::RecursiveRemove in its destructor (seen while checking %s).",
227  failing->GetName(),classRef.GetName());
228  } else {
229  ::Error(funcName, "The class %s "
230  "or one of its base classes override TObject::Hash but does not call "
231  "TROOT::CallRecursiveRemoveIfNeeded in its destructor.\n",
232  classRef.GetName());
233  }
234  return false;
235  }
236  return true;
237  }
238 
239  static bool Check(TClass &classRef)
240  {
242  return checker.VerifyRecursiveRemove(classRef);
243  }
244 
246 };
247 
248 } // namespace Internal
249 } // namespace ROOT
250 
251 #endif // ROOT__TCheckHashRecursiveRemoveConsistency
TObject::kMustCleanup
@ kMustCleanup
if object destructor must call RecursiveRemove()
Definition: TObject.h:60
ROOT::Internal::TCheckHashRecursiveRemoveConsistency::kInconclusive
@ kInconclusive
Definition: TCheckHashRecursiveRemoveConsistency.h:134
ROOT::Internal::TCheckHashRecursiveRemoveConsistency::Value::fRecordedHash
ULong_t fRecordedHash
Definition: TCheckHashRecursiveRemoveConsistency.h:65
ROOT::Internal::TCheckHashRecursiveRemoveConsistency::~TCheckHashRecursiveRemoveConsistency
~TCheckHashRecursiveRemoveConsistency()
Definition: TCheckHashRecursiveRemoveConsistency.h:80
TObject::TestBit
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition: TObject.h:172
TClass::Property
Long_t Property() const
Set TObject::fBits and fStreamerType to cache information about the class.
Definition: TClass.cxx:5857
ROOT::Internal::TCheckHashRecursiveRemoveConsistency::fCont
std::list< Value > fCont
Definition: TCheckHashRecursiveRemoveConsistency.h:64
TMethod.h
TObject::Error
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:890
ROOT::Internal::TCheckHashRecursiveRemoveConsistency::Add
void Add(TObject *obj)
Definition: TCheckHashRecursiveRemoveConsistency.h:88
ROOT::Internal::TCheckHashRecursiveRemoveConsistency::Value
Definition: TCheckHashRecursiveRemoveConsistency.h:58
TClass::HasDefaultConstructor
Bool_t HasDefaultConstructor(Bool_t testio=kFALSE) const
Return true if we have access to a constructor usable for I/O.
Definition: TClass.cxx:7135
ROOT::Internal::TCheckHashRecursiveRemoveConsistency::VerifyRecursiveRemove
bool VerifyRecursiveRemove(const char *classname)
Definition: TCheckHashRecursiveRemoveConsistency.h:182
TObject::GetUniqueID
virtual UInt_t GetUniqueID() const
Return the unique object id.
Definition: TObject.cxx:377
ROOT::Internal::TCheckHashRecursiveRemoveConsistency::RecursiveRemove
void RecursiveRemove(TObject *obj)
Recursively remove this object from a list.
Definition: TCheckHashRecursiveRemoveConsistency.h:97
TBaseClass.h
ROOT::Internal::TCheckHashRecursiveRemoveConsistency::SlowRemove
void SlowRemove(TObject *obj)
Definition: TCheckHashRecursiveRemoveConsistency.h:120
TClass.h
TObject::Hash
virtual ULong_t Hash() const
Return hash value for this object.
Definition: TObject.cxx:435
ROOT::Internal::SetRequireCleanup
void SetRequireCleanup(TObject &obj)
Definition: TROOT.h:381
TClass::HasLocalHashMember
Bool_t HasLocalHashMember() const
Returns true if this class has an definition and/or overload of the member function Hash.
Definition: TClass.cxx:7163
ROOT::Internal::TCheckHashRecursiveRemoveConsistency::CheckRecursiveRemove
EResult CheckRecursiveRemove(TClass &classRef)
Definition: TCheckHashRecursiveRemoveConsistency.h:138
ROOT::Internal::TCheckHashRecursiveRemoveConsistency::kInconsistent
@ kInconsistent
Definition: TCheckHashRecursiveRemoveConsistency.h:133
ROOT::Internal::TCheckHashRecursiveRemoveConsistency::ClassDefInline
ClassDefInline(TCheckHashRecursiveRemoveConsistency, 0)
ROOT::Internal::TCheckHashRecursiveRemoveConsistency::Value_t
Value Value_t
Definition: TCheckHashRecursiveRemoveConsistency.h:62
ROOT::Internal::TCheckHashRecursiveRemoveConsistency::fMutex
std::mutex fMutex
Definition: TCheckHashRecursiveRemoveConsistency.h:65
TClass::fRuntimeProperties
std::atomic< UChar_t > fRuntimeProperties
Definition: TClass.h:243
ROOT::Internal::TCheckHashRecursiveRemoveConsistency::TCheckHashRecursiveRemoveConsistency
TCheckHashRecursiveRemoveConsistency()
Definition: TCheckHashRecursiveRemoveConsistency.h:70
TClass::HasConsistentHashMember
Bool_t HasConsistentHashMember()
Return 'true' if we can guarantee that if this class (or any class in this class inheritance hierarch...
Definition: TClass.h:452
ROOT::Internal::TCheckHashRecursiveRemoveConsistency::kConsistent
@ kConsistent
Definition: TCheckHashRecursiveRemoveConsistency.h:135
TClass::New
void * New(ENewType defConstructor=kClassNew, Bool_t quiet=kFALSE) const
Return a pointer to a newly allocated object of this class.
Definition: TClass.cxx:4881
TObject::SetBit
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition: TObject.cxx:696
xmlio::Value
const char * Value
Definition: TXMLSetup.cxx:79
TClass::GetListOfBases
TList * GetListOfBases()
Return list containing the TBaseClass(es) of a class.
Definition: TClass.cxx:3555
ROOT::Internal::TCheckHashRecursiveRemoveConsistency::Check
static bool Check(TClass &classRef)
Definition: TCheckHashRecursiveRemoveConsistency.h:257
ROOT::Detail::TRangeStaticCast
TRangeStaticCast is an adaptater class that allows the typed iteration through a TCollection.
Definition: TCollection.h:382
ROOT::Internal::TCheckHashRecursiveRemoveConsistency::EResult
EResult
Definition: TCheckHashRecursiveRemoveConsistency.h:132
ROOT::Internal::TCheckHashRecursiveRemoveConsistency::HasConsistentHashMember
EResult HasConsistentHashMember(TClass &classRef)
Definition: TCheckHashRecursiveRemoveConsistency.h:191
Value
Definition: functioncalls.h:15
ROOT::Internal::TCheckHashRecursiveRemoveConsistency::Value::fObjectPtr
TObject * fObjectPtr
Definition: TCheckHashRecursiveRemoveConsistency.h:66
TClass::GetClass
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition: TClass.cxx:2925
ULong_t
unsigned long ULong_t
Definition: RtypesCore.h:55
TClass::IsTObject
Bool_t IsTObject() const
Return kTRUE is the class inherits from TObject.
Definition: TClass.cxx:5757
TClass::DynamicCast
void * DynamicCast(const TClass *base, void *obj, Bool_t up=kTRUE)
Cast obj of this class type up to baseclass cl if up is true.
Definition: TClass.cxx:4818
TObject::kIsReferenced
@ kIsReferenced
if object is referenced by a TRef or TRefArray
Definition: TObject.h:61
ROOT::Internal::TCheckHashRecursiveRemoveConsistency::FindMissingRecursiveRemove
TClass * FindMissingRecursiveRemove(TClass &classRef)
Definition: TCheckHashRecursiveRemoveConsistency.h:166
TClass
Definition: TClass.h:80
TObject
Definition: TObject.h:37
TNamed::GetName
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:53
Class
void Class()
Definition: Class.C:29
ROOT
VSD Structures.
Definition: StringConv.hxx:21
TClass::kDummyNew
@ kDummyNew
Definition: TClass.h:106
gROOT
#define gROOT
Definition: TROOT.h:406
TError.h
kIsAbstract
@ kIsAbstract
Definition: TDictionary.h:71