ios - Objective-C: "format string is not a string literal (potentially insecure)" warning with macro -


i'm using macro simplify returning localised strings, so:

#define getlocalstr(key, ...) \     [nsstring stringwithformat:[[nsbundle mainbundle] localizedstringforkey:key value:@"" table:nil], ##__va_args__] 

basically, if have entry in localisation strings file "name" = "my name %@";, calling

getlocalstr( @"name", @"foo" ); 

will return nsstring @"my name foo"

when run however, like:

nsstring * str = getlocalstr( @"name", @"foo" ); 

i "format string not string literal" warning. following advice of other answers on warning , replacing with:

nsstring * str = [nsstring stringwithformat:@"%@", getlocalstr( @"name", @"foo" )]; 

i still warning, , besides, kind of defeats point of macro making life easier.

how can rid of warning short of wrapping getlocalstr calls in #pragma suppressors?

edit 27/08

after running through crd's answer , doing more tests, seems made bad assumption on error. clarify:

localisation strings file:

"testnoargs" = "hello world"; "testargs" = "hello world %@"; 

code:

nsstring * str1 = getlocalstr( @"testnoargs" ); // gives warning nsstring * str2 = getlocalstr( @"testargs", @"foo" ); // doesn't give warning 

the majority of translations take no arguments, , ones giving warning, didn't make connection until read through crd's answer.

i changed single macro two, so:

#define getlocalstrnoargs(key) \     [[nsbundle mainbundle] localizedstringforkey:key value:@"" table:nil]  #define getlocalstrargs(key, ...) \     [nsstring stringwithformat:[[nsbundle mainbundle] localizedstringforkey:key value:@"" table:nil], ##__va_args__] 

and if call each 1 separately, there's no warnings.

i'd getlocalstr expand either getlocalstrnoargs or getlocalstrargs depending on if arguments passed or not, far i've been having no luck (macros not strong suit :d).

i'm using sizeof(#__va_args__) determine if there's arguments passed - stringifys arguments, , if size 1, it's empty (i.e. `\0'). perhaps it's not ideal method, seems work.

if rewrite getlocalstr macro to:

#define getlocalstr(key,...) (sizeof(#__va_args__) == 1) ? getlocalstrnoargs(key) : getlocalstrargs(key,##__va_args__) 

i can use it, still warnings everywhere it's used , there's no arguments passed, while

#define getlocalstr( key,...)               \     #if ( sizeof(#__va_args__) == 1 )       \         getlocalstrnoargs(key)              \     #else                                   \         getlocalstrargs(key,##__va_args__) 

won't compile. how can getlocalstr macro expand properly?

the clang & gcc compilers check format strings , supplied arguments conform, cannot if format string not literal - hence error message see obtaining format string bundle.

to address issue there attribute, format_arg(n) (docs), mark functions take format string; alter in way without changing actual format specifiers, e.g translate it; , return it. cocoa provides convenient macro ns_format_arg(n) attribute.

to fix problem need 2 things:

  1. wrap call nsbundle in function attribute specified; and

  2. change "key" include format specifiers.

second first, strings file should contain:

"name %@" = "my name %@" 

so key has same format specifiers result (if need reorder specifiers particular language use positional format specifiers).

now define simple function lookup, attributing format translation function. note mark static inline, using macro ns_inline hint compiler both inline macro expansion; static allows include in multiple files without symbol clashes:

ns_inline nsstring *localize(nsstring *string) ns_format_argument(1); nsstring *localize(nsstring *string) {    return [[nsbundle mainbundle] localizedstringforkey:string value:@"" table:nil]; } 

and macro becomes:

#define getlocalstr(key, ...) [nsstring stringwithformat:localize(key), ##__va_args__] 

now when you:

getlocalstr(@"name %@", @"foo") 

you both localised format string , format checking.

update

after greg's comment went , checked - had reproduced error , assumed down missing attribute. greg points out localizedstringforkey:value:table: has attribute, why error? had absentmindedly done in reproducing error was:

nslog( getlocalstr( @"name %@", @"foo" ) ); 

and compiler pointed @ macro definition , not line - should have spotted compiler misleading me.

so leave you? maybe you've done similar? key format string must either literal or result of function/method attributed format translating function. , don't forget, must had format specifier key above.

update 2

after additional comments need use function, rather macro, along format attribute, cocoa provides convenient ns_format_function(f,a) macro. attribute informs compiler function formatting one, value of f number of format string , a number of first argument format. gives function declaration:

nsstring *getlocalstr(nsstring *key, ...) ns_format_function(1,2); 

and definition (assuming arc):

nsstring *getlocalstr(nsstring *key, ...) {    va_list args;    va_start(args, key);    nsstring *format = [[nsbundle mainbundle] localizedstringforkey:key value:@"" table:nil];    nsstring *result = [[nsstring alloc] initwithformat:format arguments:args];    va_end (args);    return result; } 

(which same @a-live's).

uses of checked appropriately, example:

int x; ... nsstring *s1 = getlocalstr(@"name = %d", x); // ok nsstring *s2 = getlocalstr(@"name = %d");    // compile warning - more '%" conversions data arguments nsstring *s3 = getlocalstr(@"name", x);      // compile warning - data argument not used format string nsstring *s4 = getlocalstr(@"name");         // ok 

Comments

Popular posts from this blog

java - activate/deactivate sonar maven plugin by profile? -

python - TypeError: can only concatenate tuple (not "float") to tuple -

java - What is the difference between String. and String.this. ? -