Code insertion

This chapter is a continuation of the example in Code coverage analysis.

CoverageScanner inserts the instrumentation code as illustrated in the following examples. (The inserted code is displayed in bold blue.)

  • Sequential Statement: The statements are instrumented before their execution. The instrumentation consists in allocating a Boolean variable which detects if the code was executed or not.

    Example:

    a=foo();
    a++;
    break;

    will be changed into:

    
    a=foo();
    a++;
    { inst[0]=1; break; }
                

    inst[0] is set to 1 if the 'break' statement is executed.

  • Conditional Statements and Boolean Expressions (full instrumentation): For Boolean expressions the same principle applies except that in addition to recording the execution itself, the state (true or false) is also recorded.

    Example:

    if ( a<b )
      return 1;

    will be changed into:

    
    if ( (a<b) ? inst[0]=1 : inst[1]=1,0 )
      return 1;
                

    inst[0] is set to 1 if the Boolean expression a<b was true.

    inst[1] is set to 1 if the Boolean expression a<b was false.

  • Conditional Statements and Boolean Expressions (partial instrumentation): In some cases, recording the value of a Boolean expression is unnecessary for sequential statement instrumentation. For example, the statement if (b) return 0; else return 1; is completely covered by a statement coverage—after all, recording whether b becomes true or false does not provide any extra information. Similarly, for the statement if (b) return 0; it is only necessary to check if b was false. By default, Coco suppresses the generation of redundant instrumentation in order to minimize the instrumented code's size and to maximize execution speed.

    Example:

    if ( a<b )
      return 1;

    will be changed into:

    
    if ( a<b )
      return 1;
    else inst[0]=1 ;
                

    inst[0] is set to 1 if the Boolean expression a<b was false. Since the statement coverage records the instruction return 1;, it is not necessary to record if a<b was true;

The generated instrumentation code that needs to be inserted to provide statement coverage for the earlier foo() function example means that the function's code is transformed to the code shown here:


char inst[5];
void foo()
{
  bool found=false;
  for (int i=0; (i<100) && (!found); ++i)
  {
    if (i==50 ) { inst[0]=1;break;}
    if (i==20 ) { inst[1]=1;found=true;}
    if (i==30 ) { inst[2]=1;found=true;}
  inst[3]=1; }
  printf("foo\n");
inst[4]=1; }
    

If we insert the instrumentation code necessary to support decision coverage into this example, the resulting code will look like this:


char inst[13];
void foo()
{
  bool found=false;
  for (int i=0; ((i<100 && !found)?inst[0]=1:inst[1]=1,0); ++i)
  {
    if ((i==50?inst[2]=1:inst[3]=1,0)) {
    inst[4]=1; break;}
    if ((i==20?inst[5]=1:inst[6]=1,0)) {inst[7]=1; found=true;}
    if ((i==30?inst[8]=1:inst[9]=1,0)) {inst[10]=1; found=true;}
  inst[11]=1; }
  printf("foo\n");
inst[12]=1; }
    

If we insert the instrumentation code necessary to support condition coverage into this example, the resulting code will look like this (except that we have wrapped one line to fit better on the page):


char inst[15];
void foo()
{
  bool found=false;
  for (int i=0;((i<100)?inst[0]=1:inst[1]=1,0) &&
       ((!found)?inst[2]=1:inst[3]=1,0); ++i) {
    if ((i==50?inst[4]=1:inst[5]=1,0)) {inst[6]=1; break;}
    if ((i==20?inst[7]=1:inst[8]=1,0)) {inst[9]=1; found=true;}
    if ((i==30?inst[10]=1:inst[11]=1,0)) {inst[12]=1; found=true;}
  inst[13]=1; }
  printf("foo\n");
inst[14]=1; }
    

Here is what the code would look like if we inserted the partial instrumentation code for condition coverage (again, with one line wrapped):


char inst[12];
void foo()
{
  bool found=false;
  for (int i=0; ((i<100)?inst[0]=1:inst[1]=1,0) &&
       ((!found)?inst[2]=1:inst[3]=1,0); ++i) {
    if (i==50 ) {inst[4]=1; break;} else inst[5]=1;
    if (i==20 ) {inst[6]=1; found=true;} else inst[7]=1;
    if (i==30 ) {inst[8]=1; found=true;} else inst[9]=1;
  inst[10]=1; }
  printf("foo\n");
inst[11]=1; }