1414************************************************/
1515
1616#include "digest.h"
17+ #include <ruby/version.h>
1718
1819static VALUE rb_mDigest ;
1920static VALUE rb_mDigest_Instance ;
2021static VALUE rb_cDigest_Class ;
2122static VALUE rb_cDigest_Base ;
2223
2324static ID id_reset , id_update , id_finish , id_digest , id_hexdigest , id_digest_length ;
25+ static ID id_clone , id_freeze ;
2426static ID id_metadata ;
2527
2628RUBY_EXTERN void Init_digest_base (void );
@@ -217,12 +219,23 @@ rb_digest_instance_reset(VALUE self)
217219 * digest_obj.new -> another_digest_obj
218220 *
219221 * Returns a new, initialized copy of the digest object. Equivalent
220- * to digest_obj.clone().reset().
222+ * to digest_obj.clone(freeze: false ).reset().
221223 */
222224static VALUE
223225rb_digest_instance_new (VALUE self )
224226{
225- VALUE clone = rb_obj_clone (self );
227+ VALUE clone ;
228+
229+ #if RUBY_API_VERSION_MAJOR >= 3
230+ /* dup() would drop the singleton class, and the copy must not stay frozen */
231+ VALUE kwargs = rb_hash_new ();
232+ rb_hash_aset (kwargs , ID2SYM (id_freeze ), Qfalse );
233+ clone = rb_funcallv_kw (self , id_clone , 1 , & kwargs , RB_PASS_KEYWORDS );
234+ #else
235+ /* clone(freeze:) needs Ruby 3.0; dup() loses the singleton class but resets */
236+ clone = OBJ_FROZEN (self ) ? rb_obj_dup (self ) : rb_obj_clone (self );
237+ #endif
238+
226239 rb_funcall (clone , id_reset , 0 );
227240 return clone ;
228241}
@@ -266,7 +279,11 @@ rb_digest_instance_digest(int argc, VALUE *argv, VALUE self)
266279static VALUE
267280rb_digest_instance_digest_bang (VALUE self )
268281{
269- VALUE value = rb_funcall (self , id_finish , 0 );
282+ VALUE value ;
283+
284+ rb_check_frozen (self );
285+
286+ value = rb_funcall (self , id_finish , 0 );
270287 rb_funcall (self , id_reset , 0 );
271288
272289 return value ;
@@ -311,7 +328,11 @@ rb_digest_instance_hexdigest(int argc, VALUE *argv, VALUE self)
311328static VALUE
312329rb_digest_instance_hexdigest_bang (VALUE self )
313330{
314- VALUE value = rb_funcall (self , id_finish , 0 );
331+ VALUE value ;
332+
333+ rb_check_frozen (self );
334+
335+ value = rb_funcall (self , id_finish , 0 );
315336 rb_funcall (self , id_reset , 0 );
316337
317338 return hexencode_str_new (value );
@@ -683,6 +704,8 @@ rb_digest_base_reset(VALUE self)
683704 rb_digest_metadata_t * algo ;
684705 void * pctx ;
685706
707+ rb_check_frozen (self );
708+
686709 algo = get_digest_obj_metadata (self );
687710
688711 TypedData_Get_Struct (self , void , & digest_type , pctx );
@@ -705,6 +728,8 @@ rb_digest_base_update(VALUE self, VALUE str)
705728 rb_digest_metadata_t * algo ;
706729 void * pctx ;
707730
731+ rb_check_frozen (self );
732+
708733 algo = get_digest_obj_metadata (self );
709734
710735 TypedData_Get_Struct (self , void , & digest_type , pctx );
@@ -732,6 +757,7 @@ rb_digest_base_finish(VALUE self)
732757 algo -> finish_func (pctx , (unsigned char * )RSTRING_PTR (str ));
733758
734759 /* avoid potential coredump caused by use of a finished context */
760+ /* not frozen-checked: #digest and #hexdigest call this on a clone */
735761 algo_init (algo , pctx );
736762
737763 return str ;
@@ -777,6 +803,8 @@ Init_digest(void)
777803 id_digest = rb_intern ("digest" );
778804 id_hexdigest = rb_intern ("hexdigest" );
779805 id_digest_length = rb_intern ("digest_length" );
806+ id_clone = rb_intern ("clone" );
807+ id_freeze = rb_intern ("freeze" );
780808 id_metadata = rb_id_metadata ();
781809 InitVM (digest );
782810}
0 commit comments