How do you securely parse untrusted input in Common Lisp? Given that there is no parse-float etc, and that read-from-string will execute reader macros like #. (read time eval).
e.g. (read-from-string "#.(+ 1 2)") => 3
I can't find the other question or comment that described some of the safe input handling procedures for Common Lisp (if someone else finds them, please post a comment!), but there are at least two important things that you might do:
(let ((*readtable* (copy-readtable)))
(set-macro-character #\n (constantly 'injected))
(read-from-string "(#.(+ 2 5) n)"))
;;=> (7 INJECTED)
(let ((*readtable* (copy-readtable)))
(set-macro-character #\n (constantly 'injected))
(with-standard-io-syntax
(let ((*read-eval* nil))
(read-from-string "(#.(+ 2 5) n)"))))
;; Evaluation aborted on #<SB-INT:SIMPLE-READER-ERROR
;; "can't read #. while *READ-EVAL* is NIL" {1004DA3603}>.
(let ((*readtable* (copy-readtable)))
(set-macro-character #\n (constantly 'injected))
(list (read-from-string "(n)")
(with-standard-io-syntax
(let ((*read-eval* nil))
(read-from-string "(n)")))))
;; ((INJECTED) (N))
Generally, just that the standard code reader is so readily available and can read many kinds of input does not mean that you should use it to read anything but code.
There are many libraries for parsing a lot of things, e. g. parse-number
for the Lisp number formats, fare-csv
for CSV files (among many other CSV libraries), json-streams
for JSON (again, many others). For most formats, you can just do a system-apropos
lookup with Quicklisp.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With