Merge lp:~vanvugt/unity/fix-918329-trunk into lp:unity

Proposed by Daniel van Vugt
Status: Merged
Approved by: Sam Spilsbury
Approved revision: no longer in the source branch.
Merged at revision: 1854
Proposed branch: lp:~vanvugt/unity/fix-918329-trunk
Merge into: lp:unity
Diff against target: 250 lines (+42/-55)
3 files modified
plugins/unityshell/src/compizminimizedwindowhandler.h (+23/-31)
plugins/unityshell/src/unityshell.cpp (+15/-23)
plugins/unityshell/src/unityshell.h (+4/-1)
To merge this branch: bzr merge lp:~vanvugt/unity/fix-918329-trunk
Reviewer Review Type Date Requested Status
Sam Spilsbury (community) Approve
Unity Team Pending
Review via email: mp+89391@code.launchpad.net

Description of the change

Fix SIGSEGV when a window is minimized. (LP: #918329)

The crash was caused by 'minimizedWindows' leaking pointers to windows that had been deleted, and then later trying to dereference those pointers. The reason for the leak appears to be a reference leak in the boost::shared_ptr's to CompizMinimizedWindowHandler. Reverting to regular pointers avoids the reference leak, avoids the crash, and makes the code easier to understand (and debug).

Detailed valgrind log showing the error:
https://bugs.launchpad.net/ubuntu/+source/unity/+bug/918329/comments/6

To post a comment you must log in.
Revision history for this message
Sam Spilsbury (smspillaz) wrote :
Revision history for this message
Sam Spilsbury (smspillaz) wrote :

Alright - so what do you think then? I'm in favor of using smart pointers where possible to do so, obviously we must use raw pointers in the list, but the list is managed by the destructor of the minimized window handler.

(I really need to clean up that file, but then again, the file probably represents how much of a hack fake minimization really is, which is the only way to get live previews from minimized windows *sigh*)

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

I tried an in-between solution as you suggest, where the list is raw pointers and the share_ptrs stay in unityshell. It worked, however that necessitated some ugly dynamic typecasts. I think this version is better because the types are cleanly matched without casting required.

Smart pointers probably have their place. But in this case they caused leaks and made the code much harder to read and maintain.

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

P.S. One of us just wasted a day because you forgot to mark the bug in progress or even assign it to yourself :(

Revision history for this message
Sam Spilsbury (smspillaz) wrote :

On Fri, 20 Jan 2012, Daniel van Vugt wrote:

> I tried an in-between solution as you suggest, where the list is raw pointers and the share_ptrs stay in unityshell. It worked, however that necessitated some ugly dynamic typecasts. I think this version is better because the types are cleanly matched without casting required.
>
> Smart pointers probably have their place. But in this case they caused leaks and made the code much harder to read and maintain.

There is no need for dynamic casting as there is only a single line of
inheritance.

I'll merge this one though.

> --
> https://code.launchpad.net/~vanvugt/unity/fix-918329-trunk/+merge/89391
> You are requested to review the proposed merge of lp:~vanvugt/unity/fix-918329-trunk into lp:unity.
>

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

Thanks.

And you're right about static casts instead of dynamic. But this version avoids all casts which is even better I think.

Revision history for this message
Sam Spilsbury (smspillaz) wrote :

On Fri, 20 Jan 2012, Daniel van Vugt wrote:

> Thanks.
>
> And you're right about static casts instead of dynamic. But this version avoids all casts which is even better I think.

Yes, boost::static_pointer_cast has the cost of the boost::shared_ptr
constructor (which is not that much, but something to dislike anyways).

I don't know why the static pointer casts were changed to dynamic casts.
That seems excessively silly, especially considering that one of them was
in a paint function (!). However, use of downcasting usually indicates a
problem with the design, one that should be revisited later (also related
to testing, since the base class exists for testing purposes)

> --
> https://code.launchpad.net/~vanvugt/unity/fix-918329-trunk/+merge/89391
> You are reviewing the proposed merge of lp:~vanvugt/unity/fix-918329-trunk into lp:unity.
>

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'plugins/unityshell/src/compizminimizedwindowhandler.h'
2--- plugins/unityshell/src/compizminimizedwindowhandler.h 2011-10-05 12:20:19 +0000
3+++ plugins/unityshell/src/compizminimizedwindowhandler.h 2012-01-20 07:01:19 +0000
4@@ -63,9 +63,8 @@
5 static void handleEvent (XEvent *event);
6 static std::list<CompWindow *> minimizingWindows;
7
8- typedef CompizMinimizedWindowHandler<Screen, Window> CompizMinimizedWindowHandler_complete;
9- typedef boost::shared_ptr<CompizMinimizedWindowHandler_complete> Ptr;
10- typedef std::list <Ptr> List;
11+ typedef CompizMinimizedWindowHandler<Screen, Window> Type;
12+ typedef std::list <Type *> List;
13 protected:
14
15 virtual std::vector<unsigned int> getTransients ();
16@@ -74,10 +73,14 @@
17
18 PrivateCompizMinimizedWindowHandler *priv;
19 static bool handleEvents;
20- static std::list<Ptr> minimizedWindows;
21+ static List minimizedWindows;
22 };
23 }
24
25+/* XXX minimizedWindows should be removed because it is dangerous to keep
26+ * a list of windows separate to compiz-core. The list could get out of
27+ * sync and cause more crashes like LP: #918329, LP: #864758.
28+ */
29 template <typename Screen, typename Window>
30 typename compiz::CompizMinimizedWindowHandler<Screen, Window>::List compiz::CompizMinimizedWindowHandler<Screen, Window>::minimizedWindows;
31
32@@ -100,12 +103,7 @@
33 template <typename Screen, typename Window>
34 compiz::CompizMinimizedWindowHandler<Screen, Window>::~CompizMinimizedWindowHandler ()
35 {
36- typedef compiz::CompizMinimizedWindowHandler<Screen, Window> minimized_window_handler_full;
37-
38- compiz::CompizMinimizedWindowHandler<Screen, Window>::Ptr compizMinimizeHandler =
39- boost::dynamic_pointer_cast <minimized_window_handler_full> (Window::get (priv->mWindow)->mMinimizeHandler);
40-
41- minimizedWindows.remove (compizMinimizeHandler);
42+ minimizedWindows.remove (this);
43 }
44
45 template <typename Screen, typename Window>
46@@ -144,18 +142,13 @@
47 Atom wmState = XInternAtom (screen->dpy (), "WM_STATE", 0);
48 unsigned long data[2];
49
50- typedef compiz::CompizMinimizedWindowHandler<Screen, Window> minimized_window_handler_full;
51-
52 std::vector<unsigned int> transients = getTransients ();
53
54 handleEvents = true;
55 priv->mWindow->windowNotify (CompWindowNotifyMinimize);
56 priv->mWindow->changeState (priv->mWindow->state () | CompWindowStateHiddenMask);
57
58- compiz::CompizMinimizedWindowHandler<Screen, Window>::Ptr compizMinimizeHandler =
59- boost::dynamic_pointer_cast <minimized_window_handler_full> (Window::get (priv->mWindow)->mMinimizeHandler);
60-
61- minimizedWindows.push_back (compizMinimizeHandler);
62+ minimizedWindows.push_back (this);
63
64 for (unsigned int &w : transients)
65 {
66@@ -163,8 +156,10 @@
67
68 if (win)
69 {
70- Window::get (win)->mMinimizeHandler = MinimizedWindowHandler::Ptr (new CompizMinimizedWindowHandler (win));
71- Window::get (win)->mMinimizeHandler->minimize ();
72+ Window *w = Window::get (win);
73+ if (!w->mMinimizeHandler)
74+ w->mMinimizeHandler = new Type (win);
75+ w->mMinimizeHandler->minimize ();
76 }
77 }
78
79@@ -226,14 +221,9 @@
80 Atom wmState = XInternAtom (screen->dpy (), "WM_STATE", 0);
81 unsigned long data[2];
82
83- typedef compiz::CompizMinimizedWindowHandler<Screen, Window> minimized_window_handler_full;
84-
85 std::vector<unsigned int> transients = getTransients ();
86
87- compiz::CompizMinimizedWindowHandler<Screen, Window>::Ptr compizMinimizeHandler =
88- boost::dynamic_pointer_cast <minimized_window_handler_full> (Window::get (priv->mWindow)->mMinimizeHandler);
89-
90- minimizedWindows.remove (compizMinimizeHandler);
91+ minimizedWindows.remove (this);
92
93 priv->mWindow->focusSetEnabled (Window::get (priv->mWindow), true);
94
95@@ -247,10 +237,13 @@
96
97 if (win)
98 {
99- if (Window::get (win)->mMinimizeHandler)
100- Window::get (win)->mMinimizeHandler->unminimize ();
101-
102- Window::get (win)->mMinimizeHandler.reset ();
103+ Window *w = Window::get (win);
104+ if (w && w->mMinimizeHandler)
105+ {
106+ w->mMinimizeHandler->unminimize ();
107+ delete w->mMinimizeHandler;
108+ w->mMinimizeHandler = NULL;
109+ }
110 }
111 }
112
113@@ -330,10 +323,9 @@
114
115 if (w)
116 {
117- typedef compiz::CompizMinimizedWindowHandler<Screen, Window> plugin_handler;
118 Window *pw = Window::get (w);
119- plugin_handler::Ptr compizMinimizeHandler =
120- boost::dynamic_pointer_cast <plugin_handler> (pw->mMinimizeHandler);
121+ Type *compizMinimizeHandler = pw->mMinimizeHandler;
122+
123 /* Restore and re-save input shape and remove */
124 if (compizMinimizeHandler)
125 {
126
127=== modified file 'plugins/unityshell/src/unityshell.cpp'
128--- plugins/unityshell/src/unityshell.cpp 2012-01-19 15:13:35 +0000
129+++ plugins/unityshell/src/unityshell.cpp 2012-01-20 07:01:19 +0000
130@@ -1742,11 +1742,7 @@
131
132 if (mMinimizeHandler)
133 {
134- typedef compiz::CompizMinimizedWindowHandler<UnityScreen, UnityWindow> minimized_window_handler_unity;
135-
136- compiz::CompizMinimizedWindowHandler<UnityScreen, UnityWindow>::Ptr compizMinimizeHandler =
137- boost::dynamic_pointer_cast <minimized_window_handler_unity> (mMinimizeHandler);
138- mask |= compizMinimizeHandler->getPaintMask ();
139+ mask |= mMinimizeHandler->getPaintMask ();
140 }
141 else if (mShowdesktopHandler)
142 {
143@@ -1815,7 +1811,7 @@
144
145 if (!mMinimizeHandler)
146 {
147- mMinimizeHandler = compiz::MinimizedWindowHandler::Ptr (new compiz::CompizMinimizedWindowHandler<UnityScreen, UnityWindow> (window));
148+ mMinimizeHandler = new UnityMinimizedHandler (window);
149 mMinimizeHandler->minimize ();
150 }
151 }
152@@ -1826,14 +1822,15 @@
153 if (mMinimizeHandler)
154 {
155 mMinimizeHandler->unminimize ();
156- mMinimizeHandler.reset ();
157+ delete mMinimizeHandler;
158+ mMinimizeHandler = nullptr;
159 }
160 }
161
162 bool
163 UnityWindow::focus ()
164 {
165- if (!mMinimizeHandler.get ())
166+ if (!mMinimizeHandler)
167 return window->focus ();
168
169 if (window->overrideRedirect ())
170@@ -1865,7 +1862,7 @@
171 bool
172 UnityWindow::minimized ()
173 {
174- return mMinimizeHandler.get () != NULL;
175+ return mMinimizeHandler != nullptr;
176 }
177
178 gboolean
179@@ -1928,16 +1925,12 @@
180
181 window->windowNotify(n);
182
183- if (mMinimizeHandler.get () != NULL)
184+ if (mMinimizeHandler)
185 {
186 /* The minimize handler will short circuit the frame
187 * region update func and ensure that the frame
188 * does not have a region */
189- typedef compiz::CompizMinimizedWindowHandler<UnityScreen, UnityWindow> minimized_window_handler_unity;
190-
191- compiz::CompizMinimizedWindowHandler<UnityScreen, UnityWindow>::Ptr compizMinimizeHandler =
192- boost::dynamic_pointer_cast <minimized_window_handler_unity> (mMinimizeHandler);
193- compizMinimizeHandler->windowNotify (n);
194+ mMinimizeHandler->windowNotify (n);
195 }
196 else if (mShowdesktopHandler)
197 {
198@@ -1976,13 +1969,9 @@
199 /* The minimize handler will short circuit the frame
200 * region update func and ensure that the frame
201 * does not have a region */
202- typedef compiz::CompizMinimizedWindowHandler<UnityScreen, UnityWindow> minimized_window_handler_unity;
203-
204- compiz::CompizMinimizedWindowHandler<UnityScreen, UnityWindow>::Ptr compizMinimizeHandler =
205- boost::dynamic_pointer_cast <minimized_window_handler_unity> (mMinimizeHandler);
206-
207- if (compizMinimizeHandler)
208- compizMinimizeHandler->updateFrameRegion (region);
209+
210+ if (mMinimizeHandler)
211+ mMinimizeHandler->updateFrameRegion (region);
212 else if (mShowdesktopHandler)
213 mShowdesktopHandler->updateFrameRegion (region);
214 else
215@@ -2453,6 +2442,7 @@
216 , PluginClassHandler<UnityWindow, CompWindow>(window)
217 , window(window)
218 , gWindow(GLWindow::get(window))
219+ , mMinimizeHandler(nullptr)
220 , mShowdesktopHandler(nullptr)
221 , focusdesktop_handle_(0)
222 {
223@@ -2519,8 +2509,10 @@
224 window->minimizedSetEnabled (this, false);
225 window->minimize ();
226
227- mMinimizeHandler.reset ();
228+ delete mMinimizeHandler;
229+ mMinimizeHandler = nullptr;
230 }
231+
232 if (mShowdesktopHandler)
233 delete mShowdesktopHandler;
234
235
236=== modified file 'plugins/unityshell/src/unityshell.h'
237--- plugins/unityshell/src/unityshell.h 2012-01-14 13:05:16 +0000
238+++ plugins/unityshell/src/unityshell.h 2012-01-20 07:01:19 +0000
239@@ -376,7 +376,10 @@
240 void leaveShowDesktop ();
241 bool handleAnimations (unsigned int ms);
242
243- compiz::MinimizedWindowHandler::Ptr mMinimizeHandler;
244+ typedef compiz::CompizMinimizedWindowHandler<UnityScreen, UnityWindow>
245+ UnityMinimizedHandler;
246+ UnityMinimizedHandler *mMinimizeHandler;
247+
248 UnityShowdesktopHandler *mShowdesktopHandler;
249
250 private: