Repository navigation
Combine try, catch and finally blocks soundly - #366
Merged
Merged
Conversation
CatarinaGamboa
force-pushed
the
fix/364-try-catch-join
branch
from
October 7, 2026 14:37
540db82 to
4340fb3
Compare
try/catch blocks were checked one after the other, so after them only the last catch path was considered and errors on the try path were missed. - The try and catch blocks are visited like an if-else-if chain with unknown conditions, and each variable is combined after the join with the existing if machinery. - An exception may leave the try block after any of its statements, so a catch block starts with each variable in any of the states it had before or during the try block (instances are recorded while visiting it). - The finally block starts with any of the states of the try and catch blocks; after it, the normal completion state continues, updated with what the finally block changed. - Path conditions from inside a branch do not leak into later branches, the finally block, or the code after the try statement. - Catch parameters get an instance so refinements referring to them outlive the catch block. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CatarinaGamboa
force-pushed
the
fix/364-try-catch-join
branch
from
October 8, 2026 11:25
4340fb3 to
6559819
Compare
The Apache Derby shape behind DERBY-2472: exceptions caught in a loop are chained with initCause, but their constructor may already have set the cause, so the call can throw "Can't overwrite cause". The catch parameter's state is unknown, so the call is reported. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #339 and #364.
try/catchwas checked as straight-line code: first thetry, then thecatch. An exception can leave thetryafter any statement, and afinallyalso runs afterreturns and uncaught exceptions. Because of that, errors in all three places were missed.Example
mainassumesy == 2(the wholetryran)y == 1 ∨ y == -1 ∨ y == 2y == 3(thecatchalways ran)c ? y == 2 : y == 3y == 3Walkthrough
catch: while checking thetry, every new value ofyis recorded (-1,2). Thecatchstarts from "the value before thetryor any recorded value". So@Refinement("_ > 0") int a = y;placed at (1) is now an error; onmainit passed.trystatement: thetryand thecatchare joined like anif/elseon an unknown conditionc, reusing theifmachinery. So@Refinement("_ == 3") int b = y;placed at (2) is now an error.finally: it starts from any value seen in thetryor thecatch. After it, checking continues from the joined state (2), plus whatever thefinallyassigns.Path conditions from inside a branch (e.g.
if (x <= 0) return;in thetry) are also dropped before the next branch, thefinallyand the code after, since the exception may come before the check.Changes
TryChecker: holds thetry/catch/finallylogic. The existing try-with-resources code moved there fromRefinementTypeChecker, which is now smaller than onmain.Context:startRecordingInstances/stopRecordingInstancesrecord the new values variables get inside a block.try_catch_errorandtry_catch_correct, 13 cases each.Limitations
finallythat updates a variable from itself (y = y + 1) starts from every possible value. This is sound but imprecise.ifs.x = 1; risky();followed by a catch requiringx == 1. Exception-point-aware snapshots would improve precision.🤖 Generated with Claude Code