]> git.eshelyaron.com Git - emacs.git/commitdiff
Avoid infinite loop in display of invisible text in strings
authorEli Zaretskii <eliz@gnu.org>
Fri, 7 Aug 2015 13:42:24 +0000 (16:42 +0300)
committerEli Zaretskii <eliz@gnu.org>
Fri, 7 Aug 2015 13:42:24 +0000 (16:42 +0300)
* src/xdisp.c (handle_invisible_prop): If the next change of
invisibility spec does not mean the beginning of a visible text,
update the string position from which to start the search for the
next invisibility change.  This avoids an infinite loop when we
have more than one invisibility spec that are made inactive by
buffer-invisibility-spec.  Simplify code.  (Bug#21200)

* test/redisplay-testsuite.el (test-redisplay-4): Add a test case
for the situation that caused bug #21200.

src/xdisp.c
test/redisplay-testsuite.el

index e45cb8702b2bbc27cf9008c967950454ed44635b..e7626d1ce2594786ffd3a11b6db76e336285e107 100644 (file)
@@ -4187,13 +4187,13 @@ handle_invisible_prop (struct it *it)
 
   if (STRINGP (it->string))
     {
-      Lisp_Object end_charpos, limit, charpos;
+      Lisp_Object end_charpos, limit;
 
       /* Get the value of the invisible text property at the
         current position.  Value will be nil if there is no such
         property.  */
-      charpos = make_number (IT_STRING_CHARPOS (*it));
-      prop = Fget_text_property (charpos, Qinvisible, it->string);
+      end_charpos = make_number (IT_STRING_CHARPOS (*it));
+      prop = Fget_text_property (end_charpos, Qinvisible, it->string);
       invis = TEXT_PROP_MEANS_INVISIBLE (prop);
 
       if (invis != 0 && IT_STRING_CHARPOS (*it) < it->end_charpos)
@@ -4211,8 +4211,12 @@ handle_invisible_prop (struct it *it)
          XSETINT (limit, len);
          do
            {
-             end_charpos = Fnext_single_property_change (charpos, Qinvisible,
-                                                         it->string, limit);
+             end_charpos
+               = Fnext_single_property_change (end_charpos, Qinvisible,
+                                               it->string, limit);
+             /* Since LIMIT is always an integer, so should be the
+                value returned by Fnext_single_property_change.  */
+             eassert (INTEGERP (end_charpos));
              if (INTEGERP (end_charpos))
                {
                  endpos = XFASTINT (end_charpos);
@@ -4221,6 +4225,8 @@ handle_invisible_prop (struct it *it)
                  if (invis == 2)
                    display_ellipsis_p = true;
                }
+             else /* Should never happen; but if it does, exit the loop.  */
+               endpos = len;
            }
          while (invis != 0 && endpos < len);
 
@@ -4256,7 +4262,7 @@ handle_invisible_prop (struct it *it)
                }
              else
                {
-                 IT_STRING_CHARPOS (*it) = XFASTINT (end_charpos);
+                 IT_STRING_CHARPOS (*it) = endpos;
                  compute_string_pos (&it->current.string_pos, old, it->string);
                }
            }
index 357ab08bf84e01e70b5e2270eb311f5f42d39784..40a21b7fea46c8c5262e9712d43e38b905f05c19 100644 (file)
@@ -251,6 +251,18 @@ static unsigned char x_bits[] = {0xff, 0x81, 0xbd, 0xa5, 0xa5, 0xbd, 0x81, 0xff
          (str "ABC"))
       (put-text-property 1 2 'invisible 'test-redisplay--ellipsis-invis str)
       (overlay-put ov 'display str)))
+  ;; Overlay string with 2 adjacent and different invisible
+  ;; properties.  This caused an infloop before Emacs 25.
+  (insert "\n  Expected: ABC")
+  (insert "\n    Result: ")
+  (let ((opoint (point)))
+    (insert "ABC\n")
+    (let ((ov (make-overlay (1+ opoint) (+ 2 opoint)))
+          (str (concat (propertize "X"
+                                   'invisible 'test-redisplay--simple-invis)
+                       (propertize "Y"
+                                   'invisible 'test-redisplay--simple-invis2))))
+      (overlay-put ov 'after-string str)))
 
   (insert "\n"))
 
@@ -264,6 +276,7 @@ static unsigned char x_bits[] = {0xff, 0x81, 0xbd, 0xa5, 0xa5, 0xbd, 0x81, 0xff
     (erase-buffer)
     (setq buffer-invisibility-spec
          '(test-redisplay--simple-invis
+            test-redisplay--simple-invis2
            (test-redisplay--ellipsis-invis . t)))
     (test-redisplay-1)
     (test-redisplay-2)