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.cおよびmpz/ 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 に答える