diff options
| author | Werner Koch <[email protected]> | 2026-04-30 13:38:11 +0200 |
|---|---|---|
| committer | Werner Koch <[email protected]> | 2026-04-30 13:38:11 +0200 |
| commit | 50f0c56bdd36f7f709a62503942ac55399dafb9c (patch) | |
| tree | d38aa72fa58a11e41fb95bafc2e2270e777a00ea | |
| parent | Fix possible stack overflow in es_printf for %.100f format. (diff) | |
| download | libgpg-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.c | 2 | ||||
| -rw-r--r-- | src/b64enc.c | 2 | ||||
| -rw-r--r-- | src/estream.c | 25 | ||||
| -rw-r--r-- | src/gpgrt-int.h | 2 | ||||
| -rw-r--r-- | src/visibility.c | 2 |
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 |
