Skip to content

Commit 5a2d4a3

Browse files
yegappanbrammool
authored andcommitted
patch 8.2.4474: memory allocation failures not tested in quickfix code
Problem: Memory allocation failures not tested in quickfix code. Solution: Add alloc IDs and tests. (Yegappan Lakshmanan, closes #9848)
1 parent 416b5f4 commit 5a2d4a3

File tree

5 files changed

+183
-39
lines changed

5 files changed

+183
-39
lines changed

src/alloc.h

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,26 +8,37 @@
88

99
/*
1010
* alloc.h: enumeration of alloc IDs.
11+
* Used by test_alloc_fail() to test memory allocation failures.
1112
* Each entry must be on exactly one line, GetAllocId() depends on that.
1213
*/
1314
typedef enum {
14-
aid_none = 0,
15-
aid_qf_dirname_start,
16-
aid_qf_dirname_now,
17-
aid_qf_namebuf,
18-
aid_qf_module,
19-
aid_qf_errmsg,
20-
aid_qf_pattern,
21-
aid_tagstack_items,
22-
aid_tagstack_from,
23-
aid_tagstack_details,
24-
aid_sign_getdefined,
25-
aid_sign_getplaced,
26-
aid_sign_define_by_name,
27-
aid_sign_getlist,
28-
aid_sign_getplaced_dict,
29-
aid_sign_getplaced_list,
30-
aid_insert_sign,
31-
aid_sign_getinfo,
32-
aid_last
15+
aid_none = 0,
16+
aid_qf_dirname_start,
17+
aid_qf_dirname_now,
18+
aid_qf_namebuf,
19+
aid_qf_module,
20+
aid_qf_errmsg,
21+
aid_qf_pattern,
22+
aid_qf_efm_fmtstr,
23+
aid_qf_efm_fmtpart,
24+
aid_qf_title,
25+
aid_qf_mef_name,
26+
aid_qf_qfline,
27+
aid_qf_qfinfo,
28+
aid_qf_dirstack,
29+
aid_qf_multiline_pfx,
30+
aid_qf_makecmd,
31+
aid_qf_linebuf,
32+
aid_tagstack_items,
33+
aid_tagstack_from,
34+
aid_tagstack_details,
35+
aid_sign_getdefined,
36+
aid_sign_getplaced,
37+
aid_sign_define_by_name,
38+
aid_sign_getlist,
39+
aid_sign_getplaced_dict,
40+
aid_sign_getplaced_list,
41+
aid_insert_sign,
42+
aid_sign_getinfo,
43+
aid_last
3344
} alloc_id_T;

src/quickfix.c

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -547,13 +547,13 @@ parse_efm_option(char_u *efm)
547547

548548
// Get some space to modify the format string into.
549549
sz = efm_regpat_bufsz(efm);
550-
if ((fmtstr = alloc(sz)) == NULL)
550+
if ((fmtstr = alloc_id(sz, aid_qf_efm_fmtstr)) == NULL)
551551
goto parse_efm_error;
552552

553553
while (efm[0] != NUL)
554554
{
555555
// Allocate a new eformat structure and put it at the end of the list
556-
fmt_ptr = ALLOC_CLEAR_ONE(efm_T);
556+
fmt_ptr = ALLOC_CLEAR_ONE_ID(efm_T, aid_qf_efm_fmtpart);
557557
if (fmt_ptr == NULL)
558558
goto parse_efm_error;
559559
if (fmt_first == NULL) // first one
@@ -628,7 +628,7 @@ qf_grow_linebuf(qfstate_T *state, int newsz)
628628
state->linelen = newsz > LINE_MAXLEN ? LINE_MAXLEN - 1 : newsz;
629629
if (state->growbuf == NULL)
630630
{
631-
state->growbuf = alloc(state->linelen + 1);
631+
state->growbuf = alloc_id(state->linelen + 1, aid_qf_linebuf);
632632
if (state->growbuf == NULL)
633633
return NULL;
634634
state->growbufsiz = state->linelen;
@@ -685,7 +685,7 @@ qf_get_next_str_line(qfstate_T *state)
685685
}
686686

687687
/*
688-
* Get the next string from state->p_Li.
688+
* Get the next string from the List item state->p_li.
689689
*/
690690
static int
691691
qf_get_next_list_line(qfstate_T *state)
@@ -777,7 +777,7 @@ qf_get_next_file_line(qfstate_T *state)
777777
if (state->growbuf == NULL)
778778
{
779779
state->growbufsiz = 2 * (IOSIZE - 1);
780-
state->growbuf = alloc(state->growbufsiz);
780+
state->growbuf = alloc_id(state->growbufsiz, aid_qf_linebuf);
781781
if (state->growbuf == NULL)
782782
return QF_NOMEM;
783783
}
@@ -1382,8 +1382,9 @@ qf_parse_multiline_pfx(
13821382
if (*fields->errmsg && !qfl->qf_multiignore)
13831383
{
13841384
len = (int)STRLEN(qfprev->qf_text);
1385-
if ((ptr = alloc(len + STRLEN(fields->errmsg) + 2))
1386-
== NULL)
1385+
ptr = alloc_id(len + STRLEN(fields->errmsg) + 2,
1386+
aid_qf_multiline_pfx);
1387+
if (ptr == NULL)
13871388
return QF_FAIL;
13881389
STRCPY(ptr, qfprev->qf_text);
13891390
vim_free(qfprev->qf_text);
@@ -1859,7 +1860,7 @@ qf_store_title(qf_list_T *qfl, char_u *title)
18591860

18601861
if (title != NULL)
18611862
{
1862-
char_u *p = alloc(STRLEN(title) + 2);
1863+
char_u *p = alloc_id(STRLEN(title) + 2, aid_qf_title);
18631864

18641865
qfl->qf_title = p;
18651866
if (p != NULL)
@@ -2109,7 +2110,7 @@ qf_add_entry(
21092110
qfline_T *qfp;
21102111
qfline_T **lastp; // pointer to qf_last or NULL
21112112

2112-
if ((qfp = ALLOC_ONE(qfline_T)) == NULL)
2113+
if ((qfp = ALLOC_ONE_ID(qfline_T, aid_qf_qfline)) == NULL)
21132114
return QF_FAIL;
21142115
if (bufnum != 0)
21152116
{
@@ -2189,7 +2190,7 @@ qf_alloc_stack(qfltype_T qfltype)
21892190
{
21902191
qf_info_T *qi;
21912192

2192-
qi = ALLOC_CLEAR_ONE(qf_info_T);
2193+
qi = ALLOC_CLEAR_ONE_ID(qf_info_T, aid_qf_qfinfo);
21932194
if (qi != NULL)
21942195
{
21952196
qi->qf_refcount++;
@@ -2483,7 +2484,7 @@ qf_push_dir(char_u *dirbuf, struct dir_stack_T **stackptr, int is_file_stack)
24832484
struct dir_stack_T *ds_ptr;
24842485

24852486
// allocate new stack element and hook it in
2486-
ds_new = ALLOC_ONE(struct dir_stack_T);
2487+
ds_new = ALLOC_ONE_ID(struct dir_stack_T, aid_qf_dirstack);
24872488
if (ds_new == NULL)
24882489
return NULL;
24892490

@@ -4945,7 +4946,7 @@ get_mef_name(void)
49454946
else
49464947
off += 19;
49474948

4948-
name = alloc(STRLEN(p_mef) + 30);
4949+
name = alloc_id(STRLEN(p_mef) + 30, aid_qf_mef_name);
49494950
if (name == NULL)
49504951
break;
49514952
STRCPY(name, p_mef);
@@ -4976,7 +4977,7 @@ make_get_fullcmd(char_u *makecmd, char_u *fname)
49764977
len = (unsigned)STRLEN(p_shq) * 2 + (unsigned)STRLEN(makecmd) + 1;
49774978
if (*p_sp != NUL)
49784979
len += (unsigned)STRLEN(p_sp) + (unsigned)STRLEN(fname) + 3;
4979-
cmd = alloc(len);
4980+
cmd = alloc_id(len, aid_qf_makecmd);
49804981
if (cmd == NULL)
49814982
return NULL;
49824983
sprintf((char *)cmd, "%s%s%s", (char *)p_shq, (char *)makecmd,
@@ -5042,7 +5043,10 @@ ex_make(exarg_T *eap)
50425043

50435044
cmd = make_get_fullcmd(eap->arg, fname);
50445045
if (cmd == NULL)
5046+
{
5047+
vim_free(fname);
50455048
return;
5049+
}
50465050

50475051
// let the shell know if we are redirecting output or not
50485052
do_shell(cmd, *p_sp != NUL ? SHELL_DOOUT : 0);

src/testdir/test_quickfix.vim

Lines changed: 132 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -621,22 +621,147 @@ func Test_browse()
621621
call Xtest_browse('l')
622622
endfunc
623623

624-
func Test_nomem()
624+
" Test for memory allocation failures
625+
func Xnomem_tests(cchar)
626+
call s:setup_commands(a:cchar)
627+
625628
call test_alloc_fail(GetAllocId('qf_dirname_start'), 0, 0)
626-
call assert_fails('vimgrep vim runtest.vim', 'E342:')
629+
call assert_fails('Xvimgrep vim runtest.vim', 'E342:')
627630

628-
call GetAllocId('qf_dirname_now')->test_alloc_fail(0, 0)
629-
call assert_fails('vimgrep vim runtest.vim', 'E342:')
631+
call test_alloc_fail(GetAllocId('qf_dirname_now'), 0, 0)
632+
call assert_fails('Xvimgrep vim runtest.vim', 'E342:')
630633

631634
call test_alloc_fail(GetAllocId('qf_namebuf'), 0, 0)
632-
call assert_fails('cfile runtest.vim', 'E342:')
635+
call assert_fails('Xfile runtest.vim', 'E342:')
633636

634637
call test_alloc_fail(GetAllocId('qf_errmsg'), 0, 0)
635-
call assert_fails('cfile runtest.vim', 'E342:')
638+
call assert_fails('Xfile runtest.vim', 'E342:')
636639

637640
call test_alloc_fail(GetAllocId('qf_pattern'), 0, 0)
638-
call assert_fails('cfile runtest.vim', 'E342:')
641+
call assert_fails('Xfile runtest.vim', 'E342:')
642+
643+
call test_alloc_fail(GetAllocId('qf_efm_fmtstr'), 0, 0)
644+
set efm=%f
645+
call assert_fails('Xexpr ["Xfile1"]', 'E342:')
646+
set efm&
647+
648+
call test_alloc_fail(GetAllocId('qf_efm_fmtpart'), 0, 0)
649+
set efm=%f:%l:%m,%f-%l-%m
650+
call assert_fails('Xaddexpr ["Xfile2", "Xfile3"]', 'E342:')
651+
set efm&
652+
653+
call test_alloc_fail(GetAllocId('qf_title'), 0, 0)
654+
call assert_fails('Xexpr ""', 'E342:')
655+
call assert_equal('', g:Xgetlist({'all': 1}).title)
656+
657+
call test_alloc_fail(GetAllocId('qf_mef_name'), 0, 0)
658+
set makeef=Xtmp##.err
659+
call assert_fails('Xgrep needle haystack', 'E342:')
660+
set makeef&
661+
662+
call test_alloc_fail(GetAllocId('qf_qfline'), 0, 0)
663+
call assert_fails('Xexpr "Xfile1:10:Line10"', 'E342:')
664+
665+
if a:cchar == 'l'
666+
for id in ['qf_qfline', 'qf_qfinfo']
667+
lgetexpr ["Xfile1:10:L10", "Xfile2:20:L20"]
668+
call test_alloc_fail(GetAllocId(id), 0, 0)
669+
call assert_fails('new', 'E342:')
670+
call assert_equal(2, winnr('$'))
671+
call assert_equal([], getloclist(0))
672+
%bw!
673+
endfor
674+
endif
675+
676+
call test_alloc_fail(GetAllocId('qf_qfline'), 0, 0)
677+
try
678+
call assert_fails('Xvimgrep vim runtest.vim', 'E342:')
679+
catch /^Vim:Interrupt$/
680+
endtry
681+
682+
call test_alloc_fail(GetAllocId('qf_qfline'), 0, 0)
683+
try
684+
call assert_fails('Xvimgrep /vim/f runtest.vim', 'E342:')
685+
catch /^Vim:Interrupt$/
686+
endtry
687+
688+
let l = getqflist({"lines": ["Xfile1:10:L10"]})
689+
call test_alloc_fail(GetAllocId('qf_qfline'), 0, 0)
690+
call assert_fails('call g:Xsetlist(l.items)', 'E342:')
691+
692+
call test_alloc_fail(GetAllocId('qf_qfline'), 0, 0)
693+
try
694+
call assert_fails('Xhelpgrep quickfix', 'E342:')
695+
catch /^Vim:Interrupt$/
696+
endtry
697+
698+
call test_alloc_fail(GetAllocId('qf_qfinfo'), 0, 0)
699+
call assert_fails('let l = g:Xgetlist({"lines": ["Xfile1:10:L10"]})', 'E342:')
700+
call assert_equal(#{items: []}, l)
639701

702+
if a:cchar == 'l'
703+
call setqflist([], 'f')
704+
call setloclist(0, [], 'f')
705+
call test_alloc_fail(GetAllocId('qf_qfinfo'), 0, 0)
706+
call assert_fails('lhelpgrep quickfix', 'E342:')
707+
call assert_equal([], getloclist(0))
708+
709+
call test_alloc_fail(GetAllocId('qf_qfinfo'), 0, 0)
710+
call assert_fails('lvimgrep vim runtest.vim', 'E342:')
711+
712+
let l = getqflist({"lines": ["Xfile1:10:L10"]})
713+
call test_alloc_fail(GetAllocId('qf_qfinfo'), 0, 0)
714+
call assert_fails('call setloclist(0, l.items)', 'E342:')
715+
716+
call test_alloc_fail(GetAllocId('qf_qfinfo'), 0, 0)
717+
call assert_fails('lbuffer', 'E342:')
718+
719+
call test_alloc_fail(GetAllocId('qf_qfinfo'), 0, 0)
720+
call assert_fails('lexpr ["Xfile1:10:L10", "Xfile2:20:L20"]', 'E342:')
721+
722+
call test_alloc_fail(GetAllocId('qf_qfinfo'), 0, 0)
723+
call assert_fails('lfile runtest.vim', 'E342:')
724+
endif
725+
726+
call test_alloc_fail(GetAllocId('qf_dirstack'), 0, 0)
727+
set efm=%DEntering\ dir\ %f,%f:%l:%m
728+
call assert_fails('Xexpr ["Entering dir abc", "abc.txt:1:Hello world"]', 'E342:')
729+
set efm&
730+
731+
call test_alloc_fail(GetAllocId('qf_dirstack'), 0, 0)
732+
set efm=%+P[%f],(%l)%m
733+
call assert_fails('Xexpr ["[runtest.vim]", "(1)Hello"]', 'E342:')
734+
set efm&
735+
736+
call test_alloc_fail(GetAllocId('qf_multiline_pfx'), 0, 0)
737+
set efm=%EError,%Cline\ %l,%Z%m
738+
call assert_fails('Xexpr ["Error", "line 1", "msg"]', 'E342:')
739+
set efm&
740+
741+
call test_alloc_fail(GetAllocId('qf_makecmd'), 0, 0)
742+
call assert_fails('Xgrep vim runtest.vim', 'E342:')
743+
744+
call test_alloc_fail(GetAllocId('qf_linebuf'), 0, 0)
745+
call assert_fails('Xexpr repeat("a", 8192)', 'E342:')
746+
747+
call test_alloc_fail(GetAllocId('qf_linebuf'), 0, 0)
748+
call assert_fails('Xexpr [repeat("a", 8192)]', 'E342:')
749+
750+
new
751+
call setline(1, repeat('a', 8192))
752+
call test_alloc_fail(GetAllocId('qf_linebuf'), 0, 0)
753+
call assert_fails('Xbuffer', 'E342:')
754+
%bw!
755+
756+
call writefile([repeat('a', 8192)], 'Xtest')
757+
call test_alloc_fail(GetAllocId('qf_linebuf'), 0, 0)
758+
call assert_fails('Xfile Xtest', 'E342:')
759+
call delete('Xtest')
760+
endfunc
761+
762+
func Test_nomem()
763+
call Xnomem_tests('c')
764+
call Xnomem_tests('l')
640765
endfunc
641766

642767
func s:test_xhelpgrep(cchar)

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -754,6 +754,8 @@ static char *(features[]) =
754754

755755
static int included_patches[] =
756756
{ /* Add new patch number below this line */
757+
/**/
758+
4474,
757759
/**/
758760
4473,
759761
/**/

src/vim.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1608,8 +1608,10 @@ typedef UINT32_TYPEDEF UINT32_T;
16081608
// Allocate memory for one type and cast the returned pointer to have the
16091609
// compiler check the types.
16101610
#define ALLOC_ONE(type) (type *)alloc(sizeof(type))
1611+
#define ALLOC_ONE_ID(type, id) (type *)alloc_id(sizeof(type), id)
16111612
#define ALLOC_MULT(type, count) (type *)alloc(sizeof(type) * (count))
16121613
#define ALLOC_CLEAR_ONE(type) (type *)alloc_clear(sizeof(type))
1614+
#define ALLOC_CLEAR_ONE_ID(type, id) (type *)alloc_clear_id(sizeof(type), id)
16131615
#define ALLOC_CLEAR_MULT(type, count) (type *)alloc_clear(sizeof(type) * (count))
16141616
#define LALLOC_CLEAR_ONE(type) (type *)lalloc_clear(sizeof(type), FALSE)
16151617
#define LALLOC_CLEAR_MULT(type, count) (type *)lalloc_clear(sizeof(type) * (count), FALSE)

0 commit comments

Comments
 (0)