From 0da32f28029fcdda90f4726269dfba760a5bc415 Mon Sep 17 00:00:00 2001
From: "Stephen R. van den Berg" <srb@cuci.nl>
Date: Thu, 17 May 2018 17:16:45 +0200
Subject: [PATCH] Stdio.Buffer: Eliminates race condition from read_cstring().

In addition it makes read_cstring():
- Restartable after buffer changes from range_error().
- Call range_error(0) just like sscanf().
- Faster.

The race condition occurred after a pause due to range_error(),
the subsequent io_rewind() at the end could not rewind far enough.
---
 src/modules/_Stdio/buffer.cmod | 40 +++++++++++-----------------------
 1 file changed, 13 insertions(+), 27 deletions(-)

diff --git a/src/modules/_Stdio/buffer.cmod b/src/modules/_Stdio/buffer.cmod
index 43a86025f2..d0ad267e47 100644
--- a/src/modules/_Stdio/buffer.cmod
+++ b/src/modules/_Stdio/buffer.cmod
@@ -1783,39 +1783,25 @@ PIKECLASS Buffer
    *!
    *! Note that pike string can not be longer than 0x7fffffff bytes (~2Gb).
    */
-  PIKEFUN string(0..255) read_cstring( )
+  PIKEFUN string(0..255) read_cstring()
   {
-    LONGEST len;
     Buffer *io = THIS;
-    struct pike_string *s;
-    ONERROR e;
 
-    io_rewind_on_error( io, &e );
-    len = 0;
-    do {
-      /* search the amount of data we know we have for each call to io_avail */
-      while( io_len(io) )
+    do
+      if ( LIKELY(io_len(THIS)) )
       {
-        if( !io_read_byte_uc(io) )
-          goto found_null;
-        len++;
+        const char * start = io_read_pointer(io);
+        const char * end = memchr(start, 0, io_len(io));
+        if ( LIKELY(end) )
+        {
+          push_string(io_read_string(io, end - start));
+          io_read_byte_uc(io);		  /* consume the terminating \0 byte */
+          return;
+        }
       }
-    }
-    while( io_avail( io, 1 ) );
-    goto fail;
+    while ( UNLIKELY(io_range_error(THIS, 0)) );
 
-  found_null:
-    io_rewind( io, len+1 );
-    s = io_read_string( io, len );
-
-    if( LIKELY(s) ) {
-      io_read_byte_uc(io);		  /* consume the terminating \0 byte */
-      io_unset_rewind_on_error( io, &e );
-      push_string(s);
-    } else {
-fail: CALL_AND_UNSET_ONERROR(e);
-      push_undefined();
-    }
+    push_undefined();
   }
 
   /*! @decl Buffer read_hbuffer( int n )
-- 
GitLab