aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2026-04-30 13:38:11 +0200
committerWerner Koch <[email protected]>2026-04-30 13:38:11 +0200
commit50f0c56bdd36f7f709a62503942ac55399dafb9c (patch)
treed38aa72fa58a11e41fb95bafc2e2270e777a00ea
parentFix possible stack overflow in es_printf for %.100f format. (diff)
downloadlibgpg-error-50f0c56bdd36f7f709a62503942ac55399dafb9c.tar.gz
libgpg-error-50f0c56bdd36f7f709a62503942ac55399dafb9c.zip
Fix possible lockup in an atexit handler
* src/estream.c (_gpgrt_fflush): Add arg in_atexit and skip the flush in this mode if the lock can not be taken. Change all callers. -- The problem should up with gpgsm encryption on the standard mode and a no public key error. In this case the process got stuck in the atexit handler after a FAILURE gpgsm-exit status line to stderr. It is better not to have a hanging process than having flushed everything.
-rw-r--r--src/argparse.c2
-rw-r--r--src/b64enc.c2
-rw-r--r--src/estream.c25
-rw-r--r--src/gpgrt-int.h2
-rw-r--r--src/visibility.c2
5 files changed, 24 insertions, 9 deletions
diff --git a/src/argparse.c b/src/argparse.c
index 9868fa7..0cf0083 100644
--- a/src/argparse.c
+++ b/src/argparse.c
@@ -250,7 +250,7 @@ flushstrings (int is_error)
if (custom_outfnc)
custom_outfnc (is_error? 2:1, NULL);
else
- _gpgrt_fflush (is_error? es_stderr : es_stdout);
+ _gpgrt_fflush (is_error? es_stderr : es_stdout, 0);
}
diff --git a/src/b64enc.c b/src/b64enc.c
index a4edd0c..b25753c 100644
--- a/src/b64enc.c
+++ b/src/b64enc.c
@@ -202,7 +202,7 @@ _gpgrt_b64enc_write (gpgrt_b64state_t state, const void *buffer, size_t nbytes)
if (!nbytes)
{
if (buffer)
- if (_gpgrt_fflush (state->stream))
+ if (_gpgrt_fflush (state->stream, 0))
goto write_error;
return 0;
}
diff --git a/src/estream.c b/src/estream.c
index 4bf3bd3..55709f8 100644
--- a/src/estream.c
+++ b/src/estream.c
@@ -599,7 +599,7 @@ static void
do_deinit (void)
{
/* Flush all streams. */
- _gpgrt_fflush (NULL);
+ _gpgrt_fflush (NULL, 1); /* 1 = we are in an atexit handler */
/* We should release the estream_list. However there is one
problem: That list is also used to search for the standard
@@ -4552,8 +4552,9 @@ do_fflush (estream_t stream)
}
+/* IN_ATEXIT is set when this function is called by an atexit handler. */
int
-_gpgrt_fflush (estream_t stream)
+_gpgrt_fflush (estream_t stream, int in_atexit)
{
int err;
@@ -4572,9 +4573,23 @@ _gpgrt_fflush (estream_t stream)
for (item = estream_list; item; item = item->next)
if (item->stream)
{
- lock_stream (item->stream);
- err |= do_fflush (item->stream);
- unlock_stream (item->stream);
+ if (in_atexit)
+ {
+ /* Do not flush if we can't take the lock while we are
+ * in an atexit handler. The atexit handler might
+ * have been called while the stream was locked. */
+ if (!trylock_stream (item->stream))
+ {
+ err |= do_fflush (item->stream);
+ unlock_stream (item->stream);
+ }
+ }
+ else
+ {
+ lock_stream (item->stream);
+ err |= do_fflush (item->stream);
+ unlock_stream (item->stream);
+ }
}
unlock_list ();
}
diff --git a/src/gpgrt-int.h b/src/gpgrt-int.h
index d373435..b8533dc 100644
--- a/src/gpgrt-int.h
+++ b/src/gpgrt-int.h
@@ -377,7 +377,7 @@ void _gpgrt_clearerr_unlocked (gpgrt_stream_t stream);
int _gpgrt__pending (gpgrt_stream_t stream);
int _gpgrt__pending_unlocked (gpgrt_stream_t stream);
-int _gpgrt_fflush (gpgrt_stream_t stream);
+int _gpgrt_fflush (gpgrt_stream_t stream, int in_atexit);
int _gpgrt_fseek (gpgrt_stream_t stream, long int offset, int whence);
int _gpgrt_fseeko (gpgrt_stream_t stream, gpgrt_off_t offset, int whence);
long int _gpgrt_ftell (gpgrt_stream_t stream);
diff --git a/src/visibility.c b/src/visibility.c
index 98d4721..5574f33 100644
--- a/src/visibility.c
+++ b/src/visibility.c
@@ -374,7 +374,7 @@ gpgrt_clearerr_unlocked (estream_t stream)
int
gpgrt_fflush (estream_t stream)
{
- return _gpgrt_fflush (stream);
+ return _gpgrt_fflush (stream, 0);
}
int