Subject: Re: bug#24315: 25.1.50; re-search-forward errors with "Variable binding depth exceeds max-specpdl-size"

From: [email-masked] (Peder O. Klingenberg)
Date: Tue, 30 Aug 2016 15:09:34 +0200

On Fri, Aug 26 2016 at 23:35, [email-masked] wrote:

> This looks like it would be an inefficient regexp, since it has nested
> stars.  I suspect searching for "^[ \t]" multiple times would be more
> efficient than trying to match multiple lines in a single regexp.

Tried that.  It sort of worked, in that it worked when I directly called
`icalendar--read-event' in a buffer containing the event as manually
extracted from the gnus message.

However, parsing the problematic message in gnus still failed.  It turns
out `gnus-icalendar-event-from-buffer' calls
`icalendar--get-unfolded-buffer' before `icalendar--read-event'.

`icalendar--get-unfolded-buffer' takes care of all those pesky line
continuations, and returns a buffer with each element occupying exactly
one line.  So essentially `icalendar--read-event' was using a regexp to
extract the rest of the line, and that failed with a line nearly 40k
characters long.

The only other in-tree caller of `icalendar--read-event' (excluding
itself) also calls `icalendar--get-unfolded-buffer' first, and indeed,
`icalendar-read-event' already relies on this to take care of line
continuations in element parameters (as opposed to values).

Attached is a patch that uses buffer-substring to accomplish the same
thing as the offending regexp, and documents the dependency on
`icalendar--get-unfolded-buffer'.  This fixes the problem for me.

>From c3ae84dc48a993bb1906d5c9b6b663184e2a9d9d Mon Sep 17 00:00:00 2001
From: "Peder O. Klingenberg" <[email-masked]>
Date: Tue, 30 Aug 2016 14:44:16 +0200
Subject: [PATCH] Avoid crash in icalendar--read-element

* lisp/calendar/icalendar.el (icalendar--read-element): Stop crashing
when parsing overly long event descriptions.  (Bug#24315)
---
 lisp/calendar/icalendar.el | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/lisp/calendar/icalendar.el b/lisp/calendar/icalendar.el
index 386c554..19930d5 100644
--- a/lisp/calendar/icalendar.el
+++ b/lisp/calendar/icalendar.el
@@ -361,7 +361,8 @@ icalendar--read-element
 INVALUE gives the current iCalendar element we are reading.
 INPARAMS gives the current parameters.....
 This function calls itself recursively for each nested calendar element
-it finds."
+it finds. The current buffer should be an unfolded buffer as returned
+from `icalendar--get-unfolded-buffer'."
   (let (element children line name params param param-name param-value
                 value
                 (continue t))
@@ -391,8 +392,8 @@ icalendar--read-element
       (unless (looking-at ":")
         (error "Oops"))
       (forward-char 1)
-      (re-search-forward  "\\(.*\\)\\(\r?\n[ \t].*\\)*" nil t)
-      (setq value (icalendar--rris "\r?\n[ \t]" "" (match-string 0)))
+      (setq value (buffer-substring (point) (line-end-position)))
+      (end-of-line)
       (setq line (list name params value))
       (cond ((eq name 'BEGIN)
              (setq children
-- 
2.9.3