GNU bug report logs - #7722
24.0.50; Finding this C++ header file drops emacs into a infinite loop

Previous Next

Packages: emacs, cc-mode;

Reported by: Tassilo Horn <tassilo <at> member.fsf.org>

Date: Fri, 24 Dec 2010 08:23:01 UTC

Severity: serious

Found in version 24.0.50

Fixed in version 24.1

Done: Glenn Morris <rgm <at> gnu.org>

Bug is archived. No further changes may be made.

Full log


Message #22 received at 7722 <at> debbugs.gnu.org (full text, mbox):

From: Alan Mackenzie <acm <at> muc.de>
To: Chong Yidong <cyd <at> stupidchicken.com>
Cc: 7722 <at> debbugs.gnu.org, Tassilo Horn <tassilo <at> member.fsf.org>
Subject: Re: bug#7722: 24.0.50;
	Finding this C++ header file drops emacs into a infinite loop
Date: Fri, 4 Feb 2011 22:22:07 +0000
Hi there, Yidong, Tassilo,

On Sat, Jan 22, 2011 at 03:37:24PM -0500, Chong Yidong wrote:
> Tassilo Horn <tassilo <at> member.fsf.org> writes:

> > Originally reported by Caligo <iteronvexor <at> gmail.com>

> > He uses GNU Emacs 23.2.1 (x86_64-pc-linux-gnu, GTK+ Version 2.20.1),
> > but the bug in still in the current bzr trunk.

> > 1. emacs -Q bug.hpp
> > 2. emacs loops infinitely using 100% CPU resources

> > The offending file is that (according to the original reporter, the
> > spaces and empty lines are needed):

> I can reproduce this (file attached for convenience).  Alan, could you
> take a look?  Looks like a loop in c-forward-<>-arglist-recur:

It was indeed such a loop.  It was caused by a 500n jit-lock boundary
falling in the middle of a template construct, hence the "necessity" of
all the whitespace to reproduce the failure.

Here's a putative patch for the problem.  I've refactored the offending
function by replacing obscenely nested `if'-forms with a simple `cond'.
I've also removed some narrowing (to the 500n limit) which should help
jit-lock, hopefully without hurting too much elsewhere.

Tassilo, would you try out the patch, please, and let me know how it
goes.  Thanks!



=== modified file 'lisp/progmodes/cc-engine.el'
*** lisp/progmodes/cc-engine.el	2011-01-31 23:54:50 +0000
--- lisp/progmodes/cc-engine.el	2011-02-04 22:12:46 +0000
***************
*** 5455,5463 ****
  	    (goto-char start)
  	    nil))
  
!       (forward-char)
  
        (unless (looking-at c-<-op-cont-regexp)
  	(while (and
  		(progn
  		  (c-forward-syntactic-ws)
--- 5455,5465 ----
  	    (goto-char start)
  	    nil))
  
!       (forward-char) ; Forward over the opening '<'.
  
        (unless (looking-at c-<-op-cont-regexp)
+ 	;; go forward one non-alphanumeric character (group) per iteration of
+ 	;; this loop.
  	(while (and
  		(progn
  		  (c-forward-syntactic-ws)
***************
*** 5486,5492 ****
  			    (c-forward-type)
  			    (c-forward-syntactic-ws))))))
  
! 		  (setq pos (point))
  
  		  ;; Note: These regexps exploit the match order in \| so
  		  ;; that "<>" is matched by "<" rather than "[^>:-]>".
--- 5488,5494 ----
  			    (c-forward-type)
  			    (c-forward-syntactic-ws))))))
  
! 		  (setq pos (point))	; e.g. first token inside the '<'
  
  		  ;; Note: These regexps exploit the match order in \| so
  		  ;; that "<>" is matched by "<" rather than "[^>:-]>".
