GNU bug report logs - #25869
CC Mode 5.32.99 (C/l); Sometimes Emacs use 100% CPU on comment-dwim for a long time

Previous Next

Package: cc-mode;

Reported by: Mohammed Sadiq <sadiq <at> sadiqpk.org>

Date: Sat, 25 Feb 2017 10:58:01 UTC

Severity: normal

Done: Alan Mackenzie <acm <at> muc.de>

Bug is archived. No further changes may be made.

To add a comment to this bug, you must first unarchive it, by sending
a message to control AT debbugs.gnu.org, with unarchive 25869 in the body.
You can then email your comments to 25869 AT debbugs.gnu.org in the normal way.

Toggle the display of automated, internal messages from the tracker.

View this report as an mbox folder, status mbox, maintainer mbox


Report forwarded to bug-cc-mode <at> gnu.org:
bug#25869; Package cc-mode. (Sat, 25 Feb 2017 10:58:01 GMT) Full text and rfc822 format available.

Acknowledgement sent to Mohammed Sadiq <sadiq <at> sadiqpk.org>:
New bug report received and forwarded. Copy sent to bug-cc-mode <at> gnu.org. (Sat, 25 Feb 2017 10:58:02 GMT) Full text and rfc822 format available.

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

From: Mohammed Sadiq <sadiq <at> sadiqpk.org>
To: submit <at> debbugs.gnu.org
Subject: CC Mode 5.32.99 (C/l);
 Sometimes Emacs use 100% CPU on comment-dwim for a long time
Date: Sat, 25 Feb 2017 16:26:58 +0530
When writing code, I encountered a bug in comment-dwim, which takes 100%
CPU for a long time, and then failing to comment the line.

How to reproduce using the following code:
1. Mark some line in the first function.
   Eg: g_type_ensure (CC_TYPE_INFO_OVERVIEW);
   do C-a C-SPC C-e
2. Do comment-dwim
   ie, M-;

The code that produced the issue is the following:
Note: if I remove the array at the bottom of code, M-; begins to work
fine. The code follows is an excerpt from gnome-control-center.

============ Code starts =================

static void
cc_info_panel_class_init (CcInfoPanelClass *klass)
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);

  g_type_class_add_private (klass, sizeof (CcInfoPanelPrivate));

  object_class->dispose = cc_info_panel_dispose;
  object_class->finalize = cc_info_panel_finalize;

  g_type_ensure (CC_TYPE_INFO_OVERVIEW);
}


static void
info_panel_setup_default_app (CcInfoPanel    *self,
                              DefaultAppData *data,
                              guint           left_attach,
                              guint           top_attach)
{
  GtkWidget *button;
  GtkWidget *grid;
  GtkWidget *label;

  grid = WID ("default_apps_grid");

  button = gtk_app_chooser_button_new (data->content_type);
  g_object_set_data (G_OBJECT (button), "cc-default-app-data", data);

  gtk_app_chooser_button_set_show_default_item (GTK_APP_CHOOSER_BUTTON (button), TRUE);
  gtk_grid_attach (GTK_GRID (grid), button, left_attach, top_attach,
                   1, 1);
  g_signal_connect (G_OBJECT (button), "changed",
                    G_CALLBACK (default_app_changed), self);
  gtk_widget_show (button);

  label = WID(data->label);
  gtk_label_set_mnemonic_widget (GTK_LABEL (label), button);
}

static DefaultAppData preferred_app_infos[] = {
  /* for web, we need to support text/html,
     application/xhtml+xml and x-scheme-handler/https,
     hence the "*" pattern
  */
  { "x-scheme-handler/http", "web-label", "*" },
  { "x-scheme-handler/mailto", "mail-label", NULL },
  { "text/calendar", "calendar-label", NULL },
  { "audio/x-vorbis+ogg", "music-label", "audio/*" },
  { "video/x-ogm+ogg", "video-label", "video/*" },
  { "image/jpeg", "photos-label", "image/*" }
};


============ Code Ends ===========


Thanks

Emacs  : GNU Emacs 26.0.50.3 (x86_64-pc-linux-gnu, GTK+ Version 3.22.6)
 of 2017-02-05
Package: CC Mode 5.32.99 (C/l)
Buffer Style: gnu
c-emacs-features: (pps-extended-state col-0-paren posix-char-classes gen-string-delim gen-comment-delim syntax-properties 1-bit)

current state:
==============
(setq
 c-basic-offset 2
 c-comment-only-line-offset '(0 . 0)
 c-indent-comment-alist '((anchored-comment column . 0) (end-block space . 1)
			  (cpp-end-block space . 2))
 c-indent-comments-syntactically-p nil
 c-block-comment-prefix ""
 c-comment-prefix-regexp '((pike-mode . "//+!?\\|\\**") (awk-mode . "#+")
			   (other . "//+\\|\\**"))
 c-doc-comment-style '((java-mode . javadoc) (pike-mode . autodoc)
		       (c-mode . gtkdoc))
 c-cleanup-list '(scope-operator)
 c-hanging-braces-alist '((substatement-open before after)
			  (arglist-cont-nonempty))
 c-hanging-colons-alist nil
 c-hanging-semi&comma-criteria '(c-semi&comma-inside-parenlist)
 c-backslash-column 48
 c-backslash-max-column 72
 c-special-indent-hook '(c-gnu-impose-minimum)
 c-label-minimum-indentation 1
 c-offsets-alist '((inexpr-class . +)
		   (inexpr-statement . +)
		   (lambda-intro-cont . +)
		   (inlambda . c-lineup-inexpr-block)
		   (template-args-cont c-lineup-template-args +)
		   (incomposition . +)
		   (inmodule . +)
		   (innamespace . +)
		   (inextern-lang . +)
		   (composition-close . 0)
		   (module-close . 0)
		   (namespace-close . 0)
		   (extern-lang-close . 0)
		   (composition-open . 0)
		   (module-open . 0)
		   (namespace-open . 0)
		   (extern-lang-open . 0)
		   (objc-method-call-cont
		    c-lineup-ObjC-method-call-colons
		    c-lineup-ObjC-method-call
		    +
		    )
		   (objc-method-args-cont . c-lineup-ObjC-method-args)
		   (objc-method-intro . [0])
		   (friend . 0)
		   (cpp-define-intro c-lineup-cpp-define +)
		   (cpp-macro-cont . +)
		   (cpp-macro . [0])
		   (inclass . +)
		   (stream-op . c-lineup-streamop)
		   (arglist-cont-nonempty
		    c-lineup-gcc-asm-reg
		    c-lineup-arglist
		    )
		   (arglist-cont c-lineup-gcc-asm-reg 0)
		   (comment-intro c-lineup-knr-region-comment c-lineup-comment)
		   (catch-clause . 0)
		   (else-clause . 0)
		   (do-while-closure . 0)
		   (access-label . -)
		   (case-label . 0)
		   (substatement . +)
		   (statement-case-intro . +)
		   (statement . 0)
		   (brace-entry-open . 0)
		   (brace-list-entry . c-lineup-under-anchor)
		   (brace-list-close . 0)
		   (block-close . 0)
		   (block-open . 0)
		   (inher-cont . c-lineup-multi-inher)
		   (inher-intro . +)
		   (member-init-cont . c-lineup-multi-inher)
		   (member-init-intro . +)
		   (annotation-var-cont . +)
		   (annotation-top-cont . 0)
		   (topmost-intro . 0)
		   (knr-argdecl . 0)
		   (func-decl-cont . +)
		   (inline-close . 0)
		   (class-close . 0)
		   (class-open . 0)
		   (defun-block-intro . +)
		   (defun-close . 0)
		   (defun-open . 0)
		   (c . c-lineup-C-comments)
		   (string . c-lineup-dont-change)
		   (topmost-intro-cont
		    first
		    c-lineup-topmost-intro-cont
		    c-lineup-gnu-DEFUN-intro-cont
		    )
		   (brace-list-intro . c-lineup-arglist-intro-after-paren)
		   (brace-list-open . +)
		   (inline-open . 0)
		   (arglist-close . c-lineup-arglist)
		   (arglist-intro . c-lineup-arglist-intro-after-paren)
		   (statement-cont . +)
		   (statement-case-open . +)
		   (label . 0)
		   (substatement-label . 0)
		   (substatement-open . +)
		   (knr-argdecl-intro . 5)
		   (statement-block-intro . +)
		   )
 c-buffer-is-cc-mode 'c-mode
 c-tab-always-indent t
 c-syntactic-indentation t
 c-syntactic-indentation-in-macros t
 c-ignore-auto-fill '(string cpp code)
 c-auto-align-backslashes t
 c-backspace-function 'backward-delete-char-untabify
 c-delete-function 'delete-char
 c-electric-pound-behavior nil
 c-default-style '((java-mode . "java") (awk-mode . "awk") (other . "gnu"))
 c-enable-xemacs-performance-kludge-p nil
 c-old-style-variable-behavior nil
 defun-prompt-regexp nil
 tab-width 8
 comment-column 32
 parse-sexp-ignore-comments t
 parse-sexp-lookup-properties t
 auto-fill-function nil
 comment-multi-line t
 comment-start-skip "\\(//+\\|/\\*+\\)\\s *"
 fill-prefix nil
 fill-column 70
 paragraph-start "[ 	]*\\(//+\\|\\**\\)[ 	]*$\\|^\f"
 adaptive-fill-mode t
 adaptive-fill-regexp "[ 	]*\\(//+\\|\\**\\)[ 	]*\\([ 	]*\\([-–!|#%;>*·•‣⁃◦]+[ 	]*\\)*\\)"
 )




