I basically have a wrapper around strftime() and compilation with -Werror=format-nonliteral fails when the wrapper wants to call strftime, because "format not a string literal, format string not checked". The code in question looks like this: #include<time.h> #include<stdio.h> #define SIZE 256 size_t my_strftime(char *s, size_t max, const char *fmt, const struct tm *tm) { size_t ret; ret = strftime(s, max, fmt, tm); return ret; } int main () { char s[SIZE]; time_t curtime; struct tm* loctime; curtime = time(NULL); loctime = localtime (&curtime); my_strftime(s, SIZE, "Hello %A", loctime); printf("%s", s); return 0; } muelli@bigbox /tmp $ gcc -v -save-temp -Wformat -Wformat-nonliteral -Werror=format-nonliteral -o mystrftime{,.c} Using built-in specs. gcc: unrecognized option '-save-temp' Target: x86_64-redhat-linux Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-languages=c,c++,objc,obj-c++,java,fortran,ada --enable-java-awt=gtk --disable-dssi --enable-plugin --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-1.5.0.0/jre --enable-libgcj-multifile --enable-java-maintainer-mode --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --disable-libjava-multilib --with-cpu=generic --build=x86_64-redhat-linux Thread model: posix gcc version 4.3.2 20081105 (Red Hat 4.3.2-7) (GCC) COLLECT_GCC_OPTIONS='-v' '-save-temp' '-Wformat' '-Wformat-nonliteral' '-Werror=format-nonliteral' '-o' 'mystrftime' '-mtune=generic' /usr/libexec/gcc/x86_64-redhat-linux/4.3.2/cc1 -quiet -v mystrftime.c -quiet -dumpbase mystrftime.c -mtune=generic -auxbase mystrftime -Wformat -Wformat-nonliteral -Werror=format-nonliteral -version -o /tmp/ccznk3Wo.s ignoring nonexistent directory "/usr/lib/gcc/x86_64-redhat-linux/4.3.2/include-fixed" ignoring nonexistent directory "/usr/lib/gcc/x86_64-redhat-linux/4.3.2/../../../../x86_64-redhat-linux/include" #include "..." search starts here: #include <...> search starts here: /usr/local/include /usr/lib/gcc/x86_64-redhat-linux/4.3.2/include /usr/include End of search list. GNU C (GCC) version 4.3.2 20081105 (Red Hat 4.3.2-7) (x86_64-redhat-linux) compiled by GNU C version 4.3.2 20081105 (Red Hat 4.3.2-7), GMP version 4.2.2, MPFR version 2.3.2. GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 Compiler executable checksum: c99c7b3dc8e919a4b394102437269a84 mystrftime.c: In function ‘my_strftime’: mystrftime.c:14: error: format not a string literal, format string not checked muelli@bigbox /tmp $ I raised this issue on gcc-help (Message-ID: <49A96972.5060004@informatik.uni-hamburg.de>) and got the tip to use __attribute__(( format(strftime, 3, 0) )) but it doesn't work. I think I want to make gcc * know that the wrapper is not responsible for the format string and thus the call to strftime is allowed * pass the responsibility up to the callers and thus check whether they call the wrapper with "good" strings. but it doesn't seem possible. I hope to have all needed information included. I can't, however, fulfil the request from http://gcc.gnu.org/bugs.html to attach *.*i* files, because there are none. Also, I searched the bugzilla for "format-nonliteral" and found nothing related to this issue. I thus think it hasn't been filed yet.
It won't work. You can either put the wrapper in a system header (add #pragma GCC system_header) or build this TU with -fno-builtin-strftime.
Hey Richard. Thanks for the timely feedback. As far as I know, it works more or less good for printf-wrappers. So I expected this to be working for strftime as well. I don't think that your proposed solutions are clean and desirable ones, do you? Is there anything wrong in expecting the posted code snipped to compile fine? Especially if the "fmt" argument is indeed a checked, constant, fixed size (literal) string.
I ran into this as well. I tried two ways, neither of which works with strftime (both work with printf): static void __attribute__((format (strftime, 1, 0))) test1(const char *fmt, const struct tm *tm) { char buf[100]; strftime(buf, sizeof(buf), fmt, tm); } static const char *__attribute__((format_arg (1))) helper(const char *fmt) { return fmt; } static void test2(const char *fmt, const struct tm *tm) { char buf[100]; strftime(buf, sizeof(buf), helper(fmt), tm); }
I have this problem too. I'm writing a wrapper for strftime. I get a warning on the actual strftime call. warning: format not a string literal, format string not checked [-Wformat-nonliteral] strftime(buf, buflen, fmt, t); Surely GCC should not that for "fmt" argument has been checked to be a valid strftime format at the points where prettynow gets called. So there is no need to whine that it is unchecked. static void prettynow(char *buf, size_t buflen, const char *fmt) __attribute__ ((format (__strftime__, 3, 0))); static void prettynow(char *buf, size_t buflen, const char *fmt) { time_t n = time(0); struct tm tm1; struct tm *t = localtime_r(&n, &tm1); strftime(buf, buflen, fmt, t); } I'm using gcc-4.8.2-7.fc20.x86_64 on Fedora 20. I managed to suppress the warning with a very ugly cast: ((size_t (*)(char *, size_t, const char *, const struct tm *))strftime)(buf, buflen, fmt, t);
Could you produce a complete testcase that (In reply to D. Hugh Redelmeier from comment #4) > I have this problem too. I'm writing a wrapper for strftime. I get a > warning on the actual strftime call. > > warning: format not a string literal, format string not checked > [-Wformat-nonliteral] > strftime(buf, buflen, fmt, t); > > Surely GCC should not that for "fmt" argument has been checked to be a valid > strftime format at the points where prettynow gets called. So there is no > need to whine that it is unchecked. > You should be able to produce a minimal self-contained testcase (the one you posted doesn't compile). See http://gcc.gnu.org/bugs/minimize.html The best would be to include only the definitions of the types that you need and declare as 'extern' library functions that you use to avoid including headers. If you can produce another similar example that works with printf, that would also help. The second step would be to find out why it works with printf and not with strftime, but that would require debugging GCC while compiling your (new) testcases, so saving the first step will make it more likely that someone will do the second.
Responding to Comment 5 by Manuel López-Ibáñez: Thanks for looking at this. > Could you produce a complete testcase === /* compile with -c -Wformat -Werror=format-nonliteral */ #include <time.h> extern void prettynow(char *buf, size_t buflen, const char *fmt, struct tm *t) __attribute__ ((format (__strftime__, 3, 0))); void prettynow(char *buf, size_t buflen, const char *fmt, struct tm *t) { strftime(buf, buflen, fmt, t); } === > The best would be to include only the definitions of the types that you need > and declare as 'extern' library functions that you use to avoid including headers. I didn't do this part. My excuses: the type declarations are not portable but the example should be; the solution might be in fixing headers; this way is shorter too. > If you can produce another similar example that works with printf, that would also help. I don't think that printf is similar enough. A strftime format doesn't interact with varargs in a complex and problematic way. A string, on its own, is or is not a valid strftime format; a string is only a valid printf format when considered with the argument list. If an arg is marked as a const char * (i.e. unchanging) and has the strftime format attribute, it should be accepted as if it were a literal strftime argument. After all, the necessary checking would have been done at this routine's points of call.
(In reply to D. Hugh Redelmeier from comment #6) > > The best would be to include only the definitions of the types that you need > and declare as 'extern' library functions that you use to avoid including headers. > > I didn't do this part. My excuses: the type declarations are not portable > but the example should be; the solution might be in fixing headers; this way > is shorter too. If you compile with --save-temps (as the instruction say), you will see what GCC parses. All that code makes debugging more complex. So if someone had to debug this, he would have to cut down that code to a few lines. This is one reason why examples should be minimal.
(In reply to D. Hugh Redelmeier from comment #6) > > If you can produce another similar example that works with printf, that would also help. > > I don't think that printf is similar enough. A strftime format doesn't > interact with varargs in a complex and problematic way. A string, on its > own, is or is not a valid strftime format; a string is only a valid printf > format when considered with the argument list. > > If an arg is marked as a const char * (i.e. unchanging) and has the strftime > format attribute, it should be accepted as if it were a literal strftime > argument. After all, the necessary checking would have been done at this > routine's points of call. Assuming that the wrapper is marked with the correct attribute, GCC would need to know that this const char* comes from the correct wrapper's argument. I am not sure this is trivial to know at the point of warning without additional work/info in the front-end. Some comments above have suggested that this work/info is done for printf, so the first thing someone looking at this should do is to understand how printf detects this case, and why the same is not done for strftime, and then try to share as much code between the two cases as possible. Perhaps it is a bug, perhaps it was never implemented for strftime. In any case, one would need to debug GCC using two similar and minimal testcases to understand what is going on. See http://gcc.gnu.org/wiki/DebuggingGCC if you want to see how this works. As an exercise, try to find the point of warning while debugging using your testcase. Bugs/features are more likely to be fixed if: 1. There is a minimal testcase that reproduces the problem 2. Someone has debugged GCC and identified the problem 3. Someone has done all the legal prerequisites and posted a patch that fixes the problem 4. Someone has tested and submitted the patch for review 5. Someone has taken care of the review comments and committed the patch We are not even in 1 and the real work is 2 and 3.
Created attachment 32784 [details] minimal C source code that demonstrates the problem minimal C source code that demonstrates the problem. Notice that the (system-provided) declaration annotates the format argument dirrectly with __format. I haven't found documentation for that.
(In reply to D. Hugh Redelmeier from comment #6) > If an arg is marked as a const char * (i.e. unchanging) and has the strftime > format attribute, it should be accepted as if it were a literal strftime > argument. After all, the necessary checking would have been done at this > routine's points of call. The code that warns is this: gcc/c-family/c-format.c if (res.number_non_literal > 0) { /* Functions taking a va_list normally pass a non-literal format string. These functions typically are declared with first_arg_num == 0, so avoid warning in those cases. */ if (!(format_types[info->format_type].flags & (int) FMT_FLAG_ARG_CONVERT)) { /* For strftime-like formats, warn for not checking the format string; but there are no arguments to check. */ warning_at (loc, OPT_Wformat_nonliteral, "format not a string literal, format string not checked"); } Thus, there is nothing checking the attributes of the caller. In the same file there is this code: tree c; for (c = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl)); c; c = TREE_CHAIN (c)) if (is_attribute_p ("format", TREE_PURPOSE (c)) && (decode_format_type (IDENTIFIER_POINTER (TREE_VALUE (TREE_VALUE (c)))) == info.format_type)) break; if (c == NULL_TREE) { /* Check if the current function has a parameter to which the format attribute could be attached; if not, it can't be a candidate for a format attribute, despite the vprintf-like or vscanf-like call. */ tree args; for (args = DECL_ARGUMENTS (current_function_decl); args != 0; args = DECL_CHAIN (args)) { if (TREE_CODE (TREE_TYPE (args)) == POINTER_TYPE && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (args))) == char_type_node)) break; } if (args != 0) warning (OPT_Wsuggest_attribute_format, "function might " "be possible candidate for %qs format attribute", format_types[info.format_type].name); } I'm confident that the above code can be adjusted and moved to the point of the warning in order to check that the caller of strftime has an attribute format of type 'strftime' that refers to the same declaration as the nonliteral format argument in the call to strftime, then avoid warning. I'm not planning to work on this though.
I'm still seeing this with "gcc (Ubuntu 5.4.0-6ubuntu1~16.04.9) 5.4.0 20160609". Is there any chance that this NINE YEAR OLD bug is going to be fixed?
Also happens with `gcc (Ubuntu 8.1.0-5ubuntu1~16.04) 8.1.0`