6

我有一些使用 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 的应用程序,它中止几乎是处理此类问题的最不理想的方式。

4

3 回答 3

4

根据mpz/realloc.cmpz/realloc2.c中的代码,您似乎很不走运。如果请求的内存过多,它会这样做:

if (UNLIKELY (new_alloc > INT_MAX))
  {
    fprintf (stderr, "gmp: overflow in mpz type\n");
    abort ();
  }
于 2010-08-24T21:52:10.927 回答
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;
}
于 2010-08-25T02:06:31.850 回答
1

abort()用覆盖LD_PRELOAD

什么是 LD_PRELOAD 技巧?

编辑:为了使答案更加独立,我在此处复制该答案的文本:

如果将 LD_PRELOAD 设置为共享对象的路径,则该文件将在任何其他库(包括 C 运行时 libc.so)之前加载。因此,要使用特殊的 malloc() 实现运行 ls,请执行以下操作:

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

归功于 JesperE。

于 2010-11-09T15:02:16.167 回答