Skip to content

Commit

Permalink
Fix memory leak of rb_ast_t in parser
Browse files Browse the repository at this point in the history
ast_alloc uses TypedData_Make_Struct, which allocates a rb_ast_t. But it
is overwritten when we set the DATA_PTR so the original memory is leaked.

For example:

    10.times do
      100_000.times do
        eval("")
      end

      puts `ps -o rss= -p #{$$}`
    end

Before:

    17328
    20752
    23664
    28400
    30656
    34224
    37424
    40784
    43328
    46656

After:

    14320
    14320
    14320
    14320
    14320
    14320
    14320
    14336
    14336
    14336
  • Loading branch information
peterzhu2118 committed Apr 29, 2024
1 parent 95d036a commit e3bfd25
Showing 1 changed file with 14 additions and 20 deletions.
34 changes: 14 additions & 20 deletions ruby_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -763,10 +763,9 @@ static const rb_data_type_t ast_data_type = {
};

static VALUE
ast_alloc(void)
ast_alloc(rb_ast_t *ast)
{
rb_ast_t *ast;
VALUE vast = TypedData_Make_Struct(0, rb_ast_t, &ast_data_type, ast);
VALUE vast = TypedData_Wrap_Struct(0, &ast_data_type, ast);
#ifdef UNIVERSAL_PARSER
ast = (rb_ast_t *)DATA_PTR(vast);
ast->config = &rb_global_parser_config;
Expand All @@ -778,10 +777,9 @@ VALUE
rb_parser_compile_file_path(VALUE vparser, VALUE fname, VALUE file, int start)
{
struct ruby_parser *parser;
VALUE vast = ast_alloc();

TypedData_Get_Struct(vparser, struct ruby_parser, &ruby_parser_data_type, parser);
DATA_PTR(vast) = parser_compile_file_path(parser, fname, file, start);

VALUE vast = ast_alloc(parser_compile_file_path(parser, fname, file, start));
RB_GC_GUARD(vparser);

return vast;
Expand All @@ -791,10 +789,9 @@ VALUE
rb_parser_compile_array(VALUE vparser, VALUE fname, VALUE array, int start)
{
struct ruby_parser *parser;
VALUE vast = ast_alloc();

TypedData_Get_Struct(vparser, struct ruby_parser, &ruby_parser_data_type, parser);
DATA_PTR(vast) = parser_compile_array(parser, fname, array, start);

VALUE vast = ast_alloc(parser_compile_array(parser, fname, array, start));
RB_GC_GUARD(vparser);

return vast;
Expand All @@ -804,10 +801,9 @@ VALUE
rb_parser_compile_generic(VALUE vparser, rb_parser_lex_gets_func *lex_gets, VALUE fname, VALUE input, int start)
{
struct ruby_parser *parser;
VALUE vast = ast_alloc();

TypedData_Get_Struct(vparser, struct ruby_parser, &ruby_parser_data_type, parser);
DATA_PTR(vast) = parser_compile_generic(parser, lex_gets, fname, input, start);

VALUE vast = ast_alloc(parser_compile_generic(parser, lex_gets, fname, input, start));
RB_GC_GUARD(vparser);

return vast;
Expand All @@ -817,10 +813,9 @@ VALUE
rb_parser_compile_string(VALUE vparser, const char *f, VALUE s, int line)
{
struct ruby_parser *parser;
VALUE vast = ast_alloc();

TypedData_Get_Struct(vparser, struct ruby_parser, &ruby_parser_data_type, parser);
DATA_PTR(vast) = parser_compile_string(parser, f, s, line);

VALUE vast = ast_alloc(parser_compile_string(parser, f, s, line));
RB_GC_GUARD(vparser);

return vast;
Expand All @@ -830,10 +825,9 @@ VALUE
rb_parser_compile_string_path(VALUE vparser, VALUE f, VALUE s, int line)
{
struct ruby_parser *parser;
VALUE vast = ast_alloc();

TypedData_Get_Struct(vparser, struct ruby_parser, &ruby_parser_data_type, parser);
DATA_PTR(vast) = parser_compile_string_path(parser, f, s, line);

VALUE vast = ast_alloc(parser_compile_string_path(parser, f, s, line));
RB_GC_GUARD(vparser);

return vast;
Expand Down Expand Up @@ -1123,8 +1117,8 @@ parser_aset_script_lines_for(VALUE path, rb_parser_ary_t *lines)
VALUE
rb_ruby_ast_new(const NODE *const root)
{
VALUE vast = ast_alloc();
rb_ast_t *ast = DATA_PTR(vast);
rb_ast_t *ast = ruby_xcalloc(1, sizeof(rb_ast_t));
VALUE vast = ast_alloc(ast);
ast->body = (rb_ast_body_t){
.root = root,
.frozen_string_literal = -1,
Expand Down

0 comments on commit e3bfd25

Please sign in to comment.