Merge lp:~bregma/geis/lp-754135 into lp:geis

Proposed by Stephen M. Webb
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
Reviewer Review Type Date Requested Status
Henrik Rydberg (community) Approve
Review via email: mp+57102@code.launchpad.net

Description of the change

Fixes a persistence problem that may occur with callbacks (LP: #754135).

To post a comment you must log in.
Revision history for this message
Henrik Rydberg (rydberg) wrote :

Fix is minimal, test case looks relevant, although I do not see how it tests the duplicate instance problem?

Revision history for this message
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.

Revision history for this message
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.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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+

Subscribers

People subscribed via source and target branches