aboutsummaryrefslogtreecommitdiffstats
path: root/lib-src
diff options
context:
space:
mode:
authorEli Zaretskii2016-08-31 18:53:43 +0300
committerEli Zaretskii2016-08-31 18:53:43 +0300
commit6d8144a2abb1c37982d82e32c68ab5115aca792c (patch)
tree9d189fb7c61a358e06f754b3377cb895d8ea991f /lib-src
parent6f125aa3de06fa0180a83ec7b5a26970309eeeb6 (diff)
downloademacs-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.c290
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
2012typedef struct stack_entry {
2013 node *np;
2014 struct stack_entry *next;
2015} stkentry;
2016
2017static void
2018push_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
2030static node *
2031pop_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 */
2012static void 2050static void
2013free_tree (register node *np) 2051free_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)
2050static void 2111static void
2051add_node (node *np, node **cur_node_p) 2112add_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
2131invalidate_nodes (fdesc *badfdp, node **npp) 2218invalidate_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
2202static void 2323static void
2203put_entries (register node *np) 2324put_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 */ 2396static void
2282 put_entries (np->right); 2397put_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