When I Analyze my project in Xcode, I get a few strange errors.
All of this code is part of a single method which creates arrays that can be used to make MKAnnotations. Sorry if this is an inundation of code—I did my best to comment out the unrelated parts. I included the entire method in addition to the snippets just for some perspective. Thank you!
- (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];
*/
}
First:
int sizeLats = 0;
for(int iii = 0; iii < overlayLat.count; iii++)
if(lats[iii] != 0) //"The left operand of '!=' is a garbage value"
sizeLats++;
How dare Xcode accuse me of such shenanigans?
Second:
CLLocationCoordinate2D coords[sizeLats]; //"Declared variable-length array (VLA) has zero size"
Third:
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;
}
}
Fourth:
CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(annotationLats[iii], annotationsLongs[iii]); // "Function call argument is an uninitialized value"
Except, I just initialized that array? I understand that it could be uninitialized if annotationLats and annotationLongs were initialized with zero length.
Are these warnings vital? If my program runs as expected without these warnings can I safely ignore them? I just feel like it’s not a good idea to ignore Xcode—it’s rather intelligent.
the misunderstanding is that clang/checker cannot guarantee that the arrays’
countwill not change, and it cannot be sure that the program will flow as though your arrays are immutable.Personally, I don’t ignore them, and really strive to keep those issues down.
You can change your program slightly to align with the program flow the compiler/checker expects. The easy way to accomplish this and remove most of the warnings would be by introducing a variable for what you expect cannot change:
Then use those variables instead of the methods. Naturally, you should be careful to ensure that the variables you create will always be equal to the value they represent.
There are a few other bits: the checker does not always know the type’s semantics. For example: you might think an NSArray’s count could be cached, but the checker would have to know a lot about many classes to understand these issues. Even more, the checker cannot guarantee that the program will flow as you expect for many other reasons. Let’s say the array’s count were cached as an optimization; this would lead to a ton of bugs in real world programs. So, you have to make some things a little more obvious when you have context that the checker may not rely on – you have to introduce that context in some cases.
The first set of issues, in more detail
Details for the remaining Issues
1) Declared VLA has zero size:
Meaning: The checker sees that
sizeLatsis initialized to zero, and incremented only conditionally. It’s warning you that the array length could be zero.Resolution: Test for zero before continuing:
That’s one approach to guarantee to the compiler that you will not create or use the zero length VLA.
2) The Left operand of != is a garbage value:
Meaning:
The checker cannot guarantee that the array was ever fully initialized and that
sizeLatsis less than[overlayLat count]and[overlayLong count]. More importantly, it should warn of of the potential of an out of range access. This message is not very clear.Resolution:
There’s actually a bit of unchecked bounds and assumptions in the program (and perhaps some error checking was removed). That should be made clearer to checker and the compiler. You should make this clearer to the compiler and add some error detection just in case (will provide a more complete example).
Additional Notes
– floating point comparisons are not very safe
– you should not expect C arrays to be initialized
3) Function call argument is an uninitialized value.
Meaning:
The origin of this problem is the same as #2 “The Left operand of != is a garbage value”. The array at a specified index may not have been initialized. The worse problem again is that there is no guarantee that the array index will be in range. The fact that it is not flagged as such makes me wonder if the checker disabled this warning due to too many false positives.
Resolution:
Same as #2
So, a more thorough example with extensive error checking might flow like the following program. The program isn’t pretty and could use some cleaning up/refactoring, but all the error checking exists, it passes with no checker issues, and makes the questionable code unreachable and detects a good amount of the errors. I still don’t consider floating point comparisons or VLAs good, but that should be enough to solve your question.