Information forwarded to bug-cc-mode <at> gnu.org:
bug#25869; Package cc-mode. (Sun, 05 Mar 2017 22:12:02 GMT) Full text and rfc822 format available.

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

From: Alan Mackenzie <acm <at> muc.de>
To: Mohammed Sadiq <sadiq <at> sadiqpk.org>
Cc: 25869 <at> debbugs.gnu.org
Subject: Re: bug#25869: CC Mode 5.32.99 (C/l); Sometimes Emacs use 100% CPU
 on comment-dwim for a long time
Date: Sun, 5 Mar 2017 22:11:09 +0000
Hello, Mohammed.

On Sat, Feb 25, 2017 at 16:26:58 +0530, Mohammed Sadiq wrote:

> When writing code, I encountered a bug in comment-dwim, which takes 100%
> CPU for a long time, and then failing to comment the line.

> How to reproduce using the following code:
> 1. Mark some line in the first function.
>    Eg: g_type_ensure (CC_TYPE_INFO_OVERVIEW);
>    do C-a C-SPC C-e
> 2. Do comment-dwim
>    ie, M-;

> The code that produced the issue is the following:
> Note: if I remove the array at the bottom of code, M-; begins to work
> fine. The code follows is an excerpt from gnome-control-center.

First of all, thank you for such a detailed and complete bug report.

The bug that this code triggers has been in CC Mode for quite some
while, but it takes a rather unusual combination of constructs in the C
source to trigger it.

What is happening is that the M-; first inserts "/* ".  This causes all
the code up to the next terminating "*/" to become, temporarily, a
comment.  One of CC Mode's functions moves forward over this comment.  A
bit later on, it has cause to move backwards over it, but only moves as
far back as the "/*" which was the original start of the second comment
(but is now merely part of the first comment).  This is the bug, I
think.

This might be quite tricky to fix.  Give me a little time, please!

[ snip source code ]

> Thanks

[ CC Mode configuration dump appreciated, but snipped. ]

-- 
Alan Mackenzie (Nuremberg, Germany).




