Странные результаты Xcode Analyze - PullRequest
7 голосов
/ 03 ноября 2011

Когда я анализирую свой проект в Xcode, я получаю несколько странных ошибок.Весь этот код является частью единого метода, который создает массивы, которые можно использовать для создания MKAnnotations.Извините, если это затопление кода - я приложил все усилия, чтобы закомментировать несвязанные части.Я включил весь метод в дополнение к фрагментам только для некоторой перспективы.Спасибо!

- (void)addLines {
    /*

    NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];

    // Create region and span variables
    MKCoordinateSpan span;
    MKCoordinateRegion region;

    NSArray* arrayOuter = [defaults objectForKey:@"mapSaveDataKey"];

    NSData* data = [arrayOuter objectAtIndex:[[defaults objectForKey:@"currentMap"] intValue]];

    NSArray* arrayOne = [NSKeyedUnarchiver unarchiveObjectWithData:data];

    if (arrayOne.count == 0)
        [self returns:nil];

    */

    NSArray* overlayLat = [arrayOne objectAtIndex:1];
    double lats[overlayLat.count];

    NSArray* overlayLong = [arrayOne objectAtIndex:2];
    double longs[overlayLong.count];

    NSArray* annotationLat = [arrayOne objectAtIndex:8];
    double annotationLats[annotationLat.count];

    NSArray* annotationLong = [arrayOne objectAtIndex:9];
    double annotationsLongs[annotationLong.count];

    /*

    CLLocationCoordinate2D startLocation = CLLocationCoordinate2DMake([[overlayLat objectAtIndex:0] doubleValue], [[overlayLong objectAtIndex:0] doubleValue]);

    CLLocationCoordinate2D finishLocation = CLLocationCoordinate2DMake([[overlayLat objectAtIndex:[overlayLat count] - 1] doubleValue], [[overlayLong objectAtIndex:[overlayLong count] - 1] doubleValue]);

    NSString* string1 = [[[NSString alloc] initWithFormat:@"Lat: %.3f, Long: %.3f", [[overlayLat objectAtIndex:0] doubleValue], [[overlayLong objectAtIndex:0] doubleValue]] autorelease];

    NSString* string2 = [[[NSString alloc] initWithFormat:@"Lat: %.3f, Long: %.3f", [[overlayLat objectAtIndex:([overlayLat count] - 1)] doubleValue], [[overlayLong objectAtIndex:([overlayLong count] - 1)] doubleValue]] autorelease];

    LocationAnnotation* startAnnotation = [[LocationAnnotation alloc] initWithCoordinate:startLocation title:@"Start" subtitle:string1];

    LocationAnnotation* finishAnnotation = [[LocationAnnotation alloc] initWithCoordinate:finishLocation title:@"Finish" subtitle:string2];

    */

    for (int iii = 0; iii < overlayLat.count; iii++) {
        NSNumber* a = (NSNumber*)[overlayLat objectAtIndex:iii];
        lats[iii] = [a doubleValue];
    }

    for (int iii = 0; iii < overlayLong.count; iii++) {
        NSNumber* a = (NSNumber*)[overlayLong objectAtIndex:iii];
        longs[iii] = [a doubleValue];
    }

    for (int iii = 0; iii < annotationLong.count; iii++) {
        NSNumber* a = (NSNumber*)[annotationLong objectAtIndex:iii];
        annotationsLongs[iii] = [a doubleValue];
    }

    for (int iii = 0; iii < annotationLat.count; iii++) {
        NSNumber* a = (NSNumber*)[annotationLat objectAtIndex:iii];
        annotationLats[iii] = [a doubleValue];
    }

    int sizeLats = 0;

    for (int iii = 0; iii < overlayLat.count; iii++)
        if (lats[iii] != 0)
            sizeLats++;

    CLLocationCoordinate2D coords[sizeLats];

    for (int iii = 0; iii < sizeLats; iii++) {
        if (lats[iii] != 0 && longs[iii] != 0) {
            coords[iii].latitude = lats[iii];
            coords[iii].longitude = longs[iii];
        } else {
            coords[iii].latitude = coords[iii - 1].latitude;
            coords[iii].longitude = coords[iii - 1].longitude;
        }
    }

    /*

    // Give variables value
    span = MKCoordinateSpanMake(.05, .05);       
    region = MKCoordinateRegionMake(coords[0], span);

    MKPolyline* line = [MKPolyline polylineWithCoordinates:coords count:sizeLats];

    [mapView addOverlay:line];

    [mapView addAnnotations:[NSArray arrayWithObjects:startAnnotation, finishAnnotation, nil]];
    [mapView selectAnnotation:startAnnotation animated:YES];

    */

    for (int iii = 0; iii < annotationLong.count; iii++) {
        CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(annotationLats[iii], annotationsLongs[iii]);
        /*

        NSString* subtitle = [[[NSString alloc] initWithFormat:@"Lat: %.3f, Long: %.3f", coord.latitude, coord.longitude] autorelease];
        NSString* title = [[[NSString alloc] initWithFormat:@"Stop %i", (iii + 1)] autorelease];
        LocationAnnotation* a = [[LocationAnnotation alloc] initWithCoordinate:coord title:title subtitle:subtitle];
        CLLocation* c = [[CLLocation alloc] initWithCoordinate:coord altitude:0 horizontalAccuracy:0 verticalAccuracy:0 course:0 speed:0 timestamp:0];
        CLLocation* d = [[CLLocation alloc] initWithCoordinate:CLLocationCoordinate2DMake(finishAnnotation.coordinate.latitude, finishAnnotation.coordinate.longitude) altitude:0 horizontalAccuracy:0 verticalAccuracy:0 course:0 speed:0 timestamp:0];
        if ([c distanceFromLocation:d] > 20)
            [mapView addAnnotation:a];
        [c release];
        [d release];
        [a release];

        */
    }

    /*

    [mapView setRegion:region animated:YES];

    [startAnnotation release];
    [finishAnnotation release];

    */
}

