Objective-C内存管理问题

发布于 2024-10-05 04:32:21 字数 728 浏览 0 评论 0原文

我收到 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

↘人皮目录ツ 2024-10-12 04:32:21

当崩溃发生时,将会有一个回溯。

发布它。

您的程序将在调试器中中断,并且调用堆栈将位于调试器 UI 中(或者您可以键入“bt

这样一来,事故的原因往往就很明显了。如果没有这一点,我们就只能批评代码。

所以,这里是……


char urlChars[1000];
[self getEventURL: urlChars];

这充其量是一个安全漏洞,而最坏的情况则是崩溃的根源。任何时候您要将字节复制到缓冲区中,都应该有某种方法来(a)限制复制的字节数(传递缓冲区的长度)和(b)返回复制的字节数( 0 表示失败或未复制字节)。

鉴于上述情况,如果 getEventURL: 将 1042 字节复制到 urlChars 中,会发生什么情况? boom

NSString * theUrl = [[NSString alloc] initWithFormat:@"%s", urlChars];

这是对 urlChars 做出一些假设,这将导致失败。首先,它假设 urlChars 具有正确的 %s 兼容编码。其次,它假设 urlChars 是 NULL 终止的(并且没有溢出缓冲区)。

最好使用各种 NSString 方法之一,这些方法使用特定编码直接从字节缓冲区创建字符串。更精准、更高效。

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]);

这是执行此操作的效率最低的可能方法。无需创建 NSString 实例,然后将其转换为 (char *)。只需直接从数据中获取字节即可。

另外——您确定返回的数据以 NULL 结尾吗?如果没有,strcpy() 将直接超出 eventData 缓冲区的末尾,从而损坏堆栈。

[self parseEventData: eventData dataLength: theLength];
[whatIsShowing setStringValue:@"Showing events by this artist"];

您真正想要解析原始字节的数据类型是什么?在几乎所有情况下,此类数据都应该是某种结构化类型; 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....


char urlChars[1000];
[self getEventURL: urlChars];

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 by getEventURL:? boom

NSString * theUrl = [[NSString alloc] initWithFormat:@"%s", urlChars];

This is making some assumptions about urlChars that will lead to failure. First, it assumes that urlChars is of a proper %s compatible encoding. Secondly, it assumes that urlChars 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.

NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:theUrl]];

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.

int theLength = [data length];
NSString *content = [NSString stringWithUTF8String:[data bytes]];

char eventData[[data length]];
strcpy(eventData, [content UTF8String]);

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 the bytes 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 your eventData buffer, corrupting the stack.

[self parseEventData: eventData dataLength: theLength];
[whatIsShowing setStringValue:@"Showing events by this artist"];

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).

风吹短裙飘 2024-10-12 04:32:21

[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 using strncpy() instead and see if that still crashes. (It's also possible that getEventURL: sometimes fails to return a string in the format expected, but that's impossible to tell without the source to that method.)

假装不在乎 2024-10-12 04:32:21

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 using bzero.

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 on NSZombieEnabled 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.

╭ゆ眷念 2024-10-12 04:32:21

在我看来,代码太复杂了。除非绝对必要,否则不要诉诸纯 C 数组和字符串,它们很难正确使用。 (这不是什么火箭科学,但如果你一直玩枪,你迟早会搬起石头砸自己的脚。)即使你坚持解析纯 C 字符串,也可以使用函数接口:

// Callers have to mess with char*.
- (void) parseEventData: (char*) data {…}

// Callers can stay in the Objective-C land.
- (void) parseEventData: (NSString* or NSData*) data {
    char *unwrappedData = …;
    …
}

在我的代码中使用 strcpy 之前,我肯定会三思而后行。我认为您正在泄漏 theUrl (尽管在这种情况下这不应导致 EXC_BAD_ACCESS)。至于错误本身,您可能会挂在 urlCharseventData 的部分上,当这些基于堆栈的变量消失时,您会导致段错误吗?

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:

// Callers have to mess with char*.
- (void) parseEventData: (char*) data {…}

// Callers can stay in the Objective-C land.
- (void) parseEventData: (NSString* or NSData*) data {
    char *unwrappedData = …;
    …
}

I’d certainly think twice before I used strcpy in my code. And I think you are leaking theUrl (although that should not cause EXC_BAD_ACCESS in this case). As for the bug itself, you might be hanging on parts of urlChars or eventData and when those stack-based variables disappear, you cause the segfault?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文