emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Risky local variable mechanism


From: Chong Yidong
Subject: Re: Risky local variable mechanism
Date: Tue, 07 Feb 2006 11:45:57 -0500
User-agent: Gnus/5.11 (Gnus v5.11) Emacs/22.0.50 (gnu/linux)

"Richard M. Stallman" <address@hidden> 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.




reply via email to

[Prev in Thread] Current Thread [Next in Thread]