Ошибка сегментации при вызове wxThread::OnExit()

Обновление 2: см. раздел после моего кода.

Я использую поток для вычисления PI с использованием библиотеки GMP, но каким-то образом теперь я получаю ошибку сегментации, когда wxThread::OnExit() вызывается внутри wxWidgets.

Вот строка исходного кода wxWidgets: src/msw/ thread.cpp#553

Вот сокращенный код из моей функции входа в поток:

while (i <= m_numIterations && !TestDestroy()) {
    mpf_div(result, perimeter, edgeCount);

    mpf_pow_ui(result, result, 2);
    mpf_ui_sub(result, 1, result);
    mpf_sqrt(result, result);
    mpf_div_ui(result, result, 2);

    mpf_sub(result, half, result);
    mpf_sqrt(result, result);
    mpf_mul_ui(result, result, 2);
    mpf_mul(result, result, edgeCount);

    mpf_set(perimeter, result);

    i++;
    mpf_mul_ui(edgeCount, edgeCount, 2);
}

// Free GMP variables we don't need anymore
mpf_clear(half);
mpf_clear(result);
mpf_clear(edgeCount);

// OUTPUT_DIGITS has a constant value, e.g. 12
char outputStr[OUTPUT_DIGITS];

mp_exp_t *expptr;

// If commented out, the error does not appear!
mpf_get_str(outputStr, expptr, 10, OUTPUT_DIGITS, perimeter);

Обновление 2: если я закомментирую последнюю строку с помощью mpf_get_str(), ошибка не возникнет.
Я также нашел очень старые запросы об ошибках от 2003 года: http://gmplib.org/list-archives/gmp-discuss/2003-November/000888.html

Стек вызовов из отладчика GCC:

#0 63AE80E9 wxThreadInternal::DoThreadOnExit(thread=0x2cfa978) (../../src/msw/thread.cpp:553)
#1 63B27ACF wxScopeGuardImpl1<void (*)(wxThread*) (../../include/wx/scopeguard.h:168)
#2 63B3F95B wxPrivate::OnScopeExit<wxScopeGuardImpl1<void (*)(wxThread*) (../../include/wx/scopeguard.h:67)
#3 63B27B36 wxScopeGuardImpl1<void (*)(wxThread*) (../../include/wx/scopeguard.h:166)
#4 63AE82FB wxThreadInternal::DoThreadStart(thread=0x2cfa978) (../../src/msw/thread.cpp:561)
#5 63AE83F2 wxThreadInternal::WinThreadStart(param=0x2cfa978) (../../src/msw/thread.cpp:602)
#6 75C4906A ui64tow() (C:\Windows\SysWOW64\msvcrt.dll:??)
#7 75C49147 msvcrt!iswalnum() (C:\Windows\SysWOW64\msvcrt.dll:??)
#8 76448543 UnregisterBadMemoryNotification() (C:\Windows\SysWOW64\kernel32.dll:??)
#9 00000000 0x02cfb178 in ??() (??:??)
#10 00000000    0x77e8ac69 in ??() (??:??)
#11 00000000    0x77e8ac3c in ??() (??:??)
#12 00000000    0x00000000 in ??() (??:??)

