Skip to content

Commit 75bdf6a

Browse files
committed
patch 7.4.1058
Problem: It is not possible to test code that is only reached when memory allocation fails. Solution: Add the alloc_fail() function. Try it out with :vimgrep.
1 parent 2b7db93 commit 75bdf6a

File tree

8 files changed

+138
-5
lines changed

8 files changed

+138
-5
lines changed

runtime/doc/eval.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1739,6 +1739,8 @@ USAGE RESULT DESCRIPTION ~
17391739
abs( {expr}) Float or Number absolute value of {expr}
17401740
acos( {expr}) Float arc cosine of {expr}
17411741
add( {list}, {item}) List append {item} to |List| {list}
1742+
alloc_fail( {countdown}, {when}, {repeat})
1743+
nothing make memory allocation fail
17421744
and( {expr}, {expr}) Number bitwise AND
17431745
append( {lnum}, {string}) Number append {string} below line {lnum}
17441746
append( {lnum}, {list}) Number append lines {list} below line {lnum}
@@ -2118,6 +2120,13 @@ add({list}, {expr}) *add()*
21182120
Use |insert()| to add an item at another position.
21192121

21202122

2123+
alloc_fail({id}, {countdown}, {repeat}) *alloc_fail()*
2124+
This is for testing: If the memory allocation with {id} is
2125+
called, then decrement {countdown}, and when it reaches zero
2126+
let memory allocation fail {repeat} times. When {repeat} is
2127+
smaller than one it fails one time.
2128+
2129+
21212130
and({expr}, {expr}) *and()*
21222131
Bitwise AND on the two arguments. The arguments are converted
21232132
to a number. A List, Dict or Float argument causes an error.

src/eval.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,7 @@ static void f_abs __ARGS((typval_T *argvars, typval_T *rettv));
467467
static void f_acos __ARGS((typval_T *argvars, typval_T *rettv));
468468
#endif
469469
static void f_add __ARGS((typval_T *argvars, typval_T *rettv));
470+
static void f_alloc_fail __ARGS((typval_T *argvars, typval_T *rettv));
470471
static void f_and __ARGS((typval_T *argvars, typval_T *rettv));
471472
static void f_append __ARGS((typval_T *argvars, typval_T *rettv));
472473
static void f_argc __ARGS((typval_T *argvars, typval_T *rettv));
@@ -8071,6 +8072,7 @@ static struct fst
80718072
{"acos", 1, 1, f_acos}, /* WJMc */
80728073
#endif
80738074
{"add", 2, 2, f_add},
8075+
{"alloc_fail", 3, 3, f_alloc_fail},
80748076
{"and", 2, 2, f_and},
80758077
{"append", 2, 2, f_append},
80768078
{"argc", 0, 0, f_argc},
@@ -8983,6 +8985,28 @@ f_add(argvars, rettv)
89838985
EMSG(_(e_listreq));
89848986
}
89858987

8988+
/*
8989+
* "alloc_fail(id, countdown, repeat)" function
8990+
*/
8991+
static void
8992+
f_alloc_fail(argvars, rettv)
8993+
typval_T *argvars;
8994+
typval_T *rettv UNUSED;
8995+
{
8996+
if (argvars[0].v_type != VAR_NUMBER
8997+
|| argvars[0].vval.v_number <= 0
8998+
|| argvars[1].v_type != VAR_NUMBER
8999+
|| argvars[1].vval.v_number < 0
9000+
|| argvars[2].v_type != VAR_NUMBER)
9001+
EMSG(_(e_invarg));
9002+
else
9003+
{
9004+
alloc_fail_id = argvars[0].vval.v_number;
9005+
alloc_fail_countdown = argvars[1].vval.v_number;
9006+
alloc_fail_repeat = argvars[2].vval.v_number;
9007+
}
9008+
}
9009+
89869010
/*
89879011
* "and(expr, expr)" function
89889012
*/

src/globals.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1619,6 +1619,15 @@ EXTERN FILE *time_fd INIT(= NULL); /* where to write startup timing */
16191619
EXTERN int ignored;
16201620
EXTERN char *ignoredp;
16211621

1622+
#ifdef FEAT_EVAL
1623+
/* set by alloc_fail(): ID */
1624+
EXTERN int alloc_fail_id INIT(= 0);
1625+
/* set by alloc_fail(), when zero alloc() returns NULL */
1626+
EXTERN int alloc_fail_countdown INIT(= -1);
1627+
/* set by alloc_fail(), number of times alloc() returns NULL */
1628+
EXTERN int alloc_fail_repeat INIT(= 0);
1629+
#endif
1630+
16221631
/*
16231632
* Optional Farsi support. Include it here, so EXTERN and INIT are defined.
16241633
*/

src/misc2.c

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -797,6 +797,21 @@ vim_mem_profile_dump()
797797

798798
#endif /* MEM_PROFILE */
799799

