Bug in exception chaining results in exceptions escaping
Yuxuan Shui via Digitalmars-d
digitalmars-d at puremagic.com
Tue Dec 13 16:14:24 PST 2016
Test case originally by Ali Çehreli, modified by me to expose a
more serious bug:
import core.stdc.stdio;
class TestException : Exception {
this(string msg) {
super(typeof(this).stringof~": "~msg);
}
}
class UnrelatedException: Exception {
this() {
super("You should've caught me!!");
}
}
class TestError : Error {
this(string msg) {
super(typeof(this).stringof~": "~msg);
}
}
// Causes an exception chain where the node at index errorIndex
is an
// Error (others are all Exceptions).
void causeExceptionChain(size_t chainLength, size_t errorIndex) {
void throws(size_t n) {
scope (exit) {
string msg = [ cast(char)('a'+n) ].idup;
if (n == errorIndex) {
throw new TestError(msg);
}
else {
throw new TestException(msg);
}
}
if (n != 0) {
// Redundant 'return' keyword due to
// https://issues.dlang.org/show_bug.cgi?id=16960
return throws(n - 1);
}
}
throws(chainLength - 1);
}
void main() {
// Step 1: Setup a corrupted thread exception chain
version(bug) {
try {
size_t errorIndex = 1;
causeExceptionChain(2, errorIndex);
}
catch (Error original) {
printf("Caught\n");
string prefix = "";
for ({ size_t i; Throwable ex = original; } ex; ex =
ex.next, ++i) {
printf("%.*s%.*s\n", prefix.length, prefix.ptr,
ex.msg.length, ex.msg.ptr);
prefix = prefix~" ";
}
printf("Bypassed chain was:\n");
prefix = "";
// This loop should print something, but nope.
for ({ size_t i; Throwable ex =
original.bypassedException; } ex; ex = ex.next, ++i) {
printf("%.*s%.*s\n", prefix.length, prefix.ptr,
ex.msg.length, ex.msg.ptr);
prefix = prefix~" ";
}
}
}
// Now there's leftover exceptions unhandled
try {
// Step 2
throw new UnrelatedException();
} catch (UnrelatedException x) {
// Should be caught here
}
// But it escaped!!
// It even has some ghost exceptions chained to it.
}
Bug is fixed in https://github.com/dlang/druntime/pull/1712,
please review.
More information about the Digitalmars-d
mailing list