предотвращение прерывания в libgmp
у меня есть код, который использует libgmp. В какой-то момент пользователь может запросить факториал очень большое количество. К сожалению, это приводит к тому, что libgmp поднимает сигнал прерывания.
например, следующий код:
#include <cmath>
#include <gmp.h>
#include <iostream>
int main() {
mpz_t result;
mpz_init(result);
mpz_fac_ui(result, 20922789888000);
std::cout << mpz_get_si(result) << std::endl;
}
результаты:
$ ./test
gmp: overflow in mpz type
Aborted
по-видимому, количество произведенных действительно большое. Есть ли в любом случае, чтобы справиться с ошибкой более изящно, чем аборт. Это приложение на основе GUI, и его прерывание является в значительной степени наименее желательным способом чтобы справиться с такой проблемой.
3 ответов
лучший способ справиться с этими ошибками изящно в вашем приложении, вероятно, развить вспомогательный процесс для выполнения вычислений GMP. Если вспомогательный процесс убит SIGABRT
, ваш родительский процесс может обнаружить это и сообщить об ошибке пользователю.
(ниже приведен мой первоначальный ответ, который имеет "неопределенные результаты" в соответствии с документацией GMP - он оставлен здесь для полноты).
вы можете поймать ошибку, если вы установите обработчик сигналов для SIGABRT
использует longjmp()
:
jmp_buf abort_jb;
void abort_handler(int x)
{
longjmp(abort_jb, 1);
}
int dofac(unsigned long n)
{
signal(SIGABRT, abort_handler);
if (setjmp(abort_jb))
goto error;
mpz_t result;
mpz_init(result);
mpz_fac_ui(result, 20922789888000);
std::cout << mpz_get_si(result) << std::endl;
signal(SIGABRT, SIG_DFL);
return 0;
error:
signal(SIGABRT, SIG_DFL);
std::cerr << "Caught SIGABRT from GMP.\n";
return 1;
}
похоже, что вам не повезло, основываясь на коде в mpz / realloc.c и mpz / realloc2.c. Если слишком много памяти было запрошено, он просто делает это:
if (UNLIKELY (new_alloc > INT_MAX))
{
fprintf (stderr, "gmp: overflow in mpz type\n");
abort ();
}
перезаписать abort()
с LD_PRELOAD
.
Edit: чтобы сделать ответ более автономным, я копирую текст этого ответа здесь:
Если вы установите LD_PRELOAD в путь к общему объекту, этот файл будет загружен перед любой другой библиотекой (включая среду выполнения c, libc.Итак). Поэтому, чтобы запустить ls с вашей специальной реализацией malloc (), сделайте следующее:
$ LD_PRELOAD=/path/to/my/malloc.so /bin/ls
кредиты JesperE.