Mir

Merge lp:~afrantzis/mir/mir-client-ensure-global-symbol-resolution into lp:mir

Proposed by Alexandros Frantzis
Status: Work in progress
Proposed branch: lp:~afrantzis/mir/mir-client-ensure-global-symbol-resolution
Merge into: lp:mir
Diff against target: 219 lines (+151/-1)
7 files modified
debian/rules (+2/-1)
include/client/mir_toolkit/mir_client_ensure_global_symbol_resolution.h (+40/-0)
src/client/CMakeLists.txt (+2/-0)
src/client/mir_client_ensure_global_symbol_resolution.cpp (+28/-0)
tests/CMakeLists.txt (+5/-0)
tests/special-linkage-tests/CMakeLists.txt (+24/-0)
tests/special-linkage-tests/test_client_symbol_resolution.cpp (+50/-0)
To merge this branch: bzr merge lp:~afrantzis/mir/mir-client-ensure-global-symbol-resolution
Reviewer Review Type Date Requested Status
Daniel van Vugt Needs Fixing
PS Jenkins bot (community) continuous-integration Needs Fixing
Alan Griffiths Approve
Review via email: mp+196110@code.launchpad.net

Commit message

client: Provide a way to ensure libmirclient's symbols are available for symbol resolution in other shared objects

This is useful if libmirclient, or another library linking to libmirclient, is loaded
at runtime with dlopen() using RTLD_LOCAL (e.g., through a plugin mechanism)
and libmirclient's symbols need to be resolved at runtime in other shared objects
(like Mesa's libEGL).

Description of the change

client: Provide a way to ensure libmirclient's symbols are available for symbol resolution in other shared objects

This is useful if libmirclient, or another library linking to libmirclient, is loaded
at runtime with dlopen() using RTLD_LOCAL (e.g., through a plugin mechanism)
and libmirclient's symbols need to be resolved at runtime in other shared objects
(like Mesa's libEGL).

The specific problem that we are trying to solve is that with Qt client applications on the desktop, EGL fails to recognize native MirConnections as valid EGLNativeDisplayType objects, falling back to X11 and crashing. The reason is that the symbols needed for the MirConnection validation and which are exported by libmirclient, are not available to libEGL for dynamic runtime resolution. The problem occurs because Qt loads the platform shared object at runtime with local symbol visibility (RTLD_LOCAL), which is reasonable in general, but not suitable for our use case.

(See reference diagram: http://people.ubuntu.com/~afrantzis/mir-egl-symbol-resolution.png for the following)
Concerning our options for using this:

Ideally we would want to deal with the issue in libEGL, but unfortunately we cannot, since it would defeat the purpose of the runtime resolution, which is to transparently support applications linking against either libmirserver or libmirclient or both (or neither) and doing the right thing.

Next choice would be the Qt platform plugin (libqubuntumirclient), but the plugin doesn't have any knowledge of libmirclient, it's all abstracted through platform-api. We could make it work by linking with libmirclient at either runtime or loadtime and call the mir_client_ensure_global_symbol_resolution() from here.

Moving down a step we reach the platform-api from where we do have direct access to libmirclient. It's easy to call mir_client_ensure_global_symbol_resolution() from here. The trade-off is that we are then going to force this behavior on all users of the platform-api's mirclient backend (which might be OK).

We could even make libmirclient itself force all of its symbols to become available for global resolution, but this seems too intrusive for now (but it is an option if we find that this problem is widespread).

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

The CI failures are caused by CI scripts not disabling the new test category (special-tests). It only makes sense to change CI if the MP is approved, so please review to break the vicious circle.

Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

Wouldn't it be as easy (and have mess in fewer places) for platform-api to call dlopen() directly?

review: Needs Information
Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

> Wouldn't it be as easy (and have mess in fewer places) for platform-api to call dlopen() directly?

That's another option, but:

1. platform-api (or wherever this ends up in) will need to contain the logic to load the correct libmirserver.so.X library, which is not as straightforward as doing it in mirclient (since we know our soname)
2. it exposes the mechanism by which this is performed which platform-api doesn't really care about
3. it will not be as easy to reuse the code in other similar cases or move the point of application

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
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 :

> > Wouldn't it be as easy (and have mess in fewer places) for platform-api to
> call dlopen() directly?
>
> That's another option, but:
>
> 1. platform-api (or wherever this ends up in) will need to contain the logic
> to load the correct libmirserver.so.X library, which is not as straightforward
> as doing it in mirclient (since we know our soname)
> 2. it exposes the mechanism by which this is performed which platform-api
> doesn't really care about
> 3. it will not be as easy to reuse the code in other similar cases or move the
> point of application

OK then

review: Approve
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

I'm concerned, because using RTLD_LAZY|RTLD_GLOBAL is usually a bad sign that you've done something wrong. You should never need either. But you seem to have good reasons I don't yet fully understand.

review: Abstain
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

Actually, having slept at the weekend I'm concerned that "MIR_ENABLE_SPECIAL_TESTS" is a horribly uninformative name.

review: Needs Fixing
Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

> Actually, having slept at the weekend I'm concerned that
> "MIR_ENABLE_SPECIAL_TESTS" is a horribly uninformative name.

The name was vague on purpose so that this category could include all kinds of tests that have special needs, mostly in terms of special build flags or linking requirements. For example I was thinking that the c89 test we have could be also placed here.

Alternatively, we could just put this in acceptance tests (it is an acceptance test after all), but we need to have a different executable due to the special linking, which is why I have opted to separate it.

Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

> > Actually, having slept at the weekend I'm concerned that
> > "MIR_ENABLE_SPECIAL_TESTS" is a horribly uninformative name.
>
> The name was vague on purpose so that this category could include all kinds of
> tests that have special needs, mostly in terms of special build flags or
> linking requirements. For example I was thinking that the c89 test we have
> could be also placed here.
>
> Alternatively, we could just put this in acceptance tests (it is an acceptance
> test after all), but we need to have a different executable due to the special
> linking, which is why I have opted to separate it.

Hmm, or our so-called "unit-tests" that need an LD_PRELOAD to work.

I see the motivation, but I'm not sure these form a coherent "SPECIAL" category. Amy trying to come up with a name I like...

Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

> I see the motivation, but I'm not sure these form a coherent "SPECIAL"
> category. Amy trying to come up with a name I like...

On IRC we came up with MIR_ENABLE_SPECIAL_LINKAGE_TESTS

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 :

Ugly, but appears to address the problem. (And haven't thought of a more elegant solution within code we "own".)

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

1. Needs Fixing: Text conflict in debian/rules

2. Needs information:
"The specific problem that we are trying to solve is that with Qt client applications on the desktop, EGL fails to recognize native MirConnections as valid EGLNativeDisplayType objects, falling back to X11 and crashing. The reason is that the symbols needed for the MirConnection validation and which are exported by libmirclient, are not available to libEGL for dynamic runtime resolution."
How is failing to find a symbol not a fatal error? If we need validation functions and presently can't find them then what function is being called?

Experience with many global/local symbol resolution problems in plugin systems tells me there's possibly a nicer solution but I still don't fully understand the problem being solved.

review: Needs Fixing
Revision history for this message
Chris Halse Rogers (raof) wrote :

Hm. Looks like this could be more awesomely solved in the Mir EGL platform with judicious use of RTLD_NOLOAD;
first try resolving client & server symbols, then if neither are resolved checking whether either mirclient or mirserver are loaded with RTLD_NOLOAD, and reopening them with RTLD_GLOBAL if so.

It's only available on glibc, but whatever.

Longer term it might be nicer to dynamically load the EGL platforms and use actual link-time linking.

Revision history for this message
Chris Halse Rogers (raof) wrote :

I also don't object to the existing approach, except that we'll want to drop it when we solve this correctly.

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

Is this still active?

Unmerged revisions

1250. By Alexandros Frantzis

tests: Rename special-tests to special-linkage-tests

1249. By Alexandros Frantzis

special-tests: Add explicit dependency to mirclient library

1248. By Alexandros Frantzis

build: Disable special tests when building the package for armhf

1247. By Alexandros Frantzis

client: Provide function to ensure libmirclient's symbols are available for symbol resolution in other shared objects

This is useful if libmirclient, or another library linking to libmirclient, is loaded
at runtime with dlopen() using RTLD_LOCAL (e.g., through a plugin mechanism)
and libmirclient's symbols need to be resolved at runtime in other shared objects
(like Mesa's libEGL).

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/rules'
2--- debian/rules 2013-11-21 03:16:21 +0000
3+++ debian/rules 2013-11-25 14:25:30 +0000
4@@ -24,7 +24,8 @@
5 -DMIR_PLATFORM=android \
6 -DMIR_ENABLE_UNIT_TESTS=NO \
7 -DMIR_ENABLE_ACCEPTANCE_TESTS=NO \
8- -DMIR_ENABLE_INTEGRATION_TESTS=NO
9+ -DMIR_ENABLE_INTEGRATION_TESTS=NO \
10+ -DMIR_ENABLE_SPECIAL_LINKAGE_TESTS=NO
11 else
12 ifeq ($(DEB_HOST_ARCH),powerpc)
13 dh_auto_configure -- \
14
15=== added file 'include/client/mir_toolkit/mir_client_ensure_global_symbol_resolution.h'
16--- include/client/mir_toolkit/mir_client_ensure_global_symbol_resolution.h 1970-01-01 00:00:00 +0000
17+++ include/client/mir_toolkit/mir_client_ensure_global_symbol_resolution.h 2013-11-25 14:25:30 +0000
18@@ -0,0 +1,40 @@
19+/*
20+ * Copyright © 2013 Canonical Ltd.
21+ *
22+ * This program is free software: you can redistribute it and/or modify it
23+ * under the terms of the GNU Lesser General Public License version 3,
24+ * as published by the Free Software Foundation.
25+ *
26+ * This program is distributed in the hope that it will be useful,
27+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
28+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29+ * GNU Lesser General Public License for more details.
30+ *
31+ * You should have received a copy of the GNU Lesser General Public License
32+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
33+ */
34+
35+#ifndef MIR_CLIENT_ENSURE_GLOBAL_SYMBOL_RESOLUTION_H
36+#define MIR_CLIENT_ENSURE_GLOBAL_SYMBOL_RESOLUTION_H
37+
38+#ifdef __cplusplus
39+extern "C" {
40+#endif
41+
42+/**
43+ * Ensure the symbols defined by libmirclient are available for symbol
44+ * resolution in other shared objects.
45+ *
46+ * This is useful if libmirclient, or another library linking to libmirclient,
47+ * is loaded at runtime with dlopen() using RTLD_LOCAL (e.g., through a plugin
48+ * mechanism) and libmirclient's symbols need to be resolved at runtime in
49+ * other shared objects (like Mesa's libEGL).
50+ *
51+ */
52+void mir_client_ensure_global_symbol_resolution();
53+
54+#ifdef __cplusplus
55+}
56+#endif
57+
58+#endif /* MIR_CLIENT_ENSURE_GLOBAL_SYMBOL_RESOLUTION_H */
59
60=== modified file 'src/client/CMakeLists.txt'
61--- src/client/CMakeLists.txt 2013-11-21 03:16:21 +0000
62+++ src/client/CMakeLists.txt 2013-11-25 14:25:30 +0000
63@@ -33,6 +33,7 @@
64 default_connection_configuration.cpp
65 surface_map.cpp
66 lifecycle_control.cpp
67+ mir_client_ensure_global_symbol_resolution.cpp
68 )
69
70 if( MIR_PLATFORM STREQUAL "android")
71@@ -76,6 +77,7 @@
72
73 PROPERTIES
74 SOVERSION ${MIRCLIENT_ABI}
75+ COMPILE_DEFINITIONS MIRCLIENT_LIBRARY_NAME=\"$<TARGET_SONAME_FILE_NAME:mirclient>\"
76 )
77
78 # Ensure mirclient_compat_links exist before any dependents of mirclient
79
80=== added file 'src/client/mir_client_ensure_global_symbol_resolution.cpp'
81--- src/client/mir_client_ensure_global_symbol_resolution.cpp 1970-01-01 00:00:00 +0000
82+++ src/client/mir_client_ensure_global_symbol_resolution.cpp 2013-11-25 14:25:30 +0000
83@@ -0,0 +1,28 @@
84+/*
85+ * Copyright © 2013 Canonical Ltd.
86+ *
87+ * This program is free software: you can redistribute it and/or modify it
88+ * under the terms of the GNU Lesser General Public License version 3,
89+ * as published by the Free Software Foundation.
90+ *
91+ * This program is distributed in the hope that it will be useful,
92+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
93+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
94+ * GNU Lesser General Public License for more details.
95+ *
96+ * You should have received a copy of the GNU Lesser General Public License
97+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
98+ *
99+ * Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>
100+ */
101+
102+#include "mir_toolkit/mir_client_ensure_global_symbol_resolution.h"
103+
104+#include "dlfcn.h"
105+
106+void mir_client_ensure_global_symbol_resolution()
107+{
108+ void* handle = dlopen(MIRCLIENT_LIBRARY_NAME, RTLD_LAZY|RTLD_GLOBAL);
109+ if (handle)
110+ dlclose(handle);
111+}
112
113=== modified file 'tests/CMakeLists.txt'
114--- tests/CMakeLists.txt 2013-10-15 10:10:05 +0000
115+++ tests/CMakeLists.txt 2013-11-25 14:25:30 +0000
116@@ -22,6 +22,7 @@
117 option(MIR_ENABLE_ACCEPTANCE_TESTS "Build & run acceptance tests" ON)
118 option(MIR_ENABLE_INTEGRATION_TESTS "Build & run integration tests" ON)
119 option(MIR_ENABLE_UNIT_TESTS "Build & run unit tests" ON)
120+option(MIR_ENABLE_SPECIAL_LINKAGE_TESTS "Build & run special linkage tests" ON)
121
122 if (MIR_ENABLE_ACCEPTANCE_TESTS)
123 add_subdirectory(acceptance-tests/)
124@@ -35,6 +36,10 @@
125 add_subdirectory(integration-tests/)
126 endif (MIR_ENABLE_INTEGRATION_TESTS)
127
128+if (MIR_ENABLE_SPECIAL_LINKAGE_TESTS)
129+ add_subdirectory(special-linkage-tests/)
130+endif (MIR_ENABLE_SPECIAL_LINKAGE_TESTS)
131+
132 add_subdirectory(mir_test/)
133 add_subdirectory(mir_test_framework/)
134 add_subdirectory(mir_test_doubles/)
135
136=== added directory 'tests/special-linkage-tests'
137=== added file 'tests/special-linkage-tests/CMakeLists.txt'
138--- tests/special-linkage-tests/CMakeLists.txt 1970-01-01 00:00:00 +0000
139+++ tests/special-linkage-tests/CMakeLists.txt 2013-11-25 14:25:30 +0000
140@@ -0,0 +1,24 @@
141+add_executable(
142+ symbol-resolution-tests
143+
144+ test_client_symbol_resolution.cpp
145+)
146+
147+
148+target_link_libraries(
149+ symbol-resolution-tests
150+
151+ ${GTEST_BOTH_LIBRARIES}
152+ -ldl
153+)
154+
155+set_target_properties(
156+ symbol-resolution-tests
157+
158+ PROPERTIES
159+ COMPILE_DEFINITIONS MIRCLIENT_LIBRARY_FILE=\"$<TARGET_SONAME_FILE:mirclient>\"
160+)
161+
162+add_dependencies(symbol-resolution-tests mirclient)
163+
164+mir_discover_tests(symbol-resolution-tests)
165
166=== added file 'tests/special-linkage-tests/test_client_symbol_resolution.cpp'
167--- tests/special-linkage-tests/test_client_symbol_resolution.cpp 1970-01-01 00:00:00 +0000
168+++ tests/special-linkage-tests/test_client_symbol_resolution.cpp 2013-11-25 14:25:30 +0000
169@@ -0,0 +1,50 @@
170+/*
171+ * Copyright © 2013 Canonical Ltd.
172+ *
173+ * This program is free software: you can redistribute it and/or modify
174+ * it under the terms of the GNU General Public License version 3 as
175+ * published by the Free Software Foundation.
176+ *
177+ * This program is distributed in the hope that it will be useful,
178+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
179+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
180+ * GNU General Public License for more details.
181+ *
182+ * You should have received a copy of the GNU General Public License
183+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
184+ *
185+ * Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>
186+ */
187+
188+#include <gtest/gtest.h>
189+#include <dlfcn.h>
190+
191+typedef void (ensure_global_symbol_resolution_func_t)();
192+
193+TEST(ClientSymbolResolutionTest, can_find_client_symbols_after_ensuring_global_symbol_resolution)
194+{
195+ char const* const client_symbol = "mir_connect_sync";
196+ void* client_lib = dlopen(MIRCLIENT_LIBRARY_FILE, RTLD_LAZY);
197+ void* program = dlopen(NULL, RTLD_LAZY);
198+
199+ ASSERT_TRUE(client_lib != nullptr);
200+ ASSERT_TRUE(program != nullptr);
201+
202+ /* Client symbols aren't available yet through the program's handle */
203+ EXPECT_TRUE(dlsym(program, client_symbol) == nullptr);
204+
205+ void* sym = dlsym(client_lib, "mir_client_ensure_global_symbol_resolution");
206+ /*
207+ * This ugly trick is needed to silence warnings about converting from void* to
208+ * function pointer.
209+ */
210+ auto ensure_global_symbol_resolution =
211+ *reinterpret_cast<ensure_global_symbol_resolution_func_t**>(&sym);
212+ ASSERT_TRUE(ensure_global_symbol_resolution != nullptr);
213+
214+ ensure_global_symbol_resolution();
215+ EXPECT_TRUE(dlsym(program, client_symbol) != nullptr);
216+
217+ dlclose(program);
218+ dlclose(client_lib);
219+}

Subscribers

People subscribed via source and target branches