如何调试异常的C内存/堆栈问题

如何调试异常的C内存/堆栈问题,c,memory,stack,alloc,C,Memory,Stack,Alloc,很抱歉,我无法具体说明代码,但我看到的问题是异常的。字符串值似乎正在根据其他不相关的代码进行更改。例如,下面传递的参数值将仅根据我是否注释掉一个或两个fprintf()调用而改变!到最后一个fprintf()时,该值通常完全为空(不,我已检查以确保我没有直接修改参数……我所要做的就是注释掉一个fprintf()或添加另一个fprintf(),字符串的值将在某些点发生更改!): 到处都是代码,所以我不能要求别人调试我的程序——我想知道的是,我如何调试为什么像这样的字符串会因为不相关的代码而改变或覆

很抱歉,我无法具体说明代码,但我看到的问题是异常的。字符串值似乎正在根据其他不相关的代码进行更改。例如,下面传递的参数值将仅根据我是否注释掉一个或两个fprintf()调用而改变!到最后一个fprintf()时,该值通常完全为空(不,我已检查以确保我没有直接修改参数……我所要做的就是注释掉一个fprintf()或添加另一个fprintf(),字符串的值将在某些点发生更改!):

到处都是代码,所以我不能要求别人调试我的程序——我想知道的是,我如何调试为什么像这样的字符串会因为不相关的代码而改变或覆盖它们的内存。我的记忆力有限吗?我的书堆太小了?我怎么说?我还能做些什么来追踪这个问题?我的程序并不庞大,它就像上千行的代码和几个动态链接的外部lib,但没有什么与众不同的

救命啊!蒂亚

简单:

  • 学习使用,特别是
  • 学习使用包括断点和变量检查
  • 熟能生巧

  • 这应该可以解决问题。确保使用GCC上的
    -g
    选项编译任何库,该选项保留调试符号,以便调试输出更有意义。

    如果您正在编写用户级应用程序,Valgrind是检测内存问题(如内存泄漏、缓冲区溢出、,等等。这里有一个快速入门指南:

    您没有提供开发工具,但是如果您像90%的程序员一样,您已经在使用带有调试器的IDE来处理此问题,则不需要新的工具。在保存字符串的内存块上设置一个手表,然后逐步检查代码,查看字符串何时更改。

    有两种情况需要考虑:

  • arg
    变量在
    进程的开始和结束之间更改值
  • arg
    保持不变,但它指向的字符串已更改
  • 您的描述和代码并不区分这两种情况,但重要的是要知道这两种情况中的哪一种是实际发生的

    这将揭示答案:

    fprintf(stderr, "Function arg is %s (%p)\n", arg, (void *)arg);
    ... do bunch of stuff ...
    fprintf(stderr, "Function arg is now %s (%p)\n", arg, (void *)arg);
    
    大多数情况下,
    arg
    没有变化(即您有案例2)。如果是这样,则说明您分配的字符串已被损坏。Valgrind已经提出,但仅在Linux、AIX和MacOSX上可用,发现问题的几率只有50:50。您真正想要的是一个GDB监视点:在
    进程的开始处设置断点。\u args
    ,一旦命中,执行
    (GDB)监视*(long*)arg
    继续。当有东西写入
    *arg
    时,GDB将停止(它实际上会在下一条指令时停止)。然后使用
    (gdb)where
    命令找出发生了什么

    如果您确实让
    arg
    更改了它的值(情况1),那么调试可能会更困难,并表明堆栈出现某种形式的损坏,或者违反了平台的过程调用约定。Valgrind可能根本帮不上忙。这与您描述的行为更加一致:注释掉不相关的代码会导致错误转移


    不过,我不能就调试案例1给出任何进一步的建议,因为您还没有透露您的实际平台是什么。

    Wow!快速回答!valgrind的第一次尝试告诉我运行我的程序的“权限被拒绝”,所以我必须弄清楚。但是如果我遇到了内存问题,那么确保我的程序有足够内存的第一步是什么呢?除非你有非常非常小的内存,否则你没事。运行memcheck并检查输出。你将拥有比你想象的更多的东西,他们需要时间去了解他们的意思。。。它们常常看起来神秘莫测好吧,这就是我所希望的,但我被难住了。Valgrind告诉我我泄漏了90个字节,看起来不多,没有其他大错误,但如果是正确的90个字节,也许这就是问题所在。不管怎样,我想我必须做一些挖掘和学习。谢谢,再次谢谢。这似乎是一个范围问题。valgrind通过告诉我“条件跳转或移动取决于未初始化的值”来提醒我,所以这就是问题所在。字符串在函数中被定义为字符数组(alachar[100]),我认为它超出了范围。将其声明更改为使用malloc()就成功了。奖金现在是valgrind已验证我没有错误。:-)那总是甜蜜的。“未发现泄漏”。祝你好运!没有,没有IDE。看来valgrind是首选工具,所以我必须做一些学习。谢谢,这似乎是我下一步需要去的地方,检查指针地址,很好的建议。我这样做了,并验证了指针仍然是静态的。那么,数据/内存实际上就是正在变化的东西。我的平台是FC5,我想它是(是的,旧的,但它是离线的,仅测试)。嗯,你认为瓦尔格兰不会有帮助吗?嗯,我想我必须继续努力。谢谢你的建议!是的-GDB观察点可能是这项工作的最佳工具(Valgrind只能在你不应该写的内存中提供帮助,而不是在不应该写的内存中提供帮助)。要查找“案例1”问题,您只需在
    arg
    本身(
    watch arg
    )上设置一个watch。watch arg是无用的,因为arg从不更改。你真正想要的是“watch*arg”,除了它只会检测到字符串第一个字符的变化。使用俄语,谢谢。我希望我能选择两个答案,因为你的建议很好,非常感谢。问题在于,最初填充字符串的函数将其声明为字符数组:char string[100];我认为这超出了范围。更改为此已修复:char*string=malloc(
    fprintf(stderr, "Function arg is %s (%p)\n", arg, (void *)arg);
    ... do bunch of stuff ...
    fprintf(stderr, "Function arg is now %s (%p)\n", arg, (void *)arg);