summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2016-01-07 21:25:08 +0100
committerBram Moolenaar <Bram@vim.org>2016-01-07 21:25:08 +0100
commit75bdf6aa30a5c99d67c42886cf7a4a000bbaa422 (patch)
treee3e1a3fea418f892524eeec3cb0c2eaa31f5ad61
parent2b7db933b0418f3964da5399047ce8998007874c (diff)
downloadvim-git-75bdf6aa30a5c99d67c42886cf7a4a000bbaa422.tar.gz
patch 7.4.1058v7.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.
-rw-r--r--runtime/doc/eval.txt9
-rw-r--r--src/eval.c24
-rw-r--r--src/globals.h9
-rw-r--r--src/misc2.c48
-rw-r--r--src/proto/misc2.pro2
-rw-r--r--src/quickfix.c10
-rw-r--r--src/testdir/test_quickfix.vim39
-rw-r--r--src/version.c2
8 files changed, 138 insertions, 5 deletions
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index 10780bf64..c2a5965b5 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -1739,6 +1739,8 @@ USAGE RESULT DESCRIPTION ~
abs( {expr}) Float or Number absolute value of {expr}
acos( {expr}) Float arc cosine of {expr}
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
append( {lnum}, {string}) Number append {string} 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.
+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()*
Bitwise AND on the two arguments. The arguments are converted
to a number. A List, Dict or Float argument causes an error.
diff --git a/src/eval.c b/src/eval.c
index 76dd65387..89407b297 100644
--- a/src/eval.c
+++ b/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));
#endif
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_append __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 */
#endif
{"add", 2, 2, f_add},
+ {"alloc_fail", 3, 3, f_alloc_fail},
{"and", 2, 2, f_and},
{"append", 2, 2, f_append},
{"argc", 0, 0, f_argc},
@@ -8984,6 +8986,28 @@ f_add(argvars, rettv)
}
/*
+ * "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
*/
static void
diff --git a/src/globals.h b/src/globals.h
index d921a4e24..54a1d7256 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -1619,6 +1619,15 @@ EXTERN FILE *time_fd INIT(= NULL); /* where to write startup timing */
EXTERN int ignored;
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.
*/
diff --git a/src/misc2.c b/src/misc2.c
index 9f8d7ad99..65ac886cf 100644
--- a/src/misc2.c
+++ b/src/misc2.c
@@ -797,6 +797,21 @@ vim_mem_profile_dump()
#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
* call mf_release_all(), which needs some memory for mf_trans_add().
@@ -821,6 +836,22 @@ alloc(size)
}
/*
+ * 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.
*/
char_u *
@@ -968,6 +999,23 @@ theend:
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)
/*
* realloc() with memory profiling.
diff --git a/src/proto/misc2.pro b/src/proto/misc2.pro
index 490b1aff8..4a955e32f 100644
--- a/src/proto/misc2.pro
+++ b/src/proto/misc2.pro
@@ -20,10 +20,12 @@ void adjust_cursor_col __ARGS((void));
int leftcol_changed __ARGS((void));
void vim_mem_profile_dump __ARGS((void));
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_check __ARGS((unsigned size));
char_u *lalloc_clear __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 do_outofmem_msg __ARGS((long_u size));
void free_all_mem __ARGS((void));
diff --git a/src/quickfix.c b/src/quickfix.c
index 758f7921a..1fda31134 100644
--- a/src/quickfix.c
+++ b/src/quickfix.c
@@ -253,9 +253,9 @@ qf_init_ext(qi, efile, buf, tv, errorformat, newlist, lnumfirst, lnumlast,
{'s', ".\\+"}
};
- namebuf = alloc(CMDBUFFSIZE + 1);
- errmsg = alloc(CMDBUFFSIZE + 1);
- pattern = alloc(CMDBUFFSIZE + 1);
+ namebuf = alloc_id(CMDBUFFSIZE + 1, 3);
+ errmsg = alloc_id(CMDBUFFSIZE + 1, 4);
+ pattern = alloc_id(CMDBUFFSIZE + 1, 5);
if (namebuf == NULL || errmsg == NULL || pattern == NULL)
goto qf_init_end;
@@ -3465,8 +3465,8 @@ ex_vimgrep(eap)
goto theend;
}
- dirname_start = alloc(MAXPATHL);
- dirname_now = alloc(MAXPATHL);
+ dirname_start = alloc_id(MAXPATHL, 1);
+ dirname_now = alloc_id(MAXPATHL, 2);
if (dirname_start == NULL || dirname_now == NULL)
goto theend;
diff --git a/src/testdir/test_quickfix.vim b/src/testdir/test_quickfix.vim
index 60cb539d6..6910a8b29 100644
--- a/src/testdir/test_quickfix.vim
+++ b/src/testdir/test_quickfix.vim
@@ -273,3 +273,42 @@ function Test_cbuffer()
call XbufferTests('l')
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
+
+
diff --git a/src/version.c b/src/version.c
index b20ebd458..34df592cf 100644
--- a/src/version.c
+++ b/src/version.c
@@ -742,6 +742,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1058,
+/**/
1057,
/**/
1056,