Stackoverflow 和函数指针
我对此很迷茫,希望这里有人能提供帮助。
我的应用程序由数百个评估数字代码的函数组成(每个函数的源代码在 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/
进程仅显示最接近触发错误的地址的地址范围这一行:
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)
编辑2:反汇编函数直到失败(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 的经验。
编辑3: 使用 ulimit -s
增加堆栈大小就可以解决问题。谢谢大家的帮助!
I'm quite lost on this one and I hope someone here could help.
My application consists of hundreds of functions evaluating numerical code (source is in the 5MB range each) and I manage the functions with a std::map
to function pointers.
What apparently happens is that I get a stack overflow when trying to pass an argument to one of the functions, accessed by a pointer to it:
gdb output:
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)
and xsection149.c:2 has only the opening brace for the definition of the function.
/proc/<pid>/map
for the process shows for the address range closest to the address that triggers the error only this line:
7ffffff74000-7ffffffff000 rw-p 7ffffff73000 00:00 0 [stack]
so the address in the above error is out of bounds.
Now my question: How do I resolve this problem? I can not wrap my head around as to what I could allocate on the heap...
The only think that happens in my main routine is:
// 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();
How could this overflow the stack??
EDIT: I've tried to run it in valgrind, this is the error I get and google didn't give any meaningful info:
valgrind: m_debuginfo/storage.c:417 (vgModuleLocal_addDiCfSI):
Assertion 'cfsi.len < 5000000' failed.
==491== at 0x38029D5C: ??? (in /usr/lib64/valgrind/memcheck-amd64-linux)
EDIT2: Disassembling the function up to the point where it fails (0x0000000001ec0df7) gives me:
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
and the first few lines of the function read:
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 +
// .....
}
(Note that I have changed the signature of the function during experimentation)
Can anyone make the ends meet to what is going on here? Which additional information would you need? Sorry, but I have almost no experience with asm.
EDIT3:
Increasing the stack size with ulimit -s <size>
did the trick. Thank you all for your help!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
看起来函数 xsectiond149 需要大约 13 MB 的堆栈帧(注意指令 sub $0xc96b58,%rsp,并且一旦尝试写入内容就会失败下面有两个说明)。在调用函数之前,您需要确保线程有足够大的堆栈(默认情况下不会)。
您还可以考虑更改代码生成器以在堆而不是堆栈上分配更多内容。
It looks like the function
xsectiond149
needs a stack frame of about 13 MB (note the instructionsub $0xc96b58,%rsp
, and the failure as soon as it tries to write something down there two instructions later). You need to ensure that the thread has a large enough stack (by default it won't) before calling the function.You might also look into changing your code generator to allocate more stuff on the heap instead of the stack.
获取 Valgrind 并在构建后在 Valgrind 下运行您的程序(使用默认工具 memcheck)。这样您就可以更轻松地定位故障源。
您还可以在进入调试器(通常是 GDB)的模式下运行 Valgrind,然后您可以使用所有很酷的 GDB 命令来检查调用者堆栈帧的值等。
不管怎样,如果你陷入困境,Valgrind 应该帮助你找到一些继续的指示。
关于您的编辑,这是我的回复(引用自 Valgrind 源代码,storage.c 的 r11604):
Get Valgrind and run your program under Valgrind (using memcheck, the default tool) once built. This way you will have it much easier to locate the source of the fault.
You can also run Valgrind in a mode where it breaks into the debugger (usually GDB) and you can then use all the cool GDB commands to inspect values at stack frames of callers and so on.
Either way, if you are stuck, Valgrind should help you find some pointers where to continue.
As to your edit, here's my reply (quoting from the Valgrind source code, r11604 of storage.c):