Information forwarded to bug-cc-mode <at> gnu.org:
bug#25869; Package cc-mode. (Sun, 09 Apr 2017 14:27:02 GMT) Full text and rfc822 format available.

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

From: Alan Mackenzie <acm <at> muc.de>
To: Mohammed Sadiq <sadiq <at> sadiqpk.org>
Cc: 25869 <at> debbugs.gnu.org
Subject: Re: bug#25869: CC Mode 5.32.99 (C/l); Sometimes Emacs use 100% CPU
 on comment-dwim for a long time
Date: Sun, 9 Apr 2017 14:25:15 +0000
Hello again, Mohammed.

On Sun, Mar 05, 2017 at 22:11:09 +0000, Alan Mackenzie wrote:
> On Sat, Feb 25, 2017 at 16:26:58 +0530, Mohammed Sadiq wrote:

> > When writing code, I encountered a bug in comment-dwim, which takes 100%
> > CPU for a long time, and then failing to comment the line.

> > How to reproduce using the following code:
> > 1. Mark some line in the first function.
> >    Eg: g_type_ensure (CC_TYPE_INFO_OVERVIEW);
> >    do C-a C-SPC C-e
> > 2. Do comment-dwim
> >    ie, M-;

> > The code that produced the issue is the following:
> > Note: if I remove the array at the bottom of code, M-; begins to work
> > fine. The code follows is an excerpt from gnome-control-center.

> First of all, thank you for such a detailed and complete bug report.

> The bug that this code triggers has been in CC Mode for quite some
> while, but it takes a rather unusual combination of constructs in the C
> source to trigger it.

> What is happening is that the M-; first inserts "/* ".  This causes all
> the code up to the next terminating "*/" to become, temporarily, a
> comment.  One of CC Mode's functions moves forward over this comment.  A
> bit later on, it has cause to move backwards over it, but only moves as
> far back as the "/*" which was the original start of the second comment
> (but is now merely part of the first comment).  This is the bug, I
> think.

> This might be quite tricky to fix.  Give me a little time, please!

> [ snip source code ]

> > Thanks

> [ CC Mode configuration dump appreciated, but snipped. ]

OK, I think the following patch should do the trick.  Would you please
apply it, recompile cc-engine.el (e.g., with

    $ emacs -Q -batch -f batch-byte-compile cc-engine.el

), reload it (or restart Emacs), and either confirm to me that the bug
has been fixed, or tell me what's still wrong about it.  Thanks!



diff -r 51f7a9ff5450 cc-engine.el
--- a/cc-engine.el	Sat Feb 25 14:39:10 2017 +0000
+++ b/cc-engine.el	Sun Apr 09 14:04:38 2017 +0000
@@ -324,34 +324,41 @@
 	    (goto-char here)
 	    nil))))))
 
