NSURLConnection在10.5.7下崩溃

时间:2009-05-27 16:25:07

标签: objective-c cocoa

我有一个小应用程序可以下载股票价格并且完美运行(多年),直到我最近升级到10.5.7。升级后,程序将在此调用时崩溃:

NSString *currinfo = [NSString stringWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://finance.yahoo.com/d/quotes.csv?s=%@&f=l1c1p2", escsymbol]]];

奇怪的是,崩溃不会马上发生。这行代码被多次调用,没有任何问题,然后由于此次调用崩溃,程序最终会在1-2小时后失败。

我原本在这里发了一篇很长的帖子,描述了我试图调查这个问题。我收到了两个建议:(i)使调用异步(可能更好)和(ii)使用NSZombieEnabled来调查Objective-C对象提前解除分配的可能性(此注释是为了响应显示失败的堆栈跟踪而做出的objc_msgSend)。

我花了很多时间使调用异步(使用[[NSURLConnection alloc] initWithRequest:theRequest delegate:self]),这没有帮助。该计划最终仍然失败,通常在10-15分钟后。在失败之前的这段时间内,许多异步调用没有任何问题,数据被返回等等。一切都很好。然后程序再次突然崩溃。

然后我打开了NSZombieEnabled。果然,当程序最终崩溃时,我收到了消息:

-[CFArray count]: message sent to deallocated instance 0x16b90bd0

“info malloc 0x16b90bd0”然后屈服了:

0: 0x93db810c in malloc_zone_malloc
1: 0x946bc3d1 in _CFRuntimeCreateInstance
2: 0x9464a138 in __CFArrayInit
3: 0x946cd647 in _CFStreamScheduleWithRunLoop
4: 0x932d1267 in _Z16_scheduleRStreamPKvPv
5: 0x946bf15c in CFSetApplyFunction
6: 0x932b0e2b in CFNSchedulingSetScheduleReadStream
7: 0x9331a310 in _ZN12HTTPProtocol19createAndOpenStreamEv
8: 0x9332e877 in _ZN19URLConnectionLoader24loaderScheduleOriginLoadEPK13_CFURLRequest
9: 0x9332d739 in _ZN19URLConnectionLoader26LoaderConnectionEventQueue33processAllEventsAndConsumePayloadEP20XConnectionEventInfoI12XLoaderEvent18XLoaderEventParamsEl
10: 0x9332dbdd in _ZN19URLConnectionLoader13processEventsEv
11: 0x932d8dbf in _ZN17MultiplexerSource7performEv
12: 0x946ba595 in CFRunLoopRunSpecific
13: 0x946bac78 in CFRunLoopRunInMode
14: 0x9058c530 in +[NSURLConnection(NSURLConnectionReallyInternal) _resourceLoadLoop:]
15: 0x90528e0d in -[NSThread main]
16: 0x905289b4 in __NSThread__main__
17: 0x93de8155 in _pthread_start
18: 0x93de8012 in thread_start

我不是读取堆栈跟踪的专家,但是这条跟踪是否表明Apple代码中存在问题,而不是我的代码?或者我可以以某种方式负责取消分配有问题的CFArray?我有什么方法可以进一步调查问题的原因吗?


(这是我原帖的其余部分)

看到stringWithContentsOfURL已被弃用,我转而使用此代码:

pathURL = [NSURL URLWithString:[NSString stringWithFormat:@"http://finance.yahoo.com/d/quotes.csv?s=%@&f=l1c1p2", escsymbol]];

NSURLRequest *request = [NSURLRequest requestWithURL:pathURL cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:30.0];

responseData = [ NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];

NSString *currinfo = nil;

if ([error code]) {  dNSLog((@"%@ %d %@ %@ %@", [ error domain], [ error code], [ error localizedDescription], request, @"file://localhost/etc/gettytab"));  }

这没有帮助。程序在任意长度的时间后仍在sendSynchronousRequest行崩溃,调试器中包含此信息:

0   0x93db7286 in mach_msg_trap
1   0x93dbea7c in mach_msg
2   0x946ba04e in CFRunLoopRunSpecific
3   0x946bac78 in CFRunLoopRunInMode
4   0x932b53eb in CFURLConnectionSendSynchronousRequest
5   0x905dca4b in +[NSURLConnection sendSynchronousRequest:returningResponse:error:]

...等

真正的崩溃实际上可能在另一个线程中:

0   libobjc.A.dylib                 0x965c3688 objc_msgSend + 24
1   com.apple.CoreFoundation        0x946cc581 _CFStreamSignalEventSynch + 193
2   com.apple.CoreFoundation        0x946ba595 CFRunLoopRunSpecific + 3141
3   com.apple.CoreFoundation        0x946bac78 CFRunLoopRunInMode + 88
4   com.apple.Foundation            0x9058c530 +[NSURLConnection(NSURLConnectionReallyInternal) _resourceLoadLoop:] + 320
5   com.apple.Foundation            0x90528e0d -[NSThread main] + 45
6   com.apple.Foundation            0x905289b4 __NSThread__main__ + 308
7   libSystem.B.dylib               0x93de8155 _pthread_start + 321
8   libSystem.B.dylib               0x93de8012 thread_start + 34

我认为是生成下载URL的线程。顺便说一句,错误处理代码工作正常 - 当我故意通过断开互联网导致错误时,错误只是在控制台中报告,程序不会崩溃。

令人难以置信的是令人沮丧。我会非常乐意花费尽可能多的时间来追踪问题,但我对gdb的知识极限,尤其是汇编语言。我不知道如何找出Foundation代码的实际问题。起初我以为自动释放的NSString escsymbol可能会以某种方式被释放,但发送保留消息并没有帮助。如果 这个案例,我怎么能证明呢?

还有其他人有这个问题吗?

8 个答案:

答案 0 :(得分:9)

我认为Eugene在这个帖子中的回答恰当地描述了这个问题;经过一些测试后,我已经得出结论似乎正在进行中,希望有一些细节可以帮助其他人解决这个问题:

重定向网址会定期导致失败。在NSURLConnection的同步和异步使用中都会发生这种情况。我已经创建了一个测试项目来跟踪这个bug,并且这种崩溃将持续发生(通常在25-500次迭代之间)。在10.5.6上运行相同的测试或不重定向URL不会失败(已经运行了多达20,000次迭代)。

有两种可能的解决方法:

  1. 请勿使用重定向网址:
    显然这并不总是可行,但如果它是一个已知的URL,你仍然可以使用简单的调用(如stringWithContentsOfURL:),这将正常工作。 Dennis,在您的情况下,正确的服务器URL是download.finance.yahoo.com,而不是finance.yahoo.com,所以我相信这可以解决您的特定问题。使用curl,您可以看到当您点击后一个地址时获得301重定向。
  2. 使用异步调用并实施connection:willSendRequest:redirectResponse:
    如果你实现了这个委托方法的最基本的处理,一切似乎都有效。如果你省略这个调用(从而让系统使用它的默认实现),你就会崩溃。对于基本实现,只需返回传入的请求:
  3. - (NSURLRequest *)connection:(NSURLConnection *)connection 
                 willSendRequest:(NSURLRequest *)request 
                redirectResponse:(NSURLResponse *) redirectResponse
    {
        return request;
    }
    

    所有这些似乎都告诉我,Apple在10.5.7中的实现中存在某些问题,但如果其他人对可能发生的事情有任何见解,请发出声音。

    我已将我的测试项目的错误提交给Apple rdar://6936109,并引用了tjw的报告(Radar 6932684)。

答案 1 :(得分:5)

这似乎与重定向有关。我的应用程序直接下载大约500兆的数据(几百个单独的文件)不会崩溃。同样的应用程序下载较小的url集,所有这些都被重定向将在这一点上随机崩溃几次(重启恢复,一遍又一遍地重新启动实际上会导致成功下载)。

编辑:BTW,Colin关于重新实现重定向的建议似乎不适用于NSURLDownload :(。

EDIT2:好的,这似乎是竞争条件。添加cerr<< “redirect”<< ENDL;在回调中“通过NSURLDownload”修复了它。睡眠1秒或锁定局部静态互斥锁无效...

答案 2 :(得分:4)

objc_msgSend中的崩溃通常是由于对象生命周期不正确(即对象已被释放并且正在发送消息)。

使用NSZombieEnabled运行您的代码,以确定这是否确实是您的问题,并查看哪个对象正在提前发布。

答案 3 :(得分:2)

在Omni Group,我们在所有使用NSURL的应用程序中也看到了10.5.7的新崩溃,在异步使用中(所以我认为同步的东西是红鲱鱼)。我们也在TextMate中发生过这种情况(可能是在软件更新中)。

我已就这个问题记录了Radar 6932684,如果你也看到了,我强烈建议大家报告,并提供你可以收集的任何细节。

答案 4 :(得分:2)

我还看到在几个应用程序中10.5.7中出现了完全相同的崩溃。

鉴于实现最简单的connection:willSendRequest:redirectResponse:委托方法将解决问题,我认为可能与radar #6700222高度相关。

答案 5 :(得分:1)

对于它的价值,这似乎固定在10.5.8 ---但它被一个 new 错误所取代,该错误将重定向的响应体预先设置为实际响应的2%左右。时间。 (通过在-stringWithContentsOfURL上旋转很容易重现:但是我们也在野外看到它。)报告说这个bug是雷达#7169953。

答案 6 :(得分:0)

我建议不要使用同步网址连接。它确实需要一些代码重构,但阻止网络上的主线程是非常糟糕的行为。 (假设你在主线程中这样做了。)

另外,我猜这是苹果计划弃用或停止维护的代码,这可能就是你在这里看到的。

希望有帮助......

答案 7 :(得分:0)

我们使用未弃用的stringWithContentsOfURLsendSynchronousRequest(在不同的地方)看到同样的问题。我们看到了同样的行为;调用可以在很多次迭代中正常工作,然后随机失败(在相同的请求上)。

鉴于同步调用是在异步机制之上构建的,因此这些调用不应该仍然无法正常工作。不幸的是,我们还没有解决方案。