views:

8348

answers:

10

Since upgrading to the latest XCode 3.2.1 and SnowLeopard, I've been getting the warning,

"format not a string literal and no format arguments"

on the following:

NSError *error = nil;

if (![self.managedObjectContext save:&error]) 
{
    NSLog([NSString stringWithFormat:@"%@ %@, %@", 
       errorMsgFormat, 
       error, 
       [error userInfo]]);  

}

If 'errorMsgFormat' is an NSString with format specifiers (eg: "print me like this: %@"), what is wrong with the above NSLog statement? And what is the recommended way to fix it so that the warning isn't generated?

+26  A: 

Are you nesting your brackets correctly? I don't think NSLog() likes taking only one argument, which is what you're passing it. Also, it already does the formatting for you. Why not just do this?

NSLog(@"%@ %@, %@", 
   errorMsgFormat, 
   error, 
   [error userInfo]);

Or, since you say errorMsgFormat is a format string with a single placeholder, are you trying to do this?

NSLog(@"%@, %@", [NSString stringWithFormat:errorMsgFormat, error], 
   [error userInfo]);
Sixten Otto
+1  A: 

Quickest way to fix it would be to add @"%@", as the first argument to your NSLog call, i.e.,

NSLog(@"%@", [NSString stringWithFormat: ....]);

Though, you should probably consider Sixteen Otto's answer.

Anthony Cramp
A: 

NSLog() expects a format string, what is getting passed in is just a string. You do not need to use stringWithFormat:, you can just do:

NSLog(@"%@ %@, %@", errorMsgFormat, error, [error userInfo])

And that would make the warning go away.

Elfred
+26  A: 

Xcode is complaining because this is a security problem.

Here's code similar to yours:

NSString *nameFormat = @"%@ %@";
NSString *firstName = @"Jon";
NSString *lastName = @"Hess %@";
NSString *name = [NSString stringWithFormat:nameFormat, firstName, lastName];
NSLog(name);

That last NSLog statement is going to be executing the equivalent of this:

NSLog(@"Jon Hess %@");

That's going to cause NSLog to look for one more string argument, but there isn't one. Because of the way the C language works, it's going to pick up some random garbage pointer from the stack and try to treat it like an NSString. This will most likely crash your program. Now your strings probably don't have %@'s in them, but some day they might. You should always use a format string with data you explicitly control as the first argument to functions that take format strings (printf, scanf, NSLog, -[NSString stringWithFormat:], ...).

As Otto points out, you should probably just do something like:

NSLog(errorMsgFormat, error, [error userInfo]);
Jon Hess
And once again on SO, the detailed and good answers fall to the wayside. THANK YOU for explaining this fully. I would've never figured this out.
Yar
A: 

If you want get rid of the warning "format not a string literal and no format arguments" once and for all, you can disable the GCC warning setting "Typecheck Calls to printf/scanf" (GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = NO) in your target's build settings.

aldi
That will silence the warning, but it won't do anything to fix the underlying flaw within your application. By silencing the warning you're ignoring a potential bug that could crash your application based simply on the data entered by the user (or in this case the error message generated by CoreData). It would be better to follow some of the other answers within this question to remove the bug within the source code that is causing the warning to appear.
Christopher Fairbairn
True... That's why I posted "get rid of the warning" instead of "solve".
aldi
A: 

THANKS! IT WORKED WITH

"Typecheck Calls to printf/scanf" (GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = NO)

tippy
+2  A: 

I've just been passing a nil to negate the warnings, maybe that would work for you?

NSLog(myString, nil);

Martytoof
+1  A: 

FWIW, this applies to iPhone dev as well. I'm coding against the 3.1.3 SDK, and got the same error with the same problem (nesting stringWithFormat inside NSLog()). Sixten and Jon are on the money.

Pettiross
+3  A: 

Final answer: As Jon Hess said, it's a security issue because you're passing a WHATEVER string to a function expecting a format string. That is, it'll evaluate all format specifiers WITHIN the whatever string. If there aren't any, awesome, but if there are, bad things could happen.

The proper thing to do, then, is USE a format string directly, for example

NSLog(@"%@", myNSString);

That way, even if there are format specifiers in myNSString, they don't get evaluated by NSLog.

Alex Whittemore
A: 

I get that error message for the following actions:

- (IBAction)showNameLabelOne:(id)sender {   
    NSString *title = [sender titleForState:UIControlStateNormal];
    NSString *newText = [[NSString alloc] initWithFormat:title];
    myLabelOne.text = newText; 
    [newText release];
}

- (IBAction)showNameLabelTwo:(id)sender {   
    NSString *title = [sender titleForState:UIControlStateNormal];
    NSString *newText = [[NSString alloc] initWithFormat:title];
    myLabelTwo.text = newText; 
    [newText release];
}

- (IBAction)showNameLabelTHree:(id)sender {   
    NSString *title = [sender titleForState:UIControlStateNormal];
    NSString *newText = [[NSString alloc] initWithFormat:title];
    myLabelThree.text = newText; 
    [newText release];
}
RyeMAC3

related questions