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 | |
| 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')
| -rw-r--r-- | src/alloc.c | 4 | ||||
| -rw-r--r-- | src/intervals.c | 66 | ||||
| -rw-r--r-- | src/intervals.h | 3 | ||||
| -rw-r--r-- | src/lread.c | 110 | ||||
| -rw-r--r-- | src/print.c | 6 |
5 files changed, 53 insertions, 136 deletions
diff --git a/src/alloc.c b/src/alloc.c index ac3de83b2b6..2d785d5b9a4 100644 --- a/src/alloc.c +++ b/src/alloc.c | |||
| @@ -1553,7 +1553,7 @@ make_interval (void) | |||
| 1553 | /* Mark Lisp objects in interval I. */ | 1553 | /* Mark Lisp objects in interval I. */ |
| 1554 | 1554 | ||
| 1555 | static void | 1555 | static void |
| 1556 | mark_interval (register INTERVAL i, Lisp_Object dummy) | 1556 | mark_interval (INTERVAL i, void *dummy) |
| 1557 | { | 1557 | { |
| 1558 | /* Intervals should never be shared. So, if extra internal checking is | 1558 | /* Intervals should never be shared. So, if extra internal checking is |
| 1559 | enabled, GC aborts if it seems to have visited an interval twice. */ | 1559 | enabled, GC aborts if it seems to have visited an interval twice. */ |
| @@ -1567,7 +1567,7 @@ mark_interval (register INTERVAL i, Lisp_Object dummy) | |||
| 1567 | #define MARK_INTERVAL_TREE(i) \ | 1567 | #define MARK_INTERVAL_TREE(i) \ |
| 1568 | do { \ | 1568 | do { \ |
| 1569 | if (i && !i->gcmarkbit) \ | 1569 | if (i && !i->gcmarkbit) \ |
| 1570 | traverse_intervals_noorder (i, mark_interval, Qnil); \ | 1570 | traverse_intervals_noorder (i, mark_interval, NULL); \ |
| 1571 | } while (0) | 1571 | } while (0) |
| 1572 | 1572 | ||
| 1573 | /*********************************************************************** | 1573 | /*********************************************************************** |
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 |
diff --git a/src/intervals.h b/src/intervals.h index a0da6f37801..9140e0c17ab 100644 --- a/src/intervals.h +++ b/src/intervals.h | |||
| @@ -242,8 +242,7 @@ extern void traverse_intervals (INTERVAL, ptrdiff_t, | |||
| 242 | void (*) (INTERVAL, Lisp_Object), | 242 | void (*) (INTERVAL, Lisp_Object), |
| 243 | Lisp_Object); | 243 | Lisp_Object); |
| 244 | extern void traverse_intervals_noorder (INTERVAL, | 244 | extern void traverse_intervals_noorder (INTERVAL, |
| 245 | void (*) (INTERVAL, Lisp_Object), | 245 | void (*) (INTERVAL, void *), void *); |
| 246 | Lisp_Object); | ||
| 247 | extern INTERVAL split_interval_right (INTERVAL, ptrdiff_t); | 246 | extern INTERVAL split_interval_right (INTERVAL, ptrdiff_t); |
| 248 | extern INTERVAL split_interval_left (INTERVAL, ptrdiff_t); | 247 | extern INTERVAL split_interval_left (INTERVAL, ptrdiff_t); |
| 249 | extern INTERVAL find_interval (INTERVAL, ptrdiff_t); | 248 | extern INTERVAL find_interval (INTERVAL, ptrdiff_t); |
diff --git a/src/lread.c b/src/lread.c index 8e7cd3c5510..4d1a27d1c1d 100644 --- a/src/lread.c +++ b/src/lread.c | |||
| @@ -595,6 +595,20 @@ read_emacs_mule_char (int c, int (*readbyte) (int, Lisp_Object), Lisp_Object rea | |||
| 595 | } | 595 | } |
| 596 | 596 | ||
| 597 | 597 | ||
| 598 | /* An in-progress substitution of OBJECT for PLACEHOLDER. */ | ||
| 599 | struct subst | ||
| 600 | { | ||
| 601 | Lisp_Object object; | ||
| 602 | Lisp_Object placeholder; | ||
| 603 | |||
| 604 | /* Hash table of subobjects of OBJECT that might be circular. If | ||
| 605 | Qt, all such objects might be circular. */ | ||
| 606 | Lisp_Object completed; | ||
| 607 | |||
| 608 | /* List of subobjects of OBJECT that have already been visited. */ | ||
| 609 | Lisp_Object seen; | ||
| 610 | }; | ||
| 611 | |||
| 598 | static Lisp_Object read_internal_start (Lisp_Object, Lisp_Object, | 612 | static Lisp_Object read_internal_start (Lisp_Object, Lisp_Object, |
| 599 | Lisp_Object); | 613 | Lisp_Object); |
| 600 | static Lisp_Object read0 (Lisp_Object); | 614 | static Lisp_Object read0 (Lisp_Object); |
| @@ -603,9 +617,8 @@ static Lisp_Object read1 (Lisp_Object, int *, bool); | |||
| 603 | static Lisp_Object read_list (bool, Lisp_Object); | 617 | static Lisp_Object read_list (bool, Lisp_Object); |
| 604 | static Lisp_Object read_vector (Lisp_Object, bool); | 618 | static Lisp_Object read_vector (Lisp_Object, bool); |
| 605 | 619 | ||
| 606 | static Lisp_Object substitute_object_recurse (Lisp_Object, Lisp_Object, | 620 | static Lisp_Object substitute_object_recurse (struct subst *, Lisp_Object); |
| 607 | Lisp_Object); | 621 | static void substitute_in_interval (INTERVAL, void *); |
| 608 | static void substitute_in_interval (INTERVAL, Lisp_Object); | ||
| 609 | 622 | ||
| 610 | 623 | ||
| 611 | /* Get a character from the tty. */ | 624 | /* Get a character from the tty. */ |
| @@ -3107,7 +3120,8 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list) | |||
| 3107 | } | 3120 | } |
| 3108 | else | 3121 | else |
| 3109 | { | 3122 | { |
| 3110 | Fsubstitute_object_in_subtree (tem, placeholder); | 3123 | Flread__substitute_object_in_subtree |
| 3124 | (tem, placeholder, read_objects_completed); | ||
| 3111 | 3125 | ||
| 3112 | /* ...and #n# will use the real value from now on. */ | 3126 | /* ...and #n# will use the real value from now on. */ |
| 3113 | i = hash_lookup (h, number, &hash); | 3127 | i = hash_lookup (h, number, &hash); |
| @@ -3513,26 +3527,16 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list) | |||
| 3513 | } | 3527 | } |
| 3514 | } | 3528 | } |
| 3515 | 3529 | ||
| 3516 | 3530 | DEFUN ("lread--substitute-object-in-subtree", | |
| 3517 | /* List of nodes we've seen during substitute_object_in_subtree. */ | 3531 | Flread__substitute_object_in_subtree, |
| 3518 | static Lisp_Object seen_list; | 3532 | Slread__substitute_object_in_subtree, 3, 3, 0, |
| 3519 | 3533 | doc: /* In OBJECT, replace every occurrence of PLACEHOLDER with OBJECT. | |
| 3520 | DEFUN ("substitute-object-in-subtree", Fsubstitute_object_in_subtree, | 3534 | COMPLETED is a hash table of objects that might be circular, or is t |
| 3521 | Ssubstitute_object_in_subtree, 2, 2, 0, | 3535 | if any object might be circular. */) |
| 3522 | doc: /* Replace every reference to PLACEHOLDER in OBJECT with OBJECT. */) | 3536 | (Lisp_Object object, Lisp_Object placeholder, Lisp_Object completed) |
| 3523 | (Lisp_Object object, Lisp_Object placeholder) | ||
| 3524 | { | 3537 | { |
| 3525 | Lisp_Object check_object; | 3538 | struct subst subst = { object, placeholder, completed, Qnil }; |
| 3526 | 3539 | Lisp_Object check_object = substitute_object_recurse (&subst, object); | |
| 3527 | /* We haven't seen any objects when we start. */ | ||
| 3528 | seen_list = Qnil; | ||
| 3529 | |||
| 3530 | /* Make all the substitutions. */ | ||
| 3531 | check_object | ||
| 3532 | = substitute_object_recurse (object, placeholder, object); | ||
| 3533 | |||
| 3534 | /* Clear seen_list because we're done with it. */ | ||
| 3535 | seen_list = Qnil; | ||
| 3536 | 3540 | ||
| 3537 | /* The returned object here is expected to always eq the | 3541 | /* The returned object here is expected to always eq the |
| 3538 | original. */ | 3542 | original. */ |
| @@ -3541,26 +3545,12 @@ DEFUN ("substitute-object-in-subtree", Fsubstitute_object_in_subtree, | |||
| 3541 | return Qnil; | 3545 | return Qnil; |
| 3542 | } | 3546 | } |
| 3543 | 3547 | ||
| 3544 | /* Feval doesn't get called from here, so no gc protection is needed. */ | ||
| 3545 | #define SUBSTITUTE(get_val, set_val) \ | ||
| 3546 | do { \ | ||
| 3547 | Lisp_Object old_value = get_val; \ | ||
| 3548 | Lisp_Object true_value \ | ||
| 3549 | = substitute_object_recurse (object, placeholder, \ | ||
| 3550 | old_value); \ | ||
| 3551 | \ | ||
| 3552 | if (!EQ (old_value, true_value)) \ | ||
| 3553 | { \ | ||
| 3554 | set_val; \ | ||
| 3555 | } \ | ||
| 3556 | } while (0) | ||
| 3557 | |||
| 3558 | static Lisp_Object | 3548 | static Lisp_Object |
| 3559 | substitute_object_recurse (Lisp_Object object, Lisp_Object placeholder, Lisp_Object subtree) | 3549 | substitute_object_recurse (struct subst *subst, Lisp_Object subtree) |
| 3560 | { | 3550 | { |
| 3561 | /* If we find the placeholder, return the target object. */ | 3551 | /* If we find the placeholder, return the target object. */ |
| 3562 | if (EQ (placeholder, subtree)) | 3552 | if (EQ (subst->placeholder, subtree)) |
| 3563 | return object; | 3553 | return subst->object; |
| 3564 | 3554 | ||
| 3565 | /* For common object types that can't contain other objects, don't | 3555 | /* For common object types that can't contain other objects, don't |
| 3566 | bother looking them up; we're done. */ | 3556 | bother looking them up; we're done. */ |
| @@ -3570,15 +3560,16 @@ substitute_object_recurse (Lisp_Object object, Lisp_Object placeholder, Lisp_Obj | |||
| 3570 | return subtree; | 3560 | return subtree; |
| 3571 | 3561 | ||
| 3572 | /* If we've been to this node before, don't explore it again. */ | 3562 | /* If we've been to this node before, don't explore it again. */ |
| 3573 | if (!EQ (Qnil, Fmemq (subtree, seen_list))) | 3563 | if (!EQ (Qnil, Fmemq (subtree, subst->seen))) |
| 3574 | return subtree; | 3564 | return subtree; |
| 3575 | 3565 | ||
| 3576 | /* If this node can be the entry point to a cycle, remember that | 3566 | /* If this node can be the entry point to a cycle, remember that |
| 3577 | we've seen it. It can only be such an entry point if it was made | 3567 | we've seen it. It can only be such an entry point if it was made |
| 3578 | by #n=, which means that we can find it as a value in | 3568 | by #n=, which means that we can find it as a value in |
| 3579 | read_objects_completed. */ | 3569 | COMPLETED. */ |
| 3580 | if (hash_lookup (XHASH_TABLE (read_objects_completed), subtree, NULL) >= 0) | 3570 | if (EQ (subst->completed, Qt) |
| 3581 | seen_list = Fcons (subtree, seen_list); | 3571 | || hash_lookup (XHASH_TABLE (subst->completed), subtree, NULL) >= 0) |
| 3572 | subst->seen = Fcons (subtree, subst->seen); | ||
| 3582 | 3573 | ||
| 3583 | /* Recurse according to subtree's type. | 3574 | /* Recurse according to subtree's type. |
| 3584 | Every branch must return a Lisp_Object. */ | 3575 | Every branch must return a Lisp_Object. */ |
| @@ -3605,19 +3596,15 @@ substitute_object_recurse (Lisp_Object object, Lisp_Object placeholder, Lisp_Obj | |||
| 3605 | if (SUB_CHAR_TABLE_P (subtree)) | 3596 | if (SUB_CHAR_TABLE_P (subtree)) |
| 3606 | i = 2; | 3597 | i = 2; |
| 3607 | for ( ; i < length; i++) | 3598 | for ( ; i < length; i++) |
| 3608 | SUBSTITUTE (AREF (subtree, i), | 3599 | ASET (subtree, i, |
| 3609 | ASET (subtree, i, true_value)); | 3600 | substitute_object_recurse (subst, AREF (subtree, i))); |
| 3610 | return subtree; | 3601 | return subtree; |
| 3611 | } | 3602 | } |
| 3612 | 3603 | ||
| 3613 | case Lisp_Cons: | 3604 | case Lisp_Cons: |
| 3614 | { | 3605 | XSETCAR (subtree, substitute_object_recurse (subst, XCAR (subtree))); |
| 3615 | SUBSTITUTE (XCAR (subtree), | 3606 | XSETCDR (subtree, substitute_object_recurse (subst, XCDR (subtree))); |
| 3616 | XSETCAR (subtree, true_value)); | 3607 | return subtree; |
| 3617 | SUBSTITUTE (XCDR (subtree), | ||
| 3618 | XSETCDR (subtree, true_value)); | ||
| 3619 | return subtree; | ||
| 3620 | } | ||
| 3621 | 3608 | ||
| 3622 | case Lisp_String: | 3609 | case Lisp_String: |
| 3623 | { | 3610 | { |
| @@ -3625,11 +3612,8 @@ substitute_object_recurse (Lisp_Object object, Lisp_Object placeholder, Lisp_Obj | |||
| 3625 | substitute_in_interval contains part of the logic. */ | 3612 | substitute_in_interval contains part of the logic. */ |
| 3626 | 3613 | ||
| 3627 | INTERVAL root_interval = string_intervals (subtree); | 3614 | INTERVAL root_interval = string_intervals (subtree); |
| 3628 | AUTO_CONS (arg, object, placeholder); | ||
| 3629 | |||
| 3630 | traverse_intervals_noorder (root_interval, | 3615 | traverse_intervals_noorder (root_interval, |
| 3631 | &substitute_in_interval, arg); | 3616 | substitute_in_interval, subst); |
| 3632 | |||
| 3633 | return subtree; | 3617 | return subtree; |
| 3634 | } | 3618 | } |
| 3635 | 3619 | ||
| @@ -3641,12 +3625,10 @@ substitute_object_recurse (Lisp_Object object, Lisp_Object placeholder, Lisp_Obj | |||
| 3641 | 3625 | ||
| 3642 | /* Helper function for substitute_object_recurse. */ | 3626 | /* Helper function for substitute_object_recurse. */ |
| 3643 | static void | 3627 | static void |
| 3644 | substitute_in_interval (INTERVAL interval, Lisp_Object arg) | 3628 | substitute_in_interval (INTERVAL interval, void *arg) |
| 3645 | { | 3629 | { |
| 3646 | Lisp_Object object = Fcar (arg); | 3630 | set_interval_plist (interval, |
| 3647 | Lisp_Object placeholder = Fcdr (arg); | 3631 | substitute_object_recurse (arg, interval->plist)); |
| 3648 | |||
| 3649 | SUBSTITUTE (interval->plist, set_interval_plist (interval, true_value)); | ||
| 3650 | } | 3632 | } |
| 3651 | 3633 | ||
| 3652 | 3634 | ||
| @@ -4744,7 +4726,7 @@ syms_of_lread (void) | |||
| 4744 | { | 4726 | { |
| 4745 | defsubr (&Sread); | 4727 | defsubr (&Sread); |
| 4746 | defsubr (&Sread_from_string); | 4728 | defsubr (&Sread_from_string); |
| 4747 | defsubr (&Ssubstitute_object_in_subtree); | 4729 | defsubr (&Slread__substitute_object_in_subtree); |
| 4748 | defsubr (&Sintern); | 4730 | defsubr (&Sintern); |
| 4749 | defsubr (&Sintern_soft); | 4731 | defsubr (&Sintern_soft); |
| 4750 | defsubr (&Sunintern); | 4732 | defsubr (&Sunintern); |
| @@ -5057,8 +5039,6 @@ that are loaded before your customizations are read! */); | |||
| 5057 | read_objects_map = Qnil; | 5039 | read_objects_map = Qnil; |
| 5058 | staticpro (&read_objects_completed); | 5040 | staticpro (&read_objects_completed); |
| 5059 | read_objects_completed = Qnil; | 5041 | read_objects_completed = Qnil; |
| 5060 | staticpro (&seen_list); | ||
| 5061 | seen_list = Qnil; | ||
| 5062 | 5042 | ||
| 5063 | Vloads_in_progress = Qnil; | 5043 | Vloads_in_progress = Qnil; |
| 5064 | staticpro (&Vloads_in_progress); | 5044 | staticpro (&Vloads_in_progress); |
diff --git a/src/print.c b/src/print.c index 50c75d7712c..b6ea3ff62a5 100644 --- a/src/print.c +++ b/src/print.c | |||
| @@ -566,7 +566,7 @@ temp_output_buffer_setup (const char *bufname) | |||
| 566 | 566 | ||
| 567 | static void print (Lisp_Object, Lisp_Object, bool); | 567 | static void print (Lisp_Object, Lisp_Object, bool); |
| 568 | static void print_preprocess (Lisp_Object); | 568 | static void print_preprocess (Lisp_Object); |
| 569 | static void print_preprocess_string (INTERVAL, Lisp_Object); | 569 | static void print_preprocess_string (INTERVAL, void *); |
| 570 | static void print_object (Lisp_Object, Lisp_Object, bool); | 570 | static void print_object (Lisp_Object, Lisp_Object, bool); |
| 571 | 571 | ||
| 572 | DEFUN ("terpri", Fterpri, Sterpri, 0, 2, 0, | 572 | DEFUN ("terpri", Fterpri, Sterpri, 0, 2, 0, |
| @@ -1214,7 +1214,7 @@ print_preprocess (Lisp_Object obj) | |||
| 1214 | case Lisp_String: | 1214 | case Lisp_String: |
| 1215 | /* A string may have text properties, which can be circular. */ | 1215 | /* A string may have text properties, which can be circular. */ |
| 1216 | traverse_intervals_noorder (string_intervals (obj), | 1216 | traverse_intervals_noorder (string_intervals (obj), |
| 1217 | print_preprocess_string, Qnil); | 1217 | print_preprocess_string, NULL); |
| 1218 | break; | 1218 | break; |
| 1219 | 1219 | ||
| 1220 | case Lisp_Cons: | 1220 | case Lisp_Cons: |
| @@ -1263,7 +1263,7 @@ Fills `print-number-table'. */) | |||
| 1263 | } | 1263 | } |
| 1264 | 1264 | ||
| 1265 | static void | 1265 | static void |
| 1266 | print_preprocess_string (INTERVAL interval, Lisp_Object arg) | 1266 | print_preprocess_string (INTERVAL interval, void *arg) |
| 1267 | { | 1267 | { |
| 1268 | print_preprocess (interval->plist); | 1268 | print_preprocess (interval->plist); |
| 1269 | } | 1269 | } |