[Checkers] Question about the flow algorithm

Adam Warski adam at warski.org
Sun Mar 22 07:40:18 EDT 2009


Hello,

reading the algorithm a bit more, I think it could be improved.

The finally{} block should I be in fact evaluated with two possible  
annotation sets: in the case control continues after it normally (this  
covers the "alive" catches + the case when there are no exceptions in  
try{}), and the case when the control doesn't continue normally ("non- 
alive" catches).

The two cases can be different. The annos set after the whole try- 
catch-finally construct should correspond to the flows covering only  
the try, alive catches and finally block, not the ones covering the  
non-alive catches. In a special case, this means that if all catches  
are not alive, then the annos set after finally should only cover the  
flow of try completing without exceptions + finally block..

This could be implemented as follows:
We evaluate the try{} normally, and store two annotation sets:
- "annosAfterNormal", which is a copy of "annos", assuming that no  
exceptions were thrown
- "annosBeforeCatch", which is "annos" & tryBits.pop(), which covers  
the possibility of throwing an exception by any method that declares  
thrown exceptions

Then we evaluate each catch, storing after it a pair:  
(annosAfterCatch, catchAlive). The initial annotation set for each  
catch is "annosBeforeCatch".

Then we come to evaluating the finally block; it is evaluated twice,  
with initial annotation sets:
(1) conjunction of all annosAfterCatch where catchAlive == true and  
the "annosAfterNormal" set
(2) conjunction of all annosAfterCatch where catchAlive == false

The annotation set after the whole try-catch-construct should be the  
annotation set after evaluating finally (1).

What do you think? Any bugs that you can see? I haven't implemented it  
yet, but if you won't see any problems, I'll post the code here in  
some time :)

Adam

On Mar 22, 2009, at 11:16 AM, Adam Warski wrote:

> Hello,
>
> I've got a question about the flow algorithm, more specifically  
> about the try-catch-finally handling.
>
> In visitTry(), there's a code block:
>
> if (node.getCatches() != null) {
>        boolean catchAlive = true;
>        for (CatchTree ct : node.getCatches()) {
>            scan(ct, p);
>            catchAlive &= alive;
>        }
>        // Conservative: only if there's no finally
>        if (!catchAlive && node.getFinallyBlock() == null)
>            annos = GenKillBits.copy(annoAfterBlock);
>    }
>
> which, after scanning the try{} block, scans the catch{} blocks, if  
> there are any. Now, the last part says that if the caches aren't  
> alive, that is, control can't "pass" through them, the state of the  
> annotations after the whole try-catch should be the state of the  
> annotations as it was at the end of the catch{} block - which is  
> correct. However, I think this should happen only if ALL catches  
> aren't alive. And right now, the "catchAlive" variable will be false  
> if at least one catch isn't alive. So if one catch is alive, and a  
> second isn't, the state of the annotations will be restored.
>
> So in short, I think that the lines:
>
>            boolean catchAlive = true;
>            catchAlive &= alive;
>
> should be changed to:
>
>            boolean catchAlive = false;
>            catchAlive |= alive;
>
> -- 
> Adam




More information about the checkers mailing list