【问题标题】:Stackoverflow and function pointersStackoverflow 和函数指针
【发布时间】:2011-08-30 09:43:23
【问题描述】:

我对这个很迷茫,希望这里有人能提供帮助。

我的应用程序包含数百个评估数字代码的函数(每个源在 5MB 范围内),我使用 std::map 来管理函数指针。 显然发生的事情是,当我尝试将参数传递给通过指向它的指针访问的函数之一时,我得到了堆栈溢出:

gdb 输出:

Program received signal SIGSEGV, Segmentation fault.
0x0000000001ec0df7 in xsectiond149 (sme=Cannot access memory at address 0x7fffff34b888
) at xsection149.c:2
2       Poly3 xsectiond149(std::tr1::unordered_map<int, Poly3> & sme, 
                           EvaluationNode::Ptr ti[], ProcessVars & s)

并且 xsection149.c:2 仅具有用于定义函数的左大括号。

/proc/&lt;pid&gt;/map 为进程显示最接近触发错误的地址的地址范围仅这一行:

7ffffff74000-7ffffffff000 rw-p 7ffffff73000 00:00 0                      [stack]

所以上述错误中的地址超出范围。

现在我的问题是:我该如何解决这个问题?我不知道我可以在堆上分配什么......

在我的主程序中发生的唯一想法是:

// A map containing O(10^4) Poly3 (struct with 6 doubles)
tr1::unordered_map<int, Poly3> smetemp;
// populates smetemp
computeSMEs(smetemp);
// Map of function pointers of type, O(10^3) elements
tr1::unordered_map<int, xsdptr> diagfunctions = get_diagram_map(); 

这怎么会溢出堆栈??

编辑:我尝试在 valgrind 中运行它,这是我得到的错误,谷歌没有提供任何有意义的信息:

valgrind: m_debuginfo/storage.c:417 (vgModuleLocal_addDiCfSI): 
    Assertion 'cfsi.len < 5000000' failed.
==491==    at 0x38029D5C: ??? (in /usr/lib64/valgrind/memcheck-amd64-linux)

EDIT2:将函数反汇编到它失败的点(0x0000000001ec0df7)给我:

Dump of assembler code for function xsectiond149(std::tr1::unordered_map<int, Poly3,      std::tr1::hash<int>, std::equal_to<int>, std::allocator<std::pair<int const, Poly3> >,   false>&, std::vector<boost::shared_ptr<EvaluationNode>,    std::allocator<boost::shared_ptr<EvaluationNode> > >&, ProcessVars&):
<...+0>:      push   %rbp                                                               
<...+1>:      mov    %rsp,%rbp                                                          
<...+4>:      push   %r15                                                               
<...+6>:      push   %r14                                                               
<...+8>:      push   %r13                                                               
<...+10>:     push   %r12                                                               
<...+12>:     push   %rbx                                                               
<...+13>:     sub    $0xc96b58,%rsp                                                     
<...+20>:     mov    %rdi,%rbx                                                          
<...+23>:     mov    %rsi,-0xc8b078(%rbp)      // this instr fails                                         

函数的前几行如下:

Poly3 xsectiond149(std::tr1::unordered_map<int, Poly3> & sme,   
                   std::vector<EvaluationNode::Ptr> & ti, 
                   ProcessVars & s)
{
    Poly3 sum(0,0,0,-2);
    Poly3 prefactor, expr;

    // CF*CA^2*NF*NA^(-2)
    double col0 = 0.5625000000000000000000000000;

    prefactor = col0*ti[0]->value()*s.Qtpow2*s.epow2*s.gpow6;
    expr =       (128*(s.p1p2*sme[192]*s.mt - s.p1p2*sme[193]*s.mt +
       1/2.*s.p1p2*sme[195]*s.mt - 1/2.*s.p1p2*sme[196]*s.mt -
       s.p1p2*sme[201]*s.mt + s.p1p2*sme[202]*s.mt +
       1/2.*s.p1p2*sme[210]*s.mt - 1/2.*s.p1p2*sme[211]*s.mt -
       1/4.*s.p1p2*sme[216]*s.mt + 1/4.*s.p1p2*sme[217]*s.mt -
       s.p1p2*sme[219]*s.mt + s.p1p2*sme[220]*s.mt -
       1/8.*s.p1p2*sme[1209]*s.mt + 1/8.*s.p1p2*sme[1210]*s.mt +
       1/2.*s.p1p2*sme[1215]*s.mt - 1/2.*s.p1p2*sme[1216]*s.mt +
   // .....
}

(注意我在实验过程中更改了函数的签名)

任何人都可以解决这里发生的事情吗?您需要哪些附加信息?抱歉,我几乎没有使用 asm 的经验。

EDIT3: 使用ulimit -s &lt;size&gt; 增加堆栈大小就可以了。谢谢大家的帮助!

【问题讨论】:

  • 堆栈溢出或访问冲突?似乎是后者,而不是前者。
  • 我很想看看引入此 segv 的签入内容。
  • @GMan:我认为这是堆栈溢出,很难说。实际上在调用xsectiond149(...)之前访问smetemp可以正常工作,所以我想这是将参数传递给函数的问题。
  • 看起来像一个简单的堆栈溢出。不要在你的小线程堆栈上声明巨大的变量 =P
  • @bbtrb,如果你有 5megs 的源代码可以使用,我认为这一切都在源代码控制之下。而且你不只是结束了 5 兆的源,它肯定必须在过去的某个时候工作。那么,在它工作和失败之间发生了什么变化?找到那个签入,希望它会更容易发现问题。 :)

标签: c++ stack-overflow function-pointers


【解决方案1】:

看起来函数 xsectiond149 需要大约 13 MB 的堆栈帧(注意指令 sub $0xc96b58,%rsp,一旦它试图在两条指令后写下东西就会失败)。在调用函数之前,您需要确保线程有足够大的堆栈(默认情况下不会)。

您还可以考虑更改代码生成器以在堆上而不是堆栈上分配更多的东西。

【讨论】:

  • 谢谢!您的提示将我指向 *nix 上的ulimit -s,增加堆栈大小就可以了。选择太大的堆栈大小有什么限制和缺点吗?
  • 在你进程的内存空间中,栈向下增长,而堆向上增长。增加堆栈的大小会减少可用于堆增长的空间。您还应该记住,如果增加适用于所有线程,则效果将成倍增加。但是,使用 64 位地址空间,实际上您不必担心太多。
【解决方案2】:

获取Valgrind 并在构建后在 Valgrind 下运行您的程序(使用 memcheck,默认工具)。这样,您将更容易定位故障源。

您还可以在 Valgrind 进入调试器(通常是 GDB)的模式下运行,然后您可以使用所有很酷的 GDB 命令来检查调用者堆栈帧中的值等等。

无论哪种方式,如果您遇到困难,Valgrind 应该会帮助您找到一些继续前进的指示。

关于您的编辑,这是我的回复(引用自 Valgrind 源代码,r11604 of storage.c):

445     /* sanity */
446     vg_assert(cfsi.len > 0);
447     /* If this fails, the implication is you have a single procedure
448     with more than 5 million bytes of code. Which is pretty
449     unlikely. Either that, or the debuginfo reader is somehow
450     broken. 5 million is of course arbitrary; but it's big enough
451     to be bigger than the size of any plausible piece of code that
452     would fall within a single procedure. */
453     vg_assert(cfsi.len < 5000000); 

【讨论】:

  • 感谢您的建议。但是,它没有帮助,请参阅上面的编辑。
  • 在答案中查看我的更新。我强烈建议您检查预处理的代码,如果这还算正常,请深入研究反汇编。因为显然您的源代码中至少有一个功能具有巨大的大小,或者调试阅读器已损坏。考虑到你看到的另一个奇怪的症状,我会把钱放在第一个上。
  • 是的,函数的体积很大,但我真的无能为力...请参阅我的第二个 EDIT 进行反汇编,直到出现故障。
猜你喜欢
  • 2011-12-13
  • 2018-09-12
  • 2011-04-26
  • 1970-01-01
  • 2012-10-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-28
相关资源
最近更新 更多