diff options
Diffstat (limited to 'devel/coccinelle')
-rw-r--r-- | devel/coccinelle/ref-passed-variables-inited.cocci | 50 | ||||
-rw-r--r-- | devel/coccinelle/rename-fn.cocci | 23 | ||||
-rw-r--r-- | devel/coccinelle/rename-var.cocci | 29 | ||||
-rw-r--r-- | devel/coccinelle/string-any-of.cocci | 76 | ||||
-rw-r--r-- | devel/coccinelle/string-empty.cocci | 45 | ||||
-rw-r--r-- | devel/coccinelle/string-null-matches.cocci | 74 | ||||
-rw-r--r-- | devel/coccinelle/test/ref-passed-variables-inited.input.c | 88 | ||||
-rw-r--r-- | devel/coccinelle/test/ref-passed-variables-inited.output | 76 | ||||
-rwxr-xr-x | devel/coccinelle/test/testrunner.sh | 13 | ||||
-rw-r--r-- | devel/coccinelle/use-func.cocci | 22 |
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__ +) |