0026913: Vulnerable mechanism in Standard_Type leads to assert
[occt.git] / src / Standard / Standard_Type.cxx
1 // Copyright (c) 1998-1999 Matra Datavision
2 // Copyright (c) 1999-2014 OPEN CASCADE SAS
3 //
4 // This file is part of Open CASCADE Technology software library.
5 //
6 // This library is free software; you can redistribute it and/or modify it under
7 // the terms of the GNU Lesser General Public License version 2.1 as published
8 // by the Free Software Foundation, with special exception defined in the file
9 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
10 // distribution for complete text of the license and disclaimer of any warranty.
11 //
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
14
15
16 #include <Standard_Type.hxx>
17 #include <Standard_Mutex.hxx>
18 #include <Standard_Assert.hxx>
19
20 #include <NCollection_DataMap.hxx>
21
22 IMPLEMENT_STANDARD_RTTIEXT(Standard_Type,Standard_Transient)
23
24 //============================================================================
25
26 namespace {
27 static Standard_CString copy_string (const char* theString)
28 {
29   size_t aLength = strlen (theString);
30   char* aResult = static_cast<char*> (Standard::Allocate (aLength + 1));
31   strncpy (aResult, theString, aLength + 1); //including null-character
32   return aResult;
33 }
34 }
35
36 Standard_Type::Standard_Type (const char* theSystemName,
37                               const char* theName,
38                               Standard_Size theSize,
39                               const Handle(Standard_Type)& theParent) :
40   mySystemName (copy_string (theSystemName)),
41   myName(theName), mySize(theSize), myParent(theParent)
42 {
43 }
44
45 //============================================================================
46
47 Standard_Boolean Standard_Type::SubType (const Handle(Standard_Type)& theOther) const
48 {
49   return ! theOther.IsNull() && (theOther == this || (! myParent.IsNull() && myParent->SubType (theOther)));
50 }
51
52 //============================================================================
53
54 Standard_Boolean Standard_Type::SubType (const Standard_CString theName) const
55 {
56   return theName != 0 && (IsEqual (myName, theName) || (! myParent.IsNull() && myParent->SubType (theName)));
57 }
58
59 // ------------------------------------------------------------------
60 // Print (me; s: in out OStream) returns OStream;
61 // ------------------------------------------------------------------
62 void Standard_Type::Print (Standard_OStream& AStream) const
63 {
64   AStream << hex << (Standard_Address)this << " : " << dec << myName ;
65 }
66
67 //============================================================================
68 // Registry of types
69 //============================================================================
70
71 namespace {
72   // Value-based hasher for plain C string (char*)
73   struct CStringHasher 
74   {
75     static Standard_Integer HashCode (const Standard_CString& theKey, const Standard_Integer Upper)
76     {
77       return ::HashCode (theKey, Upper);
78     }
79     static bool IsEqual (const Standard_CString& theKey1, const Standard_CString& theKey2)
80     {
81       return ! strcmp (theKey1, theKey2);
82     }
83   };
84
85   // Map of string to type
86   typedef NCollection_DataMap<Standard_CString, Standard_Type*, CStringHasher> registry_type;
87
88   // Registry is made static in the function to ensure that it gets
89   // initialized by the time of first access
90   registry_type& GetRegistry() 
91   {
92     static registry_type theRegistry;
93     return theRegistry;
94   }
95 }
96
97 Standard_Type* Standard_Type::Register (const char* theSystemName, const char* theName,
98                                         Standard_Size theSize, const Handle(Standard_Type)& theParent)
99 {
100   // Access to registry is protected by mutex; it should not happen often because
101   // instances are cached by Standard_Type::Instance() (one per binary module)
102   static Standard_Mutex theMutex;
103   Standard_Mutex::Sentry aSentry (theMutex);
104
105   // return existing descriptor if already in the registry
106   registry_type& aRegistry = GetRegistry();
107   Standard_Type* aType = 0;
108   if (aRegistry.Find (theSystemName, aType))
109     return aType;
110
111   // else create a new descriptor
112   aType = new Standard_Type (theSystemName, theName, theSize, theParent);
113
114   // then add it to registry and return (the reference to the handle stored in the registry)
115   aRegistry.Bind (aType->mySystemName, aType);
116
117 //  cout << "Registering " << theSystemName << ": " << aRegistry.Extent() << endl;
118
119   return aType;
120 }
121
122 Standard_Type::~Standard_Type ()
123 {
124   // remove descriptor from the registry
125   registry_type& aRegistry = GetRegistry();
126   Standard_ASSERT(aRegistry.UnBind (mySystemName), "Standard_Type::~Standard_Type() cannot find itself in registry",);
127
128 //  cout << "Unregistering " << mySystemName << ": " << aRegistry.Extent() << endl;
129   Standard::Free (mySystemName);
130 }