On Android 4.3, I'm seeing this test failure: FAIL: test-argv-iter ====================
../../gltests/test-argv-iter.c:35: assertion 'fp' failed FAIL test-argv-iter (exit status: 139) The cause is that tmpfile() returns NULL, because /tmp does not exist. This patch fixes it (borrowing code from glibc/stdio-common/tmpfile.c). 2019-01-27 Bruno Haible <br...@clisp.org> tmpfile: Add support for Android. * m4/tmpfile.m4 (gl_FUNC_TMPFILE): Add a runtime test whether tmpfile() works. * lib/tmpfile.c (tmpfile): Add an alternative implementation for Android. * modules/tmpfile (Depends-on): Add 'stdbool'. * doc/posix-functions/tmpfile.texi: Mention the Android bug. * modules/argv-iter-tests (Depends-on): Add 'tmpfile'. diff --git a/doc/posix-functions/tmpfile.texi b/doc/posix-functions/tmpfile.texi index c5510af..2792458 100644 --- a/doc/posix-functions/tmpfile.texi +++ b/doc/posix-functions/tmpfile.texi @@ -9,6 +9,9 @@ Gnulib module: tmpfile Portability problems fixed by Gnulib: @itemize @item +This function always fails on some platforms: +Android 4.3. +@item This function often fails for trivial reasons on some platforms: mingw, MSVC 14. @item diff --git a/lib/tmpfile.c b/lib/tmpfile.c index 1a6cef7..45d652d 100644 --- a/lib/tmpfile.c +++ b/lib/tmpfile.c @@ -21,24 +21,36 @@ /* Specification. */ #include <stdio.h> -/* This replacement is used only on native Windows platforms. */ +#include <stdbool.h> -#include <errno.h> -#include <fcntl.h> -#include <string.h> -#include <sys/stat.h> +#if defined _WIN32 && ! defined __CYGWIN__ +/* A native Windows platforms. */ -#include <io.h> +# include <errno.h> +# include <fcntl.h> +# include <string.h> +# include <sys/stat.h> -#define WIN32_LEAN_AND_MEAN /* avoid including junk */ -#include <windows.h> +# include <io.h> + +# define WIN32_LEAN_AND_MEAN /* avoid including junk */ +# include <windows.h> + +#else + +# include <unistd.h> + +#endif #include "pathmax.h" #include "tempname.h" #include "tmpdir.h" /* PATH_MAX is guaranteed to be defined, because this replacement is only - used on native Windows. */ + used on native Windows and Android. */ + +#if defined _WIN32 && ! defined __CYGWIN__ +/* A native Windows platforms. */ /* On Windows, opening a file with _O_TEMPORARY has the effect of passing the FILE_FLAG_DELETE_ON_CLOSE flag to CreateFile(), which has the effect @@ -130,3 +142,38 @@ tmpfile (void) return NULL; } + +#else + +FILE * +tmpfile (void) +{ + char buf[PATH_MAX]; + int fd; + FILE *fp; + + /* Try $TMPDIR first, not /tmp nor P_tmpdir, because we need this replacement + on Android, and /tmp does not exist on Android. */ + + if (path_search (buf, sizeof buf, NULL, "tmpf", true)) + return NULL; + + fd = gen_tempname (buf, 0, 0, GT_FILE); + if (fd < 0) + return NULL; + + /* Note that this relies on the Unix semantics that + a file is not really removed until it is closed. */ + (void) unlink (buf); + + if ((fp = fdopen (fd, "w+b")) == NULL) + { + int saved_errno = errno; + close (fd); + errno = saved_errno; + } + + return fp; +} + +#endif diff --git a/m4/tmpfile.m4 b/m4/tmpfile.m4 index faef23e..e648d37 100644 --- a/m4/tmpfile.m4 +++ b/m4/tmpfile.m4 @@ -1,4 +1,4 @@ -# tmpfile.m4 serial 3 +# tmpfile.m4 serial 4 # Copyright (C) 2007, 2009-2019 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -18,20 +18,44 @@ # directory, even though tmpfile wouldn't work in general. Instead, # just test for a Windows platform (excluding Cygwin). +# On Android 4.3, tmpfile() always returns NULL, even if TMPDIR is set +# to a writable directory. + AC_DEFUN([gl_FUNC_TMPFILE], [ AC_REQUIRE([gl_STDIO_H_DEFAULTS]) - AC_CACHE_CHECK([whether tmpfile should be overridden], - [gl_cv_func_tmpfile_unusable], + AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles + AC_CACHE_CHECK([whether tmpfile works], + [gl_cv_func_tmpfile_works], [AC_EGREP_CPP([choke me], [ #if defined _WIN32 && !defined __CYGWIN__ choke me #endif ], - [gl_cv_func_tmpfile_unusable=yes], - [gl_cv_func_tmpfile_unusable=no])]) - if test $gl_cv_func_tmpfile_unusable = yes; then - REPLACE_TMPFILE=1 - fi + [gl_cv_func_tmpfile_works=no], + [AC_RUN_IFELSE( + [AC_LANG_SOURCE([[ +#include <stdio.h> +#include <stdlib.h> +int +main (void) +{ + return tmpfile () == NULL; +}]])], + [gl_cv_func_tmpfile_works=yes], + [gl_cv_func_tmpfile_works=no], + [case "$host_os" in + # Guess no on Android. + linux*-android*) gl_cv_func_tmpfile_works="guessing no" ;; + # Guess yes otherwise. + *) gl_cv_func_tmpfile_works="guessing yes" ;; + esac + ]) + ]) + ]) + case "$gl_cv_func_tmpfile_works" in + *yes) ;; + *) REPLACE_TMPFILE=1 ;; + esac ]) # Prerequisites of lib/tmpfile.c. diff --git a/modules/argv-iter-tests b/modules/argv-iter-tests index 92c5c82..f32587e 100644 --- a/modules/argv-iter-tests +++ b/modules/argv-iter-tests @@ -3,6 +3,7 @@ tests/test-argv-iter.c tests/macros.h Depends-on: +tmpfile configure.ac: diff --git a/modules/tmpfile b/modules/tmpfile index e98a8ee..884f284 100644 --- a/modules/tmpfile +++ b/modules/tmpfile @@ -9,6 +9,7 @@ Depends-on: stdio largefile pathmax [test $REPLACE_TMPFILE = 1] +stdbool [test $REPLACE_TMPFILE = 1] tempname [test $REPLACE_TMPFILE = 1] tmpdir [test $REPLACE_TMPFILE = 1]