Status: | Merged |
---|---|
Merged at revision: | 135 |
Proposed branch: | lp:~bregma/geis/lp-754135 |
Merge into: | lp:geis |
Diff against target: |
287 lines (+183/-9) 5 files modified
ChangeLog (+9/-0) libutouch-geis/geis_v1.c (+9/-9) testsuite/geis1/Makefile.am (+1/-0) testsuite/geis1/check_geis1_api.c (+2/-0) testsuite/geis1/check_subscription.c (+162/-0) |
To merge this branch: | bzr merge lp:~bregma/geis/lp-754135 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Henrik Rydberg (community) | Approve | ||
Review via email: mp+57102@code.launchpad.net |
Commit message
Description of the change
Fixes a persistence problem that may occur with callbacks (LP: #754135).
Henrik Rydberg (rydberg) wrote : | # |
Stephen M. Webb (bregma) wrote : | # |
There's a duplicate instance problem?
This fix is for the case where a pointer to a variable with automatic storage duration is passed to geis_subscribe() and that variable goes out of scope, leaving a dangling pointer. That was the cause of the problem reported in lp:754135.
Dereferencing dangling pointers results in undefined behaviour: there is no reliable way to reproduce the problem within the C language itself. The test case is using inside knowledge of the GCC runtime implementation on at least three of the most common architectures (i386, amd64, arm) to reliably force a segfault under the reported circumstances by setting the area previously used by the automatic variable to zeros. The test case does in fact segfault on tested hardware without the rest of the patch but runs cleanly with it.
An additional standalone program to demonstrate the problem was supplied in the bug by the reporter.
Henrik Rydberg (rydberg) wrote : | # |
The problem you describe was the problem i meant. Another way to test would be to use two instances of geis, reusing the callback struct but change functions in between. This way the problem could be tested without a crash. Either way is fine, especially with your nice explanation.
Preview Diff
1 | === modified file 'ChangeLog' |
2 | --- ChangeLog 2011-04-05 18:04:36 +0000 |
3 | +++ ChangeLog 2011-04-11 03:23:41 +0000 |
4 | @@ -1,3 +1,12 @@ |
5 | +2011-04-10 Stephen M. Webb <stephen.webb@canonical.com> |
6 | + |
7 | + Repaired a callback persistence problem (LP: #754135). |
8 | + |
9 | + * testsuite/geis1/check_subscription.c: new test suite |
10 | + * libutouch-geis/geis_v1.c: saved a copy of the callback tables |
11 | + * testsuite/geis1/Makefile.am: included new test suite |
12 | + * testsuite/geis1/check_geis1_api.c: ran new test suite |
13 | + |
14 | 2011-04-05 Stephen M. Webb <stephen.webb@canonical.com> |
15 | |
16 | Fixed invalid pointer dereference on XI initialization failure in XCB back |
17 | |
18 | === modified file 'libutouch-geis/geis_v1.c' |
19 | --- libutouch-geis/geis_v1.c 2011-03-25 19:33:18 +0000 |
20 | +++ libutouch-geis/geis_v1.c 2011-04-11 03:23:41 +0000 |
21 | @@ -37,9 +37,9 @@ |
22 | { |
23 | GeisSubscription subscription; |
24 | GeisFilter window_filter; |
25 | - GeisInputFuncs *input_funcs; |
26 | + GeisInputFuncs input_funcs; |
27 | GeisPointer input_context; |
28 | - GeisGestureFuncs *gesture_funcs; |
29 | + GeisGestureFuncs gesture_funcs; |
30 | GeisPointer gesture_cookie; |
31 | }; |
32 | |
33 | @@ -343,19 +343,19 @@ |
34 | switch (geis_event_type(event)) |
35 | { |
36 | case GEIS_EVENT_GESTURE_BEGIN: |
37 | - v1_instance->gesture_funcs->start(v1_instance->gesture_cookie, |
38 | + v1_instance->gesture_funcs.start(v1_instance->gesture_cookie, |
39 | class_id, |
40 | geis_frame_id(frame), |
41 | attr_count, attrs); |
42 | break; |
43 | case GEIS_EVENT_GESTURE_UPDATE: |
44 | - v1_instance->gesture_funcs->update(v1_instance->gesture_cookie, |
45 | + v1_instance->gesture_funcs.update(v1_instance->gesture_cookie, |
46 | class_id, |
47 | geis_frame_id(frame), |
48 | attr_count, attrs); |
49 | break; |
50 | case GEIS_EVENT_GESTURE_END: |
51 | - v1_instance->gesture_funcs->finish(v1_instance->gesture_cookie, |
52 | + v1_instance->gesture_funcs.finish(v1_instance->gesture_cookie, |
53 | class_id, |
54 | geis_frame_id(frame), |
55 | attr_count, attrs); |
56 | @@ -622,7 +622,7 @@ |
57 | { |
58 | GeisStatus result = GEIS_UNKNOWN_ERROR; |
59 | |
60 | - instance->gesture_funcs = funcs; |
61 | + memcpy(&instance->gesture_funcs, funcs, sizeof(GeisGestureFuncs)); |
62 | instance->gesture_cookie = cookie; |
63 | |
64 | /* pump the geis event queue to force device and class events to be picked up */ |
65 | @@ -759,12 +759,12 @@ |
66 | switch (geis_event_type(event)) |
67 | { |
68 | case GEIS_EVENT_DEVICE_AVAILABLE: |
69 | - v1_instance->input_funcs->added(v1_instance->input_context, |
70 | + v1_instance->input_funcs.added(v1_instance->input_context, |
71 | device_id, |
72 | attrs); |
73 | break; |
74 | case GEIS_EVENT_DEVICE_UNAVAILABLE: |
75 | - v1_instance->input_funcs->removed(v1_instance->input_context, |
76 | + v1_instance->input_funcs.removed(v1_instance->input_context, |
77 | device_id, |
78 | attrs); |
79 | break; |
80 | @@ -787,7 +787,7 @@ |
81 | { |
82 | GeisStatus result = GEIS_STATUS_SUCCESS; |
83 | |
84 | - instance->input_funcs = funcs; |
85 | + memcpy(&instance->input_funcs, funcs, sizeof(GeisInputFuncs)); |
86 | instance->input_context = context; |
87 | |
88 | geis_register_device_callback(g_geis, _v1_input_callback, instance); |
89 | |
90 | === modified file 'testsuite/geis1/Makefile.am' |
91 | --- testsuite/geis1/Makefile.am 2011-03-25 19:33:18 +0000 |
92 | +++ testsuite/geis1/Makefile.am 2011-04-11 03:23:41 +0000 |
93 | @@ -17,6 +17,7 @@ |
94 | check_instance.c \ |
95 | check_gesture_types.c \ |
96 | check_gesture_attrs.c \ |
97 | + check_subscription.c \ |
98 | check_geis1_api.c |
99 | |
100 | check_geis1_api_CFLAGS = \ |
101 | |
102 | === modified file 'testsuite/geis1/check_geis1_api.c' |
103 | --- testsuite/geis1/check_geis1_api.c 2011-03-25 19:33:18 +0000 |
104 | +++ testsuite/geis1/check_geis1_api.c 2011-04-11 03:23:41 +0000 |
105 | @@ -23,6 +23,7 @@ |
106 | extern Suite *geis1_instance_suite_new(); |
107 | extern Suite *geis1_gesture_types_new(); |
108 | extern Suite *geis1_gesture_attrs_new(); |
109 | +extern Suite *geis1_subscription_new(); |
110 | |
111 | int |
112 | main(int argc CK_ATTRIBUTE_UNUSED, char* argv[] CK_ATTRIBUTE_UNUSED) |
113 | @@ -34,6 +35,7 @@ |
114 | srunner_add_suite(sr, geis1_instance_suite_new()); |
115 | srunner_add_suite(sr, geis1_gesture_types_new()); |
116 | srunner_add_suite(sr, geis1_gesture_attrs_new()); |
117 | + srunner_add_suite(sr, geis1_subscription_new()); |
118 | |
119 | srunner_set_log(sr, "geis1_api.log"); |
120 | srunner_run_all(sr, CK_NORMAL); |
121 | |
122 | === added file 'testsuite/geis1/check_subscription.c' |
123 | --- testsuite/geis1/check_subscription.c 1970-01-01 00:00:00 +0000 |
124 | +++ testsuite/geis1/check_subscription.c 2011-04-11 03:23:41 +0000 |
125 | @@ -0,0 +1,162 @@ |
126 | +/** |
127 | + * @file check_subscription.c |
128 | + * @brief Unit tests for GEIS v1 subscriptions |
129 | + * |
130 | + * Copyright 2011 Canonical Ltd. |
131 | + * |
132 | + * This library is free software; you can redistribute it and/or modify it under |
133 | + * the terms of the GNU Lesser General Public License as published by the Free |
134 | + * Software Foundation; either version 3 of the License, or (at your option) any |
135 | + * later version. |
136 | + * |
137 | + * This library is distributed in the hope that it will be useful, but WITHOUT |
138 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
139 | + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more |
140 | + * details. |
141 | + * |
142 | + * You should have received a copy of the GNU Lesser General Public License |
143 | + * along with this program; if not, write to the Free Software Foundation, Inc., |
144 | + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
145 | + */ |
146 | +#include <check.h> |
147 | + |
148 | +#include <geis/geis.h> |
149 | +#include <string.h> |
150 | + |
151 | + |
152 | +#define GEIS_TEST_WINDOW geis_win_type_str(Test) |
153 | + |
154 | +static const char* s_gestures[] = { |
155 | + GEIS_GESTURE_TYPE_DRAG2, GEIS_GESTURE_TYPE_DRAG3, |
156 | + GEIS_GESTURE_TYPE_PINCH2, GEIS_GESTURE_TYPE_PINCH3, |
157 | + GEIS_GESTURE_TYPE_ROTATE2, GEIS_GESTURE_TYPE_ROTATE3, |
158 | + GEIS_GESTURE_TYPE_TAP2, GEIS_GESTURE_TYPE_TAP3, GEIS_GESTURE_TYPE_TAP4, |
159 | + NULL |
160 | +}; |
161 | + |
162 | +static void |
163 | +gesture_added(void *cookie CK_ATTRIBUTE_UNUSED, |
164 | + GeisGestureType gesture_type CK_ATTRIBUTE_UNUSED, |
165 | + GeisGestureId gesture_id CK_ATTRIBUTE_UNUSED, |
166 | + GeisSize attr_count CK_ATTRIBUTE_UNUSED, |
167 | + GeisGestureAttr *attrs CK_ATTRIBUTE_UNUSED) |
168 | +{ |
169 | +} |
170 | + |
171 | +static void |
172 | +gesture_removed(void *cookie CK_ATTRIBUTE_UNUSED, |
173 | + GeisGestureType gesture_type CK_ATTRIBUTE_UNUSED, |
174 | + GeisGestureId gesture_id CK_ATTRIBUTE_UNUSED, |
175 | + GeisSize attr_count CK_ATTRIBUTE_UNUSED, |
176 | + GeisGestureAttr *attrs CK_ATTRIBUTE_UNUSED) |
177 | +{ |
178 | +} |
179 | + |
180 | +/* |
181 | + * Checks for special values generated by the mock back end. |
182 | + */ |
183 | +static void |
184 | +gesture_start(void *cookie CK_ATTRIBUTE_UNUSED, |
185 | + GeisGestureType gesture_type CK_ATTRIBUTE_UNUSED, |
186 | + GeisGestureId gesture_id CK_ATTRIBUTE_UNUSED, |
187 | + GeisSize attr_count CK_ATTRIBUTE_UNUSED, |
188 | + GeisGestureAttr *attrs CK_ATTRIBUTE_UNUSED) |
189 | +{ |
190 | +} |
191 | + |
192 | +static void |
193 | +gesture_update(void *cookie CK_ATTRIBUTE_UNUSED, |
194 | + GeisGestureType gesture_type CK_ATTRIBUTE_UNUSED, |
195 | + GeisGestureId gesture_id CK_ATTRIBUTE_UNUSED, |
196 | + GeisSize attr_count CK_ATTRIBUTE_UNUSED, |
197 | + GeisGestureAttr *attrs CK_ATTRIBUTE_UNUSED) |
198 | +{ |
199 | +} |
200 | + |
201 | +static void |
202 | +gesture_finish(void *cookie CK_ATTRIBUTE_UNUSED, |
203 | + GeisGestureType gesture_type CK_ATTRIBUTE_UNUSED, |
204 | + GeisGestureId gesture_id CK_ATTRIBUTE_UNUSED, |
205 | + GeisSize attr_count CK_ATTRIBUTE_UNUSED, |
206 | + GeisGestureAttr *attrs CK_ATTRIBUTE_UNUSED) |
207 | +{ |
208 | +} |
209 | + |
210 | + |
211 | +/* fixtures */ |
212 | +static GeisInstance g_instance; |
213 | + |
214 | +/* fixture setup */ |
215 | +static void |
216 | +construct_instance() |
217 | +{ |
218 | + GeisStatus status; |
219 | + GeisXcbWinInfo x_win_info = { |
220 | + .display_name = NULL, |
221 | + .screenp = NULL, |
222 | + .window_id = 1 |
223 | + }; |
224 | + GeisWinInfo win_info = { GEIS_TEST_WINDOW, &x_win_info }; |
225 | + |
226 | + status = geis_init(&win_info, &g_instance); |
227 | +} |
228 | + |
229 | +/* fixture teardown */ |
230 | +static void |
231 | +destroy_instance() |
232 | +{ |
233 | + geis_finish(g_instance); |
234 | +} |
235 | + |
236 | + |
237 | +static void |
238 | +construct_subscription() |
239 | +{ |
240 | + GeisStatus status; |
241 | + GeisGestureFuncs gesture_funcs; |
242 | + |
243 | + gesture_funcs.added = gesture_added; |
244 | + gesture_funcs.removed = gesture_removed; |
245 | + gesture_funcs.start = gesture_start; |
246 | + gesture_funcs.update = gesture_update; |
247 | + gesture_funcs.finish = gesture_finish; |
248 | + status = geis_subscribe(g_instance, |
249 | + GEIS_ALL_INPUT_DEVICES, |
250 | + s_gestures, |
251 | + &gesture_funcs, |
252 | + &gesture_funcs); |
253 | +} |
254 | + |
255 | + |
256 | +static void |
257 | +dispatch_events() |
258 | +{ |
259 | + GeisGestureFuncs gesture_funcs; |
260 | + memset(&gesture_funcs, 0, sizeof(GeisGestureFuncs)); |
261 | + geis_event_dispatch(g_instance); |
262 | +} |
263 | + |
264 | + |
265 | +/* regression test for LP: #754135 */ |
266 | +START_TEST(check_persistence) |
267 | +{ |
268 | + construct_subscription(); |
269 | + dispatch_events(); |
270 | +} |
271 | +END_TEST |
272 | + |
273 | + |
274 | +Suite * |
275 | +geis1_subscription_new() |
276 | +{ |
277 | + Suite *s = suite_create("geis1_subscription"); |
278 | + TCase *test; |
279 | + |
280 | + test = tcase_create("lp754135"); |
281 | + tcase_add_checked_fixture(test, construct_instance, destroy_instance); |
282 | + tcase_add_test(test, check_persistence); |
283 | + suite_add_tcase(s, test); |
284 | + |
285 | + return s; |
286 | +} |
287 | + |
Fix is minimal, test case looks relevant, although I do not see how it tests the duplicate instance problem?