diff --git a/src/libsystemd/sd-bus/fuzz-bus-match.c b/src/libsystemd/sd-bus/fuzz-bus-match.c index 65461a1661..d183460ea7 100644 --- a/src/libsystemd/sd-bus/fuzz-bus-match.c +++ b/src/libsystemd/sd-bus/fuzz-bus-match.c @@ -8,6 +8,8 @@ #include "fileio.h" #include "fuzz.h" +DEFINE_TRIVIAL_DESTRUCTOR(bus_match_donep, struct bus_match_node, bus_match_free); + int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { _cleanup_free_ char *out = NULL; /* out should be freed after g */ size_t out_size; @@ -26,7 +28,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { r = sd_bus_new(&bus); assert_se(r >= 0); - struct bus_match_node root = { + _cleanup_(bus_match_donep) struct bus_match_node root = { .type = BUS_MATCH_ROOT, }; diff --git a/src/shared/json.c b/src/shared/json.c index 8962173b3a..904b26f986 100644 --- a/src/shared/json.c +++ b/src/shared/json.c @@ -1788,7 +1788,9 @@ int json_variant_format(JsonVariant *v, JsonFormatFlags flags, char **ret) { if (!f) return -ENOMEM; - json_variant_dump(v, flags, f, NULL); + r = json_variant_dump(v, flags, f, NULL); + if (r < 0) + return r; /* Add terminating 0, so that the output buffer is a valid string. */ fputc('\0', f); diff --git a/test/units/test-control.sh b/test/units/test-control.sh index dd28939cbf..cd7048ae97 100644 --- a/test/units/test-control.sh +++ b/test/units/test-control.sh @@ -6,12 +6,12 @@ if [[ "${BASH_SOURCE[0]}" -ef "$0" ]]; then exit 1 fi -declare -i CHILD_PID=0 -PASSED_TESTS=() -FAILED_TESTS=() +declare -i _CHILD_PID=0 +_PASSED_TESTS=() +_FAILED_TESTS=() # Like trap, but passes the signal name as the first argument -trap_with_sig() { +_trap_with_sig() { local fun="${1:?}" local sig shift @@ -23,16 +23,16 @@ trap_with_sig() { } # Propagate the caught signal to the current child process -handle_signal() { +_handle_signal() { local sig="${1:?}" - if [[ $CHILD_PID -gt 0 ]]; then - echo "Propagating signal $sig to child process $CHILD_PID" - kill -s "$sig" "$CHILD_PID" + if [[ $_CHILD_PID -gt 0 ]]; then + echo "Propagating signal $sig to child process $_CHILD_PID" + kill -s "$sig" "$_CHILD_PID" fi } -# In order to make the handle_signal() stuff above work, we have to execute +# In order to make the _handle_signal() stuff above work, we have to execute # each script asynchronously, since bash won't execute traps until the currently # executed command finishes. This, however, introduces another issue regarding # how bash's wait works. Quoting: @@ -44,7 +44,7 @@ handle_signal() { # # In other words - every time we propagate a signal, wait returns with # 128+signal, so we have to wait again - repeat until the process dies. -wait_harder() { +_wait_harder() { local pid="${1:?}" while kill -0 "$pid" &>/dev/null; do @@ -54,6 +54,31 @@ wait_harder() { wait "$pid" } +_show_summary() {( + set +x + + if [[ ${#_PASSED_TESTS[@]} -eq 0 && ${#_FAILED_TESTS[@]} -eq 0 ]]; then + echo >&2 "No tests were executed, this is most likely an error" + exit 1 + fi + + printf "PASSED TESTS: %3d:\n" "${#_PASSED_TESTS[@]}" + echo "------------------" + for t in "${_PASSED_TESTS[@]}"; do + echo "$t" + done + + if [[ "${#_FAILED_TESTS[@]}" -ne 0 ]]; then + printf "FAILED TESTS: %3d:\n" "${#_FAILED_TESTS[@]}" + echo "------------------" + for t in "${_FAILED_TESTS[@]}"; do + echo "$t" + done + fi + + [[ "${#_FAILED_TESTS[@]}" -eq 0 ]] +)} + # Like run_subtests, but propagate specified signals to the subtest script run_subtests_with_signals() { local subtests=("${0%.sh}".*.sh) @@ -69,19 +94,20 @@ run_subtests_with_signals() { exit 1 fi - trap_with_sig handle_signal "$@" + _trap_with_sig _handle_signal "$@" for subtest in "${subtests[@]}"; do : "--- $subtest BEGIN ---" "./$subtest" & - CHILD_PID=$! - wait_harder "$CHILD_PID" && PASSED_TESTS+=("$subtest") || FAILED_TESTS+=("$subtest") + _CHILD_PID=$! + _wait_harder "$_CHILD_PID" && _PASSED_TESTS+=("$subtest") || _FAILED_TESTS+=("$subtest") : "--- $subtest END ---" done - show_summary + _show_summary } +# Run all subtests (i.e. files named as testsuite-..sh) run_subtests() { local subtests=("${0%.sh}".*.sh) local subtest @@ -93,34 +119,32 @@ run_subtests() { for subtest in "${subtests[@]}"; do : "--- $subtest BEGIN ---" - "./$subtest" && PASSED_TESTS+=("$subtest") || FAILED_TESTS+=("$subtest") + "./$subtest" && _PASSED_TESTS+=("$subtest") || _FAILED_TESTS+=("$subtest") : "--- $subtest END ---" done - show_summary + _show_summary } -show_summary() {( - set +x +# Run all test cases (i.e. functions prefixed with testcase_ in the current namespace) +run_testcases() { + local testcase testcases - if [[ ${#PASSED_TESTS[@]} -eq 0 && ${#FAILED_TESTS[@]} -eq 0 ]]; then - echo >&2 "No tests were executed, this is most likely an error" + # Create a list of all functions prefixed with testcase_ + mapfile -t testcases < <(declare -F | awk '$3 ~ /^testcase_/ {print $3;}') + + if [[ "${#testcases[@]}" -eq 0 ]]; then + echo >&2 "No test cases found, this is most likely an error" exit 1 fi - printf "PASSED TESTS: %3d:\n" "${#PASSED_TESTS[@]}" - echo "------------------" - for t in "${PASSED_TESTS[@]}"; do - echo "$t" + for testcase in "${testcases[@]}"; do + : "+++ $testcase BEGIN +++" + # Note: the subshell here is used purposefully, otherwise we might + # unexpectedly inherit a RETURN trap handler from the called + # function and call it for the second time once we return, + # causing a "double-free" + ("$testcase") + : "+++ $testcase END +++" done - - if [[ "${#FAILED_TESTS[@]}" -ne 0 ]]; then - printf "FAILED TESTS: %3d:\n" "${#FAILED_TESTS[@]}" - echo "------------------" - for t in "${FAILED_TESTS[@]}"; do - echo "$t" - done - fi - - [[ "${#FAILED_TESTS[@]}" -eq 0 ]] -)} +} diff --git a/test/units/testsuite-07.mount-invalid-chars.sh b/test/units/testsuite-07.mount-invalid-chars.sh index 617ea697c8..b70e621126 100755 --- a/test/units/testsuite-07.mount-invalid-chars.sh +++ b/test/units/testsuite-07.mount-invalid-chars.sh @@ -7,7 +7,7 @@ set -o pipefail at_exit() { mountpoint -q /proc/1/mountinfo && umount /proc/1/mountinfo - [[ -e /tmp/fstab.bak ]] && mv -f /tmp/fstab /etc/fstab + [[ -e /tmp/fstab.bak ]] && mv -f /tmp/fstab.bak /etc/fstab rm -f /run/systemd/system/foo-*.mount systemctl daemon-reload } diff --git a/test/units/testsuite-13.nspawn.sh b/test/units/testsuite-13.nspawn.sh index 0cc96424e6..682f677735 100755 --- a/test/units/testsuite-13.nspawn.sh +++ b/test/units/testsuite-13.nspawn.sh @@ -28,9 +28,12 @@ set -eux set -o pipefail +# shellcheck source=test/units/test-control.sh +. "$(dirname "$0")"/test-control.sh # shellcheck source=test/units/util.sh . "$(dirname "$0")"/util.sh + export SYSTEMD_LOG_LEVEL=debug export SYSTEMD_LOG_TARGET=journal @@ -838,17 +841,7 @@ matrix_run_one() { return 0 } -# Create a list of all functions prefixed with testcase_ -mapfile -t TESTCASES < <(declare -F | awk '$3 ~ /^testcase_/ {print $3;}') - -if [[ "${#TESTCASES[@]}" -eq 0 ]]; then - echo >&2 "No test cases found, this is most likely an error" - exit 1 -fi - -for testcase in "${TESTCASES[@]}"; do - "$testcase" -done +run_testcases for api_vfs_writable in yes no network; do matrix_run_one no no $api_vfs_writable diff --git a/test/units/testsuite-15.sh b/test/units/testsuite-15.sh index 2f80cf2564..1b5a1775ee 100755 --- a/test/units/testsuite-15.sh +++ b/test/units/testsuite-15.sh @@ -3,6 +3,9 @@ set -eux set -o pipefail +# shellcheck source=test/units/test-control.sh +. "$(dirname "$0")"/test-control.sh + clear_unit () { local UNIT_NAME="${1:?}" systemctl stop "$UNIT_NAME" 2>/dev/null || : @@ -58,7 +61,7 @@ check_ko () { ! check_ok "$@" } -test_basic_dropins () { +testcase_basic_dropins () { echo "Testing basic dropins..." echo "*** test a wants b wants c" @@ -124,7 +127,7 @@ EOF clear_units test15-{a,b,c,c1}.service } -test_linked_units () { +testcase_linked_units () { echo "Testing linked units..." echo "*** test linked unit (same basename)" @@ -151,7 +154,7 @@ test_linked_units () { clear_units test15-{a,b}.service } -test_template_alias() { +testcase_template_alias() { echo "Testing instance alias..." echo "*** forward" @@ -177,7 +180,7 @@ test_template_alias() { clear_units test15-{a,b}@.service } -test_hierarchical_service_dropins () { +testcase_hierarchical_service_dropins () { echo "Testing hierarchical service dropins..." echo "*** test service.d/ top level drop-in" create_services a-b-c @@ -223,7 +226,7 @@ ExecCondition=echo $dropin clear_units a-b-c.service } -test_hierarchical_slice_dropins () { +testcase_hierarchical_slice_dropins () { echo "Testing hierarchical slice dropins..." echo "*** test slice.d/ top level drop-in" # Slice units don't even need a fragment, so we test the defaults here @@ -282,7 +285,7 @@ MemoryMax=1000000001 clear_units a-b-c.slice } -test_transient_service_dropins () { +testcase_transient_service_dropins () { echo "Testing dropins for a transient service..." echo "*** test transient service drop-ins" @@ -317,7 +320,7 @@ test_transient_service_dropins () { /etc/systemd/system/a-b-.service.d/drop3.conf } -test_transient_slice_dropins () { +testcase_transient_slice_dropins () { echo "Testing dropins for a transient slice..." echo "*** test transient slice drop-ins" @@ -367,7 +370,7 @@ test_transient_slice_dropins () { /etc/systemd/system/a-b-.slice.d/drop3.conf } -test_template_dropins () { +testcase_template_dropins () { echo "Testing template dropins..." create_services foo bar@ yup@ @@ -516,7 +519,7 @@ EOF clear_units foo.service {bar,yup,bar-alias}@{,1,2,3}.service } -test_alias_dropins () { +testcase_alias_dropins () { echo "Testing alias dropins..." echo "*** test a wants b1 alias of b" @@ -548,7 +551,7 @@ test_alias_dropins () { clear_units test15-{a,x,y}.service } -test_masked_dropins () { +testcase_masked_dropins () { echo "Testing masked dropins..." create_services test15-a test15-b @@ -669,7 +672,7 @@ EOF clear_units test15-{a,b}.service } -test_invalid_dropins () { +testcase_invalid_dropins () { echo "Testing invalid dropins..." # Assertion failed on earlier versions, command exits unsuccessfully on later versions systemctl cat nonexistent@.service || true @@ -682,7 +685,7 @@ test_invalid_dropins () { return 0 } -test_symlink_dropin_directory () { +testcase_symlink_dropin_directory () { # For issue #21920. echo "Testing symlink drop-in directory..." create_services test15-a @@ -701,17 +704,6 @@ EOF clear_units test15-a.service } -test_basic_dropins -test_linked_units -test_template_alias -test_hierarchical_service_dropins -test_hierarchical_slice_dropins -test_transient_service_dropins -test_transient_slice_dropins -test_template_dropins -test_alias_dropins -test_masked_dropins -test_invalid_dropins -test_symlink_dropin_directory +run_testcases touch /testok diff --git a/test/units/testsuite-35.sh b/test/units/testsuite-35.sh index 8cb380d2fd..78228ab0b2 100755 --- a/test/units/testsuite-35.sh +++ b/test/units/testsuite-35.sh @@ -3,6 +3,8 @@ set -eux set -o pipefail +# shellcheck source=test/units/test-control.sh +. "$(dirname "$0")"/test-control.sh # shellcheck source=test/units/util.sh . "$(dirname "$0")"/util.sh @@ -33,7 +35,7 @@ EOF systemctl stop systemd-logind.service } -test_properties() { +testcase_properties() { mkdir -p /run/systemd/logind.conf.d cat >/run/systemd/logind.conf.d/kill-user-processes.conf </testok exit 0 diff --git a/test/units/testsuite-45.sh b/test/units/testsuite-45.sh index b21b1105d7..d5a0448ad5 100755 --- a/test/units/testsuite-45.sh +++ b/test/units/testsuite-45.sh @@ -4,10 +4,12 @@ set -eux set -o pipefail +# shellcheck source=test/units/test-control.sh +. "$(dirname "$0")"/test-control.sh # shellcheck source=test/units/util.sh . "$(dirname "$0")"/util.sh -test_timedatectl() { +testcase_timedatectl() { timedatectl --no-pager --help timedatectl --version @@ -36,7 +38,7 @@ restore_timezone() { fi } -test_timezone() { +testcase_timezone() { local ORIG_TZ= # Debian/Ubuntu specific file @@ -87,7 +89,7 @@ check_adjtime_not_exist() { fi } -test_adjtime() { +testcase_adjtime() { # test setting UTC vs. LOCAL in /etc/adjtime if [[ -e /etc/adjtime ]]; then mv /etc/adjtime /etc/adjtime.bak @@ -221,7 +223,7 @@ wait_mon() { wait "$MONPID" 2>/dev/null || true } -test_ntp() { +testcase_ntp() { # timesyncd has ConditionVirtualization=!container by default; drop/mock that for testing if systemd-detect-virt --container --quiet; then systemctl disable --quiet --now systemd-timesyncd @@ -277,10 +279,7 @@ EOF : >/failed -test_timedatectl -test_timezone -test_adjtime -test_ntp +run_testcases touch /testok rm /failed diff --git a/test/units/testsuite-58.sh b/test/units/testsuite-58.sh index ecb376476a..b1b40851db 100755 --- a/test/units/testsuite-58.sh +++ b/test/units/testsuite-58.sh @@ -1,5 +1,6 @@ #!/usr/bin/env bash # SPDX-License-Identifier: LGPL-2.1-or-later +# shellcheck disable=SC2317 set -eux set -o pipefail @@ -11,6 +12,8 @@ if ! command -v systemd-repart &>/dev/null; then exit 0 fi +# shellcheck source=test/units/test-control.sh +. "$(dirname "$0")"/test-control.sh # shellcheck source=test/units/util.sh . "$(dirname "$0")"/util.sh @@ -88,7 +91,7 @@ else exit 1 fi -test_basic() { +testcase_basic() { local defs imgs output local loop volume @@ -338,7 +341,7 @@ $imgs/zzz7 : start= 6291416, size= 98304, type=0FC63DAF-8483-4772-8E79 umount "$imgs/mount" } -test_dropin() { +testcase_dropin() { local defs imgs output defs="$(runas testuser mktemp --directory "/tmp/test-repart.XXXXXXXXXX")" @@ -396,7 +399,7 @@ EOF EOF } -test_multiple_definitions() { +testcase_multiple_definitions() { local defs imgs output defs="$(runas testuser mktemp --directory "/tmp/test-repart.XXXXXXXXXX")" @@ -467,7 +470,7 @@ EOF EOF } -test_copy_blocks() { +testcase_copy_blocks() { local defs imgs output defs="$(runas testuser mktemp --directory "/tmp/test-repart.XXXXXXXXXX")" @@ -549,7 +552,7 @@ EOF cmp "$imgs/zzz" "$imgs/yyy" } -test_unaligned_partition() { +testcase_unaligned_partition() { local defs imgs output defs="$(runas testuser mktemp --directory "/tmp/test-repart.XXXXXXXXXX")" @@ -584,7 +587,7 @@ EOF assert_in "$imgs/unaligned3 : start= 3662944, size= 17308536, type=${root_guid}, uuid=${root_uuid}, name=\"root-${architecture}\", attrs=\"GUID:59\"" "$output" } -test_issue_21817() { +testcase_issue_21817() { local defs imgs output # testcase for #21817 @@ -620,7 +623,7 @@ EOF assert_in "$imgs/21817.img2 : start= 104448, size= (100319| 98304)," "$output" } -test_issue_24553() { +testcase_issue_24553() { local defs imgs output # testcase for #24553 @@ -720,7 +723,7 @@ EOF assert_in "$imgs/zzz3 : start= 21495848, size= 3669936, type=${usr_guid}, uuid=${usr_uuid}, name=\"usr-${architecture}\", attrs=\"GUID:59\"" "$output" } -test_zero_uuid() { +testcase_zero_uuid() { local defs imgs output defs="$(runas testuser mktemp --directory "/tmp/test-repart.XXXXXXXXXX")" @@ -748,7 +751,7 @@ EOF assert_in "$imgs/zero1 : start= 2048, size= 20480, type=${root_guid}, uuid=00000000-0000-0000-0000-000000000000" "$output" } -test_verity() { +testcase_verity() { local defs imgs output defs="$(runas testuser mktemp --directory "/tmp/test-repart.XXXXXXXXXX")" @@ -837,7 +840,7 @@ EOF systemd-dissect -U "$imgs/mnt" } -test_exclude_files() { +testcase_exclude_files() { local defs imgs root output defs="$(runas testuser mktemp --directory "/tmp/test-repart.XXXXXXXXXX")" @@ -922,7 +925,7 @@ EOF losetup -d "$loop" } -test_minimize() { +testcase_minimize() { local defs imgs output if systemd-detect-virt --quiet --container; then @@ -1035,17 +1038,7 @@ EOF assert_in "${loop}p3 : start= *${start}, size= *${size}, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=DB081670-07AE-48CA-9F5E-813D5E40B976, name=\"linux-generic-2\"" "$output" } -test_basic -test_dropin -test_multiple_definitions -test_copy_blocks -test_unaligned_partition -test_issue_21817 -test_issue_24553 -test_zero_uuid -test_verity -test_exclude_files -test_minimize +run_testcases # Valid block sizes on the Linux block layer are >= 512 and <= PAGE_SIZE, and # must be powers of 2. Which leaves exactly four different ones to test on diff --git a/test/units/testsuite-71.sh b/test/units/testsuite-71.sh index fca1819b74..1c884324cb 100755 --- a/test/units/testsuite-71.sh +++ b/test/units/testsuite-71.sh @@ -4,6 +4,8 @@ set -eux set -o pipefail +# shellcheck source=test/units/test-control.sh +. "$(dirname "$0")"/test-control.sh # shellcheck source=test/units/util.sh . "$(dirname "$0")"/util.sh @@ -15,7 +17,7 @@ restore_hostname() { fi } -test_hostname() { +testcase_hostname() { local orig= if [[ -f /etc/hostname ]]; then @@ -59,7 +61,7 @@ get_chassis() ( echo "$CHASSIS" ) -test_chassis() { +testcase_chassis() { local i if [[ -f /etc/machine-info ]]; then @@ -96,7 +98,7 @@ restore_sysfs_dmi() { systemctl stop systemd-hostnamed } -test_firmware_date() { +testcase_firmware_date() { # No DMI on s390x or ppc if [[ ! -d /sys/class/dmi/id ]]; then echo "/sys/class/dmi/id not found, skipping firmware date tests." @@ -131,9 +133,7 @@ EOF : >/failed -test_hostname -test_chassis -test_firmware_date +run_testcases touch /testok rm /failed diff --git a/test/units/testsuite-73.sh b/test/units/testsuite-73.sh index 523acd8d06..022a70862f 100755 --- a/test/units/testsuite-73.sh +++ b/test/units/testsuite-73.sh @@ -4,6 +4,8 @@ set -eux set -o pipefail +# shellcheck source=test/units/test-control.sh +. "$(dirname "$0")"/test-control.sh # shellcheck source=test/units/util.sh . "$(dirname "$0")"/util.sh @@ -688,18 +690,7 @@ testcase_locale_gen_leading_space() { export SYSTEMD_KBD_MODEL_MAP=/usr/lib/systemd/tests/testdata/test-keymap-util/kbd-model-map enable_debug - -# Create a list of all functions prefixed with testcase_ -mapfile -t TESTCASES < <(declare -F | awk '$3 ~ /^testcase_/ {print $3;}') - -if [[ "${#TESTCASES[@]}" -eq 0 ]]; then - echo >&2 "No test cases found, this is most likely an error" - exit 1 -fi - -for testcase in "${TESTCASES[@]}"; do - "$testcase" -done +run_testcases touch /testok rm /failed diff --git a/test/units/testsuite-74.machine-id-setup.sh b/test/units/testsuite-74.machine-id-setup.sh index a24f9d299e..c2b9db5178 100755 --- a/test/units/testsuite-74.machine-id-setup.sh +++ b/test/units/testsuite-74.machine-id-setup.sh @@ -4,6 +4,11 @@ set -eux set -o pipefail +# shellcheck source=test/units/test-control.sh +. "$(dirname "$0")"/test-control.sh +# shellcheck source=test/units/util.sh +. "$(dirname "$0")"/util.sh + root_mock() { local root="${1:?}" @@ -69,14 +74,4 @@ testcase_transient() { systemctl --state=failed --no-legend --no-pager >/failed test ! -s /failed -# Create a list of all functions prefixed with testcase_ -mapfile -t TESTCASES < <(declare -F | awk '$3 ~ /^testcase_/ {print $3;}') - -if [[ "${#TESTCASES[@]}" -eq 0 ]]; then - echo >&2 "No test cases found, this is most likely an error" - exit 1 -fi - -for testcase in "${TESTCASES[@]}"; do - "$testcase" -done +run_testcases