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
