examples in C

of using mygcc

a simple check

The first example concerns a simple check involving only syntax matching. Consider the following simple C program ex1.c:

#include <stdio.h>
#include <stdlib.h>

main() {
  int i, *p;

  i = 0;
  p = malloc(sizeof(int));
  if(!p) {
    printf("failed to malloc p\n");
    /* should return here! */
  }
  *p = i;
  /* should free(p) here! */
  return 0;

}

To find all the assignment statements in this program, use the --tree-check option, and maybe the –tree-checks-verbose option as well to get more detail:

$ mygcc/1.0.0/bin/gcc --tree-check="%X=%Y" --tree-checks-verbose ex/ex1.c
ex/ex1.c: In function ‘main’:
ex/ex1.c:7: warning: user-defined warning %X=%Y: .
ex/ex1.c:7: instance = {X <- i, Y <- 0},
ex/ex1.c:7: reached: i = 0.
ex/ex1.c:8: warning: user-defined warning %X=%Y: .
ex/ex1.c:8: instance = {X <- p, Y <- (int *) D.2593},
ex/ex1.c:8: reached: p = (int *) D.2593.
ex/ex1.c:13: warning: user-defined warning %X=%Y: .
ex/ex1.c:13: instance = {X <- *p, Y <- i},
ex/ex1.c:13: reached: *p = i.

Let us examine the above output. Each warning consists of three consecutive lines, the first of which telling the user-defined warning that was triggered, which is the user-supplied syntactic pattern. All the three lines are preceded by the source file and the line number raising the problem. The second line gives the problem instance, that is, the binding of pattern variables that made the check fail. The third line contains the statement reached (that was not supposed to be reached in case of a correct program).

Note that in the last warning message, D.2593 is a temporary variable introduced by gcc in the Gimple form. To see the Gimple form, use option --tree-dump-gimple, which generates it in file ex1.c.004t.gimple.

a full check

The second example concerns a full check on the same file ex1.c, that contains two errors. ex1.chk is a simple check file containing 5 checks, also called condates, involving control flow and data flow in addition to pure syntax:

condate malloc_deref {
  from "%X = malloc (%_)"   # any malloc
  to "%_ = %X->%_" or "%X->%_ = %_" 
     or "*%X = %_" or "%_ = *%X"
  avoid "%X = %_" or +"%X != 0B" or -"%X == 0B"
} warning("Unsafe dereference of X after malloc");

condate unfreed {
  from "%X = malloc (%_)" to "return" or "return %_"
  avoid "free (%X)" or +"%X == 0B" or -"%X != 0B"
} warning("Un-freed memory for variable X");

condate missing_unlock {
  from "flockfile (%X)"
  to ("return" or "return %_") 
  avoid "funlockfile (%X)"
} warning("Unreleased lock on file X");

condate missing_tryunlock {
  from "%L = ftrylockfile (%X)"
  to ("return" or "return %_") 
  avoid "funlockfile (%X)" or +"%L != 0" or -"%L == 0"
} warning("Unreleased (successful) trylock on file X");

condate gets {   # "degenerate" condate, of only one pattern
  # 'from' keyword must be omitted:
  "%X = gets(%Y)" or "gets(%Y)"
} warning("Never use gets(), see man gets");

To find the errors in ex1.c, invoke mygcc using the --tree-checks option (notice that "checks" is plural now), and maybe the –tree-checks-verbose option as well to get more detail:

$ mygcc/1.0.0/bin/gcc --tree-checks=ex/ex1.chk --tree-checks-verbose ex/ex1.c

ex/ex1.c: In function ‘main’:
ex/ex1.c:13: warning: user-defined warning malloc_deref: Unsafe dereference of X after malloc.
ex/ex1.c:13: instance = {X <- p},
ex/ex1.c:13: reached: *p = i.
ex/ex1.c:16: warning: user-defined warning unfreed: Un-freed memory for variable X.
ex/ex1.c:16: instance = {X <- p},
ex/ex1.c:16: reached: return D.2594

The warning messages have the same three-line layout as for simple checks. The first line tells the user-defined warning that was triggered: if the condate is named, then its name is given; if the condate is anonymous, it is identified by its defining file and its number within the file (numbering starts by 1). If detailed information on the line number cannot be computed, the starting or ending line of the containing function is indicated. The second line gives the problem instance, that is, the binding of pattern variables that made the check fail. The third line contains the statement reached (that was not supposed to be reached in case of a correct program).

other examples

Last update: 18/4/2007. Contact: mygcc@free.fr