Skip to content

Commit a7b8be7

Browse files
authored
Fixes an issue with AZ::Interface<T>::Get() (o3de#11176)
- When static AZ::Names were getting the NameDictionary interface before the interface static had been initialized, it cause future calls to Get() to go into the fast read path and return nullptr. - Protect the AZ::EnvironmentVariable<T*> static by wrapping it in an accessor function. This helps ensure that the static environment variable is initialized/constructed once on first access. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com>
1 parent 0689c04 commit a7b8be7

1 file changed

Lines changed: 23 additions & 20 deletions

File tree

Code/Framework/AzCore/AzCore/Interface/Interface.h

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -102,24 +102,26 @@ namespace AZ
102102
private:
103103
static uint32_t GetVariableName();
104104

105-
/**
106-
* Module-specific static environment variable. This will require a FindVariable<>() operation
107-
* when invoked for the first time in a new module. There is one of these per module, but they
108-
* all point to the same internal pointer.
109-
*/
110-
static EnvironmentVariable<T*> s_instance;
105+
inline static EnvironmentVariable<T*>& GetInstance()
106+
{
107+
/**
108+
* Module-specific static environment variable. This will require a FindVariable<>() operation
109+
* when invoked for the first time in a new module. There is one of these per module, but they
110+
* all point to the same internal pointer.
111+
*/
112+
static EnvironmentVariable<T*> s_instance;
113+
return s_instance;
114+
}
115+
111116
static AZStd::shared_mutex s_mutex;
112117
static bool s_instanceAssigned;
113118
};
114119

115-
template <typename T>
116-
EnvironmentVariable<T*> Interface<T>::s_instance;
117-
118120
template <typename T>
119121
AZStd::shared_mutex Interface<T>::s_mutex;
120122

121123
template <typename T>
122-
bool Interface<T>::s_instanceAssigned;
124+
bool Interface<T>::s_instanceAssigned = false;
123125

124126
template <typename T>
125127
void Interface<T>::Register(T* type)
@@ -137,8 +139,8 @@ namespace AZ
137139
}
138140

139141
AZStd::unique_lock<AZStd::shared_mutex> lock(s_mutex);
140-
s_instance = Environment::CreateVariable<T*>(GetVariableName());
141-
s_instance.Get() = type;
142+
GetInstance() = Environment::CreateVariable<T*>(GetVariableName());
143+
GetInstance().Get() = type;
142144
s_instanceAssigned = true;
143145
}
144146

@@ -151,16 +153,17 @@ namespace AZ
151153
return;
152154
}
153155

154-
if (s_instance && s_instance.Get() != type)
156+
if (GetInstance() && GetInstance().Get() != type)
155157
{
156-
AZ_Assert(false, "Interface '%s' is not the same instance that was registered! [Expected '%p', Found '%p']", AzTypeInfo<T>::Name(), type, s_instance.Get());
158+
AZ_Assert(false, "Interface '%s' is not the same instance that was registered! [Expected '%p', Found '%p']",
159+
AzTypeInfo<T>::Name(), type, GetInstance().Get());
157160
return;
158161
}
159162

160163
// Assign the internal pointer to null and release the EnvironmentVariable reference.
161164
AZStd::unique_lock<AZStd::shared_mutex> lock(s_mutex);
162-
*s_instance = nullptr;
163-
s_instance.Reset();
165+
*GetInstance() = nullptr;
166+
GetInstance().Reset();
164167
s_instanceAssigned = false;
165168
}
166169

@@ -173,16 +176,16 @@ namespace AZ
173176
AZStd::shared_lock<AZStd::shared_mutex> lock(s_mutex);
174177
if (s_instanceAssigned)
175178
{
176-
return s_instance ? s_instance.Get() : nullptr;
179+
return GetInstance() ? GetInstance().Get() : nullptr;
177180
}
178181
}
179182

180183
// If the instance doesn't exist (which means we could be in a different module),
181184
// take the full lock and request it.
182185
AZStd::unique_lock<AZStd::shared_mutex> lock(s_mutex);
183-
s_instance = Environment::FindVariable<T*>(GetVariableName());
184-
s_instanceAssigned = static_cast<bool>(s_instance);
185-
return s_instance ? s_instance.Get() : nullptr;
186+
GetInstance() = Environment::FindVariable<T*>(GetVariableName());
187+
s_instanceAssigned = static_cast<bool>(GetInstance());
188+
return GetInstance() ? GetInstance().Get() : nullptr;
186189
}
187190

188191
template <typename T>

0 commit comments

Comments
 (0)