предотвращение прерывания в 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.

что такое LD_PRELOAD трюк?

Edit: чтобы сделать ответ более автономным, я копирую текст этого ответа здесь:

Если вы установите LD_PRELOAD в путь к общему объекту, этот файл будет загружен перед любой другой библиотекой (включая среду выполнения c, libc.Итак). Поэтому, чтобы запустить ls с вашей специальной реализацией malloc (), сделайте следующее:

$ LD_PRELOAD=/path/to/my/malloc.so /bin/ls

кредиты JesperE.