경고 : "문자열 리터럴이 아니고 형식 인수가없는 형식"


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()당신이 그것을 전달하고있는 하나의 논쟁만을 취하는 것을 좋아하지 않는다고 생각 합니다. 또한 이미 서식을 지정합니다. 왜 이렇게하지 않습니까?

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

또는 errorMsgFormat하나의 자리 표시자가있는 형식 문자열 이라고 말 했으므로 이렇게 하시겠습니까?

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

14
"NSLog ()는 하나의 인수 만 취하는 것을 좋아하지 않는다고 생각합니다" NSLog()는 형식 문자열에 형식 지정자가없는 경우 하나의 인수를 사용할 수 있습니다.
user102008 2011 년

형식 문자열에서 사용되지 않는 다른 경고 데이터 인수를 제공합니다.
hasan 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가 하나 이상의 문자열 인수를 찾게 될 것이지만 하나는 없습니다. C 언어가 작동하는 방식 때문에 스택에서 임의의 가비지 포인터를 선택하여 NSString처럼 처리하려고합니다. 이로 인해 프로그램이 충돌 할 가능성이 높습니다. 이제 문자열에 % @가 없을 수도 있지만 언젠가는 그럴 수도 있습니다. 항상 형식 문자열 (printf, scanf, NSLog,-[NSString stringWithFormat :], ...)을 사용하는 함수에 대한 첫 번째 인수로 명시 적으로 제어하는 ​​데이터가있는 형식 문자열을 사용해야합니다.

Otto가 지적했듯이 다음과 같은 작업을 수행해야합니다.

NSLog(errorMsgFormat, error, [error userInfo]);

17
그리고 다시 한번, 자세하고 좋은 답변이 길가로 떨어집니다. 자세히 설명 해주셔서 감사합니다. 나는 이것을 결코 이해하지 못했을 것입니다.
Dan Rosenstark

38

최종 답변 : Jon Hess가 말했듯이 형식 문자열이 필요한 함수에 WHATEVER 문자열을 전달하기 때문에 보안 문제입니다. 즉, 어떤 문자열에서든 모든 형식 지정자를 평가합니다. 굉장하지만 만약 있다면 나쁜 일이 일어날 수 있습니다.

올바른 방법은 형식 문자열을 직접 사용하는 것입니다.

NSLog(@"%@", myNSString);

이렇게하면 myNSString에 형식 지정자가 있어도 NSLog에 의해 평가되지 않습니다.


13

나는 이것을 사용하는 것을 특히 추천하지 않는다. 왜냐하면 경고는 진짜 경고이기 때문이다. 언어를 동적으로 사용하면 런타임에서 문자열에 작업을 수행 할 수있다. 이렇게해야한다는 것을 알고 있고 경고를 받고 싶지 않다면 강제로 억압합니다.

#pragma GCC diagnostic ignored "-Wformat-security"

GCC에게 컴파일 경고를 일시적으로 무시하라고 지시합니다. 다시 말하지만 문제를 실제로 해결하는 좋은 방법을 찾을 수없는 경우도 있습니다.

편집 : clang에서 pragma가 변경되었습니다. 참조 : https://stackoverflow.com/a/17322337/3937


10

이를 수정하는 가장 빠른 방법 @"%@",NSLog호출에 첫 번째 인수로 추가하는 것입니다 .

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

그러나 아마도 Sixteen Otto의 대답을 고려해야합니다.


10

경고를 무효화하기 위해 방금 전무를 전달했습니다. 아마도 그게 당신에게 도움이 될까요?

NSLog (myString, nil);


5
누군가 두 번째 paramente가 경고를 해결할 때 nil을 전달하는 이유를 설명 할 수 있습니까?
cprcrack

1
nil을 전달하는 것은 명시 적이지만 두 번째 매개 변수가없는 것은 아닙니다. 집을 떠날 때 벽난로에 불이 들어오지 않았다고 가정하거나 그렇지 않은지 확인할 수 있습니다. 벽난로를 거의 사용하지 않기 때문에 일반적으로 아무 일도 일어나지 않지만 집이 불에 타는 경우는 한 번입니다.

1
@SoldOutActivist 도움이되지 않습니다. 여기에서 분명하지 않은 요점은 (C 배경에서 오지 않은 사람에게) 명시 적 nil 전달과 아무것도 전달하지 않는 것 사이의 동작 차이이며 귀하의 의견은 그것을 설명하지 않습니다.
Mark Amery 2013

Fine : 가변 개수의 인수를 허용 할 수있는 모든 Obj-C 메서드는 명시 적으로 nil로 종료되어야합니다. 아무것도 전달하지 않는 것은 nil을 전달하는 것과 다릅니다. Obj-C와 함께 시간을 보내면 이것을 계속해서 보게 될 것입니다. 배열을 구축하는 것이 가장 일반적입니다.

3
이것은 컴파일러 경고를 멈출 수 있지만 Jon Hess설명 한 근본적인 문제는 여전히 존재합니다.에 형식 지정자가 둘 이상 있으면 myString첫 번째는 괜찮지 만 두 번째는 스택에서 쓰레기를 가져옵니다. 의 대체 목록 NSLog()은 종료 되지 않습니다 nil . @Sold. 인수 목록의 길이를 알아내는 데는 두 가지 옵션이 있습니다. 센티넬 값 또는 사용되는 항목 printf()및 패밀리-숫자 계산을 허용하는 또 다른 인수입니다 (예 : 형식 지정자 계산).
jscs

3

"문자열 리터럴이 아니고 형식 인수가없는 형식"경고를 한 번에 없애려면 대상의 빌드 설정에서 GCC 경고 설정 "printf / scanf에 대한 Typecheck 호출"(GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = NO)을 비활성화 할 수 있습니다.


5
그러면 경고가 사라지지만 응용 프로그램의 근본적인 결함을 수정하는 데는 아무런 조치도 취하지 않습니다. 경고를 무음으로 설정하면 단순히 사용자가 입력 한 데이터 (또는이 경우 CoreData에서 생성 된 오류 메시지)를 기반으로 애플리케이션을 중단시킬 수있는 잠재적 버그를 무시하는 것입니다. 경고를 발생시키는 소스 코드 내의 버그를 제거하려면이 질문의 다른 답변 중 일부를 따르는 것이 좋습니다.
Christopher Fairbairn

2
사실 ... 그래서 "해결"대신 "경고 제거"를 게시했습니다.
aldi

나는 uthash 라이브러리가 utstring_printf 함수에 대한 호출 에이 경고를 트리거하는 경우를 만났으므로 경고가 잘못된 상황에서 유용합니다.
alfwatt

2

NSLog ()는 형식 문자열을 예상하며 전달되는 것은 문자열입니다. stringWithFormat :을 사용할 필요는 없으며 다음과 같이 할 수 있습니다.

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

그러면 경고가 사라집니다.


2

FWIW, 이것은 iPhone dev에도 적용됩니다. 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])
마크 Amery
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.