-(defun c-end-of-macro ()
+(defun c-end-of-macro (&optional lim)
   "Go to the end of a preprocessor directive.
 More accurately, move the point to the end of the closest following
 line that doesn't end with a line continuation backslash - no check is
 done that the point is inside a cpp directive to begin with.
 
+If LIM is provided, it is a limit position at which point is left
+if the end of the macro doesn't occur earlier.
+
 Note that this function might do hidden buffer changes.  See the
 comment at the start of cc-engine.el for more info."
-   (if (and (cdr c-macro-cache)
-	    (<= (point) (cdr c-macro-cache))
-	    (>= (point) (car c-macro-cache)))
-       (goto-char (cdr c-macro-cache))
-     (unless (and (car c-macro-cache)
-		  (<= (point) c-macro-cache-start-pos)
-		  (>= (point) (car c-macro-cache)))
-       (setq c-macro-cache nil
-	     c-macro-cache-start-pos nil
-	     c-macro-cache-syntactic nil
-	     c-macro-cache-no-comment nil))
-     (while (progn
-	      (end-of-line)
-	      (when (and (eq (char-before) ?\\)
-			 (not (eobp)))
-		(forward-char)
-		t)))
-     (when (car c-macro-cache)
-       (setcdr c-macro-cache (point))
-       (setq c-macro-cache-syntactic nil))))
+  (save-restriction
+    (if lim (narrow-to-region (point-min) lim))
+    (if (and (cdr c-macro-cache)
+	     (<= (point) (cdr c-macro-cache))
+	     (>= (point) (car c-macro-cache)))
+	(goto-char (cdr c-macro-cache))
+      (unless (and (car c-macro-cache)
+		   (<= (point) c-macro-cache-start-pos)
+		   (>= (point) (car c-macro-cache)))
+	(setq c-macro-cache nil
+	      c-macro-cache-start-pos nil
+	      c-macro-cache-syntactic nil
+	      c-macro-cache-no-comment nil))
+      (while (progn
+	       (end-of-line)
+	       (when (and (eq (char-before) ?\\)
+			  (not (eobp)))
+		 (forward-char)
+		 t)))
+      (when (and (car c-macro-cache)
+		 (bolp)
+		 (not (eq (char-before (1- (point))) ?\\)))
+	(setcdr c-macro-cache (point))
+	(setq c-macro-cache-syntactic nil)))))
 
 (defun c-syntactic-end-of-macro ()
   ;; Go to the end of a CPP directive, or a "safe" pos just before.
@@ -1846,13 +1853,10 @@
   (let (;; `rung-pos' is set to a position as early as possible in the
 	;; unmarked part of the simple ws region.
 	(rung-pos (point)) next-rung-pos rung-end-pos last-put-in-sws-pos
-	rung-is-marked next-rung-is-marked simple-ws-end
+	rung-is-marked next-rung-is-marked simple-ws-end macro-start macro-end
 	;; `safe-start' is set when it's safe to cache the start position.
-	;; It's not set if we've initially skipped over comments and line
-	;; continuations since we might have gone out through the end of a
-	;; macro then.  This provision makes `c-forward-sws' not populate the
-	;; cache in the majority of cases, but otoh is `c-backward-sws' by far
-	;; more common.
+	;; This is the case except when we have an unterminated block comment
+	;; within a macro.
 	safe-start)
 
     ;; Skip simple ws and do a quick check on the following character to see
@@ -1928,7 +1932,33 @@
 
 	    ;; Now move over any comments (x)or a CPP construct.
 	    (setq simple-ws-end (point))
-	    (c-forward-comments)
+	    (setq safe-start t)
+	    ;; Take elaborate precautions to detect an open block comment at
+	    ;; the end of a macro.  If we find one, we set `safe-start' to nil
+	    ;; and break off any further scanning of comments.
+	    (let ((com-begin (point)) com-end in-macro)
+	      (when (and (c-forward-single-comment)
+	    		 (setq com-end (point))
+	    		 (save-excursion
+	    		   (goto-char com-begin)
+	    		   (c-beginning-of-macro)))
+	    	(setq in-macro t)
+	    	(goto-char com-begin)
+	    	(if (progn (c-end-of-macro com-end)
+	    		   (< (point) com-end))
+	    	    (setq safe-start nil)))
+	      (if in-macro
+	    	  (while (and safe-start
+	    		      com-end (> com-end com-begin)
+	    		      (setq com-begin (point))
+	    		      (when (and (c-forward-single-comment)
+	    				 (setq com-end (point)))
+	    			(goto-char com-begin)
+	    			(if (progn (c-end-of-macro com-end)
+	    				   (< (point) com-end))
+	    			    (setq safe-start nil))
+	    			safe-start)))
+	    	(c-forward-comments)))
 
 	    (cond
 	     ((/= (point) simple-ws-end)
@@ -1939,6 +1969,7 @@
 	     ((save-excursion
 		(and c-opt-cpp-prefix
 		     (looking-at c-opt-cpp-start)
+		     (setq macro-start (point))
 		     (progn (skip-chars-backward " \t")
 			    (bolp))
 		     (or (bobp)
@@ -1949,8 +1980,20 @@
 	      (while (and (eq (char-before) ?\\)
 			  (= (forward-line 1) 0))
 		(end-of-line))
+	      (setq macro-end (point))
+	      ;; Check for an open block comment at the end of the macro.
+	      (goto-char macro-start)
+	      (let (s in-block-comment)
+		(while
+		    (progn
+		      (setq s (parse-partial-sexp (point) macro-end
+						  nil nil s 'syntax-table))
+		      (< (point) macro-end))
+		  (setq in-block-comment
+			(and (elt s 4)	     ; in a comment
+			     (null (elt s 7))))) ; a block comment
+		(if in-block-comment (setq safe-start nil)))
 	      (forward-line 1)
-	      (setq safe-start t)
 	      ;; Don't cache at eob in case the buffer is narrowed.
 	      (not (eobp)))
 
@@ -1958,7 +2001,6 @@
 		   (looking-at c-noise-macro-name-re))
 	      ;; Skip over a noise macro.
 	      (goto-char (match-end 1))
-	      (setq safe-start t)
 	      (not (eobp)))))
 
 	;; We've searched over a piece of non-white syntactic ws.  See if this
@@ -2021,8 +2063,7 @@
 	  (if (setq rung-is-marked next-rung-is-marked)
 	      (setq rung-pos (1- (c-next-single-property-change
 				  rung-is-marked 'c-is-sws nil rung-end-pos)))
-	    (setq rung-pos next-rung-pos))
-	  (setq safe-start t)))
+	    (setq rung-pos next-rung-pos))))
 
       ;; Make sure that the newly marked `c-in-sws' region doesn't connect to
       ;; another one after the point (which might occur when editing inside a



-- 
Alan Mackenzie (Nuremberg, Germany).




Information forwarded to bug-cc-mode <at> gnu.org:
bug#25869; Package cc-mode. (Mon, 10 Apr 2017 01:47:02 GMT) Full text and rfc822 format available.

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

From: Mohammed Sadiq <sadiq <at> sadiqpk.org>
To: Alan Mackenzie <acm <at> muc.de>
Cc: 25869 <at> debbugs.gnu.org
Subject: Re: bug#25869: CC Mode 5.32.99 (C/l); Sometimes Emacs use 100% CPU
 on comment-dwim for a long time
Date: Mon, 10 Apr 2017 07:16:12 +0530 (IST)
> On April 9, 2017 at 7:55 PM Alan Mackenzie <acm <at> muc.de> wrote:
> OK, I think the following patch should do the trick. Would you please
> apply it, recompile cc-engine.el
> [code snipped]

Seems to work perfect. Tested only with the test case given for the bug.

Thanks




Reply sent to Alan Mackenzie <acm <at> muc.de>:
You have taken responsibility. (Mon, 10 Apr 2017 21:08:02 GMT) Full text and rfc822 format available.

Notification sent to Mohammed Sadiq <sadiq <at> sadiqpk.org>:
bug acknowledged by developer. (Mon, 10 Apr 2017 21:08:02 GMT) Full text and rfc822 format available.

Message #19 received at 25869-done <at> debbugs.gnu.org (full text, mbox):

From: Alan Mackenzie <acm <at> muc.de>
To: 25869-done <at> debbugs.gnu.org
Cc: Mohammed Sadiq <sadiq <at> sadiqpk.org>
Subject: Re: bug#25869: CC Mode 5.32.99 (C/l); Sometimes Emacs use 100% CPU
 on comment-dwim for a long time
Date: Mon, 10 Apr 2017 21:07:12 +0000
Bug fixed in master.

-- 
Alan Mackenzie (Nuremberg, Germany).




bug archived. Request was from Debbugs Internal Request <help-debbugs <at> gnu.org> to internal_control <at> debbugs.gnu.org. (Tue, 09 May 2017 11:24:05 GMT) Full text and rfc822 format available.

This bug report was last modified 6 years and 347 days ago.

Previous Next


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