From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Chong Yidong Newsgroups: gmane.emacs.devel Subject: Re: Risky local variable mechanism Date: Tue, 07 Feb 2006 11:45:57 -0500 Message-ID: <87r76fkth6.fsf@stupidchicken.com> References: <87mzhbly89.fsf-monnier+emacs@gnu.org> NNTP-Posting-Host: main.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: sea.gmane.org 1139336134 12701 80.91.229.2 (7 Feb 2006 18:15:34 GMT) X-Complaints-To: usenet@sea.gmane.org NNTP-Posting-Date: Tue, 7 Feb 2006 18:15:34 +0000 (UTC) Cc: emacs-devel@gnu.org, monnier@iro.umontreal.ca, "Kim F. Storm" Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Tue Feb 07 19:15:30 2006 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([199.232.76.165]) by ciao.gmane.org with esmtp (Exim 4.43) id 1F6XMf-0002zr-Fx for ged-emacs-devel@m.gmane.org; Tue, 07 Feb 2006 19:14:58 +0100 Original-Received: from localhost ([127.0.0.1] helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1F6XMe-0002JC-ON for ged-emacs-devel@m.gmane.org; Tue, 07 Feb 2006 13:14:56 -0500 Original-Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1F6W27-0007Bh-GZ for emacs-devel@gnu.org; Tue, 07 Feb 2006 11:49:39 -0500 Original-Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1F6W24-0007Av-Nu for emacs-devel@gnu.org; Tue, 07 Feb 2006 11:49:38 -0500 Original-Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1F6W24-0007Ap-DQ for emacs-devel@gnu.org; Tue, 07 Feb 2006 11:49:36 -0500 Original-Received: from [18.95.6.197] (helo=localhost.localdomain) by monty-python.gnu.org with esmtp (Exim 4.52) id 1F6W1i-0000AI-V2; Tue, 07 Feb 2006 11:49:15 -0500 Original-Received: by localhost.localdomain (Postfix, from userid 1000) id 954021E423B; Tue, 7 Feb 2006 11:45:57 -0500 (EST) Original-To: rms@gnu.org In-Reply-To: (Richard M. Stallman's message of "Fri, 03 Feb 2006 18:43:12 -0500") User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.0.50 (gnu/linux) X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.devel:50161 Archived-At: "Richard M. Stallman" writes: > Why not make anything risky, except those explicit settings which > are recorded in safe-local-eval-forms (and add something similar > for variables), and then make it easier to update those lists > when user is queried to approve local variables/forms > > That could be a good approach. > > Would someone like to implement this? How about this patch? It implements a `safe-local-variables' custom option. If a variable is not in this list, the user is prompted before it is set. If the user agrees to set it, and the variable is not explicitly marked as risky (as determined by the currently existing `risky-local-variable-p' function), we ask if that variable can be automatically set in the future. If the user agrees to this too, `safe-local-variables' is updated and saved to the custom-file. *** emacs/lisp/files.el.~1.804.~ 2006-02-06 23:43:16.000000000 -0500 --- emacs/lisp/files.el 2006-02-07 11:35:06.000000000 -0500 *************** *** 2393,2405 **** (run-hooks 'hack-local-variables-hook)) mode-specified)) ! (defvar ignored-local-variables () ! "Variables to be ignored in a file's local variable spec.") ;; Get confirmation before setting these variables as locals in a file. (put 'debugger 'risky-local-variable t) (put 'enable-local-eval 'risky-local-variable t) (put 'ignored-local-variables 'risky-local-variable t) (put 'eval 'risky-local-variable t) (put 'file-name-handler-alist 'risky-local-variable t) (put 'inhibit-quit 'risky-local-variable t) --- 2393,2417 ---- (run-hooks 'hack-local-variables-hook)) mode-specified)) ! (defcustom safe-local-variables ! '(c-basic-offset c-indent-level compile-command fill-column ! fill-prefix indent-tabs-mode page-delimiter paragraph-separate ! sentence-end sentence-end-double-space tab-width version-control) ! "Variables that are treated as safe." ! :group 'find-file ! :type '(repeat symbol)) ! ! (defcustom ignored-local-variables ! '(ignored-local-variables safe-local-variables) ! "Variables to be ignored in a file's local variable spec." ! :group 'find-file ! :type '(repeat symbol)) ;; Get confirmation before setting these variables as locals in a file. (put 'debugger 'risky-local-variable t) (put 'enable-local-eval 'risky-local-variable t) (put 'ignored-local-variables 'risky-local-variable t) + (put 'safe-local-variables 'risky-local-variable t) (put 'eval 'risky-local-variable t) (put 'file-name-handler-alist 'risky-local-variable t) (put 'inhibit-quit 'risky-local-variable t) *************** *** 2451,2463 **** (put 'display-time-string 'risky-local-variable t) (put 'parse-time-rules 'risky-local-variable t) - ;; This case is safe because the user gets to check it before it is used. - (put 'compile-command 'safe-local-variable 'stringp) - (defun risky-local-variable-p (sym &optional val) ! "Non-nil if SYM could be dangerous as a file-local variable with value VAL. ! If VAL is nil or omitted, the question is whether any value might be ! dangerous." ;; If this is an alias, check the base name. (condition-case nil (setq sym (indirect-variable sym)) --- 2463,2482 ---- (put 'display-time-string 'risky-local-variable t) (put 'parse-time-rules 'risky-local-variable t) (defun risky-local-variable-p (sym &optional val) ! "Non-nil if SYM is dangerous as a file-local variable with value VAL. ! A variable is dangerous if any of the following conditions are met: ! ! * Its `risky-local-variable' property is non-nil (regardless of VAL). ! ! * Its `safe-local-variable' property is unset, and its name ends with ! \"hook(s)\", \"function(s)\", \"form(s)\", \"map\", \"program\", ! \"command(s)\", \"predicate(s)\", \"frame-alist\", \"mode-alist\", ! \"font-lock-keyword*\", \"font-lock-syntactic-keywords\", or ! \"map-alist\" (regardless of VAL). ! ! * Its `safe-local-variable' property is a function that ! evaluates to a non-nil value when given VAL as an argument." ;; If this is an alias, check the base name. (condition-case nil (setq sym (indirect-variable sym)) *************** *** 2540,2562 **** ((memq var ignored-local-variables) nil) ;; "Setting" eval means either eval it or do nothing. ! ;; Likewise for setting hook variables. ! ((risky-local-variable-p var val) ! ;; Permit evalling a put of a harmless property. ! ;; if the args do nothing tricky. ! (if (or (and (eq var 'eval) ! (hack-one-local-variable-eval-safep val)) ! ;; Permit eval if not root and user says ok. ! (and (not (zerop (user-uid))) ! (hack-local-variables-confirm ! "Process `eval' or hook local variables in %s? " ! enable-local-eval))) ! (if (eq var 'eval) ! (save-excursion (eval val)) ! (make-local-variable var) ! (set var val)) ! (message "Ignoring risky spec in the local variables list"))) ! ;; Ordinary variable, really set it. (t (make-local-variable var) ;; Make sure the string has no text properties. ;; Some text properties can get evaluated in various ways, --- 2559,2573 ---- ((memq var ignored-local-variables) nil) ;; "Setting" eval means either eval it or do nothing. ! ((eq var 'eval) ! (if (hack-one-local-variable-eval-safep val) ! (save-excursion (eval val)) ! (message "Ignoring eval spec in the local variables list"))) ! ;; Variables not explicitly marked as safe, ask first. ! ((not (memq var safe-local-variables)) ! (unless (zerop (user-uid)) ! (hack-one-risky-local-variable var val))) ! ;; Safe variable, really set it. (t (make-local-variable var) ;; Make sure the string has no text properties. ;; Some text properties can get evaluated in various ways, *************** *** 2565,2570 **** --- 2576,2608 ---- (set-text-properties 0 (length val) nil val)) (set var val)))) + (defun hack-one-risky-local-variable (var val) + "Set local variable VAR with value VAL if the user agrees. + If the user agrees to set the variable, and the variable is not + explicitly marked as risky (see `risky-local-variable-p'), + additionally ask if it can always be set automatically. + If so, add it to `safe-local-variables'." + (let ((risky (risky-local-variable-p var val))) + (if (y-or-n-p (format "Set variable %s in local variable list of %s? " + (symbol-name var) + (if buffer-file-name + (file-name-nondirectory buffer-file-name) + (concat "buffer " (buffer-name))))) + (progn + (when (and (not risky) + (y-or-n-p (format "Always allow setting %s? " + (symbol-name var)))) + (customize-save-variable + 'safe-local-variables + (add-to-list 'safe-local-variables var)) + (message + "To undo this change, customize `safe-local-variables'.")) + (make-local-variable var) + (set var val)) + (unless risky + (message "To always ignore %s as a local variable, \ + customize `ignored-local-variables'." + (symbol-name var)))))) (defcustom change-major-mode-with-file-name t "*Non-nil means \\[write-file] should set the major mode from the file name.