Ensure Fiber storage is only accessed from the Fiber it belongs to
This commit is contained in:
parent
d557f17974
commit
0efa36ac06
Notes:
git
2022-12-20 18:32:45 +00:00
10
cont.c
10
cont.c
@ -2069,6 +2069,14 @@ fiber_storage_get(rb_fiber_t *fiber)
|
|||||||
return storage;
|
return storage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void storage_access_must_be_from_same_fiber(VALUE self) {
|
||||||
|
rb_fiber_t *fiber = fiber_ptr(self);
|
||||||
|
rb_fiber_t *current = fiber_current();
|
||||||
|
if (fiber != current) {
|
||||||
|
rb_raise(rb_eArgError, "Fiber storage can only be accessed from the Fiber it belongs to");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* call-seq: Fiber.current.storage -> hash (dup)
|
* call-seq: Fiber.current.storage -> hash (dup)
|
||||||
*
|
*
|
||||||
@ -2077,6 +2085,7 @@ fiber_storage_get(rb_fiber_t *fiber)
|
|||||||
static VALUE
|
static VALUE
|
||||||
rb_fiber_storage_get(VALUE self)
|
rb_fiber_storage_get(VALUE self)
|
||||||
{
|
{
|
||||||
|
storage_access_must_be_from_same_fiber(self);
|
||||||
return rb_obj_dup(fiber_storage_get(fiber_ptr(self)));
|
return rb_obj_dup(fiber_storage_get(fiber_ptr(self)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2134,6 +2143,7 @@ rb_fiber_storage_set(VALUE self, VALUE value)
|
|||||||
"Fiber#storage= is experimental and may be removed in the future!");
|
"Fiber#storage= is experimental and may be removed in the future!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
storage_access_must_be_from_same_fiber(self);
|
||||||
fiber_storage_validate(value);
|
fiber_storage_validate(value);
|
||||||
|
|
||||||
fiber_ptr(self)->cont.saved_ec.storage = rb_obj_dup(value);
|
fiber_ptr(self)->cont.saved_ec.storage = rb_obj_dup(value);
|
||||||
|
@ -11,8 +11,7 @@ describe "Fiber.new(storage:)" do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it "creates a fiber with lazily initialized storage" do
|
it "creates a fiber with lazily initialized storage" do
|
||||||
fiber = Fiber.new(storage: nil) {}
|
Fiber.new(storage: nil) { Fiber.current.storage }.resume.should == {}
|
||||||
fiber.storage.should == {}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it "creates a fiber by inheriting the storage of the parent fiber" do
|
it "creates a fiber by inheriting the storage of the parent fiber" do
|
||||||
@ -28,33 +27,34 @@ describe "Fiber.new(storage:)" do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "Fiber#storage" do
|
describe "Fiber#storage=" do
|
||||||
ruby_version_is "3.2" do
|
ruby_version_is "3.2" do
|
||||||
it "can clear the storage of the fiber" do
|
it "can clear the storage of the fiber" do
|
||||||
fiber = Fiber.new(storage: {life: 42}) { Fiber.current.storage }
|
fiber = Fiber.new(storage: {life: 42}) {
|
||||||
fiber.storage = nil
|
Fiber.current.storage = nil
|
||||||
|
Fiber.current.storage
|
||||||
|
}
|
||||||
fiber.resume.should == {}
|
fiber.resume.should == {}
|
||||||
end
|
end
|
||||||
|
|
||||||
it "can set the storage of the fiber" do
|
it "can set the storage of the fiber" do
|
||||||
fiber = Fiber.new(storage: {life: 42}) { Fiber.current.storage }
|
fiber = Fiber.new(storage: {life: 42}) {
|
||||||
fiber.storage = {life: 43}
|
Fiber.current.storage = {life: 43}
|
||||||
|
Fiber.current.storage
|
||||||
|
}
|
||||||
fiber.resume.should == {life: 43}
|
fiber.resume.should == {life: 43}
|
||||||
end
|
end
|
||||||
|
|
||||||
it "can't set the storage of the fiber to non-hash" do
|
it "can't set the storage of the fiber to non-hash" do
|
||||||
fiber = Fiber.new(storage: {life: 42}) { Fiber.current.storage }
|
-> { Fiber.current.storage = 42 }.should raise_error(TypeError)
|
||||||
-> { fiber.storage = 42 }.should raise_error(TypeError)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it "can't set the storage of the fiber to a frozen hash" do
|
it "can't set the storage of the fiber to a frozen hash" do
|
||||||
fiber = Fiber.new(storage: {life: 42}) { Fiber.current.storage }
|
-> { Fiber.current.storage = {life: 43}.freeze }.should raise_error(FrozenError)
|
||||||
-> { fiber.storage = {life: 43}.freeze }.should raise_error(FrozenError)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it "can't set the storage of the fiber to a hash with non-symbol keys" do
|
it "can't set the storage of the fiber to a hash with non-symbol keys" do
|
||||||
fiber = Fiber.new(storage: {life: 42}) { Fiber.current.storage }
|
-> { Fiber.current.storage = {life: 43, Object.new => 44} }.should raise_error(TypeError)
|
||||||
-> { fiber.storage = {life: 43, Object.new => 44} }.should raise_error(TypeError)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -41,6 +41,18 @@ class TestFiberStorage < Test::Unit::TestCase
|
|||||||
Warning[:experimental] = old
|
Warning[:experimental] = old
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_storage_only_allow_access_from_same_fiber
|
||||||
|
old, Warning[:experimental] = Warning[:experimental], false
|
||||||
|
|
||||||
|
f = Fiber.new do
|
||||||
|
Fiber[:a] = 1
|
||||||
|
end
|
||||||
|
assert_raise(ArgumentError) { f.storage }
|
||||||
|
assert_raise(ArgumentError) { f.storage = {} }
|
||||||
|
ensure
|
||||||
|
Warning[:experimental] = old
|
||||||
|
end
|
||||||
|
|
||||||
def test_inherited_storage
|
def test_inherited_storage
|
||||||
Fiber.new(storage: {foo: :bar}) do
|
Fiber.new(storage: {foo: :bar}) do
|
||||||
f = Fiber.new do
|
f = Fiber.new do
|
||||||
|
Loading…
x
Reference in New Issue
Block a user