Skip to content

Commit

Permalink
Limit max encodings to 256 and raise error
Browse files Browse the repository at this point in the history
Co-authored-by: Jose Narvaez <jose.narvaez@shopify.com>
  • Loading branch information
thomasmarshall and goyox86 committed Feb 9, 2024
1 parent 5522b6a commit 7408c34
Show file tree
Hide file tree
Showing 9 changed files with 64 additions and 1 deletion.
7 changes: 7 additions & 0 deletions spec/ruby/core/encoding/replicate_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,13 @@
end
end

ruby_version_is "3.2"..."3.3" do
it "raises EncodingError if too many encodings" do
code = '1_000.times {|i| Encoding::US_ASCII.replicate("R_#{i}") }'
ruby_exe(code, args: "2>&1", exit_status: 1).should.include?('too many encoding (> 256) (EncodingError)')
end
end

ruby_version_is "3.3" do
it "has been removed" do
Encoding::US_ASCII.should_not.respond_to?(:replicate, true)
Expand Down
25 changes: 24 additions & 1 deletion spec/ruby/optional/capi/encoding_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
require_relative 'spec_helper'
require_relative 'fixtures/encoding'

load_extension('encoding')
extension_path = load_extension('encoding')

describe :rb_enc_get_index, shared: true do
it "returns the index of the encoding of a String" do
Expand Down Expand Up @@ -721,4 +721,27 @@
str.bytes.should == [0, 0x24]
end
end

describe "rb_define_dummy_encoding" do
it "defines the dummy encoding" do
@s.rb_define_dummy_encoding("FOO")
enc = Encoding.find("FOO")
enc.should.dummy?
end

it "returns the index of the dummy encoding" do
index = @s.rb_define_dummy_encoding("BAR")
index.should == Encoding.list.size - 1
end

ruby_version_is "3.2" do
it "raises EncodingError if too many encodings" do
code = <<-RUBY
require #{extension_path.dump}
1_000.times {|i| CApiEncodingSpecs.new.rb_define_dummy_encoding(\"R_\#{i}\") }
RUBY
ruby_exe(code, args: "2>&1", exit_status: 1).should.include?('too many encoding (> 256) (EncodingError)')
end
end
end
end
5 changes: 5 additions & 0 deletions spec/ruby/optional/capi/ext/encoding_spec.c
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,10 @@ static VALUE encoding_spec_rb_enc_left_char_head(VALUE self, VALUE str, VALUE of
return LONG2NUM(result - ptr);
}

static VALUE encoding_spec_rb_define_dummy_encoding(VALUE self, VALUE name) {
return INT2NUM(rb_define_dummy_encoding(RSTRING_PTR(name)));
}

void Init_encoding_spec(void) {
VALUE cls;
native_rb_encoding_pointer = (rb_encoding**) malloc(sizeof(rb_encoding*));
Expand Down Expand Up @@ -379,6 +383,7 @@ void Init_encoding_spec(void) {
rb_define_method(cls, "rb_uv_to_utf8", encoding_spec_rb_uv_to_utf8, 2);
rb_define_method(cls, "ONIGENC_MBC_CASE_FOLD", encoding_spec_ONIGENC_MBC_CASE_FOLD, 1);
rb_define_method(cls, "rb_enc_left_char_head", encoding_spec_rb_enc_left_char_head, 2);
rb_define_method(cls, "rb_define_dummy_encoding", encoding_spec_rb_define_dummy_encoding, 1);
}

#ifdef __cplusplus
Expand Down
1 change: 1 addition & 0 deletions spec/tags/core/encoding/replicate_tags.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
slow:Encoding#replicate raises EncodingError if too many encodings
1 change: 1 addition & 0 deletions spec/tags/optional/capi/encoding_tags.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ fails:C-API Encoding function rb_enc_copy sets the encoding of a Regexp to that
fails:C-API Encoding function rb_enc_get_index returns -1 for an object without an encoding
fails:C-API Encoding function rb_enc_set_index raises an ArgumentError for a non-encoding capable object
fails:C-API Encoding function ENCODING_SET raises an ArgumentError for a non-encoding capable object
slow:C-API Encoding function rb_define_dummy_encoding raises EncodingError if too many encodings
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,10 @@ public synchronized Object[] getEncodingList() {
return ArrayUtils.copyOf(ENCODING_LIST_BY_ENCODING_INDEX, ENCODING_LIST_BY_ENCODING_INDEX.length);
}

public int getNumberOfEncodings() {
return ENCODING_LIST_BY_ENCODING_INDEX.length;
}

@TruffleBoundary
public RubyEncoding getRubyEncoding(String name) {
final String normalizedName = name.toLowerCase(Locale.ENGLISH);
Expand Down
12 changes: 12 additions & 0 deletions src/main/java/org/truffleruby/core/encoding/EncodingNodes.java
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,12 @@ static RubyArray encodingReplicate(RubyEncoding object, Object nameObject,

@TruffleBoundary
private static RubyEncoding replicate(Node node, String name, RubyEncoding encoding) {
if (getContext(node).getEncodingManager().getNumberOfEncodings() >= Encodings.MAX_NUMBER_OF_ENCODINGS) {
throw new RaiseException(
getContext(node),
coreExceptions(node).encodingErrorTooManyEncodings(Encodings.MAX_NUMBER_OF_ENCODINGS, node));
}

return getContext(node).getEncodingManager().replicateEncoding(encoding, name);
}

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

@TruffleBoundary
private static RubyEncoding createDummy(Node node, String name) {
if (getContext(node).getEncodingManager().getNumberOfEncodings() >= Encodings.MAX_NUMBER_OF_ENCODINGS) {
throw new RaiseException(
getContext(node),
coreExceptions(node).encodingErrorTooManyEncodings(Encodings.MAX_NUMBER_OF_ENCODINGS, node));
}

return getContext(node).getEncodingManager().createDummyEncoding(name);
}

Expand Down
1 change: 1 addition & 0 deletions src/main/java/org/truffleruby/core/encoding/Encodings.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
public final class Encodings {

public static final int INITIAL_NUMBER_OF_ENCODINGS = EncodingDB.getEncodings().size();
public static final int MAX_NUMBER_OF_ENCODINGS = 256;
public static final RubyEncoding US_ASCII = initializeUsAscii();
private static final RubyEncoding[] BUILT_IN_ENCODINGS = initializeRubyEncodings();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1138,6 +1138,15 @@ public RubyException encodingError(Object string, RubyEncoding encoding, Node cu
return ExceptionOperations.createRubyException(context, exceptionClass, errorMessage, currentNode, null);
}

@TruffleBoundary
public RubyException encodingErrorTooManyEncodings(int maxSize, Node currentNode) {
RubyClass exceptionClass = context.getCoreLibrary().encodingErrorClass;
String message = StringUtils.format("too many encoding (> %d)", maxSize);
RubyString errorMessage = StringOperations.createUTF8String(context, language, message);

return ExceptionOperations.createRubyException(context, exceptionClass, errorMessage, currentNode, null);
}

@TruffleBoundary
public RubyException encodingCompatibilityErrorIncompatible(RubyEncoding a, RubyEncoding b, Node currentNode) {
return encodingCompatibilityError(
Expand Down

0 comments on commit 7408c34

Please sign in to comment.