Mercurial > vim
comparison src/regexp.c @ 29255:5ebc561444fe v8.2.5146
patch 8.2.5146: memory leak when substitute expression nests
Commit: https://github.com/vim/vim/commit/44ddf19ec0ff59c969658ec7d9ed42070c59c51b
Author: Bram Moolenaar <Bram@vim.org>
Date: Tue Jun 21 22:15:25 2022 +0100
patch 8.2.5146: memory leak when substitute expression nests
Problem: Memory leak when substitute expression nests.
Solution: Use an array of expression results.
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Tue, 21 Jun 2022 23:30:03 +0200 |
parents | b12fd2b3be63 |
children | 8175cd4c8fdd |
comparison
equal
deleted
inserted
replaced
29254:acb7f19c9d07 | 29255:5ebc561444fe |
---|---|
1920 rex = rex_save; | 1920 rex = rex_save; |
1921 | 1921 |
1922 return result; | 1922 return result; |
1923 } | 1923 } |
1924 | 1924 |
1925 #if defined(FEAT_EVAL) || defined(PROTO) | |
1926 // When nesting more than a couple levels it's probably a mistake. | |
1927 # define MAX_REGSUB_NESTING 4 | |
1928 static char_u *eval_result[MAX_REGSUB_NESTING] = {NULL, NULL, NULL, NULL}; | |
1929 | |
1930 # if defined(EXITFREE) || defined(PROTO) | |
1931 void | |
1932 free_resub_eval_result(void) | |
1933 { | |
1934 int i; | |
1935 | |
1936 for (i = 0; i < MAX_REGSUB_NESTING; ++i) | |
1937 VIM_CLEAR(eval_result[i]); | |
1938 } | |
1939 # endif | |
1940 #endif | |
1941 | |
1925 static int | 1942 static int |
1926 vim_regsub_both( | 1943 vim_regsub_both( |
1927 char_u *source, | 1944 char_u *source, |
1928 typval_T *expr, | 1945 typval_T *expr, |
1929 char_u *dest, | 1946 char_u *dest, |
1939 fptr_T func_all = (fptr_T)NULL; | 1956 fptr_T func_all = (fptr_T)NULL; |
1940 fptr_T func_one = (fptr_T)NULL; | 1957 fptr_T func_one = (fptr_T)NULL; |
1941 linenr_T clnum = 0; // init for GCC | 1958 linenr_T clnum = 0; // init for GCC |
1942 int len = 0; // init for GCC | 1959 int len = 0; // init for GCC |
1943 #ifdef FEAT_EVAL | 1960 #ifdef FEAT_EVAL |
1944 static char_u *eval_result = NULL; | 1961 static int nesting = 0; |
1962 int nested; | |
1945 #endif | 1963 #endif |
1946 int copy = flags & REGSUB_COPY; | 1964 int copy = flags & REGSUB_COPY; |
1947 | 1965 |
1948 // Be paranoid... | 1966 // Be paranoid... |
1949 if ((source == NULL && expr == NULL) || dest == NULL) | 1967 if ((source == NULL && expr == NULL) || dest == NULL) |
1951 emsg(_(e_null_argument)); | 1969 emsg(_(e_null_argument)); |
1952 return 0; | 1970 return 0; |
1953 } | 1971 } |
1954 if (prog_magic_wrong()) | 1972 if (prog_magic_wrong()) |
1955 return 0; | 1973 return 0; |
1974 #ifdef FEAT_EVAL | |
1975 if (nesting == MAX_REGSUB_NESTING) | |
1976 { | |
1977 emsg(_(e_substitute_nesting_too_deep)); | |
1978 return 0; | |
1979 } | |
1980 nested = nesting; | |
1981 #endif | |
1956 src = source; | 1982 src = source; |
1957 dst = dest; | 1983 dst = dest; |
1958 | 1984 |
1959 /* | 1985 /* |
1960 * When the substitute part starts with "\=" evaluate it as an expression. | 1986 * When the substitute part starts with "\=" evaluate it as an expression. |
1967 // resulting string is saved from the call with | 1993 // resulting string is saved from the call with |
1968 // "flags & REGSUB_COPY" == 0 to the call with | 1994 // "flags & REGSUB_COPY" == 0 to the call with |
1969 // "flags & REGSUB_COPY" != 0. | 1995 // "flags & REGSUB_COPY" != 0. |
1970 if (copy) | 1996 if (copy) |
1971 { | 1997 { |
1972 if (eval_result != NULL) | 1998 if (eval_result[nested] != NULL) |
1973 { | 1999 { |
1974 STRCPY(dest, eval_result); | 2000 STRCPY(dest, eval_result[nested]); |
1975 dst += STRLEN(eval_result); | 2001 dst += STRLEN(eval_result[nested]); |
1976 VIM_CLEAR(eval_result); | 2002 VIM_CLEAR(eval_result[nested]); |
1977 } | 2003 } |
1978 } | 2004 } |
1979 else | 2005 else |
1980 { | 2006 { |
1981 int prev_can_f_submatch = can_f_submatch; | 2007 int prev_can_f_submatch = can_f_submatch; |
1982 regsubmatch_T rsm_save; | 2008 regsubmatch_T rsm_save; |
1983 | 2009 |
1984 VIM_CLEAR(eval_result); | 2010 VIM_CLEAR(eval_result[nested]); |
1985 | 2011 |
1986 // The expression may contain substitute(), which calls us | 2012 // The expression may contain substitute(), which calls us |
1987 // recursively. Make sure submatch() gets the text from the first | 2013 // recursively. Make sure submatch() gets the text from the first |
1988 // level. | 2014 // level. |
1989 if (can_f_submatch) | 2015 if (can_f_submatch) |
1992 rsm.sm_match = rex.reg_match; | 2018 rsm.sm_match = rex.reg_match; |
1993 rsm.sm_mmatch = rex.reg_mmatch; | 2019 rsm.sm_mmatch = rex.reg_mmatch; |
1994 rsm.sm_firstlnum = rex.reg_firstlnum; | 2020 rsm.sm_firstlnum = rex.reg_firstlnum; |
1995 rsm.sm_maxline = rex.reg_maxline; | 2021 rsm.sm_maxline = rex.reg_maxline; |
1996 rsm.sm_line_lbr = rex.reg_line_lbr; | 2022 rsm.sm_line_lbr = rex.reg_line_lbr; |
2023 | |
2024 // Although unlikely, it is possible that the expression invokes a | |
2025 // substitute command (it might fail, but still). Therefore keep | |
2026 // an array if eval results. | |
2027 ++nesting; | |
1997 | 2028 |
1998 if (expr != NULL) | 2029 if (expr != NULL) |
1999 { | 2030 { |
2000 typval_T argv[2]; | 2031 typval_T argv[2]; |
2001 char_u buf[NUMBUFLEN]; | 2032 char_u buf[NUMBUFLEN]; |
2032 // fill_submatch_list() was called | 2063 // fill_submatch_list() was called |
2033 clear_submatch_list(&matchList); | 2064 clear_submatch_list(&matchList); |
2034 | 2065 |
2035 if (rettv.v_type == VAR_UNKNOWN) | 2066 if (rettv.v_type == VAR_UNKNOWN) |
2036 // something failed, no need to report another error | 2067 // something failed, no need to report another error |
2037 eval_result = NULL; | 2068 eval_result[nested] = NULL; |
2038 else | 2069 else |
2039 { | 2070 { |
2040 eval_result = tv_get_string_buf_chk(&rettv, buf); | 2071 eval_result[nested] = tv_get_string_buf_chk(&rettv, buf); |
2041 if (eval_result != NULL) | 2072 if (eval_result[nested] != NULL) |
2042 eval_result = vim_strsave(eval_result); | 2073 eval_result[nested] = vim_strsave(eval_result[nested]); |
2043 } | 2074 } |
2044 clear_tv(&rettv); | 2075 clear_tv(&rettv); |
2045 } | 2076 } |
2046 else if (substitute_instr != NULL) | 2077 else if (substitute_instr != NULL) |
2047 // Execute instructions from ISN_SUBSTITUTE. | 2078 // Execute instructions from ISN_SUBSTITUTE. |
2048 eval_result = exe_substitute_instr(); | 2079 eval_result[nested] = exe_substitute_instr(); |
2049 else | 2080 else |
2050 eval_result = eval_to_string(source + 2, TRUE); | 2081 eval_result[nested] = eval_to_string(source + 2, TRUE); |
2051 | 2082 --nesting; |
2052 if (eval_result != NULL) | 2083 |
2084 if (eval_result[nested] != NULL) | |
2053 { | 2085 { |
2054 int had_backslash = FALSE; | 2086 int had_backslash = FALSE; |
2055 | 2087 |
2056 for (s = eval_result; *s != NUL; MB_PTR_ADV(s)) | 2088 for (s = eval_result[nested]; *s != NUL; MB_PTR_ADV(s)) |
2057 { | 2089 { |
2058 // Change NL to CR, so that it becomes a line break, | 2090 // Change NL to CR, so that it becomes a line break, |
2059 // unless called from vim_regexec_nl(). | 2091 // unless called from vim_regexec_nl(). |
2060 // Skip over a backslashed character. | 2092 // Skip over a backslashed character. |
2061 if (*s == NL && !rsm.sm_line_lbr) | 2093 if (*s == NL && !rsm.sm_line_lbr) |
2075 } | 2107 } |
2076 } | 2108 } |
2077 if (had_backslash && (flags & REGSUB_BACKSLASH)) | 2109 if (had_backslash && (flags & REGSUB_BACKSLASH)) |
2078 { | 2110 { |
2079 // Backslashes will be consumed, need to double them. | 2111 // Backslashes will be consumed, need to double them. |
2080 s = vim_strsave_escaped(eval_result, (char_u *)"\\"); | 2112 s = vim_strsave_escaped(eval_result[nested], (char_u *)"\\"); |
2081 if (s != NULL) | 2113 if (s != NULL) |
2082 { | 2114 { |
2083 vim_free(eval_result); | 2115 vim_free(eval_result[nested]); |
2084 eval_result = s; | 2116 eval_result[nested] = s; |
2085 } | 2117 } |
2086 } | 2118 } |
2087 | 2119 |
2088 dst += STRLEN(eval_result); | 2120 dst += STRLEN(eval_result[nested]); |
2089 } | 2121 } |
2090 | 2122 |
2091 can_f_submatch = prev_can_f_submatch; | 2123 can_f_submatch = prev_can_f_submatch; |
2092 if (can_f_submatch) | 2124 if (can_f_submatch) |
2093 rsm = rsm_save; | 2125 rsm = rsm_save; |