G-WAN是一种开箱即用在web上运行C代码的方便方法,但对我来说,它不适用于valgrind。(运行valgrind ./gwan
时出现错误消息Inconsistency detected by ld.so: rtld.c: 1292: dl_main: Assertion `_rtld_local._dl_rtld_map.l_libname' failed!
,然后退出;系统为Debian Jessie 64位)。
问题是:
1) G-WAN应该和valgrind一起工作吗
2) 有没有其他可行的选择来检测在G-WAN下运行的C代码中的内存错误?
G-WAN应该和valgrind一起工作吗?
我们已经测试了Valgrind,虽然它做了很多正确的事情,但它不适合高并发作业(即使是低并发也是Valgrind的一个问题)。
在G-WAN下运行的C代码中检测内存错误的可行选项?
使用malloc()
包装器、预先分配的池,或者更好的是,首先使用alloca()
来避免内存问题。
请注意,G-WAN在处理C脚本中的坏指针时不会使服务器崩溃,请参阅:http://gwan.ch/developers#crash
这个错误代码:
int main(int argc, char *argv[])
{
strcpy(0xBADC0DE, 0xBADC0DE);
return 200;
}
将生成类似以下"优雅"的崩溃报告:
Script: crash_libc.c
Client: 127.0.0.1
Query : ?crash_libc
Signal : 11:Address not mapped to object
Signal src : 1:SEGV_MAPERR
errno : 0
Thread : 0
Code Pointer: 0000f5200b33 (module:/lib/libc.so.6, function:strcpy, line:0)
Access Address: 00000badc0de
Registers : EAX=00000badc0de CS=00000033 EIP=0000f5200b33 EFLGS=000000010202
EBX=000000000001 SS=ec2d8ed4 ESP=0000f5ded828 EBP=0000f5dee020
ECX=000033323130 DS=ec2d8ed4 ESI=0000ec2d8f86 FS=00000033
EDX=000003b03c00 ES=ec2d8ed4 EDI=00000badc0de CS=00000033
Module :Function :Line # PgrmCntr(EIP) RetAddress FramePtr(EBP)
libc.so.6: strcpy: - 0000f5200b33 0000ec2d8f00 0000f5dee020
servlet: main: 37 0000ec2d8f00 00000042e10c 0000f5dee020
G-WAN甚至会告诉您源代码中的错误发生在哪里(请参阅G-WAN crash_xxx.c示例),而不是杀死服务器进程。
如果你不想调试C代码,那么就使用Java或Scala(两者都受G-WAN支持)——你将需要更多的内存,因为你的数据将保持加载状态,直到GC放慢所有速度来释放它认为可以释放的东西——但至少你会享受更少的内存相关错误(如果有的话)。
根据提问者的要求,以下是更多详细信息。
在2012年末,我们测试了十几个免费的商业工具,比如Valgrind,它们应该有助于调试并发性。我们还使用了研究源代码的静态工具,而不仅仅是运行(编译)程序的动态工具。
可悲的事实是,他们都有共同的问题,他们:
- 通常速度太慢,无法支持并发(核心问题)
- 产生大量琐碎的警报(甚至更多的虚假警报)
- 非常昂贵(当然是商业版的),在购买之前不能总是进行测试(!)
因此,经过数周的检查和筛选,我们花了大量时间"更正"G-WAN代码库,以删除琐碎和错误的警报(由无法区分有效代码和错误代码的工具引起的警报)。。。但是,令我们当时感到沮丧的是,我们还没有在G-WAN中发现任何真正的错误(明确表示那几周是浪费时间)。
因此,上面的结论是:尽可能制作简单的代码,并在需要更复杂的策略时尝试预分配块。
当然,Linux LIBC坚持用(不可捕获的)abort
信号杀死应用程序这一事实并没有帮助(这阻止了程序恢复或转储相关跟踪),尤其是对于草率的双自由Linux LIBC检测(当程序使用malloc()一次时,错误地假设所有代码都在使用其malloc)——这通常是通过LIBC调用完成的!)。我甚至不是在谈论mmap()失败,也不是在谈论OOM终止开关。
到目前为止,我们发现唯一有效的解决方案是避免使用Linux LIBC,并使用我们自己的C运行时编译我们需要的一切。这有点难以推荐,因为"该做的事"适用于所有用户,但它对我们有效。
我们很高兴看到我们的部分代码(或者至少是G-WAN中实现的一些概念)被Linux使用,因为这将使我们的生活(以及许多其他开发人员的生活)变得非常轻松,但我们过去与"负责人"的联系并不令人鼓舞。
总而言之,操作系统、像我们这样的ISV和开发人员都有改进的空间——毕竟,自2004年以来,并发是"唯一"的主流……大约十年前。