From d140b34f09614894937465cdc3384c14b796358b Mon Sep 17 00:00:00 2001 From: Cedric Guillemet <1312968+CedricGuillemet@users.noreply.github.com> Date: Mon, 20 Apr 2026 18:02:55 +0200 Subject: [PATCH] Fix fdsan violation in StdoutLogger::Stop() on Android API 29+ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit StdoutLogger::Start() calls fdopen(fd[0], "r") to create a FILE* for each reader thread. Per POSIX, fdopen() transfers ownership of the file descriptor to the FILE*; the caller must use fclose() — not close() — to release it. StdoutLogger::Stop() was calling close(fd_stdout[0]) and close(fd_stderr[0]) directly. On Android API 29+, fdsan enforces ownership tracking and aborts with SIGABRT when a raw close() is called on a descriptor owned by a FILE*: Fatal signal 6 (SIGABRT) Abort message: 'fdsan: attempted to close file descriptor 94, expected to be unowned, actually owned by FILE* 0x6e357db180' Fix: in Stop(), only close the write ends (fd[1]). Closing fd[1] sends EOF through the pipe, causing getline() in the reader thread to return -1, which breaks the loop and calls fclose(stream) — correctly closing fd[0]. Remove the explicit close(fd[0]) / close(fd[1]) calls entirely. --- Source/StdoutLogger.cpp | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/Source/StdoutLogger.cpp b/Source/StdoutLogger.cpp index 7c45ba0..cb3762f 100644 --- a/Source/StdoutLogger.cpp +++ b/Source/StdoutLogger.cpp @@ -92,29 +92,24 @@ namespace android::StdoutLogger g_started = false; + // Close the write ends of the pipes. This signals EOF to the reader + // threads, which will then call fclose() to close the read ends. + // Do NOT close the read ends here: fdopen() transferred ownership of + // fd[0] to the FILE* inside the reader thread, and calling close() on + // an fd owned by a FILE* is a fdsan violation on Android API 29+. if (fd_stdout[1] != -1) { close(fd_stdout[1]); fd_stdout[1] = -1; } - - if (fd_stdout[0] != -1) - { - close(fd_stdout[0]); - fd_stdout[0] = -1; - } + fd_stdout[0] = -1; // owned by reader thread's FILE*; closed via fclose() if (fd_stderr[1] != -1) { close(fd_stderr[1]); fd_stderr[1] = -1; } - - if (fd_stderr[0] != -1) - { - close(fd_stderr[0]); - fd_stderr[0] = -1; - } + fd_stderr[0] = -1; // owned by reader thread's FILE*; closed via fclose() } bool IsStarted()