summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2026-05-20 09:09:21 -0700
committerPaul Eggert <eggert@cs.ucla.edu>2026-05-23 19:18:52 -0700
commit4d85084509a13fdc15ca38e6885a6a8e30e77425 (patch)
tree0bc13a0f4b4a6dc2941aab4114f20c5319f00112 /src
parent5fd1e0bbef85119527129da8bc645c102434ab28 (diff)
Fix unlikely json.c size overflow calculations
* src/json.c (json_out_grow_buf) (json_make_object_workspace_for_slow_path) (json_byte_workspace_put_slow_path): Use xpalloc rather than doing it by hand. * src/json.c (json_out_grow_buf): Change arg from needed bytes to minimum increment of bytes. Caller changed.
Diffstat (limited to 'src')
-rw-r--r--src/json.c86
1 files changed, 29 insertions, 57 deletions
diff --git a/src/json.c b/src/json.c
index 9b07f8ced26..720654bac43 100644
--- a/src/json.c
+++ b/src/json.c
@@ -244,13 +244,10 @@ symset_add (json_out_t *jo, symset_t *ss, Lisp_Object sym)
}
static NO_INLINE void
-json_out_grow_buf (json_out_t *jo, ptrdiff_t bytes)
+json_out_grow_buf (json_out_t *jo, ptrdiff_t incr_min)
{
- ptrdiff_t need = jo->size + bytes;
- ptrdiff_t new_size = max (jo->capacity, 512);
- while (new_size < need)
- new_size <<= 1;
- jo->buf = xrealloc (jo->buf, new_size);
+ ptrdiff_t new_size = jo->capacity;
+ jo->buf = xpalloc (jo->buf, &new_size, incr_min, -1, 1);
jo->capacity = new_size;
}
@@ -267,8 +264,9 @@ cleanup_json_out (void *arg)
static void
json_make_room (json_out_t *jo, ptrdiff_t bytes)
{
- if (bytes > jo->capacity - jo->size)
- json_out_grow_buf (jo, bytes);
+ ptrdiff_t avail = jo->capacity - jo->size;
+ if (avail < bytes)
+ json_out_grow_buf (jo, bytes - avail);
}
#define JSON_OUT_STR(jo, str) (json_out_str (jo, str, sizeof (str) - 1))
@@ -803,36 +801,20 @@ json_parser_done (void *parser)
Lisp_Objects */
NO_INLINE static void
json_make_object_workspace_for_slow_path (struct json_parser *parser,
- size_t size)
+ ptrdiff_t size)
{
- size_t needed_workspace_size
- = (parser->object_workspace_current + size);
- size_t new_workspace_size = parser->object_workspace_size;
- while (new_workspace_size < needed_workspace_size)
- {
- if (ckd_mul (&new_workspace_size, new_workspace_size, 2))
- {
- json_signal_error (parser, Qjson_out_of_memory);
- }
- }
-
- Lisp_Object *new_workspace_ptr;
- if (parser->object_workspace_size
- == JSON_PARSER_INTERNAL_OBJECT_WORKSPACE_SIZE)
- {
- new_workspace_ptr
- = xnmalloc (new_workspace_size, sizeof (Lisp_Object));
- memcpy (new_workspace_ptr, parser->object_workspace,
- (sizeof (Lisp_Object)
- * parser->object_workspace_current));
- }
- else
- {
- new_workspace_ptr
- = xnrealloc (parser->object_workspace, new_workspace_size,
- sizeof (Lisp_Object));
- }
-
+ bool internal = (parser->object_workspace_size
+ == JSON_PARSER_INTERNAL_OBJECT_WORKSPACE_SIZE);
+ ptrdiff_t new_workspace_size = parser->object_workspace_size;
+ Lisp_Object *new_workspace_ptr
+ = xpalloc (internal ? NULL : parser->object_workspace,
+ &new_workspace_size,
+ size - (parser->object_workspace_size
+ - parser->object_workspace_current),
+ -1, sizeof (Lisp_Object));
+ if (internal)
+ memcpy (new_workspace_ptr, parser->object_workspace,
+ sizeof (Lisp_Object) * parser->object_workspace_current);
parser->object_workspace = new_workspace_ptr;
parser->object_workspace_size = new_workspace_size;
}
@@ -854,33 +836,23 @@ json_byte_workspace_reset (struct json_parser *parser)
parser->byte_workspace_current = parser->byte_workspace;
}
-/* Puts 'value' into the byte_workspace. If there is no space
- available, it allocates space */
+/* Put VALUE into the byte_workspace, allocating space. */
NO_INLINE static void
json_byte_workspace_put_slow_path (struct json_parser *parser,
unsigned char value)
{
- size_t new_workspace_size
+ ptrdiff_t new_workspace_size
= parser->byte_workspace_end - parser->byte_workspace;
- if (ckd_mul (&new_workspace_size, new_workspace_size, 2))
- {
- json_signal_error (parser, Qjson_out_of_memory);
- }
-
- size_t offset
+ ptrdiff_t offset
= parser->byte_workspace_current - parser->byte_workspace;
- if (parser->byte_workspace == parser->internal_byte_workspace)
- {
- parser->byte_workspace = xmalloc (new_workspace_size);
- memcpy (parser->byte_workspace, parser->internal_byte_workspace,
- offset);
- }
- else
- {
- parser->byte_workspace
- = xrealloc (parser->byte_workspace, new_workspace_size);
- }
+ bool internal = parser->byte_workspace == parser->internal_byte_workspace;
+ unsigned char *new
+ = xpalloc (internal ? NULL : parser->byte_workspace,
+ &new_workspace_size, 1, -1, 1);
+ if (internal)
+ memcpy (new, parser->byte_workspace, offset);
+ parser->byte_workspace = new;
parser->byte_workspace_end
= parser->byte_workspace + new_workspace_size;
parser->byte_workspace_current = parser->byte_workspace + offset;