diff --git a/devel/Makefile.am b/devel/Makefile.am index 27237be980..bdfca76069 100644 --- a/devel/Makefile.am +++ b/devel/Makefile.am @@ -1,59 +1,68 @@ # # 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. # EXTRA_SCRIPTS = coccinelle/test/testrunner.sh EXTRA_DIST = $(EXTRA_SCRIPTS) \ coccinelle/ref-passed-variables-inited.cocci \ coccinelle/string-any-of.cocci \ coccinelle/string-empty.cocci \ coccinelle/string-null-matches.cocci \ coccinelle/string-replacements.cocci \ coccinelle/test/ref-passed-variables-inited.input.c \ coccinelle/test/ref-passed-variables-inited.output # Coccinelle is a tool that takes special patch-like files (called semantic patches) and # applies them throughout a source tree. This is useful when refactoring, changing APIs, # catching dangerous or incorrect code, and other similar tasks. It's not especially # easy to write a semantic patch but most users should only be concerned about running # the target and inspecting the results. # # Documentation (including examples, which are the most useful): # http://coccinelle.lip6.fr/documentation.php # # Run the "make cocci" target to just output what would be done, or "make cocci-inplace" # to apply the changes to the source tree. # # COCCI_FILES may be set on the command line, if you want to test just a single file # while it's under development. Otherwise, it is a list of all the files that are ready # to be run. # # ref-passed-variables-inited.cocci seems to be returning some false positives around # GHashTableIters, so it is disabled for the moment. COCCI_FILES ?= coccinelle/string-any-of.cocci \ coccinelle/string-empty.cocci \ coccinelle/string-null-matches.cocci +# Any file in this list is allowed to use any of the pcmk__ internal functions. +# Coccinelle can use any transformation that depends on "internal" to rewrite +# code to use the internal functions. +MAY_USE_INTERNAL_FILES = $(shell find .. -path "../lib/*.c" -o -path "../tools/*.c" -o -path "../daemons/*.c" -o -path '../include/pcmki/*h' -o -name '*internal.h') + +# And then any file in this list is public API, which may not use internal +# functions. Thus, only those transformations that do not depend on "internal" +# may be applied. +OTHER_FILES = $(shell find ../include -name '*h' -a \! -name '*internal.h' -a \! -path '../include/pcmki/*') + cocci: - for f in $(COCCI_FILES); do \ - for d in daemons include lib tools; do \ - test $$d = "include" \ - && spatch $(_SPATCH_FLAGS) --include-headers --local-includes \ - --preprocess --sp-file $$f --dir ../$$d \ - || spatch $(_SPATCH_FLAGS) --local-includes \ - --preprocess --sp-file $$f --dir ../$$d; \ - done; \ + for cf in $(COCCI_FILES); do \ + for f in $(MAY_USE_INTERNAL_FILES); do \ + spatch $(_SPATCH_FLAGS) -D internal --very-quiet --local-includes --preprocess --sp-file $$cf $$f; \ + done ; \ + for f in $(OTHER_FILES); do \ + spatch $(_SPATCH_FLAGS) --very-quiet --local-includes --preprocess --sp-file $$cf $$f; \ + done ; \ done cocci-inplace: $(MAKE) $(AM_MAKEFLAGS) _SPATCH_FLAGS=--in-place cocci cocci-test: for f in coccinelle/test/*.c; do \ coccinelle/test/testrunner.sh $$f; \ done diff --git a/devel/coccinelle/ref-passed-variables-inited.cocci b/devel/coccinelle/ref-passed-variables-inited.cocci index 1cc28efea8..0d19ff756d 100644 --- a/devel/coccinelle/ref-passed-variables-inited.cocci +++ b/devel/coccinelle/ref-passed-variables-inited.cocci @@ -1,48 +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/string-any-of.cocci b/devel/coccinelle/string-any-of.cocci index d63ad2e0a5..ef1a2e96dd 100644 --- a/devel/coccinelle/string-any-of.cocci +++ b/devel/coccinelle/string-any-of.cocci @@ -1,74 +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. */ -@ any_of_1 @ +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 @ +@ 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 @ +@ 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 @ +@ 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 @ +@ 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 @ +@ 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 @ +@ 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 @ +@ 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 index 7abd558794..d51f69ca8a 100644 --- a/devel/coccinelle/string-empty.cocci +++ b/devel/coccinelle/string-empty.cocci @@ -1,28 +1,30 @@ /* * 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. */ -@ string_empty @ +virtual internal + +@ string_empty depends on internal @ identifier I; @@ ( - (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) ) diff --git a/devel/coccinelle/string-null-matches.cocci b/devel/coccinelle/string-null-matches.cocci index 00b0b26bc4..b5471f694d 100644 --- a/devel/coccinelle/string-null-matches.cocci +++ b/devel/coccinelle/string-null-matches.cocci @@ -1,72 +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. */ -@ string_null_matches_1 @ +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 @ +@ 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 @ +@ 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 @ +@ 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 @ +@ 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 @ +@ 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 @ +@ 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 @ +@ 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 @ +@ 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 @ +@ 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/string-replacements.cocci b/devel/coccinelle/string-replacements.cocci index f05f246ba6..86f81df77a 100644 --- a/devel/coccinelle/string-replacements.cocci +++ b/devel/coccinelle/string-replacements.cocci @@ -1,56 +1,58 @@ /* * 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_eq 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. */ -@ safe_str_neq_replacement @ +virtual internal + +@ safe_str_neq_replacement depends on internal @ expression E1, E2; @@ - safe_str_neq(E1, E2) + !pcmk__str_eq(E1, E2, pcmk__str_casei) -@ safe_str_eq_replacement_1 @ +@ safe_str_eq_replacement_1 depends on internal @ expression E1, E2; @@ - safe_str_eq(E1, E2) + pcmk__str_eq(E1, E2, pcmk__str_casei) -@ safe_str_eq_replacement_2 @ +@ safe_str_eq_replacement_2 depends on internal @ expression E1, E2; @@ - safe_str_eq(E1, E2) == FALSE + !pcmk__str_eq(E1, E2, pcmk__str_casei) -@ crm_str_eq_replacement_1 @ +@ crm_str_eq_replacement_1 depends on internal @ expression E1, E2; @@ - crm_str_eq(E1, E2, TRUE) + pcmk__str_eq(E1, E2, pcmk__str_none) -@ crm_str_eq_replacement_2 @ +@ crm_str_eq_replacement_2 depends on internal @ expression E1, E2; @@ - crm_str_eq(E1, E2, FALSE) + pcmk__str_eq(E1, E2, pcmk__str_casei) -@ crm_str_eq_replacement_3 @ +@ crm_str_eq_replacement_3 depends on internal @ expression E1, E2; @@ - crm_str_eq(E1, E2, TRUE) == FALSE + !pcmk__str_eq(E1, E2, pcmk__str_none) -@ crm_str_eq_replacement_4 @ +@ crm_str_eq_replacement_4 depends on internal @ expression E1, E2; @@ - crm_str_eq(E1, E2, FALSE) == FALSE + !pcmk__str_eq(E1, E2, pcmk__str_casei)