On Thu, 19 May 2016, Luis R. Rodriguez wrote:
> From: "Luis R. Rodriguez" <[email protected]> Applied > > Add control flow documentation. > > v2: fix typos, add "depends on" documentation in control flow > section as well. > > Signed-off-by: Luis R. Rodriguez <[email protected]> > --- > docs/manual/Makefile | 6 +- > docs/manual/cocci_syntax.tex | 257 > +++++++++++++++++++++++++++++++++++++++++++ > docs/manual/flow1.c | 10 ++ > docs/manual/flow2.c | 11 ++ > 4 files changed, 283 insertions(+), 1 deletion(-) > create mode 100644 docs/manual/flow1.c > create mode 100644 docs/manual/flow2.c > > diff --git a/docs/manual/Makefile b/docs/manual/Makefile > index 98e397ac5b69..0cfe817cdc4e 100644 > --- a/docs/manual/Makefile > +++ b/docs/manual/Makefile > @@ -36,7 +36,11 @@ manual.pdf: $(SRC) > $(PDFLATEX_CMD) manual.tex > $(PDFLATEX_CMD) manual.tex > > -main_grammar.pdf: main_grammar.tex cocci_syntax.tex > macros_listing_cocci.tex macros_grammar.tex macros_common.tex examples.tex > tips.tex > +main_grammar.pdf: main_grammar.tex cocci_syntax.tex flow1.c flow2.c > macros_listing_cocci.tex macros_grammar.tex macros_common.tex examples.tex > tips.tex > + #spatch --control-flow-to-file flow1.c > + #spatch --control-flow-to-file flow2.c > + #dot -Gsize="0.5,0.5" -Tpdf flow1:main.dot > flow1.pdf > + #dot -Gsize="0.5,0.5" -Tpdf flow2:main.dot > flow2.pdf > $(PDFLATEX_CMD) main_grammar.tex > $(PDFLATEX_CMD) main_grammar.tex > > diff --git a/docs/manual/cocci_syntax.tex b/docs/manual/cocci_syntax.tex > index 2c0f622251f6..b62540da7093 100644 > --- a/docs/manual/cocci_syntax.tex > +++ b/docs/manual/cocci_syntax.tex > @@ -584,6 +584,263 @@ rule is only applied if all of the metavariables for > which there are no > default values have values. See demos/defaultscript.cocci for examples of > the use of this feature. > > +\section{Control Flow} > + > +Rules describe a property which Coccinelle must match, when the property > +described is matched the rule is considered successful. Program control > +flows vary, a control flow describes a possible run time path taken by > +a program. > + > +When using Coccinelle you often want to be able to express certain code > +within certain types of control flows. Typically you will use ellipses > +("...") to indicate to Coccinelle anything can be present between > +consecutive statements. For instance the following SmPL patch tells > Coccinelle > +that rule r0 wishes to remove call calls to function c(). > + > +\begin{center} > +\begin{tabular}{c} > +\begin{lstlisting}[language=Cocci] > +@r0@ > +@@ > + > +-c(); > + > +\end{lstlisting}\\ > +\end{tabular} > +\end{center} > + > +The context of the rule provides no other guidlines to Coccinelle to hint > +about any possible control flow other than this is a statement, and that > +c() must be called. We can modify the required control flow required for > +this rule by providing additional requirements and using ellipses in between. > +For instance, if we only wanted to remove call calls to c() but which also > +had a prior call to foo() we'd use the following SmPL patch: > + > +\begin{center} > +\begin{tabular}{c} > +\begin{lstlisting}[language=Cocci] > +@r1@ > +@@ > + > +foo() > +... > +-c(); > +\end{lstlisting}\\ > +\end{tabular} > +\end{center} > + > +There are two possible modifiers to the control flow for ellipses, one > +is to annotate that statements in between ellipses are optional (<... ...>), > +or that the statements in between must be present at least once (<+... ...+). > +For instance the following SmPL patch tells Coccinelle to remove all > +calls to c() but foo() must be present at least once. > + > +\begin{center} > +\begin{tabular}{c} > +\begin{lstlisting}[language=Cocci] > +@r2@ > +@@ > + > +<+... > +foo() > +...+> > +-c(); > + > +\end{lstlisting}\\ > +\end{tabular} > +\end{center} > + > +Alternatively, if you wanted to be explicit that foo() was optional, > +you could use the following SmPL rule. > + > +\begin{center} > +\begin{tabular}{c} > +\begin{lstlisting}[language=Cocci] > +@r3@ > +@@ > + > +<... > +foo() > +...> > +-c(); > + > +\end{lstlisting}\\ > +\end{tabular} > +\end{center} > + > +Let's consider some sample code to review, this is flow1.c. > + > +\begin{center} > +\begin{tabular}{c} > +\begin{lstlisting}[language=C] > + > +int main(void) > +{ > + int ret, a = 2; > + > + a = foo(a); > + ret = bar(a); > + c(); > + > + return ret; > +} > +\end{lstlisting}\\ > +\end{tabular} > +\end{center} > + > +Applying the SmPL rule r0 to flow1.c would remove the c() line as the control > +flow provides no specific context requirements. Applying rule r1 would also > +succeed as the call to foo() is present. Likewise rules r2 and r3 would also > +succeed. If the foo() call is removed from flow1.c only rules r0 and r3 would > +succeed, as foo() would not be present and only rules r0 and r3 allow for > +foo() to not be present. > + > +The program flow1.1 has a linear control flow, it has no branches. The main > +routine has a McCabe cyclomatic complexity of 1. The McCabe cyclomatic > +complexity can be computed using > +{\tt pmccabe} > (https://www.gnu.org/software/complexity/manual/html\_node/pmccabe-parsing.html). > + > +\begin{center} > +\begin{tabular}{c} > +\begin{lstlisting}[language=C] > +pmccabe /flow1.c > +1 1 5 1 10 flow1.c(1): main > +\end{lstlisting}\\ > +\end{tabular} > +\end{center} > + > +Since programs can use branches, often times you may also wish to annotate > +requirements for control flows in consideration for branches, for when > +the McCabe cyclomatic complexity is > 1. The following program, flow2.c, > +enables the control flow to diverge on line 7 due to the branch, if (a) -- > +one control flow possible is if (a) is true, another when if (a) is false. > + > +\begin{center} > +\begin{tabular}{c} > +\begin{lstlisting}[language=C] > +int main(void) > +{ > + int ret, a = 2; > + > + a = foo(a); > + ret = bar(a); > + if (a) > + c(); > + > + return ret; > +} > +\end{lstlisting}\\ > +\end{tabular} > +\end{center} > + > +This program has a McCabe cyclomatic complexity of 2. > + > +\begin{center} > +\begin{tabular}{c} > +\begin{lstlisting}[language=C] > +pmccabe flow2.c > +2 2 6 1 11 flow2.c(1): main > +\end{lstlisting}\\ > +\end{tabular} > +\end{center} > + > +Using the McCabe cyclomatic complexity is one way to get an idea of > +the complexity of the control graph for a function, another way is > +to visualize all possible paths. Coccinelle provides a way to visualize > +control flows of programs, this however requires {\tt dot} > +(http://www.graphviz.org/) and {\tt gv} to be installed (typically provided > +by a package called graphviz). To visualize control flow or a program > +using Coccinelle you use: > + > +\begin{center} > +\begin{tabular}{c} > +spatch --control-flow-to-file flow1.c > +spatch --control-flow-to-file flow2.c > +\end{tabular} > +\end{center} > + > +%Below are the two generated control flow graphs for flow1.c and flow2.c > +%respectively. > + > +%\begin{figure} > +% \[\includegraphics[width=\linewidth]{flow1.pdf}\] > +% \caption{Linear flow example} > +% \label{devmodel} > +%\end{figure} > + > +%\begin{figure} > +% \[\includegraphics[width=\linewidth]{flow2.pdf}\] > +% \caption{Linear flow example} > +% \label{devmodel} > +%\end{figure} > + > +Behind the scenes this generates a dot file and uses gv to generate > +a PDF file for viewing. To generate and inspect these manually you > +can use the following: > + > +\begin{center} > +\begin{tabular}{c} > +spatch --control-flow-to-file flow2.c > +dot -Tpdf flow1:main.dot > flow1.pdf > +\end{tabular} > +\end{center} > + > +By default properties described in a rule must match all control > +flows possible within a code section being inspected by Coccinelle. > +So for instance, in the following SmPL patch rule r1 would match all > +the control flow possible on flow1.c as its linear, however it would > +not match the control possible on flow2.c. The rule r1 would not > +be successful in flow2.c > + > +\begin{center} > +\begin{tabular}{c} > +\begin{lstlisting}[language=Cocci] > +@r1@ > +@@ > + > +foo() > +... > +-c(); > + > +\end{lstlisting}\\ > +\end{tabular} > +\end{center} > + > +The default control flow can be modified by using the keyword "exists" > +following the rule name. In the following SmPL patch the rule r2 would > +be successful on both flow1.c and flow2.c > + > +\begin{center} > +\begin{tabular}{c} > +\begin{lstlisting}[language=Cocci] > +@r2 exists@ > +@@ > + > +foo() > +... > +-c(); > + > +\end{lstlisting}\\ > +\end{tabular} > +\end{center} > + > +If the rule is followed by the "forall" keyword, then all control flow > +paths must match in order for the rule to succeed. By default when one > +has "-" and "+", or when one has no annotations at all and only script > +code, ellipses ("...") uses the forall semantics. And when one uses > +context annotation ("*"), the ellipses ("...") uses the exists semantics. > +Using the keyword "forall" or "exists" in the rule header affects > +all ellipses ("...") uses in the rule. You can also annotate each > +ellipses ("...") with "when exists" or "when forall" individually. > + > +Rules can also be not be successful if requirements do not match > +when a rule name is followed by "depends on XXX". When "depends on is used > +it means the rule should only apply if rule XXX matched with the current > +metavariable environment. Alternatively, "depends on ever XXX" can be used > +as well, this means this rule should apply if rule XXX was ever matched at > +all. A counter to this use is "depends on never XXX", which means that this > +rule should apply if rule XXX was never matched at all. > + > \section{Transformation} > > The transformation specification essentially has the form of C code, except > diff --git a/docs/manual/flow1.c b/docs/manual/flow1.c > new file mode 100644 > index 000000000000..43e45ed32843 > --- /dev/null > +++ b/docs/manual/flow1.c > @@ -0,0 +1,10 @@ > +int main(void) > +{ > + int ret, a = 2; > + > + a = foo(a); > + ret = bar(a); > + c(); > + > + return ret; > +} > diff --git a/docs/manual/flow2.c b/docs/manual/flow2.c > new file mode 100644 > index 000000000000..bb0d95e4c310 > --- /dev/null > +++ b/docs/manual/flow2.c > @@ -0,0 +1,11 @@ > +int main(void) > +{ > + int ret, a = 2; > + > + a = foo(a); > + ret = bar(a); > + if (a) > + c(); > + > + return ret; > +} > -- > 2.7.2 > > _______________________________________________ > Cocci mailing list > [email protected] > https://systeme.lip6.fr/mailman/listinfo/cocci > _______________________________________________ Cocci mailing list [email protected] https://systeme.lip6.fr/mailman/listinfo/cocci
