Wednesday, July 29, 2009

format not a string literal and no format arguments

Some time ago GCC started producing warnings like this:

warning: format not a string literal and no format arguments

What does this mean? GCC is saying that a function in printf style has a format string that it cannot check matches the format arguments. Here is some common code GLib code that causes this error:

GError *error = ...;
g_error(error->message);


Why is this a problem? As error->message cannot be checked it may contain a printf flag sequence, e.g. "Invalid data: 'g^y#%s'" (i.e. %s) that would cause run-time to try and access a non-existent argument. It could be worse and the format string could be user-input that is attempting to exploit your program.

So the solution is to always use a string literal for formatting like this:

g_error("%s", error->message);

11 comments:

Andrew Walton said...

Might want to add a note about the new _literal() functions which were added to ease the problems caused by this (e.g. g_set_error_literal()).

Simply replacing the former call g_set_error (error, domain, code, message) with g_set_error_literal (error, domain, code, message) will do the trick without having to sprinkle `"%s",` around (but I guess it might amount to a tiny bit more typing ;).

Götz Waschk said...

Mandriva has this warning upgraded to an error in the default CFLAGS since Mandriva 2009.1 .

Anonymous said...

I believe Debian also considers it a 'required to be fixed' error, although their process for ensuring this is slightly different (they don't make the build break, but their rpmlint-equivalent moans about it).

manu said...

If you feel the need to explain this, perhaps the message is not very clear. It would be nice if the message were clear enough, so no explanation would be needed. Would you care to file a bug report in GCC and suggest a better wording (one or various)? Add manu at gcc dot gnu dot org to the CC list. GCC could also print the suggestion of using ("%s", format) as a one time note.

Thanks,

Manuel.

Anonymous said...

Now even simple calls like printf(szString) are getting the gcc warning "format not a string literal and no format arguments". What is going on here?

Robert Ancell said...

Anonymous: Yes, and this is correct. szString could contain '%s' which would cause your program to crash. Change it to:
printf("%s", szString);

Anonymous said...

But Bob, szString is controlled by me. It has a clearly defined content. Should thousands of coders change their output of simple string buffers from

printf(szString) to
printf("%s", szString)

Why is printf not assuming that it should just print the buffer if no additional parameter has been given?

Robert Ancell said...

Anonymous, Unfortunately printf does not know how many arguments it has, that is a limitation of C.

Anonymous said...

How would I fix this?
NSString *totalscore = [NSString stringWithFormat:score.text];

Jim said...

Actually Anonymous, instead of

printf(szString);

consider

fputs(szString, stdout);

(You can't use puts() because it appends a newline.)

Anonymous said...

Thanks