草庐IT

c++ - 输入函数时的 SIGSEGV

coder 2023-06-17 原文

刚进入函数时什么会导致段错误?

输入的函数如下所示:

21:  void eesu3(Matrix & iQ)
22:  {

其中 Matrix 是一个 struct。当使用 GDB 运行时,回溯产生:

(gdb) backtrace 
#0  eesu3 (iQ=...) at /home/.../eesu3.cc:22
#1  ...

GDB 没有说明什么是iQ... 确实存在。 什么会导致这个?

海湾合作委员会:(Ubuntu/Linaro 4.6.3-1ubuntu5)4.6.3

使用-O3 -g构建的程序

来电者是这样的:

Matrix q;
// do some stuff with q
eesu3(q);

这里没什么特别的

我用 valgrind 重新运行程序:

valgrind --tool=memcheck --leak-check=yes --show-reachable=yes --num-callers=20 --track-fds=yes <prgname>

输出:

==2240== Warning: client switching stacks?  SP change: 0x7fef7ef68 --> 0x7fe5e3000
==2240==          to suppress, use: --max-stackframe=10076008 or greater
==2240== Invalid write of size 8
==2240==    at 0x14C765B: eesu3( Matrix &) (eesu3.cc:22)
...
==2240==  Address 0x7fe5e3fd8 is on thread 1's stack
==2240== 
==2240== Can't extend stack to 0x7fe5e2420 during signal delivery for thread 1:
==2240==   no stack segment
==2240== 
==2240== Process terminating with default action of signal 11 (SIGSEGV)
==2240==  Access not within mapped region at address 0x7FE5E2420
==2240==    at 0x14C765B: eesu3( Matrix&) (eesu3.cc:22)
==2240==  If you believe this happened as a result of a stack
==2240==  overflow in your program's main thread (unlikely but
==2240==  possible), you can try to increase the size of the
==2240==  main thread stack using the --main-stacksize= flag.
==2240==  The main thread stack size used in this run was 8388608.

看起来它是一个损坏的堆栈。

    Dump of assembler code for function eesu3( Matrix & ):
   0x00000000014c7640 <+0>: push   %rbp
   0x00000000014c7641 <+1>: mov    %rsp,%rbp
   0x00000000014c7644 <+4>: push   %r15
   0x00000000014c7646 <+6>: push   %r14
   0x00000000014c7648 <+8>: push   %r13
   0x00000000014c764a <+10>:    push   %r12
   0x00000000014c764c <+12>:    push   %rbx
   0x00000000014c764d <+13>:    and    $0xfffffffffffff000,%rsp
   0x00000000014c7654 <+20>:    sub    $0x99b000,%rsp
=> 0x00000000014c765b <+27>:    mov    %rdi,0xfd8(%rsp)

好吧,说清楚一点:Matrix 的数据存在于堆中。它基本上包含一个指向数据的指针。该结构很小,只有 32 个字节。 (刚刚检查过)

现在,我用不同的优化选项重建了程序:

-O0:错误不显示。

-O1:确实显示错误。

-O3:确实显示错误。

--更新

-O3 -fno-inline -fno-inline-functions: 错误不显示。

这就解释了。函数内联过多导致堆栈使用过多。

问题是由于堆栈溢出

最佳答案

What can cause a segmentation fault when just entering a function?

最常见的原因是堆栈耗尽。做(gdb) disas在崩溃点。如果崩溃的指令是在 %rsp 之后第一次读取或写入堆栈位置已经递减,那么堆栈耗尽几乎肯定是原因。

解决方案通常涉及创建具有更大堆栈的线程,将一些大变量从堆栈移动到堆,或两者兼而有之。

另一个可能的原因:如果Matrix包含非常大的数组,您不能将它放在堆栈上:内核不会将堆栈扩展到当前堆栈之外超过 128K(大约,我不记得确切的值)。如果Matrix大于这个限制,你不能把它放在堆栈上。

更新:

   0x00000000014c7654 <+20>:    sub    $0x99b000,%rsp
=> 0x00000000014c765b <+27>:    mov    %rdi,0xfd8(%rsp)

这个反汇编证实了诊断。

此外,您在堆栈上保留了 0x99b000 字节(几乎是 10MB)。在 eesu3 中一定有一些您试图在堆栈上定位的巨大对象常规。不要那样做。

What do you mean by "the kernel will not extend stack beyond current by more than"

当您扩展堆栈(递减 %rsp )时,例如1MB,然后尝试触摸该堆栈位置,内存将不可访问(内核按需增长堆栈)。这将生成一个硬件陷阱,并将控制权转移到内核。当内核决定做什么时,它会查看

  1. 当前 %rsp
  2. 应用程序试图访问的内存位置
  3. 当前线程的堆栈限制

