How we don't crash, by Last.fm

Max Howell max at last.fm
Mon Feb 16 18:28:24 CET 2009


Hello Amarok people,

Regarding Markey's last mail, perhaps this mail will help. Some just  
repeats Markey.
So, this is how we don't crash as much. And we can't crash, at all (if  
possible). It's a "people-pay-us-subscriptions" quality thing.

1. Stack allocate everything and pass by value
Except widgets and qobjects. The performance is fine. Especially with  
Qt container classes.

2. Parent all widgets and qobjects
Qt deletes them for you, everyone wins.

3. If you have to delete yourself, use a QPointer wrapper
This way you don't risk double frees

4. Singletons return references not pointers
This way you are forced to rethink singleton allocation. It simply has  
to exist, always. (Although singletons are evil, you end up with  
highly coupled code, but blah).

5. Initialise all data member pointers to zero
Yeah, you could be cool and only init what makes sense today. Like you  
immediately assign to m_awesome, so why bother with m_awesome( 0 )?
Because today is today, and tomorrow is tomorrow and this is open  
source people, anyone could come along and change everything in this  
code and then suddenly m_awesome is the decidely less awesome  
0x0000P00P and your delete m_awesome in the dtor crashes.

6. Our track object is never passed by pointer
We use a value-based Track class with a QExplicitlySharedDataPointer d  
pointer. This way a copied Track object still is the same Track  
object. Which if you think about it is exactly the same as a pointer.  
But the good thing is you have to test for null with a function. And  
thus there is no null pointer dereferencing And someone can't  
accidently delete the track and then cause a crash in some other place  
in your code. And users of the object can keep the objects around for  
as long as they like.

An alternative is to never pass 0 from you Track injection logic.  
Instead pass a new Track(). You have to delete it sometime though.  
Which means memory management.

You may have to do the latter if your track object has slots. Although  
that was prolly a bad idea if so. Data is data. Some kind of model  
should manage the data.

7. Always use deleteLater() on qobjects and qwidgets, (there's a few  
places that is daft though, you can figure it out)
calling delete on something from within a slot crashes often. Often  
the crash happens way up the stack inside qt because a huge trail of  
functions were called, then your slot. when you slot finishes these  
functions finish up and prolly one of them tries to use the object you  
deleted. Yay!
The best thing with this bug is different versions of Qt may have  
different call stacks and deep-usage. So you get bugs that make no  
sense.

8. Call the bounds checked versions of the Qt container functions  
accessors
This is usually the value() call. In general we always try to use  
functionality that returns a safe "null" or "zombie" object if there  
is an error. This is so we one, don't crash, and two, have better odds  
of handling the failure in a way that doesn't make the GUI look crazy.  
Zombie objects return safe empty values.

9. Use throw-away patterns
For instance, lets download an image and put it in a view. Make a new  
QObject derived class to do this. Call it ImageDownload0r. Add a  
signal kFinishedBai( QPixmap ). Make a start() function. The  
controller class does not keep a pointer to the object. The  
ImageDownload0r deletes itself (deleteLater!) when its done. The  
signal is emitted at the end always (but before the deleteLater!). To  
feel more memory conscious parent the downloader the to view it is  
populating.

You can feel safe with these classes. There is barely any coupling  
with anything else. The more you use them, the less potential crash  
bugs there are.

10. Encapsulate everything. Null pointers are more likely when you  
don't really feel sure about who is doing what.

I hope this was useful. And I'm sure you all knew most/all of it. Just  
trying to be helpful.

Max Howell
Lead Developer, Last.fm

PS liblastfm is out next weekend I hope. I'm doing all the last bits.  
I need to get it out urgently in fact so this time I may actually live  
up to my promise.
PPS you'd best cc me replies, thx


More information about the Amarok-devel mailing list