To: vim_dev@googlegroups.com Subject: Patch 8.2.4474 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.4474 Problem: Memory allocation failures not tested in quickfix code. Solution: Add alloc IDs and tests. (Yegappan Lakshmanan, closes #9848) Files: src/alloc.h, src/quickfix.c, src/vim.h, src/testdir/test_quickfix.vim *** ../vim-8.2.4473/src/alloc.h 2018-12-21 13:36:57.000000000 +0000 --- src/alloc.h 2022-02-26 10:26:38.851839325 +0000 *************** *** 8,33 **** /* * alloc.h: enumeration of alloc IDs. * Each entry must be on exactly one line, GetAllocId() depends on that. */ typedef enum { ! aid_none = 0, ! aid_qf_dirname_start, ! aid_qf_dirname_now, ! aid_qf_namebuf, ! aid_qf_module, ! aid_qf_errmsg, ! aid_qf_pattern, ! aid_tagstack_items, ! aid_tagstack_from, ! aid_tagstack_details, ! aid_sign_getdefined, ! aid_sign_getplaced, ! aid_sign_define_by_name, ! aid_sign_getlist, ! aid_sign_getplaced_dict, ! aid_sign_getplaced_list, ! aid_insert_sign, ! aid_sign_getinfo, ! aid_last } alloc_id_T; --- 8,44 ---- /* * alloc.h: enumeration of alloc IDs. + * Used by test_alloc_fail() to test memory allocation failures. * Each entry must be on exactly one line, GetAllocId() depends on that. */ typedef enum { ! aid_none = 0, ! aid_qf_dirname_start, ! aid_qf_dirname_now, ! aid_qf_namebuf, ! aid_qf_module, ! aid_qf_errmsg, ! aid_qf_pattern, ! aid_qf_efm_fmtstr, ! aid_qf_efm_fmtpart, ! aid_qf_title, ! aid_qf_mef_name, ! aid_qf_qfline, ! aid_qf_qfinfo, ! aid_qf_dirstack, ! aid_qf_multiline_pfx, ! aid_qf_makecmd, ! aid_qf_linebuf, ! aid_tagstack_items, ! aid_tagstack_from, ! aid_tagstack_details, ! aid_sign_getdefined, ! aid_sign_getplaced, ! aid_sign_define_by_name, ! aid_sign_getlist, ! aid_sign_getplaced_dict, ! aid_sign_getplaced_list, ! aid_insert_sign, ! aid_sign_getinfo, ! aid_last } alloc_id_T; *** ../vim-8.2.4473/src/quickfix.c 2022-02-24 12:33:13.151233722 +0000 --- src/quickfix.c 2022-02-26 10:26:38.851839325 +0000 *************** *** 547,559 **** // Get some space to modify the format string into. sz = efm_regpat_bufsz(efm); ! if ((fmtstr = alloc(sz)) == NULL) goto parse_efm_error; while (efm[0] != NUL) { // Allocate a new eformat structure and put it at the end of the list ! fmt_ptr = ALLOC_CLEAR_ONE(efm_T); if (fmt_ptr == NULL) goto parse_efm_error; if (fmt_first == NULL) // first one --- 547,559 ---- // Get some space to modify the format string into. sz = efm_regpat_bufsz(efm); ! if ((fmtstr = alloc_id(sz, aid_qf_efm_fmtstr)) == NULL) goto parse_efm_error; while (efm[0] != NUL) { // Allocate a new eformat structure and put it at the end of the list ! fmt_ptr = ALLOC_CLEAR_ONE_ID(efm_T, aid_qf_efm_fmtpart); if (fmt_ptr == NULL) goto parse_efm_error; if (fmt_first == NULL) // first one *************** *** 628,634 **** state->linelen = newsz > LINE_MAXLEN ? LINE_MAXLEN - 1 : newsz; if (state->growbuf == NULL) { ! state->growbuf = alloc(state->linelen + 1); if (state->growbuf == NULL) return NULL; state->growbufsiz = state->linelen; --- 628,634 ---- state->linelen = newsz > LINE_MAXLEN ? LINE_MAXLEN - 1 : newsz; if (state->growbuf == NULL) { ! state->growbuf = alloc_id(state->linelen + 1, aid_qf_linebuf); if (state->growbuf == NULL) return NULL; state->growbufsiz = state->linelen; *************** *** 685,691 **** } /* ! * Get the next string from state->p_Li. */ static int qf_get_next_list_line(qfstate_T *state) --- 685,691 ---- } /* ! * Get the next string from the List item state->p_li. */ static int qf_get_next_list_line(qfstate_T *state) *************** *** 777,783 **** if (state->growbuf == NULL) { state->growbufsiz = 2 * (IOSIZE - 1); ! state->growbuf = alloc(state->growbufsiz); if (state->growbuf == NULL) return QF_NOMEM; } --- 777,783 ---- if (state->growbuf == NULL) { state->growbufsiz = 2 * (IOSIZE - 1); ! state->growbuf = alloc_id(state->growbufsiz, aid_qf_linebuf); if (state->growbuf == NULL) return QF_NOMEM; } *************** *** 1382,1389 **** if (*fields->errmsg && !qfl->qf_multiignore) { len = (int)STRLEN(qfprev->qf_text); ! if ((ptr = alloc(len + STRLEN(fields->errmsg) + 2)) ! == NULL) return QF_FAIL; STRCPY(ptr, qfprev->qf_text); vim_free(qfprev->qf_text); --- 1382,1390 ---- if (*fields->errmsg && !qfl->qf_multiignore) { len = (int)STRLEN(qfprev->qf_text); ! ptr = alloc_id(len + STRLEN(fields->errmsg) + 2, ! aid_qf_multiline_pfx); ! if (ptr == NULL) return QF_FAIL; STRCPY(ptr, qfprev->qf_text); vim_free(qfprev->qf_text); *************** *** 1859,1865 **** if (title != NULL) { ! char_u *p = alloc(STRLEN(title) + 2); qfl->qf_title = p; if (p != NULL) --- 1860,1866 ---- if (title != NULL) { ! char_u *p = alloc_id(STRLEN(title) + 2, aid_qf_title); qfl->qf_title = p; if (p != NULL) *************** *** 2109,2115 **** qfline_T *qfp; qfline_T **lastp; // pointer to qf_last or NULL ! if ((qfp = ALLOC_ONE(qfline_T)) == NULL) return QF_FAIL; if (bufnum != 0) { --- 2110,2116 ---- qfline_T *qfp; qfline_T **lastp; // pointer to qf_last or NULL ! if ((qfp = ALLOC_ONE_ID(qfline_T, aid_qf_qfline)) == NULL) return QF_FAIL; if (bufnum != 0) { *************** *** 2189,2195 **** { qf_info_T *qi; ! qi = ALLOC_CLEAR_ONE(qf_info_T); if (qi != NULL) { qi->qf_refcount++; --- 2190,2196 ---- { qf_info_T *qi; ! qi = ALLOC_CLEAR_ONE_ID(qf_info_T, aid_qf_qfinfo); if (qi != NULL) { qi->qf_refcount++; *************** *** 2483,2489 **** struct dir_stack_T *ds_ptr; // allocate new stack element and hook it in ! ds_new = ALLOC_ONE(struct dir_stack_T); if (ds_new == NULL) return NULL; --- 2484,2490 ---- struct dir_stack_T *ds_ptr; // allocate new stack element and hook it in ! ds_new = ALLOC_ONE_ID(struct dir_stack_T, aid_qf_dirstack); if (ds_new == NULL) return NULL; *************** *** 4945,4951 **** else off += 19; ! name = alloc(STRLEN(p_mef) + 30); if (name == NULL) break; STRCPY(name, p_mef); --- 4946,4952 ---- else off += 19; ! name = alloc_id(STRLEN(p_mef) + 30, aid_qf_mef_name); if (name == NULL) break; STRCPY(name, p_mef); *************** *** 4976,4982 **** len = (unsigned)STRLEN(p_shq) * 2 + (unsigned)STRLEN(makecmd) + 1; if (*p_sp != NUL) len += (unsigned)STRLEN(p_sp) + (unsigned)STRLEN(fname) + 3; ! cmd = alloc(len); if (cmd == NULL) return NULL; sprintf((char *)cmd, "%s%s%s", (char *)p_shq, (char *)makecmd, --- 4977,4983 ---- len = (unsigned)STRLEN(p_shq) * 2 + (unsigned)STRLEN(makecmd) + 1; if (*p_sp != NUL) len += (unsigned)STRLEN(p_sp) + (unsigned)STRLEN(fname) + 3; ! cmd = alloc_id(len, aid_qf_makecmd); if (cmd == NULL) return NULL; sprintf((char *)cmd, "%s%s%s", (char *)p_shq, (char *)makecmd, *************** *** 5042,5048 **** --- 5043,5052 ---- cmd = make_get_fullcmd(eap->arg, fname); if (cmd == NULL) + { + vim_free(fname); return; + } // let the shell know if we are redirecting output or not do_shell(cmd, *p_sp != NUL ? SHELL_DOOUT : 0); *** ../vim-8.2.4473/src/vim.h 2022-02-12 21:08:55.577918000 +0000 --- src/vim.h 2022-02-26 10:26:38.851839325 +0000 *************** *** 1608,1615 **** --- 1608,1617 ---- // Allocate memory for one type and cast the returned pointer to have the // compiler check the types. #define ALLOC_ONE(type) (type *)alloc(sizeof(type)) + #define ALLOC_ONE_ID(type, id) (type *)alloc_id(sizeof(type), id) #define ALLOC_MULT(type, count) (type *)alloc(sizeof(type) * (count)) #define ALLOC_CLEAR_ONE(type) (type *)alloc_clear(sizeof(type)) + #define ALLOC_CLEAR_ONE_ID(type, id) (type *)alloc_clear_id(sizeof(type), id) #define ALLOC_CLEAR_MULT(type, count) (type *)alloc_clear(sizeof(type) * (count)) #define LALLOC_CLEAR_ONE(type) (type *)lalloc_clear(sizeof(type), FALSE) #define LALLOC_CLEAR_MULT(type, count) (type *)lalloc_clear(sizeof(type) * (count), FALSE) *** ../vim-8.2.4473/src/testdir/test_quickfix.vim 2022-02-24 12:33:13.151233722 +0000 --- src/testdir/test_quickfix.vim 2022-02-26 10:26:38.851839325 +0000 *************** *** 621,642 **** call Xtest_browse('l') endfunc ! func Test_nomem() call test_alloc_fail(GetAllocId('qf_dirname_start'), 0, 0) ! call assert_fails('vimgrep vim runtest.vim', 'E342:') ! call GetAllocId('qf_dirname_now')->test_alloc_fail(0, 0) ! call assert_fails('vimgrep vim runtest.vim', 'E342:') call test_alloc_fail(GetAllocId('qf_namebuf'), 0, 0) ! call assert_fails('cfile runtest.vim', 'E342:') call test_alloc_fail(GetAllocId('qf_errmsg'), 0, 0) ! call assert_fails('cfile runtest.vim', 'E342:') call test_alloc_fail(GetAllocId('qf_pattern'), 0, 0) ! call assert_fails('cfile runtest.vim', 'E342:') endfunc func s:test_xhelpgrep(cchar) --- 621,767 ---- call Xtest_browse('l') endfunc ! " Test for memory allocation failures ! func Xnomem_tests(cchar) ! call s:setup_commands(a:cchar) ! call test_alloc_fail(GetAllocId('qf_dirname_start'), 0, 0) ! call assert_fails('Xvimgrep vim runtest.vim', 'E342:') ! call test_alloc_fail(GetAllocId('qf_dirname_now'), 0, 0) ! call assert_fails('Xvimgrep vim runtest.vim', 'E342:') call test_alloc_fail(GetAllocId('qf_namebuf'), 0, 0) ! call assert_fails('Xfile runtest.vim', 'E342:') call test_alloc_fail(GetAllocId('qf_errmsg'), 0, 0) ! call assert_fails('Xfile runtest.vim', 'E342:') call test_alloc_fail(GetAllocId('qf_pattern'), 0, 0) ! call assert_fails('Xfile runtest.vim', 'E342:') + call test_alloc_fail(GetAllocId('qf_efm_fmtstr'), 0, 0) + set efm=%f + call assert_fails('Xexpr ["Xfile1"]', 'E342:') + set efm& + + call test_alloc_fail(GetAllocId('qf_efm_fmtpart'), 0, 0) + set efm=%f:%l:%m,%f-%l-%m + call assert_fails('Xaddexpr ["Xfile2", "Xfile3"]', 'E342:') + set efm& + + call test_alloc_fail(GetAllocId('qf_title'), 0, 0) + call assert_fails('Xexpr ""', 'E342:') + call assert_equal('', g:Xgetlist({'all': 1}).title) + + call test_alloc_fail(GetAllocId('qf_mef_name'), 0, 0) + set makeef=Xtmp##.err + call assert_fails('Xgrep needle haystack', 'E342:') + set makeef& + + call test_alloc_fail(GetAllocId('qf_qfline'), 0, 0) + call assert_fails('Xexpr "Xfile1:10:Line10"', 'E342:') + + if a:cchar == 'l' + for id in ['qf_qfline', 'qf_qfinfo'] + lgetexpr ["Xfile1:10:L10", "Xfile2:20:L20"] + call test_alloc_fail(GetAllocId(id), 0, 0) + call assert_fails('new', 'E342:') + call assert_equal(2, winnr('$')) + call assert_equal([], getloclist(0)) + %bw! + endfor + endif + + call test_alloc_fail(GetAllocId('qf_qfline'), 0, 0) + try + call assert_fails('Xvimgrep vim runtest.vim', 'E342:') + catch /^Vim:Interrupt$/ + endtry + + call test_alloc_fail(GetAllocId('qf_qfline'), 0, 0) + try + call assert_fails('Xvimgrep /vim/f runtest.vim', 'E342:') + catch /^Vim:Interrupt$/ + endtry + + let l = getqflist({"lines": ["Xfile1:10:L10"]}) + call test_alloc_fail(GetAllocId('qf_qfline'), 0, 0) + call assert_fails('call g:Xsetlist(l.items)', 'E342:') + + call test_alloc_fail(GetAllocId('qf_qfline'), 0, 0) + try + call assert_fails('Xhelpgrep quickfix', 'E342:') + catch /^Vim:Interrupt$/ + endtry + + call test_alloc_fail(GetAllocId('qf_qfinfo'), 0, 0) + call assert_fails('let l = g:Xgetlist({"lines": ["Xfile1:10:L10"]})', 'E342:') + call assert_equal(#{items: []}, l) + + if a:cchar == 'l' + call setqflist([], 'f') + call setloclist(0, [], 'f') + call test_alloc_fail(GetAllocId('qf_qfinfo'), 0, 0) + call assert_fails('lhelpgrep quickfix', 'E342:') + call assert_equal([], getloclist(0)) + + call test_alloc_fail(GetAllocId('qf_qfinfo'), 0, 0) + call assert_fails('lvimgrep vim runtest.vim', 'E342:') + + let l = getqflist({"lines": ["Xfile1:10:L10"]}) + call test_alloc_fail(GetAllocId('qf_qfinfo'), 0, 0) + call assert_fails('call setloclist(0, l.items)', 'E342:') + + call test_alloc_fail(GetAllocId('qf_qfinfo'), 0, 0) + call assert_fails('lbuffer', 'E342:') + + call test_alloc_fail(GetAllocId('qf_qfinfo'), 0, 0) + call assert_fails('lexpr ["Xfile1:10:L10", "Xfile2:20:L20"]', 'E342:') + + call test_alloc_fail(GetAllocId('qf_qfinfo'), 0, 0) + call assert_fails('lfile runtest.vim', 'E342:') + endif + + call test_alloc_fail(GetAllocId('qf_dirstack'), 0, 0) + set efm=%DEntering\ dir\ %f,%f:%l:%m + call assert_fails('Xexpr ["Entering dir abc", "abc.txt:1:Hello world"]', 'E342:') + set efm& + + call test_alloc_fail(GetAllocId('qf_dirstack'), 0, 0) + set efm=%+P[%f],(%l)%m + call assert_fails('Xexpr ["[runtest.vim]", "(1)Hello"]', 'E342:') + set efm& + + call test_alloc_fail(GetAllocId('qf_multiline_pfx'), 0, 0) + set efm=%EError,%Cline\ %l,%Z%m + call assert_fails('Xexpr ["Error", "line 1", "msg"]', 'E342:') + set efm& + + call test_alloc_fail(GetAllocId('qf_makecmd'), 0, 0) + call assert_fails('Xgrep vim runtest.vim', 'E342:') + + call test_alloc_fail(GetAllocId('qf_linebuf'), 0, 0) + call assert_fails('Xexpr repeat("a", 8192)', 'E342:') + + call test_alloc_fail(GetAllocId('qf_linebuf'), 0, 0) + call assert_fails('Xexpr [repeat("a", 8192)]', 'E342:') + + new + call setline(1, repeat('a', 8192)) + call test_alloc_fail(GetAllocId('qf_linebuf'), 0, 0) + call assert_fails('Xbuffer', 'E342:') + %bw! + + call writefile([repeat('a', 8192)], 'Xtest') + call test_alloc_fail(GetAllocId('qf_linebuf'), 0, 0) + call assert_fails('Xfile Xtest', 'E342:') + call delete('Xtest') + endfunc + + func Test_nomem() + call Xnomem_tests('c') + call Xnomem_tests('l') endfunc func s:test_xhelpgrep(cchar) *** ../vim-8.2.4473/src/version.c 2022-02-25 21:47:44.905532201 +0000 --- src/version.c 2022-02-26 10:28:37.815899194 +0000 *************** *** 756,757 **** --- 756,759 ---- { /* Add new patch number below this line */ + /**/ + 4474, /**/ -- Laughing helps. It's like jogging on the inside. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///