Skip to content

Commit a65bde3

Browse files
andrykonchineregon
authored andcommitted
[GR-18163] Fix rb_str_locktmp() and rb_str_unlocktmp() to accept Strings that are already frozen
PullRequest: truffleruby/4435
2 parents c8d7442 + 4963798 commit a65bde3

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
@@ -965,7 +965,10 @@ public abstract static class RbStrLockTmpNode extends CoreMethodArrayArgumentsNo
965965

966966
@Specialization
967967
RubyString rbStrLockTmp(RubyString string,
968-
@Cached InlinedBranchProfile errorProfile) {
968+
@Cached InlinedBranchProfile errorProfile,
969+
@Cached TypeNodes.CheckFrozenNode raiseIfFrozenNode) {
970+
raiseIfFrozenNode.execute(this, string);
971+
969972
if (string.locked) {
970973
errorProfile.enter(this);
971974
throw new RaiseException(getContext(),
@@ -977,8 +980,7 @@ RubyString rbStrLockTmp(RubyString string,
977980

978981
@Specialization
979982
RubyString rbStrLockTmpImmutable(ImmutableRubyString string) {
980-
throw new RaiseException(getContext(),
981-
coreExceptions().runtimeError("temporal locking immutable string", this));
983+
throw new RaiseException(getContext(this), coreExceptions(this).frozenError(string, this));
982984
}
983985

984986
}
@@ -988,7 +990,10 @@ public abstract static class RbStrUnlockTmpNode extends CoreMethodArrayArguments
988990

989991
@Specialization
990992
RubyString rbStrUnlockTmp(RubyString string,
991-
@Cached InlinedBranchProfile errorProfile) {
993+
@Cached InlinedBranchProfile errorProfile,
994+
@Cached TypeNodes.CheckFrozenNode raiseIfFrozenNode) {
995+
raiseIfFrozenNode.execute(this, string);
996+
992997
if (!string.locked) {
993998
errorProfile.enter(this);
994999
throw new RaiseException(getContext(),
@@ -1000,8 +1005,7 @@ RubyString rbStrUnlockTmp(RubyString string,
10001005

10011006
@Specialization
10021007
ImmutableRubyString rbStrUnlockTmpImmutable(ImmutableRubyString string) {
1003-
throw new RaiseException(getContext(),
1004-
coreExceptions().runtimeError("temporal unlocking immutable string", this));
1008+
throw new RaiseException(getContext(this), coreExceptions(this).frozenError(string, this));
10051009
}
10061010

10071011
}

0 commit comments

Comments
 (0)