diff --git a/.github/workflows/eclair.yaml b/.github/workflows/eclair.yaml new file mode 100644 index 00000000000..016b715a750 --- /dev/null +++ b/.github/workflows/eclair.yaml @@ -0,0 +1,154 @@ +name: Eclair Code Scanning +on: + pull_request: + branches: + - main + push: + branches: + - main + - v*-branch + - collab-* +permissions: + contents: read +concurrency: + group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.head_ref || github.ref }} + cancel-in-progress: true + +jobs: + EclairScanCode: + if: github.repository_owner == 'zephyrproject-rtos' + runs-on: + group: zephyr-runner-v2-linux-x64-4xlarge + container: + image: ghcr.io/zephyrproject-rtos/ci-repo-cache:v0.28.0.20250523 + options: '--entrypoint /bin/bash' + permissions: + pull-requests: write # to create/update pull request comments + security-events: write + steps: + - name: Print cloud service information + run: | + echo "ZEPHYR_RUNNER_CLOUD_PROVIDER = ${ZEPHYR_RUNNER_CLOUD_PROVIDER}" + echo "ZEPHYR_RUNNER_CLOUD_NODE = ${ZEPHYR_RUNNER_CLOUD_NODE}" + echo "ZEPHYR_RUNNER_CLOUD_POD = ${ZEPHYR_RUNNER_CLOUD_POD}" + + - name: Apply container owner mismatch workaround + run: | + # FIXME: The owner UID of the GITHUB_WORKSPACE directory may not + # match the container user UID because of the way GitHub + # Actions runner is implemented. Remove this workaround when + # GitHub comes up with a fundamental fix for this problem. + git config --global --add safe.directory ${GITHUB_WORKSPACE} + + - name: Clone cached Zephyr repository + continue-on-error: true + run: | + git clone --shared /repo-cache/zephyrproject/zephyr . + git remote set-url origin ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY} + + - name: Checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + ref: ${{ github.event.pull_request.head.sha }} + fetch-depth: 0 + persist-credentials: false + + - name: Environment Setup + run: | + if [ "${{github.event_name}}" = "pull_request" ]; then + git config --global user.email "bot@zephyrproject.org" + git config --global user.name "Zephyr Builder" + rm -fr ".git/rebase-apply" + rm -fr ".git/rebase-merge" + git rebase origin/${BASE_REF} + git clean -f -d + git log --pretty=oneline | head -n 10 + fi + echo "$HOME/.local/bin" >> $GITHUB_PATH + echo "$HOME/.cargo/bin" >> $GITHUB_PATH + + west init -l . || true + west config manifest.group-filter -- +ci,+optional + west config --global update.narrow true + west update --path-cache /repo-cache/zephyrproject 2>&1 1> west.update.log || west update --path-cache /repo-cache/zephyrproject 2>&1 1> west.update.log || ( rm -rf ../modules ../bootloader ../tools && west update --path-cache /repo-cache/zephyrproject) + west forall -c 'git reset --hard HEAD' + + echo "ZEPHYR_SDK_INSTALL_DIR=/opt/toolchains/zephyr-sdk-$( cat SDK_VERSION )" >> $GITHUB_ENV + + - name: Check Environment + run: | + cmake --version + gcc --version + cargo --version + rustup target list --installed + ls -la + echo "github.ref: ${{ github.ref }}" + echo "github.base_ref: ${{ github.base_ref }}" + echo "github.ref_name: ${{ github.ref_name }}" + + - name: SCA Setup + uses: zephyrproject-rtos/action-sca-setup@main + with: + tool-name: eclair + install-dir: eclair + s3-access-key-id: ${{ secrets.TOOLDIST_ACCESS_KEY }} + s3-secret-access-key: ${{ secrets.TOOLDIST_SECRET_ACCESS_KEY }} + license-server: ${{ secrets.TOOLDIST_ECLAIR_LICENSE_SERVER }} + license-key-ttl: 480 + + - name: Set Up Python 3.12 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 + with: + python-version: 3.12 + cache: pip + cache-dependency-path: scripts/requirements-actions.txt + + - name: install-packages + run: | + pip install -r scripts/requirements-actions.txt --require-hashes + sudo apt-get update + sudo apt-get install -y jq + + - name: Scan code with Eclair + run: | + ./scripts/twister -j 16 -p qemu_x86 -T samples/synchronization -i --build-only -v -xZEPHYR_SCA_VARIANT=eclair -x=USE_CCACHE=0 -xECLAIR_REPORTS_SARIF=1 + jq -s '{ "$schema": "https://json.schemastore.org/sarif-2.1.0", "version": "2.1.0", "runs": map(.runs) | add }' $(find twister-out -name "reports.sarif") > results.sarif + jq --arg basepath "file://${GITHUB_WORKSPACE}/" ' + .runs[].results[] |= ( + # Remove partialFingerprints if it exists + del(.partialFingerprints) + | + .locations[]? |= ( + .physicalLocation.artifactLocation.uri + |= if type == "string" then ($basepath + .) else . end + ) + | .relatedLocations[]? |= ( + .physicalLocation.artifactLocation.uri + |= if type == "string" then ($basepath + .) else . end + ) + ) + ' results.sarif > results_tmp.sarif + mv results_tmp.sarif results.sarif + + ver=`git describe` + echo "PAYLOAD_VERSION=${ver}" >> $GITHUB_ENV + echo "PAYLOAD_DESC=${ver}" >> $GITHUB_ENV + - name: Clean up + if: always() + run: | + eclair_licman -c 57350 + + - name: Upload SARIF as artifact + if: always() && github.event_name == 'push' + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: sarif + if-no-files-found: ignore + path: | + results.sarif + + - name: Upload Analysis Results + if: always() + uses: github/codeql-action/upload-sarif@v3 + with: + sarif_file: results.sarif diff --git a/cmake/sca/eclair/ECL/analysis_first_analysis.ecl b/cmake/sca/eclair/ECL/analysis_first_analysis.ecl index c8dba497206..20809bf10c0 100644 --- a/cmake/sca/eclair/ECL/analysis_first_analysis.ecl +++ b/cmake/sca/eclair/ECL/analysis_first_analysis.ecl @@ -12,10 +12,82 @@ https://docs.zephyrproject.org/latest/contribute/coding_guidelines/index.html" -enable=MC3R1.R8.2 -enable=MC3R1.R10.2 +-enable=MC3R1.R10.4 -enable=MC3R1.R10.5 -enable=MC3R1.R10.6 -enable=MC3R1.R11.2 -enable=MC3R1.R12.4 -enable=MC3R1.R13.4 +-enable=MC3R1.R16.2 +-enable=MC3R1.R16.3 +-enable=MC3R1.R16.4 +-enable=MC3R1.R16.5 +-enable=MC3R1.R16.6 +-enable=MC3R1.R16.7 +-enable=MC3R1.D4.9 +-enable=MC3R1.R7.1 +-enable=MC3R1.R13.5 +-enable=MC3R1.R10.8 +-enable=MC3R1.R3.1 +-enable=MC3R1.R10.4 +-enable=MC3R1.R11.9 +-enable=MC3R1.R11.6 +-enable=MC3R1.R11.8 +-enable=MC3R1.R14.4 +-enable=MC3R1.R13.2 +-enable=MC3R1.R8.4 +-enable=MC3R1.R2.7 +-enable=MC3R1.R12.2 +-enable=MC3R1.R10.6 +-enable=MC3R1.R17.7 +-enable=MC3R1.R18.2 +-enable=MC3R1.D4.13 +-enable=MC3R1.D4.5 +-enable=MC3R1.R17.1 +-enable=MC3R1.R9.1 +-enable=MC3R1.R5.4 -enable=MC3R1.R16.1 +-enable=MC3R1.R16.3 +-enable=MC3R1.R21.6 +-enable=MC3R1.D4.2 +-enable=MC3R1.R21.18 +-enable=MC3R1.D4.1 +-enable=MC3R1.R6.1 +-enable=MC3R1.R13.3 +-enable=MC3R1.R8.2 +-enable=MC3R1.R15.7 +-enable=MC3R1.R20.9 +-enable=MC3R1.R18.3 +-enable=MC3R1.R19.1 +-enable=MC3R1.R8.9 +-enable=MC3R1.R21.2 +-enable=MC3R1.D4.10 +-enable=MC3R1.R2.2 +-enable=MC3R1.R12.4 +-enable=MC3R1.D4.7 +-enable=MC3R1.R1.3 +-enable=MC3R1.R8.14 +-enable=MC3R1.R21.15 +-enable=MC3R1.R13.4 +-enable=MC3R1.R18.6 +-enable=MC3R1.D4.12 +-enable=MC3R1.R15.3 +-enable=MC3R1.R21.3 +-enable=MC3R1.R22.5 +-enable=MC3R1.D4.4 +-enable=MC3R1.R5.5 +-enable=MC3R1.R10.5 +-enable=MC3R1.R10.7 +-enable=MC3R1.R13.1 +-enable=MC3R1.R5.3 +-enable=MC3R1.R18.8 +-enable=MC3R1.R7.2 +-enable=MC3R1.R7.4 +-enable=MC3R1.R8.12 +-enable=MC3R1.R9.3 +-enable=MC3R1.R10.2 +-enable=MC3R1.R18.1 +-enable=MC3R1.R18.5 +-enable=MC3R1.R21.16 + -doc_end diff --git a/cmake/sca/eclair/ECL/deviations.ecl b/cmake/sca/eclair/ECL/deviations.ecl new file mode 100644 index 00000000000..c93304fb1d5 --- /dev/null +++ b/cmake/sca/eclair/ECL/deviations.ecl @@ -0,0 +1,476 @@ +# +# Series 2. +# + +-doc_begin="The compiler implementation guarantees that the unreachable code is removed. +Constant expressions and unreachable branches of if and switch statements are expected." +-config=MC3A2.R2.1,+reports={safe,"first_area(^.*has an invariantly.*$)"} +-config=MC3A2.R2.1,+reports={safe,"first_area(^.*incompatible with labeled statement$)"} +-doc_end + +-doc_begin="Unreachability caused by calls to the following functions or macros is deliberate and there is no risk of code being unexpectedly left out." +-config=MC3A2.R2.1,statements+={deliberate,"macro(name(BUG||assert_failed))"} +-config=MC3A2.R2.1,statements+={deliberate, "call(decl(name(__builtin_unreachable||panic||do_unexpected_trap||machine_halt||machine_restart||reboot_or_halt)))"} +-doc_end + +-doc_begin="Unreachability inside an ASSERT_UNREACHABLE() and analogous macro calls is deliberate and safe." +-config=MC3A2.R2.1,reports+={deliberate, "any_area(any_loc(any_exp(macro(name(ASSERT_UNREACHABLE||PARSE_ERR_RET||PARSE_ERR||FAIL_MSR||FAIL_CPUID)))))"} +-doc_end + +-doc_begin="Pure declarations (i.e., declarations without initialization) are +not executable, and therefore it is safe for them to be unreachable." +-config=MC3A2.R2.1,ignored_stmts+={"any()", "pure_decl()"} +-doc_end + +-doc_begin="The following autogenerated file is not linked deliberately." +-file_tag+={C_runtime_failures,"^automation/eclair_analysis/C-runtime-failures\\.rst\\.c$"} +-config=MC3A2.R2.1,reports+={deliberate, "any_area(any_loc(file(C_runtime_failures)))"} +-doc_end + +-doc_begin="Proving compliance with respect to Rule 2.2 is generally impossible: +see https://arxiv.org/abs/2212.13933 for details. Moreover, peer review gives us +confidence that no evidence of errors in the program's logic has been missed due +to undetected violations of Rule 2.2, if any. Testing on time behavior gives us +confidence on the fact that, should the program contain dead code that is not +removed by the compiler, the resulting slowdown is negligible." +-config=MC3A2.R2.2,reports+={disapplied,"any()"} +-doc_end + +-doc_begin="Some labels are unused in certain build configurations, or are deliberately marked as unused, so that the compiler is entitled to remove them." +-config=MC3A2.R2.6,reports+={deliberate, "any_area(text(^.*__maybe_unused.*$))"} +-doc_end + +# +# Series 3. +# + +-doc_begin="Comments starting with '/*' and containing hyperlinks are safe as +they are not instances of commented-out code." +-config=MC3A2.R3.1,reports+={safe, "first_area(text(^.*https?://.*$))"} +-doc_end + +# +# Series 4. +# + +-doc_begin="Files that are intended to be included more than once do not need to +conform to the directive." +-config=MC3A2.D4.10,reports+={safe, "first_area(text(^/\\* This file is intended to be included multiple times\\. \\*/$, begin-4))"} +-config=MC3A2.D4.10,reports+={safe, "first_area(text(^/\\* Generated file, do not edit! \\*/$, begin-3))"} +-config=MC3A2.D4.10,reports+={safe, "all_area(all_loc(file(^zephyr/build/zephyr/include/generated/autoconf\\.h$)))"} +-doc_end + +-doc_begin="Including multiple times a .c file is safe because every function or data item +it defines would (in the common case) be already defined. Peer reviewed by the community." +-config=MC3A2.D4.10,reports+={safe, "all_area(all_loc(^.*\\.c$))"} +-doc_end + +# +# Series 5. +# + +-doc_begin="The project adopted the rule with an exception listed in +'docs/misra/rules.rst'" +-config=MC3A2.R5.3,reports+={safe, "any_area(any_loc(any_exp(macro(^READ_SYSREG$))&&any_exp(macro(^WRITE_SYSREG$))))"} +-config=MC3A2.R5.3,reports+={safe, "any_area(any_loc(any_exp(macro(^max(_t)?$))&&any_exp(macro(^min(_t)?$))))"} +-config=MC3A2.R5.3,reports+={safe, "any_area(any_loc(any_exp(macro(^read[bwlq]$))&&any_exp(macro(^read[bwlq]_relaxed$))))"} +-config=MC3A2.R5.3,reports+={safe, "any_area(any_loc(any_exp(macro(^per_cpu$))&&any_exp(macro(^this_cpu$))))"} +-config=MC3A2.R5.3,reports+={safe, "any_area(any_loc(any_exp(macro(^__emulate_2op$))&&any_exp(macro(^__emulate_2op_nobyte$))))"} +-config=MC3A2.R5.3,reports+={safe, "any_area(any_loc(any_exp(macro(^read_debugreg$))&&any_exp(macro(^write_debugreg$))))"} +-doc_end + +-doc_begin="Macros expanding to their own identifier (e.g., \"#define x x\") are deliberate." +-config=MC3A2.R5.5,reports+={deliberate, "all_area(macro(same_id_body())||!macro(!same_id_body()))"} +-doc_end + +-doc_begin="There is no clash between function like macros and not callable objects." +-config=MC3A2.R5.5,reports+={deliberate, "all_area(macro(function_like())||decl(any()))&&all_area(macro(any())||!decl(kind(function))&&!decl(__function_pointer_decls))"} +-doc_end + +-doc_begin="Clashes between function names and macros are deliberate for string handling functions since some architectures may want to use their own arch-specific implementation." +-config=MC3A2.R5.5,reports+={deliberate, "all_area(all_loc(file(^xen/arch/x86/string\\.c|xen/include/xen/string\\.h|xen/lib/.*$)))"} +-doc_end + +-doc_begin="In libelf, clashes between macros and function names are deliberate and needed to prevent the use of undecorated versions of memcpy, memset and memmove." +-config=MC3A2.R5.5,reports+={deliberate, "any_area(decl(kind(function))||any_loc(macro(name(memcpy||memset||memmove))))&&any_area(any_loc(file(^xen/common/libelf/libelf-private\\.h$)))"} +-doc_end + +-doc_begin="The project intentionally reuses tag names in order to have identifiers matching the applicable external specifications as well as established internal conventions. +As there is little possibility for developer confusion not resulting into compilation errors, the risk of renaming outweighs the potential advantages of compliance." +-config=MC3A2.R5.7,reports+={deliberate,"any()"} +-doc_end + +# +# Series 7. +# + +-doc_begin="It is safe to use certain octal constants the way they are defined +in specifications, manuals, and algorithm descriptions." +-config=MC3A2.R7.1,reports+={safe, "any_area(any_loc(any_exp(text(^.*octal-ok.*$))))"} +-doc_end + + +-doc_begin="Violations caused by __HYPERVISOR_VIRT_START are related to the +particular use of it done in xen_mk_ulong." +-config=MC3A2.R7.2,reports+={deliberate,"any_area(any_loc(macro(name(BUILD_BUG_ON))))"} +-doc_end + +-doc_begin="Allow pointers of non-character type as long as the pointee is +const-qualified." +-config=MC3A2.R7.4,same_pointee=false +-doc_end + +# +# Series 8. +# + +-doc_begin="Parameter name \"unused\" (with an optional numeric suffix) is deliberate and makes explicit the intention of not using such parameter within the function." +-config=MC3A2.R8.3,reports+={deliberate, "any_area(^.*parameter `unused[0-9]*'.*$)"} +-doc_end + +-doc_begin="asmlinkage is a marker to indicate that the function is only used to interface with asm modules." +-config=MC3A2.R8.4,declarations+={safe,"loc(text(^(?s).*asmlinkage.*$, -1..0))"} +-doc_end + +-doc_begin="Declarations without definitions are allowed (specifically when the +definition is compiled-out or optimized-out by the compiler)" +-config=MC3A2.R8.6,reports+={deliberate, "first_area(^.*has no definition$)"} +-doc_end + +# +# Series 9. +# + +-doc_begin="The possibility of committing mistakes by specifying an explicit +dimension is higher than omitting the dimension." +-config=MC3A2.R9.5,reports+={deliberate, "any()"} +-doc_end + +# +# Series 10. +# + +-doc_begin="The value-preserving conversions of integer constants are safe" +-config=MC3A2.R10.1,etypes={safe,"any()","preserved_integer_constant()"} +-config=MC3A2.R10.3,etypes={safe,"any()","preserved_integer_constant()"} +-config=MC3A2.R10.4,etypes={safe,"any()","preserved_integer_constant()||sibling(rhs,preserved_integer_constant())"} +-doc_end + +-doc_begin="Shifting non-negative integers to the right is safe." +-config=MC3A2.R10.1,etypes+={safe, + "stmt(node(binary_operator)&&operator(shr))", + "src_expr(definitely_in(0..))"} +-doc_end + +-doc_begin="Shifting non-negative integers to the left is safe if the result is +still non-negative." +-config=MC3A2.R10.1,etypes+={safe, + "stmt(node(binary_operator)&&operator(shl)&&definitely_in(0..))", + "src_expr(definitely_in(0..))"} +-doc_end + +-doc_begin="Bitwise logical operations on non-negative integers are safe." +-config=MC3A2.R10.1,etypes+={safe, + "stmt(node(binary_operator)&&operator(and||or||xor))", + "src_expr(definitely_in(0..))"} +-doc_end + +-doc_begin="The implicit conversion to Boolean for logical operator arguments is well known to all Xen developers to be a comparison with 0" +-config=MC3A2.R10.1,etypes+={safe, "stmt(operator(logical)||node(conditional_operator||binary_conditional_operator))", "dst_type(ebool||boolean)"} +-doc_end + +-doc_begin="Zephyr only supports architectures where signed integers are +representend using two's complement and all the Xephyr developers are aware of +this." +-config=MC3A2.R10.1,etypes+={safe, + "stmt(operator(and||or||xor||not||and_assign||or_assign||xor_assign))", + "any()"} +-doc_end + +-doc_begin="See Section \"4.5 Integers\" of \"GCC_MANUAL\", where it says that +\"Signed `>>' acts on negative numbers by sign extension. As an extension to the +C language, GCC does not use the latitude given in C99 and C11 only to treat +certain aspects of signed `<<' as undefined. However, -fsanitize=shift (and +-fsanitize=undefined) will diagnose such cases. They are also diagnosed where +constant expressions are required.\"" +-config=MC3A2.R10.1,etypes+={safe, + "stmt(operator(shl||shr||shl_assign||shr_assign))", + "any()"} +-doc_end + +# +# Series 11 +# + +-doc_begin="The conversion from a function pointer to unsigned long or (void *) does not lose any information, provided that the target type has enough bits to store it." +-config=MC3A2.R11.1,casts+={safe, + "from(type(canonical(__function_pointer_types))) + &&to(type(canonical(builtin(unsigned long)||pointer(builtin(void))))) + &&relation(definitely_preserves_value)" +} +-doc_end + +-doc_begin="The conversion from a function pointer to a boolean has a well-known semantics that do not lead to unexpected behaviour." +-config=MC3A2.R11.1,casts+={safe, + "from(type(canonical(__function_pointer_types))) + &&kind(pointer_to_boolean)" +} +-doc_end + +-doc_begin="The conversion from a pointer to an incomplete type to unsigned long does not lose any information, provided that the target type has enough bits to store it." +-config=MC3A2.R11.2,casts+={safe, + "from(type(any())) + &&to(type(canonical(builtin(unsigned long)))) + &&relation(definitely_preserves_value)" +} +-doc_end + +-doc_begin="Conversions to object pointers that have a pointee type with a smaller (i.e., less strict) alignment requirement are safe." +-config=MC3A2.R11.3,casts+={safe, + "!relation(more_aligned_pointee)" +} +-doc_end + +-doc_begin="Conversions from and to integral types are safe, in the assumption that the target type has enough bits to store the value. +See also Section \"4.7 Arrays and Pointers\" of \"GCC_MANUAL\"" +-config=MC3A2.R11.6,casts+={safe, + "(from(type(canonical(integral())))||to(type(canonical(integral())))) + &&relation(definitely_preserves_value)"} +-doc_end + +-doc_begin="The conversion from a pointer to a boolean has a well-known semantics that do not lead to unexpected behaviour." +-config=MC3A2.R11.6,casts+={safe, + "from(type(canonical(__pointer_types))) + &&kind(pointer_to_boolean)" +} +-doc_end + +-doc_begin="Violations caused by container_of are due to pointer arithmetic operations +with the provided offset. The resulting pointer is then immediately cast back to its +original type, which preserves the qualifier. This use is deemed safe. +Fixing this violation would require to increase code complexity and lower readability." +-config=MC3A2.R11.8,reports+={safe,"any_area(any_loc(any_exp(macro(^container_of$))))"} +-doc_end + +-doc_begin="This construct is used to check if the type is scalar, and for this purpose the use of 0 as a null pointer constant is deliberate." +-config=MC3A2.R11.9,reports+={deliberate, "any_area(any_loc(any_exp(macro(^__ACCESS_ONCE$))))" +} +-doc_end + +# +# Series 13 +# + +-doc_begin="All developers and reviewers can be safely assumed to be well aware +of the short-circuit evaluation strategy of such logical operators." +-config=MC3A2.R13.5,reports+={disapplied,"any()"} +-doc_end + +-doc_begin="Anything, no matter how complicated, inside the BUILD_ASSERT macro is subject to a compile-time evaluation without relevant side effects." +-config=MC3A2.R13.6,reports+={safe,"any_area(any_loc(any_exp(macro(name(BUILD_ASSERT)))))"} +-config=B.UNEVALEFF,reports+={safe,"any_area(any_loc(any_exp(macro(name(BUILD_ASSERT)))))"} +-doc_end + +# +# Series 14 +# + +-doc_begin="The severe restrictions imposed by this rule on the use of for +statements are not balanced by the presumed facilitation of the peer review +activity." +-config=MC3A2.R14.2,reports+={disapplied,"any()"} +-doc_end + +-doc_begin="The Zephyr team relies on the fact that invariant conditions of 'if' statements and conditional operators are deliberate" +-config=MC3A2.R14.3,statements+={deliberate, "wrapped(any(),node(if_stmt||conditional_operator||binary_conditional_operator))" } +-doc_end + +-doc_begin="Switches having a 'sizeof' operator as the condition are deliberate and have limited scope." +-config=MC3A2.R14.3,statements+={deliberate, "wrapped(any(),node(switch_stmt)&&child(cond, operator(sizeof)))" } +-doc_end + +-doc_begin="A controlling expression of 'if' and iteration statements having integer, character or pointer type has a semantics that is well-known to all Zephyr developers." +-config=MC3A2.R14.4,etypes+={deliberate, "any()", "src_type(integer||character)||src_expr(type(desugar(pointer(any()))))"} +-doc_end + +-doc_begin="The Zephyr team relies on the fact that the enum is_dying has the +constant with assigned value 0 act as false and the other ones as true, +therefore have the same behavior of a boolean" +-config=MC3A2.R14.4,etypes+={deliberate, "stmt(child(cond,child(expr,ref(^?::is_dying$))))","src_type(enum)"} +-doc_end + +# +# Series 16. +# + +-doc_begin="Statements that change the control flow (i.e., break, continue, goto, return) and calls to functions that do not return the control back are \"allowed terminal statements\"." +-stmt_selector+={r16_3_allowed_terminal, "node(break_stmt||continue_stmt||goto_stmt||return_stmt)||call(property(noreturn))"} +-config=MC3A2.R16.3,terminals+={safe, "r16_3_allowed_terminal"} +-doc_end + +-doc_begin="An if-else statement having both branches ending with an allowed terminal statement is itself an allowed terminal statement." +-stmt_selector+={r16_3_if, "node(if_stmt)&&(child(then,r16_3_allowed_terminal)||child(then,any_stmt(stmt,-1,r16_3_allowed_terminal)))"} +-stmt_selector+={r16_3_else, "node(if_stmt)&&(child(else,r16_3_allowed_terminal)||child(else,any_stmt(stmt,-1,r16_3_allowed_terminal)))"} +-stmt_selector+={r16_3_if_else, "r16_3_if&&r16_3_else"} +-config=MC3A2.R16.3,terminals+={safe, "r16_3_if_else"} +-doc_end + +-doc_begin="An if-else statement having an always true condition and the true branch ending with an allowed terminal statement is itself an allowed terminal statement." +-stmt_selector+={r16_3_if_true, "r16_3_if&&child(cond,definitely_in(1..))"} +-config=MC3A2.R16.3,terminals+={safe, "r16_3_if_true"} +-doc_end + +-doc_begin="A switch clause ending with a statement expression which, in turn, ends with an allowed terminal statement is safe." +-config=MC3A2.R16.3,terminals+={safe, "node(stmt_expr)&&child(stmt,node(compound_stmt)&&any_stmt(stmt,-1,r16_3_allowed_terminal||r16_3_if_else||r16_3_if_true))"} +-doc_end + +-doc_begin="A switch clause ending with a do-while-false the body of which, in turn, ends with an allowed terminal statement is safe. +An exception to that is the macro ASSERT_UNREACHABLE() which is effective in debug build only: a switch clause ending with ASSERT_UNREACHABLE() is not considered safe." +-config=MC3A2.R16.3,terminals+={safe, "!macro(name(ASSERT_UNREACHABLE))&&node(do_stmt)&&child(cond,definitely_in(0))&&child(body,any_stmt(stmt,-1,r16_3_allowed_terminal||r16_3_if_else||r16_3_if_true))"} +-doc_end + +-doc_begin="Switch clauses ending with pseudo-keyword \"fallthrough\" are +safe." +-config=MC3A2.R16.3,reports+={safe, "any_area(end_loc(any_exp(text(/fallthrough;/))))"} +-doc_end + +-doc_begin="Switch clauses ending with failure method \"BUG()\" are safe." +-config=MC3A2.R16.3,reports+={safe, "any_area(end_loc(any_exp(text(/BUG\\(\\);/))))"} +-doc_end + +-doc_begin="Switch clauses ending with an explicit comment indicating the fallthrough intention are safe." +-config=MC3A2.R16.3,reports+={safe, "any_area(end_loc(any_exp(text(^(?s).*/\\* [fF]all ?through\\.? \\*/.*$,0..2))))"} +-doc_end + +-doc_begin="Switch statements having a controlling expression of enum type deliberately do not have a default case: gcc -Wall enables -Wswitch which warns (and breaks the build as we use -Werror) if one of the enum labels is missing from the switch." +-config=MC3A2.R16.4,reports+={deliberate,'any_area(kind(context)&&^.* has no `default.*$&&stmt(node(switch_stmt)&&child(cond,skip(__non_syntactic_paren_stmts,type(canonical(enum_underlying_type(any())))))))'} +-doc_end + +-doc_begin="A switch statement with a single switch clause and no default label may be used in place of an equivalent if statement if it is considered to improve readability." +-config=MC3A2.R16.4,switch_clauses+={deliberate,"switch(1)&&default(0)"} +-doc_end + +-doc_begin="A switch statement with a single switch clause and no default label may be used in place of an equivalent if statement if it is considered to improve readability." +-config=MC3A2.R16.6,switch_clauses+={deliberate, "default(0)"} +-doc_end + +# +# Series 17. +# + +-doc_begin="printf()-like functions are allowed to use the variadic features provided by stdarg.h." +-config=MC3A2.R17.1,reports+={deliberate,"any_area(^.*va_list.*$&&context(ancestor_or_self(^.*printk\\(.*\\)$)))"} +-config=MC3A2.R17.1,reports+={deliberate,"any_area(^.*va_list.*$&&context(ancestor_or_self(^.*printf\\(.*\\)$)))"} +-config=MC3A2.R17.1,reports+={deliberate,"any_area(^.*va_list.*$&&context(ancestor_or_self(name(panic)&&kind(function))))"} +-config=MC3A2.R17.1,reports+={deliberate,"any_area(^.*va_list.*$&&context(ancestor_or_self(name(elf_call_log_callback)&&kind(function))))"} +-config=MC3A2.R17.1,reports+={deliberate,"any_area(^.*va_list.*$&&context(ancestor_or_self(name(vprintk_common)&&kind(function))))"} +-config=MC3A2.R17.1,macros+={hide , "^va_(arg|start|copy|end)$"} +-doc_end + +-doc_begin="Not using the return value of a function does not endanger safety if it coincides with an actual argument." +-config=MC3A2.R17.7,calls+={safe, "any()", "decl(name(__builtin_memcpy||__builtin_memmove||__builtin_memset||cpumask_check))"} +-doc_end + +# +# Series 18. +# + + +-doc_begin="The following macro performs a subtraction between pointers to obtain the mfn, but does not lead to undefined behaviour." +-config=MC3A2.R18.2,reports+={safe, "any_area(any_loc(any_exp(macro(^page_to_mfn$))))"} +-doc_end + +-doc_begin="Flexible array members are deliberately used and Zephyr developers are aware of the dangers related to them: +unexpected result when the structure is given as argument to a sizeof() operator and the truncation in assignment between structures." +-config=MC3A2.R18.7,reports+={deliberate, "any()"} +-doc_end + +# +# Series 20. +# + +-doc_begin="Code violating Rule 20.7 is safe when macro parameters are used: (1) +as function arguments; (2) as macro arguments; (3) as array indices; (4) as lhs +in assignments; (5) as initializers, possibly designated, in initalizer lists; +(6) as the constant expression in a switch clause label." +-config=MC3A2.R20.7,expansion_context= +{safe, "context(__call_expr_arg_contexts)"}, +{safe, "left_right(^[(,\\[]$,^[),\\]]$)"}, +{safe, "context(skip_to(__expr_non_syntactic_contexts, stmt_child(node(array_subscript_expr), subscript)))"}, +{safe, "context(skip_to(__expr_non_syntactic_contexts, stmt_child(operator(assign), lhs)))"}, +{safe, "context(skip_to(__expr_non_syntactic_contexts, stmt_child(node(init_list_expr||designated_init_expr), init)))"}, +{safe, "context(skip_to(__expr_non_syntactic_contexts, stmt_child(node(case_stmt), lower||upper)))"} +-doc_end + +-doc_begin="Violations involving the Z_IS_ENABLED3 macros cannot be fixed without +breaking the macro's logic; futhermore, the macro is only ever used in the context +of the IS_ENABLED or STATIC_IF/STATIC_IF_NOT macros, so it always receives a literal +0 or 1 as input, posing no risk to safety." +-config=MC3A2.R20.7,reports+={safe, "any_area(any_loc(any_exp(macro(^Z_IS_ENABLED3$))))"} +-doc_end + +-doc_begin="To avoid compromising readability, the macros alternative_(v)?call[0-9] are allowed +not to parenthesize their arguments." +-config=MC3A2.R20.7,reports+={safe, "any_area(any_loc(any_exp(macro(^alternative_(v)?call[0-9]$))))"} +-doc_end + +-doc_begin="The argument 'x' of the count_args_ macro can't be parenthesized as +the rule would require, without breaking the functionality of the macro. The uses +of this macro do not lead to developer confusion, and can thus be deviated." +-config=MC3A2.R20.7,reports+={safe, "any_area(any_loc(any_exp(macro(^count_args_$))))"} +-doc_end + +-doc_begin="The argument \"fn\" in macros {COMPILE,RUNTIME}_CHECK is not parenthesized +on purpose, to be able to test function-like macros. Given the specialized and limited +use of this macro, it is deemed ok to deviate them." +-config=MC3A2.R20.7,reports+={deliberate, "any_area(any_loc(any_exp(macro(^(COMPILE_CHECK|RUNTIME_CHECK)$))))"} +-doc_end + +-doc_begin="Problems related to operator precedence can not occur if the expansion of the macro argument is surrounded by tokens '{', '}' and ';'." +-config=MC3A2.R20.7,expansion_context+={safe, "left_right(^[\\{;]$,^[;\\}]$)"} +-doc_end + +-doc_begin="Uses of variadic macros that have one of their arguments defined as +a macro and used within the body for both ordinary parameter expansion and as an +operand to the # or ## operators have a behavior that is well-understood and +deliberate." +-config=MC3A2.R20.12,macros+={deliberate, "variadic()"} +-doc_end + +-doc_begin="Uses of a macro parameter for ordinary expansion and as an operand +to the # or ## operators within the following macros are deliberate, to provide +useful diagnostic messages to the user." +-config=MC3A2.R20.12,macros+={deliberate, "name(ASSERT||BUILD_BUG_ON||BUILD_BUG_ON_ZERO||RUNTIME_CHECK)"} +-doc_end + +# +# Series 21. +# + + +# +# General +# + +-doc_begin="do-while-[01] is a well recognized loop idiom by the xen community." +-loop_idioms={do_stmt, "literal(0)||literal(1)"} +-doc_end +-doc_begin="while-[01] is a well recognized loop idiom by the xen community." +-loop_idioms+={while_stmt, "literal(0)||literal(1)"} +-doc_end + +# +# Developer confusion +# + +-doc="Selection for reports that are fully contained in adopted code." +-report_selector+={adopted_report,"all_area(!kind(culprit||evidence)||all_loc(all_exp(adopted||pseudo)))"} + +-doc_begin="Adopted code is not meant to be read, reviewed or modified by human +programmers:no developers' confusion is not possible. In addition, adopted code +is assumed to work as is. Reports that are fully contained in adopted code are +hidden/tagged with the 'adopted' tag." +-service_selector={developer_confusion_guidelines,"^(MC3A2\\.R2\\.1|MC3A2\\.R2\\.2|MC3A2\\.R2\\.3|MC3A2\\.R2\\.4|MC3A2\\.R2\\.5|MC3A2\\.R2\\.6|MC3A2\\.R2\\.7|MC3A2\\.R4\\.1|MC3A2\\.R5\\.3|MC3A2\\.R5\\.6|MC3A2\\.R5\\.7|MC3A2\\.R5\\.8|MC3A2\\.R5\\.9|MC3A2\\.R7\\.1|MC3A2\\.R7\\.2|MC3A2\\.R7\\.3|MC3A2\\.R8\\.7|MC3A2\\.R8\\.8|MC3A2\\.R8\\.9|MC3A2\\.R8\\.11|MC3A2\\.R8\\.12|MC3A2\\.R8\\.13|MC3A2\\.R9\\.3|MC3A2\\.R9\\.4|MC3A2\\.R9\\.5|MC3A2\\.R10\\.2|MC3A2\\.R10\\.5|MC3A2\\.R10\\.6|MC3A2\\.R10\\.7|MC3A2\\.R10\\.8|MC3A2\\.R11\\.9|MC3A2\\.R12\\.1|MC3A2\\.R12\\.3|MC3A2\\.R12\\.4|MC3A2\\.R13\\.5|MC3A2\\.R14\\.1|MC3A2\\.R14\\.2|MC3A2\\.R14\\.3|MC3A2\\.R15\\.1|MC3A2\\.R15\\.2|MC3A2\\.R15\\.3|MC3A2\\.R15\\.4|MC3A2\\.R15\\.5|MC3A2\\.R15\\.6|MC3A2\\.R15\\.7|MC3A2\\.R16\\.1|MC3A2\\.R16\\.2|MC3A2\\.R16\\.3|MC3A2\\.R16\\.4|MC3A2\\.R16\\.5|MC3A2\\.R16\\.6|MC3A2\\.R16\\.7|MC3A2\\.R17\\.7|MC3A2\\.R17\\.8|MC3A2\\.R18\\.4|MC3A2\\.R18\\.5)$" +} +-config=developer_confusion_guidelines,reports+={relied,adopted_report} +-doc_end diff --git a/cmake/sca/eclair/ECL/zephyr_common_config.ecl b/cmake/sca/eclair/ECL/zephyr_common_config.ecl index 38168274cdf..05d69bef1d4 100644 --- a/cmake/sca/eclair/ECL/zephyr_common_config.ecl +++ b/cmake/sca/eclair/ECL/zephyr_common_config.ecl @@ -101,6 +101,7 @@ -eval_file=adopted_code.ecl -eval_file=adopted_deviations.ecl +-eval_file=deviations.ecl -doc="Hide reports marked as compliant." -remap_rtag={compliant,hide} diff --git a/include/zephyr/sys/atomic.h b/include/zephyr/sys/atomic.h index 078be968467..b58a96cf6f3 100644 --- a/include/zephyr/sys/atomic.h +++ b/include/zephyr/sys/atomic.h @@ -237,6 +237,7 @@ static inline void atomic_set_bit_to(atomic_t *target, int bit, bool val) } /** + * @def atomic_cas * @brief Atomic compare-and-set. * * This routine performs an atomic compare-and-set on @a target. If the current @@ -251,9 +252,9 @@ static inline void atomic_set_bit_to(atomic_t *target, int bit, bool val) * @param new_value New value to store. * @return true if @a new_value is written, false otherwise. */ -bool atomic_cas(atomic_t *target, atomic_val_t old_value, atomic_val_t new_value); /** + * @def atomic_ptr_cas * @brief Atomic compare-and-set with pointer values * * This routine performs an atomic compare-and-set on @a target. If the current @@ -268,10 +269,10 @@ bool atomic_cas(atomic_t *target, atomic_val_t old_value, atomic_val_t new_value * @param new_value New value to store. * @return true if @a new_value is written, false otherwise. */ -bool atomic_ptr_cas(atomic_ptr_t *target, atomic_ptr_val_t old_value, - atomic_ptr_val_t new_value); + /** + * @def atomic_add * @brief Atomic addition. * * This routine performs an atomic addition on @a target. @@ -283,9 +284,8 @@ bool atomic_ptr_cas(atomic_ptr_t *target, atomic_ptr_val_t old_value, * * @return Previous value of @a target. */ -atomic_val_t atomic_add(atomic_t *target, atomic_val_t value); -/** +/** @def atomic_sub * @brief Atomic subtraction. * * This routine performs an atomic subtraction on @a target. @@ -297,9 +297,9 @@ atomic_val_t atomic_add(atomic_t *target, atomic_val_t value); * * @return Previous value of @a target. */ -atomic_val_t atomic_sub(atomic_t *target, atomic_val_t value); /** + * @def atomic_inc * @brief Atomic increment. * * This routine performs an atomic increment by 1 on @a target. @@ -310,9 +310,9 @@ atomic_val_t atomic_sub(atomic_t *target, atomic_val_t value); * * @return Previous value of @a target. */ -atomic_val_t atomic_inc(atomic_t *target); /** + * @def * @brief Atomic decrement. * * This routine performs an atomic decrement by 1 on @a target. @@ -323,9 +323,9 @@ atomic_val_t atomic_inc(atomic_t *target); * * @return Previous value of @a target. */ -atomic_val_t atomic_dec(atomic_t *target); /** + * @def atomic_get * @brief Atomic get. * * This routine performs an atomic read on @a target. @@ -336,9 +336,9 @@ atomic_val_t atomic_dec(atomic_t *target); * * @return Value of @a target. */ -atomic_val_t atomic_get(const atomic_t *target); /** + * @def atomic_ptr_get * @brief Atomic get a pointer value * * This routine performs an atomic read on @a target. @@ -349,9 +349,9 @@ atomic_val_t atomic_get(const atomic_t *target); * * @return Value of @a target. */ -atomic_ptr_val_t atomic_ptr_get(const atomic_ptr_t *target); /** + * @def atomic_set * @brief Atomic get-and-set. * * This routine atomically sets @a target to @a value and returns @@ -364,9 +364,9 @@ atomic_ptr_val_t atomic_ptr_get(const atomic_ptr_t *target); * * @return Previous value of @a target. */ -atomic_val_t atomic_set(atomic_t *target, atomic_val_t value); /** + * @def atomic_ptr_set * @brief Atomic get-and-set for pointer values * * This routine atomically sets @a target to @a value and returns @@ -379,9 +379,9 @@ atomic_val_t atomic_set(atomic_t *target, atomic_val_t value); * * @return Previous value of @a target. */ -atomic_ptr_val_t atomic_ptr_set(atomic_ptr_t *target, atomic_ptr_val_t value); /** + * @def atomic_clear * @brief Atomic clear. * * This routine atomically sets @a target to zero and returns its previous @@ -393,9 +393,9 @@ atomic_ptr_val_t atomic_ptr_set(atomic_ptr_t *target, atomic_ptr_val_t value); * * @return Previous value of @a target. */ -atomic_val_t atomic_clear(atomic_t *target); /** + * @def atomic_ptr_clear * @brief Atomic clear of a pointer value * * This routine atomically sets @a target to zero and returns its previous @@ -407,9 +407,9 @@ atomic_val_t atomic_clear(atomic_t *target); * * @return Previous value of @a target. */ -atomic_ptr_val_t atomic_ptr_clear(atomic_ptr_t *target); /** + * @def atomic_or * @brief Atomic bitwise inclusive OR. * * This routine atomically sets @a target to the bitwise inclusive OR of @@ -422,9 +422,9 @@ atomic_ptr_val_t atomic_ptr_clear(atomic_ptr_t *target); * * @return Previous value of @a target. */ -atomic_val_t atomic_or(atomic_t *target, atomic_val_t value); /** + * @def atomic_xor * @brief Atomic bitwise exclusive OR (XOR). * * @note @atomic_api @@ -437,9 +437,9 @@ atomic_val_t atomic_or(atomic_t *target, atomic_val_t value); * * @return Previous value of @a target. */ -atomic_val_t atomic_xor(atomic_t *target, atomic_val_t value); /** + * @def atomic_and * @brief Atomic bitwise AND. * * This routine atomically sets @a target to the bitwise AND of @a target @@ -452,9 +452,9 @@ atomic_val_t atomic_xor(atomic_t *target, atomic_val_t value); * * @return Previous value of @a target. */ -atomic_val_t atomic_and(atomic_t *target, atomic_val_t value); /** + * @def atomic_nand * @brief Atomic bitwise NAND. * * This routine atomically sets @a target to the bitwise NAND of @a target @@ -467,8 +467,6 @@ atomic_val_t atomic_and(atomic_t *target, atomic_val_t value); * * @return Previous value of @a target. */ -atomic_val_t atomic_nand(atomic_t *target, atomic_val_t value); - /** * @} */