Closed sbezverk closed 3 months ago
I believe I've reproduced the output:
yyjson_mut_doc *doc = yyjson_mut_doc_new(NULL);
yyjson_mut_val *root = yyjson_mut_obj(doc);
yyjson_mut_doc_set_root(doc, root);
yyjson_mut_val *val;
val = yyjson_mut_bool(doc, false);
yyjson_mut_obj_add_val(doc, root, "is", val);
val = yyjson_mut_bool(doc, false);
val->tag |= 0x10;
yyjson_mut_obj_add_val(doc, root, "is", val);
val = yyjson_mut_bool(doc, false);
yyjson_mut_obj_add_val(doc, root, "is", val);
val = yyjson_mut_bool(doc, true);
val->tag |= 0x10;
yyjson_mut_obj_add_val(doc, root, "is", val);
val = yyjson_mut_bool(doc, true);
yyjson_mut_obj_add_val(doc, root, "is", val);
val = yyjson_mut_bool(doc, true);
val->tag |= 0x10;
yyjson_mut_obj_add_val(doc, root, "is", val);
usize json_len = 0;
const char *json = yyjson_mut_write(doc, YYJSON_WRITE_PRETTY, &json_len);
printf("%s\n", json);
output:
{
"is": false,
"is": true, "is": false, < -- missing \n
"is": true "is": true, < -- missing comma
"is": tr < -- missing 'ue'
}
Here's why it's happening:
The bool
type only holds 0 or 1. Typically, when you pass non-bool values to a bool parameter, they get converted to 1 if they're non-zero, and everything works fine.
But if your compiler doesn't automatically handle this conversion (some environments define bool
as unsigned char
), and you feed a non-0/1 value directly as a bool, it might cause the JSON bool to have values like 0/1/2/3, potentially missing 1 or 2 characters.
Here's some yyjson's internal code:
// set bool
yyjson_mut_bool(yyjson_mut_doc *doc, bool val) {
...
val->tag = YYJSON_TYPE_BOOL | (uint8_t)((uint8_t)_val << 3);
...
}
// get bool
bool unsafe_yyjson_get_bool(void *val) {
uint8_t tag = unsafe_yyjson_get_tag(val);
return (bool)((tag & YYJSON_SUBTYPE_MASK) >> YYJSON_TYPE_BIT);
}
// write bool
u8 *write_bool(u8 *cur, bool val) {
...
return cur + 5 - val; //< val shoule be 0 or 1
}
I'd suggest you check for this scenario in your code. If you find it, you can make sure the value is treated as a bool like this yyjson_mut_bool(doc, !!val)
.
I'll also fix yyjson later to avoid this problem.
Thank you very much for such quick response, really appreciate it. Since I do not have control which value is used to indicate ‘true’ I just applied the workaround you suggested and it works perfectly.
Thank you again and I would appreciate a headsup when fixed version will be published.
Serguei
From: ibireme @.> Reply to: ibireme/yyjson @.> Date: Thursday, 7 March 2024 at 07:29 To: ibireme/yyjson @.> Cc: sbezverk @.>, Author @.***> Subject: Re: [ibireme/yyjson] incorrectly formatted bool fields. (Issue #161)
I believe I've reproduced the output:
yyjson_mut_doc *doc = yyjson_mut_doc_new(NULL);
yyjson_mut_val *root = yyjson_mut_obj(doc);
yyjson_mut_doc_set_root(doc, root);
yyjson_mut_val *val;
val = yyjson_mut_bool(doc, false);
yyjson_mut_obj_add_val(doc, root, "is", val);
val = yyjson_mut_bool(doc, false);
val->tag |= 0x10;
yyjson_mut_obj_add_val(doc, root, "is", val);
val = yyjson_mut_bool(doc, false);
yyjson_mut_obj_add_val(doc, root, "is", val);
val = yyjson_mut_bool(doc, true);
val->tag |= 0x10;
yyjson_mut_obj_add_val(doc, root, "is", val);
val = yyjson_mut_bool(doc, true);
yyjson_mut_obj_add_val(doc, root, "is", val);
val = yyjson_mut_bool(doc, true);
val->tag |= 0x10;
yyjson_mut_obj_add_val(doc, root, "is", val);
usize json_len = 0;
const char *json = yyjson_mut_write(doc, YYJSON_WRITE_PRETTY, &json_len);
printf("%s\n", json);
output:
{
"is": false,
"is": true, "is": false, < -- missing \n
"is": true "is": true, < -- missing comma
"is": tr < -- missing 'ue'
}
Here's why it's happening:
The bool type only holds 0 or 1. Typically, when you pass non-bool values to a bool parameter, they get converted to 1 if they're non-zero, and everything works fine. But if your compiler doesn't automatically handle this conversion (some environments define bool as unsigned char), and you feed a non-0/1 value directly as a bool, it might cause the JSON bool to have values like 0/1/2/3, potentially missing 1 or 2 characters.
Here's some yyjson's internal code:
// set bool
yyjson_mut_bool(yyjson_mut_doc *doc, bool val) {
...
val->tag = YYJSON_TYPE_BOOL | (uint8_t)((uint8_t)_val << 3);
...
}
// get bool
bool unsafe_yyjson_get_bool(void *val) {
uint8_t tag = unsafe_yyjson_get_tag(val);
return (bool)((tag & YYJSON_SUBTYPE_MASK) >> YYJSON_TYPE_BIT);
}
// write bool
u8 write_bool(u8 cur, bool val) {
...
return cur + 5 - val; //< val shoule be 0 or 1
}
I'd suggest you check for this scenario in your code. If you find it, you can make sure the value is treated as a bool like this yyjson_mut_bool(doc, !!val).
I'll also fix yyjson later to avoid this problem.
— Reply to this email directly, view it on GitHubhttps://github.com/ibireme/yyjson/issues/161#issuecomment-1982550281, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AD4E7UDVVQMBJLNILGCTQQTYXACKTAVCNFSM6AAAAABEJY26SOVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSOBSGU2TAMRYGE. You are receiving this because you authored the thread.Message ID: @.***>
Fixed in master branch.
Describe the bug When a relatively large number of bool fields are added to the mutable json document and then generating char * with
yyjson_mut_write(doc, YYJSON_WRITE_PRETTY, NULL);
some fields look incorrectly formated. Example missing trailing comma and\n
.Here is an example:
Your environment
Additional context Add any other context about the problem here. this issue is 100% reproducible on large json documents.