Skip to content

Commit 65dc6bb

Browse files
committed
Revert "Fix issue #21397 - Refcounting with Throwable is unsound (#21398)"
This reverts commit ecabb34.
1 parent 1e75803 commit 65dc6bb

File tree

2 files changed

+26
-55
lines changed

2 files changed

+26
-55
lines changed

compiler/src/dmd/dinterpret.d

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6782,9 +6782,8 @@ ThrownExceptionExp chainExceptions(ThrownExceptionExp oldest, ThrownExceptionExp
67826782
}
67836783
// Little sanity check to make sure it's really a Throwable
67846784
ClassReferenceExp boss = oldest.thrown;
6785-
const next = 5; // index of Throwable._nextInChainPtr
6786-
with ((*boss.value.elements)[next].type) // Throwable._nextInChainPtr
6787-
assert(ty == Tpointer || ty == Tclass);
6785+
const next = 5; // index of Throwable.next
6786+
assert((*boss.value.elements)[next].type.ty == Tclass); // Throwable.next
67886787
ClassReferenceExp collateral = newest.thrown;
67896788
if (collateral.originalClass().isErrorException() && !boss.originalClass().isErrorException())
67906789
{

druntime/src/object.d

Lines changed: 24 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -2571,27 +2571,8 @@ class Throwable : Object
25712571
* $(D Throwable) is thrown from inside a $(D catch) block. The originally
25722572
* caught $(D Exception) will be chained to the new $(D Throwable) via this
25732573
* field.
2574-
*
2575-
* If the 0 bit is set in this, it means the next exception is refcounted,
2576-
* meaning this object owns that object and should destroy it on
2577-
* destruction.
2578-
*
2579-
* WARNING: This means we are storing an interior pointer to the next in
2580-
* chain, to signify that the next in the chain is actually reference
2581-
* counted. We rely on the fact that a pointer to a Throwable is not 1-byte
2582-
* aligned. It is important to use a local field to indicate reference
2583-
* counting since we are not allowed to look at GC-allocated references
2584-
* inside the destructor. It is very important to store this as a void*,
2585-
* since optimizers can consider an unaligned pointer to not exist.
25862574
*/
2587-
private void* _nextInChainPtr;
2588-
2589-
private @property bool _nextIsRefcounted() @trusted scope pure nothrow @nogc const
2590-
{
2591-
if (__ctfe)
2592-
return false;
2593-
return (cast(size_t)_nextInChainPtr) & 1;
2594-
}
2575+
private Throwable nextInChain;
25952576

25962577
private uint _refcount; // 0 : allocated by GC
25972578
// 1 : allocated by _d_newThrowable()
@@ -2604,36 +2585,24 @@ class Throwable : Object
26042585
* caught $(D Exception) will be chained to the new $(D Throwable) via this
26052586
* field.
26062587
*/
2607-
@property inout(Throwable) next() @trusted inout return scope pure nothrow @nogc
2608-
{
2609-
if (__ctfe)
2610-
return cast(inout(Throwable)) _nextInChainPtr;
2611-
2612-
return cast(inout(Throwable)) (_nextInChainPtr - _nextIsRefcounted);
2613-
}
2614-
2588+
@property inout(Throwable) next() @safe inout return scope pure nothrow @nogc { return nextInChain; }
26152589

26162590
/**
26172591
* Replace next in chain with `tail`.
26182592
* Use `chainTogether` instead if at all possible.
26192593
*/
2620-
@property void next(Throwable tail) @trusted scope pure nothrow @nogc
2594+
@property void next(Throwable tail) @safe scope pure nothrow @nogc
26212595
{
2622-
void* newTail = cast(void*)tail;
26232596
if (tail && tail._refcount)
2624-
{
26252597
++tail._refcount; // increment the replacement *first*
2626-
++newTail; // indicate ref counting is used
2627-
}
26282598

2629-
auto n = next;
2630-
auto nrc = _nextIsRefcounted;
2631-
_nextInChainPtr = null; // sever the tail before deleting it
2599+
auto n = nextInChain;
2600+
nextInChain = null; // sever the tail before deleting it
26322601

2633-
if (nrc)
2602+
if (n && n._refcount)
26342603
_d_delThrowable(n); // now delete the old tail
26352604

2636-
_nextInChainPtr = newTail; // and set the new tail
2605+
nextInChain = tail; // and set the new tail
26372606
}
26382607

26392608
/**
@@ -2652,7 +2621,7 @@ class Throwable : Object
26522621
int opApply(scope int delegate(Throwable) dg)
26532622
{
26542623
int result = 0;
2655-
for (Throwable t = this; t; t = t.next)
2624+
for (Throwable t = this; t; t = t.nextInChain)
26562625
{
26572626
result = dg(t);
26582627
if (result)
@@ -2675,12 +2644,14 @@ class Throwable : Object
26752644
return e2;
26762645
if (!e2)
26772646
return e1;
2647+
if (e2.refcount())
2648+
++e2.refcount();
26782649

2679-
for (auto e = e1; 1; e = e.next)
2650+
for (auto e = e1; 1; e = e.nextInChain)
26802651
{
2681-
if (!e.next)
2652+
if (!e.nextInChain)
26822653
{
2683-
e.next = e2;
2654+
e.nextInChain = e2;
26842655
break;
26852656
}
26862657
}
@@ -2690,7 +2661,9 @@ class Throwable : Object
26902661
@nogc @safe pure nothrow this(string msg, Throwable nextInChain = null)
26912662
{
26922663
this.msg = msg;
2693-
this.next = nextInChain;
2664+
this.nextInChain = nextInChain;
2665+
if (nextInChain && nextInChain._refcount)
2666+
++nextInChain._refcount;
26942667
//this.info = _d_traceContext();
26952668
}
26962669

@@ -2704,9 +2677,8 @@ class Throwable : Object
27042677

27052678
@trusted nothrow ~this()
27062679
{
2707-
if (_nextIsRefcounted)
2708-
_d_delThrowable(next);
2709-
2680+
if (nextInChain && nextInChain._refcount)
2681+
_d_delThrowable(nextInChain);
27102682
// handle owned traceinfo
27112683
if (infoDeallocator !is null)
27122684
{
@@ -2835,23 +2807,23 @@ class Exception : Throwable
28352807
auto e = new Exception("msg");
28362808
assert(e.file == __FILE__);
28372809
assert(e.line == __LINE__ - 2);
2838-
assert(e._nextInChainPtr is null);
2810+
assert(e.nextInChain is null);
28392811
assert(e.msg == "msg");
28402812
}
28412813

28422814
{
28432815
auto e = new Exception("msg", new Exception("It's an Exception!"), "hello", 42);
28442816
assert(e.file == "hello");
28452817
assert(e.line == 42);
2846-
assert(e._nextInChainPtr !is null);
2818+
assert(e.nextInChain !is null);
28472819
assert(e.msg == "msg");
28482820
}
28492821

28502822
{
28512823
auto e = new Exception("msg", "hello", 42, new Exception("It's an Exception!"));
28522824
assert(e.file == "hello");
28532825
assert(e.line == 42);
2854-
assert(e._nextInChainPtr !is null);
2826+
assert(e.nextInChain !is null);
28552827
assert(e.msg == "msg");
28562828
}
28572829

@@ -2918,7 +2890,7 @@ class Error : Throwable
29182890
auto e = new Error("msg");
29192891
assert(e.file is null);
29202892
assert(e.line == 0);
2921-
assert(e._nextInChainPtr is null);
2893+
assert(e.nextInChain is null);
29222894
assert(e.msg == "msg");
29232895
assert(e.bypassedException is null);
29242896
}
@@ -2927,7 +2899,7 @@ class Error : Throwable
29272899
auto e = new Error("msg", new Exception("It's an Exception!"));
29282900
assert(e.file is null);
29292901
assert(e.line == 0);
2930-
assert(e._nextInChainPtr !is null);
2902+
assert(e.nextInChain !is null);
29312903
assert(e.msg == "msg");
29322904
assert(e.bypassedException is null);
29332905
}
@@ -2936,7 +2908,7 @@ class Error : Throwable
29362908
auto e = new Error("msg", "hello", 42, new Exception("It's an Exception!"));
29372909
assert(e.file == "hello");
29382910
assert(e.line == 42);
2939-
assert(e._nextInChainPtr !is null);
2911+
assert(e.nextInChain !is null);
29402912
assert(e.msg == "msg");
29412913
assert(e.bypassedException is null);
29422914
}

0 commit comments

Comments
 (0)