summaryrefslogtreecommitdiffstats
path: root/devel/coccinelle
diff options
context:
space:
mode:
Diffstat (limited to 'devel/coccinelle')
-rw-r--r--devel/coccinelle/ref-passed-variables-inited.cocci50
-rw-r--r--devel/coccinelle/rename-fn.cocci23
-rw-r--r--devel/coccinelle/rename-var.cocci29
-rw-r--r--devel/coccinelle/string-any-of.cocci76
-rw-r--r--devel/coccinelle/string-empty.cocci45
-rw-r--r--devel/coccinelle/string-null-matches.cocci74
-rw-r--r--devel/coccinelle/test/ref-passed-variables-inited.input.c88
-rw-r--r--devel/coccinelle/test/ref-passed-variables-inited.output76
-rwxr-xr-xdevel/coccinelle/test/testrunner.sh13
-rw-r--r--devel/coccinelle/use-func.cocci22
10 files changed, 496 insertions, 0 deletions
diff --git a/devel/coccinelle/ref-passed-variables-inited.cocci b/devel/coccinelle/ref-passed-variables-inited.cocci
new file mode 100644
index 0000000..0d19ff7
--- /dev/null
+++ b/devel/coccinelle/ref-passed-variables-inited.cocci
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2019-2020 the Pacemaker project contributors
+ *
+ * The version control history for this file may have further details.
+ *
+ * This source code is licensed under the GNU General Public License version 2
+ * or later (GPLv2+) WITHOUT ANY WARRANTY.
+ *
+ *
+ * We require each local variable that
+ *
+ * - is passed to a function through a dereference (suggesting it serves
+ * possibly also or merely as one of the output value propagators seperate
+ * from actual return value if employed at all) and
+ *
+ * - is then subsequently reused (possibly naively expecting it will always
+ * have been initialized (in said function at latest) further in its scope,
+ *
+ * to _always_ be assuredly initialized to some determined value, so as to
+ * prevent a risk of accidentally accessing unspecified value subsequent
+ * to the return from the considered function, which might not have set
+ * that variable at all, lest it would touch it at all.
+ */
+
+virtual internal
+
+@ref_passed_variables_inited exists@
+identifier f_init, f_consume, var;
+type T;
+expression E, E_propagate;
+@@
+
+ T
+- var
++ var /*FIXME:initialize me*/
+ ;
+ ... when != var = E
+ f_init(..., &var, ...)
+ ... when != var = E
+(
+ return var;
+|
+ f_consume(..., var, ...)
+|
+ E_propagate = var
+|
+ &var
+|
+ *var
+)
diff --git a/devel/coccinelle/rename-fn.cocci b/devel/coccinelle/rename-fn.cocci
new file mode 100644
index 0000000..5bce9b7
--- /dev/null
+++ b/devel/coccinelle/rename-fn.cocci
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2021 the Pacemaker project contributors
+ *
+ * The version control history for this file may have further details.
+ *
+ * This source code is licensed under the GNU General Public License version 2
+ * or later (GPLv2+) WITHOUT ANY WARRANTY.
+ */
+
+/*
+ * Rename a function or macro. This is here as a template; replace "old" and
+ * "new" below with the old and new names, run in the devel directory:
+ *
+ * make COCCI_FILES=coccinelle/rename-fn.cocci cocci-inplace
+ *
+ * then revert the file before committing.
+ */
+
+virtual internal
+
+@@ expression E; @@
+- old(E)
++ new(E)
diff --git a/devel/coccinelle/rename-var.cocci b/devel/coccinelle/rename-var.cocci
new file mode 100644
index 0000000..65bba80
--- /dev/null
+++ b/devel/coccinelle/rename-var.cocci
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2021 the Pacemaker project contributors
+ *
+ * The version control history for this file may have further details.
+ *
+ * This source code is licensed under the GNU General Public License version 2
+ * or later (GPLv2+) WITHOUT ANY WARRANTY.
+ */
+
+/*
+ * Rename a variable. This is here as a template; replace "old" and
+ * "new" below with the old and new names. Here is an example:
+ *
+ * @@ @@
+ * - xml_private_flags
+ * + pcmk__xml_flags
+ *
+ * Run in the devel directory:
+ *
+ * make COCCI_FILES=coccinelle/rename-var.cocci cocci-inplace
+ *
+ * then revert the file before committing.
+ */
+
+virtual internal
+
+@@ @@
+- old
++ new
diff --git a/devel/coccinelle/string-any-of.cocci b/devel/coccinelle/string-any-of.cocci
new file mode 100644
index 0000000..ef1a2e9
--- /dev/null
+++ b/devel/coccinelle/string-any-of.cocci
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2020 the Pacemaker project contributors
+ *
+ * The version control history for this file may have further details.
+ *
+ * This source code is licensed under the GNU General Public License version 2
+ * or later (GPLv2+) WITHOUT ANY WARRANTY.
+ *
+ * Catch string comparisons where the pcmk__str_any_of function could be used
+ * instead. Note that we are only catching uses involving identifiers (not
+ * expressions), but I think this is probably fine - we are likely not using
+ * the same expression multiple times in a single line of code. If some are
+ * found, it's easy enough to add another block here.
+ */
+
+virtual internal
+
+@ any_of_1 depends on internal @
+expression test_str, str, new_str;
+identifier I =~ "pcmk__str_none";
+@@
+- pcmk__str_eq(test_str, str, I) || pcmk__str_eq(test_str, new_str, I)
++ pcmk__str_any_of(test_str, str, new_str, NULL)
+
+@ any_of_2 depends on internal @
+expression test_str, str, new_str;
+identifier I =~ "pcmk__str_casei";
+@@
+- pcmk__str_eq(test_str, str, I) || pcmk__str_eq(test_str, new_str, I)
++ pcmk__strcase_any_of(test_str, str, new_str, NULL)
+
+@ any_of_3 depends on internal @
+expression test_str, new_str;
+expression list strs;
+identifier I =~ "pcmk__str_none";
+@@
+- pcmk__str_any_of(test_str, strs, NULL) || pcmk__str_eq(test_str, new_str, I)
++ pcmk__str_any_of(test_str, strs, new_str, NULL)
+
+@ any_of_4 depends on internal @
+expression test_str, new_str;
+expression list strs;
+identifier I =~ "pcmk__str_casei";
+@@
+- pcmk__strcase_any_of(test_str, strs, NULL) || pcmk__str_eq(test_str, new_str, I)
++ pcmk__strcase_any_of(test_str, strs, new_str, NULL)
+
+@ none_of_1 depends on internal @
+expression test_str, str, new_str;
+identifier I =~ "pcmk__str_none";
+@@
+- !pcmk__str_eq(test_str, str, I) && !pcmk__str_eq(test_str, new_str, I)
++ !pcmk__str_any_of(test_str, str, new_str, NULL)
+
+@ none_of_2 depends on internal @
+expression test_str, str, new_str;
+identifier I =~ "pcmk__str_casei";
+@@
+- !pcmk__str_eq(test_str, str, I) && !pcmk__str_eq(test_str, new_str, I)
++ !pcmk__strcase_any_of(test_str, str, new_str, NULL)
+
+@ none_of_3 depends on internal @
+expression test_str, new_str;
+expression list strs;
+identifier I =~ "pcmk__str_none";
+@@
+- !pcmk__str_any_of(test_str, strs, NULL) && !pcmk__str_eq(test_str, new_str, I)
++ !pcmk__str_any_of(test_str, strs, new_str, NULL)
+
+@ none_of_4 depends on internal @
+expression test_str, new_str;
+expression list strs;
+identifier I =~ "pcmk__str_casei";
+@@
+- !pcmk__strcase_any_of(test_str, strs, NULL) && !pcmk__str_eq(test_str, new_str, I)
++ !pcmk__strcase_any_of(test_str, strs, new_str, NULL)
diff --git a/devel/coccinelle/string-empty.cocci b/devel/coccinelle/string-empty.cocci
new file mode 100644
index 0000000..16e6b17
--- /dev/null
+++ b/devel/coccinelle/string-empty.cocci
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2020 the Pacemaker project contributors
+ *
+ * The version control history for this file may have further details.
+ *
+ * This source code is licensed under the GNU General Public License version 2
+ * or later (GPLv2+) WITHOUT ANY WARRANTY.
+ *
+ * Catch string comparisons where the pcmk__str_empty function could be used
+ * instead. Note that we are only catching uses involving identifiers (not
+ * expressions), but I think this is probably fine - we are likely not using
+ * the same expression multiple times in a single line of code. If some are
+ * found, it's easy enough to add another block here.
+ */
+
+virtual internal
+
+@ string_empty depends on internal @
+type t;
+identifier func !~ "pcmk__str_empty";
+char* I;
+@@
+t func(...) {
+...
+(
+- (I == NULL) || (strlen(I) == 0)
++ pcmk__str_empty(I)
+|
+- (I == NULL) || !strlen(I)
++ pcmk__str_empty(I)
+|
+- (I == NULL) || (I[0] == 0)
++ pcmk__str_empty(I)
+|
+- (I == NULL) || (*I == 0)
++ pcmk__str_empty(I)
+|
+- (I == NULL) || (I[0] == '\0')
++ pcmk__str_empty(I)
+|
+- (I == NULL) || (*I == '\0')
++ pcmk__str_empty(I)
+)
+...
+}
diff --git a/devel/coccinelle/string-null-matches.cocci b/devel/coccinelle/string-null-matches.cocci
new file mode 100644
index 0000000..b5471f6
--- /dev/null
+++ b/devel/coccinelle/string-null-matches.cocci
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2020 the Pacemaker project contributors
+ *
+ * The version control history for this file may have further details.
+ *
+ * This source code is licensed under the GNU General Public License version 2
+ * or later (GPLv2+) WITHOUT ANY WARRANTY.
+ *
+ * Catch places where a string can either be NULL or can match some other
+ * string. In these cases, passing the right flag to pcmk__str_eq will get
+ * the same result but without having to do the NULL comparison manually.
+ */
+
+virtual internal
+
+@ string_null_matches_1 depends on internal @
+expression E1, E2;
+@@
+- ((E1 == NULL) || crm_str_eq(E1, E2, TRUE))
++ pcmk__str_eq(E1, E2, pcmk__str_null_matches)
+
+@ string_null_matches_2 depends on internal @
+expression E1, E2;
+@@
+- ((E1 == NULL) || crm_str_eq(E2, E1, TRUE))
++ pcmk__str_eq(E1, E2, pcmk__str_null_matches)
+
+@ string_null_matches_3 depends on internal @
+expression E1, E2;
+@@
+- ((E1 == NULL) || safe_str_eq(E1, E2))
++ pcmk__str_eq(E1, E2, pcmk__str_null_matches|pcmk__str_casei)
+
+@ string_null_matches_4 depends on internal @
+expression E1, E2;
+@@
+- ((E1 == NULL) || safe_str_eq(E2, E1))
++ pcmk__str_eq(E1, E2, pcmk__str_null_matches|pcmk__str_casei)
+
+@ string_null_matches_5 depends on internal @
+expression E1, E2;
+@@
+- ((E1 == NULL) || strcmp(E1, E2) == 0)
++ pcmk__str_eq(E1, E2, pcmk__str_null_matches)
+
+@ string_null_matches_6 depends on internal @
+expression E1, E2;
+@@
+- ((E1 == NULL) || strcmp(E2, E1) == 0)
++ pcmk__str_eq(E1, E2, pcmk__str_null_matches)
+
+@ string_null_matches_7 depends on internal @
+expression E1, E2;
+@@
+- ((E1 == NULL) || !strcmp(E1, E2))
++ pcmk__str_eq(E1, E2, pcmk__str_null_matches)
+
+@ string_null_matches_8 depends on internal @
+expression E1, E2;
+@@
+- ((E1 == NULL) || !strcmp(E2, E1))
++ pcmk__str_eq(E1, E2, pcmk__str_null_matches)
+
+@ string_null_matches_9 depends on internal @
+expression E1, E2;
+@@
+- ((E1 != NULL) && strcmp(E1, E2) != 0)
++ !pcmk__str_eq(E1, E2, pcmk__str_null_matches)
+
+@ string_null_matches_10 depends on internal @
+expression E1, E2;
+@@
+- ((E1 != NULL) && strcmp(E2, E1) != 0)
++ !pcmk__str_eq(E1, E2, pcmk__str_null_matches)
diff --git a/devel/coccinelle/test/ref-passed-variables-inited.input.c b/devel/coccinelle/test/ref-passed-variables-inited.input.c
new file mode 100644
index 0000000..9ddb626
--- /dev/null
+++ b/devel/coccinelle/test/ref-passed-variables-inited.input.c
@@ -0,0 +1,88 @@
+void foo(int *z) {
+ return:
+}
+void baz(int z) {
+ return;
+}
+void zob1(int **z) {
+ return;
+}
+void zob2(int ***z) {
+ return;
+}
+
+void bar0(void) {
+ int i;
+ foo(&i);
+ baz(i);
+}
+
+void bar1(void) {
+ int i;
+ foo(&i);
+ foo(&i);
+}
+
+void bar2(void) {
+ int a = 1, b, c = 3;
+ foo(&a);
+ baz(a);
+ foo(&b);
+ baz(b);
+ foo(&c);
+ baz(c);
+}
+
+void bar3(int *w) {
+ int i;
+ foo(&i);
+ *w = i;
+}
+
+void bar4(int **w) {
+ int i;
+ foo(&i);
+ **w = *i;
+}
+
+void bar5(int ***w) {
+ int *i;
+ zob(&i);
+ ***w = *i;
+}
+
+void bar6(int ***w) {
+ int *i;
+ zob1(&i);
+ ***w = *i;
+}
+
+void bar7(int ****w) {
+ int **i;
+ zob1(&i);
+ ****w = **i;
+}
+
+int bar8(void) {
+ int i;
+ foo(&i);
+ return i;
+}
+
+void not0(void) {
+ int i;
+ foo(&i);
+}
+
+void not1(void) {
+ int i;
+ foo(&i);
+ i = 1;
+}
+
+/* XXX false positive */
+void not2(void) {
+ int i;
+ foo(&i);
+ *(&i) = 2;
+}
diff --git a/devel/coccinelle/test/ref-passed-variables-inited.output b/devel/coccinelle/test/ref-passed-variables-inited.output
new file mode 100644
index 0000000..c7a9f91
--- /dev/null
+++ b/devel/coccinelle/test/ref-passed-variables-inited.output
@@ -0,0 +1,76 @@
+@@ -12,19 +12,19 @@ void zob2(int ***z) {
+ }
+
+ void bar0(void) {
+- int i;
++ int i/*FIXME:initialize me*/;
+ foo(&i);
+ baz(i);
+ }
+
+ void bar1(void) {
+- int i;
++ int i/*FIXME:initialize me*/;
+ foo(&i);
+ foo(&i);
+ }
+
+ void bar2(void) {
+- int a = 1, b, c = 3;
++ int a = 1, b/*FIXME:initialize me*/, c = 3;
+ foo(&a);
+ baz(a);
+ foo(&b);
+@@ -34,37 +34,37 @@ void bar2(void) {
+ }
+
+ void bar3(int *w) {
+- int i;
++ int i/*FIXME:initialize me*/;
+ foo(&i);
+ *w = i;
+ }
+
+ void bar4(int **w) {
+- int i;
++ int i/*FIXME:initialize me*/;
+ foo(&i);
+ **w = *i;
+ }
+
+ void bar5(int ***w) {
+- int *i;
++ int *i/*FIXME:initialize me*/;
+ zob(&i);
+ ***w = *i;
+ }
+
+ void bar6(int ***w) {
+- int *i;
++ int *i/*FIXME:initialize me*/;
+ zob1(&i);
+ ***w = *i;
+ }
+
+ void bar7(int ****w) {
+- int **i;
++ int **i/*FIXME:initialize me*/;
+ zob1(&i);
+ ****w = **i;
+ }
+
+ int bar8(void) {
+- int i;
++ int i/*FIXME:initialize me*/;
+ foo(&i);
+ return i;
+ }
+@@ -82,7 +82,7 @@ void not1(void) {
+
+ /* XXX false positive */
+ void not2(void) {
+- int i;
++ int i/*FIXME:initialize me*/;
+ foo(&i);
+ *(&i) = 2;
+ }
diff --git a/devel/coccinelle/test/testrunner.sh b/devel/coccinelle/test/testrunner.sh
new file mode 100755
index 0000000..07e4795
--- /dev/null
+++ b/devel/coccinelle/test/testrunner.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+set -eu
+_tmpdir=$(mktemp -d /tmp/coccicheck-XXXXXX)
+_bname=$(basename "$1" .input.c)
+_dname=$(dirname "$1")
+spatch --very-quiet --sp-file "${_dname}/../${_bname}.cocci" "$1" \
+ | tail -n+3 > "${_tmpdir}/out"
+diff -u "${_dname}/${_bname}.output" "${_tmpdir}/out"
+
+if [ -d "${_tmpdir}" ]; then
+ rm "${_tmpdir}"/*
+ rmdir "${_tmpdir}"
+fi
diff --git a/devel/coccinelle/use-func.cocci b/devel/coccinelle/use-func.cocci
new file mode 100644
index 0000000..bfca919
--- /dev/null
+++ b/devel/coccinelle/use-func.cocci
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2020 the Pacemaker project contributors
+ *
+ * The version control history for this file may have further details.
+ *
+ * This source code is licensed under the GNU General Public License version 2
+ * or later (GPLv2+) WITHOUT ANY WARRANTY.
+ */
+
+/*
+ * Always use __func__ (which is in the C99 standard) instead of __FUNCTION__
+ * (which is an older GNU C extension)
+ */
+
+virtual internal
+
+@ use_func @
+@@
+(
+- __FUNCTION__
++ __func__
+)