aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSnowOnion <snowonionlee@gmail.com>2026-06-14 21:30:49 +0800
committerGitHub <noreply@github.com>2026-06-14 21:30:49 +0800
commitfa418dcac3de13c9fe2ddc997bd53e92d793f0bc (patch)
tree504480de7d00dade1233437641f6cac3dee65b3e
parentb97100852940cd7cd0ee187326778fa7c911d92f (diff)
downloadlua-cjson-2.1.0.18.tar.gz
lua-cjson-2.1.0.18.tar.bz2
lua-cjson-2.1.0.18.zip
bugfix: setting encode_escape_forward_slash on a cjson instance does not affect other instances.2.1.0.18
-rw-r--r--lua_cjson.c32
-rwxr-xr-xtests/test.lua12
2 files changed, 37 insertions, 7 deletions
diff --git a/lua_cjson.c b/lua_cjson.c
index 4642b51..8518a86 100644
--- a/lua_cjson.c
+++ b/lua_cjson.c
@@ -162,6 +162,12 @@ typedef struct {
162 json_token_type_t ch2token[256]; 162 json_token_type_t ch2token[256];
163 char escape2char[256]; /* Decoding */ 163 char escape2char[256]; /* Decoding */
164 164
165 /* Per-config encoding escape table. Initialised from the global
166 * char2escape template, then customised per instance (e.g. by
167 * encode_escape_forward_slash) so that one cjson instance's settings
168 * never leak into another. */
169 const char *char2escape[256];
170
165 /* encode_buf is only allocated and used when 171 /* encode_buf is only allocated and used when
166 * encode_keep_buffer is set */ 172 * encode_keep_buffer is set */
167 strbuf_t encode_buf; 173 strbuf_t encode_buf;
@@ -204,7 +210,10 @@ typedef struct {
204 size_t string_len; 210 size_t string_len;
205} json_token_t; 211} json_token_t;
206 212
207static const char *char2escape[256] = { 213/* Read-only template used to initialise each config's char2escape table.
214 * Per-instance customisation happens on json_config_t.char2escape, never
215 * here. */
216static const char *char2escape_template[256] = {
208 "\\u0000", "\\u0001", "\\u0002", "\\u0003", 217 "\\u0000", "\\u0001", "\\u0002", "\\u0003",
209 "\\u0004", "\\u0005", "\\u0006", "\\u0007", 218 "\\u0004", "\\u0005", "\\u0006", "\\u0007",
210 "\\b", "\\t", "\\n", "\\u000b", 219 "\\b", "\\t", "\\n", "\\u000b",
@@ -490,9 +499,9 @@ static int json_cfg_encode_escape_forward_slash(lua_State *l)
490 499
491 ret = json_enum_option(l, 1, &cfg->encode_escape_forward_slash, NULL, 1); 500 ret = json_enum_option(l, 1, &cfg->encode_escape_forward_slash, NULL, 1);
492 if (cfg->encode_escape_forward_slash) { 501 if (cfg->encode_escape_forward_slash) {
493 char2escape['/'] = "\\/"; 502 cfg->char2escape['/'] = "\\/";
494 } else { 503 } else {
495 char2escape['/'] = NULL; 504 cfg->char2escape['/'] = NULL;
496 } 505 }
497 return ret; 506 return ret;
498} 507}
@@ -547,6 +556,14 @@ static void json_create_config(lua_State *l)
547 cfg->encode_skip_unsupported_value_types = DEFAULT_ENCODE_SKIP_UNSUPPORTED_VALUE_TYPES; 556 cfg->encode_skip_unsupported_value_types = DEFAULT_ENCODE_SKIP_UNSUPPORTED_VALUE_TYPES;
548 cfg->encode_indent = DEFAULT_ENCODE_INDENT; 557 cfg->encode_indent = DEFAULT_ENCODE_INDENT;
549 558
559 /* Seed this instance's escape table from the shared template, then
560 * apply the per-instance forward-slash setting. Mutating cfg->char2escape
561 * (instead of a global) keeps each cjson instance independent. */
562 memcpy(cfg->char2escape, char2escape_template, sizeof(cfg->char2escape));
563 if (!cfg->encode_escape_forward_slash) {
564 cfg->char2escape['/'] = NULL;
565 }
566
550#if DEFAULT_ENCODE_KEEP_BUFFER > 0 567#if DEFAULT_ENCODE_KEEP_BUFFER > 0
551 strbuf_init(&cfg->encode_buf, 0); 568 strbuf_init(&cfg->encode_buf, 0);
552#endif 569#endif
@@ -614,7 +631,8 @@ static void json_encode_exception(lua_State *l, json_config_t *cfg, strbuf_t *js
614 * - String (Lua stack index) 631 * - String (Lua stack index)
615 * 632 *
616 * Returns nothing. Doesn't remove string from Lua stack */ 633 * Returns nothing. Doesn't remove string from Lua stack */
617static void json_append_string(lua_State *l, strbuf_t *json, int lindex) 634static void json_append_string(lua_State *l, json_config_t *cfg,
635 strbuf_t *json, int lindex)
618{ 636{
619 const char *escstr; 637 const char *escstr;
620 const char *str; 638 const char *str;
@@ -633,7 +651,7 @@ static void json_append_string(lua_State *l, strbuf_t *json, int lindex)
633 651
634 strbuf_append_char_unsafe(json, '\"'); 652 strbuf_append_char_unsafe(json, '\"');
635 for (i = 0; i < len; i++) { 653 for (i = 0; i < len; i++) {
636 escstr = char2escape[(unsigned char)str[i]]; 654 escstr = cfg->char2escape[(unsigned char)str[i]];
637 if (escstr) 655 if (escstr)
638 strbuf_append_string(json, escstr); 656 strbuf_append_string(json, escstr);
639 else 657 else
@@ -848,7 +866,7 @@ static void json_append_object(lua_State *l, json_config_t *cfg,
848 json_append_number(l, cfg, json, -2); 866 json_append_number(l, cfg, json, -2);
849 strbuf_append_mem(json, "\":", 2); 867 strbuf_append_mem(json, "\":", 2);
850 } else if (keytype == LUA_TSTRING) { 868 } else if (keytype == LUA_TSTRING) {
851 json_append_string(l, json, -2); 869 json_append_string(l, cfg, json, -2);
852 strbuf_append_char(json, ':'); 870 strbuf_append_char(json, ':');
853 } else { 871 } else {
854 json_encode_exception(l, cfg, json, -2, 872 json_encode_exception(l, cfg, json, -2,
@@ -889,7 +907,7 @@ static int json_append_data(lua_State *l, json_config_t *cfg,
889 907
890 switch (lua_type(l, -1)) { 908 switch (lua_type(l, -1)) {
891 case LUA_TSTRING: 909 case LUA_TSTRING:
892 json_append_string(l, json, -1); 910 json_append_string(l, cfg, json, -1);
893 break; 911 break;
894 case LUA_TNUMBER: 912 case LUA_TNUMBER:
895 json_append_number(l, cfg, json, -1); 913 json_append_number(l, cfg, json, -1);
diff --git a/tests/test.lua b/tests/test.lua
index 270f63a..fc373f6 100755
--- a/tests/test.lua
+++ b/tests/test.lua
@@ -515,6 +515,18 @@ local cjson_tests = {
515 { "Decode (safe) error generation after new()", 515 { "Decode (safe) error generation after new()",
516 function(...) return json_safe.new().decode(...) end, { "Oops" }, 516 function(...) return json_safe.new().decode(...) end, { "Oops" },
517 true, { nil, "Expected value but found invalid token at character 1" } }, 517 true, { nil, "Expected value but found invalid token at character 1" } },
518 { "Set encode_escape_forward_slash on a cjson instance should not affect other instances",
519 function()
520 local j1 = json.new()
521 local r1 = j1.encode("/")
522
523 local j2 = json.new()
524 j2.encode_escape_forward_slash(false)
525 local r2 = j2.encode("/")
526 local r3 = j1.encode("/")
527 return r1, r2, r3
528 end, { },
529 true, { [["\/"]], [["/"]], [["\/"]] } },
518} 530}
519 531
520print(("==> Testing Lua CJSON version %s\n"):format(json._VERSION)) 532print(("==> Testing Lua CJSON version %s\n"):format(json._VERSION))