Skip to content

Commit 76a2c4c

Browse files
committed
[GR-45621] Limit max encodings to 256 and raise error
PullRequest: truffleruby/4155
2 parents 178a495 + 9a8c335 commit 76a2c4c

File tree

10 files changed

+63
-1
lines changed

10 files changed

+63
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ Compatibility:
5151
* Add a deprecation warning for `Encoding#replicate` (#3039, @patricklinpl, @manefz, @nirvdrum).
5252
* Change `UnboundMethod#{==,inspect}` to use the owner module rather than the origin (#3039, @rwstauner, @manefz, @patricklinpl)
5353
* Support `lambda` keyword argument in `Proc#parameters` (#3039, @thomasmarshall, @goyox86).
54+
* Limit maximum encoding set size by 256 (#3039, @thomasmarshall, @goyox86).
5455

5556
Performance:
5657

spec/ruby/core/encoding/replicate_spec.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@
7373
Encoding::US_ASCII.replicate('MY-US-ASCII')
7474
}.should complain(/warning: Encoding#replicate is deprecated and will be removed in Ruby 3.3; use the original encoding instead/)
7575
end
76+
77+
it "raises EncodingError if too many encodings" do
78+
code = '1_000.times {|i| Encoding::US_ASCII.replicate("R_#{i}") }'
79+
ruby_exe(code, args: "2>&1", exit_status: 1).should.include?('too many encoding (> 256) (EncodingError)')
80+
end
7681
end
7782

7883
ruby_version_is "3.3" do

spec/ruby/optional/capi/encoding_spec.rb

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
require_relative 'spec_helper'
33
require_relative 'fixtures/encoding'
44

5-
load_extension('encoding')
5+
extension_path = load_extension('encoding')
66

77
describe :rb_enc_get_index, shared: true do
88
it "returns the index of the encoding of a String" do
@@ -721,4 +721,27 @@
721721
str.bytes.should == [0, 0x24]
722722
end
723723
end
724+
725+
describe "rb_define_dummy_encoding" do
726+
it "defines the dummy encoding" do
727+
@s.rb_define_dummy_encoding("FOO")
728+
enc = Encoding.find("FOO")
729+
enc.should.dummy?
730+
end
731+
732+
it "returns the index of the dummy encoding" do
733+
index = @s.rb_define_dummy_encoding("BAR")
734+
index.should == Encoding.list.size - 1
735+
end
736+
737+
ruby_version_is "3.2" do
738+
it "raises EncodingError if too many encodings" do
739+
code = <<-RUBY
740+
require #{extension_path.dump}
741+
1_000.times {|i| CApiEncodingSpecs.new.rb_define_dummy_encoding("R_\#{i}") }
742+
RUBY
743+
ruby_exe(code, args: "2>&1", exit_status: 1).should.include?('too many encoding (> 256) (EncodingError)')
744+
end
745+
end
746+
end
724747
end

spec/ruby/optional/capi/ext/encoding_spec.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,10 @@ static VALUE encoding_spec_rb_enc_left_char_head(VALUE self, VALUE str, VALUE of
320320
return LONG2NUM(result - ptr);
321321
}
322322

323+
static VALUE encoding_spec_rb_define_dummy_encoding(VALUE self, VALUE name) {
324+
return INT2NUM(rb_define_dummy_encoding(RSTRING_PTR(name)));
325+
}
326+
323327
void Init_encoding_spec(void) {
324328
VALUE cls;
325329
native_rb_encoding_pointer = (rb_encoding**) malloc(sizeof(rb_encoding*));
@@ -379,6 +383,7 @@ void Init_encoding_spec(void) {
379383
rb_define_method(cls, "rb_uv_to_utf8", encoding_spec_rb_uv_to_utf8, 2);
380384
rb_define_method(cls, "ONIGENC_MBC_CASE_FOLD", encoding_spec_ONIGENC_MBC_CASE_FOLD, 1);
381385
rb_define_method(cls, "rb_enc_left_char_head", encoding_spec_rb_enc_left_char_head, 2);
386+
rb_define_method(cls, "rb_define_dummy_encoding", encoding_spec_rb_define_dummy_encoding, 1);
382387
}
383388

384389
#ifdef __cplusplus
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
slow:Encoding#replicate raises EncodingError if too many encodings

spec/tags/optional/capi/encoding_tags.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ fails:C-API Encoding function rb_enc_copy sets the encoding of a Regexp to that
55
fails:C-API Encoding function rb_enc_get_index returns -1 for an object without an encoding
66
fails:C-API Encoding function rb_enc_set_index raises an ArgumentError for a non-encoding capable object
77
fails:C-API Encoding function ENCODING_SET raises an ArgumentError for a non-encoding capable object
8+
slow:C-API Encoding function rb_define_dummy_encoding raises EncodingError if too many encodings

src/main/java/org/truffleruby/core/encoding/EncodingManager.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,10 @@ public synchronized Object[] getEncodingList() {
206206
return ArrayUtils.copyOf(ENCODING_LIST_BY_ENCODING_INDEX, ENCODING_LIST_BY_ENCODING_INDEX.length);
207207
}
208208

209+
public int getNumberOfEncodings() {
210+
return ENCODING_LIST_BY_ENCODING_INDEX.length;
211+
}
212+
209213
@TruffleBoundary
210214
public RubyEncoding getRubyEncoding(String name) {
211215
final String normalizedName = name.toLowerCase(Locale.ENGLISH);

src/main/java/org/truffleruby/core/encoding/EncodingNodes.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -705,6 +705,12 @@ static RubyArray encodingReplicate(RubyEncoding object, Object nameObject,
705705

706706
@TruffleBoundary
707707
private static RubyEncoding replicate(Node node, String name, RubyEncoding encoding) {
708+
if (getContext(node).getEncodingManager().getNumberOfEncodings() >= Encodings.MAX_NUMBER_OF_ENCODINGS) {
709+
throw new RaiseException(
710+
getContext(node),
711+
coreExceptions(node).encodingErrorTooManyEncodings(Encodings.MAX_NUMBER_OF_ENCODINGS, node));
712+
}
713+
708714
return getContext(node).getEncodingManager().replicateEncoding(encoding, name);
709715
}
710716

@@ -726,6 +732,12 @@ static RubyArray createDummyEncoding(Object nameObject,
726732

727733
@TruffleBoundary
728734
private static RubyEncoding createDummy(Node node, String name) {
735+
if (getContext(node).getEncodingManager().getNumberOfEncodings() >= Encodings.MAX_NUMBER_OF_ENCODINGS) {
736+
throw new RaiseException(
737+
getContext(node),
738+
coreExceptions(node).encodingErrorTooManyEncodings(Encodings.MAX_NUMBER_OF_ENCODINGS, node));
739+
}
740+
729741
return getContext(node).getEncodingManager().createDummyEncoding(name);
730742
}
731743

src/main/java/org/truffleruby/core/encoding/Encodings.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
public final class Encodings {
3838

3939
public static final int INITIAL_NUMBER_OF_ENCODINGS = EncodingDB.getEncodings().size();
40+
public static final int MAX_NUMBER_OF_ENCODINGS = 256;
4041
public static final RubyEncoding US_ASCII = initializeUsAscii();
4142
private static final RubyEncoding[] BUILT_IN_ENCODINGS = initializeRubyEncodings();
4243

src/main/java/org/truffleruby/core/exception/CoreExceptions.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1138,6 +1138,15 @@ public RubyException encodingError(Object string, RubyEncoding encoding, Node cu
11381138
return ExceptionOperations.createRubyException(context, exceptionClass, errorMessage, currentNode, null);
11391139
}
11401140

1141+
@TruffleBoundary
1142+
public RubyException encodingErrorTooManyEncodings(int maxSize, Node currentNode) {
1143+
RubyClass exceptionClass = context.getCoreLibrary().encodingErrorClass;
1144+
String message = StringUtils.format("too many encoding (> %d)", maxSize);
1145+
RubyString errorMessage = StringOperations.createUTF8String(context, language, message);
1146+
1147+
return ExceptionOperations.createRubyException(context, exceptionClass, errorMessage, currentNode, null);
1148+
}
1149+
11411150
@TruffleBoundary
11421151
public RubyException encodingCompatibilityErrorIncompatible(RubyEncoding a, RubyEncoding b, Node currentNode) {
11431152
return encodingCompatibilityError(

0 commit comments

Comments
 (0)