Является ли область, которую Xcode "Build and Analyze" уловит как утечка, должна быть ограниченной? - PullRequest
0 голосов
/ 29 апреля 2010

Это не заботится об этом:

NSString* leaker()
{
 return [[NSString alloc] init];
}

Я подумал, что было бы достаточно разумно проверить, могут ли какие-либо пути кода вызывать эту функцию, не освобождая ее возвращаемое значение (я бы не стал так кодировать, я просто тестирую анализатор).

Это сообщает об утечке:

NSString* leaker()
{
 NSString* s = [[NSString alloc] init];
 [s retain];
 return s;
}

но НЕ это:

NSString* leaker()
{
 NSString* s = [[NSString alloc] init];
// [s retain];
 return s;
}

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

1 Ответ

4 голосов
/ 30 апреля 2010

clang не выполняет межпроцедурный анализ, по крайней мере, пока. Даже если бы оно и было, оно не обязательно может поймать эту «ошибку» - перестановки потенциальных путей кода имеют тенденцию к супер экспоненциальному росту, что делает это практической невозможностью.

clang работает с набором эвристик, которые работают "большую часть времени". К счастью, правила управления памятью Какао имеют тенденцию быть достаточно единообразными, поэтому эвристика работает для большинства применений. Конкретный пример, который вы привели, на самом деле не охватывается правилами управления памятью, но я думаю, что большинство людей (включая меня) склонны классифицировать ваш пример как «Вы задокументировали через API, что вызывающий * 1005» * несет ответственность за release возвращаемый объект ". Это по сути аналогично методам стиля - (NSString *)init....

clang знает, что методы, начинающиеся с init..., возвращают «невыпущенный» объект, и вызывающая сторона несет ответственность за обеспечение его правильного освобождения. Это является частью ядра эвристики - ему не нужен весь программный или межпроцедурный анализ для выполнения основной части проверки подсчета ссылок - если локальный блок кода получает объект с помощью метода init..., этот локальный блок кода должен убедиться, что он правильно released. Естественно, если локальный блок кода и рассматриваемый объект являются частью самого метода init..., он покрывается тем же «правилом», поэтому он получает исключение.

То, что вы, вероятно, хотите, это что-то вроде:

NSString* leaker() __attribute__((ns_returns_retained))
{
 return [[NSString alloc] init];
}

Это позволяет анализатору узнать, что leaker() возвращает «сохраненный» объект, и что вызывающий абонент отвечает за его правильное освобождение. Хотя я не проверял это, я сильно подозреваю, что «утечка» будет обнаружена в точке, где вызывается leaker(), т. Е .:

void test(void)
{
  NSString *leaked = leaker();
  // Previous line should be caught as a "leak" by clang.
}

Это одно из печальных ограничений любого статического анализатора, а не только clang.

...