All of lore.kernel.org
 help / color / mirror / Atom feed
* [LTP] [PATCH] lib: ujson: Update to ujson 1.0
@ 2026-11-09 16:32 Cyril Hrubis
  2026-11-10 13:06 ` [LTP] " linuxtestproject.agent
  0 siblings, 1 reply; 2+ messages in thread
From: Cyril Hrubis @ 2026-11-09 16:32 UTC (permalink / raw)
  To: ltp

Update the bundled ujson library to ujson 1.0.

Includes the fixes send from Andrea + couple of more.

Signed-off-by: Cyril Hrubis <chrubis@suse.cz>
---
 include/ujson.h           |  6 +--
 include/ujson_common.h    |  8 ++--
 include/ujson_reader.h    | 14 +++---
 include/ujson_utf.h       | 14 +++---
 include/ujson_writer.h    |  2 +-
 libs/ujson/ujson_common.c |  1 +
 libs/ujson/ujson_reader.c | 97 ++++++++++++++++++++++++++-------------
 libs/ujson/ujson_writer.c | 62 +++++++++++++++++--------
 8 files changed, 132 insertions(+), 72 deletions(-)

diff --git a/include/ujson.h b/include/ujson.h
index 1a4bb6bd9..8faeb18f0 100644
--- a/include/ujson.h
+++ b/include/ujson.h
@@ -3,11 +3,11 @@
  * Copyright (C) 2021-2024 Cyril Hrubis <metan@ucw.cz>
  */
 
-#ifndef UJSON_H__
-#define UJSON_H__
+#ifndef UJSON_H
+#define UJSON_H
 
 #include <ujson_common.h>
 #include <ujson_reader.h>
 #include <ujson_writer.h>
 
-#endif /* UJSON_H__ */
+#endif /* UJSON_H */
diff --git a/include/ujson_common.h b/include/ujson_common.h
index 1eaf3fc72..ed31c090d 100644
--- a/include/ujson_common.h
+++ b/include/ujson_common.h
@@ -8,12 +8,12 @@
  * @brief Common JSON reader/writer definitions.
  */
 
-#ifndef UJSON_COMMON_H__
-#define UJSON_COMMON_H__
+#ifndef UJSON_COMMON_H
+#define UJSON_COMMON_H
 
 /** @brief Maximal error message length. */
 #define UJSON_ERR_MAX 128
-/** @brief Maximal id string length including terminating null element. */
+/** @brief Maximal id string lenght including terminating null element. */
 #define UJSON_ID_MAX 64
 /** @brief Maximal recursion depth allowed. */
 #define UJSON_RECURSION_MAX 128
@@ -66,4 +66,4 @@ typedef struct ujson_val ujson_val;
 /** @brief An array size macro. */
 #define UJSON_ARRAY_SIZE(array) (sizeof(array) / sizeof(*array))
 
-#endif /* UJSON_COMMON_H__ */
+#endif /* UJSON_COMMON_H */
diff --git a/include/ujson_reader.h b/include/ujson_reader.h
index 3722fffea..273fe624a 100644
--- a/include/ujson_reader.h
+++ b/include/ujson_reader.h
@@ -14,8 +14,8 @@
  * if error has happened at the end of the sequence.
  */
 
-#ifndef UJSON_READER_H__
-#define UJSON_READER_H__
+#ifndef UJSON_READER_H
+#define UJSON_READER_H
 
 #include <stdio.h>
 #include <ujson_common.h>
@@ -24,7 +24,7 @@
  * @brief An ujson_reader initializer with default values.
  *
  * @param buf A pointer to a buffer with JSON data.
- * @param buf_len A JSON data buffer length.
+ * @param buf_len A JSON data buffer lenght.
  * @param rflags enum ujson_reader_flags.
  *
  * @return An ujson_reader initialized with default values.
@@ -96,7 +96,7 @@ struct ujson_val {
 	 */
 	enum ujson_type type;
 
-	/** A user supplied buffer and size to store a string values to. */
+	/** An user supplied buffer and size to store a string values to. */
 	char *buf;
 	size_t buf_size;
 
@@ -108,7 +108,7 @@ struct ujson_val {
 	 */
 	size_t idx;
 
-	/** A union to store the parsed value into. */
+	/** An union to store the parsed value into. */
 	union {
 		/** @brief A boolean value. */
 		int val_bool;
@@ -311,7 +311,7 @@ static inline size_t ujson_obj_lookup(const ujson_obj *obj, const char *key)
 #define UJSON_OBJ_ATTR(keyv, typev) \
 	{.key = keyv, .type = typev}
 
-/** @brief An ujson_obj_attr initializer with an array index. */
+/** @brief An ujson_obj_attr intializer with an array index. */
 #define UJSON_OBJ_ATTR_IDX(key_idx, keyv, typev) \
 	[key_idx] = {.key = keyv, .type = typev}
 
@@ -540,4 +540,4 @@ static inline int ujson_reader_consumed(ujson_reader *self)
 	return self->off >= self->len;
 }
 
-#endif /* UJSON_H__ */
+#endif /* UJSON_H */
diff --git a/include/ujson_utf.h b/include/ujson_utf.h
index 83fe8ab09..1e3d47c0b 100644
--- a/include/ujson_utf.h
+++ b/include/ujson_utf.h
@@ -8,8 +8,8 @@
  * @brief Unicode helper macros and functions.
  */
 
-#ifndef UJSON_UTF_H__
-#define UJSON_UTF_H__
+#ifndef UJSON_UTF_H
+#define UJSON_UTF_H
 
 #include <stdint.h>
 #include <stddef.h>
@@ -65,15 +65,15 @@ static inline uint32_t ujson_utf8_next(const char **str)
 	if (UJSON_UTF8_IS_3BYTE(s0))
 		return (s0 & 0x0f)<<12 | s1<<6 | s2;
 
-	(*str)++;
-
 	uint32_t s3 = *str[0];
 
-	if (!UJSON_UTF8_IS_NBYTE(s2))
+	if (!UJSON_UTF8_IS_NBYTE(s3))
 		return 0;
 
 	s3 &= UJSON_UTF8_NBYTE_MASK;
 
+	(*str)++;
+
 	if (UJSON_UTF8_IS_4BYTE(s0))
 		return (s0 & 0x07)<<18 | s1<<12 | s2<<6 | s3;
 
@@ -130,7 +130,7 @@ static inline unsigned int ujson_utf8_bytes(uint32_t unicode)
 }
 
 /**
- * @brief Writes a Unicode character into a UTF-8 buffer.
+ * @brief Writes an unicode character into a UTF-8 buffer.
  *
  * The buffer _must_ be large enough!
  *
@@ -165,4 +165,4 @@ static inline int ujson_to_utf8(uint32_t unicode, char *buf)
 	return 4;
 }
 
-#endif /* UJSON_UTF_H__ */
+#endif /* UJSON_UTF_H */
diff --git a/include/ujson_writer.h b/include/ujson_writer.h
index 30d2e92f6..dfcc95053 100644
--- a/include/ujson_writer.h
+++ b/include/ujson_writer.h
@@ -46,7 +46,7 @@ struct ujson_writer {
  * @brief An ujson_writer initializer with default values.
  *
  * @param vout A pointer to function to write out the data.
- * @param vout_priv A user pointer passed to the out function.
+ * @param vout_priv An user pointer passed to the out function.
  *
  * @return An ujson_writer initialized with default values.
  */
diff --git a/libs/ujson/ujson_common.c b/libs/ujson/ujson_common.c
index 639955229..c9cada9a9 100644
--- a/libs/ujson/ujson_common.c
+++ b/libs/ujson/ujson_common.c
@@ -35,3 +35,4 @@ const char *ujson_type_name(enum ujson_type type)
 		return "invalid";
 	}
 }
+
diff --git a/libs/ujson/ujson_reader.c b/libs/ujson/ujson_reader.c
index 9f86f25b7..964878b51 100644
--- a/libs/ujson/ujson_reader.c
+++ b/libs/ujson/ujson_reader.c
@@ -11,6 +11,7 @@
 #include <string.h>
 #include <stdarg.h>
 #include <stdint.h>
+#include <limits.h>
 
 #include "ujson_utf.h"
 #include "ujson_reader.h"
@@ -134,8 +135,36 @@ static unsigned int parse_ucode_esc(ujson_reader *buf, char *str,
 	if (ucode < 0)
 		return 0;
 
+	if (ucode >= 0xdc00 && ucode <= 0xdfff) {
+		ujson_err(buf, "Unpaired low surrogate");
+		return 0;
+	}
+
+	if (ucode >= 0xd800 && ucode <= 0xdbff) {
+		int32_t low;
+
+		if (peekb(buf) != '\\' || peekb_off(buf, 1) != 'u') {
+			ujson_err(buf, "Unpaired high surrogate");
+			return 0;
+		}
+
+		getb(buf);
+		getb(buf);
+
+		low = parse_ucode_cp(buf);
+		if (low < 0)
+			return 0;
+
+		if (low < 0xdc00 || low > 0xdfff) {
+			ujson_err(buf, "Invalid low surrogate in escape sequence");
+			return 0;
+		}
+
+		ucode = 0x10000 + (((ucode - 0xd800) << 10) | (low - 0xdc00));
+	}
+
 	if (!str)
-		return ucode;
+		return ujson_utf8_bytes(ucode);
 
 	if (ujson_utf8_bytes(ucode) + 1 >= len - off) {
 		ujson_err(buf, "String buffer too short!");
@@ -229,31 +258,15 @@ static int copy_str(ujson_reader *buf, char *str, size_t len)
 
 static int copy_id_str(ujson_reader *buf, char *str, size_t len)
 {
-	size_t pos = 0;
-
 	if (eatws(buf))
 		goto err0;
 
-	if (!eatb(buf, '"'))
+	if (peekb(buf) != '"')
 		goto err0;
 
-	for (;;) {
-		if (buf_empty(buf)) {
-			ujson_err(buf, "Unterminated ID string");
-			return 1;
-		}
-
-		if (eatb(buf, '"')) {
-			str[pos] = 0;
-			break;
-		}
-
-		if (pos >= len-1) {
-			ujson_err(buf, "ID string too long");
-			return 1;
-		}
-
-		str[pos++] = getb(buf);
+	if (copy_str(buf, str, len)) {
+		ujson_err(buf, "Unterminated ID string");
+		return 1;
 	}
 
 	if (eatws(buf))
@@ -283,7 +296,7 @@ static int is_digit(char b)
 
 static int get_int(ujson_reader *buf, struct ujson_val *res)
 {
-	long val = 0;
+	unsigned long val = 0;
 	int sign = 1;
 
 	if (eatb(buf, '-')) {
@@ -299,17 +312,28 @@ static int get_int(ujson_reader *buf, struct ujson_val *res)
 		return 1;
 	}
 
+	unsigned long max = LONG_MAX;
+
+	if (sign < 0)
+		max++;
+
 	while (is_digit(peekb(buf))) {
-		val *= 10;
-		val += getb(buf) - '0';
-		//TODO: overflow?
+		unsigned int d = getb(buf) - '0';
+
+		if (val > (max - d) / 10) {
+			ujson_err(buf, "Integer overflow");
+			return 1;
+		}
+
+		val = val * 10 + d;
 	}
 
 	if (sign < 0)
-		val = -val;
+		res->val_int = -(long)val;
+	else
+		res->val_int = (long)val;
 
-	res->val_int = val;
-	res->val_float = val;
+	res->val_float = res->val_int;
 
 	return 0;
 }
@@ -669,8 +693,10 @@ static int skip_obj_val(ujson_reader *buf)
 
 static int obj_next(ujson_reader *buf, struct ujson_val *res)
 {
-	if (copy_id_str(buf, res->id, sizeof(res->id)))
+	if (copy_id_str(buf, res->id, sizeof(res->id))) {
+		res->type = UJSON_VOID;
 		return 0;
+	}
 
 	return get_value(buf, res);
 }
@@ -695,8 +721,10 @@ static int obj_next_filter(ujson_reader *buf, struct ujson_val *res,
 	const struct ujson_obj_attr *attr;
 
 	for (;;) {
-		if (copy_id_str(buf, res->id, sizeof(res->id)))
+		if (copy_id_str(buf, res->id, sizeof(res->id))) {
+			res->type = UJSON_VOID;
 			return 0;
+		}
 
 		res->idx = obj ? ujson_obj_lookup(obj, res->id) : (size_t)-1;
 
@@ -1032,6 +1060,11 @@ ujson_reader *ujson_reader_load(const char *path)
 			goto err1;
 		}
 
+		if (res == 0) {
+			fprintf(stderr, "read() returned 0 (file was truncated?)\n");
+			goto err1;
+		}
+
 		off += res;
 	}
 
@@ -1047,9 +1080,9 @@ err0:
 
 void ujson_reader_finish(ujson_reader *self)
 {
-	if (ujson_reader_err(self))
+	if (ujson_reader_err(self)) {
 		ujson_err_print(self);
-	else if (!ujson_reader_consumed(self)) {
+	} else if (!ujson_reader_consumed(self)) {
 		ujson_warn(self, "Garbage after JSON string!");
 
 		if (ujson_reader_err(self))
diff --git a/libs/ujson/ujson_writer.c b/libs/ujson/ujson_writer.c
index c86a3b2af..214e20846 100644
--- a/libs/ujson/ujson_writer.c
+++ b/libs/ujson/ujson_writer.c
@@ -97,13 +97,6 @@ static inline int out_ch(ujson_writer *self, char ch)
 	return out(self, &ch, 1);
 }
 
-#define ESC_FLUSH(esc_char) do {\
-	out(self, val, i); \
-	val += i + 1; \
-	i = 0; \
-	out_str(self, esc_char); \
-} while (0)
-
 static inline int out_esc_str(ujson_writer *self, const char *val)
 {
 	if (out_ch(self, '"'))
@@ -116,32 +109,46 @@ static inline int out_esc_str(ujson_writer *self, const char *val)
 		next_chsz = ujson_utf8_next_chsz(val, i);
 
 		if (next_chsz == 1) {
+			char *esc_str = NULL;
+
 			switch (val[i]) {
 			case '\"':
-				ESC_FLUSH("\\\"");
+				esc_str = "\\\"";
 			break;
 			case '\\':
-				ESC_FLUSH("\\\\");
+				esc_str = "\\\\";
 			break;
 			case '/':
-				ESC_FLUSH("\\/");
+				esc_str = "\\/";
 			break;
 			case '\b':
-				ESC_FLUSH("\\b");
+				esc_str = "\\b";
 			break;
 			case '\f':
-				ESC_FLUSH("\\f");
+				esc_str = "\\f";
 			break;
 			case '\n':
-				ESC_FLUSH("\\n");
+				esc_str = "\\n";
 			break;
 			case '\r':
-				ESC_FLUSH("\\r");
+				esc_str = "\\r";
 			break;
 			case '\t':
-				ESC_FLUSH("\\t");
+				esc_str = "\\t";
 			break;
-			default:
+			}
+
+			/* flush buffer, write escape */
+			if (esc_str) {
+				if (out(self, val, i))
+					return 1;
+
+				val += i + 1;
+				i = 0;
+
+				if (out_str(self, esc_str))
+					return 1;
+			} else {
 				i += next_chsz;
 			}
 		} else {
@@ -389,15 +396,25 @@ struct json_writer_file {
 
 static int out_writer_file_write(ujson_writer *self, int fd, const char *buf, ssize_t buf_len)
 {
+	if (!buf_len)
+		return 0;
+
 	do {
 		ssize_t ret = write(fd, buf, buf_len);
-		if (ret <= 0) {
+		if (ret < 0) {
 			err(self, "Failed to write to a file");
 			return 1;
 		}
 
+		if (ret == 0) {
+			err(self, "The write() syscall returned 0");
+			errno = EAGAIN;
+			return 1;
+		}
+
 		if (ret > buf_len) {
 			err(self, "Wrote more bytes than requested?!");
+			errno = EIO;
 			return 1;
 		}
 
@@ -413,8 +430,15 @@ static int out_writer_file(ujson_writer *self, const char *buf, size_t buf_len)
 	size_t buf_size = sizeof(writer_file->buf);
 	size_t buf_avail = buf_size - writer_file->buf_used;
 
-	if (buf_len > buf_size/4)
+	if (buf_len > buf_size / 4) {
+		if (out_writer_file_write(self, writer_file->fd,
+					  writer_file->buf, writer_file->buf_used))
+			return 1;
+
+		writer_file->buf_used = 0;
+
 		return out_writer_file_write(self, writer_file->fd, buf, buf_len);
+	}
 
 	if (buf_len >= buf_avail) {
 		if (out_writer_file_write(self, writer_file->fd,
@@ -487,3 +511,5 @@ ujson_writer *ujson_writer_file_open(const char *path)
 
 	return ret;
 }
+
+
-- 
2.55.0


-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply related	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-11-10 13:07 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-09 16:32 [LTP] [PATCH] lib: ujson: Update to ujson 1.0 Cyril Hrubis
2026-11-10 13:06 ` [LTP] " linuxtestproject.agent

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.