diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-11-19 13:25:14 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-11-19 13:25:14 +0000 |
commit | 4ae1e13d3f4716a35acf6186f5485e53da39829d (patch) | |
tree | 6a6b72300774220f9c7d914a3ca371af89aa3bc9 | |
parent | 58a88916b926ffac657bb3c063b9906f324d4d79 (diff) | |
download | busybox-w32-4ae1e13d3f4716a35acf6186f5485e53da39829d.tar.gz busybox-w32-4ae1e13d3f4716a35acf6186f5485e53da39829d.tar.bz2 busybox-w32-4ae1e13d3f4716a35acf6186f5485e53da39829d.zip |
vi: fix several instances of major goof: when text grows, text[]
might get reallocated! We were keeping around pointers to old place...
function old new delta
colon 3017 3037 +20
char_insert 336 354 +18
stupid_insert 18 24 +6
string_insert 89 94 +5
do_cmd 4461 4465 +4
file_insert 328 329 +1
text_hole_make 134 120 -14
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 6/1 up/down: 54/-14) Total: 40 bytes
-rw-r--r-- | editors/vi.c | 123 |
1 files changed, 78 insertions, 45 deletions
diff --git a/editors/vi.c b/editors/vi.c index 92c069de0..7f1d27fdf 100644 --- a/editors/vi.c +++ b/editors/vi.c | |||
@@ -300,13 +300,17 @@ static void dot_delete(void); // delete the char at 'dot' | |||
300 | static char *bound_dot(char *); // make sure text[0] <= P < "end" | 300 | static char *bound_dot(char *); // make sure text[0] <= P < "end" |
301 | static char *new_screen(int, int); // malloc virtual screen memory | 301 | static char *new_screen(int, int); // malloc virtual screen memory |
302 | static char *char_insert(char *, char); // insert the char c at 'p' | 302 | static char *char_insert(char *, char); // insert the char c at 'p' |
303 | static char *stupid_insert(char *, char); // stupidly insert the char c at 'p' | 303 | // might reallocate text[]! use p += stupid_insert(p, ...), |
304 | // and be careful to not use pointers into potentially freed text[]! | ||
305 | static uintptr_t stupid_insert(char *, char); // stupidly insert the char c at 'p' | ||
304 | static int find_range(char **, char **, char); // return pointers for an object | 306 | static int find_range(char **, char **, char); // return pointers for an object |
305 | static int st_test(char *, int, int, char *); // helper for skip_thing() | 307 | static int st_test(char *, int, int, char *); // helper for skip_thing() |
306 | static char *skip_thing(char *, int, int, int); // skip some object | 308 | static char *skip_thing(char *, int, int, int); // skip some object |
307 | static char *find_pair(char *, char); // find matching pair () [] {} | 309 | static char *find_pair(char *, char); // find matching pair () [] {} |
308 | static char *text_hole_delete(char *, char *); // at "p", delete a 'size' byte hole | 310 | static char *text_hole_delete(char *, char *); // at "p", delete a 'size' byte hole |
309 | static char *text_hole_make(char *, int); // at "p", make a 'size' byte hole | 311 | // might reallocate text[]! use p += text_hole_make(p, ...), |
312 | // and be careful to not use pointers into potentially freed text[]! | ||
313 | static uintptr_t text_hole_make(char *, int); // at "p", make a 'size' byte hole | ||
310 | static char *yank_delete(char *, char *, int, int); // yank text[] into register then delete | 314 | static char *yank_delete(char *, char *, int, int); // yank text[] into register then delete |
311 | static void show_help(void); // display some help info | 315 | static void show_help(void); // display some help info |
312 | static void rawmode(void); // set "raw" mode on tty | 316 | static void rawmode(void); // set "raw" mode on tty |
@@ -316,11 +320,11 @@ static int mysleep(int); | |||
316 | static int readit(void); // read (maybe cursor) key from stdin | 320 | static int readit(void); // read (maybe cursor) key from stdin |
317 | static int get_one_char(void); // read 1 char from stdin | 321 | static int get_one_char(void); // read 1 char from stdin |
318 | static int file_size(const char *); // what is the byte size of "fn" | 322 | static int file_size(const char *); // what is the byte size of "fn" |
319 | #if ENABLE_FEATURE_VI_READONLY | 323 | #if !ENABLE_FEATURE_VI_READONLY |
320 | static int file_insert(const char *, char *, int); | 324 | #define file_insert(fn, p, update_ro_status) file_insert(fn, p) |
321 | #else | ||
322 | static int file_insert(const char *, char *); | ||
323 | #endif | 325 | #endif |
326 | // file_insert might reallocate text[]! | ||
327 | static int file_insert(const char *, char *, int); | ||
324 | static int file_write(char *, char *, char *); | 328 | static int file_write(char *, char *, char *); |
325 | #if !ENABLE_FEATURE_VI_OPTIMIZE_CURSOR | 329 | #if !ENABLE_FEATURE_VI_OPTIMIZE_CURSOR |
326 | #define place_cursor(a, b, optimize) place_cursor(a, b) | 330 | #define place_cursor(a, b, optimize) place_cursor(a, b) |
@@ -370,7 +374,9 @@ static void end_cmd_q(void); // stop saving input chars | |||
370 | static void showmatching(char *); // show the matching pair () [] {} | 374 | static void showmatching(char *); // show the matching pair () [] {} |
371 | #endif | 375 | #endif |
372 | #if ENABLE_FEATURE_VI_YANKMARK || (ENABLE_FEATURE_VI_COLON && ENABLE_FEATURE_VI_SEARCH) || ENABLE_FEATURE_VI_CRASHME | 376 | #if ENABLE_FEATURE_VI_YANKMARK || (ENABLE_FEATURE_VI_COLON && ENABLE_FEATURE_VI_SEARCH) || ENABLE_FEATURE_VI_CRASHME |
373 | static char *string_insert(char *, char *); // insert the string at 'p' | 377 | // might reallocate text[]! use p += string_insert(p, ...), |
378 | // and be careful to not use pointers into potentially freed text[]! | ||
379 | static uintptr_t string_insert(char *, const char *); // insert the string at 'p' | ||
374 | #endif | 380 | #endif |
375 | #if ENABLE_FEATURE_VI_YANKMARK | 381 | #if ENABLE_FEATURE_VI_YANKMARK |
376 | static char *text_yank(char *, char *, int); // save copy of "p" into a register | 382 | static char *text_yank(char *, char *, int); // save copy of "p" into a register |
@@ -486,8 +492,7 @@ static int init_text_buffer(char *fn) | |||
486 | char_insert(text, '\n'); | 492 | char_insert(text, '\n'); |
487 | rc = 0; | 493 | rc = 0; |
488 | } else { | 494 | } else { |
489 | rc = file_insert(fn, text | 495 | rc = file_insert(fn, text, 1); |
490 | USE_FEATURE_VI_READONLY(, 1)); | ||
491 | } | 496 | } |
492 | file_modified = 0; | 497 | file_modified = 0; |
493 | last_file_modified = -1; | 498 | last_file_modified = -1; |
@@ -584,7 +589,8 @@ static void edit_file(char *fn) | |||
584 | crash_dummy(); // generate a random command | 589 | crash_dummy(); // generate a random command |
585 | } else { | 590 | } else { |
586 | crashme = 0; | 591 | crashme = 0; |
587 | dot = string_insert(text, "\n\n##### Ran out of text to work on. #####\n\n"); // insert the string | 592 | string_insert(text, "\n\n##### Ran out of text to work on. #####\n\n"); // insert the string |
593 | dot = text; | ||
588 | refresh(FALSE); | 594 | refresh(FALSE); |
589 | } | 595 | } |
590 | } | 596 | } |
@@ -976,7 +982,11 @@ static void colon(char *buf) | |||
976 | // read after current line- unless user said ":0r foo" | 982 | // read after current line- unless user said ":0r foo" |
977 | if (b != 0) | 983 | if (b != 0) |
978 | q = next_line(q); | 984 | q = next_line(q); |
979 | ch = file_insert(fn, q USE_FEATURE_VI_READONLY(, 0)); | 985 | { // dance around potentially-reallocated text[] |
986 | uintptr_t ofs = q - text; | ||
987 | ch = file_insert(fn, q, 0); | ||
988 | q = text + ofs; | ||
989 | } | ||
980 | if (ch < 0) | 990 | if (ch < 0) |
981 | goto vc1; // nothing was inserted | 991 | goto vc1; // nothing was inserted |
982 | // how many lines in text[]? | 992 | // how many lines in text[]? |
@@ -990,7 +1000,7 @@ static void colon(char *buf) | |||
990 | // if the insert is before "dot" then we need to update | 1000 | // if the insert is before "dot" then we need to update |
991 | if (q <= dot) | 1001 | if (q <= dot) |
992 | dot += ch; | 1002 | dot += ch; |
993 | file_modified++; | 1003 | /*file_modified++; - done by file_insert */ |
994 | } | 1004 | } |
995 | } else if (strncasecmp(cmd, "rewind", i) == 0) { // rewind cmd line args | 1005 | } else if (strncasecmp(cmd, "rewind", i) == 0) { // rewind cmd line args |
996 | if (file_modified && !useforce) { | 1006 | if (file_modified && !useforce) { |
@@ -1063,10 +1073,12 @@ static void colon(char *buf) | |||
1063 | c = orig_buf[1]; // what is the delimiter | 1073 | c = orig_buf[1]; // what is the delimiter |
1064 | F = orig_buf + 2; // start of "find" | 1074 | F = orig_buf + 2; // start of "find" |
1065 | R = strchr(F, c); // middle delimiter | 1075 | R = strchr(F, c); // middle delimiter |
1066 | if (!R) goto colon_s_fail; | 1076 | if (!R) |
1077 | goto colon_s_fail; | ||
1067 | *R++ = '\0'; // terminate "find" | 1078 | *R++ = '\0'; // terminate "find" |
1068 | buf1 = strchr(R, c); | 1079 | buf1 = strchr(R, c); |
1069 | if (!buf1) goto colon_s_fail; | 1080 | if (!buf1) |
1081 | goto colon_s_fail; | ||
1070 | *buf1++ = '\0'; // terminate "replace" | 1082 | *buf1++ = '\0'; // terminate "replace" |
1071 | if (*buf1 == 'g') { // :s/foo/bar/g | 1083 | if (*buf1 == 'g') { // :s/foo/bar/g |
1072 | buf1++; | 1084 | buf1++; |
@@ -1084,10 +1096,14 @@ static void colon(char *buf) | |||
1084 | vc4: | 1096 | vc4: |
1085 | buf1 = char_search(q, F, FORWARD, LIMITED); // search cur line only for "find" | 1097 | buf1 = char_search(q, F, FORWARD, LIMITED); // search cur line only for "find" |
1086 | if (buf1) { | 1098 | if (buf1) { |
1099 | uintptr_t bias; | ||
1087 | // we found the "find" pattern - delete it | 1100 | // we found the "find" pattern - delete it |
1088 | text_hole_delete(buf1, buf1 + strlen(F) - 1); | 1101 | text_hole_delete(buf1, buf1 + strlen(F) - 1); |
1089 | // inset the "replace" patern | 1102 | // inset the "replace" patern |
1090 | string_insert(buf1, R); // insert the string | 1103 | bias = string_insert(buf1, R); // insert the string |
1104 | buf1 += bias; | ||
1105 | ls += bias; | ||
1106 | /*q += bias; - recalculated anyway */ | ||
1091 | // check for "global" :s/foo/bar/g | 1107 | // check for "global" :s/foo/bar/g |
1092 | if (gflag == 1) { | 1108 | if (gflag == 1) { |
1093 | if ((buf1 + strlen(R)) < end_line(ls)) { | 1109 | if ((buf1 + strlen(R)) < end_line(ls)) { |
@@ -1623,8 +1639,7 @@ static char *char_search(char *p, const char *pat, int dir, int range) | |||
1623 | static char *char_insert(char *p, char c) // insert the char c at 'p' | 1639 | static char *char_insert(char *p, char c) // insert the char c at 'p' |
1624 | { | 1640 | { |
1625 | if (c == 22) { // Is this an ctrl-V? | 1641 | if (c == 22) { // Is this an ctrl-V? |
1626 | p = stupid_insert(p, '^'); // use ^ to indicate literal next | 1642 | p += stupid_insert(p, '^'); // use ^ to indicate literal next |
1627 | p--; // backup onto ^ | ||
1628 | refresh(FALSE); // show the ^ | 1643 | refresh(FALSE); // show the ^ |
1629 | c = get_one_char(); | 1644 | c = get_one_char(); |
1630 | *p = c; | 1645 | *p = c; |
@@ -1651,7 +1666,7 @@ static char *char_insert(char *p, char c) // insert the char c at 'p' | |||
1651 | if (c == 13) | 1666 | if (c == 13) |
1652 | c = '\n'; // translate \r to \n | 1667 | c = '\n'; // translate \r to \n |
1653 | sp = p; // remember addr of insert | 1668 | sp = p; // remember addr of insert |
1654 | p = stupid_insert(p, c); // insert the char | 1669 | p += 1 + stupid_insert(p, c); // insert the char |
1655 | #if ENABLE_FEATURE_VI_SETOPTS | 1670 | #if ENABLE_FEATURE_VI_SETOPTS |
1656 | if (showmatch && strchr(")]}", *sp) != NULL) { | 1671 | if (showmatch && strchr(")]}", *sp) != NULL) { |
1657 | showmatching(sp); | 1672 | showmatching(sp); |
@@ -1659,9 +1674,11 @@ static char *char_insert(char *p, char c) // insert the char c at 'p' | |||
1659 | if (autoindent && c == '\n') { // auto indent the new line | 1674 | if (autoindent && c == '\n') { // auto indent the new line |
1660 | char *q; | 1675 | char *q; |
1661 | 1676 | ||
1662 | q = prev_line(p); // use prev line as templet | 1677 | q = prev_line(p); // use prev line as template |
1663 | for (; isblank(*q); q++) { | 1678 | for (; isblank(*q); q++) { |
1664 | p = stupid_insert(p, *q); // insert the char | 1679 | uintptr_t bias = stupid_insert(p, *q); // insert the char |
1680 | p += bias + 1; | ||
1681 | q += bias; | ||
1665 | } | 1682 | } |
1666 | } | 1683 | } |
1667 | #endif | 1684 | #endif |
@@ -1669,12 +1686,16 @@ static char *char_insert(char *p, char c) // insert the char c at 'p' | |||
1669 | return p; | 1686 | return p; |
1670 | } | 1687 | } |
1671 | 1688 | ||
1672 | static char *stupid_insert(char *p, char c) // stupidly insert the char c at 'p' | 1689 | // might reallocate text[]! use p += stupid_insert(p, ...), |
1690 | // and be careful to not use pointers into potentially freed text[]! | ||
1691 | static uintptr_t stupid_insert(char *p, char c) // stupidly insert the char c at 'p' | ||
1673 | { | 1692 | { |
1674 | p = text_hole_make(p, 1); | 1693 | uintptr_t bias; |
1694 | bias = text_hole_make(p, 1); | ||
1695 | p += bias; | ||
1675 | *p = c; | 1696 | *p = c; |
1676 | //file_modified++; - done by text_hole_make() | 1697 | //file_modified++; - done by text_hole_make() |
1677 | return p + 1; | 1698 | return bias; |
1678 | } | 1699 | } |
1679 | 1700 | ||
1680 | static int find_range(char **start, char **stop, char c) | 1701 | static int find_range(char **start, char **stop, char c) |
@@ -1854,26 +1875,31 @@ static void showmatching(char *p) | |||
1854 | } | 1875 | } |
1855 | #endif /* FEATURE_VI_SETOPTS */ | 1876 | #endif /* FEATURE_VI_SETOPTS */ |
1856 | 1877 | ||
1857 | // open a hole in text[] | 1878 | // open a hole in text[] |
1858 | static char *text_hole_make(char *p, int size) // at "p", make a 'size' byte hole | 1879 | // might reallocate text[]! use p += text_hole_make(p, ...), |
1880 | // and be careful to not use pointers into potentially freed text[]! | ||
1881 | static uintptr_t text_hole_make(char *p, int size) // at "p", make a 'size' byte hole | ||
1859 | { | 1882 | { |
1883 | uintptr_t bias = 0; | ||
1884 | |||
1860 | if (size <= 0) | 1885 | if (size <= 0) |
1861 | return p; | 1886 | return bias; |
1862 | end += size; // adjust the new END | 1887 | end += size; // adjust the new END |
1863 | if (end >= (text + text_size)) { | 1888 | if (end >= (text + text_size)) { |
1864 | char *new_text; | 1889 | char *new_text; |
1865 | text_size += end - (text + text_size) + 10240; | 1890 | text_size += end - (text + text_size) + 10240; |
1866 | new_text = xrealloc(text, text_size); | 1891 | new_text = xrealloc(text, text_size); |
1867 | screenbegin = new_text + (screenbegin - text); | 1892 | bias = (new_text - text); |
1868 | dot = new_text + (dot - text); | 1893 | screenbegin += bias; |
1869 | end = new_text + (end - text); | 1894 | dot += bias; |
1870 | p = new_text + (p - text); | 1895 | end += bias; |
1896 | p += bias; | ||
1871 | text = new_text; | 1897 | text = new_text; |
1872 | } | 1898 | } |
1873 | memmove(p + size, p, end - size - p); | 1899 | memmove(p + size, p, end - size - p); |
1874 | memset(p, ' ', size); // clear new hole | 1900 | memset(p, ' ', size); // clear new hole |
1875 | file_modified++; | 1901 | file_modified++; |
1876 | return p; | 1902 | return bias; |
1877 | } | 1903 | } |
1878 | 1904 | ||
1879 | // close a hole in text[] | 1905 | // close a hole in text[] |
@@ -2006,21 +2032,28 @@ static void end_cmd_q(void) | |||
2006 | #if ENABLE_FEATURE_VI_YANKMARK \ | 2032 | #if ENABLE_FEATURE_VI_YANKMARK \ |
2007 | || (ENABLE_FEATURE_VI_COLON && ENABLE_FEATURE_VI_SEARCH) \ | 2033 | || (ENABLE_FEATURE_VI_COLON && ENABLE_FEATURE_VI_SEARCH) \ |
2008 | || ENABLE_FEATURE_VI_CRASHME | 2034 | || ENABLE_FEATURE_VI_CRASHME |
2009 | static char *string_insert(char *p, char *s) // insert the string at 'p' | 2035 | // might reallocate text[]! use p += string_insert(p, ...), |
2036 | // and be careful to not use pointers into potentially freed text[]! | ||
2037 | static uintptr_t string_insert(char *p, const char *s) // insert the string at 'p' | ||
2010 | { | 2038 | { |
2011 | int cnt, i; | 2039 | uintptr_t bias; |
2040 | int i; | ||
2012 | 2041 | ||
2013 | i = strlen(s); | 2042 | i = strlen(s); |
2014 | text_hole_make(p, i); | 2043 | bias = text_hole_make(p, i); |
2044 | p += bias; | ||
2015 | strncpy(p, s, i); | 2045 | strncpy(p, s, i); |
2016 | for (cnt = 0; *s != '\0'; s++) { | ||
2017 | if (*s == '\n') | ||
2018 | cnt++; | ||
2019 | } | ||
2020 | #if ENABLE_FEATURE_VI_YANKMARK | 2046 | #if ENABLE_FEATURE_VI_YANKMARK |
2021 | status_line("Put %d lines (%d chars) from [%c]", cnt, i, what_reg()); | 2047 | { |
2048 | int cnt; | ||
2049 | for (cnt = 0; *s != '\0'; s++) { | ||
2050 | if (*s == '\n') | ||
2051 | cnt++; | ||
2052 | } | ||
2053 | status_line("Put %d lines (%d chars) from [%c]", cnt, i, what_reg()); | ||
2054 | } | ||
2022 | #endif | 2055 | #endif |
2023 | return p; | 2056 | return bias; |
2024 | } | 2057 | } |
2025 | #endif | 2058 | #endif |
2026 | 2059 | ||
@@ -2273,8 +2306,8 @@ static int file_size(const char *fn) // what is the byte size of "fn" | |||
2273 | return cnt; | 2306 | return cnt; |
2274 | } | 2307 | } |
2275 | 2308 | ||
2276 | static int file_insert(const char *fn, char *p | 2309 | // might reallocate text[]! |
2277 | USE_FEATURE_VI_READONLY(, int update_ro_status)) | 2310 | static int file_insert(const char *fn, char *p, int update_ro_status) |
2278 | { | 2311 | { |
2279 | int cnt = -1; | 2312 | int cnt = -1; |
2280 | int fd, size; | 2313 | int fd, size; |
@@ -2302,7 +2335,7 @@ static int file_insert(const char *fn, char *p | |||
2302 | goto fi0; | 2335 | goto fi0; |
2303 | } | 2336 | } |
2304 | size = statbuf.st_size; | 2337 | size = statbuf.st_size; |
2305 | p = text_hole_make(p, size); | 2338 | p += text_hole_make(p, size); |
2306 | cnt = safe_read(fd, p, size); | 2339 | cnt = safe_read(fd, p, size); |
2307 | if (cnt < 0) { | 2340 | if (cnt < 0) { |
2308 | status_line_bold("\"%s\" %s", fn, strerror(errno)); | 2341 | status_line_bold("\"%s\" %s", fn, strerror(errno)); |
@@ -3103,7 +3136,7 @@ static void do_cmd(int c) | |||
3103 | if (c == 'p') | 3136 | if (c == 'p') |
3104 | dot_right(); // move to right, can move to NL | 3137 | dot_right(); // move to right, can move to NL |
3105 | } | 3138 | } |
3106 | dot = string_insert(dot, p); // insert the string | 3139 | string_insert(dot, p); // insert the string |
3107 | end_cmd_q(); // stop adding to q | 3140 | end_cmd_q(); // stop adding to q |
3108 | break; | 3141 | break; |
3109 | case 'U': // U- Undo; replace current line with original version | 3142 | case 'U': // U- Undo; replace current line with original version |
@@ -3111,7 +3144,7 @@ static void do_cmd(int c) | |||
3111 | p = begin_line(dot); | 3144 | p = begin_line(dot); |
3112 | q = end_line(dot); | 3145 | q = end_line(dot); |
3113 | p = text_hole_delete(p, q); // delete cur line | 3146 | p = text_hole_delete(p, q); // delete cur line |
3114 | p = string_insert(p, reg[Ureg]); // insert orig line | 3147 | p += string_insert(p, reg[Ureg]); // insert orig line |
3115 | dot = p; | 3148 | dot = p; |
3116 | dot_skip_over_ws(); | 3149 | dot_skip_over_ws(); |
3117 | } | 3150 | } |