From 98acd95e86f7952fc40d73d19fe3400b305e0201 Mon Sep 17 00:00:00 2001 From: Kazuki Yamaguchi Date: Sun, 5 Jul 2026 18:12:47 +0900 Subject: [PATCH] Implement dcompact We can implement this now that we require Ruby 2.7 or later. The return value of OpenSSL's *_set_ex_data() functions is not checked since replacing an existing index should not fail. --- ext/openssl/ossl_ssl.c | 46 +++++++++++++++++++++------- ext/openssl/ossl_x509store.c | 58 ++++++++++++++++++++++++++---------- 2 files changed, 78 insertions(+), 26 deletions(-) diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c index 3d913a396..27a811b5a 100644 --- a/ext/openssl/ossl_ssl.c +++ b/ext/openssl/ossl_ssl.c @@ -56,7 +56,7 @@ static void ossl_sslctx_mark(void *ptr) { SSL_CTX *ctx = ptr; - rb_gc_mark((VALUE)SSL_CTX_get_ex_data(ctx, ossl_sslctx_ex_ptr_idx)); + rb_gc_mark_movable((VALUE)SSL_CTX_get_ex_data(ctx, ossl_sslctx_ex_ptr_idx)); } static void @@ -65,12 +65,25 @@ ossl_sslctx_free(void *ptr) SSL_CTX_free(ptr); } +static void +ossl_sslctx_compact(void *ptr) +{ + SSL_CTX *ctx = ptr; + VALUE self = (VALUE)SSL_CTX_get_ex_data(ctx, ossl_sslctx_ex_ptr_idx); + if (self) { + (void)SSL_CTX_set_ex_data(ctx, ossl_sslctx_ex_ptr_idx, + (void *)rb_gc_location(self)); + } +} + static const rb_data_type_t ossl_sslctx_type = { - "OpenSSL/SSL/CTX", - { - ossl_sslctx_mark, ossl_sslctx_free, + .wrap_struct_name = "OpenSSL/SSL/CTX", + .function = { + .dmark = ossl_sslctx_mark, + .dfree = ossl_sslctx_free, + .dcompact = ossl_sslctx_compact, }, - 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, + .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, }; static VALUE @@ -1567,7 +1580,7 @@ static void ossl_ssl_mark(void *ptr) { SSL *ssl = ptr; - rb_gc_mark((VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx)); + rb_gc_mark_movable((VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx)); } static void @@ -1576,12 +1589,25 @@ ossl_ssl_free(void *ssl) SSL_free(ssl); } +static void +ossl_ssl_compact(void *ptr) +{ + SSL *ssl = ptr; + VALUE self = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx); + if (self) { + (void)SSL_set_ex_data(ssl, ossl_ssl_ex_ptr_idx, + (void *)rb_gc_location(self)); + } +} + const rb_data_type_t ossl_ssl_type = { - "OpenSSL/SSL", - { - ossl_ssl_mark, ossl_ssl_free, + .wrap_struct_name = "OpenSSL/SSL", + .function = { + .dmark = ossl_ssl_mark, + .dfree = ossl_ssl_free, + .dcompact = ossl_ssl_compact, }, - 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, + .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, }; static VALUE diff --git a/ext/openssl/ossl_x509store.c b/ext/openssl/ossl_x509store.c index bed124dc3..ee9f3d0e3 100644 --- a/ext/openssl/ossl_x509store.c +++ b/ext/openssl/ossl_x509store.c @@ -116,10 +116,9 @@ static void ossl_x509store_mark(void *ptr) { X509_STORE *store = ptr; - // Note: this reference is stored as @verify_callback so we don't need to mark it. - // However we do need to ensure GC compaction won't move it, hence why - // we call rb_gc_mark here. - rb_gc_mark((VALUE)X509_STORE_get_ex_data(store, store_ex_verify_cb_idx)); + VALUE verify_cb = + (VALUE)X509_STORE_get_ex_data(store, store_ex_verify_cb_idx); + rb_gc_mark_movable(verify_cb); } static void @@ -128,12 +127,26 @@ ossl_x509store_free(void *ptr) X509_STORE_free(ptr); } +static void +ossl_x509store_compact(void *ptr) +{ + X509_STORE *store = ptr; + VALUE verify_cb = + (VALUE)X509_STORE_get_ex_data(store, store_ex_verify_cb_idx); + if (verify_cb) { + (void)X509_STORE_set_ex_data(store, store_ex_verify_cb_idx, + (void *)rb_gc_location(verify_cb)); + } +} + static const rb_data_type_t ossl_x509store_type = { - "OpenSSL/X509/STORE", - { - ossl_x509store_mark, ossl_x509store_free, + .wrap_struct_name = "OpenSSL/X509/STORE", + .function = { + .dmark = ossl_x509store_mark, + .dfree = ossl_x509store_free, + .dcompact = ossl_x509store_compact, }, - 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, + .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, }; /* @@ -570,10 +583,9 @@ static void ossl_x509stctx_mark(void *ptr) { X509_STORE_CTX *ctx = ptr; - // Note: this reference is stored as @verify_callback so we don't need to mark it. - // However we do need to ensure GC compaction won't move it, hence why - // we call rb_gc_mark here. - rb_gc_mark((VALUE)X509_STORE_CTX_get_ex_data(ctx, stctx_ex_verify_cb_idx)); + VALUE verify_cb = + (VALUE)X509_STORE_CTX_get_ex_data(ctx, stctx_ex_verify_cb_idx); + rb_gc_mark_movable(verify_cb); } static void @@ -585,12 +597,26 @@ ossl_x509stctx_free(void *ptr) X509_STORE_CTX_free(ctx); } +static void +ossl_x509stctx_compact(void *ptr) +{ + X509_STORE_CTX *ctx = ptr; + VALUE verify_cb = + (VALUE)X509_STORE_CTX_get_ex_data(ctx, stctx_ex_verify_cb_idx); + if (verify_cb) { + (void)X509_STORE_CTX_set_ex_data(ctx, stctx_ex_verify_cb_idx, + (void *)rb_gc_location(verify_cb)); + } +} + static const rb_data_type_t ossl_x509stctx_type = { - "OpenSSL/X509/STORE_CTX", - { - ossl_x509stctx_mark, ossl_x509stctx_free, + .wrap_struct_name = "OpenSSL/X509/STORE_CTX", + .function = { + .dmark = ossl_x509stctx_mark, + .dfree = ossl_x509stctx_free, + .dcompact = ossl_x509stctx_compact, }, - 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, + .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, }; static VALUE