Hello gnulib team, An enterprising Gentoo user reported compilation failures of projects using gnulib when -Werror=format-security is enabled:
https://bugs.gentoo.org/955689 https://bugs.gentoo.org/955947 Further inspection & trying to reproduce this in gnulib revealed that this requires a combination of -Werror=security and --disable-nls. To reproduce in gnulib: - clone gnulib - create a test dir: ./gnulib-tool --create-testdir --symlink --dir mytests (you can interrupt when it starts to configure) - reconfigure the project: cd mytests && ./configure --disable-nls CFLAGS="-pipe -Werror=format-security -O" - make will fail with an error like: clean-temp.c: In function 'create_temp_dir': clean-temp.c:234:7: error: format not a string literal and no format arguments [-Werror=format-security] 234 | error (0, errno, | ^~~~~ clean-temp.c:234:7: error: format not a string literal and no format arguments [-Werror=format-security] The errors cannot be reproduced when nls is enabled, which suggests an implementation difference in the generated error() macros depending on the nls feature. Attached is a patch which fixes these failures, based on top of last night's gnulib git; they make the tests compile/run and were used to resolve the aforementioned problems in gettext and m4, though they obviously affect any gnulib consuming projects. I hope you find these useful! thanks, Holger (please cc: my on replies)
diff --git a/lib/clean-temp.c b/lib/clean-temp.c index e8d0cf3113..568faf2aa3 100644 --- a/lib/clean-temp.c +++ b/lib/clean-temp.c @@ -233,7 +233,7 @@ create_temp_dir (const char *prefix, const char *parentdir, xtemplate = (char *) xmalloca (PATH_MAX); if (path_search (xtemplate, PATH_MAX, parentdir, prefix, parentdir == NULL)) { - error (0, errno, + error (0, errno, "%s", _("cannot find a temporary directory, try setting $TMPDIR")); goto quit; } diff --git a/lib/csharpcomp.c b/lib/csharpcomp.c index 5b6c9684d9..83f79e69c5 100644 --- a/lib/csharpcomp.c +++ b/lib/csharpcomp.c @@ -223,7 +223,7 @@ compile_csharp_using_mono (const char * const *sources, line if it starts with "Compilation succeeded". */ fp = fdopen (fd[0], "r"); if (fp == NULL) - error (EXIT_FAILURE, errno, _("fdopen() failed")); + error (EXIT_FAILURE, errno, "%s", _("fdopen() failed")); line[0] = NULL; linesize[0] = 0; line[1] = NULL; linesize[1] = 0; l = 0; @@ -372,7 +372,7 @@ compile_csharp_using_dotnet (const char * const *sources, /* Retrieve its result. */ FILE *fp = fdopen (fd[0], "r"); if (fp == NULL) - error (EXIT_FAILURE, errno, _("fdopen() failed")); + error (EXIT_FAILURE, errno, "%s", _("fdopen() failed")); char *line = NULL; size_t linesize = 0; @@ -464,7 +464,7 @@ compile_csharp_using_dotnet (const char * const *sources, /* Retrieve its result. */ FILE *fp = fdopen (fd[0], "r"); if (fp == NULL) - error (EXIT_FAILURE, errno, _("fdopen() failed")); + error (EXIT_FAILURE, errno, "%s", _("fdopen() failed")); char *line = NULL; size_t linesize = 0; @@ -1086,6 +1086,6 @@ compile_csharp_class (const char * const *sources, if (result >= 0) return (bool) result; - error (0, 0, _("C# compiler not found, try installing mono or dotnet")); + error (0, 0, "%s", _("C# compiler not found, try installing mono or dotnet")); return true; } diff --git a/lib/csharpexec.c b/lib/csharpexec.c index 13a05a7e73..51573d4cd6 100644 --- a/lib/csharpexec.c +++ b/lib/csharpexec.c @@ -394,7 +394,7 @@ execute_csharp_using_dotnet (const char *assembly_path, /* Retrieve its result. */ FILE *fp = fdopen (fd[0], "r"); if (fp == NULL) - error (EXIT_FAILURE, errno, _("fdopen() failed")); + error (EXIT_FAILURE, errno, "%s", _("fdopen() failed")); char *line = NULL; size_t linesize = 0; @@ -678,6 +678,6 @@ execute_csharp_program (const char *assembly_path, return (bool) result; if (!quiet) - error (0, 0, _("C# virtual machine not found, try installing mono or dotnet")); + error (0, 0, "%s", _("C# virtual machine not found, try installing mono or dotnet")); return true; } diff --git a/lib/javacomp.c b/lib/javacomp.c index 33ec8eb63e..49e394a785 100644 --- a/lib/javacomp.c +++ b/lib/javacomp.c @@ -100,7 +100,7 @@ default_target_version (void) && java_version_cache[2] >= '1' && java_version_cache[2] <= '5' && java_version_cache[3] == '\0') { - error (0, 0, _("The java program is too old. Cannot compile Java code for this old version any more.")); + error (0, 0, "%s", _("The java program is too old. Cannot compile Java code for this old version any more.")); java_version_cache = "1.6"; } else if ((java_version_cache[0] == '1' @@ -144,7 +144,7 @@ source_version_index (const char *source_version) && (source_version[1] >= '0' && source_version[1] <= '9') && source_version[2] == '\0') return (source_version[0] - '1') * 10 + source_version[1] - '0' + 4; - error (EXIT_FAILURE, 0, _("invalid source_version argument to compile_java_class")); + error (EXIT_FAILURE, 0, "%s", _("invalid source_version argument to compile_java_class")); return 0; } @@ -165,7 +165,7 @@ target_version_index (const char *target_version) && (target_version[1] >= '0' && target_version[1] <= '9') && target_version[2] == '\0') return (target_version[0] - '1') * 10 + target_version[1] - '0' + 4; - error (EXIT_FAILURE, 0, _("invalid target_version argument to compile_java_class")); + error (EXIT_FAILURE, 0, "%s", _("invalid target_version argument to compile_java_class")); return 0; } @@ -352,7 +352,7 @@ execute_and_read_line (const char *progname, /* Retrieve its result. */ fp = fdopen (fd[0], "r"); if (fp == NULL) - error (EXIT_FAILURE, errno, _("fdopen() failed")); + error (EXIT_FAILURE, errno, "%s", _("fdopen() failed")); line = NULL; linesize = 0; linelen = getline (&line, &linesize, fp); @@ -1130,7 +1130,7 @@ compile_java_class (const char * const *java_sources, } } - error (0, 0, _("Java compiler not found, try setting $JAVAC")); + error (0, 0, "%s", _("Java compiler not found, try setting $JAVAC")); err = true; done2: diff --git a/lib/javaexec.c b/lib/javaexec.c index 1158971ff9..2633a0a166 100644 --- a/lib/javaexec.c +++ b/lib/javaexec.c @@ -306,7 +306,7 @@ execute_java_class (const char *class_name, } if (!quiet) - error (0, 0, _("Java virtual machine not found, try setting $JAVA")); + error (0, 0, "%s", _("Java virtual machine not found, try setting $JAVA")); err = true; done2: diff --git a/lib/javaversion.c b/lib/javaversion.c index bd680354a4..70fe507752 100644 --- a/lib/javaversion.c +++ b/lib/javaversion.c @@ -72,7 +72,7 @@ execute_and_read_line (const char *progname, /* Retrieve its result. */ fp = fdopen (fd[0], "r"); if (fp == NULL) - error (EXIT_FAILURE, errno, _("fdopen() failed")); + error (EXIT_FAILURE, errno, "%s", _("fdopen() failed")); line = NULL; linesize = 0; linelen = getline (&line, &linesize, fp); diff --git a/lib/spawn-pipe.c b/lib/spawn-pipe.c index 098352e2d5..3dfb6499ba 100644 --- a/lib/spawn-pipe.c +++ b/lib/spawn-pipe.c @@ -215,10 +215,10 @@ create_pipe (const char *progname, process is running. */ if (pipe_stdout) if (pipe2_safer (ifd, O_BINARY | O_CLOEXEC) < 0) - error (EXIT_FAILURE, errno, _("cannot create pipe")); + error (EXIT_FAILURE, errno, "%s", _("cannot create pipe")); if (pipe_stdin) if (pipe2_safer (ofd, O_BINARY | O_CLOEXEC) < 0) - error (EXIT_FAILURE, errno, _("cannot create pipe")); + error (EXIT_FAILURE, errno, "%s", _("cannot create pipe")); /* Data flow diagram: * * write system read diff --git a/lib/vc-mtime.c b/lib/vc-mtime.c index 77acbabba4..80b221aa06 100644 --- a/lib/vc-mtime.c +++ b/lib/vc-mtime.c @@ -83,7 +83,7 @@ is_git_present (void) /* Retrieve its result. */ FILE *fp = fdopen (fd[0], "r"); if (fp == NULL) - error (EXIT_FAILURE, errno, _("fdopen() failed")); + error (EXIT_FAILURE, errno, "%s", _("fdopen() failed")); char *line = NULL; size_t linesize = 0; @@ -233,7 +233,7 @@ git_mtime (struct timespec *mtime, const char *filename) fp = fdopen (fd[0], "r"); if (fp == NULL) - error (EXIT_FAILURE, errno, _("fdopen() failed")); + error (EXIT_FAILURE, errno, "%s", _("fdopen() failed")); line = NULL; linesize = 0; linelen = getline (&line, &linesize, fp); @@ -337,7 +337,7 @@ abs_git_checkout (void) /* Retrieve its result. */ FILE *fp = fdopen (fd[0], "r"); if (fp == NULL) - error (EXIT_FAILURE, errno, _("fdopen() failed")); + error (EXIT_FAILURE, errno, "%s", _("fdopen() failed")); char *line = NULL; size_t linesize = 0; @@ -653,7 +653,7 @@ max_vc_mtime (struct timespec *max_of_mtimes, names (because we have already relativized them). */ FILE *fp = fdopen (fd[0], "r"); if (fp == NULL) - error (EXIT_FAILURE, errno, _("fdopen() failed")); + error (EXIT_FAILURE, errno, "%s", _("fdopen() failed")); char *fn = NULL; size_t fn_size = 0; @@ -778,7 +778,7 @@ max_vc_mtime (struct timespec *max_of_mtimes, checkout dir, not to currdir! */ FILE *fp = fdopen (fd[0], "r"); if (fp == NULL) - error (EXIT_FAILURE, errno, _("fdopen() failed")); + error (EXIT_FAILURE, errno, "%s", _("fdopen() failed")); char *fn = NULL; size_t fn_size = 0; @@ -867,7 +867,7 @@ max_vc_mtime (struct timespec *max_of_mtimes, single line, containing a positive integer. */ FILE *fp = fdopen (fd[0], "r"); if (fp == NULL) - error (EXIT_FAILURE, errno, _("fdopen() failed")); + error (EXIT_FAILURE, errno, "%s", _("fdopen() failed")); char *line = NULL; size_t linesize = 0; diff --git a/lib/xsetenv.c b/lib/xsetenv.c index 7dfa3fcd87..9d78a2a7f7 100644 --- a/lib/xsetenv.c +++ b/lib/xsetenv.c @@ -34,5 +34,5 @@ void xsetenv (const char *name, const char *value, int replace) { if (setenv (name, value, replace) < 0) - error (EXIT_FAILURE, 0, _("memory exhausted")); + error (EXIT_FAILURE, 0, "%s", _("memory exhausted")); }