代码之家  ›  专栏  ›  技术社区  ›  goldenmean

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

  •  3
  • goldenmean  · 技术社区  · 15 年前

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

    当我为一些测试用例运行此代码时,它执行动态内存分配( malloc )对于某些大尺寸(10MB),它会在一段时间后崩溃,并给出以下错误消息:

    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为同一个测试用例调试此代码时,在动态内存分配发生的地方,代码无法分配该内存,并且 马洛克 收益率 NULL . 但在正常的独立运行中,我相信 马洛克 应该是分配失败,但奇怪的是它可能不会返回 无效的 但是它崩溃了操作系统扼杀了我的进程。

    1. 在gdb下运行和不使用调试器时,为什么这种行为不同?
    2. 为什么会 马尔洛克 失败但未返回 无效的 . 这是可能的,还是我收到错误消息的原因是其他原因?
    3. 我该怎么解决这个问题?

    谢谢,

    -广告

    2 回复  |  直到 15 年前
        1
  •  6
  •   asveikau    15 年前

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

    为什么malloc会失败而不返回空值。这是可能的,还是我收到错误消息的原因是其他原因?

    在Linux中,默认情况下,用于分配内存的内核接口几乎从不彻底失败。相反,他们设置了 page table 在您请求的第一次访问内存时,CPU将生成一个 page fault ,此时内核将处理此问题并查找将用于该(虚拟)页的物理内存。因此,在内存不足的情况下,您可以向内核请求内存,它将“成功”,当您第一次尝试触摸该内存时,它将返回, 当分配实际失败时,会终止进程。(或者可能是其他不幸的受害者)。有一些启发性的方法,我不太熟悉。见“ oom-killer “。”

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

    在gdb下运行和不使用调试器时,为什么这种行为不同?
    可能(只是一个猜测)gdb有自己的 malloc ,并以某种方式跟踪您的分配。在某种程度上,我经常发现我的代码中的堆错误在调试程序下通常是不可复制的。这很令人沮丧,让我抓伤了头,但这基本上是我认为一个人必须忍受的…
    我该怎么解决这个问题?

    这是一个大锤解决方案(即,它改变 全部的 进程而不仅仅是您自己的进程,通常让您的程序这样改变全局状态不是一个好主意,但是您可以编写字符串 2 /proc/sys/vm/overcommit_memory . 见 this link 我从谷歌搜索中得到的。

    失败了…我只是确保你分配的不会超出你的预期。

        2
  •  2
  •   old_timer    15 年前

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

    除非您计划交付要在调试器下运行的产品,否则应该单独进行测试。理想情况下,在不使用调试器的情况下进行开发,这样可以避免您不得不重复执行任何操作。

    这听起来像是你的代码中的一个错误,慢慢地用新的眼睛重新阅读你的代码,就好像你是在向某人解释它,或者实际上是一行一行地向某人解释它。可能有一些你看不见的东西,因为你已经用同样的方式看了太久了。令人惊讶的是,它的工作次数和效果如何。

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

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

    简言之,有一个非常长的原因列表,列出了为什么在调试程序下运行会隐藏一些bug,直到您在最终的类似可交付结果的环境中进行测试,才能找到这些bug,我只提到了一些。让它在调试程序中工作而不是独立运行并不是意外的,这只是工具的工作方式。很可能是您的代码、硬件或您的工具基于您迄今为止给出的描述。

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

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