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"));
}