Первый:

int sizeLats = 0;

for(int iii = 0; iii < overlayLat.count; iii++)
    if(lats[iii] != 0) //"The left operand of '!=' is a garbage value"
        sizeLats++;

Как смеешь Xcode обвинять меня в таких махинациях?

Второй:

CLLocationCoordinate2D coords[sizeLats]; //"Declared variable-length array (VLA) has zero size"

Третье:

for (int iii = 0; iii < sizeLats; iii++) {
    if (lats[iii] != 0 && longs[iii] != 0) { // "The left operand of '!=' is a garbage value"
        coords[iii].latitude = lats[iii];
        coords[iii].longitude = longs[iii];
    } else {
        coords[iii].latitude = coords[iii - 1].latitude; // "Assigned value is garbage or undefined"
        coords[iii].longitude = coords[iii - 1].longitude;
    }
}

Четвертое:

CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(annotationLats[iii], annotationsLongs[iii]); // "Function call argument is an uninitialized value"

Кроме того, я только что инициализировал этот массив?Я понимаю, что это может быть неинициализировано, если annotationLats и annotationLongs были инициализированы с нулевой длиной.


Являются ли эти предупреждения жизненно важными?Если моя программа работает должным образом без этих предупреждений, могу ли я их игнорировать?Я просто чувствую, что не стоит игнорировать Xcode - это довольно умно.

1 Ответ

6 голосов
/ 03 ноября 2011

недоразумение заключается в том, что clang / checker не может гарантировать, что массивы count не изменятся, и не может быть уверена, что программа будет работать так, как будто ваши массивы неизменны.

MyНа самом деле вопрос в том, насколько важны эти предупреждения, и если моя программа работает должным образом, без ошибок (ну, без ошибок, связанных с этими предупреждениями: D), могу ли я их безопасно игнорировать?Я просто чувствую, что не стоит игнорировать Xcode;это довольно умно.

Лично я не игнорирую их и действительно стараюсь не допустить этих проблем.

Вы можете немного изменить свою программу, чтобы привести ее в соответствие с потоком программ.ожидает компилятор / проверка.Самый простой способ сделать это и удалить большинство предупреждений - это ввести переменную, которую, как вы ожидаете, изменить нельзя:

NSArray* overlayLat = [arrayOne objectAtIndex:1];
const NSUInteger overlayLatCount = [overlayLat count];
// now use the variable instead of calling the method where needed:
double lats[overlayLatCount];
...

Затем используйте эти переменные вместо методов.Естественно, вы должны быть осторожны, чтобы убедиться, что создаваемые вами переменные всегда будут равны значению, которое они представляют.

