Skip to content

Commit 61d1c54

Browse files
authored
Fix broken proof tree after information flow auto pilot (#3911)
2 parents d3de45c + bb0dcf0 commit 61d1c54

3 files changed

Lines changed: 79 additions & 3 deletions

File tree

key.ui/src/main/java/de/uka/ilkd/key/gui/prooftree/ProofTreeView.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1066,6 +1066,13 @@ public synchronized void autoModeStarted(ProofEvent e) {
10661066
LOGGER.debug("delegateModel is null");
10671067
return;
10681068
}
1069+
if (e.getSource() != proof) {
1070+
// Auto mode on a proof this view does not display, e.g. an auxiliary side proof
1071+
// of the information-flow macros (see #3713). Overwriting modifiedSubtrees with
1072+
// the foreign proof's goals would feed its nodes into the displayed proof's tree
1073+
// model in autoModeStopped.
1074+
return;
1075+
}
10691076

10701077
// save goals on which the prover may work
10711078
modifiedSubtrees = e.getSource().openGoals().map(Goal::node);
@@ -1088,7 +1095,10 @@ public synchronized void autoModeStopped(ProofEvent e) {
10881095
setProof(mediator.getSelectedProof());
10891096
if (modifiedSubtrees != null) {
10901097
for (final Node n : modifiedSubtrees) {
1091-
if (proof.openGoals().filter(g -> g.node() == n).isEmpty()) {
1098+
// skip nodes of other proofs: the displayed proof may have changed since the
1099+
// subtrees were recorded in autoModeStarted (see #3713)
1100+
if (n.proof() == proof
1101+
&& proof.openGoals().filter(g -> g.node() == n).isEmpty()) {
10921102
delegateModel.updateTree(n);
10931103
}
10941104
}

key.ui/src/main/java/de/uka/ilkd/key/ui/AbstractMediatorUserInterfaceControl.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,9 +172,10 @@ public void proofDisposed(ProofDisposedEvent e) {
172172
});
173173
// stop interface again, because it is activated by the proof
174174
// change through startProver; the ProofMacroWorker will activate
175-
// it again at the right time
175+
// it again at the right time.
176176
ThreadUtilities.invokeAndWait(() -> {
177-
getMediator().initiateAutoMode(info.getProof(), true, false);
177+
getMediator().stopInterface(true);
178+
getMediator().setInteractive(false);
178179
});
179180
}
180181
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/* This file is part of KeY - https://key-project.org
2+
* KeY is licensed under the GNU General Public License Version 2
3+
* SPDX-License-Identifier: GPL-2.0-only */
4+
package de.uka.ilkd.key.gui.prooftree;
5+
6+
import java.nio.file.Path;
7+
import java.util.Objects;
8+
import javax.swing.tree.TreeNode;
9+
10+
import de.uka.ilkd.key.control.DefaultUserInterfaceControl;
11+
import de.uka.ilkd.key.control.KeYEnvironment;
12+
import de.uka.ilkd.key.proof.Node;
13+
import de.uka.ilkd.key.proof.Proof;
14+
15+
import org.key_project.util.helper.FindResources;
16+
17+
import org.junit.jupiter.api.Test;
18+
19+
import static org.junit.jupiter.api.Assertions.assertThrows;
20+
21+
/**
22+
* Documents the fail-fast contract of the proof tree model for the constellation behind issue
23+
* #3713: nodes of a foreign (here: already disposed) proof must never be fed into another proof's
24+
* {@link GUIProofTreeModel}. The information-flow auto pilot's side proof used to leak into
25+
* {@code ProofTreeView.modifiedSubtrees} this way; the actual fix prevents the leak in
26+
* {@code ProofTreeView} and {@code AbstractMediatorUserInterfaceControl#macroFinished}. The model
27+
* itself deliberately keeps failing fast when the invariant is violated, so that bookkeeping bugs
28+
* of this kind surface instead of being rendered silently.
29+
*/
30+
public class DisposedProofTreeUpdateTest {
31+
private static final Path exampleDir =
32+
Objects.requireNonNull(FindResources.getExampleDirectory());
33+
private static final String EXAMPLE_PROOF =
34+
"standard_key/BookExamples/10UsingKeY/andCommutes.proof";
35+
36+
@Test
37+
void updatingWithNodeOfForeignDisposedProofFailsFast() throws Exception {
38+
KeYEnvironment<DefaultUserInterfaceControl> env =
39+
KeYEnvironment.load(exampleDir.resolve(EXAMPLE_PROOF));
40+
Proof displayed = env.getLoadedProof();
41+
KeYEnvironment<DefaultUserInterfaceControl> env2 =
42+
KeYEnvironment.load(exampleDir.resolve(EXAMPLE_PROOF));
43+
Proof foreign = env2.getLoadedProof();
44+
45+
GUIProofTreeModel model = new GUIProofTreeModel(displayed);
46+
forceExpand((TreeNode) model.getRoot());
47+
48+
// keep a node of the foreign proof (Node keeps its proof reference), then dispose it
49+
Node foreignRoot = foreign.root();
50+
foreign.dispose();
51+
52+
assertThrows(IllegalStateException.class, () -> model.updateTree(foreignRoot),
53+
"walking a foreign disposed proof's node must fail fast");
54+
55+
env.dispose();
56+
env2.dispose();
57+
}
58+
59+
private static void forceExpand(TreeNode node) {
60+
int count = node.getChildCount();
61+
for (int i = 0; i < count; i++) {
62+
forceExpand(node.getChildAt(i));
63+
}
64+
}
65+
}

0 commit comments

Comments
 (0)