436 lines
30 KiB
TeX
436 lines
30 KiB
TeX
% !TEX encoding = UTF-8
|
|
% !TEX spellcheck = en_GB
|
|
% !TEX root = ../paper.tex
|
|
\chapter{Improving the SDG for exception handling}
|
|
\label{cha:solution}
|
|
|
|
This chapter features different problems and weaknesses of the current treatment that program slicing techniques use in presence of exceptions. Each problem is described with a counterexample that illustrates the loss of completeness or precision. Finally, for each problem a solution is proposed.
|
|
|
|
Regarding the problems, even though the current state of the art considers exception handling, their treatment is not perfect. The mistakes made by program slicers can be classified in two: (1) those that lower the completeness and (2) those that lower the correctness.
|
|
|
|
The first kind is the most important one, as the resulting slices may be incorrect (i.e., the behaviour of the slice is different from the behaviour of the original program) making them invalid for some uses of program slicing. A good example of the effects that these wrong slices may produce happens when they are used for program debugging, but the error that we want to debug does not appear any more, or even the slicing criterion cannot be reached due to an uncaught exception.
|
|
|
|
The second kind is less critical, but still important because a wrong treatment of exceptions can cause the inclusion of wrong dependencies in the slice, thus producing unnecessary long slices that may turn to be useless for some applications.
|
|
|
|
\section{Unconditional jump handling}
|
|
|
|
The standard treatment of unconditional jumps as pseudo-statements introduces two separate correctness errors (type 2): \emph{the subsumption correctness error}, which is relevant in the context of both strong and weak slicing, and the \emph{structure-exiting jump}, that is only relevant in the context of weak slicing.
|
|
|
|
\subsection{Problem 1: Subsumption correctness error}
|
|
|
|
This problem has been known since the seminal publication on slicing unconditional jumps~\cite{BalH93}: the paper's chapter 4 (page 219) details an example where the slice is bigger than it needs to be, and leave the solution of that problem as an open question to be solved in future publications. An analogous example---with \texttt{break} statements instead of \texttt{goto}---is shown in Example~\ref{exa:problem-break-sub}.
|
|
|
|
\begin{example}[An unconditional jump subsumption~\cite{BalH93}]
|
|
\label{exa:problem-break-sub}
|
|
Consider the code shown in the left side of Figure~\ref{fig:problem-break-sub}. It is a simple Java method containing a \texttt{while} statement, from which the execution may exit naturally or through any of the \texttt{break} statements (lines 6 and 9). For the rest of statements and conditional expressions, uppercase letters are used; and no data dependencies are considered, as they are not relevant to the problem at hand.
|
|
|
|
\begin{figure}[h]
|
|
\begin{minipage}{0.33\linewidth}
|
|
\begin{lstlisting}[]
|
|
public void f() {
|
|
while (X) {
|
|
if (Y) {
|
|
if (Z) {
|
|
A;
|
|
break;
|
|
}
|
|
B;
|
|
break;
|
|
}
|
|
C;
|
|
}
|
|
D;
|
|
}
|
|
|
|
\end{lstlisting}
|
|
\end{minipage}
|
|
\begin{minipage}{0.33\linewidth}
|
|
\begin{lstlisting}
|
|
public void f() {
|
|
while (X) {
|
|
if (Y) {
|
|
if (Z) {
|
|
|
|
break;
|
|
}
|
|
|
|
break;
|
|
}
|
|
C;
|
|
}
|
|
|
|
}
|
|
\end{lstlisting}
|
|
\end{minipage}
|
|
\begin{minipage}{0.33\linewidth}
|
|
\begin{lstlisting}
|
|
public void f() {
|
|
while (X) {
|
|
if (Y) {
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
}
|
|
C;
|
|
}
|
|
|
|
}
|
|
\end{lstlisting}
|
|
\end{minipage}
|
|
\caption{A program (left), its computed slice (centre) and the minimal slice (right).}
|
|
\label{fig:problem-break-sub}
|
|
\end{figure}
|
|
|
|
Now consider statement \texttt{C} (line 11) as the slicing criterion. Figure~\ref{fig:problem-break-sub-sdg} displays the SDG produced for the program, and the nodes selected by the slice. Figure~\ref{fig:problem-break-sub} displays the computed slice on the centre, and one of the minimal slices on the left. The inner \texttt{break} on line 6 and the \texttt{if} surrounding it have been unnecessarily included. Their inclusion would not be specially problematic, if it were not for the condition of the \texttt{if} statement, which may include extra data dependencies that are unnecessary in the slice and that may lead to include other unnecessary statements, making the slice even more imprecise.
|
|
|
|
Line 6 is not useful because regardless of whether it executes, the execution will continue on line 13 (after the \texttt{while}), as guaranteed by the other \texttt{break} statement on line 9, which is not guarded by any condition. Note that \texttt{B} is still control-dependent on line \josep{6\deleted{5}}, as it has a direct effect on it, but the dependence between both \texttt{break} statements introduces useless statements into the slice.
|
|
|
|
\begin{figure}[h]
|
|
\centering
|
|
\includegraphics[width=0.5\linewidth]{img/problem-break-sub-graph}
|
|
\caption{The system dependence graph for the program of Figure \ref{fig:problem-break-sub}, with the slice marked in grey, and the slicing criterion in bold.}
|
|
\label{fig:problem-break-sub-sdg}
|
|
\end{figure}
|
|
\end{example}
|
|
|
|
The problem showcased in Example~\ref{exa:problem-break-sub} can be generalized as Problem~\ref{pro:p1} for any pair of unconditional jump statements that are nested and whose destination is the same.
|
|
|
|
\begin{problem}[Subsumption correctness error]
|
|
\label{pro:p1}
|
|
Let $a$ and $b$ be two distinct unconditional jump statements without data whose destination $c$ is the same. Any control edge that connects them is superfluous and includes unnecessary statements in the slices produced.
|
|
\end{problem}
|
|
|
|
\subsubsection*{A solution for the subsumption correctness error}
|
|
|
|
As only the minimum amount of control edges are inserted into the PDG (according to Definition~\ref{def:pdg}), it is only necessary to remove the edge described in Problem~\ref{pro:p1} in order to improve the correctness of the algorithm. This removal must be performed after the SDG has been build, in order to avoid the reappearance of transitive dependencies that are excluded by the PDG's definition.
|
|
|
|
\subsection{Problem 2: Unnecessary instructions in weak slicing}
|
|
|
|
In the context of weak slicing, as shown in chapter \ref{cha:incremental}, the slicing criterion is not forced to behave in exactly the same way that the original program. This means that some statements may be removed, even if it results in an infinity loop execution, or an uncaught exception behaviour. The following example describes a specific scenario which is generalized later in this section.
|
|
|
|
\begin{example}[Unnecessary unconditional jumps]
|
|
\label{exa:problem-break-weak}
|
|
Consider the code for method \texttt{g} on Figure~\ref{fig:problem-break-weak-code}, which features a simple loop with a \texttt{break} statement within. The slice in the middle has been created with respect to the slicing criterion $\langle 6, x \rangle$, and includes everything except the print statement. This seems correct, as the presence of lines 4 and 5 determine the number of times line 6 is executed.
|
|
|
|
However, if one considers weak slicing, instead of strong slicing; the loop's termination stops mattering, lines 4 and 5 are no longer relevant. Without them, the slices produce an infinite list of natural numbers (0, 1, 2, 3, 4, 5...).
|
|
As the original program's output (the numbers 0 to 9) is a prefix of the natural numbers, the program is still a valid slice (pictured on Figure~\ref{fig:problem-break-weak-code}'s right side). The sequences of values fulfil the requirements of Definition~\ref{def:weak-slice}.
|
|
|
|
Note that the removal of lines 4 and 5 is only possible if there are no statements in the slice after the \texttt{while} statement. If the slicing criterion was line 8, variable \texttt{x}, lines 4 and 5 would be required to print the value, as without them, the program would loop indefinitely and never execute line 8.
|
|
|
|
\begin{figure}[h]
|
|
\begin{minipage}{0.33\linewidth}
|
|
\begin{lstlisting}
|
|
void g() {
|
|
int x = 0;
|
|
while (x > 0) {
|
|
if (x > 10)
|
|
break;
|
|
x++;
|
|
}
|
|
System.out.println(x);
|
|
}
|
|
\end{lstlisting}
|
|
\end{minipage}
|
|
\begin{minipage}{0.33\linewidth}
|
|
\begin{lstlisting}
|
|
void g() {
|
|
int x = 0;
|
|
while (x > 0) {
|
|
if (x > 10)
|
|
break;
|
|
x++;
|
|
}
|
|
|
|
}
|
|
\end{lstlisting}
|
|
\end{minipage}
|
|
\begin{minipage}{0.33\linewidth}
|
|
\begin{lstlisting}
|
|
void g() {
|
|
int x = 0;
|
|
while (x > 0) {
|
|
|
|
|
|
x++;
|
|
}
|
|
|
|
}
|
|
\end{lstlisting}
|
|
\end{minipage}
|
|
\caption{A simple loop with a break statement (left), its computed slice (middle) with respect to $\langle 6, x\rangle$, and the smallest weak slice (right) for the same slicing criterion.}
|
|
\label{fig:problem-break-weak-code}
|
|
\end{figure}
|
|
\end{example}
|
|
|
|
If we try to generalize this problem, it becomes apparent that instructions that jump backwards (e.g., \texttt{continue}) present a problem, as they may add executions in the middle, not at the end (where they can be disregarded in weak slicing). Therefore, not only has the jump to go forwards, but no instruction can be performed after the jump.
|
|
|
|
\begin{problem}[Unnecessary instructions in weak slicing]
|
|
\label{pro:p2}
|
|
Let $j$ be an unconditional jump to $X$. $j$ is not necessary in a slice $S$ if there is no statement present in $S$ that may be executed after $X$ in the original program.
|
|
\end{problem}
|
|
|
|
As with the previous error, the problem is not the inclusion of the jump and its controlling conditional instruction, but the inclusion of the data dependencies of the condition guarding the execution of the jump.
|
|
|
|
\subsubsection*{A solution for the unnecessary instructions in weak slicing}
|
|
|
|
After the slice has been completed, the unconditional jumps are identified. Those jumps after whose destination there are no more instructions are removed, and the slice recomputed. This is repeated until there are no more unconditional jumps that fulfil the condition expressed in Problem~\ref{pro:p2}.
|
|
|
|
The complexity of this solution is higher than the previous one, as it raises the traversal of the slice from a linear time with respect to the number of nodes to $\mathcal{O}(nm)$, where $n$ is the number of nodes and $m$ is the number of unconditional jumps. That is a worst case estimation, as most cases will be close to linear time.
|
|
|
|
\section{The \texttt{try-catch} statement}
|
|
|
|
In this section we present an example where the current approach used to handle \texttt{try-catch} statements fails to capture all the correct dependencies, excluding from the slice some statements that are necessary for a complete slice (both weak and strong). After that, we generalize the set of cases where the lack of completeness (kind 1) is a problem and its possible appearances in real-life development. Finally, we propose a solution that properly represents all the dependencies introduced by the \texttt{try-catch}, focusing on producing complete strong slices.
|
|
|
|
\subsection{Problem 3: The lack control dependencies of \texttt{catch} statements}
|
|
|
|
In the current approach for exception handling \cite{AllH03}, \texttt{catch} blocks do not have any outgoing dependence leading anywhere except the instructions it contains. This means that, as showcased in chapter~\ref{cha:introduction}, the only way a \texttt{catch} statement may appear in a slice is if the slicing criterion is inside the catch block, or if the value of a variable defined inside the catch block is needed (reaching it by data dependence).
|
|
|
|
The only occasion in which \texttt{catch} blocks generate any kind of control dependence is when there is an exception thrown that is not covered by any of the \texttt{catch} blocks, and the function may exit with an exception. In that case, the instructions after the \texttt{try-catch} block are control dependent on every \texttt{catch} statement.
|
|
|
|
But, compared to the treatment of unconditional jumps, the lack of \texttt{catch} statements is not treated: unconditional jumps have a non-executable edge to the instruction that would be executed in their absence; \texttt{catch} statements do not.
|
|
|
|
\begin{example}[\texttt{catch} statements' outgoing dependencies]
|
|
\label{exa:catch-no-dep}
|
|
Consider the code shown in Figure~\ref{fig:catch-no-dep-code}, which depicts a \texttt{try-catch} where method \texttt{f}, which may throw an exception, is called. The function may throw either a \texttt{ExceptionA}, \texttt{ExceptionB} or \texttt{Exception}-typed exception; and the \texttt{try-catch} considers all three cases, logging the type of exception caught. Additionally, \texttt{f} accesses and modifies a global variable \texttt{x} (which is absent from the snippet shown, but will appear in the graphs).
|
|
|
|
\begin{figure}[h]
|
|
\begin{lstlisting}
|
|
try {
|
|
f();
|
|
} catch (ExceptionA e) {
|
|
log("Type A");
|
|
} catch (ExceptionB e) {
|
|
log("Type B");
|
|
} catch (Exception e) {
|
|
log("Exception");
|
|
}
|
|
next;
|
|
\end{lstlisting}
|
|
\caption{A snippet of code of a call to a method that throws exceptions and \texttt{catch} statements to capture and log them.}
|
|
\label{fig:catch-no-dep-code}
|
|
\end{figure}
|
|
|
|
The CFG and PDG associated to the code of Figure~\ref{fig:catch-no-dep-code}is depicted in Figure~\ref{fig:catch-no-dep-graphs}\footnote{For the sake of clarity, in the PDG of Figure~\ref{fig:catch-no-dep-graphs}, \texttt{log} function calls have been represented as a single node instead of their full node structures.}. As can be seen, the only two elements that are dependent on any \texttt{catch} are the log statement and the unpacking of \texttt{x}. If the following statement used \texttt{x} in any way, all \texttt{catch} statements would be selected, otherwise they are ignored, and not deemed necessary. It is true that they are normally not necessary; i.e., if the slicing criterion was placed on \texttt{next} (line 10), the whole \texttt{try-catch} would be rightfully ignored; but there exist cases where \texttt{f()} (line 2) would be part of the slice, and the absence of \texttt{catch} statements would result in an incomplete slice.
|
|
|
|
\begin{figure}[h]
|
|
\includegraphics[width=\linewidth]{img/catch-no-dep}
|
|
\caption{CFG (left) and PDG (right) of the code shown in Figure~\ref{fig:catch-no-dep-code}.}
|
|
\label{fig:catch-no-dep-graphs}
|
|
\end{figure}
|
|
\end{example}
|
|
|
|
\begin{example}[Incorrectly ignored \texttt{catch} statements]
|
|
Consider the code in Figure~\ref{fig:incorrect-try-catch-code}, in which the method \texttt{f} is called twice: once inside a \texttt{try-catch} statement, and a second time, outside of it. As it happened in Example~\ref{exa:catch-no-dep}, \texttt{f} also accesses and modifies variable \texttt{x}, which is redefined before the second call to \texttt{f}. Exploring this example, we demonstrate how line 3 will be necessary but not included in the slice.
|
|
|
|
\begin{figure}[h]
|
|
\begin{minipage}{0.5\linewidth}
|
|
\begin{lstlisting}
|
|
try {
|
|
f();
|
|
} catch (Exception e) {
|
|
log("error");
|
|
}
|
|
x = 0;
|
|
f();
|
|
\end{lstlisting}
|
|
\end{minipage}
|
|
\begin{minipage}{0.49\linewidth}
|
|
\begin{lstlisting}
|
|
void f() throws Exception {
|
|
if (x % 2 != 0)
|
|
throw new Exception();
|
|
x++;
|
|
}
|
|
\end{lstlisting}
|
|
\end{minipage}
|
|
\caption{A method \texttt{f} that may throw exceptions, called twice, once surrounded by a \texttt{try-catch} statement, and another time after it. On the right, the definition of \texttt{f}.}
|
|
\label{fig:incorrect-try-catch-code}
|
|
\end{figure}
|
|
|
|
Figure~\ref{fig:incorrect-try-catch-graph} displays the program dependence graph for the snippet of code on the left side of Figure~\ref{fig:incorrect-try-catch-code}. The PDG of \texttt{f} is not shown for simplicity. The set of nodes filled in grey represent the slice with respect to the slicing criterion $\langle 4, x \rangle$ in \texttt{f}. In the slice, both calls to \texttt{f} and its input (\texttt{x\_in = x}) are included, but the \texttt{catch} block is not present. The execution of the slice may not be the same: if no exception is thrown, there is no change; but if \texttt{x} was odd before entering the snippet, an exception would be thrown and not caught, exiting the program prematurely.
|
|
|
|
\begin{figure}[h]
|
|
\centering
|
|
\includegraphics[width=0.9\linewidth]{img/incorrect-try-catch}
|
|
\caption{The SDG of the left snippet of Figure~\ref{fig:incorrect-try-catch-code}. \texttt{f} and the associated inter-procedural edges are not shown for simplicity.}
|
|
\label{fig:incorrect-try-catch-graph}
|
|
\end{figure}
|
|
\label{exa:incorrect-try-catch-graph}
|
|
\end{example}
|
|
|
|
|
|
\subsubsection*{A solution for the \texttt{catch}'s lack of control dependencies}
|
|
|
|
In order to solve the drawback exposed above, we propose the \texttt{catch} statements to be handled as unconditional jumps: a non-executable edge should connect them to the instruction that would run if they were absent. There are two possibilities: to the \texttt{catch} that contains the most immediate super-type (or multiple); or to the error exit, if no other \texttt{catch} could catch the same exception.
|
|
|
|
This creates a tree-like structure among \texttt{catch} statements, with the root of each tree connected to the ``error exit'' of the method. This would generate dependencies between \texttt{catch} statements, and more importantly, dependencies from the \texttt{catch} statements to the instructions that follow the \texttt{try-catch} statement.
|
|
|
|
Unfortunately, this creates the same behaviour as with unconditional jumps: all the instructions that follow a \texttt{try-catch} structure is dependent on the presence of the \texttt{catch} statements, which in turn are dependent on all the statements that may throw exceptions. In practice, the inclusion of any statement after a \texttt{try-catch} statement would require the slice to include all \texttt{catch} statements, the statements that may throw exceptions, and all the statements required by control or data dependencies. This is a huge number of instructions just for including the \texttt{catch} statements.
|
|
|
|
We propose two separate solutions in order to reduce the number of statements introduced:
|
|
|
|
\begin{enumerate}
|
|
\item Make the inclusion of \texttt{catch} statements conditional on not one but two dependencies: a statement that throws an exception is present in the slice but also there is a statement that needs the exception to be caught. This would place the minimum amount of \texttt{catch} statements, with the cost of a slower program slicer.
|
|
\item Represent each \texttt{catch} statement in multiple nodes, one per method that may lead to it. This would minimize the number of method calls that are included when the corresponding \texttt{catch} block is included, but it may increase considerably the amount of nodes in the SDG.
|
|
\end{enumerate}
|
|
|
|
Both solutions need to be studied further before being implemented, but at least the slices produced are complete, even if some correctness is lost along the way.
|
|
|
|
% \begin{example}[Order of \texttt{catch} statements]
|
|
% Consider the following exception types declared in figure~\ref{fig:catch-order-code}, and their ordering in a simple \texttt{try-catch} statement. The \texttt{catch} blocks may be reorganized in any order if the type
|
|
|
|
% \begin{figure}[h]
|
|
% \begin{minipage}{0.60\linewidth}
|
|
% \begin{lstlisting}
|
|
% class ExceptionA extends Exception {...};
|
|
% class ExceptionB extends Exception {...};
|
|
% class ExceptionB1 extends ExceptionB {...};
|
|
% class ExceptionB2 extends ExceptionB {...};
|
|
% \end{lstlisting}
|
|
% \end{minipage}
|
|
% \begin{minipage}{0.39\linewidth}
|
|
% \begin{lstlisting}
|
|
% try {
|
|
% [...]
|
|
% } catch (ExceptionB2 e) {
|
|
% [...]
|
|
% } catch (ExceptionA e) {
|
|
% [...]
|
|
% } catch (ExceptionB1 e) {
|
|
% [...]
|
|
% } catch (ExceptionB e) {
|
|
% [...]
|
|
% } catch (Exception e) {
|
|
% [...]
|
|
% }
|
|
% \end{lstlisting}
|
|
% \end{minipage}
|
|
% \caption{A set of type declarations that extend the class \texttt{Exception} (left) and a small \texttt{try-catch} with the exceptions sorted in one of the valid orders (right).}
|
|
% \label{fig:catch-order-code}
|
|
% \end{figure}
|
|
% \end{example}
|
|
|
|
% \texttt{catch} blocks can be organized in two different orders: the physical order in which they are placed by the developer, which is the order in which they will be evaluated to check for type compatibility (in Java specifically); or a tree-like structure according to their types. Figure~\ref{fig:catch-order} showcases a couple of examples of each order. In Java's case, the tree structure is more correct; because though the order ``seems'' to matter, there is only one possible execution order.
|
|
|
|
% \begin{figure}
|
|
% \centering
|
|
% \includegraphics[width=0.5\linewidth]{img/catch-order}
|
|
% \caption{Two ways of looking at \texttt{catch} block orders: user-specified (left) and type-based tree (right).}
|
|
% \label{fig:catch-order}
|
|
% \end{figure}
|
|
|
|
% \newpage
|
|
% \section{Previous text}
|
|
% \carlos{Here begins the old text.}
|
|
% \hrulefill
|
|
|
|
% This solution is an extension of Allen's \cite{AllH03}, with some modifications to solve the problem found \josep{el problem found no ha quedado claro. Se ha diluido entre la maraña abrumadora de casos. debes formular y dejar nitido cristalino cual es el problema y por qué no lo solucinan las dsemás aproximaciones, y poner un ejempllo concreto.}. Before starting, we need to split all instructions in three categories:
|
|
|
|
% \begin{description}
|
|
% \item[statement] non-branching instruction, e.g. an assignment or method call.
|
|
% \item[predicate] conditional branch, e.g. if statements and loops.
|
|
% \item[pseudo-predicate] unconditional jump, e.g. break, continue, return, goto and throw instructions.
|
|
% \end{description}
|
|
|
|
% Pseudo-predicates have been previously use to model unconditional jumps with a counter-intuitive reasoning: the next statement that would be executed were the pseudo-predicate not there would be executed, therefore it is control dependent on it. Going back to the definition of control dependency, one could argue that the real control dependency is on the conditional branch that lead to the \josep{???}
|
|
|
|
% \begin{figure}
|
|
% \centering
|
|
% \begin{lstlisting}
|
|
% if (a) {
|
|
% return a;
|
|
% }
|
|
% print(a);
|
|
% \end{lstlisting}
|
|
% \begin{lstlisting}
|
|
% if (a) {
|
|
|
|
% }
|
|
% print(a);
|
|
% \end{lstlisting}
|
|
% \caption{Example of pseudo-predicates control dependencies \josep{no se referencia a esta figura desde ningún sitio}}
|
|
% \end{figure}
|
|
|
|
% This is the process used to build the Program Dependence Graph. \josep{Todo lo que sigue es demasiado verbose. No hay definiciones concretas. Es todo muy informal, y no hay un ongoing example que permita ver como las fases van evolucionando paso a paso. Nos reunimos para hablar de esta sección antes de reescribirla...}
|
|
|
|
% \begin{description}
|
|
% \item[Step 1 (static analysis):] Identify for each instruction the variables read and defined. Each method is annotated with the global variables that they access or modify.
|
|
% \item[Step 2 (build CFGs):] Build a CFG for each method of the program. The start of all methods is a vertex labeled \textit{enter}, which also contains the assignments for parameters and global variables used (\texttt{var = var\_in}). The \textit{enter} node is connected to the first instruction of the method. In a similar fashion, all methods end in an \textit{exit} vertex with the corresponding output variables. There exists one \textit{normal exit} to which the last instruction and all return instructions are connected. If the method can throw any exceptions, there exists one \textit{error exit} for each type of exception that may be thrown. The normal and erroneous exits are connected to the \textit{exit} node.
|
|
|
|
% Every normal statement is connected to the subsequent one by an unlabeled edge. Predicates have two outgoing edges, labeled \textit{true} and \textit{false}. Pseudo-predicates also have two outgoing edges. The \textit{true} edge is connected to the destination of the jump (\textit{normal exit} in the case of return, the begin or end of the loop in the case of continue and break, etc.). The \textit{false} edge is a non-executable edge, marked with a dashed line, and it is connected to the next instruction that would be executed if the pseudo-predicate was a \textit{nop}.
|
|
|
|
% Nodes that represent a call to a method $M$ include the transfer of parameters and variables that may be read or written to, then execute the call, and finally the extraction of modified variables. Call nodes are an exception to the previous paragraph, as they can have an unlimited amount of outgoing edges. Each outgoing edge lands on a pseudo-predicate which indicates if the execution was correct or an exception was raised. The executable edge of each pseudo-predicate will lead to the next instruction to be executed, whereas the non-executable one will lead to the end of the try-catch block. All call nodes can lead to a \textit{normal return} node, which is linked to the next instruction, and one error node for each type of exception that may be thrown. The erroneous returns are labeled \textit{catch ExType}, and lead to the first instruction in the corresponding catch block\footnotemark. Any exception that may not be caught will lead to the erroneous exit node of the method it's in. See the example for more details.
|
|
|
|
% \footnotetext{A problem presents itself here, as some exceptions may be able to trigger different catch blocks, due to the secuential nature of catches and polymorphism in Java. A way to fix this is to make catch blocks behave as a switch.}. %TODO
|
|
|
|
% \item[Step 3 (compute dependences):] For each node in the CFG, compute the control and data dependencies. Non-executable edges are only included when computing control dependencies.\\
|
|
% \carlos{put inside definition}
|
|
% A node $a$ is \textit{control dependent} on node $b$ iff $a$ post-dominates one but not all of $b$'s successors.\\
|
|
% A node $a$ is \textit{data dependent} on node $b$ iff $b$ defines or may define a variable $x$, $a$ uses or may use $x$, and there is an $x$-definition-free path in the CFG from $b$ to $a$.\\
|
|
% \item[Step 4 (convert each CFG into a PDG):] each node of the CFG is one node of the PDG, with two exceptions. The first are the \textit{enter}, \textit{exit} and method call nodes, where the variable input and output assignments are split and placed as control-dependent on their original node. The second is the \textit{exit} node, which is to be removed (the control-dependencies from \textit{exit} to the variable outputs is transferred to the \textit{enter} node). Then all the dependencies computed in the previous step are drawn.
|
|
% \item[Step 5 (connect PDGs to form a SDG):] each method call to $M$ must be connected to the \textit{enter} node in $M$'s PDG, as a control dependence. Each variable input from the method call is connected to a variable input of the method definition via a data dependence. Each variable output from the method definition is connected to the variable output of the method call via a data dependence. Each method exit is connected \carlos{complete}.
|
|
% \end{description}
|
|
|
|
% \begin{itemize}
|
|
% \item An extra type of control dependency represented by an ``exception edge''. It will represent the need to include a \textit{catch} clause when an exception can be thrown. It is represented with a dotted line (dashed line is for data dependency). These edges have a special characteristic: when one is traversed, only ``exception edges'' may be traversed from the new nodes included in the slice. If the same node is reached by another kind of edge, the restriction is lifted. The behavior is documented in algorithm \ref{alg:2pass}, with changes from the original algorithm are \underline{underlined}.
|
|
% \item Add an extra ``exception edge'' from each ``exit with exception of type T'' node, where the type of the exception is \texttt{t} to all the corresponding ``\texttt{throw e}'', such that \texttt{e} is or inherits from \texttt{T}.
|
|
% \item Add an extra ``exception edge'' from each catch statement to every statement that can throw that error.
|
|
% \item The exception edges will only be placed when the method or the try-catch statement are loop-carrier\footnote{Loop-carrier, when referring to a statement, is the property that in a CFG for the complete program, the node representing the statement is part of a loop, meaning that it could be executed again once it is executed.}.
|
|
% \end{itemize}
|
|
|
|
% \begin{algorithm} % generate slice
|
|
% \caption{Two-pass algorithm to obtain a backward static slice with exceptions}
|
|
% \label{alg:2pass}
|
|
% \begin{algorithmic}[1]
|
|
% \REQUIRE SDG $\mathcal{G}$ representing program P. $\mathcal{G} = \{\mathcal{S}, \mathcal{E}\}$, where $\mathcal{S}$ is a set of states (some are statements) connected by a set of edges $\mathcal{E}$. Each edge, is a triplet composed of the type of edge (control, data or \underline{exception} dependency, summary, param-in, param-out), the source and destination of the edge.
|
|
% \REQUIRE A slicing criterion, composed of a statement $s \in \mathcal{S}$ and a variable $v$.
|
|
% \ENSURE $\mathcal{S}' \subseteq \mathcal{S}$, representing the slice of P according to the criterion provided.
|
|
|
|
% \medskip
|
|
% \COMMENT{First pass (do not traverse output parameter edges).}
|
|
% \STATE{$\mathcal{S}' \Leftarrow \emptyset$ (slice), $\mathcal{Q}\Leftarrow\{s\}$ (queue), $\mathcal{S}\Leftarrow \mathcal{S} - \{s\}$ (not visited), $\mathcal{R}\Leftarrow \emptyset$ (only visited via exception edge)}
|
|
% \WHILE{$\mathcal{Q} \neq \emptyset$}
|
|
% \STATE{$a \in \mathcal{Q}$} \COMMENT{Select an element from $\mathcal{Q}$}
|
|
% \STATE{$\mathcal{Q} \Leftarrow \mathcal{Q} - \{a\}$}
|
|
% \STATE{$\mathcal{S}' \Leftarrow \mathcal{S}' + \{a\}$}
|
|
% \FORALL{$\mathcal{A}$ in $\{\{type, origin, a\} \in \mathcal{E}\}$}
|
|
% \IF{$type \neq$ param-out \AND ($origin \notin \mathcal{S}'$ \OR ($origin \in \mathcal{R}$ \AND $a \notin \mathcal{R}$))} \label{line:param-out}
|
|
% \IF{\underline{$a \in \mathcal{R}$}}
|
|
% \IF{\underline{$type =$ exception}}
|
|
% \STATE{\underline{$\mathcal{Q} \Leftarrow \mathcal{Q} + \{origin\}$}}
|
|
% \STATE{\underline{$\mathcal{R} \Leftarrow \mathcal{R} + \{origin\}$}}
|
|
% \ENDIF
|
|
% \ELSE
|
|
% \STATE{$\mathcal{Q} \Leftarrow \mathcal{Q} + \{origin\}$}
|
|
% \ENDIF
|
|
% \ENDIF
|
|
% \ENDFOR
|
|
% \ENDWHILE
|
|
% \\
|
|
% \medskip
|
|
% \COMMENT{Second pass (very similar, do not traverse input parameter edges).}
|
|
% \STATE $\mathcal{Q} \Leftarrow \mathcal{S}'$
|
|
% \WHILE{$\mathcal{Q} \neq \emptyset$}
|
|
% \STATE{$a \in \mathcal{Q}$} \COMMENT{Select an element from $\mathcal{Q}$}
|
|
% \STATE{$\mathcal{Q} \Leftarrow \mathcal{Q} - \{a\}$}
|
|
% \STATE{$\mathcal{S}' \Leftarrow \mathcal{S}' + \{a\}$}
|
|
% \FORALL{$\mathcal{A}$ in $\{\{type, origin, a\} \in \mathcal{E}\}$}
|
|
% \IF{$type \neq$ param-in \AND ($origin \notin \mathcal{S}'$ \OR ($origin \in \mathcal{R}$ \AND $a \notin \mathcal{R}$))}
|
|
% \IF{\underline{$a \in \mathcal{R}$}}
|
|
% \IF{\underline{$type =$ exception}}
|
|
% \STATE{\underline{$\mathcal{Q} \Leftarrow \mathcal{Q} + \{origin\}$}}
|
|
% \STATE{\underline{$\mathcal{R} \Leftarrow \mathcal{R} + \{origin\}$}}
|
|
% \ENDIF
|
|
% \ELSE
|
|
% \STATE{$\mathcal{Q} \Leftarrow \mathcal{Q} + \{origin\}$}
|
|
% \ENDIF
|
|
% \ENDIF
|
|
% \ENDFOR
|
|
% \ENDWHILE
|
|
% \end{algorithmic}
|
|
% \end{algorithm}
|
|
|
|
% vim: set noexpandtab:ts=2:sw=2:wrap
|