Skip to content

Commit 2afd1a9

Browse files
committed
Cleanup the rb_catch_obj workaround
Followup: #1031 Now that the bug has been fixed upstream, we can only apply it on unpatched version. Also refactor the workaround to expose the exact same API as `rb_catch_obj`, making it easier to ignore and remove later.
1 parent 9892514 commit 2afd1a9

3 files changed

Lines changed: 41 additions & 34 deletions

File tree

ext/json/ext/json.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,4 +144,36 @@ static inline void *ruby_xrealloc2_sized(void *ptr, size_t new_elems, size_t ele
144144
#define JSON_CPU_LITTLE_ENDIAN_64BITS 0
145145
#endif
146146

147+
#ifdef JSON_TRUFFLERUBY_RB_CATCH_BUG
148+
149+
#undef RB_BLOCK_CALL_FUNC_ARGLIST
150+
#define RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, func_args) VALUE func_args
151+
152+
NORETURN(static inline) void json_rb_throw_obj(VALUE tag, VALUE obj)
153+
{
154+
VALUE exc = rb_exc_new_str(rb_eException, rb_utf8_str_new_cstr("throw_workaround"));
155+
rb_ivar_set(exc, rb_intern("@throw_tag"), tag);
156+
rb_ivar_set(exc, rb_intern("@throw_obj"), obj);
157+
rb_exc_raise(exc);
158+
}
159+
#define rb_throw_obj json_rb_throw_obj
160+
161+
static inline VALUE json_rb_catch_obj(VALUE tag, VALUE (*func)(VALUE args), VALUE func_args)
162+
{
163+
int status;
164+
VALUE result = rb_protect(func, func_args, &status);
165+
if (status) {
166+
VALUE exc = rb_errinfo();
167+
if (tag == rb_ivar_get(exc, rb_intern("@throw_tag"))) {
168+
rb_set_errinfo(Qnil);
169+
return rb_ivar_get(exc, rb_intern("@throw_obj"));
170+
}
171+
rb_jump_tag(status);
172+
}
173+
return result;
174+
}
175+
#define rb_catch_obj json_rb_catch_obj
176+
177+
#endif // JSON_TRUFFLERUBY_RB_CATCH_BUG
178+
147179
#endif // _JSON_H_

ext/json/ext/parser/extconf.rb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@
22
require 'mkmf'
33

44
$defs << "-DJSON_DEBUG" if ENV.fetch("JSON_DEBUG", "0") != "0"
5-
$defs << "-DJSON_WORKAROUND_RB_CATCH_BUG" if RUBY_ENGINE == 'truffleruby'
5+
6+
if RUBY_ENGINE == 'truffleruby' && RUBY_VERSION < '4.0'
7+
# Ref: https://github.com/truffleruby/truffleruby/issues/4329
8+
# Ref: https://github.com/truffleruby/truffleruby/pull/4333
9+
$defs << "-DJSON_TRUFFLERUBY_RB_CATCH_BUG"
10+
end
611

712
have_func("rb_enc_interned_str", "ruby/encoding.h") # RUBY_VERSION >= 3.0
813
have_func("rb_str_to_interned_str", "ruby.h") # RUBY_VERSION >= 3.0

ext/json/ext/parser/parser.c

Lines changed: 3 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -672,43 +672,13 @@ static VALUE parse_error_new(JSON_ParserState *state, VALUE message, long line,
672672
return exc;
673673
}
674674

675-
#ifdef JSON_WORKAROUND_RB_CATCH_BUG
676-
#define JSON_CATCH_FUNC_ARGLIST(yielded_arg, func_args) VALUE func_args
677-
678-
NORETURN(static) void parser_throw_eos(VALUE parser)
679-
{
680-
VALUE exc = rb_exc_new_str(eParserError, rb_utf8_str_new_cstr("EOS"));
681-
rb_ivar_set(exc, rb_intern("@resumable_parser_eos"), parser);
682-
rb_exc_raise(exc);
683-
}
684-
685-
static VALUE parser_catch_eos(VALUE parser, VALUE (*func)(VALUE args), VALUE func_args)
686-
{
687-
int status;
688-
VALUE result = rb_protect(func, func_args, &status);
689-
if (status) {
690-
VALUE error_source = rb_ivar_get(rb_errinfo(), rb_intern("@resumable_parser_eos"));
691-
if (error_source == parser) {
692-
rb_set_errinfo(Qnil);
693-
return parser;
694-
}
695-
rb_jump_tag(status);
696-
}
697-
return result;
698-
}
699-
#else
700-
#define JSON_CATCH_FUNC_ARGLIST RB_BLOCK_CALL_FUNC_ARGLIST
701-
#define parser_throw_eos(parser) rb_throw_obj(parser, parser)
702-
#define parser_catch_eos(parser, func, func_args) rb_catch_obj(parser, func, func_args)
703-
#endif
704-
705675
NORETURN(static) void raise_parse_error(const char *format, JSON_ParserState *state, bool eos)
706676
{
707677
if (state->parser) {
708678
if (eos) {
709679
// the error will be swallowed by ResumableParser#parse, so no
710680
// point building a message or backtrace.
711-
parser_throw_eos(state->parser);
681+
rb_throw_obj(state->parser, state->parser);
712682
} else {
713683
// line and columns can't be accurate in resumable
714684
rb_exc_raise(parse_error_new(state, build_parse_error_message(format, state), 0, 0, eos));
@@ -2450,7 +2420,7 @@ struct json_parse_any_args {
24502420
VALUE parser;
24512421
};
24522422

2453-
static VALUE json_parse_any_resumable_safe0(JSON_CATCH_FUNC_ARGLIST(yielded_arg, _args))
2423+
static VALUE json_parse_any_resumable_safe0(RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, _args))
24542424
{
24552425
struct json_parse_any_args *args = (struct json_parse_any_args *)_args;
24562426
return (VALUE)json_parse_any(args->state, args->config, true);
@@ -2459,7 +2429,7 @@ static VALUE json_parse_any_resumable_safe0(JSON_CATCH_FUNC_ARGLIST(yielded_arg,
24592429
static VALUE json_parse_any_resumable_safe(VALUE _args)
24602430
{
24612431
struct json_parse_any_args *args = (struct json_parse_any_args *)_args;
2462-
VALUE result = parser_catch_eos(args->parser, json_parse_any_resumable_safe0, _args);
2432+
VALUE result = rb_catch_obj(args->parser, json_parse_any_resumable_safe0, _args);
24632433
return result == args->parser ? Qfalse : result;
24642434
}
24652435

0 commit comments

Comments
 (0)