Skip to content

Commit d66b260

Browse files
committed
Fix NoMethodError when encoding with invalid: :replace option
When encoding a string with `invalid: :replace` and `replace:` options but without `undef: :replace`, JRuby was incorrectly throwing NoMethodError instead of Encoding::UndefinedConversionError. The bug occurred because when `ecopts` hash exists (due to `:replace` option) but doesn't contain a `:fallback` key, the code was setting `fallbackFunc` to `AREF_FALLBACK` with a nil `fallback` value. When an undefined conversion was encountered, it tried to call `nil.[]()` which raised NoMethodError. The fix adds a check for `!fallback.isNil()` before assigning the fallback function, ensuring that the fallback is only used when explicitly provided. Fixes #9009
1 parent 435d102 commit d66b260

File tree

2 files changed

+31
-8
lines changed

2 files changed

+31
-8
lines changed

core/src/main/java/org/jruby/util/io/EncodingUtils.java

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1515,14 +1515,16 @@ public static void transcodeLoop(ThreadContext context, byte[] inBytes, Ptr inPo
15151515

15161516
if (!ecopts.isNil() && ecopts instanceof RubyHash) {
15171517
fallback = ((RubyHash)ecopts).op_aref(context, asSymbol(context, "fallback"));
1518-
if (fallback instanceof RubyHash) {
1519-
fallbackFunc = HASH_FALLBACK;
1520-
} else if (fallback instanceof RubyProc) { // not quite same check as MRI
1521-
fallbackFunc = PROC_FALLBACK;
1522-
} else if (fallback instanceof RubyMethod) { // not quite same check as MRI
1523-
fallbackFunc = METHOD_FALLBACK;
1524-
} else {
1525-
fallbackFunc = AREF_FALLBACK;
1518+
if (!fallback.isNil()) {
1519+
if (fallback instanceof RubyHash) {
1520+
fallbackFunc = HASH_FALLBACK;
1521+
} else if (fallback instanceof RubyProc) { // not quite same check as MRI
1522+
fallbackFunc = PROC_FALLBACK;
1523+
} else if (fallback instanceof RubyMethod) { // not quite same check as MRI
1524+
fallbackFunc = METHOD_FALLBACK;
1525+
} else {
1526+
fallbackFunc = AREF_FALLBACK;
1527+
}
15261528
}
15271529
}
15281530

test/jruby/test_string.rb

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,4 +274,25 @@ def test_strange_printf
274274
opponent = '41181 jpa:awh'.scan("jpa")[0]
275275
assert_equal('jpa', sprintf("%s", opponent))
276276
end
277+
278+
# GH-9009: encoding with invalid: :replace but without undef: :replace
279+
# should raise UndefinedConversionError, not NoMethodError
280+
def test_encode_undefined_conversion_with_invalid_replace
281+
# "Ā" (U+0100) is valid UTF-8 but not representable in windows-1252
282+
str = "1ĀŽ2"
283+
284+
# With only invalid: :replace (no undef:), should raise UndefinedConversionError
285+
assert_raises(Encoding::UndefinedConversionError) do
286+
str.encode("windows-1252", invalid: :replace, replace: "")
287+
end
288+
289+
# With undef: :replace, should replace undefined chars
290+
result = str.encode("windows-1252", undef: :replace, replace: "")
291+
assert_equal "1\x8E2".force_encoding("windows-1252"), result
292+
293+
# Without any options, should also raise UndefinedConversionError
294+
assert_raises(Encoding::UndefinedConversionError) do
295+
str.encode("windows-1252")
296+
end
297+
end
277298
end

0 commit comments

Comments
 (0)