From 67e34f0ed8f6d3bbc78187a18f71010c70e10426 Mon Sep 17 00:00:00 2001 From: Pip Cet Date: Fri, 28 Mar 2025 02:33:19 +0000 Subject: [PATCH] Respect narrowed buffers when parsing JSON (bug#77325) * src/json.c (Fjson_insert): Simplify 'memcpy' argument. (Fjson_parse_buffer): Only read to ZV, not all the way to Z. * test/src/json-tests.el (with-all-gap-positions-in-temp-buffer): New macro. (json-parse-buffer/restricted): New test. --- src/json.c | 13 +++++++------ test/src/json-tests.el | 26 ++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/src/json.c b/src/json.c index f438d191bde..5795c582ce0 100644 --- a/src/json.c +++ b/src/json.c @@ -641,7 +641,7 @@ usage: (json-insert OBJECT &rest ARGS) */) move_gap_both (PT, PT_BYTE); if (GAP_SIZE < jo.size) make_gap (jo.size - GAP_SIZE); - memcpy ((char *) BEG_ADDR + PT_BYTE - BEG_BYTE, jo.buf, jo.size); + memcpy (GPT_ADDR, jo.buf, jo.size); /* No need to keep allocation beyond this point. */ unbind_to (count, Qnil); @@ -1754,15 +1754,16 @@ usage: (json-parse-buffer &rest args) */) struct json_parser p; unsigned char *begin = PT_ADDR; - unsigned char *end = GPT_ADDR; + unsigned char *end = (GPT == ZV) ? GPT_ADDR : ZV_ADDR; unsigned char *secondary_begin = NULL; unsigned char *secondary_end = NULL; - if (GPT_ADDR < Z_ADDR) + if (PT == ZV) + begin = end = NULL; + else if (GPT > PT && GPT < ZV && GAP_SIZE > 0) { + end = GPT_ADDR; secondary_begin = GAP_END_ADDR; - if (secondary_begin < PT_ADDR) - secondary_begin = PT_ADDR; - secondary_end = Z_ADDR; + secondary_end = ZV_ADDR; } json_parser_init (&p, conf, begin, end, secondary_begin, diff --git a/test/src/json-tests.el b/test/src/json-tests.el index 94b6cfcffca..1cb667ddeac 100644 --- a/test/src/json-tests.el +++ b/test/src/json-tests.el @@ -315,6 +315,32 @@ Test with both unibyte and multibyte strings." (should-not (bobp)) (should (looking-at-p (rx " [456]" eos))))) +(defmacro with-all-gap-positions-in-temp-buffer (string &rest body) + "Create a temporary buffer containing STRING, and evaluate BODY +with each possible gap position. +See also `with-temp-buffer'." + `(with-temp-buffer + (insert ,string) + (dotimes (i (- (point-max) (point-min))) + (goto-char (- (point-max) i)) + (insert "X") + (delete-region (1- (point)) (point)) + ,@body))) + +(ert-deftest json-parse-buffer/restricted () + (with-all-gap-positions-in-temp-buffer + "[123] [456] [789]" + (pcase-dolist (`((,beg . ,end) ,result) + '(((7 . 12) [456]) + ((1 . 6) [123]) + ((13 . 18) [789]))) + (goto-char beg) + (narrow-to-region beg end) + (should (equal (json-parse-buffer) result)) + (should (= (point) end)) + (should-error (json-parse-buffer) :type 'json-end-of-file) + (widen)))) + (ert-deftest json-parse-with-custom-null-and-false-objects () (let* ((input "{ \"abc\" : [9, false] , \"def\" : null }")