Warnung: "Format kein Zeichenfolgenliteral und keine Formatargumente"

110

Seit dem Upgrade auf den neuesten Xcode 3.2.1 und Snow Leopard habe ich die Warnung erhalten

"Format kein String-Literal und keine Formatargumente"

aus dem folgenden Code:

NSError *error = nil;

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

}

Wenn errorMsgFormates sich um ein NSStringFormatformat handelt (z. B. :) "print me like this: %@", was ist mit dem obigen NSLogAufruf falsch ? Und wie kann das Problem behoben werden, damit die Warnung nicht generiert wird?

Alexi Groove
quelle

Antworten:

113

Verschachteln Sie Ihre Klammern richtig? Ich glaube nicht, dass ich NSLog()gerne nur ein Argument nehme, das ist es, woran Sie es weitergeben. Außerdem übernimmt es bereits die Formatierung für Sie. Warum nicht einfach so machen?

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

Oder errorMsgFormatversuchen Sie dies , da Sie sagen, dass es sich um eine Formatzeichenfolge mit einem einzelnen Platzhalter handelt?

NSLog(@"%@, %@", [NSString stringWithFormat:errorMsgFormat, error], 
   [error userInfo]);              
Sixten Otto
quelle
14
"Ich glaube nicht, dass NSLog () nur ein Argument akzeptiert" NSLog()kann ein Argument annehmen, wenn die Formatzeichenfolge keine Formatspezifizierer enthält.
user102008
Gibt eine weitere Warnung aus. Datenargument wird von Formatzeichenfolge nicht verwendet.
Hasan
157

Xcode beschwert sich, weil dies ein Sicherheitsproblem ist.

Hier ist ein ähnlicher Code wie Sie:

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

Diese letzte NSLog-Anweisung wird das Äquivalent dazu ausführen:

NSLog(@"Jon Hess %@");

Das wird dazu führen, dass NSLog nach einem weiteren String-Argument sucht, aber es gibt keines. Aufgrund der Funktionsweise der C-Sprache wird ein zufälliger Müllzeiger vom Stapel aufgenommen und versucht, ihn wie einen NSString zu behandeln. Dies wird höchstwahrscheinlich Ihr Programm zum Absturz bringen. Jetzt enthalten Ihre Zeichenfolgen wahrscheinlich keine% @, aber eines Tages könnten sie. Sie sollten immer eine Formatzeichenfolge mit Daten verwenden, die Sie explizit als erstes Argument für Funktionen steuern, die Formatzeichenfolgen annehmen (printf, scanf, NSLog, - [NSString stringWithFormat:], ...).

Wie Otto betont, sollten Sie wahrscheinlich nur Folgendes tun:

NSLog(errorMsgFormat, error, [error userInfo]);
Jon Hess
quelle
17
Und noch einmal auf SO fallen die detaillierten und guten Antworten auf die Strecke. DANKE, dass Sie dies vollständig erklärt haben. Ich hätte das nie herausgefunden.
Dan Rosenstark
38

Endgültige Antwort: Wie Jon Hess sagte, handelt es sich um ein Sicherheitsproblem, da Sie eine WHATEVER-Zeichenfolge an eine Funktion übergeben, die eine Formatzeichenfolge erwartet. Das heißt, es werden alle Formatbezeichner INNERHALB der beliebigen Zeichenfolge ausgewertet. Wenn es keine gibt, großartig, aber wenn es welche gibt, könnten schlimme Dinge passieren.

Das Richtige ist also, beispielsweise eine Formatzeichenfolge direkt zu verwenden

NSLog(@"%@", myNSString);

Auf diese Weise werden Formatspezifizierer, selbst wenn sie in myNSString vorhanden sind, nicht von NSLog ausgewertet.

Alex Whittemore
quelle
13

Ich empfehle dies nicht besonders, da die Warnung eine echte Warnung ist. Bei einer dynamischen Verwendung der Sprache ist es möglich, Dinge zur Laufzeit mit der Zeichenfolge zu tun (dh neue Informationen einzufügen oder sogar das Programm zum Absturz zu bringen). Dies ist jedoch möglich zu unterdrücken erzwingen, wenn Sie wissen, dass es so sein sollte und Sie wirklich nicht davor gewarnt werden wollen ..

#pragma GCC diagnostic ignored "-Wformat-security"

Würde GCC anweisen, die Kompilierungswarnung vorübergehend zu ignorieren. Wiederum löst es nichts, aber es kann vorkommen, dass Sie keinen guten Weg finden, um das Problem tatsächlich zu beheben.

EDIT: Seit dem Klirren hat sich das Pragma geändert. Siehe hierzu: https://stackoverflow.com/a/17322337/3937

Qrikko
quelle
10

Der schnellste Weg, dies zu beheben, besteht darin @"%@",, Ihrem NSLogAnruf als erstes Argument hinzuzufügen , d. H.

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

Allerdings sollten Sie wahrscheinlich die Antwort von Sechzehn Otto in Betracht ziehen.

