Skip to content

Commit a2b4f72

Browse files
committed
Raise FrozenError when modifying a frozen digest
1 parent 27cc1d1 commit a2b4f72

3 files changed

Lines changed: 79 additions & 2 deletions

File tree

ext/digest/digest.c

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,11 @@ rb_digest_instance_digest(int argc, VALUE *argv, VALUE self)
266266
static VALUE
267267
rb_digest_instance_digest_bang(VALUE self)
268268
{
269-
VALUE value = rb_funcall(self, id_finish, 0);
269+
VALUE value;
270+
271+
rb_check_frozen(self);
272+
273+
value = rb_funcall(self, id_finish, 0);
270274
rb_funcall(self, id_reset, 0);
271275

272276
return value;
@@ -311,7 +315,11 @@ rb_digest_instance_hexdigest(int argc, VALUE *argv, VALUE self)
311315
static VALUE
312316
rb_digest_instance_hexdigest_bang(VALUE self)
313317
{
314-
VALUE value = rb_funcall(self, id_finish, 0);
318+
VALUE value;
319+
320+
rb_check_frozen(self);
321+
322+
value = rb_funcall(self, id_finish, 0);
315323
rb_funcall(self, id_reset, 0);
316324

317325
return hexencode_str_new(value);
@@ -683,6 +691,8 @@ rb_digest_base_reset(VALUE self)
683691
rb_digest_metadata_t *algo;
684692
void *pctx;
685693

694+
rb_check_frozen(self);
695+
686696
algo = get_digest_obj_metadata(self);
687697

688698
TypedData_Get_Struct(self, void, &digest_type, pctx);
@@ -705,6 +715,8 @@ rb_digest_base_update(VALUE self, VALUE str)
705715
rb_digest_metadata_t *algo;
706716
void *pctx;
707717

718+
rb_check_frozen(self);
719+
708720
algo = get_digest_obj_metadata(self);
709721

710722
TypedData_Get_Struct(self, void, &digest_type, pctx);
@@ -732,6 +744,7 @@ rb_digest_base_finish(VALUE self)
732744
algo->finish_func(pctx, (unsigned char *)RSTRING_PTR(str));
733745

734746
/* avoid potential coredump caused by use of a finished context */
747+
/* not frozen-checked: #digest and #hexdigest call this on a clone */
735748
algo_init(algo, pctx);
736749

737750
return str;

lib/digest/sha2.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ def initialize(bitlen = 256)
7777
#
7878
# Reset the digest to the initial state and return self.
7979
def reset
80+
raise FrozenError, "can't modify frozen #{self.class}" if frozen?
8081
@sha2.reset
8182
self
8283
end
@@ -87,6 +88,7 @@ def reset
8788
#
8889
# Update the digest using a given _string_ and return self.
8990
def update(str)
91+
raise FrozenError, "can't modify frozen #{self.class}" if frozen?
9092
@sha2.update(str)
9193
self
9294
end

test/digest/test_digest.rb

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,42 @@ def test_eq
8181
assert_equal(md1, md2, self.class::ALGO)
8282
end
8383

84+
def test_frozen
85+
md = self.class::ALGO.new
86+
md << "a"
87+
md.freeze
88+
89+
assert_raise(FrozenError) { md.update("b") }
90+
assert_raise(FrozenError) { md << "b" }
91+
assert_raise(FrozenError) { md.reset }
92+
assert_raise(FrozenError) { md.digest! }
93+
assert_raise(FrozenError) { md.hexdigest! }
94+
assert_raise(FrozenError) { md.base64digest! }
95+
assert_raise(FrozenError) { md.digest("b") }
96+
assert_raise(FrozenError) { md.hexdigest("b") }
97+
98+
assert_equal(self.class::ALGO.hexdigest("a"), md.hexdigest)
99+
end
100+
101+
def test_new_keeps_singleton
102+
md = self.class::ALGO.new
103+
md.extend(Module.new { def extended_marker; end })
104+
def md.singleton_marker; end
105+
106+
assert_respond_to(md.new, :extended_marker)
107+
assert_respond_to(md.new, :singleton_marker)
108+
end
109+
110+
def test_frozen_copy
111+
md = self.class::ALGO.new
112+
md << "a"
113+
md.freeze
114+
115+
assert_equal(self.class::ALGO.hexdigest("a"), md.clone.hexdigest)
116+
assert_equal(self.class::ALGO.hexdigest("a"), md.dup.hexdigest)
117+
assert_raise(FrozenError) { md.new }
118+
end
119+
84120
def test_s_file
85121
Tempfile.create("test_digest_file", mode: File::BINARY) { |tmpfile|
86122
str = "hello, world.\r\n"
@@ -174,6 +210,32 @@ class TestSHA512 < Test::Unit::TestCase
174210

175211
class TestSHA2 < Test::Unit::TestCase
176212

213+
def test_frozen
214+
md = Digest::SHA2.new
215+
md << "a"
216+
md.freeze
217+
218+
assert_raise(FrozenError) { md.update("b") }
219+
assert_raise(FrozenError) { md.reset }
220+
assert_raise(FrozenError) { md.digest! }
221+
assert_raise(FrozenError) { md.hexdigest! }
222+
assert_raise(FrozenError) { md.base64digest! }
223+
assert_raise(FrozenError) { md.digest("b") }
224+
assert_raise(FrozenError) { md.hexdigest("b") }
225+
226+
assert_equal(Digest::SHA256.hexdigest("a"), md.hexdigest)
227+
end
228+
229+
def test_frozen_copy
230+
md = Digest::SHA2.new
231+
md << "a"
232+
md.freeze
233+
234+
assert_equal(Digest::SHA256.hexdigest("a"), md.clone.hexdigest)
235+
assert_equal(Digest::SHA256.hexdigest("a"), md.dup.hexdigest)
236+
assert_raise(FrozenError) { md.new }
237+
end
238+
177239
def test_s_file
178240
Tempfile.create("test_digest_file") { |tmpfile|
179241
str = Data1

0 commit comments

Comments
 (0)