From 5d742424e4789f06d12fe3c060c9df5ff0a0dee2 Mon Sep 17 00:00:00 2001 From: Lars Kanis Date: Wed, 3 Jun 2026 09:37:09 +0200 Subject: [PATCH] Avoid possibility to replace typemap while being used in Copy and Record encoders and decoders by keeping the ruby typemap object in a local variable. Fixes #707 --- ext/pg_copy_coder.c | 25 +++++++++++++++++-------- ext/pg_record_coder.c | 12 ++++++++---- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/ext/pg_copy_coder.c b/ext/pg_copy_coder.c index 28bbdab39..454ecac39 100644 --- a/ext/pg_copy_coder.c +++ b/ext/pg_copy_coder.c @@ -221,12 +221,13 @@ pg_text_enc_copy_row(t_pg_coder *conv, VALUE value, char *out, VALUE *intermedia t_pg_coder_enc_func enc_func; static t_pg_coder *p_elem_coder; int i; + VALUE rb_typemap = this->typemap; t_typemap *p_typemap; char *current_out; char *end_capa_ptr; - p_typemap = RTYPEDDATA_DATA( this->typemap ); - p_typemap->funcs.fit_to_query( this->typemap, value ); + p_typemap = RTYPEDDATA_DATA( rb_typemap ); + p_typemap->funcs.fit_to_query( rb_typemap, value ); /* Allocate a new string with embedded capacity and realloc exponential when needed. */ PG_RB_STR_NEW( *intermediate, current_out, end_capa_ptr ); @@ -314,6 +315,7 @@ pg_text_enc_copy_row(t_pg_coder *conv, VALUE value, char *out, VALUE *intermedia rb_str_set_len( *intermediate, current_out - RSTRING_PTR(*intermediate) ); + RB_GC_GUARD(rb_typemap); return -1; } @@ -366,12 +368,13 @@ pg_bin_enc_copy_row(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediat { t_pg_copycoder *this = (t_pg_copycoder *)conv; int i; + VALUE rb_typemap = this->typemap; t_typemap *p_typemap; char *current_out; char *end_capa_ptr; - p_typemap = RTYPEDDATA_DATA( this->typemap ); - p_typemap->funcs.fit_to_query( this->typemap, value ); + p_typemap = RTYPEDDATA_DATA( rb_typemap ); + p_typemap->funcs.fit_to_query( rb_typemap, value ); /* Allocate a new string with embedded capacity and realloc exponential when needed. */ PG_RB_STR_NEW( *intermediate, current_out, end_capa_ptr ); @@ -432,6 +435,7 @@ pg_bin_enc_copy_row(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediat rb_str_set_len( *intermediate, current_out - RSTRING_PTR(*intermediate) ); + RB_GC_GUARD(rb_typemap); return -1; } @@ -530,10 +534,11 @@ pg_text_dec_copy_row(t_pg_coder *conv, const char *input_line, int len, int _tup const char *cur_ptr; const char *line_end_ptr; char *end_capa_ptr; + VALUE rb_typemap = this->typemap; t_typemap *p_typemap; - p_typemap = RTYPEDDATA_DATA( this->typemap ); - expected_fields = p_typemap->funcs.fit_to_copy_get( this->typemap ); + p_typemap = RTYPEDDATA_DATA( rb_typemap ); + expected_fields = p_typemap->funcs.fit_to_copy_get( rb_typemap ); /* The received input string will probably have this->nfields fields. */ array = rb_ary_new2(expected_fields); @@ -714,6 +719,8 @@ pg_text_dec_copy_row(t_pg_coder *conv, const char *input_line, int len, int _tup break; } + RB_GC_GUARD(rb_typemap); + return array; } @@ -786,10 +793,11 @@ pg_bin_dec_copy_row(t_pg_coder *conv, const char *input_line, int len, int _tupl const char *cur_ptr; const char *line_end_ptr; char *end_capa_ptr; + VALUE rb_typemap = this->typemap; t_typemap *p_typemap; - p_typemap = RTYPEDDATA_DATA( this->typemap ); - expected_fields = p_typemap->funcs.fit_to_copy_get( this->typemap ); + p_typemap = RTYPEDDATA_DATA( rb_typemap ); + expected_fields = p_typemap->funcs.fit_to_copy_get( rb_typemap ); /* Allocate a new string with embedded capacity and realloc later with * exponential growing size when needed. */ @@ -871,6 +879,7 @@ pg_bin_dec_copy_row(t_pg_coder *conv, const char *input_line, int len, int _tupl if (cur_ptr < line_end_ptr) rb_raise( rb_eArgError, "trailing data after row data at position: %ld", (long)(cur_ptr - input_line) + 1 ); + RB_GC_GUARD(rb_typemap); return array; length_error: diff --git a/ext/pg_record_coder.c b/ext/pg_record_coder.c index 0d1fb16f4..58b1845e1 100644 --- a/ext/pg_record_coder.c +++ b/ext/pg_record_coder.c @@ -181,12 +181,13 @@ pg_text_enc_record(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate t_pg_coder_enc_func enc_func; static t_pg_coder *p_elem_coder; int i; + VALUE rb_typemap = this->typemap; t_typemap *p_typemap; char *current_out; char *end_capa_ptr; - p_typemap = RTYPEDDATA_DATA( this->typemap ); - p_typemap->funcs.fit_to_query( this->typemap, value ); + p_typemap = RTYPEDDATA_DATA( rb_typemap ); + p_typemap->funcs.fit_to_query( rb_typemap, value ); /* Allocate a new string with embedded capacity and realloc exponential when needed. */ PG_RB_STR_NEW( *intermediate, current_out, end_capa_ptr ); @@ -277,6 +278,7 @@ pg_text_enc_record(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate rb_str_set_len( *intermediate, current_out - RSTRING_PTR(*intermediate) ); + RB_GC_GUARD(rb_typemap); return -1; } @@ -387,10 +389,11 @@ pg_text_dec_record(t_pg_coder *conv, char *input_line, int len, int _tuple, int char *output_ptr; char *cur_ptr; char *end_capa_ptr; + VALUE rb_typemap = this->typemap; t_typemap *p_typemap; - p_typemap = RTYPEDDATA_DATA( this->typemap ); - expected_fields = p_typemap->funcs.fit_to_copy_get( this->typemap ); + p_typemap = RTYPEDDATA_DATA( rb_typemap ); + expected_fields = p_typemap->funcs.fit_to_copy_get( rb_typemap ); /* The received input string will probably have this->nfields fields. */ array = rb_ary_new2(expected_fields); @@ -490,6 +493,7 @@ pg_text_dec_record(t_pg_coder *conv, char *input_line, int len, int _tuple, int if (*cur_ptr) rb_raise( rb_eArgError, "malformed record literal: \"%s\" - Junk after right parenthesis.", input_line ); + RB_GC_GUARD(rb_typemap); return array; }