From 45798a206304aa16b5f78e871fbe1d9d9b31732f Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Tue, 26 Nov 2024 13:22:41 -0600 Subject: [PATCH] Fix read of number followed by EOF can break subsequent read from seeing EOF --- README.md | 3 ++- src/main/clojure/clojure/data/json.clj | 18 ++++++++++++++---- src/test/clojure/clojure/data/json_test.clj | 18 ++++++++++++++++++ 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index a4e8901..0cd9fde 100644 --- a/README.md +++ b/README.md @@ -151,7 +151,8 @@ Change Log ---------------------------------------- * next - * In `read`, update docstring to specify minimum buffer size if PushbackReader supplied + * Fix: `read` of number followed by EOF can break subsequent read from seeing EOF + * In `read`, update docstring to specify minimum buffer size when PushbackReader supplied * Release [2.5.0] on 2023-Dec-21 * Fix [DJSON-50]: `read` can take a PushbackReader for repeated read use case * Fix `write` docstring to add `:indent` option added in [DJSON-18] diff --git a/src/main/clojure/clojure/data/json.clj b/src/main/clojure/clojure/data/json.clj index 76a3e53..2eb1588 100644 --- a/src/main/clojure/clojure/data/json.clj +++ b/src/main/clojure/clojure/data/json.clj @@ -33,6 +33,7 @@ (readChars [_ buffer start bufflen] (.read rdr ^chars buffer start bufflen)) (unreadChar [_ c] + ;; ASSERT: c should never be -1 (EOF) (.unread rdr c)) (unreadChars [_ buffer start bufflen] (.unread rdr buffer start bufflen)) @@ -63,6 +64,7 @@ (.getChars ^String s p end ^chars buffer start))) (if (pos? n) n -1))) (unreadChar [_ _c] + ;; ASSERT: c should never be -1 (EOF) (set! pos (unchecked-dec pos)) nil) (unreadChars [_ _buffer _start bufflen] @@ -234,9 +236,11 @@ :whitespace (do (.unreadChar stream c) false) - (\, \] \} -1) + (\, \] \}) (do (.unreadChar stream c) false) + -1 + false (throw (Exception. "JSON error (invalid number literal)"))) ;; previous character is a "0" :frac-point @@ -251,9 +255,11 @@ :whitespace (do (.unreadChar stream c) false) - (\, \] \} -1) + (\, \] \}) (do (.unreadChar stream c) false) + -1 + false ;; Disallow zero-padded numbers or invalid characters (throw (Exception. "JSON error (invalid number literal)"))) ;; previous character is a "." @@ -276,9 +282,11 @@ :whitespace (do (.unreadChar stream c) true) - (\, \] \} -1) + (\, \] \}) (do (.unreadChar stream c) true) + -1 + true (throw (Exception. "JSON error (invalid number literal)"))) ;; previous character is a "e" or "E" :exp-symbol @@ -306,9 +314,11 @@ :whitespace (do (.unreadChar stream c) true) - (\, \] \} -1) + (\, \] \}) (do (.unreadChar stream c) true) + -1 + true (throw (Exception. "JSON error (invalid number literal)"))))))] (if decimal? (read-decimal (str buffer) bigdec?) diff --git a/src/test/clojure/clojure/data/json_test.clj b/src/test/clojure/clojure/data/json_test.clj index 2f78fcd..aa6d79c 100644 --- a/src/test/clojure/clojure/data/json_test.clj +++ b/src/test/clojure/clojure/data/json_test.clj @@ -27,6 +27,24 @@ (is (= {"foo" "some string"} (json/read pbr))) (is (= {"foo" "another long ......................................................... string"} (json/read pbr))))) +(defn read-then-eof [s] + (let [r (pbr s) + val (json/read r :eof-error? false :eof-value :EOF)] + (is (= :EOF (json/read r :eof-error? false :eof-value :EOF))) + val)) + +(deftest read-multiple-eof + (are [expected s] (= expected (read-then-eof s)) + 1.2 "1.2" + 0 "0" + 1 "1" + 1.0 "1.0" + "abc" "\"abc\"" + "\u2202" "\"\u2202\"" + [] "[]" + [1 2] "[1, 2]") + ) + (deftest read-from-reader (let [s (java.io.StringReader. "42")] (is (= 42 (json/read s)))))