如果故障地址低于当前 %rsp ,但在 128K(或其他类似大小的常量)内,内核只是扩展堆栈(前提是这种扩展不会超过堆栈限制)。

如果故障地址比当前地址低 128K 以上 %rsp (就像这里的情况一样),你得到 SIGSEGV .

这对大多数程序来说都很好:即使它们在递归过程中使用大量堆栈,它们通常也会以小块的形式扩展堆栈。但是试图在单个例程中保留所有堆栈的等效程序会崩溃。

无论如何,做(gdb) info locals在崩溃点,看看本地人可能需要 10MB 的堆栈。然后将它们移动到堆中。

更新 2:

No locals

啊,程序可能还没有进入 eesu3因为有本地人。

when building with -O0 the error disappears. GCC bug?

这可能是 GCC 错误,但更有可能是 GCC 将许多其他例程内联到 eesu3 中。 ,并且每个内联例程都需要自己的 N KB 堆栈。如果构建包含 eesu3 的源代码,问题是否会消失?与 -fno-inline

不幸的是,对此类行为进行分类并找出适当的解决方法或修复 GCC,需要编译器专业知识。您可以先使用 -fdump-tree-all 进行编译并查看生成的 <source>.*t.*文件。这些包含编译过程各个阶段的 GCC 内部表示的文本转储。您可能能够充分理解它以取得进一步的进步。

关于c++ - 输入函数时的 SIGSEGV,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10499400/

有关c++ - 输入函数时的 SIGSEGV的更多相关文章

  1. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  2. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

    我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

  3. ruby-on-rails - 在 ruby​​ 中使用 gsub 函数替换单词 - 2

    我正在尝试用ruby​​中的gsub函数替换字符串中的某些单词,但有时效果很好,在某些情况下会出现此错误?这种格式有什么问题吗NoMethodError(undefinedmethod`gsub!'fornil:NilClass):模型.rbclassTest"replacethisID1",WAY=>"replacethisID2andID3",DELTA=>"replacethisID4"}end另一个模型.rbclassCheck 最佳答案 啊,我找到了!gsub!是一个非常奇怪的方法。首先,它替换了字符串,所以它实际上修改了

  4. ruby - 在 Ruby 中有条件地定义函数 - 2

    我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin

  5. ruby - 在 Ruby 中按名称传递函数 - 2

    如何在Ruby中按名称传递函数?(我使用Ruby才几个小时,所以我还在想办法。)nums=[1,2,3,4]#Thisworks,butismoreverbosethanI'dlikenums.eachdo|i|putsiend#InJS,Icouldjustdosomethinglike:#nums.forEach(console.log)#InF#,itwouldbesomethinglike:#List.iternums(printf"%A")#InRuby,IwishIcoulddosomethinglike:nums.eachputs在Ruby中能不能做到类似的简洁?我可以只

  6. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  7. C51单片机——实现用独立按键控制LED亮灭(调用函数篇) - 2

    说在前面这部分我本来是合为一篇来写的,因为目的是一样的,都是通过独立按键来控制LED闪灭本质上是起到开关的作用,即调用函数和中断函数。但是写一篇太累了,我还是决定分为两篇写,这篇是调用函数篇。在本篇中你主要看到这些东西!!!1.调用函数的方法(主要讲语法和格式)2.独立按键如何控制LED亮灭3.程序中的一些细节(软件消抖等)1.调用函数的方法思路还是比较清晰地,就是通过按下按键来控制LED闪灭,即每按下一次,LED取反一次。重要的是,把按键与LED联系在一起。我打算用K1来作为开关,看了一下开发板原理图,K1连接的是单片机的P31口,当按下K1时,P31是与GND相连的,也就是说,当我按下去时

  8. ruby-on-rails - 如何从过时的 TZInfo 标识符中获取 Rails TimeZone 名称? - 2

    已经有一个问题回答了如何将“America/Los_Angeles”转换为“PacificTime(US&Canada)”。但是我想将“美国/太平洋”和其他过时的时区转换为RailsTimeZone。我无法在图书馆中找到任何可以帮助我完成此任务的东西。 最佳答案 来自RailsActiveSupport::TimeZonedocs:TheversionofTZInfobundledwithActiveSupportonlyincludesthedefinitionsnecessarytosupportthezonesdefinedb

  9. ruby-on-rails - 将字符串转换为 ruby​​-on-rails 中的函数 - 2

    我需要一个通过输入字符串进行计算的方法,像这样function="(a/b)*100"a=25b=50function.something>>50有什么方法吗? 最佳答案 您可以使用instance_eval:function="(a/b)*100"a=25.0b=50instance_evalfunction#=>50.0请注意,使用eval本质上是不安全的,尤其是当您使用外部输入时,因为它可能包含注入(inject)的恶意代码。另请注意,a设置为25.0而不是25,因为如果它是整数a/b将导致0(整数)。

  10. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

随机推荐