Anthony Cramp
quelle
10

Ich habe gerade eine Null übergeben, um die Warnungen zu negieren. Vielleicht würde das für Sie funktionieren?

NSLog (myString, nil);

Martytoof
quelle
5
Kann jemand erklären, WARUM das Bestehen von Null als zweites Paramente die Warnung löst?
cprcrack
1
Das Übergeben von nil ist explizit, das Fehlen eines zweiten Parameters jedoch nicht. Sie können davon ausgehen, dass Ihr Kamin beim Verlassen des Hauses nicht beleuchtet war, oder Sie können sicherstellen, dass dies nicht der Fall war. Während normalerweise nichts passiert, weil Sie Ihren Kamin selten benutzen, brennt Ihr Haus einmal nieder.
1
@SoldOutActivist Nicht hilfreich. Der nicht offensichtliche Punkt hier (für jemanden, der nicht aus einem C-Hintergrund stammt) ist, was der Unterschied im Verhalten zwischen dem Übergeben einer expliziten Null und dem Übergeben von nichts ist, und Ihr Kommentar erklärt dies nicht.
Mark Amery
Gut: Alle Obj-C-Methoden, die eine variable Anzahl von Argumenten akzeptieren können, müssen explizit mit Null abgeschlossen werden. Nichts zu bestehen ist nicht dasselbe wie nichts zu bestehen. Verbringen Sie jederzeit mit Obj-C und Sie werden dies immer wieder sehen. Das Erstellen von Arrays ist am häufigsten.
3
Dies kann die Compiler-Warnung stoppen, aber das zugrunde liegende Problem, das von Jon Hess erklärt wurde , besteht weiterhin - wenn mehr als ein Formatbezeichner vorhanden ist myString, ist der erste in Ordnung, aber der zweite nimmt Müll vom Stapel auf. Die Substitutionsliste in NSLog()wird niemals beendet nil , @Sold. Es gibt zwei Möglichkeiten, um herauszufinden, wie lang die Liste der Argumente ist: ein Sentinel-Wert oder was in printf()und in der Familie verwendet wird - ein weiteres Argument, das die Berechnung der Anzahl ermöglicht (z. B. durch Zählen der Formatspezifizierer).
Jscs
3

Wenn Sie die Warnung "Format kein Zeichenfolgenliteral und keine Formatargumente" ein für alle Mal entfernen möchten, können Sie die GCC-Warneinstellung "Typecheck Calls to printf / scanf" (GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = NO) in den Build-Einstellungen Ihres Ziels deaktivieren.

Aldi
quelle
5
Dadurch wird die Warnung stummgeschaltet, der zugrunde liegende Fehler in Ihrer Anwendung wird jedoch nicht behoben. Wenn Sie die Warnung stumm schalten, ignorieren Sie einen potenziellen Fehler, der Ihre Anwendung zum Absturz bringen könnte, basierend auf den vom Benutzer eingegebenen Daten (oder in diesem Fall der von CoreData generierten Fehlermeldung). Es ist besser, einige der anderen Antworten in dieser Frage zu befolgen, um den Fehler im Quellcode zu beseitigen, durch den die Warnung angezeigt wird.
Christopher Fairbairn
2
Richtig ... Deshalb habe ich "die Warnung loswerden" anstatt "lösen" gepostet.
Aldi
Ich bin auf einen Fall gestoßen, in dem die Uthash-Bibliothek diese Warnung bei Aufrufen der Funktion utstring_printf auslöste. Dies ist daher in Situationen nützlich, in denen die Warnung falsch ist.
Alfwatt
2

NSLog () erwartet eine Formatzeichenfolge. Was übergeben wird, ist nur eine Zeichenfolge. Sie müssen stringWithFormat: nicht verwenden. Sie können einfach Folgendes tun:

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

Und das würde die Warnung verschwinden lassen.

Elfred
quelle
2

FWIW, dies gilt auch für iPhone-Entwickler. Ich codiere gegen das 3.1.3 SDK und habe denselben Fehler mit demselben Problem erhalten (Verschachtelung von stringWithFormat in NSLog ()). Sixten und Jon sind auf dem Geld.

Pettiross
quelle
0

appendFormatWenn Sie nur jemanden über die Verwendung von on NSMutableString informieren, kann diese Warnung auch angezeigt werden, wenn Sie versuchen, eine formatierte Zeichenfolge wie folgt zu übergeben:

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

Um diese Warnung zu vermeiden, gehen Sie wie folgt vor:

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

Prägnanter und sicherer. Genießen!

ColossalChris
quelle
-2
NSLog(@"%@ %@, %@", 
       errorMsgFormat, 
       error, 
       [error userInfo]); 
ILYA2606
quelle
1
Die Verwendung stringWithFormatist hier überflüssig, wenn Sie nur tun könntenNSLog(@"%@ %@, %@", errorMsgFormat, error, [error userInfo])
Mark Amery