800+
#ifdef FEAT_EVAL
801+
static int
802+
alloc_does_fail()
803+
{
804+
if (alloc_fail_countdown == 0)
805+
{
806+
if (--alloc_fail_repeat <= 0)
807+
alloc_fail_id = 0;
808+
return TRUE;
809+
}
810+
--alloc_fail_countdown;
811+
return FALSE;
812+
}
813+
#endif
814+
800815
/*
801816
* Some memory is reserved for error messages and for being able to
802817
* call mf_release_all(), which needs some memory for mf_trans_add().
@@ -820,6 +835,22 @@ alloc(size)
820835
return (lalloc((long_u)size, TRUE));
821836
}
822837

838+
/*
839+
* alloc() with an ID for alloc_fail().
840+
* LAST_ID_USED: 5
841+
*/
842+
char_u *
843+
alloc_id(size, id)
844+
unsigned size;
845+
int id;
846+
{
847+
#ifdef FEAT_EVAL
848+
if (alloc_fail_id == id && alloc_does_fail())
849+
return NULL;
850+
#endif
851+
return (lalloc((long_u)size, TRUE));
852+
}
853+
823854
/*
824855
* Allocate memory and set all bytes to zero.
825856
*/
@@ -968,6 +999,23 @@ lalloc(size, message)
968999
return p;
9691000
}
9701001

1002+
/*
1003+
* lalloc() with an ID for alloc_fail().
1004+
* See LAST_ID_USED above.
1005+
*/
1006+
char_u *
1007+
lalloc_id(size, message, id)
1008+
long_u size;
1009+
int message;
1010+
int id;
1011+
{
1012+
#ifdef FEAT_EVAL
1013+
if (alloc_fail_id == id && alloc_does_fail())
1014+
return NULL;
1015+
#endif
1016+
return (lalloc((long_u)size, message));
1017+
}
1018+
9711019
#if defined(MEM_PROFILE) || defined(PROTO)
9721020
/*
9731021
* realloc() with memory profiling.

src/proto/misc2.pro

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,12 @@ void adjust_cursor_col __ARGS((void));
2020
int leftcol_changed __ARGS((void));
2121
void vim_mem_profile_dump __ARGS((void));
2222
char_u *alloc __ARGS((unsigned size));
23+
char_u *alloc_id __ARGS((unsigned size, int id));
2324
char_u *alloc_clear __ARGS((unsigned size));
2425
char_u *alloc_check __ARGS((unsigned size));
2526
char_u *lalloc_clear __ARGS((long_u size, int message));
2627
char_u *lalloc __ARGS((long_u size, int message));
28+
char_u *lalloc_id __ARGS((long_u size, int message, int id));
2729
void *mem_realloc __ARGS((void *ptr, size_t size));
2830
void do_outofmem_msg __ARGS((long_u size));
2931
void free_all_mem __ARGS((void));

src/quickfix.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -253,9 +253,9 @@ qf_init_ext(qi, efile, buf, tv, errorformat, newlist, lnumfirst, lnumlast,
253253
{'s', ".\\+"}
254254
};
255255

256-
namebuf = alloc(CMDBUFFSIZE + 1);
257-
errmsg = alloc(CMDBUFFSIZE + 1);
258-
pattern = alloc(CMDBUFFSIZE + 1);
256+
namebuf = alloc_id(CMDBUFFSIZE + 1, 3);
257+
errmsg = alloc_id(CMDBUFFSIZE + 1, 4);
258+
pattern = alloc_id(CMDBUFFSIZE + 1, 5);
259259
if (namebuf == NULL || errmsg == NULL || pattern == NULL)
260260
goto qf_init_end;
261261

@@ -3465,8 +3465,8 @@ ex_vimgrep(eap)
34653465
goto theend;
34663466
}
34673467

3468-
dirname_start = alloc(MAXPATHL);
3469-
dirname_now = alloc(MAXPATHL);
3468+
dirname_start = alloc_id(MAXPATHL, 1);
3469+
dirname_now = alloc_id(MAXPATHL, 2);
34703470
if (dirname_start == NULL || dirname_now == NULL)
34713471
goto theend;
34723472

src/testdir/test_quickfix.vim

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,3 +273,42 @@ function Test_cbuffer()
273273
call XbufferTests('l')
274274
endfunction
275275

276+
function Test_nomem()
277+
call alloc_fail(1, 0, 0)
278+
try
279+
vimgrep vim runtest.vim
280+
catch
281+
call assert_true(v:exception =~ 'E342')
282+
endtry
283+
284+
call alloc_fail(2, 0, 0)
285+
try
286+
vimgrep vim runtest.vim
287+
catch
288+
call assert_true(v:exception =~ 'E342')
289+
endtry
290+
291+
call alloc_fail(3, 0, 0)
292+
try
293+
cfile runtest.vim
294+
catch
295+
call assert_true(v:exception =~ 'E342')
296+
endtry
297+
298+
call alloc_fail(4, 0, 0)
299+
try
300+
cfile runtest.vim
301+
catch
302+
call assert_true(v:exception =~ 'E342')
303+
endtry
304+
305+
call alloc_fail(5, 0, 0)
306+
try
307+
cfile runtest.vim
308+
catch
309+
call assert_true(v:exception =~ 'E342')
310+
endtry
311+
312+
endfunc
313+
314+

src/version.c

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

742742
static int included_patches[] =
743743
{ /* Add new patch number below this line */
744+
/**/
745+
1058,
744746
/**/
745747
1057,
746748
/**/

0 commit comments

Comments
 (0)