Repository navigation
Description
Impact: a real bug passes verification (false negative). It blocks 1 of the 48 real-code examples we built (bugs mined from open-source Java).
Description
A state-changing call on a field, made inside an anonymous class's method (here a listener that may never run), is applied to the field's state as if it ran in the constructor, so undo() on the still-empty manager passes. Without the anonymous class it is reported (control). On fbfb4e2 the original version of this code crashed the verifier; on main it passes instead.
Minimal reproducer
import javax.swing.undo.UndoManager;
import liquidjava.specification.ExternalRefinementsFor;
import liquidjava.specification.StateRefinement;
import liquidjava.specification.StateSet;
@ExternalRefinementsFor("javax.swing.undo.UndoManager")
@StateSet({"empty", "full"})
interface UndoManagerRefinements {
@StateRefinement(to = "empty(this)")
void UndoManager();
@StateRefinement(to = "full(this)")
boolean addEdit(javax.swing.undo.UndoableEdit anEdit);
@StateRefinement(from = "full(this)")
void undo();
}
public class Repro {
UndoManager undoManager = new UndoManager();
public Repro() {
Runnable listener = new Runnable() {
public void run() {
undoManager.addEdit(null);
}
};
}
public void undo() {
undoManager.undo();
}
}Expected
A state error at undoManager.undo(): code in an anonymous class (or lambda) body runs at an unknown later time and must not change the state other methods see.
Actual
Correct! Passed Verification.
Control: the same code without the problem construct is reported
import javax.swing.undo.UndoManager;
import liquidjava.specification.ExternalRefinementsFor;
import liquidjava.specification.StateRefinement;
import liquidjava.specification.StateSet;
@ExternalRefinementsFor("javax.swing.undo.UndoManager")
@StateSet({"empty", "full"})
interface UndoManagerRefinements {
@StateRefinement(to = "empty(this)")
void UndoManager();
@StateRefinement(to = "full(this)")
boolean addEdit(javax.swing.undo.UndoableEdit anEdit);
@StateRefinement(from = "full(this)")
void undo();
}
public class Control {
UndoManager undoManager = new UndoManager();
public void undo() {
undoManager.undo();
}
}State Refinement Error: found empty(this#undoManager⁶) but expected full(this#undoManager⁶)
22 |
23 | public void undo() {
24 | undoManager.undo();
| ^^^^^^^^^^^^^^^^^^^
25 | }
Reproduced on main at 0472025 (liquidjava-verifier 0.0.35); also on fbfb4e2 and 0.0.33 in the original form.
Context
Found while turning bugs mined from real open-source Java (fixed upstream or still present) into study examples for the error-message study.
Activity