diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 06:53:20 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 06:53:20 +0000 |
commit | e5a812082ae033afb1eed82c0f2df3d0f6bdc93f (patch) | |
tree | a6716c9275b4b413f6c9194798b34b91affb3cc7 /devel | |
parent | Initial commit. (diff) | |
download | pacemaker-e5a812082ae033afb1eed82c0f2df3d0f6bdc93f.tar.xz pacemaker-e5a812082ae033afb1eed82c0f2df3d0f6bdc93f.zip |
Adding upstream version 2.1.6.upstream/2.1.6
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'devel')
-rw-r--r-- | devel/Makefile.am | 295 | ||||
-rw-r--r-- | devel/README | 2 | ||||
-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 | ||||
-rw-r--r-- | devel/gdbhelpers | 109 |
13 files changed, 902 insertions, 0 deletions
diff --git a/devel/Makefile.am b/devel/Makefile.am new file mode 100644 index 0000000..94581e1 --- /dev/null +++ b/devel/Makefile.am @@ -0,0 +1,295 @@ +# +# Copyright 2020-2023 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. +# + +include $(top_srcdir)/mk/common.mk +include $(top_srcdir)/mk/release.mk + +# 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): +# https://coccinelle.gitlabpages.inria.fr/website/docs/ +# +# 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 \ + coccinelle/use-func.cocci + + +dist_noinst_SCRIPTS = coccinelle/test/testrunner.sh +EXTRA_DIST = README gdbhelpers $(COCCI_FILES) \ + coccinelle/ref-passed-variables-inited.cocci \ + coccinelle/rename-fn.cocci \ + coccinelle/test/ref-passed-variables-inited.input.c \ + coccinelle/test/ref-passed-variables-inited.output + +# 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 "../lib/*private.h" -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 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 + +# +# Static analysis +# + +## clang + +# See scan-build(1) for possible checkers (leave empty to use default set) +CLANG_checkers ?= + +clang: + OUT=$$(cd $(top_builddir) \ + && scan-build $(CLANG_checkers:%=-enable-checker %) \ + $(MAKE) $(AM_MAKEFLAGS) CFLAGS="-std=c99 $(CFLAGS)" \ + clean all 2>&1); \ + REPORT=$$(echo "$$OUT" \ + | sed -n -e "s/.*'scan-view \(.*\)'.*/\1/p"); \ + [ -z "$$REPORT" ] && echo "$$OUT" || scan-view "$$REPORT" + +## coverity + +# Aggressiveness (low, medium, or high) +COVLEVEL ?= low + +# Generated outputs +COVERITY_DIR = $(abs_top_builddir)/coverity-$(TAG) +COVTAR = $(abs_top_builddir)/$(PACKAGE)-coverity-$(TAG).tgz +COVEMACS = $(abs_top_builddir)/$(TAG).coverity +COVHTML = $(COVERITY_DIR)/output/errors + +# Coverity outputs are phony so they get rebuilt every invocation + +.PHONY: $(COVERITY_DIR) +$(COVERITY_DIR): coverity-clean + $(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir) init core-clean + $(AM_V_GEN)cd $(top_builddir) \ + && cov-build --dir "$@" $(MAKE) $(AM_MAKEFLAGS) core + +# Public coverity instance + +.PHONY: $(COVTAR) +$(COVTAR): $(COVERITY_DIR) + $(AM_V_GEN)tar czf "$@" --transform="s@.*$(TAG)@cov-int@" "$<" + +.PHONY: coverity +coverity: $(COVTAR) + @echo "Now go to https://scan.coverity.com/users/sign_in and upload:" + @echo " $(COVTAR)" + @echo "then make clean at the top level" + +# Licensed coverity instance +# +# The prerequisites are a little hacky; rather than actually required, some +# of them are designed so that things execute in the proper order (which is +# not the same as GNU make's order-only prerequisites). + +.PHONY: coverity-analyze +coverity-analyze: $(COVERITY_DIR) + @echo "" + @echo "Analyzing (waiting for coverity license if necessary) ..." + cd $(top_builddir) && cov-analyze --dir "$<" --wait-for-license \ + --security --aggressiveness-level "$(COVLEVEL)" + +.PHONY: $(COVEMACS) +$(COVEMACS): coverity-analyze + $(AM_V_GEN)cd $(top_builddir) \ + && cov-format-errors --dir "$(COVERITY_DIR)" --emacs-style > "$@" + +.PHONY: $(COVHTML) +$(COVHTML): $(COVEMACS) + $(AM_V_GEN)cd $(top_builddir) \ + && cov-format-errors --dir "$(COVERITY_DIR)" --html-output "$@" + +.PHONY: coverity-corp +coverity-corp: $(COVHTML) + $(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir) core-clean + @echo "Done. See:" + @echo " file://$(COVHTML)/index.html" + @echo "When no longer needed, make coverity-clean" + +# Remove all outputs regardless of tag +.PHONY: coverity-clean +coverity-clean: + -rm -rf "$(abs_builddir)"/coverity-* \ + "$(abs_builddir)"/$(PACKAGE)-coverity-*.tgz \ + "$(abs_builddir)"/*.coverity + + +## cppcheck + +# Use CPPCHECK_ARGS to pass extra cppcheck options, e.g.: +# --enable={warning,style,performance,portability,information,all} +# --inconclusive --std=posix +# -DBUILD_PUBLIC_LIBPACEMAKER -DDEFAULT_CONCURRENT_FENCING_TRUE +CPPCHECK_ARGS ?= + +CPPCHECK_DIRS = replace lib daemons tools +CPPCHECK_OUT = $(abs_top_builddir)/cppcheck.out + +cppcheck: + cppcheck $(CPPCHECK_ARGS) -I $(top_srcdir)/include \ + --output-file=$(CPPCHECK_OUT) \ + --max-configs=30 --inline-suppr -q \ + --library=posix --library=gnu --library=gtk \ + $(GLIB_CFLAGS) -D__GNUC__ \ + $(foreach dir,$(CPPCHECK_DIRS),$(top_srcdir)/$(dir)) + @echo "Done: See $(CPPCHECK_OUT)" + @echo "When no longer needed, make cppcheck-clean" + +.PHONY: cppcheck-clean +cppcheck-clean: + -rm -f "$(CPPCHECK_OUT)" + +# +# Coverage/profiling +# + +COVERAGE_DIR = $(top_builddir)/coverage + +# Check coverage of unit tests +.PHONY: coverage +coverage: coverage-partial-clean + cd $(top_builddir) \ + && $(MAKE) $(AM_MAKEFLAGS) core \ + && lcov --no-external --exclude='*_test.c' -c -i -d . \ + -o pacemaker_base.info \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && lcov --no-external --exclude='*_test.c' -c -d . \ + -o pacemaker_test.info \ + && lcov -a pacemaker_base.info -a pacemaker_test.info \ + -o pacemaker_total.info + genhtml $(top_builddir)/pacemaker_total.info -o $(COVERAGE_DIR) -s + +# Check coverage of CLI regression tests +.PHONY: coverage-cts +coverage-cts: coverage-partial-clean + cd $(top_builddir) \ + && $(MAKE) $(AM_MAKEFLAGS) core \ + && lcov --no-external -c -i -d tools -o pacemaker_base.info \ + && cts/cts-cli \ + && lcov --no-external -c -d tools -o pacemaker_test.info \ + && lcov -a pacemaker_base.info -a pacemaker_test.info \ + -o pacemaker_total.info + genhtml $(top_builddir)/pacemaker_total.info -o $(COVERAGE_DIR) -s + +# Remove coverage-related files that aren't needed across runs +.PHONY: coverage-partial-clean +coverage-partial-clean: + -rm -f $(top_builddir)/pacemaker_*.info + -rm -rf $(COVERAGE_DIR) + -find $(top_builddir) -name "*.gcda" -exec rm -f \{\} \; + +# This target removes all coverage-related files. It is only to be run when +# done with coverage analysis and you are ready to go back to normal development, +# starting with re-running ./configure. It is not to be run in between +# "make coverage" runs. +# +# In particular, the *.gcno files are generated when the source is built. +# Removing those files will break "make coverage" until the whole source tree +# has been built and the *.gcno files generated again. +.PHONY: coverage-clean +coverage-clean: coverage-partial-clean + -find $(top_builddir) -name "*.gcno" -exec rm -f \{\} \; + +# +# indent cannot cope with all our exceptions and needs heavy manual editing +# + +# indent target: Limit indent to these directories +INDENT_DIRS ?= . + +# indent target: Extra options to pass to indent +INDENT_OPTS ?= + +INDENT_IGNORE_PATHS = daemons/controld/controld_fsa.h \ + lib/gnu/* +INDENT_PACEMAKER_STYLE = --blank-lines-after-declarations \ + --blank-lines-after-procedures \ + --braces-after-func-def-line \ + --braces-on-if-line \ + --braces-on-struct-decl-line \ + --break-before-boolean-operator \ + --case-brace-indentation4 \ + --case-indentation4 \ + --comment-indentation0 \ + --continuation-indentation4 \ + --continue-at-parentheses \ + --cuddle-do-while \ + --cuddle-else \ + --declaration-comment-column0 \ + --declaration-indentation1 \ + --else-endif-column0 \ + --honour-newlines \ + --indent-label0 \ + --indent-level4 \ + --line-comments-indentation0 \ + --line-length80 \ + --no-blank-lines-after-commas \ + --no-comment-delimiters-on-blank-lines \ + --no-space-after-function-call-names \ + --no-space-after-parentheses \ + --no-tabs \ + --preprocessor-indentation2 \ + --procnames-start-lines \ + --space-after-cast \ + --start-left-side-of-comments \ + --swallow-optional-blank-lines \ + --tab-size8 + +indent: + VERSION_CONTROL=none \ + find $(INDENT_DIRS) -type f -name "*.[ch]" \ + $(INDENT_IGNORE_PATHS:%= ! -path '%') \ + -exec indent $(INDENT_PACEMAKER_STYLE) $(INDENT_OPTS) \{\} \; + +# +# Scratch file for ad-hoc testing +# + +EXTRA_PROGRAMS = scratch +nodist_scratch_SOURCES = scratch.c +scratch_LDADD = $(top_builddir)/lib/common/libcrmcommon.la + +clean-local: coverage-clean coverity-clean cppcheck-clean + -rm -f $(EXTRA_PROGRAMS) diff --git a/devel/README b/devel/README new file mode 100644 index 0000000..526df19 --- /dev/null +++ b/devel/README @@ -0,0 +1,2 @@ +This directory contains helpers for the project developers. +Everyone else can safely ignore it. 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__ +) diff --git a/devel/gdbhelpers b/devel/gdbhelpers new file mode 100644 index 0000000..319a5f2 --- /dev/null +++ b/devel/gdbhelpers @@ -0,0 +1,109 @@ +# Copyright 2018-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. + +# notes: +# "print"/"set" as "compile code" requires re-including headers/multi-line + +define pcmk + # shelling avoids necessity to have an inferior around + shell printf '%s %s\n\n' 'Available commands' \ + '(all require an inferior, just break on main or so):' + shell printf '%s\t%s\n' pcmk-follow-daemon \ + 'Convenient pacemakerd to particular daemon descent' + shell printf '%s\t%s\n' pcmk-xmlnode2file \ + 'Convenient XML node to (specified/temporary) file dump' + shell printf '%s\t%s\n' pcmk-terminate \ + 'Convenient way to shut pacemaker down as a whole' +end +document pcmk +Show possible pcmk namespace rooted user-defined convenience commands. +end + + +# XXX one would expect that order of pcmk_children naturally matches +# the actual sequential ordering, but that's governed with start_seq +define pcmk-follow-daemon + dont-repeat + set $d = $arg0 + eval "set $d_alt = \"pacemaker-%s\"", $d + set $cont = 1 + break start_child + cont + while ($cont) + if (!(int)strcmp(child->name, $d) || !(int)strcmp(child->name, $d_alt)) + set $cont = 0 + set follow-fork-mode child + break getrlimit + continue + set follow-fork-mode parent # restore + else + if (child->start_seq == sizeof(pcmk_children)/sizeof(*pcmk_children) - 1) + set $cont = 0 + printf "no such daemon: %s (%s)\n", $d, $d_alt + set follow-fork-mode parent # restore + else + continue + end + end + end +end +document pcmk-follow-daemon +Convenient way to follow into particular daemon when starting debugging +from the master control process of pacemaker (pacemakerd). +For "pacemaker-" prefixed daemons, this very prefix is not needed. + +Synopsis: pcmk-follow-daemon CHILD-DAEMON +Examples: pcmk-follow-daemon "controld" +end + + +define pcmk-xmlnode2file + dont-repeat + set $n = $arg0 + if ($argc > 1) + set $fn = $arg1 + else + set $fn = tmpnam((void *) 0) + printf "refer to this file: %s\n", $fn + end + set $f = (FILE *) fopen($fn, "w") + eval "print (xmlElemDump((FILE *) %p, ((xmlNodePtr) %p)->doc, (xmlNodePtr) %p), \"%s\")", \ + $f, $n, $n, "dump done" + eval "print (fprintf((FILE *) %p, \"\\n\"), fclose((FILE *) %p), \"%s\")", \ + $f, $f, "dump finished" +end +document pcmk-xmlnode2file +Convenient way to dump an XML element to specified file, or a temporary file +when it's not. + +Synopsis: pcmk-xmlnode2file XMLNODEPTR-EXPR [FILE-NAME] +Examples: pcmk-xmlnode2file node "debug-dump.xml" + pcmk-xmlnode2file elem +end + + +define pcmk-terminate + dont-repeat + eval "set $msg = \"<create_request_adv origin='gdb' %s/>\"", \ + "t='crmd' subt='request' crm_task='quit' crm_sys_to='pacemakerd'" + set $con = crm_ipc_new("pacemakerd", 0) + eval "set $con_ok = crm_ipc_connect((crm_ipc_t *) %p)", $con + if ($con_ok) + eval "print (crm_ipc_send((crm_ipc_t *) %p, (xmlReadMemory(\"%s\", %u, %s))->children, %s), \"%s\")", \ + $con, $msg, sizeof($msg), "\"gdb.xml\", (void *) 0, 0", "0, 0, (void *) 0", "terminating..." + else + print "cannot terminate, not running/listening?" + end + eval "print (crm_ipc_close((crm_ipc_t *) %p), \"connection closed\")", $con + eval "print (crm_ipc_destroy((crm_ipc_t *) %p), \"connection destroyed\")", $con +end +document pcmk-terminate +Convenient way to shut pacemaker down as a whole, no matter from +which process, parent or child, and safely(!). + +Synopsis: pcmk-terminate +end |