Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Limit max encodings to 256 and raise error #3434

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for writing new specs!

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
Loading