Skip to content

Soundness: short-circuit RHS assignments are treated as executed #323

Description

@CatarinaGamboa

Problem

A write in the right operand of Java && or || is applied to LiquidJava's variable context even when Java short-circuits and does not execute that operand. The verifier can then prove a refinement about a value the program never assigned.

Minimal reproducer

import liquidjava.specification.Refinement;

public class Repro {
    public static void main(String[] args) {
        int x = 0;
        boolean ignored = false && ((x = 1) == 1);
        @Refinement("_ == 1") int y = x; // should be a Refinement Error
        assert y == 1;                    // fails: y is 0
    }
}

Expected: Reject the refinement on y. Java skips the RHS of &&, so x remains 0.

Actual: Correct! Passed Verification. on main at dd02e996. Compiling and running the program with assertions enabled throws AssertionError. The analogous true || RHS path has the same conditional-execution rule.

Cause and scope

RefinementTypeChecker.visitCtBinaryOperator scans both operands before applying the binary operation refinement. A RHS assignment updates the context during that scan; the later operator check does not distinguish a definitely executed write from a conditionally executed one.

The closed PR #257 contains a reproducer and a conservative fix. The fix should be ported and reviewed against current main, including both operators, nested writes, and branches where the RHS runs or is skipped. Example tests now use // Expect: Refinement Error after #293.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions