Posts Tagged ‘infinite loop’

When I set up an emacs process filter, I never know how much input the process will deliver me at one time. Therefore I generally buffer the input and process (say) a line at a time.

(defvar buffer "")

(defun process-input (input)
  (setq buffer (concat input buffer))
  (let ((count 0)
        (pos 0))
    (while (string-match "^\\([^\n]+\\)\n" buffer pos)
      (message "Before: [%s] [%d]" (match-string 1 buffer) (match-end 1))
      (process-line (match-string 1 buffer))
      (message "After: [%s] [%d]" (match-string 1 buffer) (match-end 1))

      ;; error handling in case of runaway loops
      (incf count)
      (when (> count 10)
        (error "Looped too many times!"))

      (setq pos (1+ (match-end 1))))
    (when pos (setq buffer (substring buffer pos))))
  (message "REMAINDER: [%s]" buffer))

Given a simple (process-line ...) we can see the results from a simple test.

(defun process-line (line)
  (message "[%s]" line))

(process-input "XXX (line 1)\n13.15 (line 2)\n")
Before: XXX (line 1) 12
[XXX (line 1)]
After: XXX (line 1) 12
Before: 13.15 (line 2) 27
[13.15 (line 2)]
After: 13.15 (line 2) 27

An Infinite Loop

Now say I want to add some special handling for lines with a number in, what do you think happens?

(defun process-line (line)
  (when (string-match "\\([0-9]+\.[0-9]+\\)" line)
    (message "[%s]" line)))
Debugger entered--Lisp error: (error "Looped too many times!")
Before: [XXX (line 1)] [12]
After: [XXX (line 1)] [12]
Before: [13.15 (line 2)] [27]
[13.15 (line 2)]
After: [XXX (] [5]
Before: [13.15 (line 2)] [27]
[13.15 (line 2)]
After: [XXX (] [5]

The string match against the number has reset a hidden global variable used by (match-end ...) which has sent us into an infinite loop. Surprising action at a distance indeed!

Perl Regex Globals

Perl also uses global variables such as $1, $2, @- and @+ for its regular expressions, so could this cause a similar problem?

No. Fortunately, these globals are dynamically scoped so the appropriate values are maintained up the call stack.


Read Full Post »