Skip to content

Commit a6ca258

Browse files
authored
hardening async_key_value_source (#1607)
1 parent fb08e7f commit a6ca258

File tree

2 files changed

+51
-14
lines changed

2 files changed

+51
-14
lines changed

userspace/async/async_key_value_source.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,14 @@ class async_key_value_source
274274
m_start_time(std::chrono::steady_clock::now())
275275
{ }
276276

277+
lookup_request(const lookup_request& rhs) :
278+
m_available(rhs.m_available),
279+
m_value(rhs.m_value),
280+
m_available_condition(/*not rhs*/),
281+
m_callback(rhs.m_callback),
282+
m_start_time(rhs.m_start_time)
283+
{ }
284+
277285
/** Is the value here available? */
278286
bool m_available;
279287

@@ -293,7 +301,7 @@ class async_key_value_source
293301
std::chrono::time_point<std::chrono::steady_clock> m_start_time;
294302
};
295303

296-
typedef std::map<key_type, lookup_request> value_map;
304+
typedef std::map<const key_type, lookup_request> value_map;
297305

298306
/**
299307
* The entry point of the async thread, which blocks waiting for work

userspace/async/async_key_value_source.tpp

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ limitations under the License.
2424
#include <iostream>
2525
#include <list>
2626
#include <string>
27+
#include <utility>
2728
#include <vector>
2829

2930
namespace sysdig
@@ -142,6 +143,7 @@ void async_key_value_source<key_type, value_type>::run()
142143

143144
if(!m_terminate)
144145
{
146+
145147
run_impl();
146148
}
147149
}
@@ -163,14 +165,27 @@ bool async_key_value_source<key_type, value_type>::lookup_delayed(
163165
m_thread = std::thread(&async_key_value_source::run, this);
164166
}
165167

166-
typename value_map::const_iterator itr = m_value_map.find(key);
168+
typename value_map::iterator itr = m_value_map.find(key);
167169
bool request_complete;
168170

169171
if (itr == m_value_map.end())
170172
{
171-
// Haven't made the request yet
172-
m_value_map[key].m_available = false;
173-
m_value_map[key].m_value = value;
173+
// Haven't made the request yet. Be explicit and validate insertion.
174+
auto insert_result = m_value_map.emplace(key, lookup_request());
175+
176+
if(!insert_result.second)
177+
{
178+
g_logger.log("async_key_value_source: Failed to insert an empty item "
179+
"into the container cache.", sinsp_logger::SEV_ERROR);
180+
return false;
181+
}
182+
183+
// Replace the itr with the mapped value
184+
itr = insert_result.first;
185+
186+
// Not sure why setting the value is needed, but being consistent with
187+
// previous implementation.
188+
itr->second.m_value = value;
174189

175190
// Make request to API and let the async thread know about it
176191
if (std::find(m_request_set.begin(),
@@ -200,22 +215,25 @@ bool async_key_value_source<key_type, value_type>::lookup_delayed(
200215
// and the async thread will continue handling the request so
201216
// that it'll be available on the next call.
202217
//
203-
m_value_map[key].m_available_condition.wait_for(
218+
itr->second.m_available_condition.wait_for(
204219
guard,
205220
std::chrono::milliseconds(m_max_wait_ms));
206221

222+
// Replace the iterator in case something changed
207223
itr = m_value_map.find(key);
208224
request_complete = (itr != m_value_map.end()) && itr->second.m_available;
209225
}
210226

211227
if(request_complete)
212228
{
229+
// Pass the value back the caller and erase from the list.
213230
value = itr->second.m_value;
214-
m_value_map.erase(key);
231+
m_value_map.erase(itr);
215232
}
216233
else
217234
{
218-
m_value_map[key].m_callback = handler;
235+
// Set the callback to fill the value later
236+
itr->second.m_callback = handler;
219237
}
220238

221239
return request_complete;
@@ -267,16 +285,26 @@ void async_key_value_source<key_type, value_type>::store_value(
267285
{
268286
std::lock_guard<std::mutex> guard(m_mutex);
269287

270-
if (m_value_map[key].m_callback)
288+
typename value_map::iterator itr = m_value_map.find(key);
289+
if(itr == m_value_map.end())
271290
{
272-
m_value_map[key].m_callback(key, value);
273-
m_value_map.erase(key);
291+
g_logger.log("async_key_value_source: Container not found when committing "
292+
"to container cache. Either the container no longer exists or "
293+
"the container lookup took longer than the timeout.",
294+
sinsp_logger::SEV_WARNING);
295+
return;
296+
}
297+
298+
if (itr->second.m_callback)
299+
{
300+
itr->second.m_callback(key, value);
301+
m_value_map.erase(itr);
274302
}
275303
else
276304
{
277-
m_value_map[key].m_value = value;
278-
m_value_map[key].m_available = true;
279-
m_value_map[key].m_available_condition.notify_one();
305+
itr->second.m_value = value;
306+
itr->second.m_available = true;
307+
itr->second.m_available_condition.notify_one();
280308
}
281309
}
282310

@@ -357,3 +385,4 @@ std::chrono::steady_clock::time_point async_key_value_source<key_type, value_typ
357385
}
358386

359387
} // end namespace sysdig
388+

0 commit comments

Comments
 (0)