Merge lp:~michihenning/unity-scopes-api/fix-leak-and-warnings into lp:unity-scopes-api

Proposed by Michi Henning
Status: Merged
Approved by: Paweł Stołowski
Approved revision: 285
Merged at revision: 292
Proposed branch: lp:~michihenning/unity-scopes-api/fix-leak-and-warnings
Merge into: lp:unity-scopes-api
Diff against target: 315 lines (+52/-35)
14 files modified
HACKING (+12/-8)
include/unity/scopes/internal/QueryCtrlObjectBase.h (+1/-1)
include/unity/scopes/internal/QueryObjectBase.h (+1/-1)
include/unity/scopes/internal/ReplyObject.h (+1/-1)
include/unity/scopes/internal/ScopeObjectBase.h (+1/-1)
include/unity/scopes/internal/smartscopes/SmartScopesClient.h (+0/-1)
include/unity/scopes/utility/BufferedResultForwarder.h (+5/-3)
scoperegistry/scoperegistry.cpp (+5/-6)
smartscopesproxy/smartscopesproxy.cpp (+5/-3)
src/scopes/internal/Logger.cpp (+1/-1)
src/scopes/internal/smartscopes/SmartScopesClient.cpp (+0/-1)
src/scopes/internal/zmq_middleware/ZmqMiddleware.cpp (+11/-8)
src/scopes/utility/BufferedResultForwarder.cpp (+4/-0)
test/gtest/scopes/internal/smartscopes/smartscopesproxy/smartscopesproxy_test.cpp (+5/-0)
To merge this branch: bzr merge lp:~michihenning/unity-scopes-api/fix-leak-and-warnings
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve
Paweł Stołowski (community) Approve
Review via email: mp+247254@code.launchpad.net

Commit message

Fixed memory leak in BufferedResultForwarder. Fixed a bunch of
warnings for clang build. Minor updates to HACKING.

During the tests for revision 282, we got a core dump from the smartscopesproxy test.

The core dump was caused by rapid startup and shutdown of the RuntimeImpl instances used by the smartscopesproxy test. That allowed a zmq endpoint to linger behind after the previous RuntimeImpl was destroyed, causing the next RuntimeImpl to throw because the endpoint was still bound. (zmq context destruction is asynchronous, unfortunately.) In turn, that exposed a life cycle issue where ZmqMiddleware was calling into an already-destroyed logger instance, because the signal handlers in the registry and smartscopes registry were keeping the ZmqMiddleware instance alive beyond the life time of the RuntimeImpl.

Solution was two-fold:

- Don't log from the ZmqMiddleware destructor. No information is lost because the same exception information is provided by wait_for_shutdown(), and RuntimeImpl logs that anyway.

 - Added 300 ms delay to the smartscopesproxy test when the runtime is destroyed. This gives zmq time to close its server sockets, so we don't get a double-bind failure.

Description of the change

Fixed memory leak in BufferedResultForwarder. Fixed a bunch of
warnings for clang build. Minor updates to HACKING.

During the tests for revision 282, we got a core dump from the smartscopesproxy test.

The core dump was caused by rapid startup and shutdown of the RuntimeImpl instances used by the smartscopesproxy test. That allowed a zmq endpoint to linger behind after the previous RuntimeImpl was destroyed, causing the next RuntimeImpl to throw because the endpoint was still bound. (zmq context destruction is asynchronous, unfortunately.) In turn, that exposed a life cycle issue where ZmqMiddleware was calling into an already-destroyed logger instance, because the signal handlers in the registry and smartscopes registry were keeping the ZmqMiddleware instance alive beyond the life time of the RuntimeImpl.

Solution was two-fold:

- Don't log from the ZmqMiddleware destructor. No information is lost because the same exception information is provided by wait_for_shutdown(), and RuntimeImpl logs that anyway.

 - Added 300 ms delay to the smartscopesproxy test when the runtime is destroyed. This gives zmq time to close its server sockets, so we don't get a double-bind failure.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Paweł Stołowski (stolowski) wrote :

Oh gosh, great catch with the mem leak, thanks!

review: Approve
Revision history for this message
Michi Henning (michihenning) wrote :

Top-approving myself after fixing typo in HACKING.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
285. By Michi Henning

