Re: [PATCH 2/2] Fix EOF handling.

Antonio Ceballos <[email protected]> Thu, 21 Aug 2025 17:57:59 +0200
Newsgroups gmane.comp.gnu.chess.bugs
Message-ID <CAO7R9g-40nHcGK0iyQkXD2stpEVi1aZ-3URGUQHSfDfKg_0=yw@mail.gmail.com>
--000000000000f56ea1063ce227e0
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

Hi Rudolf,

Thank you very much for your new patches. They will be included in the
release 6.3.0.

Best regards,
Antonio Ceballos


On Mon, Jul 7, 2025 at 3:55=E2=80=AFPM <[email protected]> wrote:

> From: Rudolf Polzer <[email protected]>
>
> Fixes endless loop when stdin ends:
>
> ```
> $ src/gnuchess </dev/null
> GNU Chess
> White (1) : Can't open file "(null)": Bad address - using defaults
> Invalid move:
> White (1) : Invalid move:
> White (1) : Invalid move:
> White (1) : Invalid move:
> White (1) : Invalid move:
> White (1) : Invalid move:
> White (1) : Invalid move:
> [...]
> ```
>
> and
>
> ```
> $ src/gnuchess --uci </dev/null
> GNU Chess
> ```
>
> (no log spam, but process hangs and eats CPU)
>
> Implementation is separate for UCI and XBoard/console protocols
>
> ---
>  src/frontend/common.h  |  2 +-
>  src/frontend/engine.cc |  2 +-
>  src/frontend/input.cc  | 13 ++++++++-----
>  3 files changed, 10 insertions(+), 7 deletions(-)
>
> diff --git a/src/frontend/common.h b/src/frontend/common.h
> index 193bd62..b4e8141 100644
> --- a/src/frontend/common.h
> +++ b/src/frontend/common.h
> @@ -515,7 +515,7 @@ void input_wakeup(void);
>   * Input routine, initialized to one of the specific
>   * input routines. The given argument is the prompt.
>   */
> -extern void (*get_line) (char *);
> +extern int (*get_line) (char *);
>
>  #define BUF_SIZE 4096
>
> diff --git a/src/frontend/engine.cc b/src/frontend/engine.cc
> index 6f8cf50..16a881f 100644
> --- a/src/frontend/engine.cc
> +++ b/src/frontend/engine.cc
> @@ -523,7 +523,7 @@ void ForwardUserInputToEngine( void )
>      assert( nread <=3D BUF_SIZE-2 );
>      userinputaux[nread] =3D '\n';
>      userinputaux[nread+1] =3D '\0';
> -    if ( strcmp(userinputaux,"quit\n") =3D=3D 0 ||
> strcmp(userinputaux,"quit\n\n") =3D=3D 0 ) {
> +    if ( nread =3D=3D 0 || strcmp(userinputaux,"quit\n") =3D=3D 0 ||
> strcmp(userinputaux,"quit\n\n") =3D=3D 0 ) {
>           SET (flags, QUIT);
>      }
>      int outError=3D0;
> diff --git a/src/frontend/input.cc b/src/frontend/input.cc
> index a8e4493..c2d90a9 100644
> --- a/src/frontend/input.cc
> +++ b/src/frontend/input.cc
> @@ -54,7 +54,7 @@ extern char* readline(char *);
>  extern void add_history(char *);
>  # endif
>  #endif
> -void (*get_line)(char * p);
> +int (*get_line)(char * p);
>
>  /* Variable used to communicate with the main thread */
>  volatile int input_status =3D INPUT_NONE;
> @@ -71,7 +71,7 @@ pthread_mutex_t     input_mutex =3D
> PTHREAD_MUTEX_INITIALIZER;
>   */
>
>  #ifdef HAVE_LIBREADLINE
> -void getline_readline(char * p)
> +int getline_readline(char * p)
>  {
>    char *inp;
>
> @@ -86,18 +86,19 @@ void getline_readline(char * p)
>    if (inp) {
>      free(inp);
>    }
> +  return inp !=3D NULL;
>  }
>  #endif /* HAVE_LIBREADLINE */
>
>  /* The generic input routine */
>
> -void getline_standard(char *p)
> +int getline_standard(char *p)
>  {
>    if (!(flags & XBOARD)) {
>      fputs(p, stdout);
>      fflush(stdout);
>    }
> -  if ( fgets(userinputstr, MAXSTR, stdin) );  // TODO Handle return valu=
e
> +  return fgets(userinputstr, MAXSTR, stdin) !=3D NULL;
>  }
>
>  /*
> @@ -150,7 +151,9 @@ void *input_func(void *arg __attribute__((unused)) )
>               RealSide ? _("Black") : _("White"),
>               (RealGameCnt+1)/2 + 1 );
>      }
> -    get_line(prompt);
> +    if (!get_line(prompt)) {
> +      SET(flags, QUIT);
> +    }
>      SendToFrontend( userinputstr );
>  #ifdef HAVE_LIBREADLINE
>      const char new_line[]=3D"\n";
> --
> 2.39.5
>
>
>

--000000000000f56ea1063ce227e0
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div class=3D"gmail_default" style=3D"font-size:small">Hi =
Rudolf,</div><div class=3D"gmail_default" style=3D"font-size:small"><br></d=
iv><div class=3D"gmail_default" style=3D"font-size:small">Thank you very mu=
ch for your new patches. They will be included in the release 6.3.0.</div><=
div class=3D"gmail_default" style=3D"font-size:small"><br></div><div class=
=3D"gmail_default" style=3D"font-size:small">Best regards,</div><div class=
=3D"gmail_default" style=3D"font-size:small">Antonio Ceballos</div><div cla=
ss=3D"gmail_default" style=3D"font-size:small"><br></div></div><br><div cla=
ss=3D"gmail_quote gmail_quote_container"><div dir=3D"ltr" class=3D"gmail_at=
tr">On Mon, Jul 7, 2025 at 3:55=E2=80=AFPM &lt;<a href=3D"mailto:divverent@=
gmail.com">[email protected]</a>&gt; wrote:<br></div><blockquote class=3D=
"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(2=
04,204,204);padding-left:1ex">From: Rudolf Polzer &lt;<a href=3D"mailto:div=
[email protected]" target=3D"_blank">[email protected]</a>&gt;<br>
<br>
Fixes endless loop when stdin ends:<br>
<br>
```<br>
$ src/gnuchess &lt;/dev/null<br>
GNU Chess<br>
White (1) : Can&#39;t open file &quot;(null)&quot;: Bad address - using def=
aults<br>
Invalid move:<br>
White (1) : Invalid move:<br>
White (1) : Invalid move:<br>
White (1) : Invalid move:<br>
White (1) : Invalid move:<br>
White (1) : Invalid move:<br>
White (1) : Invalid move:<br>
[...]<br>
```<br>
<br>
and<br>
<br>
```<br>
$ src/gnuchess --uci &lt;/dev/null<br>
GNU Chess<br>
```<br>
<br>
(no log spam, but process hangs and eats CPU)<br>
<br>
Implementation is separate for UCI and XBoard/console protocols <br>
<br>
---<br>
=C2=A0src/frontend/common.h=C2=A0 |=C2=A0 2 +-<br>
=C2=A0src/frontend/engine.cc |=C2=A0 2 +-<br>
=C2=A0src/frontend/input.cc=C2=A0 | 13 ++++++++-----<br>
=C2=A03 files changed, 10 insertions(+), 7 deletions(-)<br>
<br>
diff --git a/src/frontend/common.h b/src/frontend/common.h<br>
index 193bd62..b4e8141 100644<br>
--- a/src/frontend/common.h<br>
+++ b/src/frontend/common.h<br>
@@ -515,7 +515,7 @@ void input_wakeup(void);<br>
=C2=A0 * Input routine, initialized to one of the specific<br>
=C2=A0 * input routines. The given argument is the prompt.<br>
=C2=A0 */<br>
-extern void (*get_line) (char *);<br>
+extern int (*get_line) (char *);<br>
<br>
=C2=A0#define BUF_SIZE 4096<br>
<br>
diff --git a/src/frontend/engine.cc b/src/frontend/engine.cc<br>
index 6f8cf50..16a881f 100644<br>
--- a/src/frontend/engine.cc<br>
+++ b/src/frontend/engine.cc<br>
@@ -523,7 +523,7 @@ void ForwardUserInputToEngine( void )<br>
=C2=A0 =C2=A0 =C2=A0assert( nread &lt;=3D BUF_SIZE-2 );<br>
=C2=A0 =C2=A0 =C2=A0userinputaux[nread] =3D &#39;\n&#39;;<br>
=C2=A0 =C2=A0 =C2=A0userinputaux[nread+1] =3D &#39;\0&#39;;<br>
-=C2=A0 =C2=A0 if ( strcmp(userinputaux,&quot;quit\n&quot;) =3D=3D 0 || str=
cmp(userinputaux,&quot;quit\n\n&quot;) =3D=3D 0 ) {<br>
+=C2=A0 =C2=A0 if ( nread =3D=3D 0 || strcmp(userinputaux,&quot;quit\n&quot=
;) =3D=3D 0 || strcmp(userinputaux,&quot;quit\n\n&quot;) =3D=3D 0 ) {<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 SET (flags, QUIT);<br>
=C2=A0 =C2=A0 =C2=A0}<br>
=C2=A0 =C2=A0 =C2=A0int outError=3D0;<br>
diff --git a/src/frontend/input.cc b/src/frontend/input.cc<br>
index a8e4493..c2d90a9 100644<br>
--- a/src/frontend/input.cc<br>
+++ b/src/frontend/input.cc<br>
@@ -54,7 +54,7 @@ extern char* readline(char *);<br>
=C2=A0extern void add_history(char *);<br>
=C2=A0# endif<br>
=C2=A0#endif<br>
-void (*get_line)(char * p);<br>
+int (*get_line)(char * p);<br>
<br>
=C2=A0/* Variable used to communicate with the main thread */<br>
=C2=A0volatile int input_status =3D INPUT_NONE;<br>
@@ -71,7 +71,7 @@ pthread_mutex_t=C2=A0 =C2=A0 =C2=A0input_mutex =3D PTHREA=
D_MUTEX_INITIALIZER;<br>
=C2=A0 */<br>
<br>
=C2=A0#ifdef HAVE_LIBREADLINE<br>
-void getline_readline(char * p)<br>
+int getline_readline(char * p)<br>
=C2=A0{<br>
=C2=A0 =C2=A0char *inp;<br>
<br>
@@ -86,18 +86,19 @@ void getline_readline(char * p)<br>
=C2=A0 =C2=A0if (inp) {<br>
=C2=A0 =C2=A0 =C2=A0free(inp);<br>
=C2=A0 =C2=A0}<br>
+=C2=A0 return inp !=3D NULL;<br>
=C2=A0}<br>
=C2=A0#endif /* HAVE_LIBREADLINE */<br>
<br>
=C2=A0/* The generic input routine */<br>
<br>
-void getline_standard(char *p)<br>
+int getline_standard(char *p)<br>
=C2=A0{<br>
=C2=A0 =C2=A0if (!(flags &amp; XBOARD)) {<br>
=C2=A0 =C2=A0 =C2=A0fputs(p, stdout);<br>
=C2=A0 =C2=A0 =C2=A0fflush(stdout);<br>
=C2=A0 =C2=A0}<br>
-=C2=A0 if ( fgets(userinputstr, MAXSTR, stdin) );=C2=A0 // TODO Handle ret=
urn value<br>
+=C2=A0 return fgets(userinputstr, MAXSTR, stdin) !=3D NULL;<br>
=C2=A0}<br>
<br>
=C2=A0/*<br>
@@ -150,7 +151,9 @@ void *input_func(void *arg __attribute__((unused)) )<br=
>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 RealSide ? _(&quot;Black&q=
uot;) : _(&quot;White&quot;), <br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (RealGameCnt+1)/2 + 1 );<b=
r>
=C2=A0 =C2=A0 =C2=A0}<br>
-=C2=A0 =C2=A0 get_line(prompt);<br>
+=C2=A0 =C2=A0 if (!get_line(prompt)) {<br>
+=C2=A0 =C2=A0 =C2=A0 SET(flags, QUIT);<br>
+=C2=A0 =C2=A0 }<br>
=C2=A0 =C2=A0 =C2=A0SendToFrontend( userinputstr );<br>
=C2=A0#ifdef HAVE_LIBREADLINE<br>
=C2=A0 =C2=A0 =C2=A0const char new_line[]=3D&quot;\n&quot;;<br>
-- <br>
2.39.5<br>
<br>
<br>
</blockquote></div>

--000000000000f56ea1063ce227e0--