Есть еще несколько битов: средство проверки не всегда знает семантику типа.Например: вы могли бы подумать, что подсчет NSArray может быть кэширован, но контролер должен знать много о многих классах, чтобы понять эти проблемы.Более того, программа проверки не может гарантировать, что программа будет работать так, как вы ожидаете, по многим другим причинам.Допустим, счетчик массива был кэширован как оптимизация;это приведет к куче ошибок в реальных программах.Таким образом, вы должны сделать некоторые вещи немного более очевидными, когда у вас есть контекст, на который может не рассчитывать контролер - вам необходимо ввести этот контекст в некоторых случаях.

первый набор проблем, более подробно

NSArray * overlayLat = [arrayOne objectAtIndex:1];
const NSUInteger overlayLatCount = [overlayLat count];
double lats[overlayLatCount];

NSArray * overlayLong = [arrayOne objectAtIndex:2];
const NSUInteger overlayLongCount = [overlayLong count];
double longs[overlayLongCount];

NSArray * annotationLat = [arrayOne objectAtIndex:8];
const NSUInteger annotationLatCount = [annotationLat count];
double annotationLats[annotationLatCount];

NSArray * annotationLong = [arrayOne objectAtIndex:9];
const NSUInteger annotationLongCount = [annotationLong count];
double annotationsLongs[annotationLongCount];

for (int iii = 0; iii < overlayLatCount; iii++) {
    NSNumber * a = (NSNumber*)[overlayLat objectAtIndex:iii];
    lats[iii] = [a doubleValue];
}

for (int iii = 0; iii < overlayLongCount; iii++) {
    NSNumber * a = (NSNumber*)[overlayLong objectAtIndex:iii];
    longs[iii] = [a doubleValue];
}

for (int iii = 0; iii < annotationLongCount; iii++) {
    NSNumber * a = (NSNumber*)[annotationLong objectAtIndex:iii];
    annotationsLongs[iii] = [a doubleValue];
}

for (int iii = 0; iii < annotationLatCount; iii++) {
    NSNumber * a = (NSNumber*)[annotationLat objectAtIndex:iii];
    annotationLats[iii] = [a doubleValue];
}

Сведения об оставшихся проблемах

1) Объявленный VLA имеет нулевой размер:

Значение: средство проверки видит, что sizeLats инициализируется нулем и увеличивается только условно.Он предупреждает вас, что длина массива может быть равна нулю.

Разрешение: прежде чем продолжить, проверьте на ноль:

if (0 == sizeLats) return;

CLLocationCoordinate2D coords[sizeLats];

Это один из способов гарантировать компилятору, что вы не будете создавать или использоватьнулевая длина VLA.

2) Левый операнд! = является значением мусора:

if ((lats[iii] != 0) && (longs[iii] != 0)) {

Значение: средство проверки не может гарантировать, что массив когда-либо был полностью инициализирован и что sizeLatsменьше [overlayLat count] и [overlayLong count].Что еще более важно, он должен предупреждать о возможности доступа вне зоны доступа.Это сообщение не очень четкое.

Разрешение: На самом деле в программе есть немного неконтролируемых границ и предположений (и, возможно, некоторая проверка ошибок была удалена).Это должно быть прояснено для проверки и компилятора.Вы должны сделать это более понятным для компилятора и добавить некоторое обнаружение ошибок на всякий случай (предоставит более полный пример).

Дополнительные примечания - сравнения с плавающей запятой не очень безопасны - вы не должны ожидать, что массивы C будутinitialized

3) Аргумент вызова функции является неинициализированным значением.

Значение: Источник этой проблемы совпадает с # 2 «Левый операнд! = является значением мусора».Массив по указанному индексу, возможно, не был инициализирован.Еще хуже проблема заключается в том, что нет гарантии, что индекс массива будет в диапазоне.Тот факт, что он не помечен как таковой, заставляет задуматься, не отключил ли это предупреждение это предупреждение из-за слишком большого количества ложных срабатываний.

Разрешение: То же, что # 2

Итак, более подробный пример срасширенная проверка ошибок может flow , как в следующей программе.Программа не очень красива и может использовать некоторую очистку / рефакторинг, но вся проверка ошибок существует, она проходит без проблем с проверкой, делает сомнительный код недоступным и обнаруживает большое количество ошибок.Я все еще не считаю сравнения с плавающей запятой или VLA хорошими, но этого должно быть достаточно, чтобы решить ваш вопрос.

