web-dev-qa-db-fra.com

Avertissement: "formate pas un littéral de chaîne et aucun argument de format"

Depuis la mise à niveau vers la dernière version de Xcode 3.2.1 et Snow Leopard, je reçois cet avertissement.

"format pas un littéral de chaîne et aucun argument de format"

à partir du code suivant:

NSError *error = nil;

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

}

Si errorMsgFormat est un NSString avec des spécificateurs de format (par exemple: "print me like this: %@"), quel est le problème avec l'appel ci-dessus NSLog? Et quelle est la méthode recommandée pour résoudre le problème afin que l'avertissement ne soit pas généré?

109
Alexi Groove

Etes-vous emboîté vos crochets correctement? Je ne pense pas que NSLog() aime prendre un seul argument, et c'est ce que vous le transmettez. En outre, il fait déjà la mise en forme pour vous. Pourquoi ne pas simplement faire ça?

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

Ou bien, puisque vous dites que errorMsgFormat est une chaîne de format avec un seul espace réservé, essayez-vous de le faire?

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

Xcode se plaint parce que c'est un problème de sécurité.

Voici un code similaire au vôtre:

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

Cette dernière instruction NSLog va exécuter l'équivalent de ceci:

NSLog(@"Jon Hess %@");

Cela va amener NSLog à rechercher un argument de chaîne supplémentaire, mais il n'y en a pas. En raison du fonctionnement du langage C, il va ramasser un pointeur de mémoire aléatoire de la pile et essayer de le traiter comme une chaîne NSString. Cela plantera probablement votre programme. Maintenant, vos chaînes ne contiennent probablement pas% @, mais elles le seront peut-être un jour. Vous devez toujours utiliser une chaîne de format avec les données que vous contrôlez explicitement comme premier argument des fonctions prenant des chaînes de format (printf, scanf, NSLog, - [NSString stringWithFormat:], ...).

Comme Otto le fait remarquer, vous devriez probablement faire quelque chose comme:

NSLog(errorMsgFormat, error, [error userInfo]);
157
Jon Hess

Réponse finale: Comme Jon Hess l’a dit, c’est un problème de sécurité car vous passez une chaîne WHATEVER à une fonction qui attend une chaîne de format. Autrement dit, tous les spécificateurs de format seront évalués dans la chaîne. S'il n'y en a pas, génial, mais s'il y en a, de mauvaises choses pourraient arriver.

La bonne chose à faire est d'utiliser directement une chaîne de formatage, par exemple

NSLog(@"%@", myNSString);

Ainsi, même s'il existe des spécificateurs de format dans myNSString, ils ne sont pas évalués par NSLog.

38
Alex Whittemore

Je ne recommande pas particulièrement cela, car l'avertissement IS est un véritable avertissement .. Dans une utilisation dynamique de la langue, il est possible de faire fonctionner les choses à la chaîne (c'est-à-dire insérer de nouvelles informations ou même bloquer le programme) .. Cependant, il est possible de forcer la suppression si vous SAVEZ que cela devrait être ainsi et que vous ne voulez vraiment pas en être averti ..

#pragma GCC diagnostic ignored "-Wformat-security"

Je dirais à GCC d'ignorer temporairement l'avertissement de compilation. Encore une fois, cela ne résout rien, mais il peut arriver que vous ne trouviez pas le meilleur moyen de résoudre le problème.

EDIT: A partir de Clang, le pragma a changé. Voir ceci: https://stackoverflow.com/a/17322337/3937

13
Qrikko

Je viens de passer un néant pour annuler les avertissements, peut-être que cela fonctionnerait pour vous?

NSLog (myString, nil);

10
Martytoof

Le moyen le plus rapide de résoudre ce problème consiste à ajouter @"%@", comme premier argument de votre appel NSLog, c.-à-d.,

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

Cependant, vous devriez probablement considérer la réponse de Seize Otto.

10
Anthony Cramp

Si vous souhaitez vous débarrasser une fois pour toutes de l'avertissement "format pas un littéral de chaîne et pas d'arguments de format", vous pouvez désactiver le paramètre d'avertissement GCC "Appels de type vers printf/scanf" (GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = NO) dans les paramètres de construction de votre cible.

3
aldi

FWIW, cela s’applique également à l’iPhone dev. Je code avec le SDK 3.1.3 et j'ai la même erreur avec le même problème (imbrication de stringWithFormat dans NSLog ()). Sixten et Jon sont sur l'argent.

2
Pettiross

NSLog () attend une chaîne de format, ce qui est transmis est simplement une chaîne. Vous n'avez pas besoin d'utiliser stringWithFormat :, vous pouvez simplement faire:

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

Et cela ferait disparaître l'avertissement.

2
Elfred

Le simple fait d'informer quiconque d'utiliser appendFormat sur NSMutableString peut également provoquer l'apparition de cet avertissement si vous essayez de transmettre une chaîne mise en forme de la manière suivante:

NSMutableString *csv = [NSMutableString stringWithString:@""];
NSString *csvAddition = [NSString stringWithFormat:@"%@",WHATEVERYOUAREPUTTINGINYOURSTRING];
[csv appendFormat:csvAddition];

Donc, pour éviter cet avertissement, transformez ce qui précède en ceci:

NSMutableString *csv = [NSMutableString stringWithString:@""];
[csv appendFormat:@"%@",WHATEVERYOUAREPUTTINGINYOURSTRING];

Plus concis et plus sécurisé. Prendre plaisir!

0
ColossalChris