Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

### Unreleased

* Add `allow_invalid_escape` parsing option to ignore backslashes that aren't followed by one of the valid escape characters.

### 2026-02-03 (2.18.1)

* Fix a potential crash in very specific circumstance if GC triggers during a call to `to_json`
Expand Down
10 changes: 8 additions & 2 deletions ext/json/ext/parser/parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ static VALUE CNaN, CInfinity, CMinusInfinity;

static ID i_new, i_try_convert, i_uminus, i_encode;

static VALUE sym_max_nesting, sym_allow_nan, sym_allow_trailing_comma, sym_allow_control_characters, sym_symbolize_names, sym_freeze,
sym_decimal_class, sym_on_load, sym_allow_duplicate_key;
static VALUE sym_max_nesting, sym_allow_nan, sym_allow_trailing_comma, sym_allow_control_characters,
sym_allow_invalid_escape, sym_symbolize_names, sym_freeze, sym_decimal_class, sym_on_load,
sym_allow_duplicate_key;

static int binary_encindex;
static int utf8_encindex;
Expand Down Expand Up @@ -336,6 +337,7 @@ typedef struct JSON_ParserStruct {
bool allow_nan;
bool allow_trailing_comma;
bool allow_control_characters;
bool allow_invalid_escape;
bool symbolize_names;
bool freeze;
} JSON_ParserConfig;
Expand Down Expand Up @@ -746,6 +748,8 @@ NOINLINE(static) VALUE json_string_unescape(JSON_ParserState *state, JSON_Parser
}
raise_parse_error_at("invalid ASCII control character in string: %s", state, pe - 1);
}
} else if (config->allow_invalid_escape) {
APPEND_CHAR(*pe);
} else {
raise_parse_error_at("invalid escape character in string: %s", state, pe - 1);
}
Expand Down Expand Up @@ -1435,6 +1439,7 @@ static int parser_config_init_i(VALUE key, VALUE val, VALUE data)
else if (key == sym_allow_nan) { config->allow_nan = RTEST(val); }
else if (key == sym_allow_trailing_comma) { config->allow_trailing_comma = RTEST(val); }
else if (key == sym_allow_control_characters) { config->allow_control_characters = RTEST(val); }
else if (key == sym_allow_invalid_escape) { config->allow_invalid_escape = RTEST(val); }
else if (key == sym_symbolize_names) { config->symbolize_names = RTEST(val); }
else if (key == sym_freeze) { config->freeze = RTEST(val); }
else if (key == sym_on_load) { config->on_load_proc = RTEST(val) ? val : Qfalse; }
Expand Down Expand Up @@ -1653,6 +1658,7 @@ void Init_parser(void)
sym_allow_nan = ID2SYM(rb_intern("allow_nan"));
sym_allow_trailing_comma = ID2SYM(rb_intern("allow_trailing_comma"));
sym_allow_control_characters = ID2SYM(rb_intern("allow_control_characters"));
sym_allow_invalid_escape = ID2SYM(rb_intern("allow_invalid_escape"));
sym_symbolize_names = ID2SYM(rb_intern("symbolize_names"));
sym_freeze = ID2SYM(rb_intern("freeze"));
sym_on_load = ID2SYM(rb_intern("on_load"));
Expand Down
Loading