Open Harag opened 4 years ago
I had to tweak translate-form to deal with defun and defmacro. Because we are now keeping more detailed track of which functions are allowed and which are not I have to update the tracking while parsing defun(s). There might be a better way to do it, for instance to move tracking down to isolated-cl and making the macros deal with it but for now the current hack should work for most scenarios.
;; To keep track of functions created by user in the scripts/code
(defparameter *allowed-internal-functions* nil)
;; keeping track of previous form in translate so that I can identify which functions are added in the
;; form submitted
(defparameter *previous-form* nil)
(defun translate-form (form)
(when (and (consp form)
(circular-tree-p form))
(error 'circular-list))
(let ((cons-count 0))
(labels ((translate (form)
(typecase form
(cons (if (> (incf cons-count) *max-elements*)
(error 'dimension-error)
(cons (translate (car form))
(translate (cdr form)))))
(number form)
(character form)
(pathname form)
(array (if (> (array-total-size form) *max-elements*)
(error 'dimension-error)
(let ((arr (make-array (array-dimensions form)
:element-type
(array-element-type form))))
(dotimes (i (array-total-size arr) arr)
(setf (row-major-aref arr i)
(translate-form
(row-major-aref form i)))))))
(keyword form)
(symbol
(when (or (equalp *previous-form* 'isolated-cl::defun)
(equalp *previous-form* 'isolated-cl::defmacro)
(equalp *previous-form* 'cl::defun)
(equalp *previous-form* 'cl::defmacro))
(pushnew form *allowed-internal-functions*))
(let ((final-form
(if (fboundp form)
(or (find form *allowed-isolated-functions*)
(find form *allowed-packages-functions*)
(find form *allowed-internal-functions*)
(or
(and (equalp form 'isolated-cl::defun) form)
(and (equalp form 'isolated-cl::defmacro) form)
(and (equalp form 'cl:defun) form)
(and (equalp form 'cl:defmacro) form))
(error 'undefined-function :name form))
(if (or (find form *allowed-isolated-symbols*)
(find form *allowed-packages-symbols*))
form
(intern (symbol-name form) *env*)))))
(setf *previous-form* final-form)
final-form))
(t (error 'unsupported-type :type (type-of form))))))
(translate form))))
To make cl-isolated to work better as a scripting engine we need the following changes. I have implemented those changes in the eval-return-values branch.
Please comment.
I might have gone a bit over board with code etc in the discussion but since its the first majour change to cl-isolated in many moons I would like the communication to be clear.
For that to work I need to make a compatibility breaking change.
Functions etc to add functionality to cl-isolated:
a. Throw an error if something is not allowed by cl-isolate
To not have to loop each time the check needs to be done we need the following convenience function and vars
b. Differentiate between symbols and functions when translating code and throwing errors.
+
(defun reset () (setf isolated-impl::allowed-isolated-symbols nil) (setf isolated-impl::allowed-isolated-functions nil) (setf isolated-impl::allowed-packages-symbols nil) (setf isolated-impl::allowed-packages-functions nil)
(isolated-allowed-symbols)
(ignore-errors (delete-package env)) (make-package env :use '(#:isolated-cl)) (loop :for name :in '("+" "++" "+++" "" "" "" "/" "//" "///" "-") :do (eval
(defparameter ,(intern name *env*) nil))) (loop :for fn :in '(+ - * /) :for symbol := (intern (symbol-name fn) *env*) :do (setf (get symbol :isolated-locked) t) (eval
(defun ,symbol (&rest args) (apply ',fn args)))) env)(defun read-no-eval (forms &key packages exclude-symbols) "Returns forms and/or any messages." (unless (or (find-package env) (reset))
(return-from read-no-eval "ISOLATED-PACKAGE-ERROR: Isolated package not found."))
(allow-package-symbols packages exclude-symbols)
(let ((validated-forms) (msg))
(defun read-eval (forms &key packages exclude-symbols) "Returns eval values and/or any messages."
(unless (or (find-package env) (reset)) (return-from read-eval (values nil "ISOLATED-PACKAGE-ERROR: Isolated package not found.")))
(allow-package-symbols packages exclude-symbols)
(with-isolated-env (let ((values) (msg))
(defun ssetq (name value) (setf (symbol-value (find-symbol (string-upcase name) env)) value))
(defun read-eval-print (forms &optional (stream standard-output)) (unless (or (find-package env) (reset)) (msge stream "ISOLATED-PACKAGE-ERROR: Isolated package not found.") (return-from read-eval-print nil))
(with-isolated-env (let (form)
nil)
Examples Allowing additional functions: