On Monday 13 October 2008 06:48:22 am Rob Landley wrote:
> If you use the cursor keys in vi, it adds three characters at a time.  (The 
> ansi "move cursor" sequence for the direction you hit.)  If you hold it down 
> so it repeats, on a slow system (such as qemu's arm emulation) or one that's 
> heavily loaded, you can easily have several of them queue up before VI gets 
> scheduled again.
> 
> A dozen times 3 characters is 36 characters.  If you look at editors/vi.c 
> line 
> 216 you'll see that the buffer you're reading into (readbuffer) is 32 
> characters.  I.E. your buffer is not divisible by 3, so it'll read an even 10 
> cursor lefts, plus an escape left bracket pair which isn't part of a 
> recognized sequence, so is interpreted as separate characters.  The escape 
> drops you out of insert mode and into edit mode.
> 
> Next time it reads a buffer, it starts with the last character of a cursor 
> left sequence: capital D.  Capital D is "delete to end of line", which it 
> does.
> 
> So basically, busybox vi is corrupting your data when you cursor around in a 
> file on a loaded system.  Wheee...

Please try this patch, and let me know whether it helps.
--
vda
diff -d -urpN busybox.1/editors/vi.c busybox.2/editors/vi.c
--- busybox.1/editors/vi.c	2008-09-28 17:02:14.000000000 +0200
+++ busybox.2/editors/vi.c	2008-10-14 11:21:44.000000000 +0200
@@ -293,6 +293,9 @@ struct globals {
 	last_file_modified = -1; \
 } while (0)
 
+/* We want to have space for guard NUL: */
+#define readbuffer_size ((int)sizeof(readbuffer) - 1)
+
 
 static int init_text_buffer(char *); // init from file or create new
 static void edit_file(char *);	// edit one file
@@ -2250,39 +2253,41 @@ static char readit(void)	// read (maybe 
 	// get input from User - are there already input chars in Q?
 	if (n <= 0) {
 		// the Q is empty, wait for a typed char
- again:
-		n = safe_read(STDIN_FILENO, readbuffer, sizeof(readbuffer));
+		n = safe_read(STDIN_FILENO, readbuffer, readbuffer_size);
 		if (n <= 0) {
+ error:
 			place_cursor(rows - 1, 0, FALSE); // go to bottom of screen
 			clear_to_eol(); // erase to end of line
 			cookmode(); // terminal to "cooked"
 			bb_error_msg_and_die("can't read user input");
 		}
-		/* elsewhere we can get very confused by NULs */
-		if (readbuffer[0] == '\0')
-			goto again;
-		if (readbuffer[0] == 27) {
-			// This is an ESC char. Is this Esc sequence?
-			// Could be bare Esc key. See if there are any
-			// more chars to read after the ESC. This would
-			// be a Function or Cursor Key sequence.
-			struct pollfd pfd[1];
-			pfd[0].fd = 0;
-			pfd[0].events = POLLIN;
-			// keep reading while there are input chars, and room in buffer
-			// for a complete ESC sequence (assuming 8 chars is enough)
-			while ((safe_poll(pfd, 1, 0) > 0)
-			 && ((size_t)n <= (sizeof(readbuffer) - 8))
-			) {
-				// read the rest of the ESC string
-				int r = safe_read(STDIN_FILENO, readbuffer + n, sizeof(readbuffer) - n);
-				if (r > 0)
-					n += r;
-			}
-		}
-		chars_to_parse = n;
 	}
 	c = readbuffer[0];
+	/* elsewhere we can get very confused by NULs */
+	if (c == '\0')
+		c = ' ';
+	if (c == 27) {
+		// This is an ESC char,
+		// is this a whole Fn or cursor key sequence?
+		struct pollfd pfd[1];
+		pfd[0].fd = STDIN_FILENO;
+		pfd[0].events = POLLIN;
+		// Keep reading while there are room in buffer, and input chars
+		while (n < readbuffer_size
+		 && safe_poll(pfd, 1, /*timeout:*/ 0) > 0
+		) {
+			// Read the rest of the ESC string
+			int r = safe_read(STDIN_FILENO, readbuffer + n, readbuffer_size - n);
+			if (r < 0) // (btw, this can't be EAGAIN or EINTR)
+				goto error;
+			n += r;
+		}
+	}
+	// Prevent misdetection of ESC sequences
+	// (NB: potential store to readbuffer[readbuffer_size] is ok)
+	readbuffer[n] = '\0';
+
+	chars_to_parse = n;
 	if (c == 27 && n > 1) {
 		// Maybe cursor or function key?
 		const struct esc_cmds *eindex;
@@ -2294,12 +2299,12 @@ static char readit(void)	// read (maybe 
 			if (strncmp(eindex->seq, readbuffer + 1, cnt) != 0)
 				continue;
 			c = eindex->val; // magic char value
-			n = cnt + 1; // squeeze out the ESC sequence
+			n = 1 + cnt; // remove ESC + the rest of seq
 			goto found;
 		}
 		// defined ESC sequence not found
 	}
-	n = 1;
+	n = 1; // remove 1 char
  found:
 	// remove key sequence from Q
 	chars_to_parse -= n;
_______________________________________________
busybox mailing list
busybox@busybox.net
http://busybox.net/cgi-bin/mailman/listinfo/busybox

Reply via email to