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


110

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

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

次のコードから:

NSError *error = nil;

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

}

場合errorMsgFormatであるNSString書式指定子を持つが(例えば:"print me like this: %@")、上記の何が問題になっているNSLogコール?そして、警告が生成されないようにそれを修正するための推奨される方法は何ですか?

回答:


113

ブラケットを正しくネストしていますか?NSLog()引数を1つだけ取るのは好きではないと思います。また、フォーマットはすでに行われています。なぜこれをしないのですか?

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

または、errorMsgFormat単一のプレースホルダーを持つフォーマット文字列であると言うので、これを実行しようとしていますか?

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

14
NSLog()フォーマット文字列にフォーマット指定子が含まれていない場合、「NSLog()は引数を1つだけ取るのが好きだとは思わない」は1つの引数を取ることができます。
user102008年

書式文字列で使用されていない別の警告データ引数を与えます。
ハサン:2014

157

これはセキュリティ上の問題なので、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]);

17
そしてもう一度、SOで、詳細で良い答えは道端に落ちます。これを完全に説明してくれてありがとう。私はこれを理解できなかったでしょう。
Dan Rosenstark、2010

38

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

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

NSLog(@"%@", myNSString);

このように、myNSStringにフォーマット指定子があったとしても、それらはNSLogによって評価されません。


13

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

#pragma GCC diagnostic ignored "-Wformat-security"

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

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


10

それを修正する最も速い方法は、@"%@",あなたのNSLog呼び出しの最初の引数として追加することです、すなわち、

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

ただし、おそらく16オットーの答えを検討する必要があります。


10

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

NSLog(myString、nil);


5
2番目のパラメータが警告を解決するときにnilを渡す理由を誰かが説明できますか?
cprcrack

1
nilを渡すことは明示的ですが、2番目のパラメーターがないことが明示的ではありません。あなたが家を出たときにあなたの暖炉が火がつけられていなかったと仮定することができます、またはそれが火がつけられなかったことを確認することができます。暖炉はめったに使用しないため、通常は何も起こりませんが、家が焼け落ちるのはそのときです。

1
@SoldOutActivist役に立たない。ここで(Cのバックグラウンドを持たない人にとって)自明ではない点は、明示的なnilを渡すことと何も渡さないことの動作の違いであり、コメントはそれを説明していません。
マークアメリー

細かい:可変数の引数を受け入れることができるすべてのObj-Cメソッドは、明示的にnilで終了する必要があります。何も渡さないことは、nilを渡すことと同じではありません。Obj-Cでいつでも過ごすと、これが何度も見られます。アレイの構築が最も一般的です。

3
これによりコンパイラの警告が停止する可能性がありますが、Jon Hessによって説明された根本的な問題が依然として存在します-に複数のフォーマット指定子があるmyString場合、最初の指定子は問題ありませんが、2番目はスタックからゴミを拾います。の置換リストが@Soldで終了することNSLog()はありません nil。引数のリストの長さを把握するための2つのオプションがあります:センチネル値、またはprintf()ファミリで使用されるもの-数の計算を可能にする別の引数(たとえば、フォーマット指定子を数えることにより)。
jscs 2013

3

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


5
これは警告を沈黙させますが、アプリケーション内の根本的な欠陥を修正することは何もしません。警告を黙らせることで、ユーザーが入力したデータ(この場合はCoreDataが生成したエラーメッセージ)だけに基づいてアプリケーションをクラッシュさせる可能性のある潜在的なバグを無視します。警告が表示される原因となっているソースコード内のバグを削除するには、この質問内の他の回答のいくつかに従うことをお勧めします。
クリストファーフェアバーン

2
真実...それが私が「解決」の代わりに「警告を取り除く」を投稿した理由です。
アルディ2009

私は、uthashライブラリがutstring_printf関数の呼び出しでこの警告をトリガーしていたので、警告が間違っている状況で役立ちます。
alfwatt 2013

2

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

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

そしてそれは警告を消し去るでしょう。


2

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


0

appendFormaton NSMutableStringの使用を誰かに知らせるだけでも、次のようにフォーマットされた文字列を渡そうとすると、この警告が表示される可能性があります。

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

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

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

より簡潔で安全です。楽しい!


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

1
使用stringWithFormatできるのに、ここでの使用は冗長ですNSLog(@"%@ %@, %@", errorMsgFormat, error, [error userInfo])
Mark Amery 2013年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.