Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [PATCH v2] [gdb] Handle EINTR in fgets
@ 2025-08-18  8:32 Tom de Vries
  2025-08-18 10:23 ` Andrew Burgess
  0 siblings, 1 reply; 3+ messages in thread
From: Tom de Vries @ 2025-08-18  8:32 UTC (permalink / raw)
  To: gdb-patches

Usually, find_charset_names calls iconv -l to get the list of supported
charsets, allowing us to use a charset not in the default list:
...
$ /usr/bin/gdb -q -batch -ex "set charset CP858"
$
...

If the call to iconv -l fails somehow, gdb silently falls back to using the
default list, which gets us instead:
...
$ PATH= /usr/bin/gdb -q -batch -ex "set charset CP858"
Undefined item: "CP858".
$
...

PR gdb/33274 reports that gdb occasionally fails in the same way, because
fgets returns nullptr before the output of iconv -l is read entirely.

We asked the reporter to try out a patch handling errno == EINTR after
fgets returns nullptr, and that fixed the problem.

Fix this by:
- adding an inline function gdb::fgets that handles EINTR, and
- using it instead of fgets.

Tested on x86_64-linux.

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=33274
---
 gdb/charset.c               |  3 ++-
 gdb/linux-nat.c             |  3 ++-
 gdb/nat/linux-btrace.c      |  3 ++-
 gdb/nat/linux-osdata.c      | 13 +++++++------
 gdb/nat/linux-procfs.c      |  7 ++++---
 gdbserver/linux-i386-ipa.cc |  3 ++-
 gdbsupport/eintr.h          | 15 +++++++++++++++
 7 files changed, 34 insertions(+), 13 deletions(-)

diff --git a/gdb/charset.c b/gdb/charset.c
index 259362563b2..abf3fe800d2 100644
--- a/gdb/charset.c
+++ b/gdb/charset.c
@@ -25,6 +25,7 @@
 #include "gdbsupport/environ.h"
 #include "arch-utils.h"
 #include <ctype.h>
+#include "gdbsupport/eintr.h"
 
 #ifdef USE_WIN32API
 #include <windows.h>
@@ -842,7 +843,7 @@ find_charset_names (void)
 	  char *start, *r;
 	  int len;
 
-	  r = fgets (buf, sizeof (buf), in);
+	  r = gdb::fgets (buf, sizeof (buf), in);
 	  if (!r)
 	    break;
 	  len = strlen (r);
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index f3179279d92..39f1fb59ae0 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -64,6 +64,7 @@
 #include "gdbsupport/scope-exit.h"
 #include "gdbsupport/gdb-sigmask.h"
 #include "gdbsupport/common-debug.h"
+#include "gdbsupport/eintr.h"
 #include <unordered_map>
 
 /* This comment documents high-level logic of this file.
@@ -4301,7 +4302,7 @@ linux_proc_pending_signals (int pid, sigset_t *pending,
   if (procfile == NULL)
     error (_("Could not open %s"), fname);
 
-  while (fgets (buffer, PATH_MAX, procfile.get ()) != NULL)
+  while (gdb::fgets (buffer, PATH_MAX, procfile.get ()) != NULL)
     {
       /* Normal queued signals are on the SigPnd line in the status
 	 file.  However, 2.6 kernels also have a "shared" pending
diff --git a/gdb/nat/linux-btrace.c b/gdb/nat/linux-btrace.c
index 9eadd46c9be..08c7b795a86 100644
--- a/gdb/nat/linux-btrace.c
+++ b/gdb/nat/linux-btrace.c
@@ -26,6 +26,7 @@
 #include "gdbsupport/filestuff.h"
 #include "gdbsupport/scoped_fd.h"
 #include "gdbsupport/scoped_mmap.h"
+#include "gdbsupport/eintr.h"
 
 #include <inttypes.h>
 
@@ -202,7 +203,7 @@ linux_determine_kernel_start (void)
       uint64_t addr;
       int match;
 
-      line = fgets (buffer, sizeof (buffer), file.get ());
+      line = gdb::fgets (buffer, sizeof (buffer), file.get ());
       if (line == NULL)
 	break;
 
diff --git a/gdb/nat/linux-osdata.c b/gdb/nat/linux-osdata.c
index b52a8ed5f36..bfdc26f2795 100644
--- a/gdb/nat/linux-osdata.c
+++ b/gdb/nat/linux-osdata.c
@@ -35,6 +35,7 @@
 #include <dirent.h>
 #include <sys/stat.h>
 #include "gdbsupport/filestuff.h"
+#include "gdbsupport/eintr.h"
 #include <algorithm>
 #include "linux-procfs.h"
 
@@ -562,7 +563,7 @@ linux_xfer_osdata_cpus ()
 
       do
 	{
-	  if (fgets (buf, sizeof (buf), fp.get ()))
+	  if (gdb::fgets (buf, sizeof (buf), fp.get ()))
 	    {
 	      char *key, *value;
 	      int i = 0;
@@ -780,7 +781,7 @@ print_sockets (unsigned short family, int tcp, std::string &buffer)
 
       do
 	{
-	  if (fgets (buf, sizeof (buf), fp.get ()))
+	  if (gdb::fgets (buf, sizeof (buf), fp.get ()))
 	    {
 	      uid_t uid;
 	      unsigned int local_port, remote_port, state;
@@ -961,7 +962,7 @@ linux_xfer_osdata_shm ()
 
       do
 	{
-	  if (fgets (buf, sizeof (buf), fp.get ()))
+	  if (gdb::fgets (buf, sizeof (buf), fp.get ()))
 	    {
 	      key_t key;
 	      uid_t uid, cuid;
@@ -1057,7 +1058,7 @@ linux_xfer_osdata_sem ()
 
       do
 	{
-	  if (fgets (buf, sizeof (buf), fp.get ()))
+	  if (gdb::fgets (buf, sizeof (buf), fp.get ()))
 	    {
 	      key_t key;
 	      uid_t uid, cuid;
@@ -1137,7 +1138,7 @@ linux_xfer_osdata_msg ()
 
       do
 	{
-	  if (fgets (buf, sizeof (buf), fp.get ()))
+	  if (gdb::fgets (buf, sizeof (buf), fp.get ()))
 	    {
 	      key_t key;
 	      PID_T lspid, lrpid;
@@ -1231,7 +1232,7 @@ linux_xfer_osdata_modules ()
 
       do
 	{
-	  if (fgets (buf, sizeof (buf), fp.get ()))
+	  if (gdb::fgets (buf, sizeof (buf), fp.get ()))
 	    {
 	      char *name, *dependencies, *status, *tmp, *saveptr;
 	      unsigned int size;
diff --git a/gdb/nat/linux-procfs.c b/gdb/nat/linux-procfs.c
index d4f9af32bb9..1927a21314e 100644
--- a/gdb/nat/linux-procfs.c
+++ b/gdb/nat/linux-procfs.c
@@ -19,6 +19,7 @@
 #include "linux-procfs.h"
 #include "gdbsupport/filestuff.h"
 #include "gdbsupport/unordered_set.h"
+#include "gdbsupport/eintr.h"
 #include <dirent.h>
 #include <sys/stat.h>
 #include <utility>
@@ -42,7 +43,7 @@ linux_proc_get_int (pid_t lwpid, const char *field, int warn)
       return -1;
     }
 
-  while (fgets (buf, sizeof (buf), status_file.get ()))
+  while (gdb::fgets (buf, sizeof (buf), status_file.get ()))
     if (strncmp (buf, field, field_len) == 0 && buf[field_len] == ':')
       {
 	retval = strtol (&buf[field_len + 1], NULL, 10);
@@ -140,7 +141,7 @@ linux_proc_pid_get_state (pid_t pid, int warn, enum proc_state *state)
     }
 
   have_state = 0;
-  while (fgets (buffer, sizeof (buffer), procfile.get ()) != NULL)
+  while (gdb::fgets (buffer, sizeof (buffer), procfile.get ()) != NULL)
     if (startswith (buffer, "State:"))
       {
 	have_state = 1;
@@ -317,7 +318,7 @@ linux_proc_tid_get_name (ptid_t ptid)
   if (comm_file == NULL)
     return NULL;
 
-  comm_val = fgets (comm_buf, sizeof (comm_buf), comm_file.get ());
+  comm_val = gdb::fgets (comm_buf, sizeof (comm_buf), comm_file.get ());
 
   if (comm_val != NULL)
     {
diff --git a/gdbserver/linux-i386-ipa.cc b/gdbserver/linux-i386-ipa.cc
index 17af6eb3610..7d6b9600c34 100644
--- a/gdbserver/linux-i386-ipa.cc
+++ b/gdbserver/linux-i386-ipa.cc
@@ -21,6 +21,7 @@
 #include <sys/mman.h>
 #include "tracepoint.h"
 #include "gdbsupport/x86-xstate.h"
+#include "gdbsupport/eintr.h"
 #include "arch/i386-linux-tdesc.h"
 #include "arch/x86-linux-tdesc-features.h"
 
@@ -138,7 +139,7 @@ initialize_fast_tracepoint_trampoline_buffer (void)
       return;
     }
 
-  if (fgets (buf, IPA_BUFSIZ, f))
+  if (gdb::fgets (buf, IPA_BUFSIZ, f))
     sscanf (buf, "%llu", &mmap_min_addr);
       
   fclose (f);
diff --git a/gdbsupport/eintr.h b/gdbsupport/eintr.h
index 04f86c8c3df..800cab561b4 100644
--- a/gdbsupport/eintr.h
+++ b/gdbsupport/eintr.h
@@ -116,6 +116,21 @@ write (int fd, const void *buf, size_t count)
   return gdb::handle_eintr (-1, ::write, fd, buf, count);
 }
 
+inline char*
+fgets (char *str, int count, FILE* stream)
+{
+  char *ret;
+
+  do
+    {
+      errno = 0;
+      ret = ::fgets (str, count, stream);
+    }
+  while (ret == nullptr && ferror (stream) && errno == EINTR);
+
+  return ret;
+}
+
 } /* namespace gdb */
 
 #endif /* GDBSUPPORT_EINTR_H */

base-commit: 570f4c0c11910d845c35e94764ded54cb1111583
-- 
2.43.0


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH v2] [gdb] Handle EINTR in fgets
  2025-08-18  8:32 [PATCH v2] [gdb] Handle EINTR in fgets Tom de Vries
@ 2025-08-18 10:23 ` Andrew Burgess
  2025-08-18 12:29   ` Tom de Vries
  0 siblings, 1 reply; 3+ messages in thread
From: Andrew Burgess @ 2025-08-18 10:23 UTC (permalink / raw)
  To: Tom de Vries, gdb-patches

Tom de Vries <tdevries@suse.de> writes:

> Usually, find_charset_names calls iconv -l to get the list of supported
> charsets, allowing us to use a charset not in the default list:
> ...
> $ /usr/bin/gdb -q -batch -ex "set charset CP858"
> $
> ...
>
> If the call to iconv -l fails somehow, gdb silently falls back to using the
> default list, which gets us instead:
> ...
> $ PATH= /usr/bin/gdb -q -batch -ex "set charset CP858"
> Undefined item: "CP858".
> $
> ...
>
> PR gdb/33274 reports that gdb occasionally fails in the same way, because
> fgets returns nullptr before the output of iconv -l is read entirely.
>
> We asked the reporter to try out a patch handling errno == EINTR after
> fgets returns nullptr, and that fixed the problem.
>
> Fix this by:
> - adding an inline function gdb::fgets that handles EINTR, and
> - using it instead of fgets.
>
> Tested on x86_64-linux.
>
> Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=33274
> ---
>  gdb/charset.c               |  3 ++-
>  gdb/linux-nat.c             |  3 ++-
>  gdb/nat/linux-btrace.c      |  3 ++-
>  gdb/nat/linux-osdata.c      | 13 +++++++------
>  gdb/nat/linux-procfs.c      |  7 ++++---
>  gdbserver/linux-i386-ipa.cc |  3 ++-
>  gdbsupport/eintr.h          | 15 +++++++++++++++
>  7 files changed, 34 insertions(+), 13 deletions(-)
>
> diff --git a/gdb/charset.c b/gdb/charset.c
> index 259362563b2..abf3fe800d2 100644
> --- a/gdb/charset.c
> +++ b/gdb/charset.c
> @@ -25,6 +25,7 @@
>  #include "gdbsupport/environ.h"
>  #include "arch-utils.h"
>  #include <ctype.h>
> +#include "gdbsupport/eintr.h"
>  
>  #ifdef USE_WIN32API
>  #include <windows.h>
> @@ -842,7 +843,7 @@ find_charset_names (void)
>  	  char *start, *r;
>  	  int len;
>  
> -	  r = fgets (buf, sizeof (buf), in);
> +	  r = gdb::fgets (buf, sizeof (buf), in);
>  	  if (!r)
>  	    break;
>  	  len = strlen (r);
> diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
> index f3179279d92..39f1fb59ae0 100644
> --- a/gdb/linux-nat.c
> +++ b/gdb/linux-nat.c
> @@ -64,6 +64,7 @@
>  #include "gdbsupport/scope-exit.h"
>  #include "gdbsupport/gdb-sigmask.h"
>  #include "gdbsupport/common-debug.h"
> +#include "gdbsupport/eintr.h"
>  #include <unordered_map>
>  
>  /* This comment documents high-level logic of this file.
> @@ -4301,7 +4302,7 @@ linux_proc_pending_signals (int pid, sigset_t *pending,
>    if (procfile == NULL)
>      error (_("Could not open %s"), fname);
>  
> -  while (fgets (buffer, PATH_MAX, procfile.get ()) != NULL)
> +  while (gdb::fgets (buffer, PATH_MAX, procfile.get ()) != NULL)
>      {
>        /* Normal queued signals are on the SigPnd line in the status
>  	 file.  However, 2.6 kernels also have a "shared" pending
> diff --git a/gdb/nat/linux-btrace.c b/gdb/nat/linux-btrace.c
> index 9eadd46c9be..08c7b795a86 100644
> --- a/gdb/nat/linux-btrace.c
> +++ b/gdb/nat/linux-btrace.c
> @@ -26,6 +26,7 @@
>  #include "gdbsupport/filestuff.h"
>  #include "gdbsupport/scoped_fd.h"
>  #include "gdbsupport/scoped_mmap.h"
> +#include "gdbsupport/eintr.h"
>  
>  #include <inttypes.h>
>  
> @@ -202,7 +203,7 @@ linux_determine_kernel_start (void)
>        uint64_t addr;
>        int match;
>  
> -      line = fgets (buffer, sizeof (buffer), file.get ());
> +      line = gdb::fgets (buffer, sizeof (buffer), file.get ());
>        if (line == NULL)
>  	break;
>  
> diff --git a/gdb/nat/linux-osdata.c b/gdb/nat/linux-osdata.c
> index b52a8ed5f36..bfdc26f2795 100644
> --- a/gdb/nat/linux-osdata.c
> +++ b/gdb/nat/linux-osdata.c
> @@ -35,6 +35,7 @@
>  #include <dirent.h>
>  #include <sys/stat.h>
>  #include "gdbsupport/filestuff.h"
> +#include "gdbsupport/eintr.h"
>  #include <algorithm>
>  #include "linux-procfs.h"
>  
> @@ -562,7 +563,7 @@ linux_xfer_osdata_cpus ()
>  
>        do
>  	{
> -	  if (fgets (buf, sizeof (buf), fp.get ()))
> +	  if (gdb::fgets (buf, sizeof (buf), fp.get ()))
>  	    {
>  	      char *key, *value;
>  	      int i = 0;
> @@ -780,7 +781,7 @@ print_sockets (unsigned short family, int tcp, std::string &buffer)
>  
>        do
>  	{
> -	  if (fgets (buf, sizeof (buf), fp.get ()))
> +	  if (gdb::fgets (buf, sizeof (buf), fp.get ()))
>  	    {
>  	      uid_t uid;
>  	      unsigned int local_port, remote_port, state;
> @@ -961,7 +962,7 @@ linux_xfer_osdata_shm ()
>  
>        do
>  	{
> -	  if (fgets (buf, sizeof (buf), fp.get ()))
> +	  if (gdb::fgets (buf, sizeof (buf), fp.get ()))
>  	    {
>  	      key_t key;
>  	      uid_t uid, cuid;
> @@ -1057,7 +1058,7 @@ linux_xfer_osdata_sem ()
>  
>        do
>  	{
> -	  if (fgets (buf, sizeof (buf), fp.get ()))
> +	  if (gdb::fgets (buf, sizeof (buf), fp.get ()))
>  	    {
>  	      key_t key;
>  	      uid_t uid, cuid;
> @@ -1137,7 +1138,7 @@ linux_xfer_osdata_msg ()
>  
>        do
>  	{
> -	  if (fgets (buf, sizeof (buf), fp.get ()))
> +	  if (gdb::fgets (buf, sizeof (buf), fp.get ()))
>  	    {
>  	      key_t key;
>  	      PID_T lspid, lrpid;
> @@ -1231,7 +1232,7 @@ linux_xfer_osdata_modules ()
>  
>        do
>  	{
> -	  if (fgets (buf, sizeof (buf), fp.get ()))
> +	  if (gdb::fgets (buf, sizeof (buf), fp.get ()))
>  	    {
>  	      char *name, *dependencies, *status, *tmp, *saveptr;
>  	      unsigned int size;
> diff --git a/gdb/nat/linux-procfs.c b/gdb/nat/linux-procfs.c
> index d4f9af32bb9..1927a21314e 100644
> --- a/gdb/nat/linux-procfs.c
> +++ b/gdb/nat/linux-procfs.c
> @@ -19,6 +19,7 @@
>  #include "linux-procfs.h"
>  #include "gdbsupport/filestuff.h"
>  #include "gdbsupport/unordered_set.h"
> +#include "gdbsupport/eintr.h"
>  #include <dirent.h>
>  #include <sys/stat.h>
>  #include <utility>
> @@ -42,7 +43,7 @@ linux_proc_get_int (pid_t lwpid, const char *field, int warn)
>        return -1;
>      }
>  
> -  while (fgets (buf, sizeof (buf), status_file.get ()))
> +  while (gdb::fgets (buf, sizeof (buf), status_file.get ()))
>      if (strncmp (buf, field, field_len) == 0 && buf[field_len] == ':')
>        {
>  	retval = strtol (&buf[field_len + 1], NULL, 10);
> @@ -140,7 +141,7 @@ linux_proc_pid_get_state (pid_t pid, int warn, enum proc_state *state)
>      }
>  
>    have_state = 0;
> -  while (fgets (buffer, sizeof (buffer), procfile.get ()) != NULL)
> +  while (gdb::fgets (buffer, sizeof (buffer), procfile.get ()) != NULL)
>      if (startswith (buffer, "State:"))
>        {
>  	have_state = 1;
> @@ -317,7 +318,7 @@ linux_proc_tid_get_name (ptid_t ptid)
>    if (comm_file == NULL)
>      return NULL;
>  
> -  comm_val = fgets (comm_buf, sizeof (comm_buf), comm_file.get ());
> +  comm_val = gdb::fgets (comm_buf, sizeof (comm_buf), comm_file.get ());
>  
>    if (comm_val != NULL)
>      {
> diff --git a/gdbserver/linux-i386-ipa.cc b/gdbserver/linux-i386-ipa.cc
> index 17af6eb3610..7d6b9600c34 100644
> --- a/gdbserver/linux-i386-ipa.cc
> +++ b/gdbserver/linux-i386-ipa.cc
> @@ -21,6 +21,7 @@
>  #include <sys/mman.h>
>  #include "tracepoint.h"
>  #include "gdbsupport/x86-xstate.h"
> +#include "gdbsupport/eintr.h"
>  #include "arch/i386-linux-tdesc.h"
>  #include "arch/x86-linux-tdesc-features.h"
>  
> @@ -138,7 +139,7 @@ initialize_fast_tracepoint_trampoline_buffer (void)
>        return;
>      }
>  
> -  if (fgets (buf, IPA_BUFSIZ, f))
> +  if (gdb::fgets (buf, IPA_BUFSIZ, f))
>      sscanf (buf, "%llu", &mmap_min_addr);
>        
>    fclose (f);
> diff --git a/gdbsupport/eintr.h b/gdbsupport/eintr.h
> index 04f86c8c3df..800cab561b4 100644
> --- a/gdbsupport/eintr.h
> +++ b/gdbsupport/eintr.h
> @@ -116,6 +116,21 @@ write (int fd, const void *buf, size_t count)
>    return gdb::handle_eintr (-1, ::write, fd, buf, count);
>  }
>  
> +inline char*
> +fgets (char *str, int count, FILE* stream)
> +{
> +  char *ret;
> +
> +  do
> +    {
> +      errno = 0;
> +      ret = ::fgets (str, count, stream);
> +    }
> +  while (ret == nullptr && ferror (stream) && errno == EINTR);

Having read through the v1 thread, I just want to make sure I'm clear on
the motivation for not using handle_eintr:  your concern is that errno
might be set in the EOF case?

I'm not arguing with your reading of the spec, but that does seem
unlikely.  So much so that I do think that's worth a comment explaining
the logic here.  It's also worth the comment explaining that we've never
_seen_ such behaviour, just that we're worried such behaviour _might_ be
in-spec.

That comment could fill in the missing header comment for this function.

Thanks,
Andrew


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH v2] [gdb] Handle EINTR in fgets
  2025-08-18 10:23 ` Andrew Burgess
