KernelNewbies:

To search for an erroneous pattern like this:

for (i = 0; i < n; i++) {}
...
if (i > n) ...

This is wrong because at the end of the loop i equals n and cannot be greater than n. The most simple way to match this is:

gres -A40 "^ for \(" \
"for \( (@V) = @d ;
         \1 < @d ;
         \1 \+\+ \)
    \{.8.\}
@n
if \( \1 > \3 \)"

Also, @d has parentheses, that's why we have to use \3, not \2 for back-reference to match the second @d.

For me - I currently have kernel version 2.6.33-rc2 - this results after about 10 seconds in a match (simplified here):

---[ vi drivers/mmc/host/s3cmci.c +1209 ]---
        /* Set clock */
        for (mci_psc = 0; mci_psc < 255; mci_psc++) {
                ...
        }

        if (mci_psc > 255)
                mci_psc = 255;
        ...

Quite harmless so I left it. Let's extend the example, similar errors will occur with:

for (i = 0; i != MAX; i++) {}
...
if (i <= MAX) ...

To catch such errors we could use a pattern like this:

gres -A40 "^ for \(" \
"for \( (@V) = (@d|@K) ;
         \1 (<|\!=) (@d|@K) ;
         (\+\+ \1|\1 \+\+|\1 = \1 \+ 1|\1 = 1 \+ \1) \)
    \{.8.\}
@n
if \( \1 (>|<=) \5 \)"

The @K matches definitions. This did not result in more errors in this kernel version, so lets extend it even more. Similar problems may occur when we have a pattern like:

while (foo() && ++i < MAX && bar()) {}
...
if (baz() || i > MAX) ...

This can be matched by:

gres -A40 "^ (for|while) \(" \
"(for \([^;]*;|while \() (\(-..\)[&|])*
         \+* (@V) (<|\!=) (@d|@w) ([&|]\(-..\))*
         (; (\+\+ \6|\6 \+\+|\6 = \6 \+ 1|\6 = 1 \+ \6))? \)
    \{.8.\}
@n
if \( (\(-..\)[&|])* \6 (>|<=) \8 ([&|]\(-..\))* \)"

This results (after about half a minute on my computer) in the additional matches:

---[ vi arch/sparc/mm/init_64.c +786 ]---
        ...
        start += PAGE_SIZE;
        while (start < end) {
                ...
                if (...)
                        break;
                start += PAGE_SIZE;
        }

        if (start > end)
                start = end;
        ...
---[ vi drivers/atm/horizon.c +626 ]---
        while (...) ...
        ...
        if (...) ...
        ...
        while (div < CR_MAXD) {
                div++;
                if (...) {
                        ...
                        goto got_it;
                }
        }
got_it:
        if (div > CR_MAXD || ...) ...

The second one was difficult to see in the output due to a prior while loop. The first one, in contrast, is a false positive: the addition of PAGE_SIZE can cause `start' to be bigger than `end'. In the case of a while loop the chosen pattern with `\+*' allows a postfix increment, but does not ensure that an increment occurs, an addition can occur just as well. We can exclude the false positive by adding an exclusion pattern:

gres -A40 "^ (for|while) \(" \
"while \( (\(-..\)[&|])* (@V) (<|\!=) (@d|@w) ([&|]\(-..\))* \) (\{\{-..\} \n)? \5 ([+*|]=|= \5 \+)@n
if \( (\(-..\)[&|])* \5 (>|<=) \7 ([&|]\(-..\))* \)" \
"(for \([^;]*;|while \() (\(-..\)[&|])*
         \+* (@V) (<|\!=) (@d|@w) ([&|]\(-..\))*
         (; (\+\+ \6|\6 \+\+|\6 = \6 \+ 1|\6 = 1 \+ \6))? \)
    \{.8.\}
@n
if \( (\(-..\)[&|])* \6 (>|<=) \8 ([&|]\(-..\))* \)"

Similarly one can define an erroneous pattern for decrementing loops:

gres -A40 "^ (for|while) \(" \
"while \( (\(-..\)[&|])* (@V) (>|\!=) (@d|@w) ([&|]\(-..\))* \) (\{\{-..\} \n)? \5 (-=|= \5 -)@n
if \( (\(-..\)[&|])* \5 (<|>=) \7 ([&|]\(-..\))* \)" \
"(for \([^;]*;|while \() (\(-..\)[&|])*
         -* (@V) (>|\!=) (@d|@w) ([&|]\(-..\))*
         (; (-- \6|\6 --|\6 = \6 - 1|\6 = 1 - \6))? \)
    \{.8.\}
@n
if \( (\(-..\)[&|])* \6 (<|>=) \8 ([&|]\(-..\))* \)"

KernelNewbies: roelkluin/gres_examples (last edited 2009-12-30 11:24:56 by d133062)