110

最新の Xcode 3.2.1 と Snow Leopard にアップグレードしてから、警告が表示されるようになりました

「フォーマットは文字列リテラルではなく、フォーマット引数はありません」

次のコードから:

NSError *error = nil;

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

}

errorMsgFormatNSStringフォーマット指定子 (例: ) を含む場合、上記の呼び出し"print me like this: %@"の何が問題になっていますか? NSLogまた、警告が生成されないように修正するための推奨される方法は何ですか?

4

11 に答える 11

158

これはセキュリティ上の問題であるため、Xcode は不平を言っています。

あなたに似たコードは次のとおりです。

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

その最後の NSLog ステートメントは、これと同等のものを実行します。

NSLog(@"Jon Hess %@");

これにより、NSLog はもう 1 つの文字列引数を探しますが、1 つもありません。C 言語の動作方法により、スタックからランダムなガベージ ポインターを取得し、それを NSString のように処理しようとします。これにより、プログラムがクラッシュする可能性が高くなります。現在、文字列にはおそらく %@ が含まれていませんが、いつか含まれる可能性があります。フォーマット文字列を受け取る関数 (printf、scanf、NSLog、-[NSString stringWithFormat:]、...) の最初の引数として、明示的に制御するデータを含むフォーマット文字列を常に使用する必要があります。

Otto が指摘しているように、おそらく次のようにする必要があります。

NSLog(errorMsgFormat, error, [error userInfo]);
于 2009-11-05T04:16:06.820 に答える
38

最終的な答え: Jon Hess が言ったように、フォーマット文字列を期待する関数に WHATEVER 文字列を渡すため、これはセキュリティ上の問題です。つまり、文字列内のすべての書式指定子を評価します。なければ素晴らしいが、あると悪いことが起こる可能性がある。

したがって、適切なことは、フォーマット文字列を直接使用することです。たとえば、

NSLog(@"%@", myNSString);

そうすれば、myNSString に書式指定子があっても、NSLog によって評価されません。

于 2010-08-18T00:01:43.920 に答える
13

警告は実際の警告であるため、これを使用することは特にお勧めしません..言語の動的な使用では、文字列に対して実行時に何かを行うことができます(つまり、新しい情報を挿入したり、プログラムをクラッシュさせたりすることさえあります)..しかし、それは可能ですこのようにすべきだとわかっていて、本当に警告されたくない場合は、強制的に抑制します..

#pragma GCC diagnostic ignored "-Wformat-security"

コンパイルの警告を一時的に無視するように GCC に指示します。やはり何も解決しませんが、実際に問題を解決する良い方法が見つからない場合があります。

編集: clang の時点で、プラグマが変更されました。これを参照してください: https://stackoverflow.com/a/17322337/3937

于 2011-05-09T20:28:42.270 に答える
10

それを修正する最も簡単な方法は@"%@",、呼び出しに最初の引数として追加することNSLogです。つまり、

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

ただし、おそらくSixteen Ottoの回答を検討する必要があります.

于 2009-11-05T04:01:13.137 に答える
10

警告を無効にするために nil を渡したところですが、それでうまくいくでしょうか?

NSLog(myString, nil);

于 2010-04-07T16:48:58.283 に答える
3

「文字列リテラルではなくフォーマット引数なしでフォーマットする」という警告を完全に取り除きたい場合は、ターゲットのビルド設定でGCC警告設定「printf / scanfへのTypecheck呼び出し」(GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = NO)を無効にすることができます。

于 2009-11-19T15:57:28.593 に答える
2

FWIW、これは iPhone dev にも当てはまります。私は 3.1.3 SDK に対してコーディングしていますが、同じ問題 (NSLog() 内に stringWithFormat をネスト) で同じエラーが発生しました。Sixten と Jon は儲かっています。

于 2010-05-19T17:47:00.720 に答える
2

NSLog() はフォーマット文字列を想定しています。渡されるのは単なる文字列です。stringWithFormat: を使用する必要はありません。

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

そして、それは警告を消すでしょう。

于 2009-11-05T04:06:00.820 に答える
0

on NSMutableStringを使用していることを誰かに知らせるだけappendFormatでも、次のように書式設定された文字列を渡そうとすると、この警告が表示される可能性があります。

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

したがって、この警告を回避するには、上記を次のように変更します。

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

より簡潔に、より安全に。楽しみ!

于 2015-09-10T21:15:49.213 に答える
-2
NSLog(@"%@ %@, %@", 
       errorMsgFormat, 
       error, 
       [error userInfo]); 
于 2013-03-15T08:05:04.210 に答える