wxHaskell segfaults при перезапуске графического интерфейса из-за переполнения стека

Когда графический интерфейс wxHaskell запускается и закрывается, а затем снова запускается другой графический интерфейс wxHaskell, приложение получает ошибку сегментации из-за переполнения стека.

Простой демонстрационный источник:

module Main where

import Graphics.UI.WX

main = do
  start $ frame []
  start $ frame []

Кажется, это старая ошибка, см. http://permalink.gmane.org/gmane.comp.lang.haskell.wxhaskell.general/789. В этом сообщении есть ссылка на проблему в репозитории wxHaskell SourceForge, а в гораздо более позднем комментарии упоминается версия wxHaskell (кажется, ветка разработки для wxWidgets 2.9), в которой нет ошибок.

Я использую Ubuntu 12.04 с wxWidgets 2.8, поэтому мне приходится использовать wxHaskell 0.13. Я пытался найти какую-либо информацию об этой ошибке, просматривая журнал изменений якобы рабочей версии разработки, но ничего не нашел.

Можно ли исправить это ошибочное поведение для wxHaskell 0.13 или, по крайней мере, можно ли найти какое-то обходное решение? Переписывание приложения для работы с одним постоянным графическим интерфейсом кажется излишне сложным.


person myrix    schedule 23.09.2013    source источник


Ответы (1)


Можно придумать обходной путь для этой ошибки, по крайней мере, для wxWidgets-2.8 и GTK.

К сожалению, разработчикам wxHaskell не удалось реализовать GUI-стартовый интерфейс как реентерабельный. При каждом запуске GUI wxHaskell вызывает wxWidgets таким образом, что вызывается метод wxApp::Initialize из исходного файла wxWidgets src/gtk/app.cpp. В частности, этот метод выполняет следующие две строки для инициализации цикла событий GTK для wxWidgets:

wxgs_poll_func = g_main_context_get_poll_func(NULL);
g_main_context_set_poll_func(NULL, wxapp_poll_func);

Проблема в том, что в то время как при первом запуске графического интерфейса wxgs_poll_func устанавливается на любую функцию опроса, с которой начинается GTK (кажется, g_poll), при втором запуске графического интерфейса wxgs_poll_func устанавливается на wxapp_poll_func — при первом запуске графического интерфейса мы устанавливаем wxapp_poll_func как функцию опроса GTK, и когда мы просим это на втором запуске GUI с использованием g_main_context_get_poll_func, мы получаем wxapp_poll_func обратно.

Это имеет неприятные последствия во время выполнения wxapp_poll_func, который, насколько я понимаю, должен вызывать любую функцию опроса, используемую GTK, до инициализации wxWidgets вызовом wxgs_poll_func. При первом запуске графического интерфейса он фактически вызывает функцию опроса, с которой начинается GTK, но при втором запуске графического интерфейса он вызывает сам себя, переходя в бесконечную рекурсию и вызывая переполнение стека.

Довольно хакерский обходной путь — вручную сбрасывать g_poll как функцию опроса GTK после каждого сеанса GUI. Это может быть выполнено с помощью следующей функции C:

#include <glib.h>

void reset_g_poll()
{
  g_main_context_set_poll_func(NULL, g_poll);
}

Скомпилируйте его как общую библиотеку и импортируйте как внешнюю функцию C, и правильно модифицированная демонстрация работает. Модифицированная демонстрация:

module Main where

import Graphics.UI.WX

foreign import ccall unsafe "reset_g_poll"
  reset_g_poll :: IO ()

main = do

  start $ frame []
  reset_g_poll

  start $ frame []
  reset_g_poll
person myrix    schedule 23.10.2013