vi: detect and warn about invalid line addresses

BusyBox vi didn't have proper handling for invalid markers or
unsuccessful searches in colon line addresses.  This could result
in the wrong lines being affected by a change.

Detect when an invalid address is specified, propagate an error
indicator up the call chain and issue a warning.

function                                             old     new   delta
colon                                               3604    3661     +57
.rodata                                           105195  105211     +16
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/0 up/down: 73/0)               Total: 73 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Ron Yorston 2021-04-15 12:05:45 +01:00 committed by Denys Vlasenko
parent 5d1bb58b13
commit d488def0e4

View File

@ -2360,14 +2360,15 @@ static char *get_one_address(char *p, int *addr) // get colon addr, if present
p++; p++;
c = tolower(*p); c = tolower(*p);
p++; p++;
q = NULL;
if (c >= 'a' && c <= 'z') { if (c >= 'a' && c <= 'z') {
// we have a mark // we have a mark
c = c - 'a'; c = c - 'a';
q = mark[(unsigned char) c]; q = mark[(unsigned char) c];
if (q != NULL) { // is mark valid
*addr = count_lines(text, q);
}
} }
if (q == NULL) // is mark valid
return NULL;
*addr = count_lines(text, q);
} }
# endif # endif
# if ENABLE_FEATURE_VI_SEARCH # if ENABLE_FEATURE_VI_SEARCH
@ -2383,9 +2384,9 @@ static char *get_one_address(char *p, int *addr) // get colon addr, if present
p++; p++;
q = char_search(next_line(dot), last_search_pattern + 1, q = char_search(next_line(dot), last_search_pattern + 1,
(FORWARD << 1) | FULL); (FORWARD << 1) | FULL);
if (q != NULL) { if (q == NULL)
*addr = count_lines(text, q); return NULL;
} *addr = count_lines(text, q);
} }
# endif # endif
else if (*p == '$') { // the last line in file else if (*p == '$') { // the last line in file
@ -2422,6 +2423,8 @@ static char *get_address(char *p, int *b, int *e) // get two colon addrs, if pre
state = GET_SECOND; state = GET_SECOND;
} else if (state == GET_FIRST || state == GET_SECOND) { } else if (state == GET_FIRST || state == GET_SECOND) {
p = get_one_address(p, state == GET_FIRST ? b : e); p = get_one_address(p, state == GET_FIRST ? b : e);
if (p == NULL)
break;
state |= GOT; state |= GOT;
} else { } else {
break; break;
@ -2536,9 +2539,7 @@ static void colon(char *buf)
char *fn, cmd[MAX_INPUT_LEN], args[MAX_INPUT_LEN]; char *fn, cmd[MAX_INPUT_LEN], args[MAX_INPUT_LEN];
int i, l, li, b, e; int i, l, li, b, e;
int useforce; int useforce;
# if ENABLE_FEATURE_VI_SEARCH || ENABLE_FEATURE_ALLOW_EXEC
char *orig_buf; char *orig_buf;
# endif
// :3154 // if (-e line 3154) goto it else stay put // :3154 // if (-e line 3154) goto it else stay put
// :4,33w! foo // write a portion of buffer to file "foo" // :4,33w! foo // write a portion of buffer to file "foo"
@ -2568,7 +2569,12 @@ static void colon(char *buf)
fn = current_filename; fn = current_filename;
// look for optional address(es) :. :1 :1,9 :'q,'a :% // look for optional address(es) :. :1 :1,9 :'q,'a :%
orig_buf = buf;
buf = get_address(buf, &b, &e); buf = get_address(buf, &b, &e);
if (buf == NULL) {
status_line_bold("Bad address: %s", orig_buf);
goto ret;
}
# if ENABLE_FEATURE_VI_SEARCH || ENABLE_FEATURE_ALLOW_EXEC # if ENABLE_FEATURE_VI_SEARCH || ENABLE_FEATURE_ALLOW_EXEC
// remember orig command line // remember orig command line