From 953f26bace041f481e79b67b64401aa07259055c Mon Sep 17 00:00:00 2001 From: James McCoy Date: Wed, 16 Nov 2016 09:24:10 -0500 Subject: [PATCH 01/20] vim-patch:7.4.1975 Problem: On MS-Windows large files (> 2Gbyte) cause problems. Solution: Use "off_T" instead of "off_t". Use "stat_T" instead of "struct stat". Use 64 bit system functions if available. (Ken Takata) https://github.com/vim/vim/commit/8767f52fbfd4f053ce00a978227c95f1d7d323fe Only the off_T changes are relevant, since all the "struct stat" usage is abstracted by libuv. --- src/nvim/fileio.c | 8 ++-- src/nvim/globals.h | 28 +++++++++++++ src/nvim/memfile.c | 20 ++++----- src/nvim/memline.c | 4 +- src/nvim/tag.c | 57 ++++++++----------------- src/nvim/testdir/Makefile | 1 + src/nvim/testdir/test_largefile.vim | 30 ++++++++++++++ src/nvim/testdir/test_stat.vim | 64 +++++++++++++++++++++++++++++ src/nvim/version.c | 2 +- 9 files changed, 158 insertions(+), 56 deletions(-) create mode 100644 src/nvim/testdir/test_largefile.vim create mode 100644 src/nvim/testdir/test_stat.vim diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 4063277403..42cc42b844 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -281,7 +281,7 @@ readfile ( colnr_T len; long size = 0; char_u *p = NULL; - off_t filesize = 0; + off_T filesize = 0; int skip_read = FALSE; context_sha256_T sha_ctx; int read_undo_file = FALSE; @@ -777,7 +777,7 @@ retry: if (read_buffer) { read_buf_lnum = 1; read_buf_col = 0; - } else if (read_stdin || lseek(fd, (off_t)0L, SEEK_SET) != 0) { + } else if (read_stdin || vim_lseek(fd, (off_T)0L, SEEK_SET) != 0) { /* Can't rewind the file, give up. */ error = TRUE; goto failed; @@ -1626,7 +1626,7 @@ rewind_retry: if ( try_unix && !read_stdin && (read_buffer - || lseek(fd, (off_t)0L, SEEK_SET) == 0)) { + || vim_lseek(fd, (off_T)0L, SEEK_SET) == 0)) { fileformat = EOL_UNIX; if (set_options) set_fileformat(EOL_UNIX, OPT_LOCAL); @@ -3833,7 +3833,7 @@ static bool msg_add_fileformat(int eol_type) /* * Append line and character count to IObuff. */ -void msg_add_lines(int insert_space, long lnum, off_t nchars) +void msg_add_lines(int insert_space, long lnum, off_T nchars) { char_u *p; diff --git a/src/nvim/globals.h b/src/nvim/globals.h index a3657f2122..957ab6c9ce 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -97,6 +97,34 @@ typedef enum { EXTERN long Rows INIT(= DFLT_ROWS); // nr of rows in the screen EXTERN long Columns INIT(= DFLT_COLS); // nr of columns in the screen +// We use 64-bit file functions here, if available. E.g. ftello() returns +// off_t instead of long, which helps if long is 32 bit and off_t is 64 bit. +// We assume that when fseeko() is available then ftello() is too. +// Note that Windows has different function names. +#if (defined(_MSC_VER) && (_MSC_VER >= 1300)) || defined(__MINGW32__) +typedef __int64 off_T; +# ifdef __MINGW32__ +# define vim_lseek lseek64 +# define vim_fseek fseeko64 +# define vim_ftell ftello64 +# else +# define vim_lseek _lseeki64 +# define vim_fseek _fseeki64 +# define vim_ftell _ftelli64 +# endif +#else +typedef off_t off_T; +# ifdef HAVE_FSEEKO +# define vim_lseek lseek +# define vim_ftell ftello +# define vim_fseek fseeko +# else +# define vim_lseek lseek +# define vim_ftell ftell +# define vim_fseek(a, b, c) fseek(a, (long)b, c) +# endif +#endif + /* * The characters and attributes cached for the screen. */ diff --git a/src/nvim/memfile.c b/src/nvim/memfile.c index 1abc69727c..9429703620 100644 --- a/src/nvim/memfile.c +++ b/src/nvim/memfile.c @@ -115,18 +115,18 @@ memfile_T *mf_open(char_u *fname, int flags) } } - off_t size; + off_T size; // When recovering, the actual block size will be retrieved from block 0 // in ml_recover(). The size used here may be wrong, therefore mf_blocknr_max // must be rounded up. if (mfp->mf_fd < 0 || (flags & (O_TRUNC|O_EXCL)) - || (size = lseek(mfp->mf_fd, (off_t)0L, SEEK_END)) <= 0) { + || (size = vim_lseek(mfp->mf_fd, 0L, SEEK_END)) <= 0) { // no file or empty file mfp->mf_blocknr_max = 0; } else { - assert(sizeof(off_t) <= sizeof(blocknr_T) + assert(sizeof(off_T) <= sizeof(blocknr_T) && mfp->mf_page_size > 0 && mfp->mf_page_size - 1 <= INT64_MAX - size); mfp->mf_blocknr_max = (((blocknr_T)size + mfp->mf_page_size - 1) @@ -689,9 +689,9 @@ static int mf_read(memfile_T *mfp, bhdr_T *hp) return FAIL; unsigned page_size = mfp->mf_page_size; - // TODO(elmart): Check (page_size * hp->bh_bnum) within off_t bounds. - off_t offset = (off_t)(page_size * hp->bh_bnum); - if (lseek(mfp->mf_fd, offset, SEEK_SET) != offset) { + // TODO(elmart): Check (page_size * hp->bh_bnum) within off_T bounds. + off_T offset = (off_T)(page_size * hp->bh_bnum); + if (vim_lseek(mfp->mf_fd, offset, SEEK_SET) != offset) { PERROR(_("E294: Seek error in swap file read")); return FAIL; } @@ -716,7 +716,7 @@ static int mf_read(memfile_T *mfp, bhdr_T *hp) /// - Write error in swap file. static int mf_write(memfile_T *mfp, bhdr_T *hp) { - off_t offset; // offset in the file + off_T offset; // offset in the file blocknr_T nr; // block nr which is being written bhdr_T *hp2; unsigned page_size; // number of bytes in a page @@ -745,9 +745,9 @@ static int mf_write(memfile_T *mfp, bhdr_T *hp) hp2 = hp; } - // TODO(elmart): Check (page_size * nr) within off_t bounds. - offset = (off_t)(page_size * nr); - if (lseek(mfp->mf_fd, offset, SEEK_SET) != offset) { + // TODO(elmart): Check (page_size * nr) within off_T bounds. + offset = (off_T)(page_size * nr); + if (vim_lseek(mfp->mf_fd, offset, SEEK_SET) != offset) { PERROR(_("E296: Seek error in swap file write")); return FAIL; } diff --git a/src/nvim/memline.c b/src/nvim/memline.c index 40a6761225..b9ab576460 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -763,7 +763,7 @@ void ml_recover(void) int idx; int top; int txt_start; - off_t size; + off_T size; int called_from_main; int serious_error = TRUE; long mtime; @@ -914,7 +914,7 @@ void ml_recover(void) msg_end(); goto theend; } - if ((size = lseek(mfp->mf_fd, (off_t)0L, SEEK_END)) <= 0) + if ((size = vim_lseek(mfp->mf_fd, (off_T)0L, SEEK_END)) <= 0) mfp->mf_blocknr_max = 0; /* no file or empty file */ else mfp->mf_blocknr_max = size / mfp->mf_page_size; diff --git a/src/nvim/tag.c b/src/nvim/tag.c index 88b45add54..f12d86fc23 100644 --- a/src/nvim/tag.c +++ b/src/nvim/tag.c @@ -105,15 +105,6 @@ static char_u *topmsg = (char_u *)N_("E556: at top of tag stack"); static char_u *tagmatchname = NULL; /* name of last used tag */ -/* - * We use ftello() here, if available. It returns off_t instead of long, - * which helps if long is 32 bit and off_t is 64 bit. - * We assume that when fseeko() is available then ftello() is too. - */ -#ifdef HAVE_FSEEKO -# define ftell ftello -#endif - /* * Tag for preview window is remembered separately, to avoid messing up the * normal tagstack. @@ -1091,19 +1082,19 @@ find_tags ( int tag_file_sorted = NUL; /* !_TAG_FILE_SORTED value */ struct tag_search_info /* Binary search file offsets */ { - off_t low_offset; /* offset for first char of first line that + off_T low_offset; /* offset for first char of first line that could match */ - off_t high_offset; /* offset of char after last line that could + off_T high_offset; /* offset of char after last line that could match */ - off_t curr_offset; /* Current file offset in search range */ - off_t curr_offset_used; /* curr_offset used when skipping back */ - off_t match_offset; /* Where the binary search found a tag */ + off_T curr_offset; /* Current file offset in search range */ + off_T curr_offset_used; /* curr_offset used when skipping back */ + off_T match_offset; /* Where the binary search found a tag */ int low_char; /* first char at low_offset */ int high_char; /* first char at high_offset */ } search_info; - off_t filesize; + off_T filesize; int tagcmp; - off_t offset; + off_T offset; int round; enum { TS_START, /* at start of file */ @@ -1378,36 +1369,28 @@ find_tags ( if (state == TS_BINARY || state == TS_SKIP_BACK) { /* Adjust the search file offset to the correct position */ search_info.curr_offset_used = search_info.curr_offset; -#ifdef HAVE_FSEEKO - fseeko(fp, search_info.curr_offset, SEEK_SET); -#else - fseek(fp, (long)search_info.curr_offset, SEEK_SET); -#endif + vim_fseek(fp, search_info.curr_offset, SEEK_SET); eof = vim_fgets(lbuf, LSIZE, fp); if (!eof && search_info.curr_offset != 0) { /* The explicit cast is to work around a bug in gcc 3.4.2 * (repeated below). */ - search_info.curr_offset = ftell(fp); + search_info.curr_offset = vim_ftell(fp); if (search_info.curr_offset == search_info.high_offset) { /* oops, gone a bit too far; try from low offset */ -#ifdef HAVE_FSEEKO - fseeko(fp, search_info.low_offset, SEEK_SET); -#else - fseek(fp, (long)search_info.low_offset, SEEK_SET); -#endif + vim_fseek(fp, search_info.low_offset, SEEK_SET); search_info.curr_offset = search_info.low_offset; } eof = vim_fgets(lbuf, LSIZE, fp); } /* skip empty and blank lines */ while (!eof && vim_isblankline(lbuf)) { - search_info.curr_offset = ftell(fp); + search_info.curr_offset = vim_ftell(fp); eof = vim_fgets(lbuf, LSIZE, fp); } if (eof) { /* Hit end of file. Skip backwards. */ state = TS_SKIP_BACK; - search_info.match_offset = ftell(fp); + search_info.match_offset = vim_ftell(fp); search_info.curr_offset = search_info.curr_offset_used; continue; } @@ -1523,10 +1506,10 @@ line_read_in: */ if (state == TS_BINARY) { // Get the tag file size. - if ((filesize = lseek(fileno(fp), (off_t)0L, SEEK_END)) <= 0) { + if ((filesize = vim_lseek(fileno(fp), (off_T)0L, SEEK_END)) <= 0) { state = TS_LINEAR; } else { - lseek(fileno(fp), (off_t)0L, SEEK_SET); + vim_lseek(fileno(fp), (off_T)0L, SEEK_SET); /* Calculate the first read offset in the file. Start * the search in the middle of the file. */ @@ -1564,11 +1547,7 @@ parse_line: /* Avoid getting stuck. */ linear = TRUE; state = TS_LINEAR; -# ifdef HAVE_FSEEKO - fseeko(fp, search_info.low_offset, SEEK_SET); -# else - fseek(fp, (long)search_info.low_offset, SEEK_SET); -# endif + vim_fseek(fp, search_info.low_offset, SEEK_SET); } continue; } @@ -1647,7 +1626,7 @@ parse_line: continue; } if (tagcmp < 0) { - search_info.curr_offset = ftell(fp); + search_info.curr_offset = vim_ftell(fp); if (search_info.curr_offset < search_info.high_offset) { search_info.low_offset = search_info.curr_offset; if (sortic) @@ -1683,7 +1662,7 @@ parse_line: } else if (state == TS_STEP_FORWARD) { assert(cmplen >= 0); if (mb_strnicmp(tagp.tagname, orgpat.head, (size_t)cmplen) != 0) { - if ((off_t)ftell(fp) > search_info.match_offset) + if ((off_T)vim_ftell(fp) > search_info.match_offset) break; /* past last match */ else continue; /* before first match */ @@ -1908,7 +1887,7 @@ parse_line: if (line_error) { EMSG2(_("E431: Format error in tags file \"%s\""), tag_fname); if (!use_cscope) - EMSGN(_("Before byte %" PRId64), ftell(fp)); + EMSGN(_("Before byte %" PRId64), vim_ftell(fp)); stop_searching = TRUE; line_error = FALSE; } diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile index 70a9f2b8c4..77118c34bb 100644 --- a/src/nvim/testdir/Makefile +++ b/src/nvim/testdir/Makefile @@ -60,6 +60,7 @@ NEW_TESTS ?= \ test_quickfix.res \ test_signs.res \ test_smartindent.res \ + test_stat.res \ test_substitute.res \ test_syntax.res \ test_tabpage.res \ diff --git a/src/nvim/testdir/test_largefile.vim b/src/nvim/testdir/test_largefile.vim new file mode 100644 index 0000000000..ea2b8ff62d --- /dev/null +++ b/src/nvim/testdir/test_largefile.vim @@ -0,0 +1,30 @@ +" Tests for large files +" This is only executed manually: "make test_largefile". +" This is not run as part of "make test". + +func Test_largefile() + let fname = 'Xlarge.txt' + + call delete(fname) + exe "e" fname + " Make sure that a line break is 1 byte (LF). + set ff=unix + set undolevels=-1 + " Input 99 'A's. The line becomes 100 bytes including a line break. + exe "normal 99iA\" + yank + " Put 39,999,999 times. The file becomes 4,000,000,000 bytes. + normal 39999999p + " Moving around in the file randomly. + normal G + normal 10% + normal 90% + normal 50% + normal gg + w + " Check if the file size is larger than 2^31 - 1 bytes. + " Note that getfsize() returns -2 if a Number is 32 bits. + let fsize=getfsize(fname) + call assert_true(fsize > 2147483647 || fsize == -2) + "call delete(fname) +endfunc diff --git a/src/nvim/testdir/test_stat.vim b/src/nvim/testdir/test_stat.vim new file mode 100644 index 0000000000..89ca9ef379 --- /dev/null +++ b/src/nvim/testdir/test_stat.vim @@ -0,0 +1,64 @@ +" Tests for stat functions and checktime + +func Test_existent_file() + let fname='Xtest.tmp' + + let ts=localtime() + sleep 1 + let fl=['Hello World!'] + call writefile(fl, fname) + let tf=getftime(fname) + sleep 1 + let te=localtime() + + call assert_true(ts <= tf && tf <= te) + call assert_equal(strlen(fl[0] . "\n"), getfsize(fname)) + call assert_equal('file', getftype(fname)) + call assert_equal('rw-', getfperm(fname)[0:2]) +endfunc + +func Test_existent_directory() + let dname='.' + + call assert_equal(0, getfsize(dname)) + call assert_equal('dir', getftype(dname)) + call assert_equal('rwx', getfperm(dname)[0:2]) +endfunc + +func Test_checktime() + let fname='Xtest.tmp' + + let fl=['Hello World!'] + call writefile(fl, fname) + set autoread + exec 'e' fname + sleep 2 + let fl=readfile(fname) + let fl[0] .= ' - checktime' + call writefile(fl, fname) + checktime + call assert_equal(fl[0], getline(1)) +endfunc + +func Test_nonexistent_file() + let fname='Xtest.tmp' + + call delete(fname) + call assert_equal(-1, getftime(fname)) + call assert_equal(-1, getfsize(fname)) + call assert_equal('', getftype(fname)) + call assert_equal('', getfperm(fname)) +endfunc + +func Test_win32_symlink_dir() + " On Windows, non-admin users cannot create symlinks. + " So we use an existing symlink for this test. + if has('win32') + " Check if 'C:\Users\All Users' is a symlink to a directory. + let res=system('dir C:\Users /a') + if match(res, '\C *All Users') >= 0 + " Get the filetype of the symlink. + call assert_equal('dir', getftype('C:\Users\All Users')) + endif + endif +endfunc diff --git a/src/nvim/version.c b/src/nvim/version.c index b579cdef12..f48cd9f2a7 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -469,7 +469,7 @@ static const int included_patches[] = { // 1978, // 1977, // 1976, - // 1975, + 1975, // 1974 NA 1973, // 1972 NA From 81be7358be00d3d75453659bcdc7efc69207ca8e Mon Sep 17 00:00:00 2001 From: James McCoy Date: Wed, 16 Nov 2016 11:09:04 -0500 Subject: [PATCH 02/20] vim-patch:7.4.1976 Problem: Number variables are not 64 bits while they could be. Solution: Add the num64 feature. (Ken Takata) https://github.com/vim/vim/commit/22fcfad29276bd5f317faf516637dcd491b96a12 --- runtime/doc/eval.txt | 23 ++++++++++--- runtime/doc/various.txt | 1 + src/nvim/buffer.h | 6 ++-- src/nvim/charset.c | 16 ++++----- src/nvim/eval.c | 59 +++++++++++++++++----------------- src/nvim/eval/decode.c | 6 ++-- src/nvim/eval/typval.h | 13 ++++---- src/nvim/ex_cmds.c | 8 ++--- src/nvim/ex_getln.c | 2 +- src/nvim/fileio.c | 2 +- src/nvim/fold.c | 2 +- src/nvim/globals.h | 2 +- src/nvim/indent.c | 4 +-- src/nvim/keymap.c | 2 +- src/nvim/ops.c | 46 +++++++++++++------------- src/nvim/option.c | 4 +-- src/nvim/quickfix.c | 6 ++-- src/nvim/testdir/test_viml.vim | 26 +++++++++++++++ src/nvim/version.c | 2 +- 19 files changed, 137 insertions(+), 93 deletions(-) diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 11b42dd2e5..47f8414285 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -22,6 +22,8 @@ done, the features in this document are not available. See |+eval| and There are six types of variables: Number A 32 or 64 bit signed number. |expr-number| *Number* + 64-bit Number is available only when compiled with the + |+num64| feature. Examples: -123 0x10 0177 0b1011 Float A floating point number. |floating-point-format| *Float* @@ -887,6 +889,11 @@ When dividing a Number by zero the result depends on the value: <0 / 0 = -0x7fffffff (like negative infinity) (before Vim 7.2 it was always 0x7fffffff) +When 64-bit Number support is enabled: + 0 / 0 = -0x8000000000000000 (like NaN for Float) + >0 / 0 = 0x7fffffffffffffff (like positive infinity) + <0 / 0 = -0x7fffffffffffffff (like negative infinity) + When the righthand side of '%' is zero, the result is 0. None of these work for |Funcref|s. @@ -3536,17 +3543,19 @@ float2nr({expr}) *float2nr()* decimal point. {expr} must evaluate to a |Float| or a Number. When the value of {expr} is out of range for a |Number| the - result is truncated to 0x7fffffff or -0x7fffffff. NaN results - in -0x80000000. + result is truncated to 0x7fffffff or -0x7fffffff (or when + 64-bit Number support is enabled, 0x7fffffffffffffff or + -0x7fffffffffffffff. NaN results in -0x80000000 (or when + 64-bit Number support is enabled, -0x8000000000000000). Examples: > echo float2nr(3.95) < 3 > echo float2nr(-23.45) < -23 > echo float2nr(1.0e100) -< 2147483647 > +< 2147483647 (or 9223372036854775807) > echo float2nr(-1.0e150) -< -2147483647 > +< -2147483647 (or -9223372036854775807) > echo float2nr(1.0e-100) < 0 @@ -7983,7 +7992,10 @@ winwidth({nr}) *winwidth()* :if winwidth(0) <= 50 : exe "normal 50\|" :endif -< +< For getting the terminal or screen size, see the 'columns' + option. + + wordcount() *wordcount()* The result is a dictionary of byte/chars/word statistics for the current buffer. This is the same info as provided by @@ -8137,6 +8149,7 @@ mouseshape Compiled with support for 'mouseshape'. multi_byte Compiled with support for 'encoding' multi_byte_encoding 'encoding' is set to a multi-byte encoding. multi_lang Compiled with support for multiple languages. +num64 Compiled with 64-bit |Number| support. nvim This is Nvim. |has-patch| path_extra Compiled with up/downwards search in 'path' and 'tags' persistent_undo Compiled with support for persistent undo history. diff --git a/runtime/doc/various.txt b/runtime/doc/various.txt index 2679c2dabb..8880b625e9 100644 --- a/runtime/doc/various.txt +++ b/runtime/doc/various.txt @@ -352,6 +352,7 @@ N *+mouseshape* |'mouseshape'| N *+multi_byte* 16 and 32 bit characters |multibyte| *+multi_byte_ime* Win32 input method for multibyte chars |multibyte-ime| N *+multi_lang* non-English language support |multi-lang| + *+num64* 64-bit Number support |Number| N *+path_extra* Up/downwards search in 'path' and 'tags' N *+persistent_undo* Persistent undo |undo-persistence| *+postscript* |:hardcopy| writes a PostScript file diff --git a/src/nvim/buffer.h b/src/nvim/buffer.h index 39b9faf8b1..609567fbcd 100644 --- a/src/nvim/buffer.h +++ b/src/nvim/buffer.h @@ -83,14 +83,16 @@ static inline void restore_win_for_buf(win_T *save_curwin, } } -static inline void buf_set_changedtick(buf_T *const buf, const int changedtick) +static inline void buf_set_changedtick(buf_T *const buf, + const varnumber_T changedtick) REAL_FATTR_NONNULL_ALL REAL_FATTR_ALWAYS_INLINE; /// Set b_changedtick and corresponding variable /// /// @param[out] buf Buffer to set changedtick in. /// @param[in] changedtick New value. -static inline void buf_set_changedtick(buf_T *const buf, const int changedtick) +static inline void buf_set_changedtick(buf_T *const buf, + const varnumber_T changedtick) { #ifndef NDEBUG dictitem_T *const changedtick_di = tv_dict_find( diff --git a/src/nvim/charset.c b/src/nvim/charset.c index 5a0590d075..bf4dc25efd 100644 --- a/src/nvim/charset.c +++ b/src/nvim/charset.c @@ -1621,13 +1621,13 @@ bool vim_isblankline(char_u *lbuf) /// @param unptr Returns the unsigned result. /// @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, long *const nptr, unsigned long *const unptr, - const int maxlen) + const int what, varnumber_T *const nptr, + uvarnumber_T *const unptr, const int maxlen) { const char_u *ptr = start; int pre = 0; // default is decimal bool negative = false; - unsigned long un = 0; + uvarnumber_T un = 0; if (ptr[0] == '-') { negative = true; @@ -1683,7 +1683,7 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len, n += 2; // skip over "0b" } while ('0' <= *ptr && *ptr <= '1') { - un = 2 * un + (unsigned long)(*ptr - '0'); + un = 2 * un + (uvarnumber_T)(*ptr - '0'); ptr++; if (n++ == maxlen) { break; @@ -1692,7 +1692,7 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len, } else if ((pre == '0') || what == STR2NR_OCT + STR2NR_FORCE) { // octal while ('0' <= *ptr && *ptr <= '7') { - un = 8 * un + (unsigned long)(*ptr - '0'); + un = 8 * un + (uvarnumber_T)(*ptr - '0'); ptr++; if (n++ == maxlen) { break; @@ -1705,7 +1705,7 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len, n += 2; // skip over "0x" } while (ascii_isxdigit(*ptr)) { - un = 16 * un + (unsigned long)hex2nr(*ptr); + un = 16 * un + (uvarnumber_T)hex2nr(*ptr); ptr++; if (n++ == maxlen) { break; @@ -1733,9 +1733,9 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len, if (nptr != NULL) { if (negative) { // account for leading '-' for decimal numbers - *nptr = -(long)un; + *nptr = -(varnumber_T)un; } else { - *nptr = (long)un; + *nptr = (varnumber_T)un; } } diff --git a/src/nvim/eval.c b/src/nvim/eval.c index c9da08acd0..19e23190b1 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -446,7 +446,7 @@ typedef struct { bool rpc; int refcount; Callback on_stdout, on_stderr, on_exit; - int *status_ptr; + varnumber_T *status_ptr; uint64_t id; MultiQueue *events; } TerminalJobData; @@ -970,7 +970,7 @@ eval_to_bool ( emsg_skip--; } - return retval; + return (int)retval; } /// Top level evaluation function, returning a string @@ -1081,10 +1081,10 @@ char_u *eval_to_string_safe(char_u *arg, char_u **nextcmd, int use_sandbox) * Evaluates "expr" silently. * Returns -1 for an error. */ -int eval_to_number(char_u *expr) +varnumber_T eval_to_number(char_u *expr) { typval_T rettv; - int retval; + varnumber_T retval; char_u *p = skipwhite(expr); ++emsg_off; @@ -1203,7 +1203,7 @@ int call_vim_function( typval_T *rettv ) { - long n; + varnumber_T n; int len; int doesrange; void *save_funccalp = NULL; @@ -1261,7 +1261,7 @@ int call_vim_function( * Returns -1 when calling the function fails. * Uses argv[argc] for the function arguments. */ -long +varnumber_T call_func_retnr ( char_u *func, int argc, @@ -1270,7 +1270,7 @@ call_func_retnr ( ) { typval_T rettv; - long retval; + varnumber_T retval; /* All arguments are passed as strings, no conversion to number. */ if (call_vim_function(func, argc, argv, safe, TRUE, &rettv) == FAIL) @@ -1399,7 +1399,7 @@ void prof_child_exit(proftime_T *tm /* where waittime was stored */ int eval_foldexpr(char_u *arg, int *cp) { typval_T tv; - int retval; + varnumber_T retval; char_u *s; int use_sandbox = was_set_insecurely((char_u *)"foldexpr", OPT_LOCAL); @@ -1432,7 +1432,7 @@ int eval_foldexpr(char_u *arg, int *cp) --sandbox; --textlock; - return retval; + return (int)retval; } /* @@ -2286,7 +2286,7 @@ static char_u *get_lval(char_u *const name, typval_T *const rettv, if (empty1) { lp->ll_n1 = 0; } else { - lp->ll_n1 = tv_get_number(&var1); // Is number or string. + lp->ll_n1 = (long)tv_get_number(&var1); // Is number or string. tv_clear(&var1); } lp->ll_dict = NULL; @@ -2315,7 +2315,7 @@ static char_u *get_lval(char_u *const name, typval_T *const rettv, * Otherwise "lp->ll_n2" is set to the second index. */ if (lp->ll_range && !lp->ll_empty2) { - lp->ll_n2 = tv_get_number(&var2); // Is number or string. + lp->ll_n2 = (long)tv_get_number(&var2); // Is number or string. tv_clear(&var2); if (lp->ll_n2 < 0) { ni = tv_list_find(lp->ll_list, lp->ll_n2); @@ -3525,7 +3525,7 @@ static int eval4(char_u **arg, typval_T *rettv, int evaluate) exptype_T type = TYPE_UNKNOWN; int type_is = FALSE; /* TRUE for "is" and "isnot" */ int len = 2; - long n1, n2; + varnumber_T n1, n2; int ic; /* @@ -3787,7 +3787,7 @@ static int eval5(char_u **arg, typval_T *rettv, int evaluate) typval_T var2; typval_T var3; int op; - long n1, n2; + varnumber_T n1, n2; float_T f1 = 0, f2 = 0; char_u *p; @@ -3938,7 +3938,7 @@ eval6 ( { typval_T var2; int op; - long n1, n2; + varnumber_T n1, n2; int use_float = FALSE; float_T f1 = 0, f2; bool error = false; @@ -4032,11 +4032,11 @@ eval6 ( else if (op == '/') { if (n2 == 0) { /* give an error message? */ if (n1 == 0) - n1 = -0x7fffffffL - 1L; /* similar to NaN */ + n1 = -0x7fffffffffffffff - 1; /* similar to NaN */ else if (n1 < 0) - n1 = -0x7fffffffL; + n1 = -0x7fffffffffffffff; else - n1 = 0x7fffffffL; + n1 = 0x7fffffffffffffff; } else n1 = n1 / n2; } else { @@ -4087,7 +4087,7 @@ static int eval7( int want_string // after "." operator ) { - long n; + varnumber_T n; int len; char_u *s; char_u *start_leader, *end_leader; @@ -4285,7 +4285,7 @@ static int eval7( // Apply logical NOT and unary '-', from right to left, ignore '+'. if (ret == OK && evaluate && end_leader > start_leader) { bool error = false; - int val = 0; + varnumber_T val = 0; float_T f = 0.0; if (rettv->v_type == VAR_FLOAT) { @@ -7614,9 +7614,9 @@ static void f_cursor(typval_T *argvars, typval_T *rettv, FunPtr fptr) } } else { line = tv_get_lnum(argvars); - col = tv_get_number_chk(&argvars[1], NULL); + col = (long)tv_get_number_chk(&argvars[1], NULL); if (argvars[2].v_type != VAR_UNKNOWN) { - coladd = tv_get_number_chk(&argvars[2], NULL); + coladd = (long)tv_get_number_chk(&argvars[2], NULL); } } if (line < 0 || col < 0 @@ -8170,7 +8170,7 @@ static void f_extend(typval_T *argvars, typval_T *rettv, FunPtr fptr) } else if (!tv_check_lock(l1->lv_lock, arg_errmsg, TV_TRANSLATE)) { listitem_T *item; if (argvars[2].v_type != VAR_UNKNOWN) { - before = tv_get_number_chk(&argvars[2], &error); + before = (long)tv_get_number_chk(&argvars[2], &error); if (error) { return; // Type error; errmsg already given. } @@ -10516,6 +10516,7 @@ static void f_has(typval_T *argvars, typval_T *rettv, FunPtr fptr) "mouse", "multi_byte", "multi_lang", + "num64", "packages", "path_extra", "persistent_undo", @@ -12945,7 +12946,7 @@ static void f_range(typval_T *argvars, typval_T *rettv, FunPtr fptr) varnumber_T start; varnumber_T end; varnumber_T stride = 1; - long i; + varnumber_T i; bool error = false; start = tv_get_number_chk(&argvars[0], &error); @@ -13163,7 +13164,7 @@ static int list2proftime(typval_T *arg, proftime_T *tm) FUNC_ATTR_NONNULL_ALL // in f_reltime() we split up the 64-bit proftime_T into two 32-bit // values, now we combine them again. union { - struct { varnumber_T low, high; } split; + struct { int32_t low, high; } split; proftime_T prof; } u = { .split.high = n1, .split.low = n2 }; @@ -13204,7 +13205,7 @@ static void f_reltime(typval_T *argvars, typval_T *rettv, FunPtr fptr) // (varnumber_T is defined as int). For all our supported platforms, int's // are at least 32-bits wide. So we'll use two 32-bit values to store it. union { - struct { varnumber_T low, high; } split; + struct { int32_t low, high; } split; proftime_T prof; } u = { .prof = res }; @@ -15152,8 +15153,8 @@ static int item_compare(const void *s1, const void *s2, bool keep_zero) int res; if (sortinfo->item_compare_numbers) { - const long v1 = tv_get_number(tv1); - const long v2 = tv_get_number(tv2); + const varnumber_T v1 = tv_get_number(tv1); + const varnumber_T v2 = tv_get_number(tv2); res = v1 == v2 ? 0 : v1 > v2 ? 1 : -1; goto item_compare_end; @@ -15697,7 +15698,7 @@ static void f_str2float(typval_T *argvars, typval_T *rettv, FunPtr fptr) static void f_str2nr(typval_T *argvars, typval_T *rettv, FunPtr fptr) { int base = 10; - long n; + varnumber_T n; int what; if (argvars[1].v_type != VAR_UNKNOWN) { @@ -18108,7 +18109,7 @@ static int eval_isnamec1(int c) /* * Get number v: variable value. */ -long get_vim_var_nr(int idx) FUNC_ATTR_PURE +varnumber_T get_vim_var_nr(int idx) FUNC_ATTR_PURE { return vimvars[idx].vv_nr; } diff --git a/src/nvim/eval/decode.c b/src/nvim/eval/decode.c index 935c98fb84..bf0abe04a3 100644 --- a/src/nvim/eval/decode.c +++ b/src/nvim/eval/decode.c @@ -435,7 +435,7 @@ static inline int parse_json_string(const char *const buf, const size_t buf_len, case 'u': { const char ubuf[] = { t[1], t[2], t[3], t[4] }; t += 4; - unsigned long ch; + uvarnumber_T ch; vim_str2nr((char_u *) ubuf, NULL, NULL, STR2NR_HEX | STR2NR_FORCE, NULL, &ch, 4); if (ch == 0) { @@ -609,7 +609,7 @@ parse_json_number_check: tv.v_type = VAR_FLOAT; } else { // Convert integer - long nr; + varnumber_T nr; int num_len; vim_str2nr((char_u *) s, NULL, &num_len, 0, &nr, NULL, (int) (p - s)); if ((int) exp_num_len != num_len) { @@ -617,7 +617,7 @@ parse_json_number_check: "to integer vim_str2nr consumed %i bytes in place of %zu"), (int) exp_num_len, s, num_len, exp_num_len); } - tv.vval.v_number = (varnumber_T) nr; + tv.vval.v_number = nr; } if (json_decoder_pop(OBJ(tv, false, *didcomma, *didcolon), stack, container_stack, diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h index 0f659727ee..3f8ed3b3f9 100644 --- a/src/nvim/eval/typval.h +++ b/src/nvim/eval/typval.h @@ -1,7 +1,7 @@ #ifndef NVIM_EVAL_TYPVAL_H #define NVIM_EVAL_TYPVAL_H -#include +#include #include #include #include @@ -20,20 +20,21 @@ #include "nvim/macros.h" /// Type used for VimL VAR_NUMBER values -typedef int varnumber_T; +typedef int64_t varnumber_T; +typedef uint64_t uvarnumber_T; /// Type used for VimL VAR_FLOAT values typedef double float_T; /// Maximal possible value of varnumber_T variable -#define VARNUMBER_MAX INT_MAX +#define VARNUMBER_MAX INT64_MAX +#define UVARNUMBER_MAX UINT64_MAX /// Mimimal possible value of varnumber_T variable -#define VARNUMBER_MIN INT_MIN -#define PRIdVARNUMBER "d" +#define VARNUMBER_MIN INT64_MIN /// %d printf format specifier for varnumber_T -#define PRIdVARNUMBER "d" +#define PRIdVARNUMBER PRId64 typedef struct listvar_S list_T; typedef struct dictvar_S dict_T; diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index a528a65abb..008a44b43b 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -318,14 +318,12 @@ static int sort_abort; ///< flag to indicate if sorting has been interrupted /// Struct to store info to be sorted. typedef struct { linenr_T lnum; ///< line number - long start_col_nr; ///< starting column number or number - long end_col_nr; ///< ending column number union { struct { - long start_col_nr; ///< starting column number - long end_col_nr; ///< ending column number + varnumber_T start_col_nr; ///< starting column number + varnumber_T end_col_nr; ///< ending column number } line; - long value; ///< value if sorting by integer + varnumber_T value; ///< value if sorting by integer float_T value_flt; ///< value if sorting by float } st_u; } sorti_T; diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 2b4997928e..b27d778140 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -5004,7 +5004,7 @@ int get_list_range(char_u **str, int *num1, int *num2) { int len; int first = false; - long num; + varnumber_T num; *str = skipwhite(*str); if (**str == '-' || ascii_isdigit(**str)) { // parse "from" part of range diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 42cc42b844..031aca97ff 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -6871,7 +6871,7 @@ static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io, active_apc_list = &patcmd; /* set v:cmdarg (only when there is a matching pattern) */ - save_cmdbang = get_vim_var_nr(VV_CMDBANG); + save_cmdbang = (long)get_vim_var_nr(VV_CMDBANG); if (eap != NULL) { save_cmdarg = set_cmdarg(eap, NULL); set_vim_var_nr(VV_CMDBANG, (long)eap->forceit); diff --git a/src/nvim/fold.c b/src/nvim/fold.c index 9c44e89eed..db88791967 100644 --- a/src/nvim/fold.c +++ b/src/nvim/fold.c @@ -2894,7 +2894,7 @@ static void foldlevelExpr(fline_T *flp) /* KeyTyped may be reset to 0 when calling a function which invokes * do_cmdline(). To make 'foldopen' work correctly restore KeyTyped. */ save_keytyped = KeyTyped; - n = eval_foldexpr(flp->wp->w_p_fde, &c); + n = (int)eval_foldexpr(flp->wp->w_p_fde, &c); KeyTyped = save_keytyped; switch (c) { diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 957ab6c9ce..785c9fade9 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -1015,7 +1015,7 @@ EXTERN int did_cursorhold INIT(= false); // set when CursorHold t'gerd // for CursorMoved event EXTERN pos_T last_cursormoved INIT(= INIT_POS_T(0, 0, 0)); -EXTERN int last_changedtick INIT(= 0); // for TextChanged event +EXTERN varnumber_T last_changedtick INIT(= 0); // for TextChanged event EXTERN buf_T *last_changedtick_buf INIT(= NULL); EXTERN int postponed_split INIT(= 0); /* for CTRL-W CTRL-] command */ diff --git a/src/nvim/indent.c b/src/nvim/indent.c index 5471b41b2c..efca739c2d 100644 --- a/src/nvim/indent.c +++ b/src/nvim/indent.c @@ -471,7 +471,7 @@ int get_breakindent_win(win_T *wp, char_u *line) { || prev_tick != wp->w_buffer->b_changedtick) { prev_line = line; prev_ts = wp->w_buffer->b_p_ts; - prev_tick = wp->w_buffer->b_changedtick; + prev_tick = (int)wp->w_buffer->b_changedtick; prev_indent = get_indent_str(line, (int)wp->w_buffer->b_p_ts, wp->w_p_list); } @@ -538,7 +538,7 @@ int get_expr_indent(void) sandbox++; } textlock++; - indent = eval_to_number(curbuf->b_p_inde); + indent = (int)eval_to_number(curbuf->b_p_inde); if (use_sandbox) { sandbox--; diff --git a/src/nvim/keymap.c b/src/nvim/keymap.c index 9c5fe78c7c..ee67b4c19d 100644 --- a/src/nvim/keymap.c +++ b/src/nvim/keymap.c @@ -557,7 +557,7 @@ int find_special_key(const char_u **srcp, const size_t src_len, int *const modp, int modifiers; int bit; int key; - unsigned long n; + uvarnumber_T n; int l; if (src_len == 0) { diff --git a/src/nvim/ops.c b/src/nvim/ops.c index e374686286..ce34e26994 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -939,9 +939,9 @@ static int stuff_yank(int regname, char_u *p) static int execreg_lastc = NUL; /* - * execute a yank register: copy it into the stuff buffer + * Execute a yank register: copy it into the stuff buffer * - * return FAIL for failure, OK otherwise + * Return FAIL for failure, OK otherwise */ int do_execreg ( @@ -4439,8 +4439,8 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) char_u buf2[NUMBUFLEN]; int pre; // 'X' or 'x': hex; '0': octal; 'B' or 'b': bin static bool hexupper = false; // 0xABC - unsigned long n; - unsigned long oldn; + uvarnumber_T n; + uvarnumber_T oldn; char_u *ptr; int c; int todel; @@ -4635,20 +4635,20 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) oldn = n; - n = subtract ? n - (unsigned long) Prenum1 - : n + (unsigned long) Prenum1; + n = subtract ? n - (uvarnumber_T) Prenum1 + : n + (uvarnumber_T) Prenum1; // handle wraparound for decimal numbers if (!pre) { if (subtract) { if (n > oldn) { - n = 1 + (n ^ (unsigned long)-1); + n = 1 + (n ^ (uvarnumber_T)-1); negative ^= true; } } else { // add if (n < oldn) { - n = (n ^ (unsigned long)-1); + n = (n ^ (uvarnumber_T)-1); negative ^= true; } } @@ -5238,11 +5238,13 @@ void clear_oparg(oparg_T *oap) * case, eol_size will be added to the character count to account for * the size of the EOL character. */ -static long line_count_info(char_u *line, long *wc, long *cc, long limit, int eol_size) +static varnumber_T line_count_info(char_u *line, varnumber_T *wc, + varnumber_T *cc, varnumber_T limit, + int eol_size) { - long i; - long words = 0; - long chars = 0; + varnumber_T i; + varnumber_T words = 0; + varnumber_T chars = 0; int is_word = 0; for (i = 0; i < limit && line[i] != NUL; ) { @@ -5280,15 +5282,15 @@ void cursor_pos_info(dict_T *dict) char_u buf1[50]; char_u buf2[40]; linenr_T lnum; - long byte_count = 0; - long bom_count = 0; - long byte_count_cursor = 0; - long char_count = 0; - long char_count_cursor = 0; - long word_count = 0; - long word_count_cursor = 0; + varnumber_T byte_count = 0; + varnumber_T bom_count = 0; + varnumber_T byte_count_cursor = 0; + varnumber_T char_count = 0; + varnumber_T char_count_cursor = 0; + varnumber_T word_count = 0; + varnumber_T word_count_cursor = 0; int eol_size; - long last_check = 100000L; + varnumber_T last_check = 100000L; long line_count_selected = 0; pos_T min_pos, max_pos; oparg_T oparg; @@ -5398,12 +5400,12 @@ void cursor_pos_info(dict_T *dict) byte_count_cursor = byte_count + line_count_info(ml_get(lnum), &word_count_cursor, &char_count_cursor, - (long)(curwin->w_cursor.col + 1), eol_size); + (varnumber_T)(curwin->w_cursor.col + 1), eol_size); } } /* Add to the running totals */ byte_count += line_count_info(ml_get(lnum), &word_count, - &char_count, (long)MAXCOL, eol_size); + &char_count, (varnumber_T)MAXCOL, eol_size); } // Correction for when last line doesn't have an EOL. diff --git a/src/nvim/option.c b/src/nvim/option.c index 392a2f3908..defe0ad246 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -1144,7 +1144,7 @@ do_set ( int afterchar; /* character just after option name */ int len; int i; - long value; + varnumber_T value; int key; uint32_t flags; /* flags for current option */ char_u *varp = NULL; /* pointer to variable for current option */ @@ -4630,7 +4630,7 @@ get_option_value ( if ((int *)varp == &curbuf->b_changed) { *numval = curbufIsChanged(); } else { - *numval = *(int *)varp; + *numval = (long) *(varnumber_T *)varp; } } return 1; diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index ff51bf289e..b6878cbbf4 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -4027,7 +4027,7 @@ int get_errorlist_properties(win_T *wp, dict_T *what, dict_T *retdict) if ((di = tv_dict_find(what, S_LEN("nr"))) != NULL) { // Use the specified quickfix/location list if (di->di_tv.v_type == VAR_NUMBER) { - qf_idx = di->di_tv.vval.v_number - 1; + qf_idx = (int)di->di_tv.vval.v_number - 1; if (qf_idx < 0 || qf_idx >= qi->qf_listcount) { return FAIL; } @@ -4101,7 +4101,7 @@ static int qf_add_entries(qf_info_T *qi, list_T *list, char_u *title, char *const filename = tv_dict_get_string(d, "filename", true); int bufnum = (int)tv_dict_get_number(d, "bufnr"); - long lnum = tv_dict_get_number(d, "lnum"); + long lnum = (long)tv_dict_get_number(d, "lnum"); int col = (int)tv_dict_get_number(d, "col"); char_u vcol = (char_u)tv_dict_get_number(d, "vcol"); int nr = (int)tv_dict_get_number(d, "nr"); @@ -4183,7 +4183,7 @@ static int qf_set_properties(qf_info_T *qi, dict_T *what, int action) if ((di = tv_dict_find(what, S_LEN("nr"))) != NULL) { // Use the specified quickfix/location list if (di->di_tv.v_type == VAR_NUMBER) { - qf_idx = di->di_tv.vval.v_number - 1; + qf_idx = (int)di->di_tv.vval.v_number - 1; if (qf_idx < 0 || qf_idx >= qi->qf_listcount) { return FAIL; } diff --git a/src/nvim/testdir/test_viml.vim b/src/nvim/testdir/test_viml.vim index a2997b6d4d..55d0dc21a3 100644 --- a/src/nvim/testdir/test_viml.vim +++ b/src/nvim/testdir/test_viml.vim @@ -1062,6 +1062,32 @@ func Test_echo_and_string() call assert_equal(["{'a': [], 'b': []}", \ "{'a': [], 'b': []}"], l) +"------------------------------------------------------------------------------- +" Test 94: 64-bit Numbers {{{1 +"------------------------------------------------------------------------------- + +func Test_num64() + if !has('num64') + return + endif + + call assert_notequal( 4294967296, 0) + call assert_notequal(-4294967296, 0) + call assert_equal( 4294967296, 0xFFFFffff + 1) + call assert_equal(-4294967296, -0xFFFFffff - 1) + + call assert_equal( 9223372036854775807, 1 / 0) + call assert_equal(-9223372036854775807, -1 / 0) + call assert_equal(-9223372036854775808, 0 / 0) + + call assert_equal( 0x7FFFffffFFFFffff, float2nr( 1.0e150)) + call assert_equal(-0x7FFFffffFFFFffff, float2nr(-1.0e150)) + + let rng = range(0xFFFFffff, 0x100000001) + call assert_equal([0xFFFFffff, 0x100000000, 0x100000001], rng) + call assert_equal(0x100000001, max(rng)) + call assert_equal(0xFFFFffff, min(rng)) + call assert_equal(rng, sort(range(0x100000001, 0xFFFFffff, -1), 'N')) endfunc "------------------------------------------------------------------------------- diff --git a/src/nvim/version.c b/src/nvim/version.c index f48cd9f2a7..174ae2836c 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -468,7 +468,7 @@ static const int included_patches[] = { // 1979, // 1978, // 1977, - // 1976, + 1976, 1975, // 1974 NA 1973, From 481654a88bd184ed90b87607d6798865bcc375a3 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Wed, 16 Nov 2016 14:08:53 -0500 Subject: [PATCH 03/20] vim-patch:7.4.1977 Problem: With 64 bit changes don't need three calls to sprintf(). Solution: Simplify the code, use vim_snprintf(). (Ken Takata) https://github.com/vim/vim/commit/bde9810d6103ffe3a22a9330021cb21db1ed1792 nvim already had the equivalent code, so only the patch number was needed. --- src/nvim/version.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nvim/version.c b/src/nvim/version.c index 174ae2836c..2e43670edb 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -467,7 +467,7 @@ static const int included_patches[] = { 1980, // 1979, // 1978, - // 1977, + 1977, 1976, 1975, // 1974 NA From 0164a5fea3a240efc631bc10ebf1b547c2149971 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Wed, 16 Nov 2016 14:11:15 -0500 Subject: [PATCH 04/20] vim-patch:7.4.1978 Problem: Large file test does not delete its output. Solution: Delete the output. Check size properly when possible. (Ken Takata) https://github.com/vim/vim/commit/c5af40ae646ceda817eff93b4f9ba274f031bea6 --- src/nvim/testdir/test_largefile.vim | 12 ++++++++---- src/nvim/version.c | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/nvim/testdir/test_largefile.vim b/src/nvim/testdir/test_largefile.vim index ea2b8ff62d..1b3e02a0c8 100644 --- a/src/nvim/testdir/test_largefile.vim +++ b/src/nvim/testdir/test_largefile.vim @@ -22,9 +22,13 @@ func Test_largefile() normal 50% normal gg w - " Check if the file size is larger than 2^31 - 1 bytes. - " Note that getfsize() returns -2 if a Number is 32 bits. + " Check if the file size is 4,000,000,000 bytes. let fsize=getfsize(fname) - call assert_true(fsize > 2147483647 || fsize == -2) - "call delete(fname) + if has('num64') + call assert_true(fsize == 4000000000) + else + " getfsize() returns -2 if a Number is 32 bits. + call assert_true(fsize == -2) + endif + call delete(fname) endfunc diff --git a/src/nvim/version.c b/src/nvim/version.c index 2e43670edb..6838c476c1 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -466,7 +466,7 @@ static const int included_patches[] = { 1981, 1980, // 1979, - // 1978, + 1978, 1977, 1976, 1975, From 03f5f78792c578520139a785c0d3d34e284c372d Mon Sep 17 00:00:00 2001 From: James McCoy Date: Wed, 16 Nov 2016 14:12:13 -0500 Subject: [PATCH 05/20] vim-patch:7.4.1979 Problem: Getting value of binary option is wrong. (Kent Sibilev) Solution: Fix type cast. Add a test. https://github.com/vim/vim/commit/2acfbed9dbea990f129535de7ff3df360365130b --- src/nvim/option.c | 2 +- src/nvim/testdir/test_expr.vim | 23 +++++++++++++++++++++++ src/nvim/version.c | 2 +- 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/nvim/option.c b/src/nvim/option.c index defe0ad246..aed55620a1 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -4630,7 +4630,7 @@ get_option_value ( if ((int *)varp == &curbuf->b_changed) { *numval = curbufIsChanged(); } else { - *numval = (long) *(varnumber_T *)varp; + *numval = (long) *(int *)varp; } } return 1; diff --git a/src/nvim/testdir/test_expr.vim b/src/nvim/testdir/test_expr.vim index 03a9155512..25cbd60114 100644 --- a/src/nvim/testdir/test_expr.vim +++ b/src/nvim/testdir/test_expr.vim @@ -98,6 +98,29 @@ func Test_special_char() call assert_fails('echo "\') endfunc +func Test_option_value() + " boolean + set bri + call assert_equal(1, &bri) + set nobri + call assert_equal(0, &bri) + + " number + set ts=1 + call assert_equal(1, &ts) + set ts=8 + call assert_equal(8, &ts) + + " string + exe "set cedit=\" + call assert_equal("\", &cedit) + set cpo= + call assert_equal("", &cpo) + set cpo=abcdefi + call assert_equal("abcdefi", &cpo) + set cpo&vim +endfunc + func Test_setmatches() hi def link 1 Comment hi def link 2 PreProc diff --git a/src/nvim/version.c b/src/nvim/version.c index 6838c476c1..fe8dd69fca 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -465,7 +465,7 @@ static const int included_patches[] = { // 1982 NA 1981, 1980, - // 1979, + 1979, 1978, 1977, 1976, From 9c01efd6fb7cc01b779ffb6d435f84e0a8e5f22d Mon Sep 17 00:00:00 2001 From: James McCoy Date: Wed, 16 Nov 2016 14:27:30 -0500 Subject: [PATCH 06/20] vim-patch:7.4.1986 Problem: Compiler warns for loss of data. Solution: Use size_t instead of int. (Christian Brabandt) https://github.com/vim/vim/commit/fef524bbff9aa186838c35212b2f89f61d627cf8 Equivalent change had already been made when merging earlier pack patches. --- src/nvim/version.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nvim/version.c b/src/nvim/version.c index fe8dd69fca..40cea51c58 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -458,7 +458,7 @@ static const int included_patches[] = { 1989, // 1988 NA // 1987 NA - // 1986, + 1986, // 1985 NA 1984, // 1983 NA From c3efb2804a6bcf3b61695cd2b0c60bb16f1ec0a9 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Wed, 16 Nov 2016 14:30:20 -0500 Subject: [PATCH 07/20] vim-patch:7.4.2029 Problem: printf() does not work with 64 bit numbers. Solution: use the "L" length modifier. (Ken Takata) https://github.com/vim/vim/commit/38ee6b041e73ad31c3b6b99d56d20833b59b2b57 --- src/nvim/strings.c | 7 +++++++ src/nvim/testdir/test_expr.vim | 6 ++++++ src/nvim/version.c | 2 +- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/nvim/strings.c b/src/nvim/strings.c index c5fd8741b8..9b9aa6d2f4 100644 --- a/src/nvim/strings.c +++ b/src/nvim/strings.c @@ -910,6 +910,13 @@ int vim_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap, default: break; } + switch (fmt_spec) { + case 'd': case 'u': case 'o': case 'x': case 'X': + if (tvs && length_modifier == '\0') { + length_modifier = '2'; + } + } + // get parameter value, do initial processing switch (fmt_spec) { // '%' and 'c' behave similar to 's' regarding flags and field widths diff --git a/src/nvim/testdir/test_expr.vim b/src/nvim/testdir/test_expr.vim index 25cbd60114..04979b867f 100644 --- a/src/nvim/testdir/test_expr.vim +++ b/src/nvim/testdir/test_expr.vim @@ -121,6 +121,12 @@ func Test_option_value() set cpo&vim endfunc +function Test_printf_64bit() + if has('num64') + call assert_equal("123456789012345", printf('%d', 123456789012345)) + endif +endfunc + func Test_setmatches() hi def link 1 Comment hi def link 2 PreProc diff --git a/src/nvim/version.c b/src/nvim/version.c index 40cea51c58..242b2c4b69 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -415,7 +415,7 @@ static const int included_patches[] = { // 2032 NA 2031, // 2030 NA - // 2029, + 2029, 2028, // 2027 NA // 2026 NA From 55c93ea16438d6bacd287460e370a49c559af514 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Wed, 19 Apr 2017 23:32:47 -0400 Subject: [PATCH 08/20] vim-patch:7.4.2224 Problem: Compiler warnings with older compiler and 64 bit numbers. Solution: Add "LL" to large values. (Mike Williams) https://github.com/vim/vim/commit/af9c4c9b5761c4c074237d87e2c95713bf721eab Equivalent change was made in ZyX's typval refactoring. --- src/nvim/version.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nvim/version.c b/src/nvim/version.c index 242b2c4b69..804968af3d 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -220,7 +220,7 @@ static const int included_patches[] = { 2227, 2226, 2225, - // 2224, + 2224, 2223, 2222, 2221, From 2fb0a62553480406a1b8ea314a528f00692c365a Mon Sep 17 00:00:00 2001 From: James McCoy Date: Mon, 23 Jan 2017 12:55:27 -0500 Subject: [PATCH 09/20] vim-patch:8.0.0219 Problem: Ubsan reports errors for integer overflow. Solution: Define macros for minimum and maximum values. Select an expression based on the value. (Mike Williams) https://github.com/vim/vim/commit/7a40ea2138102545848ea86a361f1b8dec7552b5 --- src/nvim/charset.c | 41 ++++++++++++++++++++++++++++------ src/nvim/eval.c | 10 ++++----- src/nvim/testdir/test_viml.vim | 2 +- 3 files changed, 40 insertions(+), 13 deletions(-) diff --git a/src/nvim/charset.c b/src/nvim/charset.c index bf4dc25efd..48db1030a6 100644 --- a/src/nvim/charset.c +++ b/src/nvim/charset.c @@ -1683,7 +1683,12 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len, n += 2; // skip over "0b" } while ('0' <= *ptr && *ptr <= '1') { - un = 2 * un + (uvarnumber_T)(*ptr - '0'); + // avoid ubsan error for overflow + if (un < UVARNUMBER_MAX / 2) { + un = 2 * un + (uvarnumber_T)(*ptr - '0'); + } else { + un = UVARNUMBER_MAX; + } ptr++; if (n++ == maxlen) { break; @@ -1692,7 +1697,12 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len, } else if ((pre == '0') || what == STR2NR_OCT + STR2NR_FORCE) { // octal while ('0' <= *ptr && *ptr <= '7') { - un = 8 * un + (uvarnumber_T)(*ptr - '0'); + // avoid ubsan error for overflow + if (un < UVARNUMBER_MAX / 8) { + un = 8 * un + (uvarnumber_T)(*ptr - '0'); + } else { + un = UVARNUMBER_MAX; + } ptr++; if (n++ == maxlen) { break; @@ -1705,7 +1715,12 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len, n += 2; // skip over "0x" } while (ascii_isxdigit(*ptr)) { - un = 16 * un + (uvarnumber_T)hex2nr(*ptr); + // avoid ubsan error for overflow + if (un < UVARNUMBER_MAX / 16) { + un = 16 * un + (uvarnumber_T)hex2nr(*ptr); + } else { + un = UVARNUMBER_MAX; + } ptr++; if (n++ == maxlen) { break; @@ -1714,7 +1729,12 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len, } else { // decimal while (ascii_isdigit(*ptr)) { - un = 10 * un + (unsigned long)(*ptr - '0'); + // avoid ubsan error for overflow + if (un < UVARNUMBER_MAX / 10) { + un = 10 * un + (uvarnumber_T)(*ptr - '0'); + } else { + un = UVARNUMBER_MAX; + } ptr++; if (n++ == maxlen) { break; @@ -1731,10 +1751,17 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len, } if (nptr != NULL) { - if (negative) { - // account for leading '-' for decimal numbers - *nptr = -(varnumber_T)un; + if (negative) { // account for leading '-' for decimal numbers + // avoid ubsan error for overflow + if (un > VARNUMBER_MAX) { + *nptr = VARNUMBER_MIN; + } else { + *nptr = -(varnumber_T)un; + } } else { + if (un > VARNUMBER_MAX) { + un = VARNUMBER_MAX; + } *nptr = (varnumber_T)un; } } diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 19e23190b1..785643b5e0 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -4032,11 +4032,11 @@ eval6 ( else if (op == '/') { if (n2 == 0) { /* give an error message? */ if (n1 == 0) - n1 = -0x7fffffffffffffff - 1; /* similar to NaN */ + n1 = VARNUMBER_MIN; /* similar to NaN */ else if (n1 < 0) - n1 = -0x7fffffffffffffff; + n1 = -VARNUMBER_MAX; else - n1 = 0x7fffffffffffffff; + n1 = VARNUMBER_MAX; } else n1 = n1 / n2; } else { @@ -8539,8 +8539,8 @@ static void f_float2nr(typval_T *argvars, typval_T *rettv, FunPtr fptr) float_T f; if (tv_get_float_chk(argvars, &f)) { - if (f < VARNUMBER_MIN) { - rettv->vval.v_number = VARNUMBER_MIN; + if (f < -VARNUMBER_MAX) { + rettv->vval.v_number = -VARNUMBER_MAX; } else if (f > VARNUMBER_MAX) { rettv->vval.v_number = VARNUMBER_MAX; } else { diff --git a/src/nvim/testdir/test_viml.vim b/src/nvim/testdir/test_viml.vim index 55d0dc21a3..9c1bc802a0 100644 --- a/src/nvim/testdir/test_viml.vim +++ b/src/nvim/testdir/test_viml.vim @@ -1078,7 +1078,7 @@ func Test_num64() call assert_equal( 9223372036854775807, 1 / 0) call assert_equal(-9223372036854775807, -1 / 0) - call assert_equal(-9223372036854775808, 0 / 0) + call assert_equal(-9223372036854775807 - 1, 0 / 0) call assert_equal( 0x7FFFffffFFFFffff, float2nr( 1.0e150)) call assert_equal(-0x7FFFffffFFFFffff, float2nr(-1.0e150)) From 43534cab025fa57109c832f13fb567da2299e707 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Mon, 23 Jan 2017 23:13:25 -0500 Subject: [PATCH 10/20] lint --- src/nvim/eval.c | 28 +++++++++++++++------------- src/nvim/eval/decode.c | 2 +- src/nvim/fileio.c | 31 ++++++++++++++----------------- src/nvim/memline.c | 7 ++++--- src/nvim/ops.c | 31 +++++++++++++++---------------- src/nvim/option.c | 2 +- src/nvim/tag.c | 41 +++++++++++++++++++++-------------------- 7 files changed, 71 insertions(+), 71 deletions(-) diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 785643b5e0..398ae0045a 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -970,7 +970,7 @@ eval_to_bool ( emsg_skip--; } - return (int)retval; + return retval; } /// Top level evaluation function, returning a string @@ -1262,7 +1262,7 @@ int call_vim_function( * Uses argv[argc] for the function arguments. */ varnumber_T -call_func_retnr ( +call_func_retnr( char_u *func, int argc, const char_u *const *const argv, @@ -3939,7 +3939,7 @@ eval6 ( typval_T var2; int op; varnumber_T n1, n2; - int use_float = FALSE; + bool use_float = false; float_T f1 = 0, f2; bool error = false; @@ -3960,7 +3960,7 @@ eval6 ( if (evaluate) { if (rettv->v_type == VAR_FLOAT) { f1 = rettv->vval.v_float; - use_float = TRUE; + use_float = true; n1 = 0; } else { n1 = tv_get_number_chk(rettv, &error); @@ -3984,7 +3984,7 @@ eval6 ( if (var2.v_type == VAR_FLOAT) { if (!use_float) { f1 = n1; - use_float = TRUE; + use_float = true; } f2 = var2.vval.v_float; n2 = 0; @@ -4027,18 +4027,20 @@ eval6 ( rettv->v_type = VAR_FLOAT; rettv->vval.v_float = f1; } else { - if (op == '*') + if (op == '*') { n1 = n1 * n2; - else if (op == '/') { - if (n2 == 0) { /* give an error message? */ - if (n1 == 0) - n1 = VARNUMBER_MIN; /* similar to NaN */ - else if (n1 < 0) + } else if (op == '/') { + if (n2 == 0) { // give an error message? + if (n1 == 0) { + n1 = VARNUMBER_MIN; // similar to NaN + } else if (n1 < 0) { n1 = -VARNUMBER_MAX; - else + } else { n1 = VARNUMBER_MAX; - } else + } + } else { n1 = n1 / n2; + } } else { if (n2 == 0) /* give an error message? */ n1 = 0; diff --git a/src/nvim/eval/decode.c b/src/nvim/eval/decode.c index bf0abe04a3..9c9c2c2dc8 100644 --- a/src/nvim/eval/decode.c +++ b/src/nvim/eval/decode.c @@ -436,7 +436,7 @@ static inline int parse_json_string(const char *const buf, const size_t buf_len, const char ubuf[] = { t[1], t[2], t[3], t[4] }; t += 4; uvarnumber_T ch; - vim_str2nr((char_u *) ubuf, NULL, NULL, + vim_str2nr((char_u *)ubuf, NULL, NULL, STR2NR_HEX | STR2NR_FORCE, NULL, &ch, 4); if (ch == 0) { hasnul = true; diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 031aca97ff..be4188c4df 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -282,7 +282,7 @@ readfile ( long size = 0; char_u *p = NULL; off_T filesize = 0; - int skip_read = FALSE; + int skip_read = false; context_sha256_T sha_ctx; int read_undo_file = FALSE; int split = 0; /* number of split lines */ @@ -778,8 +778,8 @@ retry: read_buf_lnum = 1; read_buf_col = 0; } else if (read_stdin || vim_lseek(fd, (off_T)0L, SEEK_SET) != 0) { - /* Can't rewind the file, give up. */ - error = TRUE; + // Can't rewind the file, give up. + error = true; goto failed; } /* Delete the previously read lines. */ @@ -1614,19 +1614,16 @@ rewind_retry: if (fileformat == EOL_DOS) { if (ptr[-1] == CAR) { /* remove CR */ ptr[-1] = NUL; - --len; - } - /* - * Reading in Dos format, but no CR-LF found! - * When 'fileformats' includes "unix", delete all - * the lines read so far and start all over again. - * Otherwise give an error message later. - */ - else if (ff_error != EOL_DOS) { - if ( try_unix - && !read_stdin - && (read_buffer - || vim_lseek(fd, (off_T)0L, SEEK_SET) == 0)) { + len--; + } else if (ff_error != EOL_DOS) { + // Reading in Dos format, but no CR-LF found! + // When 'fileformats' includes "unix", delete all + // the lines read so far and start all over again. + // Otherwise give an error message later. + if (try_unix + && !read_stdin + && (read_buffer + || vim_lseek(fd, (off_T)0L, SEEK_SET) == 0)) { fileformat = EOL_UNIX; if (set_options) set_fileformat(EOL_UNIX, OPT_LOCAL); @@ -6870,7 +6867,7 @@ static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io, patcmd.next = active_apc_list; active_apc_list = &patcmd; - /* set v:cmdarg (only when there is a matching pattern) */ + // set v:cmdarg (only when there is a matching pattern) save_cmdbang = (long)get_vim_var_nr(VV_CMDBANG); if (eap != NULL) { save_cmdarg = set_cmdarg(eap, NULL); diff --git a/src/nvim/memline.c b/src/nvim/memline.c index b9ab576460..55e7e01825 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -914,10 +914,11 @@ void ml_recover(void) msg_end(); goto theend; } - if ((size = vim_lseek(mfp->mf_fd, (off_T)0L, SEEK_END)) <= 0) - mfp->mf_blocknr_max = 0; /* no file or empty file */ - else + if ((size = vim_lseek(mfp->mf_fd, (off_T)0L, SEEK_END)) <= 0) { + mfp->mf_blocknr_max = 0; // no file or empty file + } else { mfp->mf_blocknr_max = size / mfp->mf_page_size; + } mfp->mf_infile_count = mfp->mf_blocknr_max; /* need to reallocate the memory used to store the data */ diff --git a/src/nvim/ops.c b/src/nvim/ops.c index ce34e26994..c5660f68fd 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -938,13 +938,11 @@ static int stuff_yank(int regname, char_u *p) static int execreg_lastc = NUL; -/* - * Execute a yank register: copy it into the stuff buffer - * - * Return FAIL for failure, OK otherwise - */ -int -do_execreg ( +/// Execute a yank register: copy it into the stuff buffer +/// +/// Return FAIL for failure, OK otherwise +int +do_execreg( int regname, int colon, /* insert ':' before each line */ int addcr, /* always add '\n' to end of line */ @@ -4635,8 +4633,8 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) oldn = n; - n = subtract ? n - (uvarnumber_T) Prenum1 - : n + (uvarnumber_T) Prenum1; + n = subtract ? n - (uvarnumber_T)Prenum1 + : n + (uvarnumber_T)Prenum1; // handle wraparound for decimal numbers if (!pre) { @@ -5397,15 +5395,16 @@ void cursor_pos_info(dict_T *dict) if (lnum == curwin->w_cursor.lnum) { word_count_cursor += word_count; char_count_cursor += char_count; - byte_count_cursor = byte_count + - line_count_info(ml_get(lnum), - &word_count_cursor, &char_count_cursor, - (varnumber_T)(curwin->w_cursor.col + 1), eol_size); + byte_count_cursor = byte_count + + line_count_info(ml_get(lnum), &word_count_cursor, + &char_count_cursor, + (varnumber_T)(curwin->w_cursor.col + 1), + eol_size); } } - /* Add to the running totals */ - byte_count += line_count_info(ml_get(lnum), &word_count, - &char_count, (varnumber_T)MAXCOL, eol_size); + // Add to the running totals + byte_count += line_count_info(ml_get(lnum), &word_count, &char_count, + (varnumber_T)MAXCOL, eol_size); } // Correction for when last line doesn't have an EOL. diff --git a/src/nvim/option.c b/src/nvim/option.c index aed55620a1..ec74ead83c 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -4630,7 +4630,7 @@ get_option_value ( if ((int *)varp == &curbuf->b_changed) { *numval = curbufIsChanged(); } else { - *numval = (long) *(int *)varp; + *numval = (long) *(int *)varp; // NOLINT(whitespace/cast) } } return 1; diff --git a/src/nvim/tag.c b/src/nvim/tag.c index f12d86fc23..be9d621c7d 100644 --- a/src/nvim/tag.c +++ b/src/nvim/tag.c @@ -1079,18 +1079,17 @@ find_tags ( char_u *p; char_u *s; int i; - int tag_file_sorted = NUL; /* !_TAG_FILE_SORTED value */ - struct tag_search_info /* Binary search file offsets */ - { - off_T low_offset; /* offset for first char of first line that - could match */ - off_T high_offset; /* offset of char after last line that could - match */ - off_T curr_offset; /* Current file offset in search range */ - off_T curr_offset_used; /* curr_offset used when skipping back */ - off_T match_offset; /* Where the binary search found a tag */ - int low_char; /* first char at low_offset */ - int high_char; /* first char at high_offset */ + int tag_file_sorted = NUL; // !_TAG_FILE_SORTED value + struct tag_search_info { // Binary search file offsets + off_T low_offset; // offset for first char of first line that + // could match + off_T high_offset; // offset of char after last line that could + // match + off_T curr_offset; // Current file offset in search range + off_T curr_offset_used; // curr_offset used when skipping back + off_T match_offset; // Where the binary search found a tag + int low_char; // first char at low_offset + int high_char; // first char at high_offset } search_info; off_T filesize; int tagcmp; @@ -1376,7 +1375,7 @@ find_tags ( * (repeated below). */ search_info.curr_offset = vim_ftell(fp); if (search_info.curr_offset == search_info.high_offset) { - /* oops, gone a bit too far; try from low offset */ + // oops, gone a bit too far; try from low offset vim_fseek(fp, search_info.low_offset, SEEK_SET); search_info.curr_offset = search_info.low_offset; } @@ -1662,10 +1661,11 @@ parse_line: } else if (state == TS_STEP_FORWARD) { assert(cmplen >= 0); if (mb_strnicmp(tagp.tagname, orgpat.head, (size_t)cmplen) != 0) { - if ((off_T)vim_ftell(fp) > search_info.match_offset) - break; /* past last match */ - else - continue; /* before first match */ + if ((off_T)vim_ftell(fp) > search_info.match_offset) { + break; // past last match + } else { + continue; // before first match + } } } else /* skip this match if it can't match */ @@ -1886,10 +1886,11 @@ parse_line: if (line_error) { EMSG2(_("E431: Format error in tags file \"%s\""), tag_fname); - if (!use_cscope) + if (!use_cscope) { EMSGN(_("Before byte %" PRId64), vim_ftell(fp)); - stop_searching = TRUE; - line_error = FALSE; + } + stop_searching = true; + line_error = false; } if (!use_cscope) From fb2b3f98bbb90c8cebe0d272cb94c4d49789df21 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Sat, 6 May 2017 21:26:44 -0400 Subject: [PATCH 11/20] func_attr: Allow disabling UBSAN for a function --- src/nvim/func_attr.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/nvim/func_attr.h b/src/nvim/func_attr.h index f1a1d9a563..d2d88924e5 100644 --- a/src/nvim/func_attr.h +++ b/src/nvim/func_attr.h @@ -95,6 +95,10 @@ # undef FUNC_ATTR_NORETURN #endif +#ifdef FUNC_ATTR_NO_SANITIZE_UNDEFINED +# undef FUNC_ATTR_NO_SANITIZE_UNDEFINED +#endif + #ifndef DID_REAL_ATTR # define DID_REAL_ATTR # ifdef __GNUC__ @@ -122,6 +126,12 @@ # define REAL_FATTR_ALLOC_SIZE(x) __attribute__((alloc_size(x))) # define REAL_FATTR_ALLOC_SIZE_PROD(x, y) __attribute__((alloc_size(x, y))) # endif + +# if NVIM_HAS_ATTRIBUTE(no_sanitize_undefined) +# define REAL_FATTR_NO_SANITIZE_UNDEFINED __attribute__((no_sanitize_undefined)) +# elif NVIM_HAS_ATTRIBUTE(no_sanitize) +# define REAL_FATTR_NO_SANITIZE_UNDEFINED __attribute__((no_sanitize("undefined"))) +# endif # endif // Define attributes that are not defined for this compiler. @@ -177,6 +187,10 @@ # ifndef REAL_FATTR_NORETURN # define REAL_FATTR_NORETURN # endif + +# ifndef REAL_FATTR_NO_SANITIZE_UNDEFINED +# define REAL_FATTR_NO_SANITIZE_UNDEFINED +# endif #endif #ifdef DEFINE_FUNC_ATTRIBUTES @@ -198,6 +212,7 @@ # define FUNC_ATTR_NONNULL_ARG(...) REAL_FATTR_NONNULL_ARG(__VA_ARGS__) # define FUNC_ATTR_NONNULL_RET REAL_FATTR_NONNULL_RET # define FUNC_ATTR_NORETURN REAL_FATTR_NORETURN +# define FUNC_ATTR_NO_SANITIZE_UNDEFINED REAL_FATTR_NO_SANITIZE_UNDEFINED #elif !defined(DO_NOT_DEFINE_EMPTY_ATTRIBUTES) # define FUNC_ATTR_MALLOC # define FUNC_ATTR_ALLOC_SIZE(x) @@ -212,4 +227,5 @@ # define FUNC_ATTR_NONNULL_ARG(...) # define FUNC_ATTR_NONNULL_RET # define FUNC_ATTR_NORETURN +# define FUNC_ATTR_NO_SANITIZE_UNDEFINED #endif From eb5e4a247666c0ba26b21e214249789ea7c52e85 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Sat, 6 May 2017 22:35:50 -0400 Subject: [PATCH 12/20] *: Disable UBSAN for VimL arithmetic implementation After merging +num64, the 64-bit sanitizer builds show that Vim doesn't buffer the user from C's UB in signed arithmetic. Upstream doesn't appear to be [interested] in fixing the issue, so suppress UBSAN until someone decides to fix the problem. N.B., the problem existed before but went unnoticed since the sanitizer builds weren't being run in 32-bit mode. [interested]: https://groups.google.com/d/topic/vim_dev/_tqf8eQy5eA/discussion --- src/nvim/eval.c | 2 +- src/nvim/eval/executor.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 398ae0045a..654c786227 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -3934,7 +3934,7 @@ eval6 ( typval_T *rettv, int evaluate, int want_string /* after "." operator */ -) +) FUNC_ATTR_NO_SANITIZE_UNDEFINED { typval_T var2; int op; diff --git a/src/nvim/eval/executor.c b/src/nvim/eval/executor.c index 91bb61323f..118228a40c 100644 --- a/src/nvim/eval/executor.c +++ b/src/nvim/eval/executor.c @@ -25,7 +25,7 @@ char *e_listidx = N_("E684: list index out of range: %" PRId64); /// @return OK or FAIL. int eexe_mod_op(typval_T *const tv1, const typval_T *const tv2, const char *const op) - FUNC_ATTR_NONNULL_ALL + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NO_SANITIZE_UNDEFINED { // Can't do anything with a Funcref, a Dict or special value on the right. if (tv2->v_type != VAR_FUNC && tv2->v_type != VAR_DICT) { From b3129b37917f54eb056033a41d1acbb920a5b93b Mon Sep 17 00:00:00 2001 From: James McCoy Date: Sat, 6 May 2017 22:45:26 -0400 Subject: [PATCH 13/20] eexe_mod_op: Explicitly cast varnumber_T to float_T for -Wconversion --- src/nvim/eval/executor.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/nvim/eval/executor.c b/src/nvim/eval/executor.c index 118228a40c..99298cbbcf 100644 --- a/src/nvim/eval/executor.c +++ b/src/nvim/eval/executor.c @@ -55,7 +55,7 @@ int eexe_mod_op(typval_T *const tv1, const typval_T *const tv2, // nr += nr or nr -= nr varnumber_T n = tv_get_number(tv1); if (tv2->v_type == VAR_FLOAT) { - float_T f = n; + float_T f = (float_T)n; if (*op == '+') { f += tv2->vval.v_float; @@ -99,7 +99,7 @@ int eexe_mod_op(typval_T *const tv1, const typval_T *const tv2, } const float_T f = (tv2->v_type == VAR_FLOAT ? tv2->vval.v_float - : tv_get_number(tv2)); + : (float_T)tv_get_number(tv2)); if (*op == '+') { tv1->vval.v_float += f; } else { From 6757c503bd6c8715cee38475c329f7daee7a760f Mon Sep 17 00:00:00 2001 From: James McCoy Date: Tue, 6 Jun 2017 07:34:25 -0400 Subject: [PATCH 14/20] vim-patch:8.0.0614 Problem: float2nr() is not exactly right. Solution: Make float2nr() more accurate. Turn test64 into a new style test. (Hirohito Higashi, closes vim/vim#1688) https://github.com/vim/vim/commit/863e80b4451b5102b41bebf9ddca3a420de746fa --- src/nvim/eval.c | 5 +-- src/nvim/testdir/test_float_func.vim | 47 ++++++++++++++++++++++++++++ src/nvim/testdir/test_vimscript.vim | 43 +++++++++++++++++++++++++ 3 files changed, 93 insertions(+), 2 deletions(-) diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 4856315786..57ec5d1b47 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -8562,9 +8563,9 @@ static void f_float2nr(typval_T *argvars, typval_T *rettv, FunPtr fptr) float_T f; if (tv_get_float_chk(argvars, &f)) { - if (f < -VARNUMBER_MAX) { + if (f <= -VARNUMBER_MAX + DBL_EPSILON) { rettv->vval.v_number = -VARNUMBER_MAX; - } else if (f > VARNUMBER_MAX) { + } else if (f >= VARNUMBER_MAX - DBL_EPSILON) { rettv->vval.v_number = VARNUMBER_MAX; } else { rettv->vval.v_number = (varnumber_T)f; diff --git a/src/nvim/testdir/test_float_func.vim b/src/nvim/testdir/test_float_func.vim index 07ffe96129..5ea5192994 100644 --- a/src/nvim/testdir/test_float_func.vim +++ b/src/nvim/testdir/test_float_func.vim @@ -224,6 +224,20 @@ func Test_str2float() call assert_fails("call str2float(function('string'))", 'E729:') endfunc +func Test_float2nr() + call assert_equal(1, float2nr(1.234)) + call assert_equal(123, float2nr(1.234e2)) + call assert_equal(12, float2nr(123.4e-1)) + let max_number = 1/0 + let min_number = -max_number + call assert_equal(max_number/2+1, float2nr(pow(2, 62))) + call assert_equal(max_number, float2nr(pow(2, 63))) + call assert_equal(max_number, float2nr(pow(2, 64))) + call assert_equal(min_number/2-1, float2nr(-pow(2, 62))) + call assert_equal(min_number, float2nr(-pow(2, 63))) + call assert_equal(min_number, float2nr(-pow(2, 64))) +endfunc + func Test_floor() call assert_equal('2.0', string(floor(2.0))) call assert_equal('2.0', string(floor(2.11))) @@ -283,3 +297,36 @@ func Test_isnan() call assert_equal(0, isnan([])) call assert_equal(0, isnan({})) endfunc + +" This was converted from test65 +func Test_float_misc() + call assert_equal('123.456000', printf('%f', 123.456)) + call assert_equal('1.234560e+02', printf('%e', 123.456)) + call assert_equal('123.456', printf('%g', 123.456)) + " += + let v = 1.234 + let v += 6.543 + call assert_equal('7.777', printf('%g', v)) + let v = 1.234 + let v += 5 + call assert_equal('6.234', printf('%g', v)) + let v = 5 + let v += 3.333 + call assert_equal('8.333', string(v)) + " == + let v = 1.234 + call assert_true(v == 1.234) + call assert_false(v == 1.2341) + " add-subtract + call assert_equal('5.234', printf('%g', 4 + 1.234)) + call assert_equal('-6.766', printf('%g', 1.234 - 8)) + " mult-div + call assert_equal('4.936', printf('%g', 4 * 1.234)) + call assert_equal('0.003241', printf('%g', 4.0 / 1234)) + " dict + call assert_equal("{'x': 1.234, 'y': -2.0e20}", string({'x': 1.234, 'y': -2.0e20})) + " list + call assert_equal('[-123.4, 2.0e-20]', string([-123.4, 2.0e-20])) +endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_vimscript.vim b/src/nvim/testdir/test_vimscript.vim index 13e4793b26..4e0f1bbd2f 100644 --- a/src/nvim/testdir/test_vimscript.vim +++ b/src/nvim/testdir/test_vimscript.vim @@ -1172,6 +1172,49 @@ func Test_script_emty_line_continuation() \ endfunc +"------------------------------------------------------------------------------- +" Test 97: bitwise functions {{{1 +"------------------------------------------------------------------------------- +func Test_bitwise_functions() + " and + call assert_equal(127, and(127, 127)) + call assert_equal(16, and(127, 16)) + call assert_equal(0, and(127, 128)) + call assert_fails("call and(1.0, 1)", 'E805:') + call assert_fails("call and([], 1)", 'E745:') + call assert_fails("call and({}, 1)", 'E728:') + call assert_fails("call and(1, 1.0)", 'E805:') + call assert_fails("call and(1, [])", 'E745:') + call assert_fails("call and(1, {})", 'E728:') + " or + call assert_equal(23, or(16, 7)) + call assert_equal(15, or(8, 7)) + call assert_equal(123, or(0, 123)) + call assert_fails("call or(1.0, 1)", 'E805:') + call assert_fails("call or([], 1)", 'E745:') + call assert_fails("call or({}, 1)", 'E728:') + call assert_fails("call or(1, 1.0)", 'E805:') + call assert_fails("call or(1, [])", 'E745:') + call assert_fails("call or(1, {})", 'E728:') + " xor + call assert_equal(0, xor(127, 127)) + call assert_equal(111, xor(127, 16)) + call assert_equal(255, xor(127, 128)) + call assert_fails("call xor(1.0, 1)", 'E805:') + call assert_fails("call xor([], 1)", 'E745:') + call assert_fails("call xor({}, 1)", 'E728:') + call assert_fails("call xor(1, 1.0)", 'E805:') + call assert_fails("call xor(1, [])", 'E745:') + call assert_fails("call xor(1, {})", 'E728:') + " invert + call assert_equal(65408, and(invert(127), 65535)) + call assert_equal(65519, and(invert(16), 65535)) + call assert_equal(65407, and(invert(128), 65535)) + call assert_fails("call invert(1.0)", 'E805:') + call assert_fails("call invert([])", 'E745:') + call assert_fails("call invert({})", 'E728:') +endfunc + "------------------------------------------------------------------------------- " Modelines {{{1 " vim: ts=8 sw=4 tw=80 fdm=marker From 2109fb18e663e0ab1e47fa9093713a4e9d8c4932 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Tue, 6 Jun 2017 07:56:03 -0400 Subject: [PATCH 15/20] eval/typval: Convert string to varnumber_T instead of intermediate long --- src/nvim/eval/typval.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c index f017f57b12..34fb319d76 100644 --- a/src/nvim/eval/typval.c +++ b/src/nvim/eval/typval.c @@ -2405,9 +2405,7 @@ varnumber_T tv_get_number_chk(const typval_T *const tv, bool *const ret_error) case VAR_STRING: { varnumber_T n = 0; if (tv->vval.v_string != NULL) { - long nr; - vim_str2nr(tv->vval.v_string, NULL, NULL, STR2NR_ALL, &nr, NULL, 0); - n = (varnumber_T)nr; + vim_str2nr(tv->vval.v_string, NULL, NULL, STR2NR_ALL, &n, NULL, 0); } return n; } From 601bf9642fe8f3655a3090d093843ae136110f27 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Tue, 6 Jun 2017 09:56:09 -0400 Subject: [PATCH 16/20] strings/tv_float: Explicitly cast v_number to float_T for -Wconversion --- src/nvim/strings.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nvim/strings.c b/src/nvim/strings.c index 9b9aa6d2f4..687f734742 100644 --- a/src/nvim/strings.c +++ b/src/nvim/strings.c @@ -653,7 +653,7 @@ static float_T tv_float(typval_T *const tvs, int *const idxp) if (tvs[idx].v_type == VAR_FLOAT) { f = tvs[idx].vval.v_float; } else if (tvs[idx].v_type == VAR_NUMBER) { - f = tvs[idx].vval.v_number; + f = (float_T)tvs[idx].vval.v_number; } else { EMSG(_("E807: Expected Float argument for printf()")); } From d69286c065a27706b1b8c8992be1bf5238f433a7 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Tue, 6 Jun 2017 11:37:56 -0400 Subject: [PATCH 17/20] functests/msgpack: Use assert_equal() for more informative errors --- test/functional/eval/msgpack_functions_spec.lua | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/functional/eval/msgpack_functions_spec.lua b/test/functional/eval/msgpack_functions_spec.lua index 4a052b4aff..8ed01d4996 100644 --- a/test/functional/eval/msgpack_functions_spec.lua +++ b/test/functional/eval/msgpack_functions_spec.lua @@ -337,7 +337,8 @@ describe('msgpack*() functions', function() eq(1, eval('type(parsed[0]) == type(0) ' .. '|| parsed[0]._TYPE is v:msgpack_types.integer')) if eval('type(parsed[0]) == type(0)') == 1 then - eq(1, eval('0xFFFFFFFFFFFFFFFF == parsed[0]')) + command('call assert_equal(0xFFFFFFFFFFFFFFFF, parsed[0])') + eq({}, eval('v:errors')) else eq({_TYPE={}, _VAL={1, 3, 0x7FFFFFFF, 0x7FFFFFFF}}, eval('parsed[0]')) end @@ -351,7 +352,8 @@ describe('msgpack*() functions', function() eq(1, eval('type(parsed[0]) == type(0) ' .. '|| parsed[0]._TYPE is v:msgpack_types.integer')) if eval('type(parsed[0]) == type(0)') == 1 then - eq(1, eval('-0x8000000000000000 == parsed[0]')) + command('call assert_equal(-0x8000000000000000, parsed[0])') + eq({}, eval('v:errors')) else eq({_TYPE={}, _VAL={-1, 2, 0, 0}}, eval('parsed[0]')) end From bf4de3f6f761bc73801eadffc63a0c18d00c2db7 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Tue, 6 Jun 2017 13:38:23 -0400 Subject: [PATCH 18/20] functests/msgpack: Correct representation of literal INT64_MIN In order to generate INT64_MIN from literal values, it's necessary to use "-0x7fffffffffffffff - 1". Using "-0x8000000000000000" causes the value to get clamped to INT64_MAX and then negated. --- test/functional/eval/msgpack_functions_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/functional/eval/msgpack_functions_spec.lua b/test/functional/eval/msgpack_functions_spec.lua index 8ed01d4996..b241635dfe 100644 --- a/test/functional/eval/msgpack_functions_spec.lua +++ b/test/functional/eval/msgpack_functions_spec.lua @@ -352,7 +352,7 @@ describe('msgpack*() functions', function() eq(1, eval('type(parsed[0]) == type(0) ' .. '|| parsed[0]._TYPE is v:msgpack_types.integer')) if eval('type(parsed[0]) == type(0)') == 1 then - command('call assert_equal(-0x8000000000000000, parsed[0])') + command('call assert_equal(-0x7fffffffffffffff - 1, parsed[0])') eq({}, eval('v:errors')) else eq({_TYPE={}, _VAL={-1, 2, 0, 0}}, eval('parsed[0]')) From af59a290d8fb22a1b33be39c2fe1a6ab6848ee6d Mon Sep 17 00:00:00 2001 From: James McCoy Date: Tue, 6 Jun 2017 14:30:48 -0400 Subject: [PATCH 19/20] *: Fix conversion warnings for tv_get_number*() --- src/nvim/eval.c | 4 ++-- src/nvim/eval/typval.c | 2 +- src/nvim/option.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 57ec5d1b47..73e19d604d 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -6691,7 +6691,7 @@ static void f_argv(typval_T *argvars, typval_T *rettv, FunPtr fptr) int idx; if (argvars[0].v_type != VAR_UNKNOWN) { - idx = tv_get_number_chk(&argvars[0], NULL); + idx = (int)tv_get_number_chk(&argvars[0], NULL); if (idx >= 0 && idx < ARGCOUNT) { rettv->vval.v_string = (char_u *)xstrdup( (const char *)alist_name(&ARGLIST[idx])); @@ -7427,7 +7427,7 @@ static void f_complete(typval_T *argvars, typval_T *rettv, FunPtr fptr) return; } - const int startcol = tv_get_number_chk(&argvars[0], NULL); + const colnr_T startcol = tv_get_number_chk(&argvars[0], NULL); if (startcol <= 0) { return; } diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c index 34fb319d76..4521085519 100644 --- a/src/nvim/eval/typval.c +++ b/src/nvim/eval/typval.c @@ -2442,7 +2442,7 @@ varnumber_T tv_get_number_chk(const typval_T *const tv, bool *const ret_error) linenr_T tv_get_lnum(const typval_T *const tv) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { - linenr_T lnum = tv_get_number_chk(tv, NULL); + linenr_T lnum = (linenr_T)tv_get_number_chk(tv, NULL); if (lnum == 0) { // No valid number, try using same function as line() does. int fnum; pos_T *const fp = var2fpos(tv, true, &fnum); diff --git a/src/nvim/option.c b/src/nvim/option.c index ec74ead83c..337d16a55b 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -1477,7 +1477,7 @@ do_set ( if (removing) { value = *(long *)varp - value; } - errmsg = (char_u *)set_num_option(opt_idx, varp, value, + errmsg = (char_u *)set_num_option(opt_idx, varp, (long)value, errbuf, sizeof(errbuf), opt_flags); } else if (opt_idx >= 0) { // String. From ca1ba1085a2be1f8963b48c9ccf3936359959924 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Tue, 6 Jun 2017 21:35:44 -0400 Subject: [PATCH 20/20] lint --- src/nvim/eval.c | 33 +++++++++++++++------------------ src/nvim/func_attr.h | 6 ++++-- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 73e19d604d..94916e3e3c 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -3915,24 +3915,21 @@ static int eval5(char_u **arg, typval_T *rettv, int evaluate) // TODO(ZyX-I): move to eval/expressions -/* - * Handle fifth level expression: - * * number multiplication - * / number division - * % number modulo - * - * "arg" must point to the first non-white of the expression. - * "arg" is advanced to the next non-white after the recognized expression. - * - * Return OK or FAIL. - */ -static int -eval6 ( - char_u **arg, - typval_T *rettv, - int evaluate, - int want_string /* after "." operator */ -) FUNC_ATTR_NO_SANITIZE_UNDEFINED +/// Handle fifth level expression: +/// - * number multiplication +/// - / number division +/// - % number modulo +/// +/// @param[in,out] arg Points to the first non-whitespace character of the +/// expression. Is advanced to the next non-whitespace +/// character after the recognized expression. +/// @param[out] rettv Location where result is saved. +/// @param[in] evaluate If not true, rettv is not populated. +/// @param[in] want_string True if "." is string_concatenation, otherwise +/// float +/// @return OK or FAIL. +static int eval6(char_u **arg, typval_T *rettv, int evaluate, int want_string) + FUNC_ATTR_NO_SANITIZE_UNDEFINED { typval_T var2; int op; diff --git a/src/nvim/func_attr.h b/src/nvim/func_attr.h index d2d88924e5..bd26205d6d 100644 --- a/src/nvim/func_attr.h +++ b/src/nvim/func_attr.h @@ -128,9 +128,11 @@ # endif # if NVIM_HAS_ATTRIBUTE(no_sanitize_undefined) -# define REAL_FATTR_NO_SANITIZE_UNDEFINED __attribute__((no_sanitize_undefined)) +# define REAL_FATTR_NO_SANITIZE_UNDEFINED \ + __attribute__((no_sanitize_undefined)) # elif NVIM_HAS_ATTRIBUTE(no_sanitize) -# define REAL_FATTR_NO_SANITIZE_UNDEFINED __attribute__((no_sanitize("undefined"))) +# define REAL_FATTR_NO_SANITIZE_UNDEFINED \ + __attribute__((no_sanitize("undefined"))) # endif # endif