【问题标题】:Segfault in D for too large inputsD 中的段错误,因为输入太大
【发布时间】:2013-11-24 06:33:22
【问题描述】:

以下 D 程序会因输入 939971 或更高版本而崩溃,但不会因输入 939970 或更低版本而崩溃:

#!/usr/bin/rdmd --shebang -w -d-debug --relocation-model=pic
    import std.stdio;
import std.bigint;
import std.conv;
import std.array;
//extern (C) void fibonacci (int* pointer, int length);
int main(string[] args)
{
  args.popFront();
  foreach(size_t i, string a; args) {
    writeln(fibonacci(to!BigInt(a)));
  }
  return 0;
}



BigInt fibonacci (BigInt input)
{
  struct FibMatrix
  {
    BigInt a;
    BigInt b;
    BigInt d;

    this(bool test)
    {
      a = 1;
      if (test) {
        b = 1; d = 0;
      } else {
        b = 0; d = 1;
      }
    }

    void square()
    {
      BigInt f = b^^2;
      b = b*(a + d);
      a = a^^2 + f;
      d = d^^2 + f;
    }

    void opOpAssign(string op, FibMatrix) (FibMatrix input)
    {
      static if (op == "*")
      {
        BigInt temp1 = b * input.b;
        d *= input.d;
        d += temp1;
        b *= input.d;
        b += a*input.b;
        a *= input.a;
        a += temp1;
      } else static assert(0, "Unsupported operator");
    }
  }
  if (input == 0) {
    return BigInt(0);
  } else {
    input -= 1;
  }
  FibMatrix base = FibMatrix(true);
  FibMatrix result = FibMatrix(false);
  version (none)
  {
    writeln (result.a);
    writeln (result.b);
    writeln (result.d);
  }
  if (input % 2 == 1) {
    result *= base;
  }
  version (none)
  {
    writeln (result.a);
    writeln (result.b);
    writeln (result.d);
  }
  input /= 2;
  while (input > 0) {
    base.square();
    if (input % 2 == 1) {
      result *= base;
    }
    input /= 2;
  }
  return result.a;
}

堆栈跟踪:

#0  0x0000003c51b492e6 in __memcpy_ssse3_back () from /lib64/libc.so.6
#1  0x000000000043d6d8 in std.internal.math.biguintcore.inplaceSub() ()
#2  0x000000000043c340 in std.internal.math.biguintcore.mulKaratsuba() ()
#3  0x000000000043c519 in std.internal.math.biguintcore.mulKaratsuba() ()
#4  0x000000000043ad34 in std.internal.math.biguintcore.mulInternal() ()
#5  0x000000000043a7ef in std.internal.math.biguintcore.BigUint.mul() ()
#6  0x000000000040a8a6 in std.bigint.BigInt.__T10opOpAssignVAyaa1_2aTS3std6bigint6BigIntZ.opOpAssign() ()
#7  0x0000000000403f00 in std.bigint.BigInt.__T8opBinaryVAyaa1_2aTS3std6bigint6BigIntZ.opBinary() ()
#8  0x000000000040456b in getints.fibonacci() ()
#9  0x00000000004035d9 in getints.fibonacci() ()
#10 0x0000000000402f4a in D main ()
#11 0x000000000045bfea in rt.dmain2._d_run_main() ()
#12 0x000000000045bc06 in _d_run_main ()
#13 0x0000003c51a21b45 in __libc_start_main () from /lib64/libc.so.6
#14 0x0000000000402d29 in _start ()

在我看来,这就像 Phobos 中的一个错误 - 我说的对吗?

【问题讨论】:

  • 在 dejan 的回答中查看我的 cmets - 我认为他对崩溃本身的看法是正确的,但我也很确定实际问题出在火卫一内部,所以是的,很可能是火卫一中的错误。

标签: segmentation-fault d phobos


【解决方案1】:

我认为您的应用程序进程已达到堆栈大小限制。当我编译和运行时,我得到的是:

object.Error: Access Violation
----------------
0x0041DDDC
----------------
Press any key to continue . . .

0x0041DDDC 是一个熟悉的数字 - 它正好是 4MB (4 * 1024 * 1024)。所以我的第一个猜测是 - 你达到了堆栈大小限制。

更新:稍微挖掘一下 DMD 设置的默认堆栈大小导致找到 this thread on D forum。根据该线程,DMD 显然设置了 4k 千字节 (4mb) 堆栈大小,我相信这可以解释为什么我们会收到上述错误。

【讨论】:

  • 这没有意义……BigInt 的文档提到了堆分配。
  • 堆栈在我看来也很混乱。我在调试模式下使用 phobos 模块重新编译(比听起来容易:只需将单个模块添加到您的 dmd -debug 命令行)并得到这个: core.exception.AssertError@d/dmd2/src/phobos/std/internal/math/biguintcore.d(1783): Bigint Internal Error: Asymmetric Karatsuba 我对 bigint 知之甚少,但我的猜测是没有调试版本,断言永远不会触发,它会覆盖暂存缓冲区或其他东西,导致访问冲突和/或堆栈粉碎。我猜底线,可能是火卫一错误
  • 并在断言上方注释掉if (x.length <= KARATSUBALIMIT) 几行似乎使问题消失(我没有运行它完成,花费了太长时间,但它也没有崩溃.) - 它总是使用其他乘法算法。我敢肯定,在这种情况下,karatsuba impl 中的某些内容会超出范围,从而破坏内存。我不知道如何解决这个问题,但绝对值得一个错误报告,特别是因为它是一个内部模块的断言,它肯定不是你的代码的错。
  • 在 D bugzilla 上报告为 bug 11599。
【解决方案2】:

问题是 std.BigInt 中的一个错误,它在乘以过大的 BigInt 值时会导致崩溃。这可能是因为 Karatsuba 乘法算法的实现不好,因为阻止它被使用可以解决问题,迫使它使用标准的 BigInts 乘法方式(这对于如此大的输入效率较低,但没有错误)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-12-28
    • 1970-01-01
    • 1970-01-01
    • 2021-02-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-21
    相关资源
    最近更新 更多