Removed call to boost log from ZmqMiddleware destructor.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'HACKING'
2--- HACKING 2015-01-06 01:05:48 +0000
3+++ HACKING 2015-01-23 05:01:22 +0000
4@@ -61,12 +61,7 @@
5 $ make test
6 $ make coverage
7
8-Note that, with gcc 4.7.2 and cmake 2.8.10, you may get a bunch of
9-warnings. To fix this, you can build cmake 2.8.10 with the following patch:
10-
11-http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=61ace1df2616e472d056b302e4269cbf112fb020#patch1
12-
13-Unfortunately, it is not possibly to get 100% coverage for some files,
14+Unfortunately, it is not possible to get 100% coverage for some files,
15 mainly due to gcc's generation of two destructors for dynamic and non-
16 dynamic instances. For abstract base classes and for classes that
17 prevent stack and static allocation, this causes one of the destructors
18@@ -85,7 +80,8 @@
19
20 $ make clean-coverage
21
22-This deletes all the .gcda files, allowing the merge to succeed again.
23+This deletes all the .gcda files, allowing the merge to (sometimes) succeed again.
24+If this doesn't work either, the only remedy is to do a clean build.
25
26 If lcov complains about unrecognized lines involving '=====',
27 you can patch geninfo and gcovr as explained here:
28@@ -102,13 +98,21 @@
29 We use a format tool that fixes a whole lot of issues
30 regarding code style. The formatting changes made by
31 the tool are generally sensible (even though they may not be your
32-personal preference in all case). If there is a case where the formatting
33+personal preference in all cases). If there is a case where the formatting
34 really messes things up, consider re-arranging the code to avoid the problem.
35 The convenience of running the entire code base through the pretty-printer
36 far outweighs any minor glitches with pretty printing, and it means that
37 we get consistent code style for free, rather than endlessly having to
38 watch out for formatting issues during code reviews.
39
40+As of clang-format-3.7, you can use
41+
42+ // clang-format off
43+ void unformatted_code ;
44+ // clang-format on
45+
46+to suppress formatting for a section of code.
47+
48 To format specific files:
49
50 ${CMAKE_BINARY_DIR}/tools/formatcode x.cpp x.h
51
52=== modified file 'include/unity/scopes/internal/QueryCtrlObjectBase.h'
53--- include/unity/scopes/internal/QueryCtrlObjectBase.h 2015-01-09 00:14:14 +0000
54+++ include/unity/scopes/internal/QueryCtrlObjectBase.h 2015-01-23 05:01:22 +0000
55@@ -29,7 +29,7 @@
56 namespace internal
57 {
58
59-class InvokeInfo;
60+struct InvokeInfo;
61
62 class QueryCtrlObjectBase : public AbstractObject
63 {
64
65=== modified file 'include/unity/scopes/internal/QueryObjectBase.h'
66--- include/unity/scopes/internal/QueryObjectBase.h 2015-01-09 00:14:14 +0000
67+++ include/unity/scopes/internal/QueryObjectBase.h 2015-01-23 05:01:22 +0000
68@@ -31,7 +31,7 @@
69 namespace internal
70 {
71
72-class InvokeInfo;
73+struct InvokeInfo;
74
75 class QueryObjectBase : public AbstractObject
76 {
77
78=== modified file 'include/unity/scopes/internal/ReplyObject.h'
79--- include/unity/scopes/internal/ReplyObject.h 2015-01-09 00:14:14 +0000
80+++ include/unity/scopes/internal/ReplyObject.h 2015-01-23 05:01:22 +0000
81@@ -35,7 +35,7 @@
82 namespace internal
83 {
84
85-class InvokeInfo;
86+struct InvokeInfo;
87 class RuntimeImpl;
88
89 // A ReplyObject sits in between the incoming requests from the middleware layer and the
90
91=== modified file 'include/unity/scopes/internal/ScopeObjectBase.h'
92--- include/unity/scopes/internal/ScopeObjectBase.h 2015-01-09 00:14:14 +0000
93+++ include/unity/scopes/internal/ScopeObjectBase.h 2015-01-23 05:01:22 +0000
94@@ -38,7 +38,7 @@
95 namespace internal
96 {
97
98-class InvokeInfo;
99+struct InvokeInfo;
100
101 class ScopeObjectBase : public AbstractObject
102 {
103
104=== modified file 'include/unity/scopes/internal/smartscopes/SmartScopesClient.h'
105--- include/unity/scopes/internal/smartscopes/SmartScopesClient.h 2015-01-09 03:16:51 +0000
106+++ include/unity/scopes/internal/smartscopes/SmartScopesClient.h 2015-01-23 05:01:22 +0000
107@@ -229,7 +229,6 @@
108
109 HttpClientInterface::SPtr http_client_;
110 JsonNodeInterface::SPtr json_node_;
111- RuntimeImpl* runtime_;
112 boost::log::sources::severity_channel_logger_mt<>& logger_;
113 std::string url_;
114
115
116=== modified file 'include/unity/scopes/utility/BufferedResultForwarder.h'
117--- include/unity/scopes/utility/BufferedResultForwarder.h 2014-12-01 01:51:38 +0000
118+++ include/unity/scopes/utility/BufferedResultForwarder.h 2015-01-23 05:01:22 +0000
119@@ -46,6 +46,8 @@
120 /// @cond
121 NONCOPYABLE(BufferedResultForwarder);
122 UNITY_DEFINES_PTRS(BufferedResultForwarder);
123+
124+ virtual ~BufferedResultForwarder();
125 /// @endcond
126
127 /**
128@@ -56,8 +58,8 @@
129 \param next_forwarder The forwarder that becomes ready once this forwarder calls set_ready().
130 \throws unity::LogicException when passed next_forwarder that has already been linked to another BufferedResultForwarder.
131 */
132- BufferedResultForwarder(unity::scopes::SearchReplyProxy const& upstream, BufferedResultForwarder::SPtr const& next_forwarder =
133- BufferedResultForwarder::SPtr());
134+ BufferedResultForwarder(unity::scopes::SearchReplyProxy const& upstream,
135+ BufferedResultForwarder::SPtr const& next_forwarder = BufferedResultForwarder::SPtr());
136
137 /**
138 \brief Forwards a single result before calling `set_ready()`.
139@@ -104,7 +106,7 @@
140 private:
141 friend class internal::BufferedResultForwarderImpl;
142
143- internal::BufferedResultForwarderImpl *p;
144+ std::unique_ptr<internal::BufferedResultForwarderImpl> p;
145 };
146
147 } // namespace utility
148
149=== modified file 'scoperegistry/scoperegistry.cpp'
150--- scoperegistry/scoperegistry.cpp 2015-01-09 03:16:51 +0000
151+++ scoperegistry/scoperegistry.cpp 2015-01-23 05:01:22 +0000
152@@ -527,7 +527,7 @@
153 // And finally creating our runtime.
154 string identity;
155 string ss_reg_id;
156- RuntimeImpl::UPtr runtime;
157+ RuntimeImpl::SPtr runtime;
158 {
159 RuntimeConfig rt_config(config_file);
160 runtime = RuntimeImpl::create(rt_config.registry_identity(), config_file);
161@@ -576,18 +576,16 @@
162 process_timeout = c.process_timeout();
163 } // Release memory for config parser
164
165- MiddlewareBase::SPtr middleware = runtime->factory()->find(identity, mw_kind);
166-
167- // Inform the signal thread that it should shutdown the middleware
168+ // Inform the signal thread that it should shutdown the runtime
169 // if we get a termination signal.
170- signal_handler_wrapper.signal_raised().connect([middleware](core::posix::Signal signal)
171+ signal_handler_wrapper.signal_raised().connect([runtime](core::posix::Signal signal)
172 {
173 switch(signal)
174 {
175 case core::posix::Signal::sig_int:
176 case core::posix::Signal::sig_hup:
177 case core::posix::Signal::sig_term:
178- middleware->stop();
179+ runtime->destroy();
180 break;
181 default:
182 break;
183@@ -595,6 +593,7 @@
184 });
185
186 // The registry object stores the local and remote scopes
187+ MiddlewareBase::SPtr middleware = runtime->factory()->find(identity, mw_kind);
188 Executor::SPtr executor = std::make_shared<Executor>();
189 RegistryObject::SPtr registry(new RegistryObject(*signal_handler_wrapper.death_observer, executor, middleware, true));
190
191
192=== modified file 'smartscopesproxy/smartscopesproxy.cpp'
193--- smartscopesproxy/smartscopesproxy.cpp 2014-07-04 03:26:15 +0000
194+++ smartscopesproxy/smartscopesproxy.cpp 2015-01-23 05:01:22 +0000
195@@ -116,7 +116,7 @@
196 std::string ss_scope_id = ss_config.scope_identity();
197
198 // Instantiate the run time
199- RuntimeImpl::UPtr rt = RuntimeImpl::create(ss_reg_id, config_file);
200+ RuntimeImpl::SPtr rt = RuntimeImpl::create(ss_reg_id, config_file);
201
202 // Get registry config
203 RegistryConfig reg_conf(ss_reg_id, rt->registry_configfile());
204@@ -125,11 +125,13 @@
205 // Get middleware handle from runtime
206 MiddlewareBase::SPtr mw = rt->factory()->find(ss_reg_id, mw_kind);
207
208- signal_handler.signal_raised().connect([mw](core::posix::Signal)
209+ signal_handler.signal_raised().connect([rt](core::posix::Signal)
210 {
211- mw->stop();
212+ rt->destroy();
213 });
214
215+ MiddlewareBase::SPtr middleware = rt->factory()->find(ss_reg_id, mw_kind);
216+
217 // Instantiate a SS registry object
218 SSRegistryObject::SPtr reg(new SSRegistryObject(mw, ss_config, mw->get_scope_endpoint()));
219
220
221=== modified file 'src/scopes/internal/Logger.cpp'
222--- src/scopes/internal/Logger.cpp 2015-01-18 23:48:55 +0000
223+++ src/scopes/internal/Logger.cpp 2015-01-23 05:01:22 +0000
224@@ -51,7 +51,7 @@
225
226 static array<string, Logger::LastChannelEnum_> const channel_names =
227 {
228- "IPC"
229+ { "IPC" }
230 };
231
232 string const& to_severity(int s)
233
234=== modified file 'src/scopes/internal/smartscopes/SmartScopesClient.cpp'
235--- src/scopes/internal/smartscopes/SmartScopesClient.cpp 2015-01-09 03:16:51 +0000
236+++ src/scopes/internal/smartscopes/SmartScopesClient.cpp 2015-01-23 05:01:22 +0000
237@@ -116,7 +116,6 @@
238 std::string const& partner_id_path)
239 : http_client_(http_client)
240 , json_node_(json_node)
241- , runtime_(runtime)
242 , logger_(runtime ? runtime->logger() : test_logger::get())
243 , have_latest_cache_(false)
244 , query_counter_(0)
245
246=== modified file 'src/scopes/internal/zmq_middleware/ZmqMiddleware.cpp'
247--- src/scopes/internal/zmq_middleware/ZmqMiddleware.cpp 2015-01-09 03:16:51 +0000
248+++ src/scopes/internal/zmq_middleware/ZmqMiddleware.cpp 2015-01-23 05:01:22 +0000
249@@ -160,24 +160,27 @@
250 // Until we figure out what's going on here, we measure
251 // how long it takes and print a warning if it takes
252 // longer than 100 ms.
253+ //
254+ // Update: This happens only when build nodes on
255+ // Jenkins are ridiculously slow. Leaving the
256+ // diagnostic in place for the time being, which
257+ // helps with realizing when something isn't working
258+ // right on Jenkins.
259 auto start_time = chrono::system_clock::now();
260 context_.terminate();
261 auto end_time = chrono::system_clock::now();
262 auto millisecs = chrono::duration_cast<chrono::milliseconds>(end_time - start_time).count();
263 if (millisecs > 100)
264 {
265- BOOST_LOG(logger_)
266- << "warning: ~ZmqMiddleware(): context_.terminate() took " << millisecs
267- << " ms to complete for " << server_name_;
268+ cerr << "warning: ~ZmqMiddleware(): context_.terminate() took " << millisecs
269+ << " ms to complete for " << server_name_ << endl;
270 }
271 }
272- catch (std::exception const& e)
273- {
274- BOOST_LOG(logger_) << "~ZmqMiddleware(): " << e.what();
275- }
276 catch (...)
277 {
278- BOOST_LOG(logger_) << "~ZmqMiddleware(): unknown exception";
279+ // Don't log here. RuntimeImpl does that after calling wait_for_shutdown().
280+ // We may no longer have a logger here if something holds the middleware
281+ // in scope beyond the life time of the runtime.
282 }
283 }
284
285
286=== modified file 'src/scopes/utility/BufferedResultForwarder.cpp'
287--- src/scopes/utility/BufferedResultForwarder.cpp 2014-11-27 17:03:10 +0000
288+++ src/scopes/utility/BufferedResultForwarder.cpp 2015-01-23 05:01:22 +0000
289@@ -129,6 +129,10 @@
290 {
291 }
292
293+/// @cond
294+BufferedResultForwarder::~BufferedResultForwarder() = default;
295+/// @endcond
296+
297 bool BufferedResultForwarder::is_ready() const
298 {
299 return p->is_ready();
300
301=== modified file 'test/gtest/scopes/internal/smartscopes/smartscopesproxy/smartscopesproxy_test.cpp'
302--- test/gtest/scopes/internal/smartscopes/smartscopesproxy/smartscopesproxy_test.cpp 2014-12-03 06:53:40 +0000
303+++ test/gtest/scopes/internal/smartscopes/smartscopesproxy/smartscopesproxy_test.cpp 2015-01-23 05:01:22 +0000
304@@ -88,6 +88,11 @@
305 ~smartscopesproxytest()
306 {
307 rt_->destroy();
308+ // zmq shutdown is asynchronous and, if we don't wait,
309+ // the next RuntimeImpl instance that is created may
310+ // fail because the zmq endpoints may not have been unlinked
311+ // in the filesystem yet.
312+ std::this_thread::sleep_for(std::chrono::milliseconds(300));
313 }
314
315 protected:

Subscribers

People subscribed via source and target branches

to all changes: