diff options
| author | Eli Zaretskii | 2016-08-31 18:53:43 +0300 |
|---|---|---|
| committer | Eli Zaretskii | 2016-08-31 18:53:43 +0300 |
| commit | 6d8144a2abb1c37982d82e32c68ab5115aca792c (patch) | |
| tree | 9d189fb7c61a358e06f754b3377cb895d8ea991f /lib-src | |
| parent | 6f125aa3de06fa0180a83ec7b5a26970309eeeb6 (diff) | |
| download | emacs-6d8144a2abb1c37982d82e32c68ab5115aca792c.tar.gz emacs-6d8144a2abb1c37982d82e32c68ab5115aca792c.zip | |
Avoid recursive calls in etags
* lib-src/etags.c (stack_entry): New struct.
(push_node, pop_node, put_entry): New functions.
(free_tree, add_node, invalidate_nodes, put_entries): Re-implement
in a non-recursive way, to avoid stack overflow. (Bug#5847)
Diffstat (limited to 'lib-src')
| -rw-r--r-- | lib-src/etags.c | 290 |
1 files changed, 226 insertions, 64 deletions
diff --git a/lib-src/etags.c b/lib-src/etags.c index 1c85a792896..95553e9c42a 100644 --- a/lib-src/etags.c +++ b/lib-src/etags.c | |||
| @@ -2006,19 +2006,80 @@ pfnote (char *name, bool is_func, char *linestart, int linelen, int lno, | |||
| 2006 | } | 2006 | } |
| 2007 | 2007 | ||
| 2008 | /* | 2008 | /* |
| 2009 | * Utility functions and data to avoid recursion. | ||
| 2010 | */ | ||
| 2011 | |||
| 2012 | typedef struct stack_entry { | ||
| 2013 | node *np; | ||
| 2014 | struct stack_entry *next; | ||
| 2015 | } stkentry; | ||
| 2016 | |||
| 2017 | static void | ||
| 2018 | push_node (node *np, stkentry **stack_top) | ||
| 2019 | { | ||
| 2020 | if (np) | ||
| 2021 | { | ||
| 2022 | stkentry *new = xnew (1, stkentry); | ||
| 2023 | |||
| 2024 | new->np = np; | ||
| 2025 | new->next = *stack_top; | ||
| 2026 | *stack_top = new; | ||
| 2027 | } | ||
| 2028 | } | ||
| 2029 | |||
| 2030 | static node * | ||
| 2031 | pop_node (stkentry **stack_top) | ||
| 2032 | { | ||
| 2033 | node *ret = NULL; | ||
| 2034 | |||
| 2035 | if (*stack_top) | ||
| 2036 | { | ||
| 2037 | stkentry *old_start = *stack_top; | ||
| 2038 | |||
| 2039 | ret = (*stack_top)->np; | ||
| 2040 | *stack_top = (*stack_top)->next; | ||
| 2041 | free (old_start); | ||
| 2042 | } | ||
| 2043 | return ret; | ||
| 2044 | } | ||
| 2045 | |||
| 2046 | /* | ||
| 2009 | * free_tree () | 2047 | * free_tree () |
| 2010 | * recurse on left children, iterate on right children. | 2048 | * emulate recursion on left children, iterate on right children. |
| 2011 | */ | 2049 | */ |
| 2012 | static void | 2050 | static void |
| 2013 | free_tree (register node *np) | 2051 | free_tree (register node *np) |
| 2014 | { | 2052 | { |
| 2053 | stkentry *stack = NULL; | ||
| 2054 | |||
| 2015 | while (np) | 2055 | while (np) |
| 2016 | { | 2056 | { |
| 2017 | register node *node_right = np->right; | 2057 | register node *node_right; |
| 2018 | free_tree (np->left); | 2058 | |
| 2059 | /* Descent on left children. */ | ||
| 2060 | while (np->left) | ||
| 2061 | { | ||
| 2062 | push_node (np, &stack); | ||
| 2063 | np = np->left; | ||
| 2064 | } | ||
| 2065 | /* Free node without left children. */ | ||
| 2066 | node_right = np->right; | ||
| 2019 | free (np->name); | 2067 | free (np->name); |
| 2020 | free (np->regex); | 2068 | free (np->regex); |
| 2021 | free (np); | 2069 | free (np); |
| 2070 | if (!node_right) | ||
| 2071 | { | ||
| 2072 | /* Backtrack to find a node with right children, while freeing nodes | ||
| 2073 | that don't have right children. */ | ||
| 2074 | while (node_right == NULL && (np = pop_node (&stack)) != NULL) | ||
| 2075 | { | ||
| 2076 | node_right = np->right; | ||
| 2077 | free (np->name); | ||
| 2078 | free (np->regex); | ||
| 2079 | free (np); | ||
| 2080 | } | ||
| 2081 | } | ||
| 2082 | /* Free right children. */ | ||
| 2022 | np = node_right; | 2083 | np = node_right; |
| 2023 | } | 2084 | } |
| 2024 | } | 2085 | } |
| @@ -2050,9 +2111,9 @@ free_fdesc (register fdesc *fdp) | |||
| 2050 | static void | 2111 | static void |
| 2051 | add_node (node *np, node **cur_node_p) | 2112 | add_node (node *np, node **cur_node_p) |
| 2052 | { | 2113 | { |
| 2053 | register int dif; | 2114 | node *cur_node = *cur_node_p; |
| 2054 | register node *cur_node = *cur_node_p; | ||
| 2055 | 2115 | ||
| 2116 | /* Make the first node. */ | ||
| 2056 | if (cur_node == NULL) | 2117 | if (cur_node == NULL) |
| 2057 | { | 2118 | { |
| 2058 | *cur_node_p = np; | 2119 | *cur_node_p = np; |
| @@ -2074,51 +2135,77 @@ add_node (node *np, node **cur_node_p) | |||
| 2074 | last_node->right = np; | 2135 | last_node->right = np; |
| 2075 | last_node = np; | 2136 | last_node = np; |
| 2076 | } | 2137 | } |
| 2077 | else if (cur_node->fdp == np->fdp) | 2138 | else |
| 2078 | { | 2139 | { |
| 2079 | /* Scanning the list we found the head of a sublist which is | 2140 | while (cur_node->fdp != np->fdp) |
| 2080 | good for us. Let's scan this sublist. */ | 2141 | { |
| 2081 | add_node (np, &cur_node->right); | 2142 | if (cur_node->left == NULL) |
| 2143 | break; | ||
| 2144 | /* The head of this sublist is not good for us. Let's try the | ||
| 2145 | next one. */ | ||
| 2146 | cur_node = cur_node->left; | ||
| 2147 | } | ||
| 2148 | if (cur_node->left) | ||
| 2149 | { | ||
| 2150 | /* Scanning the list we found the head of a sublist which is | ||
| 2151 | good for us. Let's scan this sublist. */ | ||
| 2152 | if (cur_node->right) | ||
| 2153 | { | ||
| 2154 | cur_node = cur_node->right; | ||
| 2155 | while (cur_node->right) | ||
| 2156 | cur_node = cur_node->right; | ||
| 2157 | } | ||
| 2158 | /* Make a new node in this sublist. */ | ||
| 2159 | cur_node->right = np; | ||
| 2160 | } | ||
| 2161 | else | ||
| 2162 | { | ||
| 2163 | /* Make a new sublist. */ | ||
| 2164 | cur_node->left = np; | ||
| 2165 | } | ||
| 2166 | last_node = np; | ||
| 2082 | } | 2167 | } |
| 2083 | else | ||
| 2084 | /* The head of this sublist is not good for us. Let's try the | ||
| 2085 | next one. */ | ||
| 2086 | add_node (np, &cur_node->left); | ||
| 2087 | } /* if ETAGS mode */ | 2168 | } /* if ETAGS mode */ |
| 2088 | |||
| 2089 | else | 2169 | else |
| 2090 | { | 2170 | { |
| 2091 | /* Ctags Mode */ | 2171 | /* Ctags Mode */ |
| 2092 | dif = strcmp (np->name, cur_node->name); | 2172 | register int dif; |
| 2173 | node **next_node = &cur_node; | ||
| 2093 | 2174 | ||
| 2094 | /* | 2175 | while ((cur_node = *next_node) != NULL) |
| 2095 | * If this tag name matches an existing one, then | ||
| 2096 | * do not add the node, but maybe print a warning. | ||
| 2097 | */ | ||
| 2098 | if (no_duplicates && !dif) | ||
| 2099 | { | 2176 | { |
| 2100 | if (np->fdp == cur_node->fdp) | 2177 | dif = strcmp (np->name, cur_node->name); |
| 2178 | /* | ||
| 2179 | * If this tag name matches an existing one, then | ||
| 2180 | * do not add the node, but maybe print a warning. | ||
| 2181 | */ | ||
| 2182 | if (!dif && no_duplicates) | ||
| 2101 | { | 2183 | { |
| 2102 | if (!no_warnings) | 2184 | if (np->fdp == cur_node->fdp) |
| 2103 | { | 2185 | { |
| 2104 | fprintf (stderr, "Duplicate entry in file %s, line %d: %s\n", | 2186 | if (!no_warnings) |
| 2105 | np->fdp->infname, lineno, np->name); | 2187 | { |
| 2106 | fprintf (stderr, "Second entry ignored\n"); | 2188 | fprintf (stderr, |
| 2189 | "Duplicate entry in file %s, line %d: %s\n", | ||
| 2190 | np->fdp->infname, lineno, np->name); | ||
| 2191 | fprintf (stderr, "Second entry ignored\n"); | ||
| 2192 | } | ||
| 2107 | } | 2193 | } |
| 2194 | else if (!cur_node->been_warned && !no_warnings) | ||
| 2195 | { | ||
| 2196 | fprintf | ||
| 2197 | (stderr, | ||
| 2198 | "Duplicate entry in files %s and %s: %s (Warning only)\n", | ||
| 2199 | np->fdp->infname, cur_node->fdp->infname, np->name); | ||
| 2200 | cur_node->been_warned = true; | ||
| 2201 | } | ||
| 2202 | return; | ||
| 2108 | } | 2203 | } |
| 2109 | else if (!cur_node->been_warned && !no_warnings) | 2204 | else |
| 2110 | { | 2205 | next_node = dif < 0 ? &cur_node->left : &cur_node->right; |
| 2111 | fprintf | ||
| 2112 | (stderr, | ||
| 2113 | "Duplicate entry in files %s and %s: %s (Warning only)\n", | ||
| 2114 | np->fdp->infname, cur_node->fdp->infname, np->name); | ||
| 2115 | cur_node->been_warned = true; | ||
| 2116 | } | ||
| 2117 | return; | ||
| 2118 | } | 2206 | } |
| 2119 | 2207 | *next_node = np; | |
| 2120 | /* Actually add the node */ | 2208 | last_node = np; |
| 2121 | add_node (np, dif < 0 ? &cur_node->left : &cur_node->right); | ||
| 2122 | } /* if CTAGS mode */ | 2209 | } /* if CTAGS mode */ |
| 2123 | } | 2210 | } |
| 2124 | 2211 | ||
| @@ -2131,31 +2218,65 @@ static void | |||
| 2131 | invalidate_nodes (fdesc *badfdp, node **npp) | 2218 | invalidate_nodes (fdesc *badfdp, node **npp) |
| 2132 | { | 2219 | { |
| 2133 | node *np = *npp; | 2220 | node *np = *npp; |
| 2221 | stkentry *stack = NULL; | ||
| 2134 | 2222 | ||
| 2135 | if (np == NULL) | 2223 | if (np == NULL) |
| 2136 | return; | 2224 | return; |
| 2137 | 2225 | ||
| 2138 | if (CTAGS) | 2226 | if (CTAGS) |
| 2139 | { | 2227 | { |
| 2140 | if (np->left != NULL) | 2228 | while (np) |
| 2141 | invalidate_nodes (badfdp, &np->left); | 2229 | { |
| 2142 | if (np->fdp == badfdp) | 2230 | /* Push all the left children on the stack. */ |
| 2143 | np->valid = false; | 2231 | while (np->left != NULL) |
| 2144 | if (np->right != NULL) | 2232 | { |
| 2145 | invalidate_nodes (badfdp, &np->right); | 2233 | push_node (np->left, &stack); |
| 2234 | np = np->left; | ||
| 2235 | } | ||
| 2236 | /* Invalidate this node. */ | ||
| 2237 | if (np->fdp == badfdp) | ||
| 2238 | np->valid = false; | ||
| 2239 | if (!np->right) | ||
| 2240 | { | ||
| 2241 | /* Pop nodes from stack, invalidating them, until we find one | ||
| 2242 | with a right child. */ | ||
| 2243 | do { | ||
| 2244 | np = pop_node (&stack); | ||
| 2245 | if (np->fdp == badfdp) | ||
| 2246 | np->valid = false; | ||
| 2247 | } while (np && np->right == NULL); | ||
| 2248 | } | ||
| 2249 | /* Process the right child, if any. */ | ||
| 2250 | if (np) | ||
| 2251 | np = np->right; | ||
| 2252 | } | ||
| 2146 | } | 2253 | } |
| 2147 | else | 2254 | else |
| 2148 | { | 2255 | { |
| 2149 | assert (np->fdp != NULL); | 2256 | node super_root, *np_parent; |
| 2150 | if (np->fdp == badfdp) | 2257 | |
| 2258 | super_root.left = np; | ||
| 2259 | super_root.fdp = (fdesc *)-1; | ||
| 2260 | np = &super_root; | ||
| 2261 | |||
| 2262 | while (np) | ||
| 2151 | { | 2263 | { |
| 2152 | *npp = np->left; /* detach the sublist from the list */ | 2264 | /* Descent on left children until node with BADFP. */ |
| 2153 | np->left = NULL; /* isolate it */ | 2265 | while (np && np->fdp != badfdp) |
| 2154 | free_tree (np); /* free it */ | 2266 | { |
| 2155 | invalidate_nodes (badfdp, npp); | 2267 | assert (np->fdp != NULL); |
| 2268 | np_parent = np; | ||
| 2269 | np = np->left; | ||
| 2270 | } | ||
| 2271 | if (np) | ||
| 2272 | { | ||
| 2273 | np_parent->left = np->left; /* detach subtree from the tree */ | ||
| 2274 | np->left = NULL; /* isolate it */ | ||
| 2275 | free_tree (np); /* free it */ | ||
| 2276 | np = np_parent->left; /* continue with rest of tree */ | ||
| 2277 | } | ||
| 2156 | } | 2278 | } |
| 2157 | else | 2279 | *npp = super_root.left; |
| 2158 | invalidate_nodes (badfdp, &np->left); | ||
| 2159 | } | 2280 | } |
| 2160 | } | 2281 | } |
| 2161 | 2282 | ||
| @@ -2200,20 +2321,13 @@ total_size_of_entries (register node *np) | |||
| 2200 | } | 2321 | } |
| 2201 | 2322 | ||
| 2202 | static void | 2323 | static void |
| 2203 | put_entries (register node *np) | 2324 | put_entry (register node *np) |
| 2204 | { | 2325 | { |
| 2205 | register char *sp; | 2326 | register char *sp; |
| 2206 | static fdesc *fdp = NULL; | 2327 | static fdesc *fdp = NULL; |
| 2207 | 2328 | ||
| 2208 | if (np == NULL) | ||
| 2209 | return; | ||
| 2210 | |||
| 2211 | /* Output subentries that precede this one */ | ||
| 2212 | if (CTAGS) | ||
| 2213 | put_entries (np->left); | ||
| 2214 | |||
| 2215 | /* Output this entry */ | 2329 | /* Output this entry */ |
| 2216 | if (np->valid) | 2330 | if (np && np->valid) |
| 2217 | { | 2331 | { |
| 2218 | if (!CTAGS) | 2332 | if (!CTAGS) |
| 2219 | { | 2333 | { |
| @@ -2277,11 +2391,59 @@ put_entries (register node *np) | |||
| 2277 | } | 2391 | } |
| 2278 | } | 2392 | } |
| 2279 | } /* if this node contains a valid tag */ | 2393 | } /* if this node contains a valid tag */ |
| 2394 | } | ||
| 2280 | 2395 | ||
| 2281 | /* Output subentries that follow this one */ | 2396 | static void |
| 2282 | put_entries (np->right); | 2397 | put_entries (register node *np) |
| 2283 | if (!CTAGS) | 2398 | { |
| 2284 | put_entries (np->left); | 2399 | stkentry *stack = NULL; |
| 2400 | |||
| 2401 | if (np == NULL) | ||
| 2402 | return; | ||
| 2403 | |||
| 2404 | if (CTAGS) | ||
| 2405 | { | ||
| 2406 | while (np) | ||
| 2407 | { | ||
| 2408 | /* Stack subentries that precede this one. */ | ||
| 2409 | while (np->left) | ||
| 2410 | { | ||
| 2411 | push_node (np, &stack); | ||
| 2412 | np = np->left; | ||
| 2413 | } | ||
| 2414 | /* Output this subentry. */ | ||
| 2415 | put_entry (np); | ||
| 2416 | /* Stack subentries that follow this one. */ | ||
| 2417 | if (!np->right) | ||
| 2418 | { | ||
| 2419 | /* Output subentries that precede the next one. */ | ||
| 2420 | do { | ||
| 2421 | np = pop_node (&stack); | ||
| 2422 | put_entry (np); | ||
| 2423 | } while (np && np->right == NULL); | ||
| 2424 | } | ||
| 2425 | if (np) | ||
| 2426 | np = np->right; | ||
| 2427 | } | ||
| 2428 | } | ||
| 2429 | else | ||
| 2430 | { | ||
| 2431 | push_node (np, &stack); | ||
| 2432 | while ((np = pop_node (&stack)) != NULL) | ||
| 2433 | { | ||
| 2434 | /* Output this subentry. */ | ||
| 2435 | put_entry (np); | ||
| 2436 | while (np->right) | ||
| 2437 | { | ||
| 2438 | /* Output subentries that follow this one. */ | ||
| 2439 | put_entry (np->right); | ||
| 2440 | /* Stack subentries from the following files. */ | ||
| 2441 | push_node (np->left, &stack); | ||
| 2442 | np = np->right; | ||
| 2443 | } | ||
| 2444 | push_node (np->left, &stack); | ||
| 2445 | } | ||
| 2446 | } | ||
| 2285 | } | 2447 | } |
| 2286 | 2448 | ||
| 2287 | 2449 | ||