Package: epiphany-browser
Version: 3.4.2-2
Severity: serious
Tags: patch


Machine: Dell PowerEdge 3250
Processor: 2x Itanium Madison 1.5GHz 6M
Memory: 16G


While working on bug#642750, I realized a failing assertion in the epiphany browser:
    at lib/history/ephy-history-service.c:363
          g_assert (priv->history_thread == g_thread_self ());

The assertion failed almost often upon the start of epiphany browser; sometimes epiphany could start with success.


The ephy_history_service_init() function creates a new thread (using g_thread_new()); run_history_service_thread() is the starting function of the thread.

static void
ephy_history_service_init (EphyHistoryService *self)
{
  self->priv = EPHY_HISTORY_SERVICE_GET_PRIVATE (self);

self->priv->history_thread = g_thread_new ("EphyHistoryService", (GThreadFunc) run_history_service_thread, self);
  self->priv->queue = g_async_queue_new ();
}


static gpointer
run_history_service_thread (EphyHistoryService *self)
{
  EphyHistoryServicePrivate *priv = self->priv;
  EphyHistoryServiceMessage *message;

  g_assert (priv->history_thread == g_thread_self ());

  if (ephy_history_service_open_database_connections (self) == FALSE)
    return NULL;

  do {
    message = g_async_queue_try_pop (priv->queue);
    if (!message) {
      /* Schedule commit if needed. */
      if (ephy_history_service_is_scheduled_to_commit (self))
        ephy_history_service_commit (self);

      /* Block the thread until there's data in the queue. */
      message = g_async_queue_pop (priv->queue);
    }

    /* Process item. */
    ephy_history_service_process_message (self, message);

  } while (!ephy_history_service_is_scheduled_to_quit (self));

  ephy_history_service_close_database_connections (self);
  ephy_history_service_execute_quit (self, NULL, NULL);

  return NULL;
}

The third non-empty line of run_history_service_thread() is the failing assertion.

The assertion fails because the created thread can execute its code before g_thread_new() returns and before the history_thread member is initialized. Whether it happens or not depends on how the operating system schedules the processors to the threads.

The history_thread member isn't any problem; it is used just for the assertions. But there is also an async queue (->queue) which is initialized *after* creating the new thread in ephy_history_service_init(). This means that the code in run_history_service_thread() touches the queue when it isn't initialized or while the queue is being initialized by the main thread.
That isn't healthy; this can result in data corruption.

The patch
- fixes the issue with the queue, and
- fixes the mentioned assertion.

Although it was experienced on ia64, the bug affects all archs.


You can find a link to the built debs on bug report#642750.

Stephan

Attachment: history-thread-startup-race.patch
Description: history-thread-startup-race.patch

Reply via email to