From 060a71d4e75e3329b5cae7cd416addba7c5bd263 Mon Sep 17 00:00:00 2001 From: S-H-GAMELINKS Date: Wed, 20 Mar 2024 00:26:54 +0900 Subject: [PATCH] Fix Ripper memory allocation size when enabled Universal Parser The size of `struct parser_params` is 8 bytes difference in `ripper_s_allocate` and `rb_ruby_parser_allocate` when the universal parser is enabled. This causes a situation where `*r->p` is not fully initialized in `ripper_s_allocate` as shown below. ```console (gdb) p *r->p $2 = {heap = 0x0, lval = 0x0, yylloc = 0x0, lex = {strterm = 0x0, gets = 0x0, input = 0, string_buffer = {head = 0x0, last = 0x0}, lastlin e = 0x0, nextline = 0x0, pbeg = 0x0, pcur = 0x0, pend = 0x0, ptok = 0x0, gets_ = {ptr = 0, call = 0x0}, state = EXPR_NONE, paren_nest = 0, lpar _seen = 0, debug = 0, has_shebang = 0, token_seen = 0, token_info_enabled = 0, error_p = 0, cr_seen = 0, value = 0, result = 0, parsing_thread = 0, s_value = 0, s_lvalue = 0, s_value_stack = 2097} ```` This seems to cause `double free or corruption (!prev)` and SEGV. So, fixing this by introduce `rb_ripper_parser_params_allocate` and `rb_ruby_parser_config` functions for Ripper, and `struct parser_params` same size is returned. --- ext/ripper/ripper_init.c.tmpl | 3 ++- internal/parse.h | 3 +++ internal/ruby_parser.h | 1 + parse.y | 10 ++++++++++ ruby_parser.c | 6 ++++++ 5 files changed, 22 insertions(+), 1 deletion(-) diff --git a/ext/ripper/ripper_init.c.tmpl b/ext/ripper/ripper_init.c.tmpl index 2386f54c0e..894cbc0b44 100644 --- a/ext/ripper/ripper_init.c.tmpl +++ b/ext/ripper/ripper_init.c.tmpl @@ -94,7 +94,8 @@ ripper_s_allocate(VALUE klass) &parser_data_type, r); #ifdef UNIVERSAL_PARSER - r->p = rb_parser_params_allocate(); + const rb_parser_config_t *config = rb_ruby_parser_config(); + r->p = rb_ripper_parser_params_allocate(config); #else r->p = rb_ruby_ripper_parser_allocate(); #endif diff --git a/internal/parse.h b/internal/parse.h index e05b2bc02f..fc78836e5c 100644 --- a/internal/parse.h +++ b/internal/parse.h @@ -105,6 +105,9 @@ long rb_ruby_ripper_column(rb_parser_t *p); long rb_ruby_ripper_token_len(rb_parser_t *p); rb_parser_string_t *rb_ruby_ripper_lex_lastline(rb_parser_t *p); VALUE rb_ruby_ripper_lex_state_name(struct parser_params *p, int state); +#ifdef UNIVERSAL_PARSER +rb_parser_t *rb_ripper_parser_params_allocate(const rb_parser_config_t *config); +#endif struct parser_params *rb_ruby_ripper_parser_allocate(void); #endif diff --git a/internal/ruby_parser.h b/internal/ruby_parser.h index 7b4c715268..1c59851f0d 100644 --- a/internal/ruby_parser.h +++ b/internal/ruby_parser.h @@ -12,6 +12,7 @@ RUBY_SYMBOL_EXPORT_BEGIN #ifdef UNIVERSAL_PARSER +const rb_parser_config_t *rb_ruby_parser_config(void); rb_parser_t *rb_parser_params_allocate(void); rb_parser_t *rb_parser_params_new(void); #endif diff --git a/parse.y b/parse.y index 7b58134f0d..28b03f8cd1 100644 --- a/parse.y +++ b/parse.y @@ -16613,6 +16613,16 @@ rb_ruby_ripper_lex_state_name(struct parser_params *p, int state) return rb_parser_lex_state_name(p, (enum lex_state_e)state); } +#ifdef UNIVERSAL_PARSER +rb_parser_t * +rb_ripper_parser_params_allocate(const rb_parser_config_t *config) +{ + rb_parser_t *p = (rb_parser_t *)config->calloc(1, sizeof(rb_parser_t)); + p->config = config; + return p; +} +#endif + struct parser_params* rb_ruby_ripper_parser_allocate(void) { diff --git a/ruby_parser.c b/ruby_parser.c index d37dc388cd..6d85a72c5b 100644 --- a/ruby_parser.c +++ b/ruby_parser.c @@ -685,6 +685,12 @@ static const rb_parser_config_t rb_global_parser_config = { .str_coderange_scan_restartable = str_coderange_scan_restartable, }; +const rb_parser_config_t * +rb_ruby_parser_config(void) +{ + return &rb_global_parser_config; +} + rb_parser_t * rb_parser_params_allocate(void) {