llvm.org GIT mirror llvm / fe9953a
[WinEH] Verify unwind edges against EH pad tree Summary: Funclet EH personalities require a tree-like nesting among funclets (enforced by the ParentPad linkage in the IR), and also require that unwind edges conform to certain rules with respect to the tree: - An unwind edge may exit 0 or more ancestor pads - An unwind edge must enter exactly one EH pad, which must be distinct from any exited pads - A cleanupret's edge must exit its cleanuppad Describe these rules in the LangRef, and enforce them in the verifier. Reviewers: rnk, majnemer, andrew.w.kaylor Subscribers: llvm-commits Differential Revision: http://reviews.llvm.org/D15961 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@257272 91177308-0d34-0410-b5e6-96231b3b80d8 Joseph Tremoulet 3 years ago
6 changed file(s) with 213 addition(s) and 49 deletion(s). Raw diff Collapse all Expand all
774774
775775 The "inner" ``catchswitch`` consumes ``%1`` which is produced by the outer
776776 catchswitch.
777
778 .. _wineh-constraints:
779
780 Funclet transitions
781 -----------------------
782
783 The EH tables for personalities that use funclets make implicit use of the
784 funclet nesting relationship to encode unwind destinations, and so are
785 constrained in the set of funclet transitions they can represent. The related
786 LLVM IR instructions accordingly have constraints that ensure encodability of
787 the EH edges in the flow graph.
788
789 A ``catchswitch``, ``catchpad``, or ``cleanuppad`` is said to be "entered"
790 when it executes. It may subsequently be "exited" by any of the following
791 means:
792
793 * A ``catchswitch`` is immediately exited when none of its constituent
794 ``catchpad``\ s are appropriate for the in-flight exception and it unwinds
795 to its unwind destination or the caller.
796 * A ``catchpad`` and its parent ``catchswitch`` are both exited when a
797 ``catchret`` from the ``catchpad`` is executed.
798 * A ``cleanuppad`` is exited when a ``cleanupret`` from it is executed.
799 * Any of these pads is exited when control unwinds to the function's caller,
800 either by a ``call`` which unwinds all the way to the function's caller,
801 a nested ``catchswitch`` marked "``unwinds to caller``", or a nested
802 ``cleanuppad``\ 's ``cleanupret`` marked "``unwinds to caller"``.
803 * Any of these pads is exited when an unwind edge (from an ``invoke``,
804 nested ``catchswitch``, or nested ``cleanuppad``\ 's ``cleanupret``)
805 unwinds to a destination pad that is not a descendant of the given pad.
806
807 Note that the ``ret`` instruction is *not* a valid way to exit a funclet pad;
808 it is undefined behavior to execute a ``ret`` when a pad has been entered but
809 not exited.
810
811 A single unwind edge may exit any number of pads (with the restrictions that
812 the edge from a ``catchswitch`` must exit at least itself, and the edge from
813 a ``cleanupret`` must exit at least its ``cleanuppad``), and then must enter
814 exactly one pad, which must be distinct from all the exited pads. The parent
815 of the pad that an unwind edge enters must be the most-recently-entered
816 not-yet-exited pad (after exiting from any pads that the unwind edge exits),
817 or "none" if there is no such pad. This ensures that the stack of executing
818 funclets at run-time always corresponds to some path in the funclet pad tree
819 that the parent tokens encode.
15781578 semantically equivalent to composing the caller's deoptimization
15791579 continuation after the callee's deoptimization continuation.
15801580
1581 .. _ob_funclet:
1582
15811583 Funclet Operand Bundles
15821584 ^^^^^^^^^^^^^^^^^^^^^^^
15831585
15861588 is within a particular funclet. There can be at most one
15871589 ``"funclet"`` operand bundle attached to a call site and it must have
15881590 exactly one bundle operand.
1591
1592 If any funclet EH pads have been "entered" but not "exited" (per the
1593 `description in the EH doc\ `_),
1594 it is undefined behavior to execute a ``call`` or ``invoke`` which:
1595
1596 * does not have a ``"funclet"`` bundle and is not a ``call`` to a nounwind
1597 intrinsic, or
1598 * has a ``"funclet"`` bundle whose operand is not the most-recently-entered
1599 not-yet-exited funclet EH pad.
1600
1601 Similarly, if no funclet EH pads have been entered-but-not-yet-exited,
1602 executing a ``call`` or ``invoke`` with a ``"funclet"`` bundle is undefined behavior.
15891603
15901604 .. _moduleasm:
15911605
54035417 ``catchswitch`` instruction. If the ``catchswitch`` is not inside a funclet,
54045418 this operand may be the token ``none``.
54055419
5406 The ``default`` argument is the label of another basic block beginning with a
5407 "pad" instruction, one of ``cleanuppad`` or ``catchswitch``.
5408
5409 The ``handlers`` are a list of successor blocks that each begin with a
5420 The ``default`` argument is the label of another basic block beginning with
5421 either a ``cleanuppad`` or ``catchswitch`` instruction. This unwind destination
5422 must be a legal target with respect to the ``parent`` links, as described in
5423 the `exception handling documentation\ `_.
5424
5425 The ``handlers`` are a nonempty list of successor blocks that each begin with a
54105426 :ref:`catchpad ` instruction.
54115427
54125428 Semantics:
54805496
54815497 The meaning of the tokens produced and consumed by ``catchpad`` and other "pad"
54825498 instructions is described in the
5483 `Windows exception handling documentation `.
5484
5485 Executing a ``catchpad`` instruction constitutes "entering" that pad.
5486 The pad may then be "exited" in one of three ways:
5487
5488 1) explicitly via a ``catchret`` that consumes it. Executing such a ``catchret``
5489 is undefined behavior if any descendant pads have been entered but not yet
5490 exited.
5491 2) implicitly via a call (which unwinds all the way to the current function's caller),
5492 or via a ``catchswitch`` or a ``cleanupret`` that unwinds to caller.
5493 3) implicitly via an unwind edge whose destination EH pad isn't a descendant of
5494 the ``catchpad``. When the ``catchpad`` is exited in this manner, it is
5495 undefined behavior if the destination EH pad has a parent which is not an
5496 ancestor of the ``catchpad`` being exited.
5499 `Windows exception handling documentation\ `_.
5500
5501 When a ``catchpad`` has been "entered" but not yet "exited" (as
5502 described in the `EH documentation\ `_),
5503 it is undefined behavior to execute a :ref:`call ` or :ref:`invoke `
5504 that does not carry an appropriate :ref:`"funclet" bundle `.
54975505
54985506 Example:
54995507 """"""""
55425550 code to, for example, destroy the active exception. Control then transfers to
55435551 ``normal``.
55445552
5545 The ``token`` argument must be a token produced by a dominating ``catchpad``
5546 instruction. The ``catchret`` destroys the physical frame established by
5547 ``catchpad``, so executing multiple returns on the same token without
5548 re-executing the ``catchpad`` will result in undefined behavior.
5549 See :ref:`catchpad ` for more details.
5553 The ``token`` argument must be a token produced by a ``catchpad`` instruction.
5554 If the specified ``catchpad`` is not the most-recently-entered not-yet-exited
5555 funclet pad (as described in the `EH documentation\ `_),
5556 the ``catchret``'s behavior is undefined.
55505557
55515558 Example:
55525559 """"""""
55805587
55815588 The '``cleanupret``' instruction requires one argument, which indicates
55825589 which ``cleanuppad`` it exits, and must be a :ref:`cleanuppad `.
5583 It also has an optional successor, ``continue``.
5590 If the specified ``cleanuppad`` is not the most-recently-entered not-yet-exited
5591 funclet pad (as described in the `EH documentation\ `_),
5592 the ``cleanupret``'s behavior is undefined.
5593
5594 The '``cleanupret``' instruction also has an optional successor, ``continue``,
5595 which must be the label of another basic block beginning with either a
5596 ``cleanuppad`` or ``catchswitch`` instruction. This unwind destination must
5597 be a legal target with respect to the ``parent`` links, as described in the
5598 `exception handling documentation\ `_.
55845599
55855600 Semantics:
55865601 """"""""""
55895604 :ref:`personality function ` that one
55905605 :ref:`cleanuppad ` it transferred control to has ended.
55915606 It transfers control to ``continue`` or unwinds out of the function.
5592
5593 The unwind destination ``continue``, if present, must be an EH pad
5594 whose parent is either ``none`` or an ancestor of the ``cleanuppad``
5595 being returned from. This constitutes an exceptional exit from all
5596 ancestors of the completed ``cleanuppad``, up to but not including
5597 the parent of ``continue``.
5598 See :ref:`cleanuppad ` for more details.
55995607
56005608 Example:
56015609 """"""""
86438651 - A basic block that is not a cleanup block may not include a
86448652 '``cleanuppad``' instruction.
86458653
8646 Executing a ``cleanuppad`` instruction constitutes "entering" that pad.
8647 The pad may then be "exited" in one of three ways:
8648
8649 1) explicitly via a ``cleanupret`` that consumes it. Executing such a ``cleanupret``
8650 is undefined behavior if any descendant pads have been entered but not yet
8651 exited.
8652 2) implicitly via a call (which unwinds all the way to the current function's caller),
8653 or via a ``catchswitch`` or a ``cleanupret`` that unwinds to caller.
8654 3) implicitly via an unwind edge whose destination EH pad isn't a descendant of
8655 the ``cleanuppad``. When the ``cleanuppad`` is exited in this manner, it is
8656 undefined behavior if the destination EH pad has a parent which is not an
8657 ancestor of the ``cleanuppad`` being exited.
8654 When a ``cleanuppad`` has been "entered" but not yet "exited" (as
8655 described in the `EH documentation\ `_),
8656 it is undefined behavior to execute a :ref:`call ` or :ref:`invoke `
8657 that does not carry an appropriate :ref:`"funclet" bundle `.
86588658
86598659 It is undefined behavior for the ``cleanuppad`` to exit via an unwind edge which
86608660 does not transitively unwind to the same destination as a constituent
28942894 visitInstruction(IVI);
28952895 }
28962896
2897 static Value *getParentPad(Value *EHPad) {
2898 if (auto *FPI = dyn_cast(EHPad))
2899 return FPI->getParentPad();
2900
2901 return cast(EHPad)->getParentPad();
2902 }
2903
28972904 void Verifier::visitEHPadPredecessors(Instruction &I) {
28982905 assert(I.isEHPad());
28992906
29242931 return;
29252932 }
29262933
2934 // Verify that each pred has a legal terminator with a legal to/from EH
2935 // pad relationship.
2936 Instruction *ToPad = &I;
2937 Value *ToPadParent = getParentPad(ToPad);
29272938 for (BasicBlock *PredBB : predecessors(BB)) {
29282939 TerminatorInst *TI = PredBB->getTerminator();
2940 Value *FromPad;
29292941 if (auto *II = dyn_cast(TI)) {
29302942 Assert(II->getUnwindDest() == BB && II->getNormalDest() != BB,
2931 "EH pad must be jumped to via an unwind edge", &I, II);
2932 } else if (!isa(TI) && !isa(TI)) {
2933 Assert(false, "EH pad must be jumped to via an unwind edge", &I, TI);
2943 "EH pad must be jumped to via an unwind edge", ToPad, II);
2944 if (auto Bundle = II->getOperandBundle(LLVMContext::OB_funclet))
2945 FromPad = Bundle->Inputs[0];
2946 else
2947 FromPad = ConstantTokenNone::get(II->getContext());
2948 } else if (auto *CRI = dyn_cast(TI)) {
2949 FromPad = CRI->getCleanupPad();
2950 Assert(FromPad != ToPadParent, "A cleanupret must exit its cleanup", CRI);
2951 } else if (auto *CSI = dyn_cast(TI)) {
2952 FromPad = CSI;
2953 } else {
2954 Assert(false, "EH pad must be jumped to via an unwind edge", ToPad, TI);
2955 }
2956
2957 // The edge may exit from zero or more nested pads.
2958 for (;; FromPad = getParentPad(FromPad)) {
2959 Assert(FromPad != ToPad,
2960 "EH pad cannot handle exceptions raised within it", FromPad, TI);
2961 if (FromPad == ToPadParent) {
2962 // This is a legal unwind edge.
2963 break;
2964 }
2965 Assert(!isa(FromPad),
2966 "A single unwind edge may only enter one EH pad", TI);
29342967 }
29352968 }
29362969 }
884884 ; CHECK-NEXT: br label %body
885885
886886 body:
887 invoke void @f.ccc() to label %continue unwind label %terminate.inner
887 invoke void @f.ccc() [ "funclet"(token %catch) ]
888 to label %continue unwind label %terminate.inner
888889 catchret from %catch to label %return
889890 ; CHECK: catchret from %catch to label %return
890891
4242 invoke void @_Z3quxv() optsize
4343 to label %exit unwind label %pad
4444 cleanup:
45 cleanupret from %cp unwind label %pad
45 cleanupret from %cp unwind to caller
4646 pad:
4747 %cp = cleanuppad within none []
4848 br label %cleanup
5656 invoke void @_Z3quxv() optsize
5757 to label %exit unwind label %pad
5858 cleanup:
59 cleanupret from %0 unwind label %pad
59 cleanupret from %0 unwind to caller
6060 pad:
6161 %0 = cleanuppad within none []
6262 br label %cleanup
55 ; RUN: sed -e s/.T6:// %s | not opt -verify -disable-output 2>&1 | FileCheck --check-prefix=CHECK6 %s
66 ; RUN: sed -e s/.T7:// %s | not opt -verify -disable-output 2>&1 | FileCheck --check-prefix=CHECK7 %s
77 ; RUN: sed -e s/.T8:// %s | not opt -verify -disable-output 2>&1 | FileCheck --check-prefix=CHECK8 %s
8 ; RUN: sed -e s/.T9:// %s | not opt -verify -disable-output 2>&1 | FileCheck --check-prefix=CHECK9 %s
9 ; RUN: sed -e s/.T10:// %s | not opt -verify -disable-output 2>&1 | FileCheck --check-prefix=CHECK10 %s
10 ; RUN: sed -e s/.T11:// %s | not opt -verify -disable-output 2>&1 | FileCheck --check-prefix=CHECK11 %s
11 ; RUN: sed -e s/.T12:// %s | not opt -verify -disable-output 2>&1 | FileCheck --check-prefix=CHECK12 %s
12 ; RUN: sed -e s/.T13:// %s | not opt -verify -disable-output 2>&1 | FileCheck --check-prefix=CHECK13 %s
813
914 declare void @g()
1015
95100 ;T8: %cs1 = catchswitch within none [ label %switch1 ] unwind to caller
96101 ;T8: ; CHECK8: CatchSwitchInst handlers must be catchpads
97102 ;T8: }
103
104 ;T9: define void @f() personality void ()* @g {
105 ;T9: entry:
106 ;T9: ret void
107 ;T9: cleanup:
108 ;T9: %cp = cleanuppad within none []
109 ;T9: invoke void @g() [ "funclet"(token %cp) ]
110 ;T9: to label %exit unwind label %cleanup
111 ;T9: ; CHECK9: EH pad cannot handle exceptions raised within it
112 ;T9: ; CHECK9-NEXT: %cp = cleanuppad within none []
113 ;T9: ; CHECK9-NEXT: invoke void @g() [ "funclet"(token %cp) ]
114 ;T9: exit:
115 ;T9: ret void
116 ;T9: }
117
118 ;T10: define void @f() personality void ()* @g {
119 ;T10: entry:
120 ;T10: ret void
121 ;T10: cleanup1:
122 ;T10: %cp1 = cleanuppad within none []
123 ;T10: unreachable
124 ;T10: switch:
125 ;T10: %cs = catchswitch within %cp1 [label %catch] unwind to caller
126 ;T10: catch:
127 ;T10: %catchp1 = catchpad within %cs [i32 1]
128 ;T10: unreachable
129 ;T10: cleanup2:
130 ;T10: %cp2 = cleanuppad within %catchp1 []
131 ;T10: unreachable
132 ;T10: cleanup3:
133 ;T10: %cp3 = cleanuppad within %cp2 []
134 ;T10: cleanupret from %cp3 unwind label %switch
135 ;T10: ; CHECK10: EH pad cannot handle exceptions raised within it
136 ;T10: ; CHECK10-NEXT: %cs = catchswitch within %cp1 [label %catch] unwind to caller
137 ;T10: ; CHECK10-NEXT: cleanupret from %cp3 unwind label %switch
138 ;T10: }
139
140 ;T11: define void @f() personality void ()* @g {
141 ;T11: entry:
142 ;T11: ret void
143 ;T11: cleanup1:
144 ;T11: %cp1 = cleanuppad within none []
145 ;T11: unreachable
146 ;T11: cleanup2:
147 ;T11: %cp2 = cleanuppad within %cp1 []
148 ;T11: unreachable
149 ;T11: switch:
150 ;T11: %cs = catchswitch within none [label %catch] unwind label %cleanup2
151 ;T11: ; CHECK11: A single unwind edge may only enter one EH pad
152 ;T11: ; CHECK11-NEXT: %cs = catchswitch within none [label %catch] unwind label %cleanup2
153 ;T11: catch:
154 ;T11: catchpad within %cs [i32 1]
155 ;T11: unreachable
156 ;T11: }
157
158 ;T12: define void @f() personality void ()* @g {
159 ;T12: entry:
160 ;T12: ret void
161 ;T12: cleanup:
162 ;T12: %cp = cleanuppad within none []
163 ;T12: cleanupret from %cp unwind label %switch
164 ;T12: ; CHECK12: A cleanupret must exit its cleanup
165 ;T12: ; CHECK12-NEXT: cleanupret from %cp unwind label %switch
166 ;T12: switch:
167 ;T12: %cs = catchswitch within %cp [label %catch] unwind to caller
168 ;T12: catch:
169 ;T12: catchpad within %cs [i32 1]
170 ;T12: unreachable
171 ;T12: }
172
173 ;T13: define void @f() personality void ()* @g {
174 ;T13: entry:
175 ;T13: ret void
176 ;T13: switch:
177 ;T13: %cs = catchswitch within none [label %catch] unwind label %switch
178 ;T13: ; CHECK13: EH pad cannot handle exceptions raised within it
179 ;T13: ; CHECK13-NEXT: %cs = catchswitch within none [label %catch] unwind label %switch
180 ;T13: catch:
181 ;T13: catchpad within %cs [i32 0]
182 ;T13: unreachable
183 ;T13: }
184