他们如何在受保护的内存之前调试分段错误?


20

现在,当我用C中的指针犯了一个编程错误时,我遇到了一个很好的分段错误,程序崩溃了,调试器甚至可以告诉我哪里出错了。

在没有内存保护的情况下,他们是如何做到的?我可以看到一个DOS程序员在弄错时摆弄着他,并使整个操作系统崩溃。虚拟化不可用,因此他所能做的就是重新启动并重试。真的那样吗?


4
是的,就是这样。随机计算机重新启动发生了,并且经常发生。内存保护是一件了不起的事情:)
Rocklan

7
当您没有受保护的内存时,就不会出现分段错误。当然,即使您确实拥有受保护的内存,也仍然可以破坏自己的空间;操作系统只是不关心它。
Blrfl 2013年

3
即使是现在,许多指针错误也不会导致良好的段错误。
CodesInChaos

1
在使用DOS时,其他操作系统中已经存在受保护的内存。
mouviciel 2013年

Answers:


36

我可以看到一个DOS程序员在弄错时摆弄着他,并使整个操作系统崩溃。

是的,那几乎就是发生了什么。在大多数具有内存映射的系统上,位置0被标记为无效,因此可以很容易地检测到空指针,因为这是最常见的情况。但是还有很多其他情况,它们造成了严重破坏。

冒着听起来像个盖茨的危险,我应该指出,当前对调试的关注不是过去。以前需要付出更多的努力来编写正确的程序,而不是消除错误程序中的错误。其中一些是因为这是我们的目标,但很多是因为这些工具使工作变得困难。尝试在纸上或打孔卡上编写程序,而不是在IDE中,并且没有交互式调试器的好处。它给您带来正确感。


3
实际上,我希望“老顽童”能回答我的问题。第一手经验无所不能。谢谢。
巴特·弗里德里希斯

6
当硬件每天晚上02:00至06:00可用于调试时,请尝试编写代码,当然前提是您的同事没有为调试会话保留它。
MSalters 2013年

@MSalters的确!在我的第一份工作中,我们还可以在周日0700至1900年预订老虎机-真正的享受,lemme告诉您:-)
Ross Patterson

2
我记得我写了第一个程序写的是从大学回家的纸上。第二天,当我可以打孔并运行它时,它是完美无缺的;-)
Jan Doggen

1
@JanDoggen,对我也一样。当您只有一次尝试时,您就可以真正进行尝试。
2013年

23

早在我的时代,我们就没有内存保护功能,也没有那么出色的业务!我们使用printf来确定我们在程序中的位置,并且我们喜欢它

尽管非常认真,但这通常意味着我们要更加小心。在调用malloc的地方,程序中的其他地方必须有空闲空间,并且这种检查非常严格,因为正如您已经清楚指出的那样,在出现问题的情况下,分段错误不是有用的错误。

对于此类错误,您最好的办法是尝试了解何时发生此类分段错误(使用printf),然后查看代码,确定为何此时对内存的访问无效并从那里进行反向操作。

从本质上讲,今天发生了同样的事情,除了我们使用调试器确定何时发生错误外,但您仍然必须了解发生错误的原因,而且这并不总是比发现错误发生的行那么简单。错误会导致诸如连锁反应之类的错误,如果您那时是C程序员,那么您将花费20%的时间进行编码,而其余时间则花费大量时间来修复错误。


2
释放Malloc!
克里斯,

1
有时甚至在今天,即使是调用堆栈和变量状态也完全无法确定到底出了什么问题以及如何解决。如果您的复杂软件具有大量可能的状态,其中某些状态相互依赖,而某些状态相互排斥,则尤其如此。在任何地方进行一次杂散写操作并为保证的前提条件省略断言,即可带您到那里。
CVn 2013年

1
@MichaelKjörling,我认为对于发现程序错误的问题,我们仅在发现错误触发器的问题方面取得了进展,但是在发现这些错误的原因方面,我们还有很长的路要走。断言肯定可以使我保持理智。:)
Neil

6

好 ..

分段故障确实是一个很好的指示,表明出了点问题,但您仍然必须找到根本原因。因此,如果您问的问题是如何找到根本原因,那么答案与今天相比并没有太大不同。当然,语言和工具变得更易于使用,但是一般的taktik是相同的:

  • 日志记录有助于查找问题所在的区域。二进制搜索printf是它的一种形式。
  • 调试,逐步,断点和监视
  • 重构以获得更好的理解
  • 盯着代码
  • 看一下内存/核心转储
  • 提供不同的数据
  • 向其他人展示
  • 切换到没有指针的语言(以及一系列新问题)...

在更抽象的级别上,您可以使用三种方法:1.使用代码2.在程序运行时查看程序3.在执行愚蠢的操作后查看结果

顺便说一句,指针错误不必创建段错误。

作为Amiga程序员,我几乎全部使用了它。是的,在常见实践中会重新开始。


4

在运行Fortran批处理作业的IBM 360上,我们过去常常获得十六进制核心转储。这样的转储可能多达一英寸厚的扇形折叠绿色和白色打印机纸。它会告诉您寄存器是什么,然后我们可以回溯并弄清楚程序在做什么。我们可以找到每个子例程并弄清楚它的返回地址存储在哪里,因此我们可以看到上下文。拥有该程序的汇编程序列表将很有帮助。


2

有一次,我在当时著名的Windows 3.1 Presentation软件上进行错误修复。

我有一个错误,当它发生时,导致了死亡蓝屏。

该错误仅在某个循环已执行1000次以上时发生。我使用调试器的高级功能使断点通过1000次,然后我仔细地逐步执行了该程序。每次我走得太远或跳过包含Windows Blue Screened错误的函数调用时。

最终,经过几天的工作,我将其范围缩小到内存不足的功能,并且不显示错误消息,而是将错误消息附加到缓冲区。在随后的每次迭代中,它浪费了更多的内存,直到关键内容被覆盖并且Windows被浪费为止。

调试技巧和毅力是解决方案。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.