如果独立运行,gdb下Linux上的C代码运行方式会有所不同吗?

如果独立运行,gdb下Linux上的C代码运行方式会有所不同吗?,c,linux,embedded,gdb,C,Linux,Embedded,Gdb,我使用代码魔法工具链在Linux(Fedora)上构建了一个普通的C代码。这是针对手臂皮质-A8目标的。此代码运行在Cortex A8板上,运行嵌入式Linux 当我为某个测试用例运行此代码时,该测试用例为某个较大的大小(10MB)执行动态内存分配(malloc),它在一段时间后崩溃,并给出如下错误消息: select 1 (init), adj 0, size 61, to kill select 1030 (syslogd), adj 0, size 64, to kill select 1

我使用代码魔法工具链在Linux(Fedora)上构建了一个普通的C代码。这是针对手臂皮质-A8目标的。此代码运行在Cortex A8板上,运行嵌入式Linux

当我为某个测试用例运行此代码时,该测试用例为某个较大的大小(10MB)执行动态内存分配(
malloc
),它在一段时间后崩溃,并给出如下错误消息:

select 1 (init), adj 0, size 61, to kill
select 1030 (syslogd), adj 0, size 64, to kill
select 1032 (klogd), adj 0, size 74, to kill
select 1227 (bash), adj 0, size 378, to kill
select 1254 (ppp), adj 0, size 1069, to kill
select 1255 (TheoraDec_Corte), adj 0, size 1159, to kill
send sigkill to 1255 (TheoraDec_Corte), adj 0, size 1159
Program terminated with signal SIGKILL, Killed.
然后,当我使用为目标构建的gdb调试同一测试用例的代码时,这个动态内存分配发生的点,代码无法分配该内存,并且
malloc
返回
NULL
。但在正常的独立运行期间,我认为
malloc
应该无法分配,但奇怪的是,它可能没有返回
NULL
,但它崩溃了,操作系统杀死了我的进程

  • 为什么在gdb下运行和不使用调试器时,这种行为会有所不同
  • 为什么
    malloc
    会失败而不返回
    NULL
    。这是可能的,还是我收到错误消息的原因是其他原因
  • 我该如何解决这个问题
  • 谢谢


    -因此,对于问题的这一部分,有一个肯定的答案:

    为什么malloc失败却不返回NULL。这是可能的,还是我收到错误消息的原因是其他原因? 在Linux中,默认情况下,用于分配内存的内核接口几乎不会完全失败。取而代之的是,它们以这样一种方式设置您的内存:在第一次访问您请求的内存时,CPU将生成一个,此时内核将处理这个问题并查找将用于该(虚拟)页面的物理内存。因此,在内存不足的情况下,您可以向内核请求内存,它将“成功”,当您第一次尝试触摸该内存时,它将返回,此时分配实际上失败,终止您的进程。(或者是其他不幸的受害者。这里有一些启发法,我并不十分熟悉。请参阅“”)

    你的其他一些问题,答案对我来说不太清楚

    为什么在gdb下运行和不使用调试器时,这种行为会有所不同?这可能是(真的只是猜测)gdb有自己的
    malloc
    ,并且以某种方式跟踪您的分配。在某种程度上相关的一点上,我实际上经常发现代码中的堆错误在调试器下是不可复制的。这很令人沮丧,让我抓狂,但基本上这是我认为一个人必须忍受的事情

    我该如何解决这个问题? 这是一个大锤式的解决方案(也就是说,它改变了所有进程的行为,而不仅仅是你自己的进程,让你的程序这样改变全局状态通常不是一个好主意),但是你可以将字符串
    2
    写入
    /proc/sys/vm/overmit\u memory
    。看看我从谷歌搜索得到的


    如果不行。。。我只想确保分配的资源没有超出预期。

    根据定义,在调试器下运行与单独运行不同。调试器可以而且确实隐藏了许多bug。如果您为调试而编译,则可以添加相当数量的代码,类似于完全未优化的编译(例如,允许您单步或监视变量)。在为发布版编译可以删除调试选项并删除所需代码的地方,您可能会陷入许多优化陷阱。从你的帖子中我不知道谁在控制编译选项或者它们是什么

    除非您计划交付要在调试器下运行的产品,否则您应该独立进行测试。理想情况下,在不使用调试器的情况下进行开发,这样您就不必做任何事情两次

    这听起来像是代码中的一个bug,用新的眼睛慢慢地重新阅读代码,就像是在向某人解释代码一样,或者是一行一行地向某人解释代码。可能有一些东西你看不见,因为你已经用同样的方式看了太久。这是令人惊讶的多少次,以及如何很好地工作

    我也可能是一个编译器错误。执行诸如打印或不打印返回值之类的操作可能会导致编译器生成不同的代码。添加另一个变量并将结果保存到该变量可能会促使编译器执行不同的操作。尝试更改编译器选项,减少或删除任何优化选项,减少或删除调试器编译器选项,等等

    这是一个经过验证的系统,还是您正在开发新的硬件?例如,尝试在未启用任何缓存的情况下运行。在调试器中工作,而不是在独立环境中工作,如果不是编译器错误,则可能是一个计时问题,单步执行会刷新管道,以不同方式混合缓存,使缓存和内存系统有一个永恒的时间来产生它不实时的结果

    简言之,在调试器下运行隐藏bug的原因有很多,只有在最终可交付的环境中进行测试才能找到这些bug,我只提到了几个。让它在调试器中而不是在单机版中工作并非意外,这只是工具的工作方式。它很可能是您的代码、硬件或基于您目前给出的描述的工具

    消除代码或工具错误的最快方法是分解该部分,并检查传递的值和返回值是如何处理的。如果返回值被优化了,那就是你的答案


    您是为共享C库编译还是为静态C库编译?也许是静态编译…

    为什么你说你希望你的10MB
    malloc
    无论如何都会失败?您在系统上没有那么多内存?您提到的错误消息是什么?错过了OP中的错误消息,现在进行编辑以添加相同的错误消息。@dwelch:谢谢所有的指针。我已经更新了错误消息。我在OP里搞砸了,如果这有助于缩小未来