/**
  @brief fills a double buffer with values from an NSArray
  @param destinationBuffer the buffer to fill
  @param countOfDestinationBuffer the number of elements in @a destinationBuffer
  @param the source values. an NSArray filled with NSNumber objects. @a countOfDestinationBuffer must be equal to @a [source count]
  @return false if an error occurred, else true
*/
static bool FillDoubleArrayFromNSArray(double* const destinationBuffer, const NSUInteger countOfDestinationBuffer, NSArray* source) {
    const NSUInteger sourceCount = [source count];
    if ((0 == destinationBuffer) || (0 == countOfDestinationBuffer) || (0 == [source count])) {
        assert(0 && "invalid argument");
        return false;
    }
    else if (sourceCount != countOfDestinationBuffer) {
        assert(0 && "buffer size mismatch");
        return false;
    }

    for (NSUInteger idx = 0; idx < sourceCount; ++idx) {
        NSNumber* a = (NSNumber*)[source objectAtIndex:idx];
        destinationBuffer[idx] = [a doubleValue];
    }

    return true;
}

- (void)addLines {
    NSArray* arrayOne = [NSArray array];

    NSArray* overlayLatArray = [arrayOne objectAtIndex:1];
    const NSUInteger overlayLatCount = [overlayLatArray count];
    if (0 == overlayLatCount) {
        assert(0 && "empty array or invalid object. bailing.");
        return;
    }

    double lats[overlayLatCount];
    if (!FillDoubleArrayFromNSArray(lats, overlayLatCount, overlayLatArray)) {
    /* do something */
        return;
    }

    NSArray* overlayLongArray = [arrayOne objectAtIndex:2];
    const NSUInteger overlayLongCount = [overlayLongArray count];
    if (0 == overlayLongCount) {
        assert(0 && "empty array or invalid object. bailing.");
        return;
    }

    double longs[overlayLongCount];
    if (!FillDoubleArrayFromNSArray(longs, overlayLongCount, overlayLongArray)) {
    /* do something */
        return;
    }

    NSUInteger sizeLat = 0;
    for (NSUInteger idx = 0; idx < overlayLatCount; ++idx) {
        if (lats[idx] != 0) {
            ++sizeLat;
        }
    }

    if (0 == sizeLat) {
        assert(0 && "what to do when no lines can be drawn?");
        return;
    }

    if ((overlayLatCount < sizeLat) || (overlayLongCount < sizeLat)) {
        assert(0 && "input range error (overlayLongCount is really what we are testing here)");
        return;
    }

    CLLocationCoordinate2D coords[sizeLat];
    for (NSUInteger idx = 0; idx < sizeLat; ++idx) {
        if ((lats[idx] != 0) && (longs[idx] != 0)) {
            coords[idx] = CLLocationCoordinate2DMake(lats[idx], longs[idx]);
        }
        else if (0 == idx) {
            assert(0 && "range error. access of invalid index would have occurred");
            return;
        }
        else {
            coords[idx] = coords[idx - 1];
        }
    }

    NSArray* annotationLatArray = [arrayOne objectAtIndex:8];
    const NSUInteger annotationLatCount = [annotationLatArray count];
    if (0 == annotationLatCount) {
        assert(0 && "empty array or invalid object. bailing.");
        return;
    }

    double annotationLat[annotationLatCount];
    if (!FillDoubleArrayFromNSArray(annotationLat, annotationLatCount, annotationLatArray)) {
    /* do something */
        return;
    }

    NSArray* annotationLongArray = [arrayOne objectAtIndex:9];
    const NSUInteger annotationLongCount = [annotationLongArray count];
    if (0 == annotationLongCount) {
        assert(0 && "empty array or invalid object. bailing.");
        return;
    }

    double annotationLong[annotationLongCount];
    if (!FillDoubleArrayFromNSArray(annotationLong, annotationLongCount, annotationLongArray)) {
    /* do something */
        return;
    }

    if (annotationLatCount < annotationLongCount) {
        assert(0 && "input range error in next loop. bailing");
        return;
    }

    for (NSUInteger idx = 0; idx < annotationLongCount; ++idx) {
        CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(annotationLat[idx], annotationLong[idx]);
/* ... */
    }
}
...