[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Tightening Exception-based Control flow graph



    vranganath> I have a comment regarding the last 2 bullets.
    vranganath> In general, a control statement determines which
    vranganath> of it's successors gets control after it
    vranganath> completes.  Given this notion an exception
    vranganath> raising statement is a control statement.  The
    vranganath> definition was confined to control constructs
    vranganath> such as if, while, switch, ... in the days
    vranganath> earlier to languages supporting exceptions.  So,
    vranganath> bullet 3 is untrue in the presence of exception
    vranganath> only if the way the successor is determined by a
    vranganath> control statement is defined as dependent on a
    vranganath> boolean expression. 

Sure, but I guess that's my point.  With old fashioned
conditional branches, the choice of which edge you take depends
solely on the value of that boolean expression (or integer
expression in the case of a switch). The expression is explicitly
available in the program statement, and it is stated in terms of
constants and variables that are explicitly present in the
method's code, so even if a static analysis cannot determine the
value of the expression, it is at least clear where the value
comes from.

In principle, you can also express whether or not an exceptional
edge is taken in the form of a boolean expression, but the
expression is not explicitly available in the program statement,
and it may depend on factors that are not even mentioned in the
the function's code, such as whether referenced classes can be
loaded successfully given the current class path, whether the VM
is running short of memory, or whether some other thread is about
to ignore Sun's recommendations and call Thread.stop().

If you want to say that this is a difference of degree rather
than kind, fine, I'll concede that. But it's an awfully big
difference of degree.

    vranganath> As for the last bullet, asynchronous exceptions
    vranganath> can ensure that this bullet is true.  So in my
    vranganath> opinion, exceptional edges are different from
    vranganath> normal control flow edges but they are still
    vranganath> control flow edges, and any statement that can
    vranganath> raise an exception is a valid control statement.

The Java Language Specification certainly gives VM implementors
the leeway to delay checks for asynchronous exceptions to
convenient points (JLS 11.3.2). I'm not sure that this leeway is
available to Soot, though, since Soot is a bytecode-to-bytecode
transformer, not a VM. Shouldn't our analyses reflect the
possible behaviour of our generated bytecode on Java
implementations which choose to deliver asynchronous exceptions
immediately as well as those which delay them until the next
control transfer point? I don't know the answer to this question,
so I opt for a conservative approach.

    vranganath> Well, independent of the type or sort of
    vranganath> exception that may occur at the first statement
    vranganath> of the inner handler, if the inner handler was
    vranganath> covered by the outer catch block, this exception
    vranganath> will be caught by the outer handler.  

That's true, but that's not the issue. The issue is that the CFG
should indicate that it is possible for statements in the outer
handler to be executed (to completion) without any statements in
the inner handler being executed (to completion).

>     >> As for code generated for other try blocks, we want to ensure
>     >> that we do not lose the ability to recognize that in the
>     >> following code it is possible for "b" to get set to 1 even though
>     >> "a" remains 0:
>     >> 
>     >> static int a = 0;
>     >> static int b = 0;
>     >> 
>     >> void tryUpdate(int[] values, int index, 
>     >>                LockObject inner, LockObject outer) {
>     >> try {
>     >>   try {
>     >>     inner.value = index;  //A
>     >>     int i = values[index]; //x
>     >>     outer.value = i;       //y
>     >>   } catch (Throwable t) {
>     >>     a = 1;                //B
>     >>   }
>     >> } catch (Throwable t) {
>     >>   b = 1;                  //C
>     >> }
> 

    vranganath> Consider the following CFG:
    vranganath> 	A -> B,
    vranganath> 	x -> B,
    vranganath> 	y -> B,
    vranganath> 	B -> C

    vranganath> Let's consider your scenario, an exception at x
    vranganath> will transfer control to B, but before the B
    vranganath> begins an asynch exception occurs and transfers
    vranganath> control to C and C completes.  As the exception
    vranganath> occurs after A, index was assigned to inner.value
    vranganath> at A and 1 was assigned to B.  So, the given
    vranganath> graph gives enough information to capture your
    vranganath> scenario.

But in the given graph, the only way to get from A to C is
through B, which implies that whenever "b" has been assigned the
value 1 (by statement C), "a" has also been assigned the value 1
(by statement B). That's not true, "a" might still have the value
0, because you don't necessarily have to complete statement B to
get to statement C.

Incidentally, there really shouldn't be an edge from y to B,
since if y completes successfully, there hasn't been any
exception and B won't be executed (and y has no side effects; if
it did we would still need an edge from y to B, since those side
effects might occur before y throws its exception, so we would
need to flow the side effects into the handler).

    vranganath> On the other hand, with the original graph,

    vranganath> 	A -> B,	A -> C,
    vranganath> 	x -> B, x -> C,
    vranganath> 	y -> B, y -> C
    vranganath> 	B -> C

Again, there should be no edges from y to B and C, but the
existing CFG classes in Soot do produce them.

    vranganath> The data flow analysis will indicate that the
    vranganath> assignment to index.value at A is equally
    vranganath> eligible to be visible visible at B and C which
    vranganath> is incorrect by the exceution semantics of JVM.

I don't understand why it isn't potentially visiable at both B
and C. If statement x throws an exception caught at B and B does
not itself raise an exception, then the definition of index.value
at A will reach B. If statements x and B both throw exceptions,
the definition of index.value at A will reach C, won't it? 
Obviously I'm missing something here.

    vranganath> I think the same suggestion would be applicable
    vranganath> to any intermediate representation as it based on
    vranganath> language and JVM semantics and not based on the
    vranganath> IR semantics.

Well, maybe there should be a policy that in all IRs, the initial
statement in an exception handler should be an empty placeholder
that does nothing (and hence can be considered immune to
exceptions). That would certainly simplify program analysis
(which is, after all, the goal of an IR), but I don't see how it
is imposed by Java semantics. 

Are you saying that because the initial instruction in most
exception handlers just stores or pops the exception object from
the stack---pure ALU operations which are not subject to
synchronous exceptions---we can safely assume that the first
instruction in any exception handler will always complete
successfully? But that's just a matter of convention; I don't
know of any rule that says you can't ignore the exception object
entirely and, say, dereference a potentially null pointer as the
first instruction in your handler. And then there are those pesky
asynchronous exceptions, which you can't ignore when the catch
type is Throwable.

-- 
John Jorgensen		jjorge1@cs.mcgill.ca