Category Archives: Linux

How to waste an evening debugging the internals of glib’s qsort implementation

Working on a personal itch-scratching project, I found myself wanting a sortable treeview. So I stuffed my treemodel into a TreeModelSort and set up my sort functions, and everything was happy. Except, when running my application, I kept getting strange segfaults within glib’s qsort implementation. I had set the following function as my sort_func (yes, it’s C++, but it should be fairly self-explanatory):

static int
compare_foo (const Gtk::TreeModel::iterator& a, const Gtk::TreeModel::iterator& b)
    std::tr1::shared_ptr<Foo> l1, l2;
    l1 = a->get_value (COLUMN_FOO);
    l2 = b->get_value (COLUMN_FOO);

    if (!l1)
        return -1;

    if (!l2)
        return 1;

    return l1->get_id () - l2->get_id ();

Can you spot the error? Running it under valgrind indicated that I was reading data from *before* the start of the array that was being sorted. In fact, the following lines of code in g_qsort_with_data() were causing tmp_ptr to be decreased back past the start of the array:

        while ((*compare_func) ((void *) run_ptr, (void *) tmp_ptr, user_data) < 0)
          tmp_ptr -= size;

Hmm. Why is there no guard to prevent tmp_ptr from being decreased past the start? Then I noticed the following comment up a few lines:

    /* Find smallest element in first threshold and place it at the
       array's beginning.  This is the smallest array element,
       and the operation speeds up insertion sort's inner loop. */

So at this point, the code is assuming that the very first element of the array is the smallest, so compare_func should always return >= 0 when it reaches the start of the array. Aha! So the problem is my compare_func. It turns out I forgot to handle the single case of both values being NULL.

    l1 = a->get_value (COLUMN_FOO);
    l2 = b->get_value (COLUMN_FOO);
+   if (!l1 && !l2)
+       return 0;

    if (!l1)
        return -1;

So there’s not really a big lesson to be learned here, but if you ever hit strange segfaults deep inside glib’s qsort while sorting a treemodel, do yourself a favor and double-check that your sort function is sane first. Also, do yourself a favor and run it under valgrind as soon as you get a strange segfault. Knowing the exact point of the invalid read is infinitely more helpful than waiting until that invalid read causes a segfault.

Testing Nemiver

Progress on nemiver has been slightly slower of late, but we’re making some steady progress on new things. In an effort to help more people test out newer versions of nemiver and to brush up on my packaging skills, I set up a personal package archive at launchpad about a week ago where I’ve uploaded a recent build of nemiver. Those of you using Ubuntu Feisty that want to try out a more up-to-date version of Nemiver can do so by adding the following lines to /etc/apt/sources.list

deb feisty main universe
deb-src feisty main  universe

Followed by the requisite apt-get install nemiver.

I’ll try to upload new versions periodically. Let me know if you have any issues with them. All of the usual caveats apply — this is development code so may not be completely stable, etc.

Webcams on Linux

Since Joanne’s parents live in Thailand, they’re not able to see their new granddaughter very often. They use skype to communicate regularly, so we thought we’d grab a cheap little webcam so that they could see Ruby while they were talking as well. I picked up the cheapest webcam they had at the local Best Buy: a Logitech QuickCam Communicate STX for $35. Just for fun, I thought I’d try it out on my Ubuntu Feisty machine, not really expecting much. To my surprise, I plugged it into the USB port, fired up Ekiga [1], and within 10 seconds was having a video chat with my brother (well, the video chat was one way, since he doesn’t have a webcam or a microphone, but I’m told that he could see and hear me).

By contrast, to get it to work on Joanne’s Windows machine (so she could use it with Skype), it wanted to immediately download updated ‘drivers’ (probably including a bunch of useless utility software — over 100MB!) and of course, install them. It installed without problem, but all-in-all, it took about 10 times as long as it did to get it working on Linux.

When I first started using Linux, I would have never dreamed that hardware support would have gotten this good by now. In fact, on the way home from picking up the webcam, I joked to Joanne that getting it to work on Linux was going to be my weekend project. Ha!

[1] By the way, this is the first time I’ve used Ekiga. It’s quite nice, and the new GUI work looks great.