person ComFreek    schedule 19.09.2012    source источник
comment
Если это постоянный размер, почему вы динамически выделяете его?   -  person chris    schedule 20.09.2012
comment
Ты прав. Я только что попробовал, но теперь он выдает ошибку сегментации при вызове wxThread::OnExit()!   -  person ComFreek    schedule 20.09.2012
comment
Он должен вызывать исключение, а не возвращать NULL. Кроме того, ваше утверждение, которое следует ниже, неверно.   -  person Nikolai Fetissov    schedule 20.09.2012
comment
Обратите внимание, что я изменил вопрос и код. outputStr теперь размещается в стеке.   -  person ComFreek    schedule 20.09.2012
comment
Какую версию GMP вы используете? [V4.1])(cs.nyu.edu/exact/core/gmp) вызывал аналогичную ошибку в Windows 7 x64 в этом коде: char *data = mpz_get_str(NULL, base, gmpInt); std::string output(data); free(data);. В моем случае ошибка сегментации была вызвана вызовом free, и я предположил, что mpz_get_str, вероятно, выделяет память каким-то странным образом, не предоставляя никаких (очевидных) средств ее освобождения. Мне удалось обойти это с помощью MPIR в Windows и последней версии GMP в Linux.   -  person Mihai Todor    schedule 24.09.2012
comment
@MihaiTodor Спасибо за ваш комментарий и спасибо, что вы вспомнили меня, чтобы опубликовать решение. Проблема заключалась в том, что expptr не был инициализирован (т. е. вы должны new это сделать, GMP не сделает это за вас!)   -  person ComFreek    schedule 24.09.2012
comment
@ComFreek Мне кажется довольно странным, что вы используете на нем new, поскольку вы вызываете C-версию GMP API. Я ожидал бы использовать malloc и free в этом случае, но в любом случае, я рад, что вам удалось заставить его работать.   -  person Mihai Todor    schedule 24.09.2012
comment
@MihaiTodor Я уже видел оболочку C++. Но я не вижу причин использовать его в моей небольшой программе PI, если это всего лишь оболочка.   -  person ComFreek    schedule 24.09.2012
comment
Ну, вот что я говорю: если вы используете материал C, то не смешивайте его с элементами C++, такими как new и delete, потому что, делая это, вы определенно напрашиваетесь на неприятности;)   -  person Mihai Todor    schedule 24.09.2012
comment
@MihaiTodor Есть ли у вас какие-либо ссылки по этой теме? Я был бы заинтересован в моих будущих проектах.   -  person ComFreek    schedule 24.09.2012
comment
Это много раз обсуждалось на SO: stackoverflow.com/questions/240212/ и здесь stackoverflow.com/questions/9972212/   -  person Mihai Todor    schedule 24.09.2012
comment
@MihaiTodor Спасибо. Я учту их в своих будущих проектах. Но AFAIK GMP не использует new или delete какие-либо переданные параметры. Так что это безопасно (это означает, что это не сломает что-то напрямую) использовать здесь.   -  person ComFreek    schedule 24.09.2012
comment
@ComFreek Ну, это твой код;)   -  person Mihai Todor    schedule 24.09.2012


Ответы (3)


new не «отказывается», как таковой, у вас где-то есть повреждение кучи.

person mark    schedule 19.09.2012
comment
Спасибо за Ваш ответ. Я изменил свой вопрос, так как вы ответили. Но я все еще получаю ошибку сегментации, см. мой текст. - person ComFreek; 20.09.2012
comment
у вас все еще есть повреждение где-то ... перемещение элемента из кучи в стек не меняет этого. запустите его в отладчике, он может ошибаться рядом или там, где на самом деле происходит повреждение. - person mark; 20.09.2012
comment
вы также можете попробовать valgrind, если вы работаете в Linux... он будет работать намного медленнее, эффективно в эмуляторе, но он может обнаруживать недопустимый доступ к указателю, переполнение стека и т. д. - person mark; 20.09.2012
comment
Я поместил стек вызовов в свой вопрос. Я на Windows. - person ComFreek; 20.09.2012
comment
new, безусловно, может выйти из строя, но, вероятно, проблема не в этом. new выдаст исключение, если не сможет выделить запрошенный объем памяти, а new (nothrow) вернет нулевой указатель. - person Ed S.; 20.09.2012
comment
@ЭдС. Спасибо за информацию. Я не знал этого раньше. - person ComFreek; 20.09.2012
comment
@Ed S: технически вы правы на 100%, но с практической точки зрения new не подведет, если вы используете его обычным способом ... - person mark; 20.09.2012
comment
@mark: Конечно, бывает, просто не часто. По вашей логике вы никогда не должны проверять, возвращает ли malloc нулевой указатель, потому что вы используете его обычным способом. Я также не уверен, как вы могли бы использовать его ненормальным образом. - person Ed S.; 20.09.2012

Если он действительно вылетает в этой строке (есть также немалая вероятность того, что gdb просто потеряется и не покажет последующие кадры), то сам указатель thread должен быть NULL или недействительным, что не может произойти при нормальном выполнении, поэтому Я согласен с другим ответом: что-то, кажется, испортило ваши переменные. Но проверьте, введен ли ваш OnExit() вообще на случай, если gdb лжет.

И поскольку вы используете кросс-платформенные библиотеки, вы должны иметь возможность пересобирать под Linux и запускать его под valgrind, что должно выявить все очевидные проблемы.

person VZ.    schedule 20.09.2012

Указатель экспоненты (здесь expptr) уже должен быть инициализирован объектом.

Этот однострочный решает проблему:

expptr = new mp_exp_t();

// call mpf_get_str()

Также хочу отметить, что ВЗ. был прав в том, что GDB (отладчик GNU) может показать неправильную строку исходного кода, в которой должна появиться ошибка.

Так что не полагайтесь только на это.

person ComFreek    schedule 24.09.2012