This patch fixes three things that seemed off to me.

1. If you enter a count that is too large for a long; you just get the 
arbitrary value 999999999L.  This patch causes normal_cmd(...) to fail.

2. If you try to read a value from the screen (with ctrla/ctrlx) that causes an 
overflow, vim will just use the part of the value coming after the overflow; 
this patch ``does nothing'' instead.

3. If your ctrla/ctrlx produces a value that causes an unsigned overflow, vim 
will do wrapping for decimal, hex and octal.  I think that it should not wrap 
for decimal and instead do nothing.

At the very least, I think it is much saner to use strtoul(...) in 
vim_str2nr(...) as opposed to the rollyourown solution.

Patch attached.

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.
>From f80e0b95d848974e56dc56f8e8541df24e19c7bb Mon Sep 17 00:00:00 2001
From: burrows <[email protected]>
Date: Thu, 12 Dec 2013 01:27:51 -0500
Subject: [PATCH] entering a count that is too large for type long will now
 cause normal_cmd(...) to fail instead of using the value
 999999999L; if your ctrla/ctrlx causes the absolute value
 of the on screen integer to overflow in an unsigned long,
 vim will do nothing with your command; if the value
 produced by your ctrla/ctrlx is too large for an unsigned
 long vim will no longer wrap if the on screen value is
 decimal, instead opting to do nothing.

---
 src/charset.c |   35 ++++++++++-------------------------
 src/normal.c  |    7 +++++--
 src/ops.c     |   41 +++++++++++++++++++++++------------------
 3 files changed, 38 insertions(+), 45 deletions(-)

diff --git a/src/charset.c b/src/charset.c
index fd4b500..eff9f9a 100644
--- a/src/charset.c
+++ b/src/charset.c
@@ -1850,32 +1850,17 @@ vim_str2nr(start, hexp, len, dooct, dohex, nptr, unptr)
     /*
      * Do the string-to-numeric conversion "manually" to avoid sscanf quirks.
      */
-    if (hex == '0' || dooct > 1)
     {
-	/* octal */
-	while ('0' <= *ptr && *ptr <= '7')
-	{
-	    un = 8 * un + (unsigned long)(*ptr - '0');
-	    ++ptr;
-	}
-    }
-    else if (hex != 0 || dohex > 1)
-    {
-	/* hex */
-	while (vim_isxdigit(*ptr))
-	{
-	    un = 16 * un + (unsigned long)hex2nr(*ptr);
-	    ++ptr;
-	}
-    }
-    else
-    {
-	/* decimal */
-	while (VIM_ISDIGIT(*ptr))
-	{
-	    un = 10 * un + (unsigned long)(*ptr - '0');
-	    ++ptr;
-	}
+        int base = 10;
+        char *endptr;
+        if (hex == '0' || dooct > 1)
+            base = 8;
+        else if (hex != 0 || dohex > 1)
+            base = 16;
+        /* propagate ERANGE error to the caller */
+        errno = 0;
+        un = strtoul(ptr, &endptr, base);
+        ptr = endptr;
     }
 
     if (hexp != NULL)
diff --git a/src/normal.c b/src/normal.c
index 013fdce..c130272 100644
--- a/src/normal.c
+++ b/src/normal.c
@@ -731,8 +731,11 @@ getcount:
 	    }
 	    else
 		ca.count0 = ca.count0 * 10 + (c - '0');
-	    if (ca.count0 < 0)	    /* got too large! */
-		ca.count0 = 999999999L;
+	    if (ca.count0 < 0) {	/* got too large! */
+        	clearopbeep(oap);
+        	goto normal_end;
+            }
+
 #ifdef FEAT_EVAL
 	    /* Set v:count here, when called from main() and not a stuffed
 	     * command, so that v:count can be used in an expression mapping
diff --git a/src/ops.c b/src/ops.c
index d2060a4..cc152ff 100644
--- a/src/ops.c
+++ b/src/ops.c
@@ -5536,7 +5536,12 @@ do_addsub(command, Prenum1)
 	}
 
 	/* get the number value (unsigned) */
+        errno = 0;
 	vim_str2nr(ptr + col, &hex, &length, dooct, dohex, NULL, &n);
+        if (ERANGE == errno) {
+            beep_flush();
+            return FAIL;
+        }
 
 	/* ignore leading '-' for hex and octal numbers */
 	if (hex && negative)
@@ -5562,24 +5567,24 @@ do_addsub(command, Prenum1)
 	/* handle wraparound for decimal numbers */
 	if (!hex)
 	{
-	    if (subtract)
-	    {
-		if (n > oldn)
-		{
-		    n = 1 + (n ^ (unsigned long)-1);
-		    negative ^= TRUE;
-		}
-	    }
-	    else /* add */
-	    {
-		if (n < oldn)
-		{
-		    n = (n ^ (unsigned long)-1);
-		    negative ^= TRUE;
-		}
-	    }
-	    if (n == 0)
-		negative = FALSE;
+            /* handle underflow; this happens when we go from negative
+             * to positive or vice versa */
+            if (subtract && n > oldn)
+            {
+                n = 1 + (n ^ (unsigned long)-1);
+                negative ^= TRUE;
+            }
+            /* do nothing for overflow; don't present circularity
+             * for decimals */
+            else if (!subtract && n < oldn)
+            {
+                beep_flush();
+                return FAIL;
+            }
+            /* when adding to a negative that results in zero we must
+             * manually strip the negative sign */
+            else if (0 == n)  
+                negative = FALSE;
 	}
 
 	/*
-- 
1.7.9.5

Raspunde prin e-mail lui