libCurl中的Segfault正在进程中分叉在信号处理程序中

时间:2013-11-07 09:42:02

标签: segmentation-fault arm signals fork libcurl

我正试图让Android上的本机崩溃报告工作。我使用breakpad创建转储文件,并使用curl上传它(以与breakpad一起提供的minidump_upload工具非常类似的方式)。

为了测试我试图写入一个解除引用的NULL指针来激发段错误。

在我的转储回调函数中,在成功创建minidump之后从breakpad的信号处理程序调用,我fork()并运行我的上传代码。

设置libCurl工作正常,但随后在curl_easy_perform内部崩溃并发生以下回溯(为了便于阅读而删除了文件名,删除了10以上的帧)。

Program received signal SIGSEGV, Segmentation fault.
0x7356d700 in dprintf_formatf (data=0x7393ba34, stream=0x65, format=0x739458a4 "l>\016", ap_save=...) at .../lib/mprintf.c:518
518 {
(gdb) bt
#0  0x7356d700 in dprintf_formatf (data=0x7393ba34, stream=0x65, format=0x739458a4 "l>\016", ap_save=...) at .../lib/mprintf.c:518
#1  0x7356e5fe in curl_mvsnprintf (buffer=0x73860540 "\b\025\206sa", maxlength=4096, format=0x737a1528 "%s; boundary=%s\r\n", ap_save=...) at .../lib/mprintf.c:932
#2  0x7355d092 in AddFormDataf (formp=0x73861780, size=0x0, fmt=0x737a1528 "%s; boundary=%s\r\n") at .../lib/formdata.c:918
#3  0x7355d606 in Curl_getformdata (data=0x75527970, finalform=0x75511ec0, post=0x75482af0, custom_content_type=0x0, sizep=0x75511ec8) at .../lib/formdata.c:1172
#4  0x73561dfc in Curl_http (conn=0x755300a0, done=0x73861928) at .../lib/http.c:1969
#5  0x7356badc in Curl_do (connp=0x75527978, done=0x73861928) at .../lib/url.c:5897
#6  0x735771f0 in multi_runsingle (multi=0x7551dfa0, now=..., data=0x75527970) at .../lib/multi.c:1218
#7  0x73577aac in curl_multi_perform (multi_handle=0x7551dfa0, running_handles=0x738619cc) at .../lib/multi.c:1714
#8  0x73571fa4 in easy_transfer (multi=0x7551dfa0) at .../lib/easy.c:759
#9  0x7357209a in easy_perform (data=0x75527970, events=false) at .../lib/easy.c:838
#10 0x735720c4 in curl_easy_perform (easy=0x75527970) at .../lib/easy.c:857

让我们分析一下我们在这里得到的东西,它在第3帧开始变得有趣。 这里使用

调用AddFormDataf
  • 指向表单的NULL指针的指针(预期,表单仍为空)
  • NULL指示大小指针
  • 有效的格式字符串“%s; boundary =%s \ r \ n”
  • 和两个字符串参数进入可变元部分:“Content-Type:multipart / form-data”和“------------------------ a7584d0e40b10c4a “

在第2帧中,一切都很好,构造了va_list(它应该指向两个字符串中的第一个,但我不知道如何在gdb中调试它),并且控制权被移交给vsnprintf, curl内部定义为curl_mvsnprintf。

在第1帧中,所有参数仍然看起来很好,4k缓冲区中有随机数据,但是应该没问题,它会被覆盖,最大长度4096是正确的,格式字符串仍然是我们的格式。创建了nsprintf结构,并将控制权移交给dprintf_formatf - 让我们打印传递给dprintf_formatf的所有参数:

(gdb) print info
$6 = {buffer = 0x73860540 "\b\025\206sa", length = 0, max = 4096}
(gdb) print &info
$7 = (struct nsprintf *) 0x73860510
(gdb) print addbyter
$8 = {int (int, FILE *)} 0x7356e580 <addbyter>
(gdb) print format
$9 = 0x737a1528 "%s; boundary=%s\r\n"
(gdb) print ap_save
$10 = {__ap = 0x73861554}

正如你所看到的,info结构是正确填充的,没有什么可说的关于addbyter函数的函数指针和va_args ap_save,但至少格式字符串仍然可以。

现在,当我们看到第0帧时,一切都被破坏了:

#0  0x7356d700 in dprintf_formatf (data=0x7393ba34, stream=0x65, format=0x739458a4 "l>\016", ap_save=...) at .../curl/./lib/mprintf.c:518
(gdb) print ap_save
$11 = {__ap = 0x739fae60}

信息指针从0x73860510变为0x7393ba34,函数指针从0x7356e580变为0x65,格式字符串从0x737a1528变为0x739458a4,v__list内的__ap从0x73861554变为0x739fae60。

这些(无效的)指针似乎在程序的每次运行中都保持不变 - 每当我运行时,我获得完全相同的数据,流和格式地址,甚至相同的格式内容(“l&gt; \ 016”)该计划。

我有几个问题:

  • 当我fork()时,父进程的内存被复制到新的子进程,但是fork之后父进程无法修改客户端的内存,对吧?我问,因为我的父进程是多线程的(是的,我知道,多线程和分叉,不是一个好主意,但我只是在我崩溃的时候才这样做...)
  • 怎么会发生函数的所有参数丢失并被无效的东西取代?我认为这里唯一的答案就是腐败了堆栈,对吗?
  • 什么可能会破坏我在子进程中的堆栈(这应该是一个完全健康的进程,只是拥有来自父进程的大量潜在损坏的内存)?
  • 我在编译libCurl时可能做错了吗? (在这种情况下,当在信号处理程序中创建子进程时,从任何地方(包括分叉的子进程)之外的整个上传工作正常)
  • 指向哪些无效指针,为什么我总是在格式中看到相同的字符串?我假设我在这里看到程序代码?

在此先感谢您的帮助,我真的没有想法如何解决这个问题:)

0 个答案:

没有答案