diff options
-rw-r--r-- | src/nvim/charset.c | 60 | ||||
-rw-r--r-- | test/symbolic/klee/nvim/charset.c | 60 | ||||
-rw-r--r-- | test/unit/viml/expressions/lexer_spec.lua | 3 | ||||
-rw-r--r-- | test/unit/viml/expressions/parser_spec.lua | 10 |
4 files changed, 53 insertions, 80 deletions
diff --git a/src/nvim/charset.c b/src/nvim/charset.c index f824717fcd..7b307b8160 100644 --- a/src/nvim/charset.c +++ b/src/nvim/charset.c @@ -1620,13 +1620,16 @@ bool vim_isblankline(char_u *lbuf) /// @param maxlen Max length of string to check. void vim_str2nr(const char_u *const start, int *const prep, int *const len, const int what, varnumber_T *const nptr, - uvarnumber_T *const unptr, const int maxlen) + uvarnumber_T *const unptr, int maxlen) FUNC_ATTR_NONNULL_ARG(1) { - const char_u *ptr = start; + const char *ptr = (const char *)start; + if (maxlen == 0) { + maxlen = (int)strlen(ptr); + } + const char *const e = ptr + maxlen; int pre = 0; // default is decimal bool negative = false; - uvarnumber_T un = 0; if (ptr[0] == '-') { negative = true; @@ -1635,19 +1638,19 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len, // Recognize hex, octal and bin. if ((what & (STR2NR_HEX|STR2NR_OCT|STR2NR_BIN)) - && (maxlen == 0 || maxlen > 1) - && (ptr[0] == '0') && (ptr[1] != '8') && (ptr[1] != '9')) { + && maxlen > 1 + && ptr[0] == '0' && ptr[1] != '8' && ptr[1] != '9') { pre = ptr[1]; if ((what & STR2NR_HEX) - && (maxlen == 0 || maxlen > 2) - && ((pre == 'X') || (pre == 'x')) + && maxlen > 2 + && (pre == 'X' || pre == 'x') && ascii_isxdigit(ptr[2])) { // hexadecimal ptr += 2; } else if ((what & STR2NR_BIN) - && (maxlen == 0 || maxlen > 2) - && ((pre == 'B') || (pre == 'b')) + && maxlen > 2 + && (pre == 'B' || pre == 'b') && ascii_isbdigit(ptr[2])) { // binary ptr += 2; @@ -1657,32 +1660,26 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len, if (what & STR2NR_OCT) { // Don't interpret "0", "08" or "0129" as octal. - for (int n = 1; ascii_isdigit(ptr[n]); ++n) { - if (ptr[n] > '7') { + for (int i = 1; i < maxlen && ascii_isdigit(ptr[i]); i++) { + if (ptr[i] > '7') { // can't be octal pre = 0; break; } - if (ptr[n] >= '0') { + if (ptr[i] >= '0') { // assume octal pre = '0'; } - if (n == maxlen) { - break; - } } } } } // Do the string-to-numeric conversion "manually" to avoid sscanf quirks. - int n = 1; + uvarnumber_T un = 0; if (pre == 'B' || pre == 'b' || what == (STR2NR_BIN|STR2NR_FORCE)) { // bin - if (pre != 0) { - n += 2; // skip over "0b" - } - while ('0' <= *ptr && *ptr <= '1') { + while (ptr < e && '0' <= *ptr && *ptr <= '1') { // avoid ubsan error for overflow if (un < UVARNUMBER_MAX / 2) { un = 2 * un + (uvarnumber_T)(*ptr - '0'); @@ -1690,13 +1687,10 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len, un = UVARNUMBER_MAX; } ptr++; - if (n++ == maxlen) { - break; - } } } else if (pre == '0' || what == (STR2NR_OCT|STR2NR_FORCE)) { // octal - while ('0' <= *ptr && *ptr <= '7') { + while (ptr < e && '0' <= *ptr && *ptr <= '7') { // avoid ubsan error for overflow if (un < UVARNUMBER_MAX / 8) { un = 8 * un + (uvarnumber_T)(*ptr - '0'); @@ -1704,16 +1698,10 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len, un = UVARNUMBER_MAX; } ptr++; - if (n++ == maxlen) { - break; - } } } else if (pre == 'X' || pre == 'x' || what == (STR2NR_HEX|STR2NR_FORCE)) { // hex - if (pre != 0) { - n += 2; // skip over "0x" - } - while (ascii_isxdigit(*ptr)) { + while (ptr < e && ascii_isxdigit(*ptr)) { // avoid ubsan error for overflow if (un < UVARNUMBER_MAX / 16) { un = 16 * un + (uvarnumber_T)hex2nr(*ptr); @@ -1721,13 +1709,10 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len, un = UVARNUMBER_MAX; } ptr++; - if (n++ == maxlen) { - break; - } } } else { // decimal - while (ascii_isdigit(*ptr)) { + while (ptr < e && ascii_isdigit(*ptr)) { // avoid ubsan error for overflow if (un < UVARNUMBER_MAX / 10) { un = 10 * un + (uvarnumber_T)(*ptr - '0'); @@ -1735,9 +1720,6 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len, un = UVARNUMBER_MAX; } ptr++; - if (n++ == maxlen) { - break; - } } } @@ -1746,7 +1728,7 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len, } if (len != NULL) { - *len = (int)(ptr - start); + *len = (int)(ptr - (const char *)start); } if (nptr != NULL) { diff --git a/test/symbolic/klee/nvim/charset.c b/test/symbolic/klee/nvim/charset.c index 59fe6a1430..7dcf6868bf 100644 --- a/test/symbolic/klee/nvim/charset.c +++ b/test/symbolic/klee/nvim/charset.c @@ -25,12 +25,15 @@ int hex2nr(int c) void vim_str2nr(const char_u *const start, int *const prep, int *const len, const int what, varnumber_T *const nptr, - uvarnumber_T *const unptr, const int maxlen) + uvarnumber_T *const unptr, int maxlen) { - const char_u *ptr = start; + const char *ptr = (const char *)start; + if (maxlen == 0) { + maxlen = (int)strlen(ptr); + } + const char *const e = ptr + maxlen; int pre = 0; // default is decimal bool negative = false; - uvarnumber_T un = 0; if (ptr[0] == '-') { negative = true; @@ -39,19 +42,19 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len, // Recognize hex, octal and bin. if ((what & (STR2NR_HEX|STR2NR_OCT|STR2NR_BIN)) - && (maxlen == 0 || maxlen > 1) - && (ptr[0] == '0') && (ptr[1] != '8') && (ptr[1] != '9')) { + && maxlen > 1 + && ptr[0] == '0' && ptr[1] != '8' && ptr[1] != '9') { pre = ptr[1]; if ((what & STR2NR_HEX) - && (maxlen == 0 || maxlen > 2) - && ((pre == 'X') || (pre == 'x')) + && maxlen > 2 + && (pre == 'X' || pre == 'x') && ascii_isxdigit(ptr[2])) { // hexadecimal ptr += 2; } else if ((what & STR2NR_BIN) - && (maxlen == 0 || maxlen > 2) - && ((pre == 'B') || (pre == 'b')) + && maxlen > 2 + && (pre == 'B' || pre == 'b') && ascii_isbdigit(ptr[2])) { // binary ptr += 2; @@ -61,32 +64,26 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len, if (what & STR2NR_OCT) { // Don't interpret "0", "08" or "0129" as octal. - for (int n = 1; ascii_isdigit(ptr[n]); ++n) { - if (ptr[n] > '7') { + for (int i = 1; i < maxlen && ascii_isdigit(ptr[i]); i++) { + if (ptr[i] > '7') { // can't be octal pre = 0; break; } - if (ptr[n] >= '0') { + if (ptr[i] >= '0') { // assume octal pre = '0'; } - if (n == maxlen) { - break; - } } } } } // Do the string-to-numeric conversion "manually" to avoid sscanf quirks. - int n = 1; + uvarnumber_T un = 0; if (pre == 'B' || pre == 'b' || what == (STR2NR_BIN|STR2NR_FORCE)) { // bin - if (pre != 0) { - n += 2; // skip over "0b" - } - while ('0' <= *ptr && *ptr <= '1') { + while (ptr < e && '0' <= *ptr && *ptr <= '1') { // avoid ubsan error for overflow if (un < UVARNUMBER_MAX / 2) { un = 2 * un + (uvarnumber_T)(*ptr - '0'); @@ -94,13 +91,10 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len, un = UVARNUMBER_MAX; } ptr++; - if (n++ == maxlen) { - break; - } } } else if (pre == '0' || what == (STR2NR_OCT|STR2NR_FORCE)) { // octal - while ('0' <= *ptr && *ptr <= '7') { + while (ptr < e && '0' <= *ptr && *ptr <= '7') { // avoid ubsan error for overflow if (un < UVARNUMBER_MAX / 8) { un = 8 * un + (uvarnumber_T)(*ptr - '0'); @@ -108,16 +102,10 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len, un = UVARNUMBER_MAX; } ptr++; - if (n++ == maxlen) { - break; - } } } else if (pre == 'X' || pre == 'x' || what == (STR2NR_HEX|STR2NR_FORCE)) { // hex - if (pre != 0) { - n += 2; // skip over "0x" - } - while (ascii_isxdigit(*ptr)) { + while (ptr < e && ascii_isxdigit(*ptr)) { // avoid ubsan error for overflow if (un < UVARNUMBER_MAX / 16) { un = 16 * un + (uvarnumber_T)hex2nr(*ptr); @@ -125,13 +113,10 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len, un = UVARNUMBER_MAX; } ptr++; - if (n++ == maxlen) { - break; - } } } else { // decimal - while (ascii_isdigit(*ptr)) { + while (ptr < e && ascii_isdigit(*ptr)) { // avoid ubsan error for overflow if (un < UVARNUMBER_MAX / 10) { un = 10 * un + (uvarnumber_T)(*ptr - '0'); @@ -139,9 +124,6 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len, un = UVARNUMBER_MAX; } ptr++; - if (n++ == maxlen) { - break; - } } } @@ -150,7 +132,7 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len, } if (len != NULL) { - *len = (int)(ptr - start); + *len = (int)(ptr - (const char *)start); } if (nptr != NULL) { diff --git a/test/unit/viml/expressions/lexer_spec.lua b/test/unit/viml/expressions/lexer_spec.lua index 674b1b37db..5910468017 100644 --- a/test/unit/viml/expressions/lexer_spec.lua +++ b/test/unit/viml/expressions/lexer_spec.lua @@ -292,6 +292,9 @@ describe('Expressions lexer', function() simple_test({'0b102'}, 'Number', 4, {data={is_float=false, base=2, val=2}, str='0b10'}) simple_test({'10F'}, 'Number', 2, {data={is_float=false, base=10, val=10}, str='10'}) simple_test({'0x0123456789ABCDEFG'}, 'Number', 18, {data={is_float=false, base=16, val=81985529216486895}, str='0x0123456789ABCDEF'}) + simple_test({{data='00', size=2}}, 'Number', 2, {data={is_float=false, base=8, val=0}, str='00'}) + simple_test({{data='009', size=2}}, 'Number', 2, {data={is_float=false, base=8, val=0}, str='00'}) + simple_test({{data='01', size=1}}, 'Number', 1, {data={is_float=false, base=10, val=0}, str='0'}) end local function regular_scope_tests() diff --git a/test/unit/viml/expressions/parser_spec.lua b/test/unit/viml/expressions/parser_spec.lua index 22263af8e2..36af875bd2 100644 --- a/test/unit/viml/expressions/parser_spec.lua +++ b/test/unit/viml/expressions/parser_spec.lua @@ -6867,13 +6867,19 @@ describe('Expressions parser', function() }, }, { }) - check_parsing('0', 0, { - -- 0 + check_parsing({data='01', size=1}, 0, { ast = { 'Integer(val=0):0:0:0', }, }, { hl('Number', '0'), }) + check_parsing({data='001', size=2}, 0, { + ast = { + 'Integer(val=0):0:0:00', + }, + }, { + hl('Number', '00'), + }) end) end) |