Skip to content

Commit 4963798

Browse files
committed
Fix rb_str_locktmp and rb_str_unlocktmp to raise FrozenError when string is frozen
1 parent 1112b40 commit 4963798

File tree

3 files changed

+37
-10
lines changed

3 files changed

+37
-10
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ Compatibility:
2222
* Fix numeric coercing when `#coerce` method is not public (#3848, @andrykonchin).
2323
* Fix `Kernel#raise` and don't override `cause` at exception re-raising (#3831, @andrykonchin).
2424
* Return a pointer with `#type_size` of 1 for `Pointer#read_pointer` (@eregon).
25+
* Fix `rb_str_locktmp()` and `rb_str_unlocktmp()` to raise `FrozenError` when string argument is frozen (#3752, @andrykonchin).
2526

2627
Performance:
2728

spec/ruby/optional/capi/string_spec.rb

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1201,28 +1201,50 @@ def inspect
12011201

12021202
describe "rb_str_locktmp" do
12031203
it "raises an error when trying to lock an already locked string" do
1204-
str = "test"
1204+
str = +"test"
12051205
@s.rb_str_locktmp(str).should == str
12061206
-> { @s.rb_str_locktmp(str) }.should raise_error(RuntimeError, 'temporal locking already locked string')
12071207
end
12081208

12091209
it "locks a string so that modifications would raise an error" do
1210-
str = "test"
1210+
str = +"test"
12111211
@s.rb_str_locktmp(str).should == str
12121212
-> { str.upcase! }.should raise_error(RuntimeError, 'can\'t modify string; temporarily locked')
12131213
end
1214+
1215+
ruby_bug "#20998", ""..."3.5" do
1216+
it "raises FrozenError if string is frozen" do
1217+
str = -"rb_str_locktmp"
1218+
-> { @s.rb_str_locktmp(str) }.should raise_error(FrozenError)
1219+
1220+
str = +"rb_str_locktmp"
1221+
str.freeze
1222+
-> { @s.rb_str_locktmp(str) }.should raise_error(FrozenError)
1223+
end
1224+
end
12141225
end
12151226

12161227
describe "rb_str_unlocktmp" do
12171228
it "unlocks a locked string" do
1218-
str = "test"
1229+
str = +"test"
12191230
@s.rb_str_locktmp(str)
12201231
@s.rb_str_unlocktmp(str).should == str
12211232
str.upcase!.should == "TEST"
12221233
end
12231234

12241235
it "raises an error when trying to unlock an already unlocked string" do
1225-
-> { @s.rb_str_unlocktmp("test") }.should raise_error(RuntimeError, 'temporal unlocking already unlocked string')
1236+
-> { @s.rb_str_unlocktmp(+"test") }.should raise_error(RuntimeError, 'temporal unlocking already unlocked string')
1237+
end
1238+
1239+
ruby_bug "#20998", ""..."3.5" do
1240+
it "raises FrozenError if string is frozen" do
1241+
str = -"rb_str_locktmp"
1242+
-> { @s.rb_str_unlocktmp(str) }.should raise_error(FrozenError)
1243+
1244+
str = +"rb_str_locktmp"
1245+
str.freeze
1246+
-> { @s.rb_str_unlocktmp(str) }.should raise_error(FrozenError)
1247+
end
12261248
end
12271249
end
12281250

src/main/java/org/truffleruby/cext/CExtNodes.java

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -964,7 +964,10 @@ public abstract static class RbStrLockTmpNode extends CoreMethodArrayArgumentsNo
964964

965965
@Specialization
966966
RubyString rbStrLockTmp(RubyString string,
967-
@Cached InlinedBranchProfile errorProfile) {
967+
@Cached InlinedBranchProfile errorProfile,
968+
@Cached TypeNodes.CheckFrozenNode raiseIfFrozenNode) {
969+
raiseIfFrozenNode.execute(this, string);
970+
968971
if (string.locked) {
969972
errorProfile.enter(this);
970973
throw new RaiseException(getContext(),
@@ -976,8 +979,7 @@ RubyString rbStrLockTmp(RubyString string,
976979

977980
@Specialization
978981
RubyString rbStrLockTmpImmutable(ImmutableRubyString string) {
979-
throw new RaiseException(getContext(),
980-
coreExceptions().runtimeError("temporal locking immutable string", this));
982+
throw new RaiseException(getContext(this), coreExceptions(this).frozenError(string, this));
981983
}
982984

983985
}
@@ -987,7 +989,10 @@ public abstract static class RbStrUnlockTmpNode extends CoreMethodArrayArguments
987989

988990
@Specialization
989991
RubyString rbStrUnlockTmp(RubyString string,
990-
@Cached InlinedBranchProfile errorProfile) {
992+
@Cached InlinedBranchProfile errorProfile,
993+
@Cached TypeNodes.CheckFrozenNode raiseIfFrozenNode) {
994+
raiseIfFrozenNode.execute(this, string);
995+
991996
if (!string.locked) {
992997
errorProfile.enter(this);
993998
throw new RaiseException(getContext(),
@@ -999,8 +1004,7 @@ RubyString rbStrUnlockTmp(RubyString string,
9991004

10001005
@Specialization
10011006
ImmutableRubyString rbStrUnlockTmpImmutable(ImmutableRubyString string) {
1002-
throw new RaiseException(getContext(),
1003-
coreExceptions().runtimeError("temporal unlocking immutable string", this));
1007+
throw new RaiseException(getContext(this), coreExceptions(this).frozenError(string, this));
10041008
}
10051009

10061010
}

0 commit comments

Comments
 (0)