Mir

Merge lp:~afrantzis/mir/fix-1358191-connect-segv into lp:mir

Proposed by Alexandros Frantzis
Status: Merged
Approved by: Daniel van Vugt
Approved revision: no longer in the source branch.
Merged at revision: 1868
Proposed branch: lp:~afrantzis/mir/fix-1358191-connect-segv
Merge into: lp:mir
Diff against target: 344 lines (+57/-125)
6 files modified
src/client/connection_configuration.h (+1/-2)
src/client/default_connection_configuration.cpp (+14/-20)
src/client/default_connection_configuration.h (+4/-0)
src/client/mir_connection.cpp (+1/-20)
src/client/mir_connection.h (+6/-0)
tests/acceptance-tests/test_client_authorization.cpp (+31/-83)
To merge this branch: bzr merge lp:~afrantzis/mir/fix-1358191-connect-segv
Reviewer Review Type Date Requested Status
Alberto Aguirre (community) Approve
Kevin DuBois (community) Approve
Alan Griffiths Approve
PS Jenkins bot (community) continuous-integration Approve
Review via email: mp+232218@code.launchpad.net

Commit message

client: Ensure our platform library stays loaded for as long as it is needed by other objects. This avoids crashes observed on mir_connect failure
(LP: #1358191)

Both the DefaultClientConfiguration and the MirConnection need to keep the platform library loaded independently for their own reasons (see the bug addressed by this MP).

This MP drops the library cache since the dl library uses reference counting internally, so having a global cache to share libraries between connections complicates the code without offering any benefits.

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
Alan Griffiths (alan-griffiths) wrote :

LGTM

review: Approve
Revision history for this message
Kevin DuBois (kdub) wrote :

+1

review: Approve
Revision history for this message
Alberto Aguirre (albaguirre) wrote :

OK.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/client/connection_configuration.h'
2--- src/client/connection_configuration.h 2014-07-30 15:25:54 +0000
3+++ src/client/connection_configuration.h 2014-08-26 13:48:43 +0000
4@@ -43,8 +43,6 @@
5
6 namespace client
7 {
8-std::shared_ptr<SharedLibrary>& libraries_cache(std::string const& lib_name);
9-
10 class ConnectionSurfaceMap;
11 class Logger;
12 class ClientPlatformFactory;
13@@ -67,6 +65,7 @@
14 virtual std::shared_ptr<LifecycleControl> the_lifecycle_control() = 0;
15 virtual std::shared_ptr<EventSink> the_event_sink() = 0;
16 virtual std::shared_ptr<EventHandlerRegister> the_event_handler_register() = 0;
17+ virtual std::shared_ptr<SharedLibrary> the_platform_library() = 0;
18
19 protected:
20 ConnectionConfiguration() = default;
21
22=== modified file 'src/client/default_connection_configuration.cpp'
23--- src/client/default_connection_configuration.cpp 2014-07-30 15:25:54 +0000
24+++ src/client/default_connection_configuration.cpp 2014-08-26 13:48:43 +0000
25@@ -42,20 +42,6 @@
26 std::string const log_opt_val{"log"};
27 std::string const lttng_opt_val{"lttng"};
28 std::string const default_platform_lib{"libmirclientplatform.so"};
29-
30-mir::SharedLibrary const* load_library(std::string const& libname)
31-{
32-
33- if (auto& ptr = mcl::libraries_cache(libname))
34- {
35- return ptr.get();
36- }
37- else
38- {
39- ptr = std::make_shared<mir::SharedLibrary>(libname);
40- return ptr.get();
41- }
42-}
43 }
44
45 mcl::DefaultConnectionConfiguration::DefaultConnectionConfiguration(
46@@ -98,14 +84,10 @@
47 mcl::DefaultConnectionConfiguration::the_client_platform_factory()
48 {
49 return client_platform_factory(
50- []
51+ [this]
52 {
53- auto const val_raw = getenv("MIR_CLIENT_PLATFORM_LIB");
54- std::string const val{val_raw ? val_raw : default_platform_lib};
55- auto const platform_lib = ::load_library(val);
56-
57 auto const create_client_platform_factory =
58- platform_lib->load_function<mcl::CreateClientPlatformFactory>(
59+ the_platform_library()->load_function<mcl::CreateClientPlatformFactory>(
60 "create_client_platform_factory");
61
62 return create_client_platform_factory();
63@@ -199,3 +181,15 @@
64 return std::make_shared<MirEventDistributor>();
65 });
66 }
67+
68+std::shared_ptr<mir::SharedLibrary> mcl::DefaultConnectionConfiguration::the_platform_library()
69+{
70+ if (!platform_library)
71+ {
72+ auto const val_raw = getenv("MIR_CLIENT_PLATFORM_LIB");
73+ std::string const libname{val_raw ? val_raw : default_platform_lib};
74+ platform_library = std::make_shared<mir::SharedLibrary>(libname);
75+ }
76+
77+ return platform_library;
78+}
79
80=== modified file 'src/client/default_connection_configuration.h'
81--- src/client/default_connection_configuration.h 2014-07-02 06:29:24 +0000
82+++ src/client/default_connection_configuration.h 2014-08-26 13:48:43 +0000
83@@ -57,12 +57,16 @@
84 std::shared_ptr<LifecycleControl> the_lifecycle_control();
85 std::shared_ptr<EventSink> the_event_sink();
86 std::shared_ptr<EventHandlerRegister> the_event_handler_register();
87+ std::shared_ptr<SharedLibrary> the_platform_library() override;
88
89 virtual std::string the_socket_file();
90 virtual std::shared_ptr<rpc::RpcReport> the_rpc_report();
91 virtual std::shared_ptr<input::receiver::InputReceiverReport> the_input_receiver_report();
92
93 protected:
94+ // MUST be first data member so it is destroyed last.
95+ std::shared_ptr<mir::SharedLibrary> platform_library;
96+
97 CachedPtr<google::protobuf::RpcChannel> rpc_channel;
98 CachedPtr<mir::logging::Logger> logger;
99 CachedPtr<ClientPlatformFactory> client_platform_factory;
100
101=== modified file 'src/client/mir_connection.cpp'
102--- src/client/mir_connection.cpp 2014-08-22 02:56:00 +0000
103+++ src/client/mir_connection.cpp 2014-08-26 13:48:43 +0000
104@@ -67,19 +67,6 @@
105
106 std::mutex connection_guard;
107 MirConnection* valid_connections{nullptr};
108-// There's no point in loading twice, and it isn't safe to
109-// unload while there are valid connections
110-std::map<std::string, std::shared_ptr<mir::SharedLibrary>>* libraries_cache_ptr{nullptr};
111-}
112-
113-std::shared_ptr<mir::SharedLibrary>& mcl::libraries_cache(std::string const& libname)
114-{
115- std::lock_guard<std::mutex> lock(connection_guard);
116-
117- if (!libraries_cache_ptr)
118- libraries_cache_ptr = new LibrariesCache;
119-
120- return (*libraries_cache_ptr)[libname];
121 }
122
123 MirConnection::Deregisterer::~Deregisterer()
124@@ -94,13 +81,6 @@
125 break;
126 }
127 }
128-
129- // When the last valid connection goes we can clear the libraries cache
130- if (!valid_connections)
131- {
132- delete libraries_cache_ptr;
133- libraries_cache_ptr = nullptr;
134- }
135 }
136
137 MirConnection::MirConnection(std::string const& error_message) :
138@@ -114,6 +94,7 @@
139 MirConnection::MirConnection(
140 mir::client::ConnectionConfiguration& conf) :
141 deregisterer{this},
142+ platform_library{conf.the_platform_library()},
143 channel(conf.the_rpc_channel()),
144 server(channel.get(), ::google::protobuf::Service::STUB_DOESNT_OWN_CHANNEL),
145 logger(conf.the_logger()),
146
147=== modified file 'src/client/mir_connection.h'
148--- src/client/mir_connection.h 2014-07-30 15:25:54 +0000
149+++ src/client/mir_connection.h 2014-08-26 13:48:43 +0000
150@@ -37,6 +37,8 @@
151
152 namespace mir
153 {
154+class SharedLibrary;
155+
156 /// The client-side library implementation namespace
157 namespace client
158 {
159@@ -138,6 +140,10 @@
160 struct Deregisterer
161 { MirConnection* const self; ~Deregisterer(); } deregisterer;
162
163+ // MUST be placed before any variables for components that are loaded
164+ // from a shared library, e.g., the ClientPlatform* objects.
165+ std::shared_ptr<mir::SharedLibrary> const platform_library;
166+
167 std::mutex mutex; // Protects all members of *this (except release_wait_handles)
168
169 std::shared_ptr<google::protobuf::RpcChannel> const channel;
170
171=== modified file 'tests/acceptance-tests/test_client_authorization.cpp'
172--- tests/acceptance-tests/test_client_authorization.cpp 2014-07-10 03:45:37 +0000
173+++ tests/acceptance-tests/test_client_authorization.cpp 2014-08-26 13:48:43 +0000
174@@ -23,6 +23,7 @@
175
176 #include "mir_test/fake_shared.h"
177 #include "mir_test_framework/display_server_test_fixture.h"
178+#include "mir_test_doubles/stub_session_authorizer.h"
179
180 #include <gtest/gtest.h>
181 #include <gmock/gmock.h>
182@@ -36,25 +37,11 @@
183 namespace mf = mir::frontend;
184 namespace mt = mir::test;
185 namespace mtf = mir_test_framework;
186-
187-namespace
188-{
189- char const* const mir_test_socket = mtf::test_socket_file().c_str();
190-}
191-
192-namespace
193-{
194-struct ConnectingClient : TestingClientConfiguration
195-{
196- MirConnection *connection;
197- void exec()
198- {
199- connection = mir_connect_sync(
200- mir_test_socket,
201- __PRETTY_FUNCTION__);
202- mir_connection_release(connection);
203- }
204-};
205+namespace mtd = mir::test::doubles;
206+
207+namespace
208+{
209+char const* const mir_test_socket = mtf::test_socket_file().c_str();
210
211 struct ClientCredsTestFixture : BespokeDisplayServerTestFixture
212 {
213@@ -144,6 +131,10 @@
214 screencast_is_allowed(Truly(matches_creds)))
215 .Times(1)
216 .WillOnce(Return(false));
217+ EXPECT_CALL(mock_authorizer,
218+ prompt_session_is_allowed(Truly(matches_creds)))
219+ .Times(1)
220+ .WillOnce(Return(false));
221 connect_sync.try_signal_ready_for();
222 }
223
224@@ -159,7 +150,7 @@
225 launch_server_process(server_config);
226
227
228- struct ClientConfiguration : ConnectingClient
229+ struct ClientConfiguration : TestingClientConfiguration
230 {
231 ClientConfiguration(ClientCredsTestFixture::SharedRegion *shared_region,
232 mtf::CrossProcessSync const& connect_sync)
233@@ -172,7 +163,9 @@
234 {
235 shared_region->post_client_creds();
236 connect_sync.wait_for_signal_ready_for();
237- ConnectingClient::exec();
238+ auto const connection = mir_connect_sync(mir_test_socket, __PRETTY_FUNCTION__);
239+ EXPECT_TRUE(mir_connection_is_valid(connection));
240+ mir_connection_release(connection);
241 }
242
243 ClientCredsTestFixture::SharedRegion* shared_region;
244@@ -181,83 +174,38 @@
245 launch_client_process(client_config);
246 }
247
248-// TODO this test exposes a race condition when the client processes both an error
249-// TODO from connect and the socket being dropped. RAOF is doing some rework that
250-// TODO should fix this a side effect. It should be re-enabled when that is done.
251-TEST_F(ClientCredsTestFixture, DISABLED_authorizer_may_prevent_connection_of_clients)
252+// This test is also a regression test for https://bugs.launchpad.net/mir/+bug/1358191
253+TEST_F(ClientCredsTestFixture, authorizer_may_prevent_connection_of_clients)
254 {
255 using namespace ::testing;
256
257 struct ServerConfiguration : TestingServerConfiguration
258 {
259- ServerConfiguration(ClientCredsTestFixture::SharedRegion *shared_region)
260- : shared_region(shared_region)
261- {
262- }
263-
264- void exec() override
265- {
266- using namespace ::testing;
267-
268- EXPECT_TRUE(shared_region->wait_for_client_creds());
269- auto matches_creds = [&](mf::SessionCredentials const& creds)
270- {
271- return shared_region->matches_client_process_creds(creds);
272- };
273-
274- EXPECT_CALL(mock_authorizer,
275- connection_is_allowed(Truly(matches_creds)))
276- .Times(1)
277- .WillOnce(Return(false));
278- }
279-
280 std::shared_ptr<mf::SessionAuthorizer> the_session_authorizer() override
281 {
282- return mt::fake_shared(mock_authorizer);
283+ struct StubAuthorizer : mtd::StubSessionAuthorizer
284+ {
285+ bool connection_is_allowed(mir::frontend::SessionCredentials const&) override
286+ {
287+ return false;
288+ }
289+ };
290+
291+ return std::make_shared<StubAuthorizer>();
292 }
293+ } server_config;
294
295- ClientCredsTestFixture::SharedRegion* shared_region;
296- MockSessionAuthorizer mock_authorizer;
297- } server_config(shared_region);
298 launch_server_process(server_config);
299
300-
301- struct ClientConfiguration : ConnectingClient
302+ struct ClientConfiguration : TestingClientConfiguration
303 {
304- ClientConfiguration(ClientCredsTestFixture::SharedRegion *shared_region)
305- : shared_region(shared_region)
306- {
307- }
308-
309 void exec() override
310 {
311- shared_region->post_client_creds();
312-
313- connection = mir_connect_sync(
314- mir_test_socket,
315- __PRETTY_FUNCTION__);
316-
317- MirSurfaceParameters const parameters =
318- {
319- __PRETTY_FUNCTION__,
320- 1, 1,
321- mir_pixel_format_abgr_8888,
322- mir_buffer_usage_hardware,
323- mir_display_output_id_invalid
324- };
325- mir_connection_create_surface_sync(connection, &parameters);
326- EXPECT_GT(strlen(mir_connection_get_error_message(connection)), static_cast<unsigned int>(0));
327+ auto const connection = mir_connect_sync(mir_test_socket, __PRETTY_FUNCTION__);
328+ EXPECT_FALSE(mir_connection_is_valid(connection));
329 mir_connection_release(connection);
330 }
331-
332- //we are testing the connect function itself, without getting to the
333- // point where drivers are used, so force using production config
334- bool use_real_graphics(mir::options::Option const&) override
335- {
336- return true;
337- }
338-
339- ClientCredsTestFixture::SharedRegion* shared_region;
340- } client_config(shared_region);
341+ } client_config;
342+
343 launch_client_process(client_config);
344 }

Subscribers

People subscribed via source and target branches