@ 2025-08-18 12:29   ` Tom de Vries
  0 siblings, 0 replies; 3+ messages in thread
From: Tom de Vries @ 2025-08-18 12:29 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches

On 8/18/25 12:23, Andrew Burgess wrote:
> Tom de Vries <tdevries@suse.de> writes:
> 
>> Usually, find_charset_names calls iconv -l to get the list of supported
>> charsets, allowing us to use a charset not in the default list:
>> ...
>> $ /usr/bin/gdb -q -batch -ex "set charset CP858"
>> $
>> ...
>>
>> If the call to iconv -l fails somehow, gdb silently falls back to using the
>> default list, which gets us instead:
>> ...
>> $ PATH= /usr/bin/gdb -q -batch -ex "set charset CP858"
>> Undefined item: "CP858".
>> $
>> ...
>>
>> PR gdb/33274 reports that gdb occasionally fails in the same way, because
>> fgets returns nullptr before the output of iconv -l is read entirely.
>>
>> We asked the reporter to try out a patch handling errno == EINTR after
>> fgets returns nullptr, and that fixed the problem.
>>
>> Fix this by:
>> - adding an inline function gdb::fgets that handles EINTR, and
>> - using it instead of fgets.
>>
>> Tested on x86_64-linux.
>>
>> Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=33274
>> ---
>>   gdb/charset.c               |  3 ++-
>>   gdb/linux-nat.c             |  3 ++-
>>   gdb/nat/linux-btrace.c      |  3 ++-
>>   gdb/nat/linux-osdata.c      | 13 +++++++------
>>   gdb/nat/linux-procfs.c      |  7 ++++---
>>   gdbserver/linux-i386-ipa.cc |  3 ++-
>>   gdbsupport/eintr.h          | 15 +++++++++++++++
>>   7 files changed, 34 insertions(+), 13 deletions(-)
>>
>> diff --git a/gdb/charset.c b/gdb/charset.c
>> index 259362563b2..abf3fe800d2 100644
>> --- a/gdb/charset.c
>> +++ b/gdb/charset.c
>> @@ -25,6 +25,7 @@
>>   #include "gdbsupport/environ.h"
>>   #include "arch-utils.h"
>>   #include <ctype.h>
>> +#include "gdbsupport/eintr.h"
>>   
>>   #ifdef USE_WIN32API
>>   #include <windows.h>
>> @@ -842,7 +843,7 @@ find_charset_names (void)
>>   	  char *start, *r;
>>   	  int len;
>>   
>> -	  r = fgets (buf, sizeof (buf), in);
>> +	  r = gdb::fgets (buf, sizeof (buf), in);
>>   	  if (!r)
>>   	    break;
>>   	  len = strlen (r);
>> diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
>> index f3179279d92..39f1fb59ae0 100644
>> --- a/gdb/linux-nat.c
>> +++ b/gdb/linux-nat.c
>> @@ -64,6 +64,7 @@
>>   #include "gdbsupport/scope-exit.h"
>>   #include "gdbsupport/gdb-sigmask.h"
>>   #include "gdbsupport/common-debug.h"
>> +#include "gdbsupport/eintr.h"
>>   #include <unordered_map>
>>   
>>   /* This comment documents high-level logic of this file.
>> @@ -4301,7 +4302,7 @@ linux_proc_pending_signals (int pid, sigset_t *pending,
>>     if (procfile == NULL)
>>       error (_("Could not open %s"), fname);
>>   
>> -  while (fgets (buffer, PATH_MAX, procfile.get ()) != NULL)
>> +  while (gdb::fgets (buffer, PATH_MAX, procfile.get ()) != NULL)
>>       {
>>         /* Normal queued signals are on the SigPnd line in the status
>>   	 file.  However, 2.6 kernels also have a "shared" pending
>> diff --git a/gdb/nat/linux-btrace.c b/gdb/nat/linux-btrace.c
>> index 9eadd46c9be..08c7b795a86 100644
>> --- a/gdb/nat/linux-btrace.c
>> +++ b/gdb/nat/linux-btrace.c
>> @@ -26,6 +26,7 @@
>>   #include "gdbsupport/filestuff.h"
>>   #include "gdbsupport/scoped_fd.h"
>>   #include "gdbsupport/scoped_mmap.h"
>> +#include "gdbsupport/eintr.h"
>>   
>>   #include <inttypes.h>
>>   
>> @@ -202,7 +203,7 @@ linux_determine_kernel_start (void)
>>         uint64_t addr;
>>         int match;
>>   
>> -      line = fgets (buffer, sizeof (buffer), file.get ());
>> +      line = gdb::fgets (buffer, sizeof (buffer), file.get ());
>>         if (line == NULL)
>>   	break;
>>   
>> diff --git a/gdb/nat/linux-osdata.c b/gdb/nat/linux-osdata.c
>> index b52a8ed5f36..bfdc26f2795 100644
>> --- a/gdb/nat/linux-osdata.c
>> +++ b/gdb/nat/linux-osdata.c
>> @@ -35,6 +35,7 @@
>>   #include <dirent.h>
>>   #include <sys/stat.h>
>>   #include "gdbsupport/filestuff.h"
>> +#include "gdbsupport/eintr.h"
>>   #include <algorithm>
>>   #include "linux-procfs.h"
>>   
>> @@ -562,7 +563,7 @@ linux_xfer_osdata_cpus ()
>>   
>>         do
>>   	{
>> -	  if (fgets (buf, sizeof (buf), fp.get ()))
>> +	  if (gdb::fgets (buf, sizeof (buf), fp.get ()))
>>   	    {
>>   	      char *key, *value;
>>   	      int i = 0;
>> @@ -780,7 +781,7 @@ print_sockets (unsigned short family, int tcp, std::string &buffer)
>>   
>>         do
>>   	{
>> -	  if (fgets (buf, sizeof (buf), fp.get ()))
>> +	  if (gdb::fgets (buf, sizeof (buf), fp.get ()))
>>   	    {
>>   	      uid_t uid;
>>   	      unsigned int local_port, remote_port, state;
>> @@ -961,7 +962,7 @@ linux_xfer_osdata_shm ()
>>   
>>         do
>>   	{
>> -	  if (fgets (buf, sizeof (buf), fp.get ()))
>> +	  if (gdb::fgets (buf, sizeof (buf), fp.get ()))
>>   	    {
>>   	      key_t key;
>>   	      uid_t uid, cuid;
>> @@ -1057,7 +1058,7 @@ linux_xfer_osdata_sem ()
>>   
>>         do
>>   	{
>> -	  if (fgets (buf, sizeof (buf), fp.get ()))
>> +	  if (gdb::fgets (buf, sizeof (buf), fp.get ()))
>>   	    {
>>   	      key_t key;
>>   	      uid_t uid, cuid;
>> @@ -1137,7 +1138,7 @@ linux_xfer_osdata_msg ()
>>   
>>         do
>>   	{
>> -	  if (fgets (buf, sizeof (buf), fp.get ()))
>> +	  if (gdb::fgets (buf, sizeof (buf), fp.get ()))
>>   	    {
>>   	      key_t key;
>>   	      PID_T lspid, lrpid;
>> @@ -1231,7 +1232,7 @@ linux_xfer_osdata_modules ()
>>   
>>         do
>>   	{
>> -	  if (fgets (buf, sizeof (buf), fp.get ()))
>> +	  if (gdb::fgets (buf, sizeof (buf), fp.get ()))
>>   	    {
>>   	      char *name, *dependencies, *status, *tmp, *saveptr;
>>   	      unsigned int size;
>> diff --git a/gdb/nat/linux-procfs.c b/gdb/nat/linux-procfs.c
>> index d4f9af32bb9..1927a21314e 100644
>> --- a/gdb/nat/linux-procfs.c
>> +++ b/gdb/nat/linux-procfs.c
>> @@ -19,6 +19,7 @@
>>   #include "linux-procfs.h"
>>   #include "gdbsupport/filestuff.h"
>>   #include "gdbsupport/unordered_set.h"
>> +#include "gdbsupport/eintr.h"
>>   #include <dirent.h>
>>   #include <sys/stat.h>
>>   #include <utility>
>> @@ -42,7 +43,7 @@ linux_proc_get_int (pid_t lwpid, const char *field, int warn)
>>         return -1;
>>       }
>>   
>> -  while (fgets (buf, sizeof (buf), status_file.get ()))
>> +  while (gdb::fgets (buf, sizeof (buf), status_file.get ()))
>>       if (strncmp (buf, field, field_len) == 0 && buf[field_len] == ':')
>>         {
>>   	retval = strtol (&buf[field_len + 1], NULL, 10);
>> @@ -140,7 +141,7 @@ linux_proc_pid_get_state (pid_t pid, int warn, enum proc_state *state)
>>       }
>>   
>>     have_state = 0;
>> -  while (fgets (buffer, sizeof (buffer), procfile.get ()) != NULL)
>> +  while (gdb::fgets (buffer, sizeof (buffer), procfile.get ()) != NULL)
>>       if (startswith (buffer, "State:"))
>>         {
>>   	have_state = 1;
>> @@ -317,7 +318,7 @@ linux_proc_tid_get_name (ptid_t ptid)
>>     if (comm_file == NULL)
>>       return NULL;
>>   
>> -  comm_val = fgets (comm_buf, sizeof (comm_buf), comm_file.get ());
>> +  comm_val = gdb::fgets (comm_buf, sizeof (comm_buf), comm_file.get ());
>>   
>>     if (comm_val != NULL)
>>       {
>> diff --git a/gdbserver/linux-i386-ipa.cc b/gdbserver/linux-i386-ipa.cc
>> index 17af6eb3610..7d6b9600c34 100644
>> --- a/gdbserver/linux-i386-ipa.cc
>> +++ b/gdbserver/linux-i386-ipa.cc
>> @@ -21,6 +21,7 @@
>>   #include <sys/mman.h>
>>   #include "tracepoint.h"
>>   #include "gdbsupport/x86-xstate.h"
>> +#include "gdbsupport/eintr.h"
>>   #include "arch/i386-linux-tdesc.h"
>>   #include "arch/x86-linux-tdesc-features.h"
>>   
>> @@ -138,7 +139,7 @@ initialize_fast_tracepoint_trampoline_buffer (void)
>>         return;
>>       }
>>   
>> -  if (fgets (buf, IPA_BUFSIZ, f))
>> +  if (gdb::fgets (buf, IPA_BUFSIZ, f))
>>       sscanf (buf, "%llu", &mmap_min_addr);
>>         
>>     fclose (f);
>> diff --git a/gdbsupport/eintr.h b/gdbsupport/eintr.h
>> index 04f86c8c3df..800cab561b4 100644
>> --- a/gdbsupport/eintr.h
>> +++ b/gdbsupport/eintr.h
>> @@ -116,6 +116,21 @@ write (int fd, const void *buf, size_t count)
>>     return gdb::handle_eintr (-1, ::write, fd, buf, count);
>>   }
>>   
>> +inline char*
>> +fgets (char *str, int count, FILE* stream)
>> +{
>> +  char *ret;
>> +
>> +  do
>> +    {
>> +      errno = 0;
>> +      ret = ::fgets (str, count, stream);
>> +    }
>> +  while (ret == nullptr && ferror (stream) && errno == EINTR);
> 
> Having read through the v1 thread, I just want to make sure I'm clear on
> the motivation for not using handle_eintr:  your concern is that errno
> might be set in the EOF case?
> 

Hi Andrew,

thanks for the review.

Yes, that is my concern.

> I'm not arguing with your reading of the spec, but that does seem
> unlikely. 

Agreed.

> So much so that I do think that's worth a comment explaining
> the logic here.  It's also worth the comment explaining that we've never
> _seen_ such behaviour, just that we're worried such behaviour _might_ be
> in-spec.
> 

Good point.  I've added a comment in a v3 ( 
https://sourceware.org/pipermail/gdb-patches/2025-August/220017.html ).

> That comment could fill in the missing header comment for this function.
> 

Since it's a comment about the implementation of the function, I've 
added it in the function.

[ The missing header comment seems to be a feature of all the functions 
in the file, probably because they're wrappers and the interface is 
defined by what they're wrapping, and there's only one difference in 
behaviour implemented by the wrapper, which is described in detail at 
the top of the file. ]

Thanks,
- Tom

> Thanks,
> Andrew
> 


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2025-08-18 12:30 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-08-18  8:32 [PATCH v2] [gdb] Handle EINTR in fgets Tom de Vries
2025-08-18 10:23 ` Andrew Burgess
2025-08-18 12:29   ` Tom de Vries

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox