Skip to content

Commit d2d8607

Browse files
committed
[GR-26970] Backports for 20.3 batch 2
PullRequest: truffleruby/2128
2 parents d48121d + e1dc3a3 commit d2d8607

File tree

24 files changed

+127
-45
lines changed

24 files changed

+127
-45
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ Bug fixes:
1919
* Fixed `SystemStackError` sometimes replaced by an internal Java `NoClassDefFoundError` on JVM (#1743).
2020
* Fixed constant/identifier detection in lexer for non-ASCII encodings (#2079, #2102, @ivoanjo).
2121
* Fixed parsing of `--jvm` as an application argument (#2108).
22+
* Fix `rb_rescue2` to ignore the end marker `(VALUE)0` (#2127, #2130).
23+
* Fix `String#{chomp, chomp!}` issue with invalid encoded strings (#2133).
24+
* Fix status and output when SystemExit is subclassed and raised (#2128)
2225

2326
Compatibility:
2427

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
require_relative '../../spec_helper'
2+
3+
describe "SystemExit" do
4+
it "sets the exit status and exits silently when raised" do
5+
code = 'raise SystemExit.new(7)'
6+
result = ruby_exe(code, args: "2>&1")
7+
result.should == ""
8+
$?.exitstatus.should == 7
9+
end
10+
11+
it "sets the exit status and exits silently when raised when subclassed" do
12+
code = 'class CustomExit < SystemExit; end; raise CustomExit.new(8)'
13+
result = ruby_exe(code, args: "2>&1")
14+
result.should == ""
15+
$?.exitstatus.should == 8
16+
end
17+
end

spec/ruby/core/string/chomp_spec.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@
5555
$/ = "cdef"
5656
"abcdef".chomp.should == "ab"
5757
end
58+
59+
it "removes one trailing newline for string with invalid encoding" do
60+
"\xa0\xa1\n".chomp.should == "\xa0\xa1"
61+
end
5862
end
5963

6064
describe "when passed nil" do
@@ -108,6 +112,10 @@
108112
it "returns an empty String when self is empty" do
109113
"".chomp("").should == ""
110114
end
115+
116+
it "removes one trailing newline for string with invalid encoding" do
117+
"\xa0\xa1\n".chomp("").should == "\xa0\xa1"
118+
end
111119
end
112120

113121
describe "when passed '\\n'" do

spec/ruby/optional/capi/kernel_spec.rb

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -396,12 +396,20 @@ def proc_caller
396396
proc = -> x { x }
397397
arg_error_proc = -> *_ { raise ArgumentError, '' }
398398
run_error_proc = -> *_ { raise RuntimeError, '' }
399-
type_error_proc = -> *_ { raise TypeError, '' }
399+
type_error_proc = -> *_ { raise Exception, 'custom error' }
400400
@s.rb_rescue2(arg_error_proc, :no_exc, proc, :exc, ArgumentError, RuntimeError).should == :exc
401401
@s.rb_rescue2(run_error_proc, :no_exc, proc, :exc, ArgumentError, RuntimeError).should == :exc
402402
-> {
403403
@s.rb_rescue2(type_error_proc, :no_exc, proc, :exc, ArgumentError, RuntimeError)
404-
}.should raise_error(TypeError)
404+
}.should raise_error(Exception, 'custom error')
405+
end
406+
407+
ruby_bug "#17305", ""..."2.7" do
408+
it "raises TypeError if one of the passed exceptions is not a Module" do
409+
-> {
410+
@s.rb_rescue2(-> *_ { raise RuntimeError, "foo" }, :no_exc, -> x { x }, :exc, Object.new, 42)
411+
}.should raise_error(TypeError, /class or module required/)
412+
end
405413
end
406414
end
407415

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
slow:SystemExit sets the exit status and exits silently when raised
2+
slow:SystemExit sets the exit status and exits silently when raised when subclassed

src/main/c/cext/exception.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@ VALUE rb_rescue2(VALUE (*b_proc)(ANYARGS), VALUE data1, VALUE (*r_proc)(ANYARGS)
8585
// arguments using the polyglot api.
8686
for (;n < total; n++) {
8787
VALUE arg = polyglot_get_arg(n);
88+
if (arg == (VALUE)0) {
89+
break;
90+
}
91+
8892
rb_ary_push(rescued, arg);
8993
}
9094
return cext_rb_rescue2(b_proc, data1, r_proc, data2, rb_tr_unwrap(rescued));

src/main/java/org/truffleruby/core/array/ArrayNodes.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1591,7 +1591,7 @@ private RubyString finishPack(int formatLength, BytesResult result) {
15911591

15921592
@TruffleBoundary
15931593
protected RootCallTarget compileFormat(RubyString format) {
1594-
return new PackCompiler(getContext(), this).compile(format.toString());
1594+
return new PackCompiler(getContext(), this).compile(format.getJavaString());
15951595
}
15961596

15971597
protected int getCacheLimit() {

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

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,14 @@ public void showExceptionIfDebug(RubyClass rubyClass, Object message, Backtrace
8989
}
9090
}
9191

92+
public String inspectReceiver(Object receiver) {
93+
RubyString rubyString = (RubyString) context.send(
94+
context.getCoreLibrary().truffleExceptionOperationsModule,
95+
"receiver_string",
96+
receiver);
97+
return rubyString.getJavaString();
98+
}
99+
92100
// ArgumentError
93101

94102
public RubyException argumentErrorOneHashRequired(Node currentNode) {
@@ -488,17 +496,17 @@ public RubyException typeErrorCantConvertInto(Object from, String toClass, Node
488496

489497
@TruffleBoundary
490498
public RubyException typeErrorIsNotA(Object value, String expectedType, Node currentNode) {
491-
return typeErrorIsNotA(value.toString(), expectedType, currentNode);
499+
return typeErrorIsNotA(inspectReceiver(value), expectedType, currentNode);
492500
}
493501

494502
@TruffleBoundary
495503
public RubyException typeErrorIsNotA(String value, String expectedType, Node currentNode) {
496-
return typeError(StringUtils.format("%s is not a %s", value, expectedType), currentNode);
504+
return typeError(value + " is not a " + expectedType, currentNode);
497505
}
498506

499507
@TruffleBoundary
500508
public RubyException typeErrorIsNotAClassModule(Object value, Node currentNode) {
501-
return typeError(StringUtils.format("%s is not a class/module", value), currentNode);
509+
return typeError(inspectReceiver(value) + " is not a class/module", currentNode);
502510
}
503511

504512
@TruffleBoundary

src/main/java/org/truffleruby/core/kernel/AtExitManager.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@
1616

1717
import org.truffleruby.RubyContext;
1818
import org.truffleruby.core.exception.RubyException;
19-
import org.truffleruby.core.klass.RubyClass;
2019
import org.truffleruby.core.proc.ProcOperations;
2120
import org.truffleruby.core.proc.RubyProc;
2221
import org.truffleruby.language.control.ExitException;
2322
import org.truffleruby.language.control.RaiseException;
2423

2524
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
25+
import org.truffleruby.language.objects.IsANode;
2626

2727
public class AtExitManager {
2828

@@ -83,9 +83,9 @@ public List<RubyProc> getHandlers() {
8383
}
8484

8585
public static boolean isSilentException(RubyContext context, RubyException rubyException) {
86-
final RubyClass logicalClass = rubyException.getLogicalClass();
87-
return logicalClass == context.getCoreLibrary().systemExitClass ||
88-
logicalClass == context.getCoreLibrary().signalExceptionClass;
86+
final IsANode isANode = IsANode.getUncached();
87+
return isANode.executeIsA(rubyException, context.getCoreLibrary().systemExitClass) ||
88+
isANode.executeIsA(rubyException, context.getCoreLibrary().signalExceptionClass);
8989
}
9090

9191
private static void handleAtExitException(RubyContext context, RubyException rubyException) {

src/main/java/org/truffleruby/core/module/ModuleFields.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,10 @@ public RubyConstant setConstant(RubyContext context, Node currentNode, String na
343343
@TruffleBoundary
344344
public void setAutoloadConstant(RubyContext context, Node currentNode, String name, RubyString filename) {
345345
RubyConstant autoloadConstant = setConstantInternal(context, currentNode, name, filename, true);
346+
if (autoloadConstant == null) {
347+
return;
348+
}
349+
346350
if (context.getOptions().LOG_AUTOLOAD) {
347351
RubyLanguage.LOGGER.info(() -> String.format(
348352
"%s: setting up autoload %s with %s",
@@ -351,7 +355,7 @@ public void setAutoloadConstant(RubyContext context, Node currentNode, String na
351355
filename));
352356
}
353357
final ReentrantLockFreeingMap<String> fileLocks = getContext().getFeatureLoader().getFileLocks();
354-
final ReentrantLock lock = fileLocks.get(filename.toString());
358+
final ReentrantLock lock = fileLocks.get(filename.getJavaString());
355359
if (lock.isLocked()) {
356360
// We need to handle the new autoload constant immediately
357361
// if Object.autoload(name, filename) is executed from filename.rb
@@ -367,10 +371,22 @@ private RubyConstant setConstantInternal(RubyContext context, Node currentNode,
367371

368372
SharedObjects.propagate(context, rubyModule, value);
369373

374+
final String autoloadPath = autoload ? ((RubyString) value).getJavaString() : null;
370375
RubyConstant previous;
371376
RubyConstant newConstant;
372377
do {
373378
previous = constants.get(name);
379+
if (autoload && previous != null) {
380+
if (previous.hasValue()) {
381+
// abort, do not set an autoload constant, the constant already has a value
382+
return null;
383+
} else if (previous.isAutoload() &&
384+
previous.getAutoloadConstant().getAutoloadPath().equals(autoloadPath)) {
385+
// already an autoload constant with the same path,
386+
// do nothing so we don't replace the AutoloadConstant#autoloadLock which might be already acquired
387+
return null;
388+
}
389+
}
374390
newConstant = newConstant(currentNode, name, value, autoload, previous);
375391
} while (!ConcurrentOperations.replace(constants, name, previous, newConstant));
376392

0 commit comments

Comments
 (0)