Match expressions when assigned to a boolean variable

In this example, we propose to write a patch that matches usages of expressions assigned to a boolean variable. Here, you will get familiar with the concept of expression. The following semantic patch also uses inheritance of metavariable between rules, the definition of custom types and type restriction for expressions.

@find_expression@
typedef bool;
bool id;
expression e;
@@
 
  id = e
 
@@
expression find_expression.e;
@@
 
* e

The first rule, namely “find_expression” defines “bool” as a type through the use of typedef. “bool id” defines an expression of type “bool”, that is any expression matched by “e” has to be of that type. Finally, “expression e” is a generic expression.
“id = e” matches every assignment to a variable of type “bool”.

The second rule tells Coccinelle to output every usage of the expressions matched by “e” in “find_expression”.

Here is the sample of C code we chose to illustrate the semantic patch.

struct mystruct1 {
	bool field1;
	int  field2;
};
 
bool f1() {
	bool var = 0;
	long test;
	struct mystruct1 s;
	var = true || false;
	s.field1 = true && false || var;
	s.field2 = 1;
	test = true && false || var;
	return var;
}
 
int f2() {
	int var;
	var = true && true;
	return var;
}
 
long f3() {
	long var = 0;
	var = true && false || var;
	return var;
}
 
bool f4() {
	bool var = 0;
	var = true && false || var;
	return var;
}
 
long f5() {
	long var;
	Bool foo;
	foo = true && true;
	var = 0;
	return var;
}
 
int f6() {
	int var;
	var = true || false;
	return var;
}
 
int f7() {
	int var;
	var = (true || false) && false && false;
	return var;
}
 
int f8() {
	int var;
	var = true || false && false;
	return var;
}
 
int f9() {
	int var;
	var = true;
	return var;
}

The follwing patch is the resulting output:

--- tuto04.c
+++ /tmp/cocci-output-3812-81abe0-tuto04.c
@@ -4,13 +4,9 @@ struct mystruct1 {
 };
 
 bool f1() {
-	bool var = 0;
 	long test;
 	struct mystruct1 s;
-	var = true || false;
-	s.field1 = true && false || var;
 	s.field2 = 1;
-	test = true && false || var;
 	return var;
 }
 
@@ -21,14 +17,11 @@ int f2() {
 }
 
 long f3() {
-	long var = 0;
 	var = true && false || var;
 	return var;
 }
 
 bool f4() {
-	bool var = 0;
-	var = true && false || var;
 	return var;
 }
 
@@ -36,19 +29,16 @@ long f5() {
 	long var;
 	Bool foo;
 	foo = true && true;
-	var = 0;
 	return var;
 }
 
 int f6() {
 	int var;
-	var = true || false;
 	return var;
 }
 
 int f7() {
 	int var;
-	var = (true || false) && false && false;
 	return var;
 }

In “f1”, “var” is declared as a “bool”. In that function, “var” is assigned “0” and “true || false”. The field “field1” of the structure “mystruct1” is also declared as a “bool”, in “f1” this field is assigned “true && false || var”. You can notice that every other statement matched is composed of one of these expressions.

Note also, that “e” does not match both “true || false” and “true” on the third line of “f1”, indeed if “e” had matched “true”, the assignment in “f8” would be present in the resulting patch.

Coccinelle’s expressions take type into consideration, an illustration of that is the difference between the functions “f3” and “f4”. Since “var” is declared as a “long” in “f3” but as a “bool” in “f1”, the type of “true && false || var” changes. Therefore, the expression is matched in “f4” but not in “f3”.