Status Update
Comments
gr...@gmail.com <gr...@gmail.com> #2
I have forgotten to check the return value of open_output
in the "working" code. If I change wopenout
to
void wopenout (gzFile f) {
if (open_output ((FILE**)&(f), "wb"))
f = gzdopen(fileno((FILE*)f), "wb");
}
I get the same error as with the macro, so I suppose there is a real fd issue in this code.
gr...@gmail.com <gr...@gmail.com> #3
There's another error in the test program as well, -Wall warns that gzFile fp is uninitialized. After fixing that it works again for the function implementation, but not the macro-implementation. So, this gives an error:
#include <zlib.h>
#include <stdio.h>
int open_output(FILE **f_ptr, char *mode) {
*f_ptr = fopen ("test.gz", mode);
return *f_ptr != NULL;
}
#define wopenout(f) (open_output ((FILE**)&(f), "wb") \
&& (f = gzdopen(fileno((FILE*)f), "wb")))
int main() {
gzFile fp = NULL;
wopenout(fp);
gzclose(fp);
}
and this works:
#include <zlib.h>
#include <stdio.h>
int open_output(FILE **f_ptr, char *mode) {
*f_ptr = fopen ("test.gz", mode);
return *f_ptr != NULL;
}
void wopenout (gzFile f) {
if (open_output ((FILE**)&(f), "wb"))
f = gzdopen(fileno((FILE*)f), "wb");
}
int main() {
gzFile fp = NULL;
wopenout(fp);
gzclose(fp);
}
and I cannot see why there should be a difference in behaviour. I also noticed that clang 11 gives a working program when using -O0, but -O1 or higher gives the fdsan error. clang 9 (which the ndk uses) gives the error for all optimization levels.
ra...@google.com <ra...@google.com>
gr...@gmail.com <gr...@gmail.com> #4
Here's another minimal example, condensed from emacs, that fails:
#include <stdio.h>
int main()
{
fdopen (2, "w");
fclose (stderr);
}
My guess is that the sanitizer does not like that we do not use the fd fdopen returns when closing stream 2/stderr. If I change to this:
#include <stdio.h>
int main()
{
FILE *err = fdopen (2, "w");
fclose (err);
}
It compiles and runs without issues. Is there an actual problem in the first snippet?
en...@google.com <en...@google.com> #5
Is there an actual problem in the first snippet?
yes. you have two FILE*s that both think they own file descriptor 2. depending on what you're actually trying to do, you probably meant to use freopen(3) instead?
gr...@gmail.com <gr...@gmail.com> #6
Thanks for the feedback. The idea in the code is to open a line buffered copy of stderr, is that valid? I am still having some problems wrapping my head around the issue, so I would be greatful if you could have a look at the failing example below:
#include <stdlib.h>
#include <unistd.h>
/* If FD is not already open, arrange for it to be open with FLAGS. */
static void
force_open (int fd, int flags)
{
if (dup2 (fd, fd) < 0)
{
int n = open ("/dev/null", flags);
if (n < 0 || (fd != n && (dup2 (n, fd) < 0 || close (n) == 0 != 0)))
exit (EXIT_FAILURE);
}
}
/* A stream that is like stderr, except line buffered. It is NULL
during startup, or if line buffering is not in use. */
static FILE *buferr;
int
main()
{
/* Make sure stderr are open to something, so that the file
descriptor is not hijacked by later system calls. */
force_open (STDERR_FILENO, O_RDONLY);
/* Set buferr if possible on platforms defining _PC_PIPE_BUF, as
they support the notion of atomic writes to pipes. */
#ifdef _PC_PIPE_BUF
buferr = fdopen (STDERR_FILENO, "w");
if (buferr)
setvbuf (buferr, NULL, _IOLBF, 0);
#endif
int err = buferr && (fflush (buferr) != 0 || ferror (buferr));
if (err | (fclose (stderr) != 0))
return 1;
return 0;
}
Compiling and executing on device gives
fdsan: attempted to close file descriptor 2, expected to be unowned, actually owned by FILE* 0xaba9700c
Aborted
from the fclose (stderr) call, similar to in the previous very minimal example.
en...@google.com <en...@google.com> #7
The idea in the code is to open a line buffered copy of stderr
in that case you just want setlinebuf(stderr)
. see
Description
Since android 11 programs stop when the file descriptor sanitizer detects issues with default fdsan error level setting.
This small test program, condensed from texlive's source code, stops with such an error when compiled with something like
and executed on device.
The issue seem to be in the wopenout macro here, if I convert that to a normal function the error does not occur:
Is it expected that fdsan should trigger when using a macro as defined above, but not when implementing the same code as a function?
This has been reproduced on a Pixel 4 XL and a Samsung galaxy tab A. Backtrace on Samsung device shows: