Skip to content

Commit c0f5a78

Browse files
committed
patch 8.1.0736: code for Blob not sufficiently tested
Problem: Code for Blob not sufficiently tested. Solution: Add more tests. Fix uncovered crash. Add test_null_blob().
1 parent 6e5ea8d commit c0f5a78

File tree

10 files changed

+155
-38
lines changed

10 files changed

+155
-38
lines changed

runtime/doc/eval.txt

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
*eval.txt* For Vim version 8.1. Last change: 2019 Jan 11
1+
*eval.txt* For Vim version 8.1. Last change: 2019 Jan 13
22

33

44
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -2528,6 +2528,7 @@ test_autochdir() none enable 'autochdir' during startup
25282528
test_feedinput({string}) none add key sequence to input buffer
25292529
test_garbagecollect_now() none free memory right now for testing
25302530
test_ignore_error({expr}) none ignore a specific error
2531+
test_null_blob() Blob null value for testing
25312532
test_null_channel() Channel null value for testing
25322533
test_null_dict() Dict null value for testing
25332534
test_null_job() Job null value for testing
@@ -3129,7 +3130,7 @@ ch_evalraw({handle}, {string} [, {options}]) *ch_evalraw()*
31293130
is removed.
31303131
Note that Vim does not know when the text received on a raw
31313132
channel is complete, it may only return the first part and you
3132-
need to use ch_readraw() to fetch the rest.
3133+
need to use |ch_readraw()| to fetch the rest.
31333134
See |channel-use|.
31343135

31353136
{only available when compiled with the |+channel| feature}
@@ -9338,25 +9339,28 @@ test_ignore_error({expr}) *test_ignore_error()*
93389339
When the {expr} is the string "RESET" then the list of ignored
93399340
errors is made empty.
93409341

9342+
test_null_blob() *test_null_blob()*
9343+
Return a |Blob| that is null. Only useful for testing.
9344+
93419345
test_null_channel() *test_null_channel()*
9342-
Return a Channel that is null. Only useful for testing.
9346+
Return a |Channel| that is null. Only useful for testing.
93439347
{only available when compiled with the +channel feature}
93449348

93459349
test_null_dict() *test_null_dict()*
9346-
Return a Dict that is null. Only useful for testing.
9350+
Return a |Dict| that is null. Only useful for testing.
93479351

93489352
test_null_job() *test_null_job()*
9349-
Return a Job that is null. Only useful for testing.
9353+
Return a |Job| that is null. Only useful for testing.
93509354
{only available when compiled with the +job feature}
93519355

93529356
test_null_list() *test_null_list()*
9353-
Return a List that is null. Only useful for testing.
9357+
Return a |List| that is null. Only useful for testing.
93549358

93559359
test_null_partial() *test_null_partial()*
9356-
Return a Partial that is null. Only useful for testing.
9360+
Return a |Partial| that is null. Only useful for testing.
93579361

93589362
test_null_string() *test_null_string()*
9359-
Return a String that is null. Only useful for testing.
9363+
Return a |String| that is null. Only useful for testing.
93609364

93619365
test_option_not_set({name}) *test_option_not_set()*
93629366
Reset the flag that indicates option {name} was set. Thus it

src/blob.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -114,13 +114,16 @@ blob_equal(
114114
blob_T *b1,
115115
blob_T *b2)
116116
{
117-
int i;
117+
int i;
118+
int len1 = blob_len(b1);
119+
int len2 = blob_len(b2);
118120

119-
if (b1 == NULL || b2 == NULL)
120-
return FALSE;
121+
// empty and NULL are considered the same
122+
if (len1 == 0 && len2 == 0)
123+
return TRUE;
121124
if (b1 == b2)
122125
return TRUE;
123-
if (blob_len(b1) != blob_len(b2))
126+
if (len1 != len2)
124127
return FALSE;
125128

126129
for (i = 0; i < b1->bv_ga.ga_len; i++)

src/eval.c

Lines changed: 42 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1983,9 +1983,9 @@ get_lval(
19831983
}
19841984
if (rettv != NULL
19851985
&& !(rettv->v_type == VAR_LIST
1986-
|| rettv->vval.v_list != NULL)
1986+
&& rettv->vval.v_list != NULL)
19871987
&& !(rettv->v_type == VAR_BLOB
1988-
|| rettv->vval.v_blob != NULL))
1988+
&& rettv->vval.v_blob != NULL))
19891989
{
19901990
if (!quiet)
19911991
EMSG(_("E709: [:] requires a List or Blob value"));
@@ -2109,6 +2109,8 @@ get_lval(
21092109
}
21102110
else if (lp->ll_tv->v_type == VAR_BLOB)
21112111
{
2112+
long bloblen = blob_len(lp->ll_tv->vval.v_blob);
2113+
21122114
/*
21132115
* Get the number and item for the only or first index of the List.
21142116
*/
@@ -2120,16 +2122,26 @@ get_lval(
21202122
clear_tv(&var1);
21212123

21222124
if (lp->ll_n1 < 0
2123-
|| lp->ll_n1 > blob_len(lp->ll_tv->vval.v_blob))
2125+
|| lp->ll_n1 > bloblen
2126+
|| (lp->ll_range && lp->ll_n1 == bloblen))
21242127
{
21252128
if (!quiet)
2126-
EMSGN(_(e_listidx), lp->ll_n1);
2129+
EMSGN(_(e_blobidx), lp->ll_n1);
2130+
clear_tv(&var2);
21272131
return NULL;
21282132
}
21292133
if (lp->ll_range && !lp->ll_empty2)
21302134
{
21312135
lp->ll_n2 = (long)tv_get_number(&var2);
21322136
clear_tv(&var2);
2137+
if (lp->ll_n2 < 0
2138+
|| lp->ll_n2 >= bloblen
2139+
|| lp->ll_n2 < lp->ll_n1)
2140+
{
2141+
if (!quiet)
2142+
EMSGN(_(e_blobidx), lp->ll_n2);
2143+
return NULL;
2144+
}
21332145
}
21342146
lp->ll_blob = lp->ll_tv->vval.v_blob;
21352147
lp->ll_tv = NULL;
@@ -2241,6 +2253,7 @@ set_var_lval(
22412253
if (lp->ll_blob != NULL)
22422254
{
22432255
int error = FALSE, val;
2256+
22442257
if (op != NULL && *op != '=')
22452258
{
22462259
EMSG2(_(e_letwrong), op);
@@ -2249,17 +2262,23 @@ set_var_lval(
22492262

22502263
if (lp->ll_range && rettv->v_type == VAR_BLOB)
22512264
{
2252-
int i;
2265+
int il, ir;
22532266

2254-
if (blob_len(rettv->vval.v_blob) != blob_len(lp->ll_blob))
2267+
if (lp->ll_empty2)
2268+
lp->ll_n2 = blob_len(lp->ll_blob) - 1;
2269+
2270+
if (lp->ll_n2 - lp->ll_n1 + 1 != blob_len(rettv->vval.v_blob))
22552271
{
2256-
EMSG(_("E972: Blob value has more items than target"));
2272+
EMSG(_("E972: Blob value does not have the right number of bytes"));
22572273
return;
22582274
}
2275+
if (lp->ll_empty2)
2276+
lp->ll_n2 = blob_len(lp->ll_blob);
22592277

2260-
for (i = lp->ll_n1; i <= lp->ll_n2; i++)
2261-
blob_set(lp->ll_blob, i,
2262-
blob_get(rettv->vval.v_blob, i));
2278+
ir = 0;
2279+
for (il = lp->ll_n1; il <= lp->ll_n2; il++)
2280+
blob_set(lp->ll_blob, il,
2281+
blob_get(rettv->vval.v_blob, ir++));
22632282
}
22642283
else
22652284
{
@@ -2278,8 +2297,7 @@ set_var_lval(
22782297
if (lp->ll_n1 == gap->ga_len)
22792298
++gap->ga_len;
22802299
}
2281-
else
2282-
EMSG(_(e_invrange));
2300+
// error for invalid range was already given in get_lval()
22832301
}
22842302
}
22852303
}
@@ -2312,7 +2330,7 @@ set_var_lval(
23122330
else if (lp->ll_range)
23132331
{
23142332
listitem_T *ll_li = lp->ll_li;
2315-
int ll_n1 = lp->ll_n1;
2333+
int ll_n1 = lp->ll_n1;
23162334

23172335
/*
23182336
* Check whether any of the list items is locked
@@ -3354,6 +3372,8 @@ eval0(
33543372
{
33553373
int ret;
33563374
char_u *p;
3375+
int did_emsg_before = did_emsg;
3376+
int called_emsg_before = called_emsg;
33573377

33583378
p = skipwhite(arg);
33593379
ret = eval1(&p, rettv, evaluate);
@@ -3364,9 +3384,11 @@ eval0(
33643384
/*
33653385
* Report the invalid expression unless the expression evaluation has
33663386
* been cancelled due to an aborting error, an interrupt, or an
3367-
* exception.
3387+
* exception, or we already gave a more specific error.
3388+
* Also check called_emsg for when using assert_fails().
33683389
*/
3369-
if (!aborting())
3390+
if (!aborting() && did_emsg == did_emsg_before
3391+
&& called_emsg == called_emsg_before)
33703392
EMSG2(_(e_invexpr2), arg);
33713393
ret = FAIL;
33723394
}
@@ -4195,7 +4217,7 @@ eval7(
41954217
{
41964218
if (!vim_isxdigit(bp[1]))
41974219
{
4198-
EMSG(_("E973: Blob literal should have an even number of hex characters'"));
4220+
EMSG(_("E973: Blob literal should have an even number of hex characters"));
41994221
vim_free(blob);
42004222
ret = FAIL;
42014223
break;
@@ -4632,7 +4654,7 @@ eval_index(
46324654
len = blob_len(rettv->vval.v_blob);
46334655
if (range)
46344656
{
4635-
// The resulting variable is a substring. If the indexes
4657+
// The resulting variable is a sub-blob. If the indexes
46364658
// are out of range the result is empty.
46374659
if (n1 < 0)
46384660
{
@@ -8336,6 +8358,7 @@ ex_echo(exarg_T *eap)
83368358
int atstart = TRUE;
83378359
char_u numbuf[NUMBUFLEN];
83388360
int did_emsg_before = did_emsg;
8361+
int called_emsg_before = called_emsg;
83398362

83408363
if (eap->skip)
83418364
++emsg_skip;
@@ -8353,7 +8376,8 @@ ex_echo(exarg_T *eap)
83538376
* has been cancelled due to an aborting error, an interrupt, or an
83548377
* exception.
83558378
*/
8356-
if (!aborting() && did_emsg == did_emsg_before)
8379+
if (!aborting() && did_emsg == did_emsg_before
8380+
&& called_emsg == called_emsg_before)
83578381
EMSG2(_(e_invexpr2), p);
83588382
need_clr_eos = FALSE;
83598383
break;

src/evalfunc.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,7 @@ static void f_test_option_not_set(typval_T *argvars, typval_T *rettv);
429429
static void f_test_override(typval_T *argvars, typval_T *rettv);
430430
static void f_test_garbagecollect_now(typval_T *argvars, typval_T *rettv);
431431
static void f_test_ignore_error(typval_T *argvars, typval_T *rettv);
432+
static void f_test_null_blob(typval_T *argvars, typval_T *rettv);
432433
#ifdef FEAT_JOB_CHANNEL
433434
static void f_test_null_channel(typval_T *argvars, typval_T *rettv);
434435
#endif
@@ -950,6 +951,7 @@ static struct fst
950951
{"test_feedinput", 1, 1, f_test_feedinput},
951952
{"test_garbagecollect_now", 0, 0, f_test_garbagecollect_now},
952953
{"test_ignore_error", 1, 1, f_test_ignore_error},
954+
{"test_null_blob", 0, 0, f_test_null_blob},
953955
#ifdef FEAT_JOB_CHANNEL
954956
{"test_null_channel", 0, 0, f_test_null_channel},
955957
#endif
@@ -13902,6 +13904,13 @@ f_test_ignore_error(typval_T *argvars, typval_T *rettv UNUSED)
1390213904
ignore_error_for_testing(tv_get_string(&argvars[0]));
1390313905
}
1390413906

13907+
static void
13908+
f_test_null_blob(typval_T *argvars UNUSED, typval_T *rettv)
13909+
{
13910+
rettv->v_type = VAR_BLOB;
13911+
rettv->vval.v_blob = NULL;
13912+
}
13913+
1390513914
#ifdef FEAT_JOB_CHANNEL
1390613915
static void
1390713916
f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv)

src/testdir/test49.vim

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
" Vim script language tests
22
" Author: Servatius Brandt <Servatius.Brandt@fujitsu-siemens.com>
3-
" Last Change: 2019 Jan 09
3+
" Last Change: 2019 Jan 13
44

55
"-------------------------------------------------------------------------------
66
" Test environment {{{1
@@ -3694,15 +3694,15 @@ endif
36943694
if ExtraVim(msgfile)
36953695
try
36963696
Xpath 4194304 " X: 4194304
3697-
let x = novar " error E121/E15; exception: E121
3697+
let x = novar " error E121; exception: E121
36983698
catch /E15:/ " should not catch
36993699
Xpath 8388608 " X: 0
37003700
endtry
37013701
Xpath 16777216 " X: 0
37023702
endif
37033703

37043704
Xpath 33554432 " X: 33554432
3705-
if !MESSAGES('E121', "Undefined variable", 'E15', "Invalid expression")
3705+
if !MESSAGES('E121', "Undefined variable")
37063706
Xpath 67108864 " X: 0
37073707
endif
37083708

src/testdir/test_assign.vim

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@ func Test_let_termcap()
2323
let &t_k1 = old_t_k1
2424
endif
2525

26-
call assert_fails('let x = &t_xx', 'E15')
26+
call assert_fails('let x = &t_xx', 'E113')
2727
let &t_xx = "yes"
2828
call assert_equal("yes", &t_xx)
2929
let &t_xx = ""
30-
call assert_fails('let x = &t_xx', 'E15')
30+
call assert_fails('let x = &t_xx', 'E113')
3131
endfunc
3232

3333
func Test_let_option_error()
@@ -43,3 +43,11 @@ func Test_let_option_error()
4343
call assert_equal("vert:|", &fillchars)
4444
let &fillchars = _w
4545
endfunc
46+
47+
func Test_let_errors()
48+
let s = 'abcd'
49+
call assert_fails('let s[1] = 5', 'E689:')
50+
51+
let l = [1, 2, 3]
52+
call assert_fails('let l[:] = 5', 'E709:')
53+
endfunc

0 commit comments

Comments
 (0)