7

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がそのようなシェナニガンで私をどのように非難するのですか?

2番:

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

第3:

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;
    }
}

第4:

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

ただし、その配列を初期化したばかりですか?とがゼロの長さで初期化された場合annotationLats、初期化されない可能性があることを理解しています。annotationLongs


これらの警告は重要ですか?これらの警告なしにプログラムが期待どおりに実行された場合、それらを安全に無視できますか?Xcodeを無視するのは良い考えではないように感じます—それはかなりインテリジェントです。

4

1 に答える 1

6

誤解は、clang / checkerは配列countが変更されないことを保証できず、配列が不変であるかのようにプログラムが流れることを保証できないということです。

私の本当の質問は、これらの警告が重要であり、プログラムがエラーなしで(まあ、これらの警告に関連するエラーなしで)期待どおりに実行された場合、それらを安全に無視できますか?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を作成または使用しないことをコンパイラーに保証するための1つのアプローチです。

2)!=の左オペランドはガベージ値です:

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

意味:チェッカーは、配列が完全に初期化されたこと、およびそれがand未満であることを保証できませsizeLatsん。さらに重要なことに、範囲外アクセスの可能性について警告する必要があります。このメッセージはあまり明確ではありません。[overlayLat count][overlayLong count]

解決策:プログラムには、実際にはチェックされていない境界と仮定が少しあります(おそらく、いくつかのエラーチェックが削除されました)。これは、チェッカーとコンパイラーにとってより明確にする必要があります。これをコンパイラーに明確にし、万が一の場合に備えてエラー検出を追加する必要があります(より完全な例を提供します)。

追記-浮動小数点の比較はあまり安全ではありません-C配列が初期化されることを期待すべきではありません

3)関数呼び出し引数は初期化されていない値です。

意味:この問題の原因は、#2「!=の左オペランドはガベージ値です」と同じです。指定されたインデックスの配列が初期化されていない可能性があります。さらに悪い問題は、配列インデックスが範囲内にあるという保証がないことです。そのようにフラグが立てられていないという事実は、誤検知が多すぎるためにチェッカーがこの警告を無効にしたのではないかと思います。

解決策:#2と同じ

したがって、広範なエラーチェックを伴うより徹底的な例は、次のプログラムのように流れる可能性があります。プログラムはきれいではなく、クリーンアップ/リファクタリングを使用できますが、すべてのエラーチェックが存在し、チェッカーの問題なしで合格し、疑わしいコードに到達できなくなり、大量のエラーを検出します。私はまだ浮動小数点の比較や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]);
/* ... */
    }
}
于 2011-11-03T01:52:21.523 に答える