Задача управления памятью Objective-C - PullRequest
1 голос
/ 02 декабря 2010

Я получаю ошибку 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"];
}

Ответы [ 4 ]

11 голосов
/ 02 декабря 2010

При сбое происходит обратный след.

Опубликовать это.

Либо ваша программа сломается в отладчике, а стек вызовов будет в интерфейсе отладчика (или вы можете набрать 'bt

При этом причина аварии часто становится совершенно очевидной. Без этого нам остается критиковать код.

Итак, вот так ...

<Ч />
char urlChars[1000];
[self getEventURL: urlChars];

В лучшем случае это дыра в безопасности и, в худшем случае, источник вашей аварии. Каждый раз, когда вы собираетесь копировать байты в буфер, должен быть какой-то способ (а) ограничить количество копируемых байтов (передать длину буфера) и (б) возвращается количество скопированных байтов ( 0 для сбоя или нет скопированных байтов).

Учитывая вышесказанное, что произойдет, если в urlChars с помощью getEventURL: скопировано 1042 байта? бум

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 *). Просто возьмите bytes из данных напрямую.

Кроме того - вы уверены, что возвращаемые данные равны NULL? Если нет, то strcpy() взорвется прямо за концом вашего eventData буфера, разрушая стек.

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

Какие данные вы анализируете, что вы действительно хотите проанализировать необработанные байты? Почти во всех случаях такие данные должны быть структурированного типа; XML или даже HTML. Если это так, то нет необходимости переходить к разбору необработанных байтов. (Не то, чтобы необработанные данные были неслыханными - просто странные).

1 голос
/ 02 декабря 2010

Возможно ли, что строка, содержащаяся в urlChars, иногда возвращается без завершения NULL? Возможно, вы захотите попробовать обнулить массив, например, используя bzero.

Кроме того, существует множество методов для отладки EXC_BAD_ACCESS. Поскольку вы выполняете много чистых манипуляций со строками Си, обычный метод включения NSZombieEnabled может вам помочь, а может и не помочь (хотя я рекомендую включать его независимо от того). Другая техника, которую вы можете попробовать, это восстановить предыдущий кадр стека, используя GDB. См. мой предыдущий ответ на аналогичный вопрос , если вам интересно.

1 голос
/ 02 декабря 2010

На мой взгляд, код слишком сложный.Не прибегайте к простым массивам и строкам 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 в этом случае).Что касается самой ошибки, вы можете зависать на частях urlChars или eventData, и когда эти переменные на основе стека исчезают, вы вызываете segfault?

1 голос
/ 02 декабря 2010

Байты, которые вы получаете от [content UTF8String], могут предположительно отличаться по значению от значения [data length]. Попробуйте вместо этого использовать strncpy() и посмотрите, все равно ли это. (Также возможно, что getEventURL: иногда не может вернуть строку в ожидаемом формате, но это невозможно сказать без источника для этого метода.)

...