***************
*** 5522,5559 ****
  		  ;; Either an operator starting with '<' or a nested arglist.
  		  (setq pos (point))
  		  (let (id-start id-end subres keyword-match)
! 		    (if (if (looking-at c-<-op-cont-regexp)
! 			    (setq tmp (match-end 0))
! 			  (setq tmp pos)
! 			  (backward-char)
! 			  (not
! 			   (and
! 
! 			    (save-excursion
! 			      ;; There's always an identifier before an angle
! 			      ;; bracket arglist, or a keyword in
! 			      ;; `c-<>-type-kwds' or `c-<>-arglist-kwds'.
! 			      (c-backward-syntactic-ws)
! 			      (setq id-end (point))
! 			      (c-simple-skip-symbol-backward)
! 			      (when (or (setq keyword-match
! 					      (looking-at c-opt-<>-sexp-key))
! 					(not (looking-at c-keywords-regexp)))
! 				(setq id-start (point))))
! 
! 			    (setq subres
! 				  (let ((c-promote-possible-types t)
! 					(c-record-found-types t))
! 				    (c-forward-<>-arglist-recur
! 				     (and keyword-match
! 					  (c-keyword-member
! 					   (c-keyword-sym (match-string 1))
! 					   'c-<>-type-kwds)))))
! 			    )))
! 
! 			;; It was not an angle bracket arglist.
! 			(goto-char tmp)
! 
  		      ;; It was an angle bracket arglist.
  		      (setq c-record-found-types subres)
  
--- 5524,5558 ----
  		  ;; Either an operator starting with '<' or a nested arglist.
  		  (setq pos (point))
  		  (let (id-start id-end subres keyword-match)
! 		    (cond
! 		     ;; The '<' begins a multi-char operator.
! 		     ((looking-at c-<-op-cont-regexp)
! 		      (setq tmp (match-end 0))
! 		      (goto-char (match-end 0)))
! 		     ;; We're at a nested <.....>
! 		     ((progn
! 			(setq tmp pos)
! 			(backward-char)	; to the '<'
! 			(and
! 			 (save-excursion
! 			   ;; There's always an identifier before an angle
! 			   ;; bracket arglist, or a keyword in `c-<>-type-kwds'
! 			   ;; or `c-<>-arglist-kwds'.
! 			   (c-backward-syntactic-ws)
! 			   (setq id-end (point))
! 			   (c-simple-skip-symbol-backward)
! 			   (when (or (setq keyword-match
! 					   (looking-at c-opt-<>-sexp-key))
! 				     (not (looking-at c-keywords-regexp)))
! 			     (setq id-start (point))))
! 			 (setq subres
! 			       (let ((c-promote-possible-types t)
! 				     (c-record-found-types t))
! 				 (c-forward-<>-arglist-recur
! 				  (and keyword-match
! 				       (c-keyword-member
! 					(c-keyword-sym (match-string 1))
! 					'c-<>-type-kwds)))))))
  		      ;; It was an angle bracket arglist.
  		      (setq c-record-found-types subres)
  
***************
*** 5567,5574 ****
  				   (c-forward-syntactic-ws)
  				   (looking-at c-opt-identifier-concat-key)))
  			    (c-record-ref-id (cons id-start id-end))
! 			  (c-record-type-id (cons id-start id-end))))))
! 		  t)
  
  		 ((and (not c-restricted-<>-arglists)
  		       (or (and (eq (char-before) ?&)
--- 5566,5578 ----
  				   (c-forward-syntactic-ws)
  				   (looking-at c-opt-identifier-concat-key)))
  			    (c-record-ref-id (cons id-start id-end))
! 			  (c-record-type-id (cons id-start id-end)))))
! 
! 		     ;; At a "less than" operator.
! 		     (t
! 		      (forward-char)
! 		      )))
! 		  t)			; carry on looping.
  
  		 ((and (not c-restricted-<>-arglists)
  		       (or (and (eq (char-before) ?&)

=== modified file 'lisp/progmodes/cc-fonts.el'
*** lisp/progmodes/cc-fonts.el	2011-01-25 04:08:28 +0000
--- lisp/progmodes/cc-fonts.el	2011-02-04 22:10:01 +0000
***************
*** 1082,1088 ****
  	     (boundp 'parse-sexp-lookup-properties))))
  
        ;; Below we fontify a whole declaration even when it crosses the limit,
!       ;; to avoid gaps when lazy-lock fontifies the file a screenful at a
        ;; time.  That is however annoying during editing, e.g. the following is
        ;; a common situation while the first line is being written:
        ;;
--- 1082,1088 ----
  	     (boundp 'parse-sexp-lookup-properties))))
  
        ;; Below we fontify a whole declaration even when it crosses the limit,
!       ;; to avoid gaps when jit/lazy-lock fontifies the file a block at a
        ;; time.  That is however annoying during editing, e.g. the following is
        ;; a common situation while the first line is being written:
        ;;
***************
*** 1094,1102 ****
        ;; "some_other_variable" as an identifier, and the latter will not
        ;; correct itself until the second line is changed.  To avoid that we
        ;; narrow to the limit if the region to fontify is a single line.
!       (narrow-to-region
!        (point-min)
!        (if (<= limit (c-point 'bonl))
  	   (save-excursion
  	     ;; Narrow after any operator chars following the limit though,
  	     ;; since those characters can be useful in recognizing a
--- 1094,1102 ----
        ;; "some_other_variable" as an identifier, and the latter will not
        ;; correct itself until the second line is changed.  To avoid that we
        ;; narrow to the limit if the region to fontify is a single line.
!       (if (<= limit (c-point 'bonl))
! 	  (narrow-to-region
! 	   (point-min)
  	   (save-excursion
  	     ;; Narrow after any operator chars following the limit though,
  	     ;; since those characters can be useful in recognizing a
***************
*** 1104,1111 ****
  	     ;; after the header).
  	     (goto-char limit)
  	     (skip-chars-forward c-nonsymbol-chars)
! 	     (point))
! 	 limit))
  
        (c-find-decl-spots
         limit
--- 1104,1110 ----
  	     ;; after the header).
  	     (goto-char limit)
  	     (skip-chars-forward c-nonsymbol-chars)
! 	     (point))))
  
        (c-find-decl-spots
         limit




-- 
Alan Mackenzie (Nuremberg, Germany).




This bug report was last modified 14 years and 20 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.