forked from aniani/vim
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.
This commit is contained in:
@@ -1739,6 +1739,8 @@ USAGE RESULT DESCRIPTION ~
|
|||||||
abs( {expr}) Float or Number absolute value of {expr}
|
abs( {expr}) Float or Number absolute value of {expr}
|
||||||
acos( {expr}) Float arc cosine of {expr}
|
acos( {expr}) Float arc cosine of {expr}
|
||||||
add( {list}, {item}) List append {item} to |List| {list}
|
add( {list}, {item}) List append {item} to |List| {list}
|
||||||
|
alloc_fail( {countdown}, {when}, {repeat})
|
||||||
|
nothing make memory allocation fail
|
||||||
and( {expr}, {expr}) Number bitwise AND
|
and( {expr}, {expr}) Number bitwise AND
|
||||||
append( {lnum}, {string}) Number append {string} below line {lnum}
|
append( {lnum}, {string}) Number append {string} below line {lnum}
|
||||||
append( {lnum}, {list}) Number append lines {list} below line {lnum}
|
append( {lnum}, {list}) Number append lines {list} below line {lnum}
|
||||||
@@ -2118,6 +2120,13 @@ add({list}, {expr}) *add()*
|
|||||||
Use |insert()| to add an item at another position.
|
Use |insert()| to add an item at another position.
|
||||||
|
|
||||||
|
|
||||||
|
alloc_fail({id}, {countdown}, {repeat}) *alloc_fail()*
|
||||||
|
This is for testing: If the memory allocation with {id} is
|
||||||
|
called, then decrement {countdown}, and when it reaches zero
|
||||||
|
let memory allocation fail {repeat} times. When {repeat} is
|
||||||
|
smaller than one it fails one time.
|
||||||
|
|
||||||
|
|
||||||
and({expr}, {expr}) *and()*
|
and({expr}, {expr}) *and()*
|
||||||
Bitwise AND on the two arguments. The arguments are converted
|
Bitwise AND on the two arguments. The arguments are converted
|
||||||
to a number. A List, Dict or Float argument causes an error.
|
to a number. A List, Dict or Float argument causes an error.
|
||||||
|
|||||||
24
src/eval.c
24
src/eval.c
@@ -467,6 +467,7 @@ static void f_abs __ARGS((typval_T *argvars, typval_T *rettv));
|
|||||||
static void f_acos __ARGS((typval_T *argvars, typval_T *rettv));
|
static void f_acos __ARGS((typval_T *argvars, typval_T *rettv));
|
||||||
#endif
|
#endif
|
||||||
static void f_add __ARGS((typval_T *argvars, typval_T *rettv));
|
static void f_add __ARGS((typval_T *argvars, typval_T *rettv));
|
||||||
|
static void f_alloc_fail __ARGS((typval_T *argvars, typval_T *rettv));
|
||||||
static void f_and __ARGS((typval_T *argvars, typval_T *rettv));
|
static void f_and __ARGS((typval_T *argvars, typval_T *rettv));
|
||||||
static void f_append __ARGS((typval_T *argvars, typval_T *rettv));
|
static void f_append __ARGS((typval_T *argvars, typval_T *rettv));
|
||||||
static void f_argc __ARGS((typval_T *argvars, typval_T *rettv));
|
static void f_argc __ARGS((typval_T *argvars, typval_T *rettv));
|
||||||
@@ -8071,6 +8072,7 @@ static struct fst
|
|||||||
{"acos", 1, 1, f_acos}, /* WJMc */
|
{"acos", 1, 1, f_acos}, /* WJMc */
|
||||||
#endif
|
#endif
|
||||||
{"add", 2, 2, f_add},
|
{"add", 2, 2, f_add},
|
||||||
|
{"alloc_fail", 3, 3, f_alloc_fail},
|
||||||
{"and", 2, 2, f_and},
|
{"and", 2, 2, f_and},
|
||||||
{"append", 2, 2, f_append},
|
{"append", 2, 2, f_append},
|
||||||
{"argc", 0, 0, f_argc},
|
{"argc", 0, 0, f_argc},
|
||||||
@@ -8983,6 +8985,28 @@ f_add(argvars, rettv)
|
|||||||
EMSG(_(e_listreq));
|
EMSG(_(e_listreq));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* "alloc_fail(id, countdown, repeat)" function
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
f_alloc_fail(argvars, rettv)
|
||||||
|
typval_T *argvars;
|
||||||
|
typval_T *rettv UNUSED;
|
||||||
|
{
|
||||||
|
if (argvars[0].v_type != VAR_NUMBER
|
||||||
|
|| argvars[0].vval.v_number <= 0
|
||||||
|
|| argvars[1].v_type != VAR_NUMBER
|
||||||
|
|| argvars[1].vval.v_number < 0
|
||||||
|
|| argvars[2].v_type != VAR_NUMBER)
|
||||||
|
EMSG(_(e_invarg));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
alloc_fail_id = argvars[0].vval.v_number;
|
||||||
|
alloc_fail_countdown = argvars[1].vval.v_number;
|
||||||
|
alloc_fail_repeat = argvars[2].vval.v_number;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* "and(expr, expr)" function
|
* "and(expr, expr)" function
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1619,6 +1619,15 @@ EXTERN FILE *time_fd INIT(= NULL); /* where to write startup timing */
|
|||||||
EXTERN int ignored;
|
EXTERN int ignored;
|
||||||
EXTERN char *ignoredp;
|
EXTERN char *ignoredp;
|
||||||
|
|
||||||
|
#ifdef FEAT_EVAL
|
||||||
|
/* set by alloc_fail(): ID */
|
||||||
|
EXTERN int alloc_fail_id INIT(= 0);
|
||||||
|
/* set by alloc_fail(), when zero alloc() returns NULL */
|
||||||
|
EXTERN int alloc_fail_countdown INIT(= -1);
|
||||||
|
/* set by alloc_fail(), number of times alloc() returns NULL */
|
||||||
|
EXTERN int alloc_fail_repeat INIT(= 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Optional Farsi support. Include it here, so EXTERN and INIT are defined.
|
* Optional Farsi support. Include it here, so EXTERN and INIT are defined.
|
||||||
*/
|
*/
|
||||||
|
|||||||
48
src/misc2.c
48
src/misc2.c
@@ -797,6 +797,21 @@ vim_mem_profile_dump()
|
|||||||
|
|
||||||
#endif /* MEM_PROFILE */
|
#endif /* MEM_PROFILE */
|
||||||
|
|
||||||
|
#ifdef FEAT_EVAL
|
||||||
|
static int
|
||||||
|
alloc_does_fail()
|
||||||
|
{
|
||||||
|
if (alloc_fail_countdown == 0)
|
||||||
|
{
|
||||||
|
if (--alloc_fail_repeat <= 0)
|
||||||
|
alloc_fail_id = 0;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
--alloc_fail_countdown;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Some memory is reserved for error messages and for being able to
|
* Some memory is reserved for error messages and for being able to
|
||||||
* call mf_release_all(), which needs some memory for mf_trans_add().
|
* call mf_release_all(), which needs some memory for mf_trans_add().
|
||||||
@@ -820,6 +835,22 @@ alloc(size)
|
|||||||
return (lalloc((long_u)size, TRUE));
|
return (lalloc((long_u)size, TRUE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* alloc() with an ID for alloc_fail().
|
||||||
|
* LAST_ID_USED: 5
|
||||||
|
*/
|
||||||
|
char_u *
|
||||||
|
alloc_id(size, id)
|
||||||
|
unsigned size;
|
||||||
|
int id;
|
||||||
|
{
|
||||||
|
#ifdef FEAT_EVAL
|
||||||
|
if (alloc_fail_id == id && alloc_does_fail())
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
|
return (lalloc((long_u)size, TRUE));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocate memory and set all bytes to zero.
|
* Allocate memory and set all bytes to zero.
|
||||||
*/
|
*/
|
||||||
@@ -968,6 +999,23 @@ theend:
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* lalloc() with an ID for alloc_fail().
|
||||||
|
* See LAST_ID_USED above.
|
||||||
|
*/
|
||||||
|
char_u *
|
||||||
|
lalloc_id(size, message, id)
|
||||||
|
long_u size;
|
||||||
|
int message;
|
||||||
|
int id;
|
||||||
|
{
|
||||||
|
#ifdef FEAT_EVAL
|
||||||
|
if (alloc_fail_id == id && alloc_does_fail())
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
|
return (lalloc((long_u)size, message));
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(MEM_PROFILE) || defined(PROTO)
|
#if defined(MEM_PROFILE) || defined(PROTO)
|
||||||
/*
|
/*
|
||||||
* realloc() with memory profiling.
|
* realloc() with memory profiling.
|
||||||
|
|||||||
@@ -20,10 +20,12 @@ void adjust_cursor_col __ARGS((void));
|
|||||||
int leftcol_changed __ARGS((void));
|
int leftcol_changed __ARGS((void));
|
||||||
void vim_mem_profile_dump __ARGS((void));
|
void vim_mem_profile_dump __ARGS((void));
|
||||||
char_u *alloc __ARGS((unsigned size));
|
char_u *alloc __ARGS((unsigned size));
|
||||||
|
char_u *alloc_id __ARGS((unsigned size, int id));
|
||||||
char_u *alloc_clear __ARGS((unsigned size));
|
char_u *alloc_clear __ARGS((unsigned size));
|
||||||
char_u *alloc_check __ARGS((unsigned size));
|
char_u *alloc_check __ARGS((unsigned size));
|
||||||
char_u *lalloc_clear __ARGS((long_u size, int message));
|
char_u *lalloc_clear __ARGS((long_u size, int message));
|
||||||
char_u *lalloc __ARGS((long_u size, int message));
|
char_u *lalloc __ARGS((long_u size, int message));
|
||||||
|
char_u *lalloc_id __ARGS((long_u size, int message, int id));
|
||||||
void *mem_realloc __ARGS((void *ptr, size_t size));
|
void *mem_realloc __ARGS((void *ptr, size_t size));
|
||||||
void do_outofmem_msg __ARGS((long_u size));
|
void do_outofmem_msg __ARGS((long_u size));
|
||||||
void free_all_mem __ARGS((void));
|
void free_all_mem __ARGS((void));
|
||||||
|
|||||||
@@ -253,9 +253,9 @@ qf_init_ext(qi, efile, buf, tv, errorformat, newlist, lnumfirst, lnumlast,
|
|||||||
{'s', ".\\+"}
|
{'s', ".\\+"}
|
||||||
};
|
};
|
||||||
|
|
||||||
namebuf = alloc(CMDBUFFSIZE + 1);
|
namebuf = alloc_id(CMDBUFFSIZE + 1, 3);
|
||||||
errmsg = alloc(CMDBUFFSIZE + 1);
|
errmsg = alloc_id(CMDBUFFSIZE + 1, 4);
|
||||||
pattern = alloc(CMDBUFFSIZE + 1);
|
pattern = alloc_id(CMDBUFFSIZE + 1, 5);
|
||||||
if (namebuf == NULL || errmsg == NULL || pattern == NULL)
|
if (namebuf == NULL || errmsg == NULL || pattern == NULL)
|
||||||
goto qf_init_end;
|
goto qf_init_end;
|
||||||
|
|
||||||
@@ -3465,8 +3465,8 @@ ex_vimgrep(eap)
|
|||||||
goto theend;
|
goto theend;
|
||||||
}
|
}
|
||||||
|
|
||||||
dirname_start = alloc(MAXPATHL);
|
dirname_start = alloc_id(MAXPATHL, 1);
|
||||||
dirname_now = alloc(MAXPATHL);
|
dirname_now = alloc_id(MAXPATHL, 2);
|
||||||
if (dirname_start == NULL || dirname_now == NULL)
|
if (dirname_start == NULL || dirname_now == NULL)
|
||||||
goto theend;
|
goto theend;
|
||||||
|
|
||||||
|
|||||||
@@ -273,3 +273,42 @@ function Test_cbuffer()
|
|||||||
call XbufferTests('l')
|
call XbufferTests('l')
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
function Test_nomem()
|
||||||
|
call alloc_fail(1, 0, 0)
|
||||||
|
try
|
||||||
|
vimgrep vim runtest.vim
|
||||||
|
catch
|
||||||
|
call assert_true(v:exception =~ 'E342')
|
||||||
|
endtry
|
||||||
|
|
||||||
|
call alloc_fail(2, 0, 0)
|
||||||
|
try
|
||||||
|
vimgrep vim runtest.vim
|
||||||
|
catch
|
||||||
|
call assert_true(v:exception =~ 'E342')
|
||||||
|
endtry
|
||||||
|
|
||||||
|
call alloc_fail(3, 0, 0)
|
||||||
|
try
|
||||||
|
cfile runtest.vim
|
||||||
|
catch
|
||||||
|
call assert_true(v:exception =~ 'E342')
|
||||||
|
endtry
|
||||||
|
|
||||||
|
call alloc_fail(4, 0, 0)
|
||||||
|
try
|
||||||
|
cfile runtest.vim
|
||||||
|
catch
|
||||||
|
call assert_true(v:exception =~ 'E342')
|
||||||
|
endtry
|
||||||
|
|
||||||
|
call alloc_fail(5, 0, 0)
|
||||||
|
try
|
||||||
|
cfile runtest.vim
|
||||||
|
catch
|
||||||
|
call assert_true(v:exception =~ 'E342')
|
||||||
|
endtry
|
||||||
|
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -741,6 +741,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
1058,
|
||||||
/**/
|
/**/
|
||||||
1057,
|
1057,
|
||||||
/**/
|
/**/
|
||||||
|
|||||||
Reference in New Issue
Block a user