追踪Haskell段错误

Mat*_*hid 6 haskell

太令人生气了!> _ <

我写了一个庞大而复杂的Haskell库.我写了一个小测试程序,到目前为止,我花了大约8个小时试图弄清楚为什么它一直在崩溃我.有时GHC抱怨"奇怪的封闭类型".有时我只是得到一个段错误.显然问题是内存损坏.

该库本身是100%纯Haskell.但是,测试程序使用了与阵列相关的几个不安全的GHC原语.这显然是导致问题的原因.实际上,如果我注释掉该writeArray#行,该程序就会停止崩溃.但这对我的面条来说是完全油炸的...尽管我能说清楚,但我所使用的所有阵列边界都是完全有效的.程序将它们全部打印出来,它们都是正数且小于数组大小.

我编写了第二个程序,它与第一个程序完全相同,但没有涉及庞大,复杂的库.我尝试过并试过,但我根本无法让它崩溃.我所做的一切似乎都没有让它崩溃,但它与实际数组几乎完全相同.

有没有人有任何进一步的故障排除技巧?有什么方法可以追踪内存损坏的确切时刻吗?(而不仅仅是系统注意到腐败的那一刻.)


更新:

问题是什么?

嗯,基本上,它创建了一个表示像素缓冲区的数组.它产生一个迭代每个像素的线程,并将相应的值写入其中.它产生了第二个读取数组的线程,并使用相当复杂的协议将像素写入网络套接字.(因此我正在尝试测试的大型库.)

如果我不生成编写器线程,崩溃就会消失.如果我writeArray'在编写器线程中注释掉调用,那么崩溃就会消失.在写入每个像素之前,写入器线程打印出像素坐标数组索引.它打印出来的一切看起来都很完美.然而......它不会停止崩溃.

我几乎想知道GHC的数组原语是不是线程安全的还是其他东西.(如果它有任何区别,读取器线程看起来像数组的副本已被不安全冻结,而编写器线程继续同时改变它.)

但是,我编写了一个完全相同的程序,但没有通过网络发送流量.程序在每个细节上都能完美运行.只有真正复杂的程序才行不通.这有多烦人?!

这有效:http://hpaste.org/70987

这不是:http://hpaste.org/70988

dav*_*420 6

您已经记录了对不安全原语的使用.

您是否编写了一个程序来查看这些日志中是否存在违反不变量的行为?


Don*_*art 6

使用安全,经过检查的版本替换已知的不安全功能.检查日志以查找将导致的异常,并修复代码.


Bor*_*ris 6

也许测试程序和带有库的程序之间的区别在于后者有更多的分配,因此更频繁地调用GC.

读者线程看起来像数组的副本已被不安全冻结,而编写器线程继续同时改变它.

可能GC无法跟踪冻结后仍然引用可变数组.在这种情况下,GC可能会移动冻结的数组,但writeArray#使用旧指针执行写入.


Mat*_*hid 5

可能是固定的:

我更改了一些内容,并且代码不再崩溃。那可能只是a幸,或者我可能“确实”解决了这个问题。很难说。

假设:

问题似乎是从并发线程中读取同一数组的可变且不可变的副本。(即使简化测试确实做到了这一点,也不会崩溃。)

我从一个不相关的不可变数组中读取了网络线程,并且崩溃停止了。我什至添加了一个循环,将数据从一个可变数组复制到另一个新的可变数组,然后冻结并检查了新的数组。这似乎完美地工作。

因此看来,这只是GHC处理对同一阵列的两个版本的并发访问的一个小故障。

(或者,这是a幸。有几次我在程序中更改了某些内容,它停止崩溃了,然后又开始崩溃了……)

更新:这似乎是完全固定的。自从进行此更改以来,我再也没有崩溃过。感谢所有在这里帮助过我的人。:-)