Objective-C内存管理问题
我收到 EXC_BAD_ACCESS 错误,这是因为这部分代码。基本上,我接受输入并对其进行一些工作。多次输入后,会抛出错误。我在这里的记忆有问题吗?我会发布其余的代码,但它相当长——我认为这可能是我的问题所在(至少是 Xcode 指出的地方)。
-(IBAction) findShows: (id) clicked
{
char urlChars[1000];
[self getEventURL: urlChars];
NSString * theUrl = [[NSString alloc] initWithFormat:@"%s", urlChars];
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:theUrl]];
int theLength = [data length];
NSString *content = [NSString stringWithUTF8String:[data bytes]];
char eventData[[data length]];
strcpy(eventData, [content UTF8String]);
[self parseEventData: eventData dataLength: theLength];
[whatIsShowing setStringValue:@"Showing events by this artist"];
}
I'm getting an EXC_BAD_ACCESS error, and It's because of this part of code. Basically, I take an input and do some work on it. After multiple inputs, it throws the error. Am I doing something wrong with my memory here? I'd post the rest of the code, but it's rather long -- and I think this may be where my problem lies (It's where Xcode points me, at least).
-(IBAction) findShows: (id) clicked
{
char urlChars[1000];
[self getEventURL: urlChars];
NSString * theUrl = [[NSString alloc] initWithFormat:@"%s", urlChars];
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:theUrl]];
int theLength = [data length];
NSString *content = [NSString stringWithUTF8String:[data bytes]];
char eventData[[data length]];
strcpy(eventData, [content UTF8String]);
[self parseEventData: eventData dataLength: theLength];
[whatIsShowing setStringValue:@"Showing events by this artist"];
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
当崩溃发生时,将会有一个回溯。
发布它。
您的程序将在调试器中中断,并且调用堆栈将位于调试器 UI 中(或者您可以键入“bt
这样一来,事故的原因往往就很明显了。如果没有这一点,我们就只能批评代码。
所以,这里是……
这充其量是一个安全漏洞,而最坏的情况则是崩溃的根源。任何时候您要将字节复制到缓冲区中,都应该有某种方法来(a)限制复制的字节数(传递缓冲区的长度)和(b)返回复制的字节数( 0 表示失败或未复制字节)。
鉴于上述情况,如果
getEventURL:
将 1042 字节复制到urlChars
中,会发生什么情况? boom这是对
urlChars
做出一些假设,这将导致失败。首先,它假设urlChars
具有正确的%s
兼容编码。其次,它假设 urlChars 是 NULL 终止的(并且没有溢出缓冲区)。最好使用各种 NSString 方法之一,这些方法使用特定编码直接从字节缓冲区创建字符串。更精准、更高效。
我希望这不是在主线程上......因为如果是的话它会阻塞,这将使您的应用程序在缓慢/不稳定的网络上无响应。
这是执行此操作的效率最低的可能方法。无需创建
NSString
实例,然后将其转换为(char *)
。只需直接从数据中获取字节
即可。另外——您确定返回的数据以 NULL 结尾吗?如果没有,
strcpy()
将直接超出eventData
缓冲区的末尾,从而损坏堆栈。您真正想要解析原始字节的数据类型是什么?在几乎所有情况下,此类数据都应该是某种结构化类型; XML,甚至 HTML。如果是这样,则无需解析原始字节。 (并不是说原始数据是闻所未闻的——只是奇怪)。
When a crash occurs, there will be a backtrace.
Post it.
Either your program will break in the debugger, and the call stack will be in the debugger UI (or you can type 'bt
With that, the cause of the crash is often quite obvious. Without that, we are left to critique the code.
So, here goes....
This is, at best, a security hole and, at worst, the source of your crash. Any time you are going to copy bytes into a buffer, there should be some kind of way to (a) limit the # of bytes copied in (pass the length of the buffer) and (b) the # of bytes copied is returned (0 for failure or no bytes copied).
Given the above, what happens if there are 1042 bytes copied into
urlChars
bygetEventURL:
? boomThis is making some assumptions about
urlChars
that will lead to failure. First, it assumes thaturlChars
is of a proper%s
compatible encoding. Secondly, it assumes thaturlChars
is NULL terminated (and didn't overflow the buffer).Best to use one of the various NSString methods that create strings directly from the buffer of bytes using a particular encoding. More precise and more efficient.
I hope this isn't on the main thread... 'cause it'll block if it is and that'll make your app unresponsive on slow/flaky networks.
This is about the least efficient possible way of doing this. There is no need to create an
NSString
instance just to then turn it into a(char *)
. Just grab thebytes
from the data directly.Also -- are you sure that the data returned is NULL terminated? If not, that
strcpy()
is gonna blow right past the end of youreventData
buffer, corrupting the stack.What kind of data are you parsing that you really want to parse the raw bytes? In almost all cases, such data should be of some kind of structured type; XML or, even, HTML. If so, there is no need to drop down to parsing the raw bytes. (Not that raw data is unheard of -- just odd).
从
[content UTF8String]
获取的字节数量可能与[data length]
的值不同。尝试使用strncpy()
代替,看看是否仍然崩溃。 (也有可能getEventURL:
有时无法返回预期格式的字符串,但如果没有该方法的源代码,就无法判断。)The bytes you get from
[content UTF8String]
could conceivably be different in number from the value of[data length]
. Try usingstrncpy()
instead and see if that still crashes. (It's also possible thatgetEventURL:
sometimes fails to return a string in the format expected, but that's impossible to tell without the source to that method.)urlChars 中包含的字符串有时是否可能返回非 NULL 终止符?您可能想尝试将数组清零,例如使用
bzero
。此外,还有很多调试
EXC_BAD_ACCESS
的技术。由于您正在进行大量纯 C 字符串操作,因此打开 NSZombieEnabled 的常用方法可能对您有帮助,也可能没有帮助(尽管我建议无论如何都打开它)。您可以尝试的另一种技术是使用 GDB 恢复以前的堆栈帧。请参阅我之前对类似问题的回答如果你有兴趣的话。Is it possible that the string contained in
urlChars
sometimes comes back non-NULL-terminated? You might want to try zeroing out the array, for example usingbzero
.Additionally, there are a bunch of techniques for debugging
EXC_BAD_ACCESS
. Since you're doing a lot of pure C string manipulation, the usual method of turning onNSZombieEnabled
may or may not help you (though I recommend turning it on regardless). Another technique you can try is recovering a previous stack frame using GDB. See my previous answer to a similar question if you're interested.在我看来,代码太复杂了。除非绝对必要,否则不要诉诸纯 C 数组和字符串,它们很难正确使用。 (这不是什么火箭科学,但如果你一直玩枪,你迟早会搬起石头砸自己的脚。)即使你坚持解析纯 C 字符串,也可以使用函数接口:
在我的代码中使用
strcpy
之前,我肯定会三思而后行。我认为您正在泄漏theUrl
(尽管在这种情况下这不应导致EXC_BAD_ACCESS
)。至于错误本身,您可能会挂在urlChars
或eventData
的部分上,当这些基于堆栈的变量消失时,您会导致段错误吗?In my opinion the code is too complex. Do not resort to plain C arrays and strings unless you absolutely have to, they are harder to get right. (It’s no rocket science, but if you play with guns all the time, you will shoot yourself in the foot sooner or later.) Even if you insist on parsing plain C strings, isolate the code using the function interface:
I’d certainly think twice before I used
strcpy
in my code. And I think you are leakingtheUrl
(although that should not causeEXC_BAD_ACCESS
in this case). As for the bug itself, you might be hanging on parts ofurlChars
oreventData
and when those stack-based variables disappear, you cause the segfault?