diff options
| author | Paul Eggert | 2017-07-09 16:04:02 -0700 |
|---|---|---|
| committer | Paul Eggert | 2017-07-09 16:05:13 -0700 |
| commit | 083940a93df17c6e50d6523e30d56ca3d179f688 (patch) | |
| tree | 7192d741b6d66943c4f4fd38436aaf8960e6299a /src/intervals.c | |
| parent | ce6773aad5c71f6c486244a6fc9fcb69fc99784d (diff) | |
| download | emacs-083940a93df17c6e50d6523e30d56ca3d179f688.tar.gz emacs-083940a93df17c6e50d6523e30d56ca3d179f688.zip | |
Fix core dump in substitute-object-in-subtree
Without this fix, (substitute-object-in-subtree #0=(#0# 'a) 'a)
would dump core, since the C code would recurse indefinitely through
the infinite structure. This patch adds an argument to the function,
and renames it to lread--substitute-object-in-subtree as the function
is not general-purpose and should not be relied on by outside code.
See Bug#23660.
* src/intervals.c (traverse_intervals_noorder): ARG is now void *,
not Lisp_Object, so that callers need not cons unnecessarily.
All callers changed. Also, remove related #if-0 code that was
“temporary” in the early 1990s and has not been compilable for
some time.
* src/lread.c (struct subst): New type, for substitution closure data.
(seen_list): Remove this static var, as this info is now part of
struct subst. All uses removed.
(Flread__substitute_object_in_subtree): Rename from
Fsubstitute_object_in_subtree, and give it a 3rd arg so that it
doesn’t dump core when called from the top level with an
already-cyclic structure. All callers changed.
(SUBSTITUTE): Remove. All callers expanded and then simplified.
(substitute_object_recurse): Take a single argument SUBST rather
than a pair OBJECT and PLACEHOLDER, so that its address can be
passed around as part of a closure; this avoids the need for an
AUTO_CONS call. All callers changed. If the COMPLETED component
is t, treat every subobject as potentially circular.
(substitute_in_interval): Take a struct subst * rather than a
Lisp_Object, for the closure data. All callers changed.
* test/src/lread-tests.el (lread-lread--substitute-object-in-subtree):
New test, to check that the core dump does not reoccur.
Diffstat (limited to 'src/intervals.c')
| -rw-r--r-- | src/intervals.c | 66 |
1 files changed, 2 insertions, 64 deletions
diff --git a/src/intervals.c b/src/intervals.c index d17d80ac865..0089ecb8dde 100644 --- a/src/intervals.c +++ b/src/intervals.c | |||
| @@ -224,7 +224,8 @@ intervals_equal (INTERVAL i0, INTERVAL i1) | |||
| 224 | Pass FUNCTION two args: an interval, and ARG. */ | 224 | Pass FUNCTION two args: an interval, and ARG. */ |
| 225 | 225 | ||
| 226 | void | 226 | void |
| 227 | traverse_intervals_noorder (INTERVAL tree, void (*function) (INTERVAL, Lisp_Object), Lisp_Object arg) | 227 | traverse_intervals_noorder (INTERVAL tree, void (*function) (INTERVAL, void *), |
| 228 | void *arg) | ||
| 228 | { | 229 | { |
| 229 | /* Minimize stack usage. */ | 230 | /* Minimize stack usage. */ |
| 230 | while (tree) | 231 | while (tree) |
| @@ -257,69 +258,6 @@ traverse_intervals (INTERVAL tree, ptrdiff_t position, | |||
| 257 | } | 258 | } |
| 258 | } | 259 | } |
| 259 | 260 | ||
| 260 | #if 0 | ||
| 261 | |||
| 262 | static int icount; | ||
| 263 | static int idepth; | ||
| 264 | static int zero_length; | ||
| 265 | |||
| 266 | /* These functions are temporary, for debugging purposes only. */ | ||
| 267 | |||
| 268 | INTERVAL search_interval, found_interval; | ||
| 269 | |||
| 270 | void | ||
| 271 | check_for_interval (INTERVAL i) | ||
| 272 | { | ||
| 273 | if (i == search_interval) | ||
| 274 | { | ||
| 275 | found_interval = i; | ||
| 276 | icount++; | ||
| 277 | } | ||
| 278 | } | ||
| 279 | |||
| 280 | INTERVAL | ||
| 281 | search_for_interval (INTERVAL i, INTERVAL tree) | ||
| 282 | { | ||
| 283 | icount = 0; | ||
| 284 | search_interval = i; | ||
| 285 | found_interval = NULL; | ||
| 286 | traverse_intervals_noorder (tree, &check_for_interval, Qnil); | ||
| 287 | return found_interval; | ||
| 288 | } | ||
| 289 | |||
| 290 | static void | ||
| 291 | inc_interval_count (INTERVAL i) | ||
| 292 | { | ||
| 293 | icount++; | ||
| 294 | if (LENGTH (i) == 0) | ||
| 295 | zero_length++; | ||
| 296 | if (depth > idepth) | ||
| 297 | idepth = depth; | ||
| 298 | } | ||
| 299 | |||
| 300 | int | ||
| 301 | count_intervals (INTERVAL i) | ||
| 302 | { | ||
| 303 | icount = 0; | ||
| 304 | idepth = 0; | ||
| 305 | zero_length = 0; | ||
| 306 | traverse_intervals_noorder (i, &inc_interval_count, Qnil); | ||
| 307 | |||
| 308 | return icount; | ||
| 309 | } | ||
| 310 | |||
| 311 | static INTERVAL | ||
| 312 | root_interval (INTERVAL interval) | ||
| 313 | { | ||
| 314 | register INTERVAL i = interval; | ||
| 315 | |||
| 316 | while (! ROOT_INTERVAL_P (i)) | ||
| 317 | i = INTERVAL_PARENT (i); | ||
| 318 | |||
| 319 | return i; | ||
| 320 | } | ||
| 321 | #endif | ||
| 322 | |||
| 323 | /* Assuming that a left child exists, perform the following operation: | 261 | /* Assuming that a left child exists, perform the following operation: |
| 324 | 262 | ||
| 325 | A B | 263 | A B |