diff --git a/.github/workflows/update-release-status.yml b/.github/workflows/update-release-status.yml index 15e212f369..874bc4d0b2 100644 --- a/.github/workflows/update-release-status.yml +++ b/.github/workflows/update-release-status.yml @@ -1,12 +1,5 @@ name: "Update Release Status" on: - check_run: - types: - - completed - - rerequested - branches: - - "rc/**" - workflow_dispatch: inputs: head-sha: @@ -20,32 +13,23 @@ permissions: checks: write contents: write +env: + HEAD_SHA: ${{ inputs.head-sha }} + jobs: validate-check-runs: runs-on: ubuntu-22.04 outputs: status: ${{ steps.set-output.outputs.status }} - check-run-head-sha: ${{ steps.set-output.outputs.check-run-head-sha }} + conclusion: ${{ steps.set-output.outputs.conclusion }} steps: - - name: Determine check run head SHA - env: - HEAD_SHA_FROM_EVENT: ${{ github.event.check_run.head_sha }} - HEAD_SHA_FROM_INPUTS: ${{ inputs.head-sha }} - run: | - if [[ $GITHUB_EVENT_NAME == "workflow_dispatch" ]]; then - echo "CHECK_RUN_HEAD_SHA=$HEAD_SHA_FROM_INPUTS" >> "$GITHUB_ENV" - else - echo "CHECK_RUN_HEAD_SHA=$HEAD_SHA_FROM_EVENT" >> "$GITHUB_ENV" - fi - - name: Checkout uses: actions/checkout@v4 with: - ref: ${{ env.CHECK_RUN_HEAD_SHA }} + ref: ${{ inputs.head-sha }} - name: Get release status check run id: get-check-run - if: (github.event_name == 'check_run' && github.event.check_run.conclusion == 'success' && github.event.check_run.name != github.workflow) || github.event_name == 'workflow_dispatch' env: GITHUB_TOKEN: ${{ github.token }} run: | @@ -53,7 +37,12 @@ jobs: --header "Accept: application/vnd.github+json" \ --header "X-GitHub-Api-Version: 2022-11-28" \ --jq '.check_runs[] | select(.name == "release-status") | {id: .id, status: .status, conclusion: .conclusion}' \ - /repos/$GITHUB_REPOSITORY/commits/$CHECK_RUN_HEAD_SHA/check-runs) + /repos/$GITHUB_REPOSITORY/commits/$HEAD_SHA/check-runs) + + if [[ -z "$check_run_info" ]]; then + echo "No release status check run found" + exit 1 + fi check_run_id=$(echo "$check_run_info" | jq -r '.id') check_run_status=$(echo "$check_run_info" | jq -r '.status') @@ -64,19 +53,22 @@ jobs: echo "CHECK_RUN_CONCLUSION=$check_run_conclusion" >> "$GITHUB_ENV" - name: Reset release status - if: env.CHECK_RUN_STATUS == 'completed' && ((github.event_name == 'check_run' && github.event.action == 'rerequested') || github.event_name == 'workflow_dispatch') + if: env.CHECK_RUN_STATUS == 'completed' env: GITHUB_TOKEN: ${{ github.token }} run: | - CHECK_RUN_ID=$(gh api \ + check_run_id=$(gh api \ --header "Accept: application/vnd.github+json" \ --header "X-GitHub-Api-Version: 2022-11-28" \ --field name="release-status" \ - --field head_sha="$CHECK_RUN_HEAD_SHA" \ + --field head_sha="$HEAD_SHA" \ --jq ".id" \ /repos/$GITHUB_REPOSITORY/check-runs) - echo "Created release status check run with id $CHECK_RUN_ID" + echo "Created release status check run with id $check_run_id" + # Reset the status to in progress. + echo "CHECK_RUN_STATUS=in_progress" >> "$GITHUB_ENV" + echo "CHECK_RUN_ID=$check_run_id" >> "$GITHUB_ENV" - name: Check all runs completed if: env.CHECK_RUN_STATUS != 'completed' @@ -87,10 +79,12 @@ jobs: --header "Accept: application/vnd.github+json" \ --header "X-GitHub-Api-Version: 2022-11-28" \ --jq '.check_runs | map(select(.name != "release-status"))' \ - /repos/$GITHUB_REPOSITORY/commits/$CHECK_RUN_HEAD_SHA/check-runs) + /repos/$GITHUB_REPOSITORY/commits/$HEAD_SHA/check-runs) status_stats=$(echo "$check_runs" | jq -r '. | {failed: (map(select(.conclusion == "failure")) | length), pending: (map(select(.status != "completed")) | length) }') + echo "status_stats=$status_stats" + failed=$(echo "$status_stats" | jq -r '.failed') pending=$(echo "$status_stats" | jq -r '.pending') @@ -101,7 +95,6 @@ jobs: if: env.CHECK_RUNS_PENDING == '0' && env.CHECK_RUN_STATUS != 'completed' env: GITHUB_TOKEN: ${{ github.token }} - CHECK_RUNS_FAILED: ${{ env.check-runs-failed }} run: | if [[ "$CHECK_RUNS_FAILED" == "0" ]]; then echo "All check runs succeeded" @@ -123,22 +116,23 @@ jobs: --input - \ /repos/$GITHUB_REPOSITORY/check-runs/$CHECK_RUN_ID + echo "RELEASE_STATUS_CONCLUSION=$conclusion" >> "$GITHUB_ENV" + - name: Set output id: set-output run: | + echo "conclusion=$RELEASE_STATUS_CONCLUSION" >> "$GITHUB_OUTPUT" if [[ "$CHECK_RUNS_PENDING" == "0" ]]; then echo "status=completed" >> "$GITHUB_OUTPUT" else echo "status=in_progress" >> "$GITHUB_OUTPUT" fi - echo "check-run-head-sha=$CHECK_RUN_HEAD_SHA" >> "$GITHUB_OUTPUT" - update-release: needs: validate-check-runs - if: needs.validate-check-runs.outputs.status == 'completed' + if: needs.validate-check-runs.outputs.status == 'completed' && needs.validate-check-runs.outputs.conclusion == 'success' uses: ./.github/workflows/update-release.yml with: - head-sha: ${{ needs.validate-check-runs.outputs.check-run-head-sha }} + head-sha: ${{ inputs.head-sha }} secrets: AUTOMATION_PRIVATE_KEY: ${{ secrets.AUTOMATION_PRIVATE_KEY }} diff --git a/.github/workflows/update-release.yml b/.github/workflows/update-release.yml index 7a2ae00797..67666bbf39 100644 --- a/.github/workflows/update-release.yml +++ b/.github/workflows/update-release.yml @@ -30,7 +30,7 @@ jobs: - name: Checkout uses: actions/checkout@v4 with: - ref: ${{ inputs.head-sha }} + fetch-depth: 0 # We need the full history to compute the changelog - name: Install Python uses: actions/setup-python@v4 diff --git a/c/cert/src/rules/ARR37-C/DoNotUsePointerArithmeticOnNonArrayObjectPointers.ql b/c/cert/src/rules/ARR37-C/DoNotUsePointerArithmeticOnNonArrayObjectPointers.ql index 1abc2ad882..2f8ecec25d 100644 --- a/c/cert/src/rules/ARR37-C/DoNotUsePointerArithmeticOnNonArrayObjectPointers.ql +++ b/c/cert/src/rules/ARR37-C/DoNotUsePointerArithmeticOnNonArrayObjectPointers.ql @@ -14,16 +14,14 @@ import cpp import codingstandards.c.cert import codingstandards.cpp.dataflow.DataFlow -import DataFlow::PathGraph +import NonArrayPointerToArrayIndexingExprFlow::PathGraph /** * A data-flow configuration that tracks flow from an `AddressOfExpr` of a variable * of `PointerType` that is not also an `ArrayType` to a `PointerArithmeticOrArrayExpr` */ -class NonArrayPointerToArrayIndexingExprConfig extends DataFlow::Configuration { - NonArrayPointerToArrayIndexingExprConfig() { this = "ArrayToArrayIndexConfig" } - - override predicate isSource(DataFlow::Node source) { +module NonArrayPointerToArrayIndexingExprConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { exists(AddressOfExpr ao, Type t | source.asExpr() = ao and not ao.getOperand() instanceof ArrayExpr and @@ -35,7 +33,7 @@ class NonArrayPointerToArrayIndexingExprConfig extends DataFlow::Configuration { ) } - override predicate isSink(DataFlow::Node sink) { + predicate isSink(DataFlow::Node sink) { exists(PointerArithmeticOrArrayExpr ae | sink.asExpr() = ae.getPointerOperand() and not sink.asExpr() instanceof Literal and @@ -43,7 +41,7 @@ class NonArrayPointerToArrayIndexingExprConfig extends DataFlow::Configuration { ) } - override predicate isBarrierOut(DataFlow::Node node) { + predicate isBarrierOut(DataFlow::Node node) { // the default interprocedural data-flow model flows through any field or array assignment // expressions to the qualifier (array base, pointer dereferenced, or qualifier) instead of the // individual element or field that the assignment modifies. this default behaviour causes @@ -63,6 +61,9 @@ class NonArrayPointerToArrayIndexingExprConfig extends DataFlow::Configuration { } } +module NonArrayPointerToArrayIndexingExprFlow = + DataFlow::Global; + class PointerArithmeticOrArrayExpr extends Expr { Expr operand; @@ -101,9 +102,11 @@ class PointerArithmeticOrArrayExpr extends Expr { predicate isNonPointerOperandZero() { operand.(Literal).getValue().toInt() = 0 } } -from DataFlow::PathNode source, DataFlow::PathNode sink +from + NonArrayPointerToArrayIndexingExprFlow::PathNode source, + NonArrayPointerToArrayIndexingExprFlow::PathNode sink where not isExcluded(sink.getNode().asExpr(), InvalidMemory2Package::doNotUsePointerArithmeticOnNonArrayObjectPointersQuery()) and - any(NonArrayPointerToArrayIndexingExprConfig cfg).hasFlowPath(source, sink) + NonArrayPointerToArrayIndexingExprFlow::flowPath(source, sink) select sink, source, sink, "Pointer arithmetic on non-array object pointer." diff --git a/c/cert/src/rules/ARR39-C/DoNotAddOrSubtractAScaledIntegerToAPointer.ql b/c/cert/src/rules/ARR39-C/DoNotAddOrSubtractAScaledIntegerToAPointer.ql index 5606c8485f..c641c17124 100644 --- a/c/cert/src/rules/ARR39-C/DoNotAddOrSubtractAScaledIntegerToAPointer.ql +++ b/c/cert/src/rules/ARR39-C/DoNotAddOrSubtractAScaledIntegerToAPointer.ql @@ -15,7 +15,7 @@ import cpp import codingstandards.c.cert import codingstandards.c.Pointers import codingstandards.cpp.dataflow.TaintTracking -import DataFlow::PathGraph +import ScaledIntegerPointerArithmeticFlow::PathGraph /** * An expression which invokes the `offsetof` macro or `__builtin_offsetof` operation. @@ -69,12 +69,10 @@ class ScaledIntegerExpr extends Expr { * A data-flow configuration modeling data-flow from a `ScaledIntegerExpr` to a * `PointerArithmeticExpr` where the pointer does not point to a 1-byte type. */ -class ScaledIntegerPointerArithmeticConfig extends DataFlow::Configuration { - ScaledIntegerPointerArithmeticConfig() { this = "ScaledIntegerPointerArithmeticConfig" } +module ScaledIntegerPointerArithmeticConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node src) { src.asExpr() instanceof ScaledIntegerExpr } - override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof ScaledIntegerExpr } - - override predicate isSink(DataFlow::Node sink) { + predicate isSink(DataFlow::Node sink) { exists(PointerArithmeticExpr pa | // exclude pointers to 1-byte types as they do not scale pa.getPointer().getFullyConverted().getType().(DerivedType).getBaseType().getSize() != 1 and @@ -83,9 +81,13 @@ class ScaledIntegerPointerArithmeticConfig extends DataFlow::Configuration { } } -from ScaledIntegerPointerArithmeticConfig config, DataFlow::PathNode src, DataFlow::PathNode sink +module ScaledIntegerPointerArithmeticFlow = DataFlow::Global; + +from + ScaledIntegerPointerArithmeticFlow::PathNode src, + ScaledIntegerPointerArithmeticFlow::PathNode sink where not isExcluded(sink.getNode().asExpr(), Pointers2Package::doNotAddOrSubtractAScaledIntegerToAPointerQuery()) and - config.hasFlowPath(src, sink) + ScaledIntegerPointerArithmeticFlow::flowPath(src, sink) select sink, src, sink, "Scaled integer used in pointer arithmetic." diff --git a/c/cert/src/rules/CON30-C/CleanUpThreadSpecificStorage.ql b/c/cert/src/rules/CON30-C/CleanUpThreadSpecificStorage.ql index 4b31b89023..59fab6e455 100644 --- a/c/cert/src/rules/CON30-C/CleanUpThreadSpecificStorage.ql +++ b/c/cert/src/rules/CON30-C/CleanUpThreadSpecificStorage.ql @@ -18,10 +18,8 @@ import codingstandards.cpp.Concurrency import codingstandards.cpp.dataflow.TaintTracking import codingstandards.cpp.dataflow.DataFlow -class TssCreateToTssDeleteDataFlowConfiguration extends DataFlow::Configuration { - TssCreateToTssDeleteDataFlowConfiguration() { this = "TssCreateToTssDeleteDataFlowConfiguration" } - - override predicate isSource(DataFlow::Node node) { +module TssCreateToTssDeleteConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node node) { exists(TSSCreateFunctionCall tsc, Expr e | // the only requirement of the source is that at some point // it refers to the key of a create statement @@ -30,7 +28,7 @@ class TssCreateToTssDeleteDataFlowConfiguration extends DataFlow::Configuration ) } - override predicate isSink(DataFlow::Node node) { + predicate isSink(DataFlow::Node node) { exists(TSSDeleteFunctionCall tsd, Expr e | // the only requirement of a sink is that at some point // it references the key of a delete call. @@ -40,15 +38,17 @@ class TssCreateToTssDeleteDataFlowConfiguration extends DataFlow::Configuration } } +module TssCreateToTssDeleteFlow = DataFlow::Global; + from TSSCreateFunctionCall tcfc where not isExcluded(tcfc, Concurrency4Package::cleanUpThreadSpecificStorageQuery()) and // all calls to `tss_create` must be bookended by calls to tss_delete // even if a thread is not created. - not exists(TssCreateToTssDeleteDataFlowConfiguration config | - config.hasFlow(DataFlow::definitionByReferenceNodeFromArgument(tcfc.getKey()), _) + not ( + TssCreateToTssDeleteFlow::flow(DataFlow::definitionByReferenceNodeFromArgument(tcfc.getKey()), _) or - config.hasFlow(DataFlow::exprNode(tcfc.getKey()), _) + TssCreateToTssDeleteFlow::flow(DataFlow::exprNode(tcfc.getKey()), _) ) or // if a thread is created, we must check additional items diff --git a/c/cert/src/rules/EXP36-C/DoNotCastPointerToMoreStrictlyAlignedPointerType.ql b/c/cert/src/rules/EXP36-C/DoNotCastPointerToMoreStrictlyAlignedPointerType.ql index b161beac1b..e5735a5fda 100644 --- a/c/cert/src/rules/EXP36-C/DoNotCastPointerToMoreStrictlyAlignedPointerType.ql +++ b/c/cert/src/rules/EXP36-C/DoNotCastPointerToMoreStrictlyAlignedPointerType.ql @@ -15,9 +15,8 @@ import cpp import codingstandards.c.cert import codingstandards.cpp.Alignment import codingstandards.cpp.dataflow.DataFlow -import codingstandards.cpp.dataflow.DataFlow2 import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis -import DataFlow::PathGraph +import ExprWithAlignmentToCStyleCastFlow::PathGraph /** * An expression with a type that has defined alignment requirements @@ -96,8 +95,7 @@ class UnconvertedCastFromNonVoidPointerExpr extends Expr { */ class DefaultAlignedPointerExpr extends UnconvertedCastFromNonVoidPointerExpr, ExprWithAlignment { DefaultAlignedPointerExpr() { - not any(AllocationOrAddressOfExprToUnconvertedCastFromNonVoidPointerExprConfig config) - .hasFlowTo(DataFlow::exprNode(this)) + not AllocationOrAddressOfExprToUnconvertedCastFromNonVoidPointerExprFlow::flowTo(DataFlow::exprNode(this)) } override int getAlignment() { result = this.getType().(PointerType).getBaseType().getAlignment() } @@ -118,43 +116,37 @@ class DefaultAlignedPointerExpr extends UnconvertedCastFromNonVoidPointerExpr, E * to exclude an `DefaultAlignedPointerAccessExpr` as a source if a preceding source * defined by this configuration provides more accurate alignment information. */ -class AllocationOrAddressOfExprToUnconvertedCastFromNonVoidPointerExprConfig extends DataFlow2::Configuration +module AllocationOrAddressOfExprToUnconvertedCastFromNonVoidPointerExprConfig implements + DataFlow::ConfigSig { - AllocationOrAddressOfExprToUnconvertedCastFromNonVoidPointerExprConfig() { - this = "AllocationOrAddressOfExprToUnconvertedCastFromNonVoidPointerExprConfig" - } - - override predicate isSource(DataFlow::Node source) { + predicate isSource(DataFlow::Node source) { source.asExpr() instanceof AddressOfAlignedVariableExpr or source.asExpr() instanceof DefinedAlignmentAllocationExpr } - override predicate isSink(DataFlow::Node sink) { + predicate isSink(DataFlow::Node sink) { sink.asExpr() instanceof UnconvertedCastFromNonVoidPointerExpr } } +module AllocationOrAddressOfExprToUnconvertedCastFromNonVoidPointerExprFlow = + DataFlow::Global; + /** * A data-flow configuration for analysing the flow of `ExprWithAlignment` pointer expressions * to casts which perform pointer type conversions and potentially create pointer alignment issues. */ -class ExprWithAlignmentToCStyleCastConfiguration extends DataFlow::Configuration { - ExprWithAlignmentToCStyleCastConfiguration() { - this = "ExprWithAlignmentToCStyleCastConfiguration" - } +module ExprWithAlignmentToCStyleCastConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { source.asExpr() instanceof ExprWithAlignment } - override predicate isSource(DataFlow::Node source) { - source.asExpr() instanceof ExprWithAlignment - } - - override predicate isSink(DataFlow::Node sink) { + predicate isSink(DataFlow::Node sink) { exists(CStyleCast cast | cast.getUnderlyingType() instanceof PointerType and cast.getUnconverted() = sink.asExpr() ) } - override predicate isBarrierOut(DataFlow::Node node) { + predicate isBarrierOut(DataFlow::Node node) { // the default interprocedural data-flow model flows through any array assignment expressions // to the qualifier (array base or pointer dereferenced) instead of the individual element // that the assignment modifies. this default behaviour causes false positives for any future @@ -169,12 +161,15 @@ class ExprWithAlignmentToCStyleCastConfiguration extends DataFlow::Configuration } } +module ExprWithAlignmentToCStyleCastFlow = DataFlow::Global; + from - DataFlow::PathNode source, DataFlow::PathNode sink, ExprWithAlignment expr, CStyleCast cast, + ExprWithAlignmentToCStyleCastFlow::PathNode source, + ExprWithAlignmentToCStyleCastFlow::PathNode sink, ExprWithAlignment expr, CStyleCast cast, Type toBaseType, int alignmentFrom, int alignmentTo where not isExcluded(cast, Pointers3Package::doNotCastPointerToMoreStrictlyAlignedPointerTypeQuery()) and - any(ExprWithAlignmentToCStyleCastConfiguration config).hasFlowPath(source, sink) and + ExprWithAlignmentToCStyleCastFlow::flowPath(source, sink) and source.getNode().asExpr() = expr and sink.getNode().asExpr() = cast.getUnconverted() and toBaseType = cast.getActualType().(PointerType).getBaseType() and diff --git a/c/cert/src/rules/EXP37-C/DoNotCallFunctionPointerWithIncompatibleType.ql b/c/cert/src/rules/EXP37-C/DoNotCallFunctionPointerWithIncompatibleType.ql index b68cfa8ce1..e28dbddaaf 100644 --- a/c/cert/src/rules/EXP37-C/DoNotCallFunctionPointerWithIncompatibleType.ql +++ b/c/cert/src/rules/EXP37-C/DoNotCallFunctionPointerWithIncompatibleType.ql @@ -14,7 +14,7 @@ import cpp import codingstandards.c.cert import codingstandards.cpp.dataflow.DataFlow -import DataFlow::PathGraph +import SuspectFunctionPointerToCallFlow::PathGraph /** * An expression of type `FunctionPointer` which is the unconverted expression of a cast @@ -37,26 +37,26 @@ class SuspiciousFunctionPointerCastExpr extends Expr { * Data-flow configuration for flow from a `SuspiciousFunctionPointerCastExpr` * to a call of the function pointer resulting from the function pointer cast */ -class SuspectFunctionPointerToCallConfig extends DataFlow::Configuration { - SuspectFunctionPointerToCallConfig() { this = "SuspectFunctionPointerToCallConfig" } - - override predicate isSource(DataFlow::Node src) { +module SuspectFunctionPointerToCallConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SuspiciousFunctionPointerCastExpr } - override predicate isSink(DataFlow::Node sink) { + predicate isSink(DataFlow::Node sink) { exists(VariableCall call | sink.asExpr() = call.getExpr().(VariableAccess)) } } +module SuspectFunctionPointerToCallFlow = DataFlow::Global; + from - SuspectFunctionPointerToCallConfig config, DataFlow::PathNode src, DataFlow::PathNode sink, + SuspectFunctionPointerToCallFlow::PathNode src, SuspectFunctionPointerToCallFlow::PathNode sink, Access access where not isExcluded(src.getNode().asExpr(), ExpressionsPackage::doNotCallFunctionPointerWithIncompatibleTypeQuery()) and access = src.getNode().asExpr() and - config.hasFlowPath(src, sink) + SuspectFunctionPointerToCallFlow::flowPath(src, sink) select src, src, sink, "Incompatible function $@ assigned to function pointer is eventually called through the pointer.", access.getTarget(), access.getTarget().getName() diff --git a/c/cert/src/rules/EXP39-C/DoNotAccessVariableViaPointerOfIncompatibleType.ql b/c/cert/src/rules/EXP39-C/DoNotAccessVariableViaPointerOfIncompatibleType.ql index 784fb54b2f..825f85b0bd 100644 --- a/c/cert/src/rules/EXP39-C/DoNotAccessVariableViaPointerOfIncompatibleType.ql +++ b/c/cert/src/rules/EXP39-C/DoNotAccessVariableViaPointerOfIncompatibleType.ql @@ -15,7 +15,7 @@ import cpp import codingstandards.c.cert import codingstandards.cpp.dataflow.DataFlow import semmle.code.cpp.controlflow.Dominance -import DataFlow::PathGraph +import IndirectCastFlow::PathGraph /** * The standard function `memset` and its assorted variants @@ -42,35 +42,31 @@ class ReallocationFunction extends AllocationFunction { ReallocationFunction() { exists(this.getReallocPtrArg()) } } -/** - * A data-flow state for a pointer which has not been reallocated. - */ -class IndirectCastDefaultFlowState extends DataFlow::FlowState { - IndirectCastDefaultFlowState() { this = "IndirectCastDefaultFlowState" } -} - -/** - * A data-flow state for a pointer which has been reallocated but - * has not yet been zeroed with a memset call. - */ -class IndirectCastReallocatedFlowState extends DataFlow::FlowState { - IndirectCastReallocatedFlowState() { this = "IndirectCastReallocatedFlowState" } -} +newtype IndirectCastFlowState = + /** + * A data-flow state for a pointer which has not been reallocated. + */ + IndirectCastDefaultFlowState() or + /** + * A data-flow state for a pointer which has been reallocated but + * has not yet been zeroed with a memset call. + */ + IndirectCastReallocatedFlowState() /** * A data-flow configuration to track the flow from cast expressions to either * other cast expressions or to dereferences of pointers reallocated with a call * to `realloc` but not cleared via a function call to `memset`. */ -class IndirectCastConfiguration extends DataFlow::Configuration { - IndirectCastConfiguration() { this = "CastToIncompatibleTypeConfiguration" } +module IndirectCastConfig implements DataFlow::StateConfigSig { + class FlowState = IndirectCastFlowState; - override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) { + predicate isSource(DataFlow::Node source, FlowState state) { state instanceof IndirectCastDefaultFlowState and source.asExpr() instanceof IndirectCastAnalysisUnconvertedCastExpr } - override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) { + predicate isSink(DataFlow::Node sink, FlowState state) { sink.asExpr() instanceof IndirectCastAnalysisUnconvertedCastExpr and state instanceof IndirectCastDefaultFlowState or @@ -103,7 +99,7 @@ class IndirectCastConfiguration extends DataFlow::Configuration { ) } - override predicate isBarrier(DataFlow::Node node, DataFlow::FlowState state) { + predicate isBarrier(DataFlow::Node node, FlowState state) { state instanceof IndirectCastReallocatedFlowState and exists(FunctionCall fc | fc.getTarget() instanceof MemsetFunction and @@ -111,9 +107,8 @@ class IndirectCastConfiguration extends DataFlow::Configuration { ) } - override predicate isAdditionalFlowStep( - DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2, - DataFlow::FlowState state2 + predicate isAdditionalFlowStep( + DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2 ) { // track pointer flow through realloc calls and update state to `IndirectCastReallocatedFlowState` state1 instanceof IndirectCastDefaultFlowState and @@ -135,6 +130,8 @@ class IndirectCastConfiguration extends DataFlow::Configuration { } } +module IndirectCastFlow = DataFlow::GlobalWithState; + pragma[inline] predicate areTypesSameExceptForConstSpecifiers(Type a, Type b) { a.stripType() = b.stripType() and @@ -190,12 +187,14 @@ Type compatibleTypes(Type type) { ) } -from DataFlow::PathNode source, DataFlow::PathNode sink, Cast cast, Type fromType, Type toType +from + IndirectCastFlow::PathNode source, IndirectCastFlow::PathNode sink, Cast cast, Type fromType, + Type toType where not isExcluded(sink.getNode().asExpr(), Pointers3Package::doNotAccessVariableViaPointerOfIncompatibleTypeQuery()) and cast.getFile().compiledAsC() and - any(IndirectCastConfiguration config).hasFlowPath(source, sink) and + IndirectCastFlow::flowPath(source, sink) and // include only sinks which are not a compatible type to the associated source source.getNode().asExpr() = cast.getUnconverted() and fromType = cast.getUnconverted().getType().(PointerType).getBaseType() and diff --git a/c/cert/src/rules/EXP40-C/DoNotModifyConstantObjects.ql b/c/cert/src/rules/EXP40-C/DoNotModifyConstantObjects.ql index dbeffd8153..d79224435f 100644 --- a/c/cert/src/rules/EXP40-C/DoNotModifyConstantObjects.ql +++ b/c/cert/src/rules/EXP40-C/DoNotModifyConstantObjects.ql @@ -13,7 +13,7 @@ import cpp import codingstandards.c.cert import codingstandards.cpp.dataflow.DataFlow -import DataFlow::PathGraph +import CastFlow::PathGraph import codingstandards.cpp.SideEffect class ConstRemovingCast extends Cast { @@ -32,23 +32,23 @@ class MaybeReturnsStringLiteralFunctionCall extends FunctionCall { } } -class MyDataFlowConfCast extends DataFlow::Configuration { - MyDataFlowConfCast() { this = "MyDataFlowConfCast" } - - override predicate isSource(DataFlow::Node source) { +module CastConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { source.asExpr().getFullyConverted() instanceof ConstRemovingCast or source.asExpr().getFullyConverted() = any(MaybeReturnsStringLiteralFunctionCall c) } - override predicate isSink(DataFlow::Node sink) { + predicate isSink(DataFlow::Node sink) { sink.asExpr() = any(Assignment a).getLValue().(PointerDereferenceExpr).getOperand() } } -from MyDataFlowConfCast conf, DataFlow::PathNode src, DataFlow::PathNode sink +module CastFlow = DataFlow::Global; + +from CastFlow::PathNode src, CastFlow::PathNode sink where - conf.hasFlowPath(src, sink) + CastFlow::flowPath(src, sink) or sink.getNode() .asExpr() diff --git a/c/cert/src/rules/EXP43-C/DoNotPassAliasedPointerToRestrictQualifiedParam.ql b/c/cert/src/rules/EXP43-C/DoNotPassAliasedPointerToRestrictQualifiedParam.ql index 2e96e25f9f..a4cc4e8944 100644 --- a/c/cert/src/rules/EXP43-C/DoNotPassAliasedPointerToRestrictQualifiedParam.ql +++ b/c/cert/src/rules/EXP43-C/DoNotPassAliasedPointerToRestrictQualifiedParam.ql @@ -115,25 +115,24 @@ int getPointerArithmeticOperandStatedValue(CallToFunctionWithRestrictParametersA result = 0 } -class PointerValueToRestrictArgConfig extends DataFlow::Configuration { - PointerValueToRestrictArgConfig() { this = "PointerValueToRestrictArgConfig" } +module PointerValueToRestrictArgConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { pointerValue(source.asExpr()) } - override predicate isSource(DataFlow::Node source) { pointerValue(source.asExpr()) } - - override predicate isSink(DataFlow::Node sink) { + predicate isSink(DataFlow::Node sink) { exists(CallToFunctionWithRestrictParameters call | sink.asExpr() = call.getAPtrArg(_).getAChild*() ) } - override predicate isBarrierIn(DataFlow::Node node) { + predicate isBarrierIn(DataFlow::Node node) { exists(AddressOfExpr a | node.asExpr() = a.getOperand().getAChild*()) } } +module PointerValueToRestrictArgFlow = DataFlow::Global; + from - PointerValueToRestrictArgConfig config, CallToFunctionWithRestrictParameters call, - CallToFunctionWithRestrictParametersArgExpr arg1, + CallToFunctionWithRestrictParameters call, CallToFunctionWithRestrictParametersArgExpr arg1, CallToFunctionWithRestrictParametersArgExpr arg2, int argOffset1, int argOffset2, Expr source1, Expr source2, string sourceMessage1, string sourceMessage2 where @@ -144,17 +143,20 @@ where (not arg2 = call.getARestrictPtrArg() or arg2.getParamIndex() > arg1.getParamIndex()) and ( // check if two pointers address the same object - config.hasFlow(DataFlow::exprNode(source1), DataFlow::exprNode(arg1.getAChild*())) and + PointerValueToRestrictArgFlow::flow(DataFlow::exprNode(source1), + DataFlow::exprNode(arg1.getAChild*())) and ( // one pointer value flows to both args - config.hasFlow(DataFlow::exprNode(source1), DataFlow::exprNode(arg2.getAChild*())) and + PointerValueToRestrictArgFlow::flow(DataFlow::exprNode(source1), + DataFlow::exprNode(arg2.getAChild*())) and sourceMessage1 = "$@" and sourceMessage2 = "source" and source1 = source2 or // there are two separate values that flow from an AddressOfExpr of the same target getAddressOfExprTargetBase(source1) = getAddressOfExprTargetBase(source2) and - config.hasFlow(DataFlow::exprNode(source2), DataFlow::exprNode(arg2.getAChild*())) and + PointerValueToRestrictArgFlow::flow(DataFlow::exprNode(source2), + DataFlow::exprNode(arg2.getAChild*())) and sourceMessage1 = "a pair of address-of expressions ($@, $@)" and sourceMessage2 = "addressof1" and not source1 = source2 diff --git a/c/cert/src/rules/EXP43-C/RestrictPointerReferencesOverlappingObject.ql b/c/cert/src/rules/EXP43-C/RestrictPointerReferencesOverlappingObject.ql index 727bda754e..bbe41259b8 100644 --- a/c/cert/src/rules/EXP43-C/RestrictPointerReferencesOverlappingObject.ql +++ b/c/cert/src/rules/EXP43-C/RestrictPointerReferencesOverlappingObject.ql @@ -39,22 +39,20 @@ class AssignmentOrInitializationToRestrictPtrValueExpr extends Expr { * A data-flow configuration for tracking flow from an assignment or initialization to * an assignment to an `AssignmentOrInitializationToRestrictPtrValueExpr`. */ -class AssignedValueToRestrictPtrValueConfiguration extends DataFlow::Configuration { - AssignedValueToRestrictPtrValueConfiguration() { - this = "AssignmentOrInitializationToRestrictPtrValueConfiguration" - } - - override predicate isSource(DataFlow::Node source) { +module AssignedValueToRestrictPtrValueConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { exists(Variable v | source.asExpr() = v.getAnAssignedValue()) } - override predicate isSink(DataFlow::Node sink) { + predicate isSink(DataFlow::Node sink) { sink.asExpr() instanceof AssignmentOrInitializationToRestrictPtrValueExpr } } +module AssignedValueToRestrictPtrValueFlow = + DataFlow::Global; + from - AssignedValueToRestrictPtrValueConfiguration config, AssignmentOrInitializationToRestrictPtrValueExpr expr, DataFlow::Node sourceValue, string sourceMessage where @@ -71,8 +69,8 @@ where exists(AssignmentOrInitializationToRestrictPtrValueExpr pre_expr | expr.getEnclosingBlock() = pre_expr.getEnclosingBlock() and ( - config.hasFlow(sourceValue, DataFlow::exprNode(pre_expr)) and - config.hasFlow(sourceValue, DataFlow::exprNode(expr)) and + AssignedValueToRestrictPtrValueFlow::flow(sourceValue, DataFlow::exprNode(pre_expr)) and + AssignedValueToRestrictPtrValueFlow::flow(sourceValue, DataFlow::exprNode(expr)) and sourceMessage = "the same source value" or // Expressions referring to the address of the same variable can also result in aliasing diff --git a/c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql b/c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql index 94f3238f26..33a906136f 100644 --- a/c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql +++ b/c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql @@ -22,24 +22,24 @@ class FsetposCall extends FunctionCall { FsetposCall() { this.getTarget().hasGlobalOrStdName("fsetpos") } } -class FposDFConf extends DataFlow::Configuration { - FposDFConf() { this = "FposDFConf" } - - override predicate isSource(DataFlow::Node source) { +module FposDFConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { // source must be the second parameter of a FgetposCall call source = DataFlow::definitionByReferenceNodeFromArgument(any(FgetposCall c).getArgument(1)) } - override predicate isSink(DataFlow::Node sink) { + predicate isSink(DataFlow::Node sink) { // sink must be the second parameter of a FsetposCall call sink.asExpr() = any(FsetposCall c).getArgument(1) } } +module FposDFFlow = DataFlow::Global; + from FsetposCall fsetpos where not isExcluded(fsetpos.getArgument(1), IO2Package::onlyUseValuesForFsetposThatAreReturnedFromFgetposQuery()) and - not any(FposDFConf dfConf).hasFlowToExpr(fsetpos.getArgument(1)) + not FposDFFlow::flowToExpr(fsetpos.getArgument(1)) select fsetpos.getArgument(1), "The position argument of a call to `fsetpos()` should be obtained from a call to `fgetpos()`." diff --git a/c/cert/src/rules/MEM36-C/DoNotModifyAlignmentOfMemoryWithRealloc.ql b/c/cert/src/rules/MEM36-C/DoNotModifyAlignmentOfMemoryWithRealloc.ql index 0d334a89f8..512b783030 100644 --- a/c/cert/src/rules/MEM36-C/DoNotModifyAlignmentOfMemoryWithRealloc.ql +++ b/c/cert/src/rules/MEM36-C/DoNotModifyAlignmentOfMemoryWithRealloc.ql @@ -16,7 +16,7 @@ import cpp import codingstandards.c.cert import codingstandards.cpp.Alignment import codingstandards.cpp.dataflow.DataFlow -import DataFlow::PathGraph +import AlignedAllocToReallocFlow::PathGraph int getStatedValue(Expr e) { // `upperBound(e)` defaults to `exprMaxVal(e)` when `e` isn't analyzable. So to get a meaningful @@ -37,22 +37,22 @@ class ReallocCall extends FunctionCall { ReallocCall() { this.getTarget().hasName("realloc") } } -class AlignedAllocToReallocConfig extends DataFlow::Configuration { - AlignedAllocToReallocConfig() { this = "AlignedAllocToReallocConfig" } - - override predicate isSource(DataFlow::Node source) { +module AlignedAllocToReallocConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { source.asExpr() instanceof NonDefaultAlignedAllocCall } - override predicate isSink(DataFlow::Node sink) { + predicate isSink(DataFlow::Node sink) { exists(ReallocCall realloc | sink.asExpr() = realloc.getArgument(0)) } } -from AlignedAllocToReallocConfig cfg, DataFlow::PathNode source, DataFlow::PathNode sink +module AlignedAllocToReallocFlow = DataFlow::Global; + +from AlignedAllocToReallocFlow::PathNode source, AlignedAllocToReallocFlow::PathNode sink where not isExcluded(sink.getNode().asExpr(), Memory2Package::doNotModifyAlignmentOfMemoryWithReallocQuery()) and - cfg.hasFlowPath(source, sink) + AlignedAllocToReallocFlow::flowPath(source, sink) select sink, source, sink, "Memory allocated with $@ but reallocated with realloc.", source.getNode().asExpr(), "aligned_alloc" diff --git a/c/cert/src/rules/MSC33-C/DoNotPassInvalidDataToTheAsctimeFunction.ql b/c/cert/src/rules/MSC33-C/DoNotPassInvalidDataToTheAsctimeFunction.ql index f9e2c605ae..52dd0b1046 100644 --- a/c/cert/src/rules/MSC33-C/DoNotPassInvalidDataToTheAsctimeFunction.ql +++ b/c/cert/src/rules/MSC33-C/DoNotPassInvalidDataToTheAsctimeFunction.ql @@ -30,22 +30,22 @@ class AsctimeArg extends Expr { * Dataflow configuration for flow from a library function * to a call of function `asctime` */ -class TmStructSafeConfig extends DataFlow::Configuration { - TmStructSafeConfig() { this = "TmStructSafeConfig" } - - override predicate isSource(DataFlow::Node src) { +module TmStructSafeConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node src) { src.asExpr() .(FunctionCall) .getTarget() .hasGlobalName(["localtime", "localtime_r", "localtime_s", "gmtime", "gmtime_r", "gmtime_s"]) } - override predicate isSink(DataFlow::Node sink) { sink.asExpr() instanceof AsctimeArg } + predicate isSink(DataFlow::Node sink) { sink.asExpr() instanceof AsctimeArg } } -from AsctimeArg fc, TmStructSafeConfig config +module TmStructSafeFlow = DataFlow::Global; + +from AsctimeArg fc where not isExcluded(fc, Contracts7Package::doNotPassInvalidDataToTheAsctimeFunctionQuery()) and - not config.hasFlowToExpr(fc) + not TmStructSafeFlow::flowToExpr(fc) select fc, "The function `asctime` and `asctime_r` should be discouraged. Unsanitized input can overflow the output buffer." diff --git a/c/cert/src/rules/MSC39-C/DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql b/c/cert/src/rules/MSC39-C/DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql index 457c1803ba..821b79c8e4 100644 --- a/c/cert/src/rules/MSC39-C/DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql +++ b/c/cert/src/rules/MSC39-C/DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql @@ -35,17 +35,17 @@ class VaEndArg extends VaAccess { * Dataflow configuration for flow from a library function * to a call of function `asctime` */ -class VaArgConfig extends DataFlow::Configuration { - VaArgConfig() { this = "VaArgConfig" } - - override predicate isSource(DataFlow::Node src) { +module VaArgConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node src) { src.asUninitialized() = any(VariableDeclarationEntry m | m.getType().hasName("va_list")).getVariable() } - override predicate isSink(DataFlow::Node sink) { sink.asExpr() instanceof VaAccess } + predicate isSink(DataFlow::Node sink) { sink.asExpr() instanceof VaAccess } } +module VaArgFlow = DataFlow::Global; + /** * Controlflow nodes preceeding a call to `va_arg` */ @@ -65,9 +65,9 @@ ControlFlowNode preceedsFC(VaAccess va_arg) { } predicate sameSource(VaAccess e1, VaAccess e2) { - exists(VaArgConfig config, DataFlow::Node source | - config.hasFlow(source, DataFlow::exprNode(e1)) and - config.hasFlow(source, DataFlow::exprNode(e2)) + exists(DataFlow::Node source | + VaArgFlow::flow(source, DataFlow::exprNode(e1)) and + VaArgFlow::flow(source, DataFlow::exprNode(e2)) ) } diff --git a/c/cert/src/rules/STR30-C/DoNotAttemptToModifyStringLiterals.ql b/c/cert/src/rules/STR30-C/DoNotAttemptToModifyStringLiterals.ql index 7fbdc276c5..40f19ed4a0 100644 --- a/c/cert/src/rules/STR30-C/DoNotAttemptToModifyStringLiterals.ql +++ b/c/cert/src/rules/STR30-C/DoNotAttemptToModifyStringLiterals.ql @@ -39,12 +39,8 @@ class ModifiesFirstArgFunction extends BufferWrite, FunctionCall { * literal that is assigned to a non modifiable type or wherein the string * literal arises as a argument to a function that may modify its argument. */ -class ImplicitOrExplicitStringLiteralModifiedConfiguration extends DataFlow::Configuration { - ImplicitOrExplicitStringLiteralModifiedConfiguration() { - this = "ImplicitOrExplicitStringLiteralModifiedConfiguration" - } - - override predicate isSource(DataFlow::Node node) { +module ImplicitOrExplicitStringLiteralModifiedConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node node) { // usage through variables exists(Variable v | v.getAnAssignedValue() = node.asExpr() and @@ -65,7 +61,7 @@ class ImplicitOrExplicitStringLiteralModifiedConfiguration extends DataFlow::Con ) } - override predicate isSink(DataFlow::Node node) { + predicate isSink(DataFlow::Node node) { // it's either a buffer write of some kind that we // know about exists(BufferWrite bw | bw.getDest() = node.asExpr()) @@ -77,6 +73,9 @@ class ImplicitOrExplicitStringLiteralModifiedConfiguration extends DataFlow::Con } } +module ImplicitOrExplicitStringLiteralModifiedFlow = + DataFlow::Global; + class MaybeReturnsStringLiteralFunctionCall extends FunctionCall { MaybeReturnsStringLiteralFunctionCall() { getTarget().getName() in [ @@ -144,11 +143,12 @@ class ImplicitStringLiteralBase extends Expr { } } -from Expr literal, Expr literalWrite, ImplicitOrExplicitStringLiteralModifiedConfiguration config +from Expr literal, Expr literalWrite where not isExcluded(literal, Strings1Package::doNotAttemptToModifyStringLiteralsQuery()) and not isExcluded(literalWrite, Strings1Package::doNotAttemptToModifyStringLiteralsQuery()) and - config.hasFlow(DataFlow::exprNode(literal), DataFlow::exprNode(literalWrite)) + ImplicitOrExplicitStringLiteralModifiedFlow::flow(DataFlow::exprNode(literal), + DataFlow::exprNode(literalWrite)) select literalWrite, "This operation may write to a string that may be a string literal that was $@.", literal, "created here" diff --git a/c/common/src/codingstandards/c/Literals.qll b/c/common/src/codingstandards/c/Literals.qll new file mode 100644 index 0000000000..beeeccb8cc --- /dev/null +++ b/c/common/src/codingstandards/c/Literals.qll @@ -0,0 +1,4 @@ +// Reuse the `IntegerLiteral` class +import codingstandards.cpp.Cpp14Literal + +class IntegerLiteral = Cpp14Literal::IntegerLiteral; diff --git a/c/common/src/codingstandards/c/OutOfBounds.qll b/c/common/src/codingstandards/c/OutOfBounds.qll index d6d68d04d5..87c7c17870 100644 --- a/c/common/src/codingstandards/c/OutOfBounds.qll +++ b/c/common/src/codingstandards/c/OutOfBounds.qll @@ -906,13 +906,10 @@ module OOB { override predicate isNotNullTerminated() { none() } } - private class PointerToObjectSourceOrSizeToBufferAccessFunctionConfig extends DataFlow::Configuration + private module PointerToObjectSourceOrSizeToBufferAccessFunctionConfig implements + DataFlow::ConfigSig { - PointerToObjectSourceOrSizeToBufferAccessFunctionConfig() { - this = "PointerToObjectSourceOrSizeToBufferAccessFunctionConfig" - } - - override predicate isSource(DataFlow::Node source) { + predicate isSource(DataFlow::Node source) { source.asExpr() instanceof PointerToObjectSource or exists(PointerToObjectSource ptr | @@ -921,7 +918,7 @@ module OOB { ) } - override predicate isSink(DataFlow::Node sink) { + predicate isSink(DataFlow::Node sink) { exists(BufferAccess ba, Expr arg | ( arg = ba.(BufferAccessLibraryFunctionCall).getAnArgument() or @@ -934,7 +931,7 @@ module OOB { ) } - override predicate isBarrierOut(DataFlow::Node node) { + predicate isBarrierOut(DataFlow::Node node) { // the default interprocedural data-flow model flows through any array assignment expressions // to the qualifier (array base or pointer dereferenced) instead of the individual element // that the assignment modifies. this default behaviour causes false positives for any future @@ -955,10 +952,14 @@ module OOB { } } + private module PointerToObjectSourceOrSizeToBufferAccessFunctionFlow = + DataFlow::Global; + private predicate hasFlowFromBufferOrSizeExprToUse(Expr source, Expr use) { - exists(PointerToObjectSourceOrSizeToBufferAccessFunctionConfig config, Expr useOrChild | + exists(Expr useOrChild | exists(getArithmeticOffsetValue(use, useOrChild)) and - config.hasFlow(DataFlow::exprNode(source), DataFlow::exprNode(useOrChild)) + PointerToObjectSourceOrSizeToBufferAccessFunctionFlow::flow(DataFlow::exprNode(source), + DataFlow::exprNode(useOrChild)) ) } diff --git a/c/common/test/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.expected b/c/common/test/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.expected index 0011556fd0..d0ba3bdb5c 100644 --- a/c/common/test/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.expected +++ b/c/common/test/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.expected @@ -4,15 +4,19 @@ problems | test.c:13:10:13:11 | p4 | test.c:5:14:5:15 | l2 | test.c:13:10:13:11 | p4 | Subtraction between left operand pointing to array $@ and other operand pointing to array $@. | test.c:3:7:3:8 | l2 | l2 | test.c:2:7:2:8 | l1 | l1 | | test.c:13:15:13:16 | l1 | test.c:13:15:13:16 | l1 | test.c:13:15:13:16 | l1 | Subtraction between right operand pointing to array $@ and other operand pointing to array $@. | test.c:2:7:2:8 | l1 | l1 | test.c:3:7:3:8 | l2 | l2 | edges -| test.c:4:14:4:15 | l1 | test.c:10:10:10:11 | p1 | -| test.c:4:14:4:15 | l1 | test.c:12:10:12:11 | p1 | -| test.c:5:14:5:15 | l2 | test.c:11:10:11:11 | p2 | -| test.c:5:14:5:15 | l2 | test.c:12:15:12:16 | p2 | -| test.c:5:14:5:15 | l2 | test.c:13:10:13:11 | p4 | -| test.c:5:14:5:15 | l2 | test.c:14:10:14:11 | p4 | +| test.c:4:14:4:15 | l1 | test.c:4:14:4:18 | access to array | +| test.c:4:14:4:18 | access to array | test.c:10:10:10:11 | p1 | +| test.c:4:14:4:18 | access to array | test.c:12:10:12:11 | p1 | +| test.c:5:14:5:15 | l2 | test.c:5:14:5:19 | access to array | +| test.c:5:14:5:19 | access to array | test.c:11:10:11:11 | p2 | +| test.c:5:14:5:19 | access to array | test.c:12:15:12:16 | p2 | +| test.c:5:14:5:19 | access to array | test.c:13:10:13:11 | p4 | +| test.c:5:14:5:19 | access to array | test.c:14:10:14:11 | p4 | nodes | test.c:4:14:4:15 | l1 | semmle.label | l1 | +| test.c:4:14:4:18 | access to array | semmle.label | access to array | | test.c:5:14:5:15 | l2 | semmle.label | l2 | +| test.c:5:14:5:19 | access to array | semmle.label | access to array | | test.c:10:10:10:11 | p1 | semmle.label | p1 | | test.c:10:15:10:16 | l1 | semmle.label | l1 | | test.c:11:10:11:11 | p2 | semmle.label | p2 | diff --git a/c/common/test/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.expected b/c/common/test/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.expected index 5431867345..8db569a98d 100644 --- a/c/common/test/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.expected +++ b/c/common/test/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.expected @@ -11,20 +11,26 @@ problems | test.c:25:7:25:14 | ... >= ... | test.c:25:13:25:14 | l3 | test.c:25:13:25:14 | l3 | Compare operation >= comparing right operand pointing to array $@ and other operand pointing to array $@. | test.c:4:7:4:8 | l3 | l3 | test.c:2:7:2:8 | l1 | l1 | edges | test.c:6:13:6:14 | l1 | test.c:13:12:13:13 | p0 | -| test.c:7:14:7:15 | l1 | test.c:11:7:11:8 | p1 | -| test.c:7:14:7:15 | l1 | test.c:13:7:13:8 | p1 | -| test.c:7:14:7:15 | l1 | test.c:15:13:15:14 | p1 | -| test.c:7:14:7:15 | l1 | test.c:17:7:17:8 | p1 | -| test.c:7:14:7:15 | l1 | test.c:23:13:23:14 | p1 | -| test.c:7:14:7:15 | l1 | test.c:25:7:25:8 | p1 | -| test.c:8:14:8:15 | l1 | test.c:11:12:11:13 | p2 | -| test.c:8:14:8:15 | l1 | test.c:21:7:21:8 | p2 | -| test.c:9:14:9:15 | l2 | test.c:21:12:21:13 | p3 | +| test.c:7:14:7:15 | l1 | test.c:7:14:7:18 | access to array | +| test.c:7:14:7:18 | access to array | test.c:11:7:11:8 | p1 | +| test.c:7:14:7:18 | access to array | test.c:13:7:13:8 | p1 | +| test.c:7:14:7:18 | access to array | test.c:15:13:15:14 | p1 | +| test.c:7:14:7:18 | access to array | test.c:17:7:17:8 | p1 | +| test.c:7:14:7:18 | access to array | test.c:23:13:23:14 | p1 | +| test.c:7:14:7:18 | access to array | test.c:25:7:25:8 | p1 | +| test.c:8:14:8:15 | l1 | test.c:8:14:8:18 | access to array | +| test.c:8:14:8:18 | access to array | test.c:11:12:11:13 | p2 | +| test.c:8:14:8:18 | access to array | test.c:21:7:21:8 | p2 | +| test.c:9:14:9:15 | l2 | test.c:9:14:9:18 | access to array | +| test.c:9:14:9:18 | access to array | test.c:21:12:21:13 | p3 | nodes | test.c:6:13:6:14 | l1 | semmle.label | l1 | | test.c:7:14:7:15 | l1 | semmle.label | l1 | +| test.c:7:14:7:18 | access to array | semmle.label | access to array | | test.c:8:14:8:15 | l1 | semmle.label | l1 | +| test.c:8:14:8:18 | access to array | semmle.label | access to array | | test.c:9:14:9:15 | l2 | semmle.label | l2 | +| test.c:9:14:9:18 | access to array | semmle.label | access to array | | test.c:11:7:11:8 | p1 | semmle.label | p1 | | test.c:11:12:11:13 | p2 | semmle.label | p2 | | test.c:13:7:13:8 | p1 | semmle.label | p1 | diff --git a/c/misra/src/rules/RULE-17-5/ArrayFunctionArgumentNumberOfElements.ql b/c/misra/src/rules/RULE-17-5/ArrayFunctionArgumentNumberOfElements.ql index 6a0ff9833a..208e8153d6 100644 --- a/c/misra/src/rules/RULE-17-5/ArrayFunctionArgumentNumberOfElements.ql +++ b/c/misra/src/rules/RULE-17-5/ArrayFunctionArgumentNumberOfElements.ql @@ -44,21 +44,22 @@ class ArrayParameter extends Parameter { */ int countElements(ArrayAggregateLiteral l) { result = count(l.getAnElementExpr(_)) } -class SmallArrayConfig extends DataFlow::Configuration { - SmallArrayConfig() { this = "SmallArrayConfig" } +module SmallArrayConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node src) { src.asExpr() instanceof ArrayAggregateLiteral } - override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof ArrayAggregateLiteral } - - override predicate isSink(DataFlow::Node sink) { + predicate isSink(DataFlow::Node sink) { sink.asExpr() = any(ArrayParameter p).getAMatchingArgument() } } +module SmallArrayFlow = DataFlow::Global; + from Expr arg, ArrayParameter p where not isExcluded(arg, Contracts6Package::arrayFunctionArgumentNumberOfElementsQuery()) and - exists(SmallArrayConfig config | arg = p.getAMatchingArgument() | - // the argument is a value and not an arrey + arg = p.getAMatchingArgument() and + ( + // the argument is a value and not an array not arg.getType() instanceof DerivedType or // the argument is an array too small @@ -67,7 +68,7 @@ where // the argument is a pointer and its value does not come from a literal of the correct arg.getType() instanceof PointerType and not exists(ArrayAggregateLiteral l | - config.hasFlow(DataFlow::exprNode(l), DataFlow::exprNode(arg)) and + SmallArrayFlow::flow(DataFlow::exprNode(l), DataFlow::exprNode(arg)) and countElements(l) >= p.getArraySize() ) ) diff --git a/c/misra/src/rules/RULE-21-14/MemcmpUsedToCompareNullTerminatedStrings.ql b/c/misra/src/rules/RULE-21-14/MemcmpUsedToCompareNullTerminatedStrings.ql index 96d6dedcb3..44e21d14db 100644 --- a/c/misra/src/rules/RULE-21-14/MemcmpUsedToCompareNullTerminatedStrings.ql +++ b/c/misra/src/rules/RULE-21-14/MemcmpUsedToCompareNullTerminatedStrings.ql @@ -16,13 +16,11 @@ import cpp import codingstandards.c.misra import codingstandards.c.misra.EssentialTypes import codingstandards.cpp.dataflow.TaintTracking -import DataFlow::PathGraph +import NullTerminatedStringToMemcmpFlow::PathGraph // Data flow from a StringLiteral or from an array of characters, to a memcmp call -class NullTerminatedStringToMemcmpConfiguration extends TaintTracking::Configuration { - NullTerminatedStringToMemcmpConfiguration() { this = "NullTerminatedStringToMemcmpConfiguration" } - - override predicate isSource(DataFlow::Node source) { +module NullTerminatedStringToMemcmpConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { source.asExpr() instanceof StringLiteral or exists(Variable v, ArrayAggregateLiteral aal | @@ -48,7 +46,7 @@ class NullTerminatedStringToMemcmpConfiguration extends TaintTracking::Configura ) } - override predicate isSink(DataFlow::Node sink) { + predicate isSink(DataFlow::Node sink) { exists(FunctionCall memcmp | memcmp.getTarget().hasGlobalOrStdName("memcmp") and sink.asExpr() = memcmp.getArgument([0, 1]) @@ -56,20 +54,23 @@ class NullTerminatedStringToMemcmpConfiguration extends TaintTracking::Configura } } +module NullTerminatedStringToMemcmpFlow = TaintTracking::Global; + from - FunctionCall memcmp, DataFlow::PathNode source, DataFlow::PathNode sink, - DataFlow::PathNode source1, DataFlow::PathNode arg1, DataFlow::PathNode source2, - DataFlow::PathNode arg2 + FunctionCall memcmp, NullTerminatedStringToMemcmpFlow::PathNode source, + NullTerminatedStringToMemcmpFlow::PathNode sink, + NullTerminatedStringToMemcmpFlow::PathNode source1, + NullTerminatedStringToMemcmpFlow::PathNode arg1, + NullTerminatedStringToMemcmpFlow::PathNode source2, + NullTerminatedStringToMemcmpFlow::PathNode arg2 where not isExcluded(memcmp, EssentialTypesPackage::memcmpUsedToCompareNullTerminatedStringsQuery()) and memcmp.getTarget().hasGlobalOrStdName("memcmp") and arg1.getNode().asExpr() = memcmp.getArgument(0) and arg2.getNode().asExpr() = memcmp.getArgument(1) and // There is a path from a null-terminated string to each argument - exists(NullTerminatedStringToMemcmpConfiguration cfg | - cfg.hasFlowPath(source1, arg1) and - cfg.hasFlowPath(source2, arg2) - ) and + NullTerminatedStringToMemcmpFlow::flowPath(source1, arg1) and + NullTerminatedStringToMemcmpFlow::flowPath(source2, arg2) and // Produce multiple paths for each result, one for each source/arg pair ( source = source1 and sink = arg1 diff --git a/c/misra/src/rules/RULE-22-4/AttemptToWriteToAReadOnlyStream.ql b/c/misra/src/rules/RULE-22-4/AttemptToWriteToAReadOnlyStream.ql index 58d46176c2..6dc3b3ee71 100644 --- a/c/misra/src/rules/RULE-22-4/AttemptToWriteToAReadOnlyStream.ql +++ b/c/misra/src/rules/RULE-22-4/AttemptToWriteToAReadOnlyStream.ql @@ -15,22 +15,22 @@ import codingstandards.c.misra import codingstandards.cpp.standardlibrary.FileAccess import codingstandards.cpp.dataflow.DataFlow -class FileDFConf extends DataFlow::Configuration { - FileDFConf() { this = "FileDFConf" } - - override predicate isSource(DataFlow::Node source) { +module FileDFConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { // source is the return value of a call to fopen source.asExpr().(FOpenCall).isReadOnlyMode() } - override predicate isSink(DataFlow::Node sink) { + predicate isSink(DataFlow::Node sink) { // sink must be the second parameter of a FsetposCall call sink.asExpr() = any(FileWriteFunctionCall write).getFileExpr() } } -from FileDFConf dfConf, DataFlow::Node source, FileWriteFunctionCall sink +module FileDFFlow = DataFlow::Global; + +from DataFlow::Node source, FileWriteFunctionCall sink where not isExcluded(sink, IO3Package::attemptToWriteToAReadOnlyStreamQuery()) and - dfConf.hasFlow(source, DataFlow::exprNode(sink.getFileExpr())) + FileDFFlow::flow(source, DataFlow::exprNode(sink.getFileExpr())) select sink, "Attempt to write to a $@ opened as read-only.", source, "stream" diff --git a/c/misra/src/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.ql b/c/misra/src/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.ql index 22499946a0..307357a93a 100644 --- a/c/misra/src/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.ql +++ b/c/misra/src/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.ql @@ -19,14 +19,12 @@ import codingstandards.cpp.ReadErrorsAndEOF * The getchar() return value propagates directly to a check against EOF macro * type conversions are not allowed */ -class DFConf extends DataFlow::Configuration { - DFConf() { this = "DFConf" } - - override predicate isSource(DataFlow::Node source) { +module DFConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { source.asExpr() instanceof InBandErrorReadFunctionCall } - override predicate isSink(DataFlow::Node sink) { + predicate isSink(DataFlow::Node sink) { exists(EOFWEOFInvocation mi, EqualityOperation eq | // one operand is the sink sink.asExpr() = eq.getAnOperand() and @@ -35,11 +33,13 @@ class DFConf extends DataFlow::Configuration { ) } - override predicate isBarrier(DataFlow::Node barrier) { + predicate isBarrier(DataFlow::Node barrier) { barrier.asExpr() = any(IntegralConversion c).getExpr() } } +module DFFlow = DataFlow::Global; + // The equality operation `eq` checks a char fetched from `read` against a macro predicate isWeakMacroCheck(EqualityOperation eq, InBandErrorReadFunctionCall read) { exists(Expr c, EOFWEOFInvocation mi | @@ -51,10 +51,10 @@ predicate isWeakMacroCheck(EqualityOperation eq, InBandErrorReadFunctionCall rea ) } -from EqualityOperation eq, InBandErrorReadFunctionCall read, DFConf dfConf +from EqualityOperation eq, InBandErrorReadFunctionCall read where not isExcluded(eq, IO3Package::eofShallBeComparedWithUnmodifiedReturnValuesQuery()) and isWeakMacroCheck(eq, read) and - not dfConf.hasFlow(DataFlow::exprNode(read), DataFlow::exprNode(eq.getAnOperand())) + not DFFlow::flow(DataFlow::exprNode(read), DataFlow::exprNode(eq.getAnOperand())) select eq, "The check is not reliable as the type of the return value of $@ is converted.", read, read.toString() diff --git a/c/misra/src/rules/RULE-7-3/LowercaseCharacterLUsedInLiteralSuffix.ql b/c/misra/src/rules/RULE-7-3/LowercaseCharacterLUsedInLiteralSuffix.ql index 311831d2b8..4fc257578b 100644 --- a/c/misra/src/rules/RULE-7-3/LowercaseCharacterLUsedInLiteralSuffix.ql +++ b/c/misra/src/rules/RULE-7-3/LowercaseCharacterLUsedInLiteralSuffix.ql @@ -14,10 +14,10 @@ import cpp import codingstandards.c.misra +import codingstandards.c.Literals -from Literal l +from IntegerLiteral l where not isExcluded(l, SyntaxPackage::lowercaseCharacterLUsedInLiteralSuffixQuery()) and - not l instanceof StringLiteral and exists(l.getValueText().indexOf("l")) select l, "Lowercase 'l' used as a literal suffix." diff --git a/c/misra/src/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.ql b/c/misra/src/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.ql index 62aade0c0c..e46085750d 100644 --- a/c/misra/src/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.ql +++ b/c/misra/src/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.ql @@ -45,7 +45,7 @@ where msg = "Function " + f + " declares parameter that is unnamed." or hasZeroParamDecl(f) and - msg = "Function " + f + " does not specifiy void for no parameters present." + msg = "Function " + f + " does not specify void for no parameters present." or //parameters declared in declaration list (not in function signature) //have placeholder file location associated only diff --git a/c/misra/test/rules/RULE-7-3/cpp/LowercaseCharacterLUsedInLiteralSuffix.expected b/c/misra/test/rules/RULE-7-3/cpp/LowercaseCharacterLUsedInLiteralSuffix.expected new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/misra/test/rules/RULE-7-3/cpp/LowercaseCharacterLUsedInLiteralSuffix.qlref b/c/misra/test/rules/RULE-7-3/cpp/LowercaseCharacterLUsedInLiteralSuffix.qlref new file mode 100644 index 0000000000..464efc3b2f --- /dev/null +++ b/c/misra/test/rules/RULE-7-3/cpp/LowercaseCharacterLUsedInLiteralSuffix.qlref @@ -0,0 +1 @@ +rules/RULE-7-3/LowercaseCharacterLUsedInLiteralSuffix.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-7-3/cpp/README.md b/c/misra/test/rules/RULE-7-3/cpp/README.md new file mode 100644 index 0000000000..b9aa3d6d8f --- /dev/null +++ b/c/misra/test/rules/RULE-7-3/cpp/README.md @@ -0,0 +1 @@ +This test case was added to validate FP report [#319](https://github.com/github/codeql-coding-standards/issues/319) that occurs when this rule is run on a translation unit with language mode c++. \ No newline at end of file diff --git a/c/misra/test/rules/RULE-7-3/cpp/options b/c/misra/test/rules/RULE-7-3/cpp/options new file mode 100644 index 0000000000..8dbed822c6 --- /dev/null +++ b/c/misra/test/rules/RULE-7-3/cpp/options @@ -0,0 +1 @@ +semmle-extractor-options:--clang -std=c++14 --edg --diag_error=implicit_func_decl -nostdinc -I../../../../../cpp/common/test/includes/standard-library \ No newline at end of file diff --git a/c/misra/test/rules/RULE-7-3/cpp/test.cpp b/c/misra/test/rules/RULE-7-3/cpp/test.cpp new file mode 100644 index 0000000000..ba3ca4f14e --- /dev/null +++ b/c/misra/test/rules/RULE-7-3/cpp/test.cpp @@ -0,0 +1 @@ +int x = false; // COMPLIANT - reported as FP in #319 \ No newline at end of file diff --git a/c/misra/test/rules/RULE-7-3/test.c b/c/misra/test/rules/RULE-7-3/test.c index 00a61817aa..5e1c448926 100644 --- a/c/misra/test/rules/RULE-7-3/test.c +++ b/c/misra/test/rules/RULE-7-3/test.c @@ -41,4 +41,4 @@ long d9 = 001LU; // COMPLIANT char *e1 = ""; char *e2 = "ul"; -char *e3 = "UL"; +char *e3 = "UL"; \ No newline at end of file diff --git a/c/misra/test/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.expected b/c/misra/test/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.expected index f33a53174e..f2c08897b8 100644 --- a/c/misra/test/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.expected +++ b/c/misra/test/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.expected @@ -1,4 +1,4 @@ | test.c:3:6:3:7 | f1 | Function f1 declares parameter that is unnamed. | -| test.c:4:6:4:7 | f2 | Function f2 does not specifiy void for no parameters present. | -| test.c:5:6:5:7 | f3 | Function f3 does not specifiy void for no parameters present. | +| test.c:4:6:4:7 | f2 | Function f2 does not specify void for no parameters present. | +| test.c:5:6:5:7 | f3 | Function f3 does not specify void for no parameters present. | | test.c:7:5:7:6 | f5 | Function f5 declares parameter in unsupported declaration list. | diff --git a/c/misra/test/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.expected.clang b/c/misra/test/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.expected.clang index 8d933c8b4d..1d4a30ce8c 100644 --- a/c/misra/test/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.expected.clang +++ b/c/misra/test/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.expected.clang @@ -1,3 +1,3 @@ | test.c:3:6:3:7 | f1 | Function f1 declares parameter that is unnamed. | -| test.c:4:6:4:7 | f2 | Function f2 does not specifiy void for no parameters present. | +| test.c:4:6:4:7 | f2 | Function f2 does not specify void for no parameters present. | | test.c:7:5:7:6 | f5 | Function f5 declares parameter in unsupported declaration list. | diff --git a/change_notes/2023-10-24-a7-1-5-non-fundamental.md b/change_notes/2023-10-24-a7-1-5-non-fundamental.md new file mode 100644 index 0000000000..f0c9802f5c --- /dev/null +++ b/change_notes/2023-10-24-a7-1-5-non-fundamental.md @@ -0,0 +1,8 @@ + * `A7-1-5` - exclude auto variables initialized with an expression of non-fundamental type. Typically this occurs when using range based for loops with arrays of non-fundamental types. For example: + ``` + void iterate(Foo values[]) { + for (auto value : values) { // COMPLIANT (previously false positive) + // ... + } + } + ``` \ No newline at end of file diff --git a/change_notes/2023-10-25-a0-1-1.md b/change_notes/2023-10-25-a0-1-1.md new file mode 100644 index 0000000000..bd85f52143 --- /dev/null +++ b/change_notes/2023-10-25-a0-1-1.md @@ -0,0 +1,4 @@ + * `A0-1-1` - address a number of false positive issues: + * Exclude compiler-generated variables, such as those generated for range-based for loops. + * Exclude variables in uninstantiated templates, for which we have no precise data on uses. + * Deviations should now be applied to the useless assignment instead of the variable itself. diff --git a/change_notes/2023-10-26-a15-4-4-noexcept.md b/change_notes/2023-10-26-a15-4-4-noexcept.md new file mode 100644 index 0000000000..e778264cc3 --- /dev/null +++ b/change_notes/2023-10-26-a15-4-4-noexcept.md @@ -0,0 +1 @@ + * `A15-4-4`: remove false positives reported on uninsantiated templates. \ No newline at end of file diff --git a/change_notes/2023-11-22-remove-parameters-a7-1-1.md b/change_notes/2023-11-22-remove-parameters-a7-1-1.md new file mode 100644 index 0000000000..415e2ba332 --- /dev/null +++ b/change_notes/2023-11-22-remove-parameters-a7-1-1.md @@ -0,0 +1 @@ + * `A7-1-1` - no longer report parameters as contravening this rule. This is inline with the rule intent as described in the referenced C++ Core Guidelines rule [CON.1](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#con1-by-default-make-objects-immutable), which states "To avoid confusion and lots of false positives, don’t enforce this rule for function parameters." \ No newline at end of file diff --git a/change_notes/2024-01-12-fix-reported-fp-a3-9-1.md b/change_notes/2024-01-12-fix-reported-fp-a3-9-1.md new file mode 100644 index 0000000000..fa9d9dbe74 --- /dev/null +++ b/change_notes/2024-01-12-fix-reported-fp-a3-9-1.md @@ -0,0 +1,5 @@ +- `A3-9-1` - `VariableWidthIntegerTypesUsed.ql`: + - Exclude the plain char type. Still includes `signed char` and `unsigned char`. + - Include CV-qualified variable width integer types. +- `A3-9-1` - `VariableWidthPlainCharTypeUsed.ql`: + - New query to support fine grained deviation support for the plain char type. \ No newline at end of file diff --git a/change_notes/2024-01-17-a4-7-1-exclude-pointers.md b/change_notes/2024-01-17-a4-7-1-exclude-pointers.md new file mode 100644 index 0000000000..325149b219 --- /dev/null +++ b/change_notes/2024-01-17-a4-7-1-exclude-pointers.md @@ -0,0 +1 @@ + * `A4-7-1` - exclude pointer increment and decrement operators from this rule. \ No newline at end of file diff --git a/change_notes/2024-01-17-fix-reported-fp-for-a2-3-1.md b/change_notes/2024-01-17-fix-reported-fp-for-a2-3-1.md new file mode 100644 index 0000000000..0ac0580506 --- /dev/null +++ b/change_notes/2024-01-17-fix-reported-fp-for-a2-3-1.md @@ -0,0 +1,2 @@ +`A2-3-1`: ` cpp/autosar/invalid-character-in-string-literal` + - Fixes #311. Exclude wide string literals and utf8 string literal. \ No newline at end of file diff --git a/change_notes/2024-01-18-fix-reported-fp-for-rule-7-3.md b/change_notes/2024-01-18-fix-reported-fp-for-rule-7-3.md new file mode 100644 index 0000000000..dea57f1be4 --- /dev/null +++ b/change_notes/2024-01-18-fix-reported-fp-for-rule-7-3.md @@ -0,0 +1,2 @@ +`RULE-7-3`: `c/misra/lowercase-character-l-used-in-literal-suffix` + - Exclude non integer literals. This removes a false positive triggered when analyzing C++ code containing the `false` literal. \ No newline at end of file diff --git a/change_notes/2024-01-24-throwing-functions-exclude-noexcept.md b/change_notes/2024-01-24-throwing-functions-exclude-noexcept.md new file mode 100644 index 0000000000..4752123832 --- /dev/null +++ b/change_notes/2024-01-24-throwing-functions-exclude-noexcept.md @@ -0,0 +1,6 @@ + * Exceptions are no longer propagated from calls to `noexcept` functions, or calls functions with dynamic exception specifications where the exception is not permitted. This is consistent with the default behaviour specified in `[expect.spec]` which indicates that `std::terminate` is called. This has the following impact: + - `A15-4-2`, `ERR55-CPP` - reduce false positives for `noexcept` functions which call other `noexcept` function which may throw. + - `A15-2-2` - reduce false positives for constructors which call `noexcept` functions. + - `A15-4-5` - reduce false positives for checked exceptions that are thrown from `noexcept` functions called by the original function. + - `DCL57-CPP` - do not report exceptions thrown from `noexcept` functions called by deallocation functions or destructors. + - `A15-5-1`, `M15-3-1` - do not report exceptions thrown from `noexcept` functions called by special functions. \ No newline at end of file diff --git a/change_notes/2024-01-25-exclusion-m9-3-3.md b/change_notes/2024-01-25-exclusion-m9-3-3.md new file mode 100644 index 0000000000..cb16180172 --- /dev/null +++ b/change_notes/2024-01-25-exclusion-m9-3-3.md @@ -0,0 +1,2 @@ +`M9-3-3` - `MemberFunctionConstIfPossible.ql`, `MemberFunctionStaticIfPossible.ql`: + - Fixes #413. Exclude deleted member functions. \ No newline at end of file diff --git a/change_notes/2024-01-25-fix-reported-fp-for-a8-4-7.md b/change_notes/2024-01-25-fix-reported-fp-for-a8-4-7.md new file mode 100644 index 0000000000..34c4343d1b --- /dev/null +++ b/change_notes/2024-01-25-fix-reported-fp-for-a8-4-7.md @@ -0,0 +1,3 @@ +`A8-4-7` - `InParametersForCheapToCopyTypesNotPassedByValue.ql`, `InParametersForNotCheapToCopyTypesNotPassedByReference.ql`: + - Fixes #397. Exclude user defined operators and move constructors.` + - Exclude parameters for instantiated templates because the declaration location of the function does not contain enough information about the type used in the instantiation to make an actionable alert. \ No newline at end of file diff --git a/change_notes/2024-01-26-exclusion-a5-0-2.md b/change_notes/2024-01-26-exclusion-a5-0-2.md new file mode 100644 index 0000000000..33d8113774 --- /dev/null +++ b/change_notes/2024-01-26-exclusion-a5-0-2.md @@ -0,0 +1,2 @@ +`A5-0-2` - `NonBooleanIfStmt.qll`, `NonBooleanIterationStmt.qll`: + - Exclude compiler generated conditions. \ No newline at end of file diff --git a/change_notes/2024-01-30-exclusion-a13-3-1.md b/change_notes/2024-01-30-exclusion-a13-3-1.md new file mode 100644 index 0000000000..7033fb040e --- /dev/null +++ b/change_notes/2024-01-30-exclusion-a13-3-1.md @@ -0,0 +1,2 @@ +`A13-3-1` - `FunctionThatContainsForwardingReferenceAsItsArgumentOverloaded.ql`: + - Fixes #399. Exclude functions that have different number of parameters. \ No newline at end of file diff --git a/change_notes/2024-01-30-fix-fp-for-a4-7-1.md b/change_notes/2024-01-30-fix-fp-for-a4-7-1.md new file mode 100644 index 0000000000..2c4a3d7d19 --- /dev/null +++ b/change_notes/2024-01-30-fix-fp-for-a4-7-1.md @@ -0,0 +1,2 @@ +`A4-7-1`: `IntegerExpressionLeadToDataLoss.ql` + - Fix #368: Incorrectly reporting `/=` as a cause for data loss. diff --git a/change_notes/2024-01-31-exclusion-a16-0-1.md b/change_notes/2024-01-31-exclusion-a16-0-1.md new file mode 100644 index 0000000000..8ff06ba32d --- /dev/null +++ b/change_notes/2024-01-31-exclusion-a16-0-1.md @@ -0,0 +1,2 @@ +`A16-0-1` - `PreProcessorShallOnlyBeUsedForCertainDirectivesPatterns.ql`: + - Exclude all preprocessor elses and also consider elifs separately (ie do not affect valid ifs) but not valid if not meeting the same criteria as an ifdef etc. \ No newline at end of file diff --git a/change_notes/2024-01-31-fix-fp-a4-5-1.md b/change_notes/2024-01-31-fix-fp-a4-5-1.md new file mode 100644 index 0000000000..89caded89c --- /dev/null +++ b/change_notes/2024-01-31-fix-fp-a4-5-1.md @@ -0,0 +1,4 @@ +`A4-5-1`: `EnumUsedInArithmeticContexts.ql`: + - Address incorrect exclusion of the binary operator `&`. + - Address incorrect inclusion of the unary operator `&`. + - Fix FP reported in #366. \ No newline at end of file diff --git a/change_notes/2024-01-31-fix-fp-a7-1-2.md b/change_notes/2024-01-31-fix-fp-a7-1-2.md new file mode 100644 index 0000000000..94a74d463f --- /dev/null +++ b/change_notes/2024-01-31-fix-fp-a7-1-2.md @@ -0,0 +1,2 @@ +`A7-1-2` - `VariableMissingConstexpr.ql`: + - Fix FP reported in #466. Addresses incorrect assumption that calls to `constexpr` functions are always compile-time evaluated. \ No newline at end of file diff --git a/change_notes/2024-01-31-fix-fp-m9-3-3.md b/change_notes/2024-01-31-fix-fp-m9-3-3.md new file mode 100644 index 0000000000..4294871638 --- /dev/null +++ b/change_notes/2024-01-31-fix-fp-m9-3-3.md @@ -0,0 +1,2 @@ +`M9-3-3`: `MemberFunctionConstIfPossible.ql`: + - Fix FP reported in 467. Excluding candidates in uninstantiated templates. \ No newline at end of file diff --git a/change_notes/2024-02-01-fix-fp-reported-for-a7-1-1.md b/change_notes/2024-02-01-fix-fp-reported-for-a7-1-1.md new file mode 100644 index 0000000000..346d7a0182 --- /dev/null +++ b/change_notes/2024-02-01-fix-fp-reported-for-a7-1-1.md @@ -0,0 +1,2 @@ +`A7-1-1` - `DeclarationUnmodifiedObjectMissingConstSpecifier.ql` + - Fix FP reported in #372. Exclude compiler generated variables. \ No newline at end of file diff --git a/change_notes/2024-02-13-fix-fn-M7-3-6.md b/change_notes/2024-02-13-fix-fn-M7-3-6.md new file mode 100644 index 0000000000..aa86ab6222 --- /dev/null +++ b/change_notes/2024-02-13-fix-fn-M7-3-6.md @@ -0,0 +1,2 @@ +- `M7-3-6` - `UsingDeclarationsUsedInHeaderFiles.ql`: + - Address FN reported in #400. Only using-declarations are exempted from class- and function-scope. \ No newline at end of file diff --git a/cpp/autosar/src/rules/A0-1-1/UselessAssignment.ql b/cpp/autosar/src/rules/A0-1-1/UselessAssignment.ql index f6219abe4b..a1c6fb1fa8 100644 --- a/cpp/autosar/src/rules/A0-1-1/UselessAssignment.ql +++ b/cpp/autosar/src/rules/A0-1-1/UselessAssignment.ql @@ -20,6 +20,6 @@ import codingstandards.cpp.deadcode.UselessAssignments from SsaDefinition ultimateDef, InterestingStackVariable v where - not isExcluded(v, DeadCodePackage::uselessAssignmentQuery()) and + not isExcluded(ultimateDef, DeadCodePackage::uselessAssignmentQuery()) and isUselessSsaDefinition(ultimateDef, v) select ultimateDef, "Definition of $@ is unused.", v, v.getName() diff --git a/cpp/autosar/src/rules/A13-3-1/FunctionThatContainsForwardingReferenceAsItsArgumentOverloaded.ql b/cpp/autosar/src/rules/A13-3-1/FunctionThatContainsForwardingReferenceAsItsArgumentOverloaded.ql index 7562082656..393c1222fd 100644 --- a/cpp/autosar/src/rules/A13-3-1/FunctionThatContainsForwardingReferenceAsItsArgumentOverloaded.ql +++ b/cpp/autosar/src/rules/A13-3-1/FunctionThatContainsForwardingReferenceAsItsArgumentOverloaded.ql @@ -21,10 +21,36 @@ class Candidate extends TemplateFunction { } } -from Candidate c, Function f +from + Candidate c, Function f, Function overload, Function overloaded, string msg, + string firstMsgSegment where not isExcluded(f, OperatorsPackage::functionThatContainsForwardingReferenceAsItsArgumentOverloadedQuery()) and not f.isDeleted() and - f = c.getAnOverload() -select f, "Function overloads a $@ with a forwarding reference parameter.", c, "function" + f = c.getAnOverload() and + // allow for overloading with different number of parameters, because there is no + // confusion on what function will be called. + f.getNumberOfParameters() = c.getNumberOfParameters() and + //build a dynamic select statement that guarantees to read that the overloading function is the explicit one + if + (f instanceof CopyConstructor or f instanceof MoveConstructor) and + f.isCompilerGenerated() + then ( + ( + f instanceof CopyConstructor and + msg = "implicit copy constructor" + or + f instanceof MoveConstructor and + msg = "implicit move constructor" + ) and + firstMsgSegment = " with a forwarding reference parameter " and + overloaded = f and + overload = c + ) else ( + msg = "function with a forwarding reference parameter" and + firstMsgSegment = " " and + overloaded = c and + overload = f + ) +select overload, "Function" + firstMsgSegment + "overloads a $@.", overloaded, msg diff --git a/cpp/autosar/src/rules/A15-4-4/MissingNoExcept.ql b/cpp/autosar/src/rules/A15-4-4/MissingNoExcept.ql index 0226c20d30..7701a8a1ea 100644 --- a/cpp/autosar/src/rules/A15-4-4/MissingNoExcept.ql +++ b/cpp/autosar/src/rules/A15-4-4/MissingNoExcept.ql @@ -33,5 +33,7 @@ where // The function is defined in this database f.hasDefinition() and // This function is not an overriden call operator of a lambda expression - not exists(LambdaExpression lambda | lambda.getLambdaFunction() = f) -select f, "Function " + f.getName() + " could be declared noexcept(true)." + not exists(LambdaExpression lambda | lambda.getLambdaFunction() = f) and + // Exclude results from uinstantiated templates + not f.isFromUninstantiatedTemplate(_) +select f, "Function " + f.getQualifiedName() + " could be declared noexcept(true)." diff --git a/cpp/autosar/src/rules/A16-0-1/PreProcessorShallOnlyBeUsedForCertainDirectivesPatterns.ql b/cpp/autosar/src/rules/A16-0-1/PreProcessorShallOnlyBeUsedForCertainDirectivesPatterns.ql index a8e1e59839..6a4182d538 100644 --- a/cpp/autosar/src/rules/A16-0-1/PreProcessorShallOnlyBeUsedForCertainDirectivesPatterns.ql +++ b/cpp/autosar/src/rules/A16-0-1/PreProcessorShallOnlyBeUsedForCertainDirectivesPatterns.ql @@ -21,13 +21,26 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.FunctionLikeMacro +class PermittedInnerDirectiveType extends PreprocessorDirective { + PermittedInnerDirectiveType() { + //permissive listing for directives that can be used in a valid wrapper + this instanceof MacroWrapper or + this instanceof PreprocessorEndif or + this instanceof Include or + this instanceof PermittedMacro or + this instanceof PreprocessorElif or + this instanceof PreprocessorElse + } +} + class PermittedDirectiveType extends PreprocessorDirective { PermittedDirectiveType() { //permissive listing in case directive types modelled in ql ever expands (example non valid directives) this instanceof MacroWrapper or this instanceof PreprocessorEndif or this instanceof Include or - this instanceof PermittedMacro + this instanceof PermittedMacro or + this instanceof PreprocessorElse } } @@ -40,9 +53,9 @@ pragma[noinline] predicate isPreprocConditionalRange( PreprocessorBranch pb, string filepath, int startLine, int endLine ) { - exists(PreprocessorEndif end | pb.getEndIf() = end | - isPreprocFileAndLine(pb, filepath, startLine) and - isPreprocFileAndLine(end, filepath, endLine) + isPreprocFileAndLine(pb, filepath, startLine) and + exists(PreprocessorDirective end | + pb.getNext() = end and isPreprocFileAndLine(end, filepath, endLine) ) } @@ -73,7 +86,7 @@ class MacroWrapper extends PreprocessorIfndef { class AcceptableWrapper extends PreprocessorBranch { AcceptableWrapper() { forall(Element inner | not inner instanceof Comment and this = getAGuard(inner) | - inner instanceof PermittedDirectiveType + inner instanceof PermittedInnerDirectiveType ) } } diff --git a/cpp/autosar/src/rules/A18-1-4/PointerToAnElementOfAnArrayPassedToASmartPointer.ql b/cpp/autosar/src/rules/A18-1-4/PointerToAnElementOfAnArrayPassedToASmartPointer.ql index 72496d703d..842dc14390 100644 --- a/cpp/autosar/src/rules/A18-1-4/PointerToAnElementOfAnArrayPassedToASmartPointer.ql +++ b/cpp/autosar/src/rules/A18-1-4/PointerToAnElementOfAnArrayPassedToASmartPointer.ql @@ -17,18 +17,14 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.SmartPointers import codingstandards.cpp.dataflow.TaintTracking -import DataFlow::PathGraph +import SingleObjectSmartPointerArrayConstructionFlow::PathGraph class AutosarSmartPointerArraySpecialisation extends AutosarSmartPointer { AutosarSmartPointerArraySpecialisation() { this.getOwnedObjectType() instanceof ArrayType } } -class SingleObjectSmartPointerArrayConstructionConfig extends TaintTracking::Configuration { - SingleObjectSmartPointerArrayConstructionConfig() { - this = "SingleObjectSmartPointerArrayConstructionConfig" - } - - override predicate isSource(DataFlow::Node source) { +module SingleObjectSmartPointerArrayConstructionConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { source.asExpr() instanceof NewArrayExpr or source.asExpr() = any(FunctionCall fc, MemberFunction mf | @@ -40,7 +36,7 @@ class SingleObjectSmartPointerArrayConstructionConfig extends TaintTracking::Con ) } - override predicate isSink(DataFlow::Node sink) { + predicate isSink(DataFlow::Node sink) { exists(AutosarSmartPointer sp | not sp instanceof AutosarSmartPointerArraySpecialisation and ( @@ -51,7 +47,7 @@ class SingleObjectSmartPointerArrayConstructionConfig extends TaintTracking::Con ) } - override predicate isAdditionalTaintStep(DataFlow::Node source, DataFlow::Node sink) { + predicate isAdditionalFlowStep(DataFlow::Node source, DataFlow::Node sink) { exists(AutosarUniquePointer sp, FunctionCall fc | fc = sp.getAReleaseCall() and source.asExpr() = fc.getQualifier() and @@ -59,7 +55,7 @@ class SingleObjectSmartPointerArrayConstructionConfig extends TaintTracking::Con ) } - override predicate isSanitizerIn(DataFlow::Node node) { + predicate isBarrierIn(DataFlow::Node node) { // Exclude flow into header files outside the source archive which are summarized by the // additional taint steps above. exists(AutosarUniquePointer sp | @@ -70,12 +66,15 @@ class SingleObjectSmartPointerArrayConstructionConfig extends TaintTracking::Con } } +module SingleObjectSmartPointerArrayConstructionFlow = + TaintTracking::Global; + from - SingleObjectSmartPointerArrayConstructionConfig config, DataFlow::PathNode source, - DataFlow::PathNode sink + SingleObjectSmartPointerArrayConstructionFlow::PathNode source, + SingleObjectSmartPointerArrayConstructionFlow::PathNode sink where not isExcluded(sink.getNode().asExpr(), PointersPackage::pointerToAnElementOfAnArrayPassedToASmartPointerQuery()) and - config.hasFlowPath(source, sink) + SingleObjectSmartPointerArrayConstructionFlow::flowPath(source, sink) select sink.getNode(), source, sink, "A pointer to an element of an array of objects flows to a smart pointer of a single object type." diff --git a/cpp/autosar/src/rules/A2-3-1/InvalidCharacterInStringLiteral.ql b/cpp/autosar/src/rules/A2-3-1/InvalidCharacterInStringLiteral.ql index 93109bcd30..4f215d7d9c 100644 --- a/cpp/autosar/src/rules/A2-3-1/InvalidCharacterInStringLiteral.ql +++ b/cpp/autosar/src/rules/A2-3-1/InvalidCharacterInStringLiteral.ql @@ -17,6 +17,7 @@ import cpp import codingstandards.cpp.autosar +import codingstandards.cpp.Literals bindingset[s] string getCharOutsideBasicSourceCharSet(string s) { @@ -27,6 +28,9 @@ string getCharOutsideBasicSourceCharSet(string s) { from StringLiteral s, string ch where not isExcluded(s, NamingPackage::invalidCharacterInStringLiteralQuery()) and - ch = getCharOutsideBasicSourceCharSet(s.getValueText()) + ch = getCharOutsideBasicSourceCharSet(s.getValueText()) and + // wide string and utf8 string literals are exempted. + not s instanceof WideStringLiteral and + not s instanceof Utf8StringLiteral select s, "String literal uses the character '" + ch + "' that is outside the language basic character set." diff --git a/cpp/autosar/src/rules/A3-9-1/VariableWidthIntegerTypesUsed.ql b/cpp/autosar/src/rules/A3-9-1/VariableWidthIntegerTypesUsed.ql index 699b79ae61..460457e0f8 100644 --- a/cpp/autosar/src/rules/A3-9-1/VariableWidthIntegerTypesUsed.ql +++ b/cpp/autosar/src/rules/A3-9-1/VariableWidthIntegerTypesUsed.ql @@ -1,8 +1,8 @@ /** * @id cpp/autosar/variable-width-integer-types-used * @name A3-9-1: Use fixed-width integer types instead of basic, variable-width, integer types - * @description The basic numerical types of char, int, short, long are not supposed to be used. The - * specific-length types from header need be used instead. + * @description The basic numerical types of signed/unsigned char, int, short, long are not supposed + * to be used. The specific-length types from header need be used instead. * @kind problem * @precision very-high * @problem.severity error @@ -19,15 +19,16 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.EncapsulatingFunctions import codingstandards.cpp.BuiltInNumericTypes +import codingstandards.cpp.Type -from Variable v +from Variable v, Type typeStrippedOfSpecifiers where not isExcluded(v, DeclarationsPackage::variableWidthIntegerTypesUsedQuery()) and + typeStrippedOfSpecifiers = stripSpecifiers(v.getType()) and ( - v.getType() instanceof BuiltInIntegerType or - v.getType() instanceof PlainCharType or - v.getType() instanceof UnsignedCharType or - v.getType() instanceof SignedCharType + typeStrippedOfSpecifiers instanceof BuiltInIntegerType or + typeStrippedOfSpecifiers instanceof UnsignedCharType or + typeStrippedOfSpecifiers instanceof SignedCharType ) and not v instanceof ExcludedVariable select v, "Variable '" + v.getName() + "' has variable-width type." diff --git a/cpp/autosar/src/rules/A3-9-1/VariableWidthPlainCharTypeUsed.ql b/cpp/autosar/src/rules/A3-9-1/VariableWidthPlainCharTypeUsed.ql new file mode 100644 index 0000000000..20f74bb511 --- /dev/null +++ b/cpp/autosar/src/rules/A3-9-1/VariableWidthPlainCharTypeUsed.ql @@ -0,0 +1,26 @@ +/** + * @id cpp/autosar/variable-width-plain-char-type-used + * @name A3-9-1: Use a fixed-width integer type instead of a char type + * @description The basic numerical type char is not supposed to be used. The specific-length types + * from header need be used instead. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/autosar/id/a3-9-1 + * correctness + * security + * maintainability + * external/autosar/allocated-target/implementation + * external/autosar/enforcement/automated + * external/autosar/obligation/required + */ + +import cpp +import codingstandards.cpp.autosar +import codingstandards.cpp.Type + +from Variable variable +where + not isExcluded(variable, DeclarationsPackage::variableWidthPlainCharTypeUsedQuery()) and + stripSpecifiers(variable.getType()) instanceof PlainCharType +select variable, "Variable '" + variable.getName() + "' has variable-width char type." diff --git a/cpp/autosar/src/rules/A4-5-1/EnumUsedInArithmeticContexts.ql b/cpp/autosar/src/rules/A4-5-1/EnumUsedInArithmeticContexts.ql index 3f21a66580..af69a4dca4 100644 --- a/cpp/autosar/src/rules/A4-5-1/EnumUsedInArithmeticContexts.ql +++ b/cpp/autosar/src/rules/A4-5-1/EnumUsedInArithmeticContexts.ql @@ -18,44 +18,26 @@ import cpp import codingstandards.cpp.autosar +import codingstandards.cpp.Operator +import codingstandards.cpp.Type -/* - * Get an operand to all overloaded operator member functions, except: - * operator[] - * operator= - * operator== - * operator!= - * operator& - * operator< - * operator<= - * operator> - * operator>= - */ - -Expr getAnOperandOfAllowedOverloadedOperator(FunctionCall fc) { - fc.getAnArgument() = result and - fc.getTarget().getName().regexpMatch("operator(?!\\[]$|=$|==$|!=$|&$|<$|<=$|>$|>=$).+") -} - -Expr getAnOperandOfAllowedOperation(Operation o) { - o.getAnOperand() = result and - not ( - o instanceof AssignExpr or - o instanceof BitwiseAndExpr or - o instanceof ComparisonOperation - ) +class AllowedOperatorUse extends OperatorUse { + AllowedOperatorUse() { + this.getOperator() in ["[]", "=", "==", "!=", "<", "<=", ">", ">="] + or + this.(UnaryOperatorUse).getOperator() = "&" + } } -from Expr e, Expr operand +from OperatorUse operatorUse, Access access, Enum enum where - not isExcluded(e, ExpressionsPackage::enumUsedInArithmeticContextsQuery()) and + not isExcluded(access, ExpressionsPackage::enumUsedInArithmeticContextsQuery()) and + operatorUse.getAnOperand() = access and ( - operand = getAnOperandOfAllowedOverloadedOperator(e) - or - operand = getAnOperandOfAllowedOperation(e) + access.(EnumConstantAccess).getTarget().getDeclaringEnum() = enum or + access.(VariableAccess).getType() = enum ) and - ( - operand instanceof EnumConstantAccess or - operand.(VariableAccess).getType() instanceof Enum - ) -select e, "Enum $@ is used as an operand of arithmetic operation.", operand, "expression" + not operatorUse instanceof AllowedOperatorUse and + // Enums that implement the BitmaskType trait are an exception. + not enum instanceof BitmaskType +select access, "Enum $@ is used as an operand of arithmetic operation.", enum, enum.getName() diff --git a/cpp/autosar/src/rules/A4-7-1/IntegerExpressionLeadToDataLoss.ql b/cpp/autosar/src/rules/A4-7-1/IntegerExpressionLeadToDataLoss.ql index aae951351a..a6d7abc456 100644 --- a/cpp/autosar/src/rules/A4-7-1/IntegerExpressionLeadToDataLoss.ql +++ b/cpp/autosar/src/rules/A4-7-1/IntegerExpressionLeadToDataLoss.ql @@ -30,5 +30,7 @@ where not e instanceof MulExpr and // Not covered by this query - overflow/underflow in division is rare not e instanceof DivExpr and - not e instanceof RemExpr + not e instanceof AssignDivExpr and + not e instanceof RemExpr and + not e instanceof AssignRemExpr select e, "Binary expression ..." + e.getOperator() + "... may overflow." diff --git a/cpp/autosar/src/rules/A5-0-4/PointerArithmeticUsedWithPointersToNonFinalClasses.ql b/cpp/autosar/src/rules/A5-0-4/PointerArithmeticUsedWithPointersToNonFinalClasses.ql index 6caf641446..34b6660778 100644 --- a/cpp/autosar/src/rules/A5-0-4/PointerArithmeticUsedWithPointersToNonFinalClasses.ql +++ b/cpp/autosar/src/rules/A5-0-4/PointerArithmeticUsedWithPointersToNonFinalClasses.ql @@ -18,7 +18,7 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.Type import codingstandards.cpp.dataflow.DataFlow -import DataFlow::PathGraph +import NonFinalClassToPointerArithmeticExprFlow::PathGraph class ArrayAccessOrPointerArith extends Expr { ArrayAccessOrPointerArith() { @@ -42,12 +42,8 @@ class AddressOfPointerCreation extends ClassPointerCreation, AddressOfExpr { AddressOfPointerCreation() { this.getAnOperand().getUnderlyingType() instanceof Class } } -class NonFinalClassToPointerArithmeticExprConfig extends DataFlow::Configuration { - NonFinalClassToPointerArithmeticExprConfig() { - this = "NonFinalClassToPointerArithmeticExprConfig" - } - - override predicate isSource(DataFlow::Node source) { +module NonFinalClassToPointerArithmeticExprConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { exists(Class c | source.asExpr() instanceof ClassPointerCreation and source.asExpr().getUnderlyingType().(PointerType).getBaseType() = c @@ -56,17 +52,21 @@ class NonFinalClassToPointerArithmeticExprConfig extends DataFlow::Configuration ) } - override predicate isSink(DataFlow::Node sink) { + predicate isSink(DataFlow::Node sink) { exists(ArrayAccessOrPointerArith e | e.getAnOperand() = sink.asExpr()) } } +module NonFinalClassToPointerArithmeticExprFlow = + DataFlow::Global; + from - ArrayAccessOrPointerArith e, Class clz, Variable v, DataFlow::PathNode source, - DataFlow::PathNode sink + ArrayAccessOrPointerArith e, Class clz, Variable v, + NonFinalClassToPointerArithmeticExprFlow::PathNode source, + NonFinalClassToPointerArithmeticExprFlow::PathNode sink where not isExcluded(e, PointersPackage::pointerArithmeticUsedWithPointersToNonFinalClassesQuery()) and - any(NonFinalClassToPointerArithmeticExprConfig c).hasFlowPath(source, sink) and + NonFinalClassToPointerArithmeticExprFlow::flowPath(source, sink) and v.getAnAssignedValue() = source.getNode().asExpr() and ( e.(PointerArithmeticOperation).getAnOperand() = sink.getNode().asExpr() diff --git a/cpp/autosar/src/rules/A5-1-7/LambdaPassedToDecltype.ql b/cpp/autosar/src/rules/A5-1-7/LambdaPassedToDecltype.ql index da33fd5a78..afbd809664 100644 --- a/cpp/autosar/src/rules/A5-1-7/LambdaPassedToDecltype.ql +++ b/cpp/autosar/src/rules/A5-1-7/LambdaPassedToDecltype.ql @@ -17,26 +17,27 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.dataflow.DataFlow -class LambdaExpressionToInitializer extends DataFlow::Configuration { - LambdaExpressionToInitializer() { this = "LambdaExpressionToInitializer" } +module LambdaExpressionToInitializerConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { source.asExpr() instanceof LambdaExpression } - override predicate isSource(DataFlow::Node source) { source.asExpr() instanceof LambdaExpression } - - override predicate isSink(DataFlow::Node sink) { + predicate isSink(DataFlow::Node sink) { exists(Variable v | v.getInitializer().getExpr() = sink.asExpr()) } } +module LambdaExpressionToInitializerFlow = DataFlow::Global; + from Decltype dt, LambdaExpression lambda where not isExcluded(dt, LambdasPackage::lambdaPassedToDecltypeQuery()) and ( dt.getExpr() = lambda or - exists(LambdaExpressionToInitializer config, VariableAccess va, Variable v | + exists(VariableAccess va, Variable v | dt.getExpr() = va and v = va.getTarget() and - config.hasFlow(DataFlow::exprNode(lambda), DataFlow::exprNode(v.getInitializer().getExpr())) + LambdaExpressionToInitializerFlow::flow(DataFlow::exprNode(lambda), + DataFlow::exprNode(v.getInitializer().getExpr())) ) ) select dt, "Lambda $@ passed as operand to decltype.", lambda, "expression" diff --git a/cpp/autosar/src/rules/A5-1-7/LambdaPassedToTypeid.ql b/cpp/autosar/src/rules/A5-1-7/LambdaPassedToTypeid.ql index d43568af21..08dbecc755 100644 --- a/cpp/autosar/src/rules/A5-1-7/LambdaPassedToTypeid.ql +++ b/cpp/autosar/src/rules/A5-1-7/LambdaPassedToTypeid.ql @@ -16,21 +16,19 @@ import cpp import codingstandards.cpp.dataflow.DataFlow import codingstandards.cpp.autosar -import DataFlow::PathGraph +import LambdaExpressionToTypeidFlow::PathGraph -class LambdaExpressionToTypeid extends DataFlow::Configuration { - LambdaExpressionToTypeid() { this = "LambdaExpressionToTypeid" } +module LambdaExpressionToTypeidConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { source.asExpr() instanceof LambdaExpression } - override predicate isSource(DataFlow::Node source) { source.asExpr() instanceof LambdaExpression } - - override predicate isSink(DataFlow::Node sink) { - exists(TypeidOperator op | op.getExpr() = sink.asExpr()) - } + predicate isSink(DataFlow::Node sink) { exists(TypeidOperator op | op.getExpr() = sink.asExpr()) } } -from DataFlow::PathNode source, DataFlow::PathNode sink +module LambdaExpressionToTypeidFlow = DataFlow::Global; + +from LambdaExpressionToTypeidFlow::PathNode source, LambdaExpressionToTypeidFlow::PathNode sink where not isExcluded(source.getNode().asExpr(), LambdasPackage::lambdaPassedToTypeidQuery()) and - any(LambdaExpressionToTypeid config).hasFlowPath(source, sink) + LambdaExpressionToTypeidFlow::flowPath(source, sink) select sink.getNode(), source, sink, "Lambda $@ passed as operand to typeid operator.", source.getNode(), "expression" diff --git a/cpp/autosar/src/rules/A7-1-1/DeclarationUnmodifiedObjectMissingConstSpecifier.ql b/cpp/autosar/src/rules/A7-1-1/DeclarationUnmodifiedObjectMissingConstSpecifier.ql index d85a638530..ff7d7e4e27 100644 --- a/cpp/autosar/src/rules/A7-1-1/DeclarationUnmodifiedObjectMissingConstSpecifier.ql +++ b/cpp/autosar/src/rules/A7-1-1/DeclarationUnmodifiedObjectMissingConstSpecifier.ql @@ -36,5 +36,6 @@ where else cond = " is used for an object" ) and not exists(LambdaExpression lc | lc.getACapture().getField() = v) and - not v.isFromUninstantiatedTemplate(_) + not v.isFromUninstantiatedTemplate(_) and + not v.isCompilerGenerated() select v, "Non-constant variable " + v.getName() + cond + " and is not modified." diff --git a/cpp/autosar/src/rules/A7-1-1/DeclarationUnmodifiedParamMissingConstSpecifier.ql b/cpp/autosar/src/rules/A7-1-1/DeclarationUnmodifiedParamMissingConstSpecifier.ql deleted file mode 100644 index d4ecbdebfa..0000000000 --- a/cpp/autosar/src/rules/A7-1-1/DeclarationUnmodifiedParamMissingConstSpecifier.ql +++ /dev/null @@ -1,42 +0,0 @@ -/** - * @id cpp/autosar/declaration-unmodified-param-missing-const-specifier - * @name A7-1-1: Constexpr or const specifiers shall be used for immutable parameter usage - * @description `Constexpr`/`const` specifiers prevent unintentional data modification for - * parameters intended as immutable. - * @kind problem - * @precision high - * @problem.severity warning - * @tags external/autosar/id/a7-1-1 - * correctness - * maintainability - * readability - * external/autosar/allocated-target/implementation - * external/autosar/enforcement/automated - * external/autosar/obligation/required - */ - -import cpp -import codingstandards.cpp.autosar -import codingstandards.cpp.ConstHelpers - -from FunctionParameter v, string cond -where - not isExcluded(v, ConstPackage::declarationUnmodifiedParamMissingConstSpecifierQuery()) and - v instanceof AccessedParameter and - ( - isNotDirectlyModified(v) and - not v.getAnAccess().isAddressOfAccessNonConst() and - notPassedAsArgToNonConstParam(v) and - notAssignedToNonLocalNonConst(v) and - if v instanceof NonConstPointerorReferenceParameter - then - notUsedAsQualifierForNonConst(v) and - notReturnedFromNonConstFunction(v) and - cond = " points to an object" - else cond = " is used for an object" - ) and - //exclude already consts - if v.getType() instanceof ReferenceType - then not v.getType().(DerivedType).getBaseType+().isConst() - else not v.getType().isConst() -select v, "Non-constant parameter " + v.getName() + cond + " and is not modified." diff --git a/cpp/autosar/src/rules/A7-1-2/VariableMissingConstexpr.ql b/cpp/autosar/src/rules/A7-1-2/VariableMissingConstexpr.ql index e3981b3836..3c2ae9a592 100644 --- a/cpp/autosar/src/rules/A7-1-2/VariableMissingConstexpr.ql +++ b/cpp/autosar/src/rules/A7-1-2/VariableMissingConstexpr.ql @@ -17,6 +17,7 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.TrivialType import codingstandards.cpp.SideEffect +import semmle.code.cpp.controlflow.SSA predicate isZeroInitializable(Variable v) { not exists(v.getInitializer().getExpr()) and @@ -33,6 +34,78 @@ predicate isTypeZeroInitializable(Type t) { t.getUnderlyingType() instanceof ArrayType } +/** + * An optimized set of expressions used to determine the flow through constexpr variables. + */ +class VariableAccessOrCallOrLiteral extends Expr { + VariableAccessOrCallOrLiteral() { + this instanceof VariableAccess or + this instanceof Call or + this instanceof Literal + } +} + +/** + * Holds if the value of source flows through compile time evaluated variables to target. + */ +predicate flowsThroughConstExprVariables( + VariableAccessOrCallOrLiteral source, VariableAccessOrCallOrLiteral target +) { + ( + source = target + or + source != target and + exists(SsaDefinition intermediateDef, StackVariable intermediate | + intermediateDef.getAVariable().getFunction() = source.getEnclosingFunction() and + intermediateDef.getAVariable().getFunction() = target.getEnclosingFunction() and + intermediateDef.getAVariable() = intermediate and + intermediate.isConstexpr() + | + DataFlow::localExprFlow(source, intermediateDef.getDefiningValue(intermediate)) and + flowsThroughConstExprVariables(intermediateDef.getAUse(intermediate), target) + ) + ) +} + +/* + * Returns true if the given call may be evaluated at compile time and is compile time evaluated because + * all its arguments are compile time evaluated and its default values are compile time evaluated. + */ + +predicate isCompileTimeEvaluated(Call call) { + // 1. The call may be evaluated at compile time, because it is constexpr, and + call.getTarget().isConstexpr() and + // 2. all its arguments are compile time evaluated, and + forall(DataFlow::Node ultimateArgSource, DataFlow::Node argSource | + argSource = DataFlow::exprNode(call.getAnArgument()) and + DataFlow::localFlow(ultimateArgSource, argSource) and + not DataFlow::localFlowStep(_, ultimateArgSource) + | + ( + ultimateArgSource.asExpr() instanceof Literal + or + any(Call c | isCompileTimeEvaluated(c)) = ultimateArgSource.asExpr() + ) and + // If the ultimate argument source is not the same as the argument source, then it must flow through + // constexpr variables. + ( + ultimateArgSource != argSource + implies + flowsThroughConstExprVariables(ultimateArgSource.asExpr(), argSource.asExpr()) + ) + ) and + // 3. all the default values used are compile time evaluated. + forall(Expr defaultValue, Parameter parameterUsingDefaultValue, int idx | + parameterUsingDefaultValue = call.getTarget().getParameter(idx) and + not exists(call.getArgument(idx)) and + parameterUsingDefaultValue.getAnAssignedValue() = defaultValue + | + defaultValue instanceof Literal + or + any(Call c | isCompileTimeEvaluated(c)) = defaultValue + ) +} + from Variable v where not isExcluded(v, ConstPackage::variableMissingConstexprQuery()) and @@ -46,7 +119,7 @@ where ( v.getInitializer().getExpr().isConstant() or - v.getInitializer().getExpr().(Call).getTarget().isConstexpr() + any(Call call | isCompileTimeEvaluated(call)) = v.getInitializer().getExpr() or isZeroInitializable(v) or diff --git a/cpp/autosar/src/rules/A7-1-5/AutoSpecifierNotUsedAppropriatelyInVariableDefinition.ql b/cpp/autosar/src/rules/A7-1-5/AutoSpecifierNotUsedAppropriatelyInVariableDefinition.ql index 54b62720a9..7c91ade133 100644 --- a/cpp/autosar/src/rules/A7-1-5/AutoSpecifierNotUsedAppropriatelyInVariableDefinition.ql +++ b/cpp/autosar/src/rules/A7-1-5/AutoSpecifierNotUsedAppropriatelyInVariableDefinition.ql @@ -19,6 +19,10 @@ import cpp import codingstandards.cpp.autosar +class FundamentalType extends BuiltInType { + FundamentalType() { not this instanceof ErroneousType and not this instanceof UnknownType } +} + from Variable v where not isExcluded(v, @@ -28,12 +32,14 @@ where // exclude uninstantiated templates and rely on the instantiated templates, because an uninstantiated template may not contain the information required to determine if the usage is allowed. not v.isFromUninstantiatedTemplate(_) and not ( - // find ones where + // Initialized by function call v.getInitializer().getExpr() instanceof FunctionCall or + // Initialized by lambda expression v.getInitializer().getExpr() instanceof LambdaExpression or - v.getInitializer().getExpr() instanceof ClassAggregateLiteral + // Initialized by non-fundamental type + not v.getInitializer().getExpr().getType() instanceof FundamentalType ) and // Exclude compiler generated variables not v.isCompilerGenerated() diff --git a/cpp/autosar/src/rules/A8-4-7/InParametersForCheapToCopyTypesNotPassedByValue.ql b/cpp/autosar/src/rules/A8-4-7/InParametersForCheapToCopyTypesNotPassedByValue.ql index e188241672..78e9db28a4 100644 --- a/cpp/autosar/src/rules/A8-4-7/InParametersForCheapToCopyTypesNotPassedByValue.ql +++ b/cpp/autosar/src/rules/A8-4-7/InParametersForCheapToCopyTypesNotPassedByValue.ql @@ -17,6 +17,7 @@ import cpp import codingstandards.cpp.autosar import TriviallySmallType import codingstandards.cpp.CommonTypes as CommonTypes +import codingstandards.cpp.Class /* * For the purposes of this rule, "cheap to copy" is defined as a trivially copyable type that is no @@ -34,8 +35,10 @@ where ) and t.isConst() and not exists(CatchBlock cb | cb.getParameter() = v) and - not exists(CopyConstructor cc | cc.getAParameter() = v) and - not v.isFromUninstantiatedTemplate(_) + not exists(SpecialMemberFunction cc | cc.getAParameter() = v) and + not exists(Operator op | op.getAParameter() = v) and + not v.isFromUninstantiatedTemplate(_) and + not v.isFromTemplateInstantiation(_) select v, - "Parameter " + v.getName() + " is the trivially copyable type " + t.getName() + - " but it is passed by reference instead of by value." + "Parameter '" + v.getName() + "' is the trivially copyable type '" + t.getName() + + "' but it is passed by reference instead of by value." diff --git a/cpp/autosar/src/rules/A8-4-7/InParametersForNotCheapToCopyTypesNotPassedByReference.ql b/cpp/autosar/src/rules/A8-4-7/InParametersForNotCheapToCopyTypesNotPassedByReference.ql index f6d481a54a..b96b9347d3 100644 --- a/cpp/autosar/src/rules/A8-4-7/InParametersForNotCheapToCopyTypesNotPassedByReference.ql +++ b/cpp/autosar/src/rules/A8-4-7/InParametersForNotCheapToCopyTypesNotPassedByReference.ql @@ -31,7 +31,8 @@ where not v.getType() instanceof TriviallySmallType and not v.getType().getUnderlyingType() instanceof ReferenceType and not exists(CatchBlock cb | cb.getParameter() = v) and - not v.isFromUninstantiatedTemplate(_) + not v.isFromUninstantiatedTemplate(_) and + not v.isFromTemplateInstantiation(_) select v, "Parameter " + v.getName() + " is the trivially non-copyable type $@ but it is passed by value instead of by reference.", diff --git a/cpp/autosar/src/rules/M5-0-17/PointerSubtractionOnDifferentArrays.ql b/cpp/autosar/src/rules/M5-0-17/PointerSubtractionOnDifferentArrays.ql index dd8fbaa553..ec432cea42 100644 --- a/cpp/autosar/src/rules/M5-0-17/PointerSubtractionOnDifferentArrays.ql +++ b/cpp/autosar/src/rules/M5-0-17/PointerSubtractionOnDifferentArrays.ql @@ -16,40 +16,41 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.dataflow.DataFlow -import DataFlow::PathGraph +import ArrayToPointerDiffOperandFlow::PathGraph -class ArrayToPointerDiffOperandConfig extends DataFlow::Configuration { - ArrayToPointerDiffOperandConfig() { this = "ArrayToPointerDiffOperandConfig" } - - override predicate isSource(DataFlow::Node source) { +module ArrayToPointerDiffOperandConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { source.asExpr().(VariableAccess).getType() instanceof ArrayType or // Consider array to pointer decay for parameters. source.asExpr().(VariableAccess).getTarget().(Parameter).getType() instanceof ArrayType } - override predicate isSink(DataFlow::Node sink) { + predicate isSink(DataFlow::Node sink) { exists(PointerDiffExpr e | e.getAnOperand() = sink.asExpr()) } - override predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) { + predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) { // Add a flow step from the base to the array expression to track pointers to elements of the array. exists(ArrayExpr e | e.getArrayBase() = pred.asExpr() and e = succ.asExpr()) } } +module ArrayToPointerDiffOperandFlow = DataFlow::Global; + from PointerDiffExpr pointerSubstraction, Variable currentOperandPointee, Variable otherOperandPointee, - DataFlow::PathNode source, DataFlow::PathNode sink, string side + ArrayToPointerDiffOperandFlow::PathNode source, ArrayToPointerDiffOperandFlow::PathNode sink, + string side where not isExcluded(pointerSubstraction, PointersPackage::pointerSubtractionOnDifferentArraysQuery()) and - exists(ArrayToPointerDiffOperandConfig c, Variable sourceLeft, Variable sourceRight | - c.hasFlow(DataFlow::exprNode(sourceLeft.getAnAccess()), + exists(Variable sourceLeft, Variable sourceRight | + ArrayToPointerDiffOperandFlow::flow(DataFlow::exprNode(sourceLeft.getAnAccess()), DataFlow::exprNode(pointerSubstraction.getLeftOperand())) and - c.hasFlow(DataFlow::exprNode(sourceRight.getAnAccess()), + ArrayToPointerDiffOperandFlow::flow(DataFlow::exprNode(sourceRight.getAnAccess()), DataFlow::exprNode(pointerSubstraction.getRightOperand())) and not sourceLeft = sourceRight and - c.hasFlowPath(source, sink) and + ArrayToPointerDiffOperandFlow::flowPath(source, sink) and ( source.getNode().asExpr() = sourceLeft.getAnAccess() and sink.getNode().asExpr() = pointerSubstraction.getLeftOperand() and diff --git a/cpp/autosar/src/rules/M7-3-6/UsingDeclarationsUsedInHeaderFiles.ql b/cpp/autosar/src/rules/M7-3-6/UsingDeclarationsUsedInHeaderFiles.ql index 84b8c45a86..5a2a1e7b30 100644 --- a/cpp/autosar/src/rules/M7-3-6/UsingDeclarationsUsedInHeaderFiles.ql +++ b/cpp/autosar/src/rules/M7-3-6/UsingDeclarationsUsedInHeaderFiles.ql @@ -28,5 +28,13 @@ predicate isInClassScope(UsingEntry u) { exists(Class c | u.getEnclosingElement( from UsingEntry u where not isExcluded(u, BannedSyntaxPackage::usingDeclarationsUsedInHeaderFilesQuery()) and - (isInHeaderFile(u) and not isInFunctionScope(u) and not isInClassScope(u)) + isInHeaderFile(u) and + ( + u instanceof UsingDeclarationEntry + implies + ( + not isInFunctionScope(u) and + not isInClassScope(u) + ) + ) select u, "Using directive or declaration used in a header file " + u.getFile() + "." diff --git a/cpp/autosar/src/rules/M9-3-3/MemberFunctionConstIfPossible.ql b/cpp/autosar/src/rules/M9-3-3/MemberFunctionConstIfPossible.ql index 3b0ee9c058..66a3affa24 100644 --- a/cpp/autosar/src/rules/M9-3-3/MemberFunctionConstIfPossible.ql +++ b/cpp/autosar/src/rules/M9-3-3/MemberFunctionConstIfPossible.ql @@ -54,7 +54,10 @@ class ConstMemberFunctionCandidate extends NonConstMemberFunction { not this instanceof Destructor and not this instanceof Operator and //less interested in MemberFunctions with no definition - this.hasDefinition() + this.hasDefinition() and + // For uninstantiated templates we have only partial information that prevents us from determining + // if the candidate calls non-const functions. Therefore we exclude these. + not this.isFromUninstantiatedTemplate(_) } /** @@ -121,5 +124,6 @@ where not f.callsNonConstOwnMember() and not f.callsNonConstFromMemberVariable() and not f.isOverride() and - not f.isFinal() + not f.isFinal() and + not f.isDeleted() select f, "Member function can be declared as const." diff --git a/cpp/autosar/src/rules/M9-3-3/MemberFunctionStaticIfPossible.ql b/cpp/autosar/src/rules/M9-3-3/MemberFunctionStaticIfPossible.ql index 36c13fe5d3..5148e72f79 100644 --- a/cpp/autosar/src/rules/M9-3-3/MemberFunctionStaticIfPossible.ql +++ b/cpp/autosar/src/rules/M9-3-3/MemberFunctionStaticIfPossible.ql @@ -39,5 +39,6 @@ from NonStaticMemberFunction nonstatic where not isExcluded(nonstatic, ConstPackage::memberFunctionStaticIfPossibleQuery()) and not exists(ThisExpr t | t.getEnclosingFunction() = nonstatic) and - not nonstatic.isVirtual() + not nonstatic.isVirtual() and + not nonstatic.isDeleted() select nonstatic, "Member function can be declared as static." diff --git a/cpp/autosar/test/rules/A0-1-1/test.cpp b/cpp/autosar/test/rules/A0-1-1/test.cpp index 824d649c6a..021b1bf792 100644 --- a/cpp/autosar/test/rules/A0-1-1/test.cpp +++ b/cpp/autosar/test/rules/A0-1-1/test.cpp @@ -112,4 +112,15 @@ int test_useless_assignment(int &x, int p) { return y; } -int main() { return 0; } \ No newline at end of file +int main() { return 0; } + +#include +template void test_range_based_for_loop_template() { + std::vector values_; + for (auto &elem : values_) { // COMPLIANT - should not report either elem or + // the compiler generated (__range) + // variable in the uninstantiated + // template + elem; + } +} \ No newline at end of file diff --git a/cpp/autosar/test/rules/A13-3-1/FunctionThatContainsForwardingReferenceAsItsArgumentOverloaded.expected b/cpp/autosar/test/rules/A13-3-1/FunctionThatContainsForwardingReferenceAsItsArgumentOverloaded.expected index 590f891ead..6e79cb00a4 100644 --- a/cpp/autosar/test/rules/A13-3-1/FunctionThatContainsForwardingReferenceAsItsArgumentOverloaded.expected +++ b/cpp/autosar/test/rules/A13-3-1/FunctionThatContainsForwardingReferenceAsItsArgumentOverloaded.expected @@ -1,5 +1,7 @@ -| test.cpp:24:6:24:7 | F1 | Function overloads a $@ with a forwarding reference parameter. | test.cpp:27:25:27:26 | F1 | function | -| test.cpp:49:3:49:3 | A | Function overloads a $@ with a forwarding reference parameter. | test.cpp:47:3:47:3 | A | function | -| test.cpp:50:3:50:3 | A | Function overloads a $@ with a forwarding reference parameter. | test.cpp:47:3:47:3 | A | function | -| test.cpp:63:8:63:8 | B | Function overloads a $@ with a forwarding reference parameter. | test.cpp:66:3:66:3 | B | function | -| test.cpp:63:8:63:8 | B | Function overloads a $@ with a forwarding reference parameter. | test.cpp:66:3:66:3 | B | function | +| test.cpp:24:6:24:7 | F1 | Function overloads a $@. | test.cpp:27:25:27:26 | F1 | function with a forwarding reference parameter | +| test.cpp:50:3:50:3 | A | Function overloads a $@. | test.cpp:48:3:48:3 | A | function with a forwarding reference parameter | +| test.cpp:51:3:51:3 | A | Function overloads a $@. | test.cpp:48:3:48:3 | A | function with a forwarding reference parameter | +| test.cpp:69:3:69:3 | B | Function with a forwarding reference parameter overloads a $@. | test.cpp:64:8:64:8 | B | implicit copy constructor | +| test.cpp:69:3:69:3 | B | Function with a forwarding reference parameter overloads a $@. | test.cpp:64:8:64:8 | B | implicit move constructor | +| test.cpp:77:25:77:25 | C | Function with a forwarding reference parameter overloads a $@. | test.cpp:74:7:74:7 | C | implicit copy constructor | +| test.cpp:77:25:77:25 | C | Function with a forwarding reference parameter overloads a $@. | test.cpp:74:7:74:7 | C | implicit move constructor | diff --git a/cpp/autosar/test/rules/A13-3-1/test.cpp b/cpp/autosar/test/rules/A13-3-1/test.cpp index 4a706b53e2..82fe866a0a 100644 --- a/cpp/autosar/test/rules/A13-3-1/test.cpp +++ b/cpp/autosar/test/rules/A13-3-1/test.cpp @@ -39,7 +39,8 @@ template void F1(T &&x) {} // class A { public: - // COMPLIANT by exception, constrained to not match copy/move ctors + // COMPLIANT[FALSE_POSITIVE] - by exception, constrained to not match + // copy/move ctors template < typename T, std::enable_if_t::value> * = nullptr> - B(T &&value) {} + template < + typename T, + std::enable_if_t>, A>::value> * = nullptr> + B(T &&value) {} // COMPLIANT[FALSE_POSITIVE] - by exception }; -int main() {} \ No newline at end of file +int main() {} + +class C { +public: + C() {} + template C(T &&) {} // NON_COMPLIANT +}; \ No newline at end of file diff --git a/cpp/autosar/test/rules/A15-4-2/NoExceptFunctionThrows.expected b/cpp/autosar/test/rules/A15-4-2/NoExceptFunctionThrows.expected index 2a0726c356..b2f8391b15 100644 --- a/cpp/autosar/test/rules/A15-4-2/NoExceptFunctionThrows.expected +++ b/cpp/autosar/test/rules/A15-4-2/NoExceptFunctionThrows.expected @@ -1,11 +1,19 @@ edges | test.cpp:5:3:5:20 | throw ... [ExceptionA] | test.cpp:4:6:4:15 | test_throw [ExceptionA] | -| test.cpp:8:6:8:11 | throwA [ExceptionA] | test.cpp:11:3:11:8 | call to throwA [ExceptionA] | -| test.cpp:8:6:8:11 | throwA [ExceptionA] | test.cpp:15:3:15:8 | call to throwA [ExceptionA] | +| test.cpp:8:6:8:11 | throwA [ExceptionA] | test.cpp:9:25:9:30 | call to throwA [ExceptionA] | +| test.cpp:8:6:8:11 | throwA [ExceptionA] | test.cpp:10:42:10:47 | call to throwA [ExceptionA] | +| test.cpp:8:6:8:11 | throwA [ExceptionA] | test.cpp:13:3:13:8 | call to throwA [ExceptionA] | +| test.cpp:8:6:8:11 | throwA [ExceptionA] | test.cpp:17:3:17:8 | call to throwA [ExceptionA] | | test.cpp:8:17:8:34 | throw ... [ExceptionA] | test.cpp:8:6:8:11 | throwA [ExceptionA] | -| test.cpp:11:3:11:8 | call to throwA [ExceptionA] | test.cpp:10:6:10:24 | test_indirect_throw [ExceptionA] | -| test.cpp:15:3:15:8 | call to throwA [ExceptionA] | test.cpp:14:6:14:26 | test_indirect_throw_2 [ExceptionA] | +| test.cpp:9:6:9:19 | indirectThrowA [ExceptionA] | test.cpp:34:3:34:16 | call to indirectThrowA [ExceptionA] | +| test.cpp:9:25:9:30 | call to throwA [ExceptionA] | test.cpp:9:6:9:19 | indirectThrowA [ExceptionA] | +| test.cpp:10:42:10:47 | call to throwA [ExceptionA] | test.cpp:10:6:10:27 | noexceptIndirectThrowA [ExceptionA] | +| test.cpp:13:3:13:8 | call to throwA [ExceptionA] | test.cpp:12:6:12:24 | test_indirect_throw [ExceptionA] | +| test.cpp:17:3:17:8 | call to throwA [ExceptionA] | test.cpp:16:6:16:26 | test_indirect_throw_2 [ExceptionA] | +| test.cpp:34:3:34:16 | call to indirectThrowA [ExceptionA] | test.cpp:33:6:33:26 | test_indirect_throw_6 [ExceptionA] | #select | test.cpp:4:6:4:15 | test_throw | test.cpp:5:3:5:20 | throw ... [ExceptionA] | test.cpp:4:6:4:15 | test_throw [ExceptionA] | Function test_throw is declared noexcept(true) but can throw exceptions of type ExceptionA. | -| test.cpp:10:6:10:24 | test_indirect_throw | test.cpp:8:17:8:34 | throw ... [ExceptionA] | test.cpp:10:6:10:24 | test_indirect_throw [ExceptionA] | Function test_indirect_throw is declared noexcept(true) but can throw exceptions of type ExceptionA. | -| test.cpp:14:6:14:26 | test_indirect_throw_2 | test.cpp:8:17:8:34 | throw ... [ExceptionA] | test.cpp:14:6:14:26 | test_indirect_throw_2 [ExceptionA] | Function test_indirect_throw_2 is declared noexcept(true) but can throw exceptions of type ExceptionA. | +| test.cpp:10:6:10:27 | noexceptIndirectThrowA | test.cpp:8:17:8:34 | throw ... [ExceptionA] | test.cpp:10:6:10:27 | noexceptIndirectThrowA [ExceptionA] | Function noexceptIndirectThrowA is declared noexcept(true) but can throw exceptions of type ExceptionA. | +| test.cpp:12:6:12:24 | test_indirect_throw | test.cpp:8:17:8:34 | throw ... [ExceptionA] | test.cpp:12:6:12:24 | test_indirect_throw [ExceptionA] | Function test_indirect_throw is declared noexcept(true) but can throw exceptions of type ExceptionA. | +| test.cpp:16:6:16:26 | test_indirect_throw_2 | test.cpp:8:17:8:34 | throw ... [ExceptionA] | test.cpp:16:6:16:26 | test_indirect_throw_2 [ExceptionA] | Function test_indirect_throw_2 is declared noexcept(true) but can throw exceptions of type ExceptionA. | +| test.cpp:33:6:33:26 | test_indirect_throw_6 | test.cpp:8:17:8:34 | throw ... [ExceptionA] | test.cpp:33:6:33:26 | test_indirect_throw_6 [ExceptionA] | Function test_indirect_throw_6 is declared noexcept(true) but can throw exceptions of type ExceptionA. | diff --git a/cpp/autosar/test/rules/A15-4-2/test.cpp b/cpp/autosar/test/rules/A15-4-2/test.cpp index afa46e5ae6..de5e00bd35 100644 --- a/cpp/autosar/test/rules/A15-4-2/test.cpp +++ b/cpp/autosar/test/rules/A15-4-2/test.cpp @@ -6,6 +6,8 @@ void test_throw() noexcept(true) { } void throwA() { throw ExceptionA(); } +void indirectThrowA() { throwA(); } +void noexceptIndirectThrowA() noexcept { throwA(); } // NON_COMPLIANT void test_indirect_throw() noexcept(true) { throwA(); // NON_COMPLIANT - function marked as noexcept(true) @@ -21,4 +23,13 @@ void test_indirect_throw_3() noexcept(false) { void test_indirect_throw_4() { throwA(); // COMPLIANT - function marked as noexcept(false) +} + +void test_indirect_throw_5() noexcept { + noexceptIndirectThrowA(); // COMPLIANT - noexceptIndirectThrowA would call + // std::terminate() if ExceptionA is thrown +} + +void test_indirect_throw_6() noexcept { + indirectThrowA(); // NON_COMPLIANT } \ No newline at end of file diff --git a/cpp/autosar/test/rules/A15-4-4/test.cpp b/cpp/autosar/test/rules/A15-4-4/test.cpp index f0b676373e..7d8597a75f 100644 --- a/cpp/autosar/test/rules/A15-4-4/test.cpp +++ b/cpp/autosar/test/rules/A15-4-4/test.cpp @@ -30,4 +30,17 @@ class A { void lambda_example() noexcept { auto with_capture = [=]() {}; auto empty_capture = []() {}; +} + +#include +template +void swap_wrapper(TypeA lhs, + TypeB rhs) noexcept(noexcept(std::swap(*lhs, *rhs))) { + std::swap(*lhs, *rhs); +} + +void test_swap_wrapper() noexcept { + int a = 0; + int b = 1; + swap_wrapper(&a, &b); } \ No newline at end of file diff --git a/cpp/autosar/test/rules/A16-0-1/PreProcessorShallOnlyBeUsedForCertainDirectivesPatterns.expected b/cpp/autosar/test/rules/A16-0-1/PreProcessorShallOnlyBeUsedForCertainDirectivesPatterns.expected index 5f6114bea8..44dd686b23 100644 --- a/cpp/autosar/test/rules/A16-0-1/PreProcessorShallOnlyBeUsedForCertainDirectivesPatterns.expected +++ b/cpp/autosar/test/rules/A16-0-1/PreProcessorShallOnlyBeUsedForCertainDirectivesPatterns.expected @@ -2,3 +2,7 @@ | test.cpp:9:1:9:26 | #define OBJECTLIKE_MACRO 1 | Preprocessor directive used for conditional compilation. | | test.cpp:10:1:10:35 | #define FUNCTIONLIKE_MACRO(X) X + 1 | Preprocessor directive used for conditional compilation. | | test.cpp:11:1:11:37 | #define FUNCTIONLIKE_MACROTWO() 1 + 1 | Preprocessor directive used for conditional compilation. | +| test.cpp:31:1:31:26 | #elif OBJECTLIKE_MACRO > 0 | Preprocessor directive used for conditional compilation. | +| test.cpp:37:1:37:26 | #elif OBJECTLIKE_MACRO > 0 | Preprocessor directive used for conditional compilation. | +| test.cpp:41:1:41:23 | #ifdef OBJECTLIKE_MACRO | Preprocessor directive used for conditional compilation. | +| test.cpp:58:1:58:27 | #elif MACRO_ENABLED_OTHER_1 | Preprocessor directive used for conditional compilation. | diff --git a/cpp/autosar/test/rules/A16-0-1/options b/cpp/autosar/test/rules/A16-0-1/options new file mode 100644 index 0000000000..9c0e6cf7b5 --- /dev/null +++ b/cpp/autosar/test/rules/A16-0-1/options @@ -0,0 +1 @@ +semmle-extractor-options:--clang -std=c++14 --edg --diag_error=implicit_func_decl -nostdinc -I../../../../../cpp/common/test/includes/standard-library -D MACRO_ENABLED_NON_1 -D MACRO_ENABLED_OTHER_1 diff --git a/cpp/autosar/test/rules/A16-0-1/test.cpp b/cpp/autosar/test/rules/A16-0-1/test.cpp index b1ee540032..a8b83e40ec 100644 --- a/cpp/autosar/test/rules/A16-0-1/test.cpp +++ b/cpp/autosar/test/rules/A16-0-1/test.cpp @@ -17,3 +17,59 @@ int g; #ifndef TESTHEADER // COMPLIANT #include //COMPLIANT #endif // COMPLIANT + +#ifdef MACRO_ENABLED // COMPLIANT +#include // COMPLIANT +#else // COMPLIANT +#include // COMPLIANT +#endif // COMPLIANT + +#ifdef MACRO_ENABLED_NON // COMPLIANT +#include // COMPLIANT +#elif MACRO_ENABLED_OTHER // COMPLIANT +#include // COMPLIANT +#elif OBJECTLIKE_MACRO > 0 // NON_COMPLIANT +int x00 = 1; // present +#endif // COMPLIANT + +#ifdef OBJECTLIKE_MACRO_NO // COMPLIANT +int x0 = 0; // not present +#elif OBJECTLIKE_MACRO > 0 // NON_COMPLIANT +int x0 = 1; // present +#endif // COMPLIANT + +#ifdef OBJECTLIKE_MACRO // NON_COMPLIANT +int x1 = 0; // present +#elif OBJECTLIKE_MACRO > -1 // NON_COMPLIANT[FALSE_NEGATIVE] - known due to + // database not containing elements +int x1 = 1; // not present +#endif // COMPLIANT + +// case 1 - first present only +#ifdef MACRO_ENABLED_NON_1 // COMPLIANT +#include //present +#elif MACRO_ENABLED_OTHER // NON_COMPLIANT[FALSE_NEGATIVE] +int x = 1; // not present +#endif + +// case 2 - second present only +#ifdef MACRO_ENABLED_NON // COMPLIANT +#include //not present +#elif MACRO_ENABLED_OTHER_1 // NON_COMPLIANT +int x = 1; // present +#endif + +// case 3 - neither present +#ifdef MACRO_ENABLED_NON // COMPLIANT +#include //not present +#elif MACRO_ENABLED_OTHER // NON_COMPLIANT[FALSE_NEGATIVE] +int x = 1; // not present +#endif + +// case 4 - both look present but the second still not bc the condition is not +// required to be evaluated +#ifdef MACRO_ENABLED_NON_1 // COMPLIANT +#include //present +#elif MACRO_ENABLED_OTHER_1 // NON_COMPLIANT[FALSE_NEGATIVE] +int x = 1; // not present +#endif \ No newline at end of file diff --git a/cpp/autosar/test/rules/A18-1-4/PointerToAnElementOfAnArrayPassedToASmartPointer.expected b/cpp/autosar/test/rules/A18-1-4/PointerToAnElementOfAnArrayPassedToASmartPointer.expected index a96c3fb64f..dcf263fc54 100644 --- a/cpp/autosar/test/rules/A18-1-4/PointerToAnElementOfAnArrayPassedToASmartPointer.expected +++ b/cpp/autosar/test/rules/A18-1-4/PointerToAnElementOfAnArrayPassedToASmartPointer.expected @@ -2,11 +2,13 @@ edges | test.cpp:3:36:3:45 | new[] | test.cpp:19:27:19:44 | call to allocate_int_array | | test.cpp:3:36:3:45 | new[] | test.cpp:23:12:23:29 | call to allocate_int_array | | test.cpp:3:36:3:45 | new[] | test.cpp:27:20:27:37 | call to allocate_int_array | -| test.cpp:11:29:11:41 | call to unique_ptr | test.cpp:12:30:12:36 | call to release | +| test.cpp:11:29:11:41 | call to unique_ptr | test.cpp:12:27:12:28 | v2 | +| test.cpp:12:27:12:28 | v2 | test.cpp:12:30:12:36 | call to release | | test.cpp:27:20:27:37 | call to allocate_int_array | test.cpp:32:12:32:20 | int_array | nodes | test.cpp:3:36:3:45 | new[] | semmle.label | new[] | | test.cpp:11:29:11:41 | call to unique_ptr | semmle.label | call to unique_ptr | +| test.cpp:12:27:12:28 | v2 | semmle.label | v2 | | test.cpp:12:30:12:36 | call to release | semmle.label | call to release | | test.cpp:19:27:19:44 | call to allocate_int_array | semmle.label | call to allocate_int_array | | test.cpp:23:12:23:29 | call to allocate_int_array | semmle.label | call to allocate_int_array | diff --git a/cpp/autosar/test/rules/A2-3-1/InvalidCharacterInComment.expected b/cpp/autosar/test/rules/A2-3-1/InvalidCharacterInComment.expected index b5fd4c77cc..4df213e5c2 100644 --- a/cpp/autosar/test/rules/A2-3-1/InvalidCharacterInComment.expected +++ b/cpp/autosar/test/rules/A2-3-1/InvalidCharacterInComment.expected @@ -1,2 +1,2 @@ | test.cpp:3:1:3:37 | // Invalid character \u00ce\u00b1 NON_COMPLIANT | Comment uses the character '\u00ce\u00b1' that is outside the language basic character set. | -| test.cpp:10:1:12:2 | /*\nInvalid character \u00e2\u0086\u00a6 NON_COMPLIANT\n*/ | Comment uses the character '\u00e2\u0086\u00a6' that is outside the language basic character set. | +| test.cpp:12:1:14:2 | /*\nInvalid character \u00e2\u0086\u00a6 NON_COMPLIANT\n*/ | Comment uses the character '\u00e2\u0086\u00a6' that is outside the language basic character set. | diff --git a/cpp/autosar/test/rules/A2-3-1/InvalidCharacterInStringLiteral.expected b/cpp/autosar/test/rules/A2-3-1/InvalidCharacterInStringLiteral.expected index 3ad38685ba..fe21bce430 100644 --- a/cpp/autosar/test/rules/A2-3-1/InvalidCharacterInStringLiteral.expected +++ b/cpp/autosar/test/rules/A2-3-1/InvalidCharacterInStringLiteral.expected @@ -1 +1 @@ -| test.cpp:7:20:7:22 | \u00ce\u00b1 | String literal uses the character '\u03b1' that is outside the language basic character set. | +| test.cpp:7:21:7:23 | \u00ce\u00b1 | String literal uses the character '\u03b1' that is outside the language basic character set. | diff --git a/cpp/autosar/test/rules/A2-3-1/test.cpp b/cpp/autosar/test/rules/A2-3-1/test.cpp index 5d1550f292..cc8b1b53ac 100644 --- a/cpp/autosar/test/rules/A2-3-1/test.cpp +++ b/cpp/autosar/test/rules/A2-3-1/test.cpp @@ -4,9 +4,15 @@ double α = 2.; // NON_COMPLIANT; U+03b1 void *to_𐆅_and_beyond = nullptr; // NON_COMPLIANT; U+10185 int l1_\u00A8; // COMPLIANT[FALSE_POSITIVE] -const char *euro = "α"; // NON_COMPLIANT +const char *euro1 = "α"; // NON_COMPLIANT +const wchar_t *euro2 = L"α"; // COMPLIANT +const char *euro3 = u8"α"; // COMPLIANT int valid; /* Invalid character ↦ NON_COMPLIANT +*/ + +/* +Valid character @ in comments COMPLIANT */ \ No newline at end of file diff --git a/cpp/autosar/test/rules/A3-9-1/VariableWidthIntegerTypesUsed.expected b/cpp/autosar/test/rules/A3-9-1/VariableWidthIntegerTypesUsed.expected index 4f748125d9..7609c76101 100644 --- a/cpp/autosar/test/rules/A3-9-1/VariableWidthIntegerTypesUsed.expected +++ b/cpp/autosar/test/rules/A3-9-1/VariableWidthIntegerTypesUsed.expected @@ -1,4 +1,3 @@ -| test.cpp:4:8:4:8 | c | Variable 'c' has variable-width type. | | test.cpp:5:17:5:18 | uc | Variable 'uc' has variable-width type. | | test.cpp:6:15:6:16 | sc | Variable 'sc' has variable-width type. | | test.cpp:8:7:8:7 | i | Variable 'i' has variable-width type. | @@ -12,3 +11,29 @@ | test.cpp:18:8:18:8 | l | Variable 'l' has variable-width type. | | test.cpp:19:17:19:18 | ul | Variable 'ul' has variable-width type. | | test.cpp:20:15:20:16 | sl | Variable 'sl' has variable-width type. | +| test.cpp:39:23:39:25 | uc1 | Variable 'uc1' has variable-width type. | +| test.cpp:40:21:40:23 | sc1 | Variable 'sc1' has variable-width type. | +| test.cpp:42:13:42:14 | i1 | Variable 'i1' has variable-width type. | +| test.cpp:43:22:43:24 | ui1 | Variable 'ui1' has variable-width type. | +| test.cpp:44:18:44:19 | u1 | Variable 'u1' has variable-width type. | +| test.cpp:45:20:45:22 | si1 | Variable 'si1' has variable-width type. | +| test.cpp:46:16:46:17 | s1 | Variable 's1' has variable-width type. | +| test.cpp:48:15:48:17 | sh1 | Variable 'sh1' has variable-width type. | +| test.cpp:49:24:49:27 | ush1 | Variable 'ush1' has variable-width type. | +| test.cpp:50:22:50:25 | ssh1 | Variable 'ssh1' has variable-width type. | +| test.cpp:52:14:52:15 | l1 | Variable 'l1' has variable-width type. | +| test.cpp:53:23:53:25 | ul1 | Variable 'ul1' has variable-width type. | +| test.cpp:54:21:54:23 | sl1 | Variable 'sl1' has variable-width type. | +| test.cpp:57:26:57:28 | uc2 | Variable 'uc2' has variable-width type. | +| test.cpp:58:24:58:26 | sc2 | Variable 'sc2' has variable-width type. | +| test.cpp:60:16:60:17 | i2 | Variable 'i2' has variable-width type. | +| test.cpp:61:25:61:27 | ui2 | Variable 'ui2' has variable-width type. | +| test.cpp:62:21:62:22 | u2 | Variable 'u2' has variable-width type. | +| test.cpp:63:23:63:25 | si2 | Variable 'si2' has variable-width type. | +| test.cpp:64:19:64:20 | s2 | Variable 's2' has variable-width type. | +| test.cpp:66:18:66:20 | sh2 | Variable 'sh2' has variable-width type. | +| test.cpp:67:27:67:30 | ush2 | Variable 'ush2' has variable-width type. | +| test.cpp:68:25:68:28 | ssh2 | Variable 'ssh2' has variable-width type. | +| test.cpp:70:17:70:18 | l2 | Variable 'l2' has variable-width type. | +| test.cpp:71:26:71:28 | ul2 | Variable 'ul2' has variable-width type. | +| test.cpp:72:24:72:26 | sl2 | Variable 'sl2' has variable-width type. | diff --git a/cpp/autosar/test/rules/A3-9-1/VariableWidthPlainCharTypeUsed.expected b/cpp/autosar/test/rules/A3-9-1/VariableWidthPlainCharTypeUsed.expected new file mode 100644 index 0000000000..6631606cbf --- /dev/null +++ b/cpp/autosar/test/rules/A3-9-1/VariableWidthPlainCharTypeUsed.expected @@ -0,0 +1,3 @@ +| test.cpp:4:8:4:8 | c | Variable 'c' has variable-width char type. | +| test.cpp:38:14:38:15 | c1 | Variable 'c1' has variable-width char type. | +| test.cpp:56:17:56:18 | c2 | Variable 'c2' has variable-width char type. | diff --git a/cpp/autosar/test/rules/A3-9-1/VariableWidthPlainCharTypeUsed.qlref b/cpp/autosar/test/rules/A3-9-1/VariableWidthPlainCharTypeUsed.qlref new file mode 100644 index 0000000000..b76c61f4c7 --- /dev/null +++ b/cpp/autosar/test/rules/A3-9-1/VariableWidthPlainCharTypeUsed.qlref @@ -0,0 +1 @@ +rules/A3-9-1/VariableWidthPlainCharTypeUsed.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A3-9-1/test.cpp b/cpp/autosar/test/rules/A3-9-1/test.cpp index 8d2ef48523..9d1e257b8c 100644 --- a/cpp/autosar/test/rules/A3-9-1/test.cpp +++ b/cpp/autosar/test/rules/A3-9-1/test.cpp @@ -3,7 +3,7 @@ void test_variable_width_type_variables() { char c; // NON_COMPLIANT unsigned char uc; // NON_COMPLIANT - signed char sc; // NON_COMPLIANt + signed char sc; // NON_COMPLIANT int i; // NON_COMPLIANT unsigned int ui; // NON_COMPLIANT @@ -32,4 +32,42 @@ void test_variable_width_type_variables() { int main(int argc, char *argv[]) { // COMPLIANT // main as an exception +} + +void test_variable_width_type_qualified_variables() { + const char c1 = 0; // NON_COMPLIANT + const unsigned char uc1 = 0; // NON_COMPLIANT + const signed char sc1 = 0; // NON_COMPLIANt + + const int i1 = 0; // NON_COMPLIANT + const unsigned int ui1 = 0; // NON_COMPLIANT + const unsigned u1 = 0; // NON_COMPLIANT + const signed int si1 = 0; // NON_COMPLIANT + const signed s1 = 0; // NON_COMPLIANT + + const short sh1 = 0; // NON_COMPLIANT + const unsigned short ush1 = 0; // NON_COMPLIANT + const signed short ssh1 = 0; // NON_COMPLIANT + + const long l1 = 0; // NON_COMPLIANT + const unsigned long ul1 = 0; // NON_COMPLIANT + const signed long sl1 = 0; // NON_COMPLIANT + + volatile char c2; // NON_COMPLIANT + volatile unsigned char uc2; // NON_COMPLIANT + volatile signed char sc2; // NON_COMPLIANt + + volatile int i2; // NON_COMPLIANT + volatile unsigned int ui2; // NON_COMPLIANT + volatile unsigned u2; // NON_COMPLIANT + volatile signed int si2; // NON_COMPLIANT + volatile signed s2; // NON_COMPLIANT + + volatile short sh2; // NON_COMPLIANT + volatile unsigned short ush2; // NON_COMPLIANT + volatile signed short ssh2; // NON_COMPLIANT + + volatile long l2; // NON_COMPLIANT + volatile unsigned long ul2; // NON_COMPLIANT + volatile signed long sl2; // NON_COMPLIANT } \ No newline at end of file diff --git a/cpp/autosar/test/rules/A4-5-1/EnumUsedInArithmeticContexts.expected b/cpp/autosar/test/rules/A4-5-1/EnumUsedInArithmeticContexts.expected index a813b23223..8ece6b3dd1 100644 --- a/cpp/autosar/test/rules/A4-5-1/EnumUsedInArithmeticContexts.expected +++ b/cpp/autosar/test/rules/A4-5-1/EnumUsedInArithmeticContexts.expected @@ -1,96 +1,104 @@ -| enum.cpp:21:3:21:16 | ... + ... | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:21:3:21:8 | Avenue | expression | -| enum.cpp:21:3:21:16 | ... + ... | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:21:12:21:16 | Place | expression | -| enum.cpp:22:3:22:15 | ... - ... | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:22:3:22:7 | Place | expression | -| enum.cpp:22:3:22:15 | ... - ... | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:22:11:22:15 | Place | expression | -| enum.cpp:23:3:23:9 | - ... | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:23:4:23:9 | Avenue | expression | -| enum.cpp:24:3:24:10 | ... % ... | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:24:3:24:6 | Road | expression | -| enum.cpp:25:3:25:12 | ... / ... | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:25:3:25:8 | Avenue | expression | -| enum.cpp:26:3:26:15 | ... * ... | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:26:3:26:11 | Boulevard | expression | -| enum.cpp:29:3:29:13 | ... && ... | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:29:3:29:6 | Lane | expression | -| enum.cpp:29:3:29:13 | ... && ... | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:29:10:29:13 | Road | expression | -| enum.cpp:30:3:30:15 | ... \|\| ... | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:30:3:30:7 | Place | expression | -| enum.cpp:30:3:30:15 | ... \|\| ... | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:30:12:30:15 | Lane | expression | -| enum.cpp:31:3:31:7 | ! ... | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:31:4:31:7 | Road | expression | -| enum.cpp:34:3:34:23 | ... \| ... | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:34:3:34:11 | Boulevard | expression | -| enum.cpp:34:3:34:23 | ... \| ... | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:34:15:34:23 | Boulevard | expression | -| enum.cpp:35:3:35:7 | ~ ... | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:35:4:35:7 | Lane | expression | -| enum.cpp:36:3:36:14 | ... ^ ... | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:36:3:36:7 | Place | expression | -| enum.cpp:36:3:36:14 | ... ^ ... | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:36:11:36:14 | Road | expression | -| enum.cpp:37:3:37:11 | ... >> ... | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:37:3:37:6 | Road | expression | -| enum.cpp:38:3:38:11 | ... << ... | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:38:3:38:6 | Road | expression | -| enum.cpp:39:10:39:10 | call to operator&= | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:39:3:39:8 | Avenue | expression | -| enum.cpp:39:10:39:10 | call to operator&= | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:39:13:39:17 | Place | expression | -| enum.cpp:40:8:40:8 | call to operator^= | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:40:3:40:6 | Road | expression | -| enum.cpp:40:8:40:8 | call to operator^= | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:40:11:40:14 | Road | expression | -| enum.cpp:41:8:41:8 | call to operator>>= | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:41:3:41:6 | Road | expression | -| enum.cpp:41:8:41:8 | call to operator>>= | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:41:12:41:15 | Road | expression | -| enum.cpp:42:8:42:8 | call to operator<<= | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:42:3:42:6 | Road | expression | -| enum.cpp:42:8:42:8 | call to operator<<= | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:42:12:42:15 | Road | expression | -| enum.cpp:57:3:57:7 | ... + ... | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:57:3:57:3 | a | expression | -| enum.cpp:57:3:57:7 | ... + ... | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:57:7:57:7 | a | expression | -| enum.cpp:58:3:58:7 | ... - ... | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:58:3:58:3 | a | expression | -| enum.cpp:58:3:58:7 | ... - ... | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:58:7:58:7 | a | expression | -| enum.cpp:59:3:59:4 | - ... | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:59:4:59:4 | a | expression | -| enum.cpp:60:3:60:7 | ... % ... | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:60:3:60:3 | a | expression | -| enum.cpp:61:3:61:7 | ... / ... | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:61:3:61:3 | a | expression | -| enum.cpp:62:3:62:7 | ... * ... | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:62:3:62:3 | a | expression | -| enum.cpp:65:3:65:7 | ... && ... | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:65:3:65:3 | a | expression | -| enum.cpp:65:3:65:7 | ... && ... | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:65:7:65:7 | b | expression | -| enum.cpp:66:3:66:8 | ... \|\| ... | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:66:3:66:3 | a | expression | -| enum.cpp:66:3:66:8 | ... \|\| ... | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:66:8:66:8 | b | expression | -| enum.cpp:67:3:67:4 | ! ... | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:67:4:67:4 | b | expression | -| enum.cpp:70:3:70:7 | ... \| ... | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:70:3:70:3 | a | expression | -| enum.cpp:70:3:70:7 | ... \| ... | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:70:7:70:7 | b | expression | -| enum.cpp:71:3:71:4 | ~ ... | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:71:4:71:4 | a | expression | -| enum.cpp:72:3:72:7 | ... ^ ... | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:72:3:72:3 | a | expression | -| enum.cpp:72:3:72:7 | ... ^ ... | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:72:7:72:7 | b | expression | -| enum.cpp:73:3:73:8 | ... >> ... | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:73:3:73:3 | a | expression | -| enum.cpp:74:3:74:8 | ... << ... | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:74:3:74:3 | a | expression | -| enum.cpp:75:5:75:5 | call to operator&= | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:75:3:75:3 | a | expression | -| enum.cpp:75:5:75:5 | call to operator&= | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:75:8:75:8 | b | expression | -| enum.cpp:76:5:76:5 | call to operator^= | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:76:3:76:3 | a | expression | -| enum.cpp:77:5:77:5 | call to operator>>= | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:77:3:77:3 | a | expression | -| enum.cpp:78:5:78:5 | call to operator<<= | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:78:3:78:3 | a | expression | -| enum_class.cpp:49:22:49:22 | call to operator+ | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:49:3:49:20 | ML | expression | -| enum_class.cpp:50:23:50:23 | call to operator- | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:50:3:50:21 | SML | expression | -| enum_class.cpp:50:23:50:23 | call to operator- | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:50:25:50:42 | ML | expression | -| enum_class.cpp:51:3:51:3 | call to operator- | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:51:4:51:26 | Haskell | expression | -| enum_class.cpp:52:26:52:26 | call to operator% | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:52:3:52:24 | Racket | expression | -| enum_class.cpp:53:23:53:23 | call to operator/ | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:53:3:53:21 | Elm | expression | -| enum_class.cpp:54:26:54:26 | call to operator* | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:54:3:54:24 | Scheme | expression | -| enum_class.cpp:57:27:57:27 | call to operator&& | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:57:3:57:25 | Haskell | expression | -| enum_class.cpp:57:27:57:27 | call to operator&& | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:57:29:57:47 | Elm | expression | -| enum_class.cpp:58:24:58:24 | call to operator\|\| | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:58:3:58:22 | Lisp | expression | -| enum_class.cpp:58:24:58:24 | call to operator\|\| | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:58:27:58:48 | Racket | expression | -| enum_class.cpp:59:3:59:3 | call to operator! | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:59:4:59:25 | Scheme | expression | -| enum_class.cpp:62:23:62:23 | call to operator\| | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:62:3:62:21 | Elm | expression | -| enum_class.cpp:62:23:62:23 | call to operator\| | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:62:25:62:46 | Racket | expression | -| enum_class.cpp:63:3:63:3 | call to operator~ | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:63:4:63:24 | Idris | expression | -| enum_class.cpp:64:22:64:22 | call to operator^ | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:64:3:64:20 | ML | expression | -| enum_class.cpp:64:22:64:22 | call to operator^ | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:64:24:64:44 | OCaml | expression | -| enum_class.cpp:65:25:65:25 | call to operator>> | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:65:3:65:23 | OCaml | expression | -| enum_class.cpp:66:24:66:24 | call to operator<< | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:66:3:66:22 | Lisp | expression | -| enum_class.cpp:67:5:67:5 | call to operator&= | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:67:3:67:3 | l | expression | -| enum_class.cpp:67:5:67:5 | call to operator&= | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:67:8:67:28 | OCaml | expression | -| enum_class.cpp:68:5:68:5 | call to operator^= | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:68:3:68:3 | l | expression | -| enum_class.cpp:69:5:69:5 | call to operator>>= | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:69:3:69:3 | l | expression | -| enum_class.cpp:70:5:70:5 | call to operator<<= | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:70:3:70:3 | l | expression | -| enum_class.cpp:85:5:85:5 | call to operator+ | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:85:3:85:3 | a | expression | -| enum_class.cpp:86:5:86:5 | call to operator- | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:86:3:86:3 | a | expression | -| enum_class.cpp:86:5:86:5 | call to operator- | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:86:7:86:7 | b | expression | -| enum_class.cpp:87:3:87:3 | call to operator- | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:87:4:87:4 | a | expression | -| enum_class.cpp:88:5:88:5 | call to operator% | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:88:3:88:3 | a | expression | -| enum_class.cpp:89:5:89:5 | call to operator/ | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:89:3:89:3 | a | expression | -| enum_class.cpp:90:5:90:5 | call to operator* | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:90:3:90:3 | b | expression | -| enum_class.cpp:93:5:93:5 | call to operator&& | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:93:3:93:3 | a | expression | -| enum_class.cpp:93:5:93:5 | call to operator&& | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:93:7:93:7 | b | expression | -| enum_class.cpp:94:5:94:5 | call to operator\|\| | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:94:3:94:3 | a | expression | -| enum_class.cpp:94:5:94:5 | call to operator\|\| | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:94:8:94:8 | b | expression | -| enum_class.cpp:95:3:95:3 | call to operator! | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:95:4:95:4 | a | expression | -| enum_class.cpp:98:5:98:5 | call to operator\| | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:98:3:98:3 | a | expression | -| enum_class.cpp:98:5:98:5 | call to operator\| | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:98:7:98:7 | b | expression | -| enum_class.cpp:99:3:99:3 | call to operator~ | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:99:4:99:4 | a | expression | -| enum_class.cpp:100:5:100:5 | call to operator^ | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:100:3:100:3 | a | expression | -| enum_class.cpp:100:5:100:5 | call to operator^ | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:100:7:100:7 | b | expression | -| enum_class.cpp:101:5:101:5 | call to operator>> | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:101:3:101:3 | a | expression | -| enum_class.cpp:102:5:102:5 | call to operator<< | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:102:3:102:3 | a | expression | +| enum.cpp:20:3:20:8 | Avenue | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:20:12:20:16 | Place | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:21:3:21:7 | Place | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:21:11:21:15 | Place | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:22:4:22:9 | Avenue | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:23:3:23:6 | Road | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:24:3:24:8 | Avenue | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:25:3:25:11 | Boulevard | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:28:3:28:6 | Lane | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:28:10:28:13 | Road | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:29:3:29:7 | Place | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:29:12:29:15 | Lane | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:30:4:30:7 | Road | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:33:3:33:11 | Boulevard | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:33:15:33:23 | Boulevard | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:34:4:34:7 | Lane | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:35:3:35:7 | Place | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:35:11:35:14 | Road | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:36:3:36:6 | Road | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:37:3:37:6 | Road | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:38:3:38:8 | Avenue | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:38:13:38:17 | Place | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:39:3:39:6 | Road | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:39:11:39:14 | Road | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:40:3:40:6 | Road | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:40:12:40:15 | Road | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:41:3:41:6 | Road | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:41:12:41:15 | Road | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:42:3:42:6 | Road | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:42:9:42:12 | Road | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:57:3:57:3 | a | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:57:7:57:7 | a | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:58:3:58:3 | a | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:58:7:58:7 | a | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:59:4:59:4 | a | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:60:3:60:3 | a | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:61:3:61:3 | a | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:62:3:62:3 | a | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:65:3:65:3 | a | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:65:7:65:7 | b | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:66:3:66:3 | a | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:66:8:66:8 | b | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:67:4:67:4 | b | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:70:3:70:3 | a | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:70:7:70:7 | b | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:71:4:71:4 | a | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:72:3:72:3 | a | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:72:7:72:7 | b | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:73:3:73:3 | a | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:74:3:74:3 | a | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:75:3:75:3 | a | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:75:8:75:8 | b | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:76:3:76:3 | a | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:77:3:77:3 | a | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:78:3:78:3 | a | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:79:3:79:3 | a | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum.cpp:79:6:79:6 | b | Enum $@ is used as an operand of arithmetic operation. | enum.cpp:1:6:1:11 | Street | Street | +| enum_class.cpp:48:3:48:20 | ML | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:1:12:1:25 | FunctionalLang | FunctionalLang | +| enum_class.cpp:49:3:49:21 | SML | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:1:12:1:25 | FunctionalLang | FunctionalLang | +| enum_class.cpp:49:25:49:42 | ML | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:1:12:1:25 | FunctionalLang | FunctionalLang | +| enum_class.cpp:50:4:50:26 | Haskell | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:1:12:1:25 | FunctionalLang | FunctionalLang | +| enum_class.cpp:51:3:51:24 | Racket | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:1:12:1:25 | FunctionalLang | FunctionalLang | +| enum_class.cpp:52:3:52:21 | Elm | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:1:12:1:25 | FunctionalLang | FunctionalLang | +| enum_class.cpp:53:3:53:24 | Scheme | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:1:12:1:25 | FunctionalLang | FunctionalLang | +| enum_class.cpp:56:3:56:25 | Haskell | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:1:12:1:25 | FunctionalLang | FunctionalLang | +| enum_class.cpp:56:29:56:47 | Elm | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:1:12:1:25 | FunctionalLang | FunctionalLang | +| enum_class.cpp:57:3:57:22 | Lisp | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:1:12:1:25 | FunctionalLang | FunctionalLang | +| enum_class.cpp:57:27:57:48 | Racket | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:1:12:1:25 | FunctionalLang | FunctionalLang | +| enum_class.cpp:58:4:58:25 | Scheme | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:1:12:1:25 | FunctionalLang | FunctionalLang | +| enum_class.cpp:61:3:61:21 | Elm | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:1:12:1:25 | FunctionalLang | FunctionalLang | +| enum_class.cpp:61:25:61:46 | Racket | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:1:12:1:25 | FunctionalLang | FunctionalLang | +| enum_class.cpp:62:4:62:24 | Idris | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:1:12:1:25 | FunctionalLang | FunctionalLang | +| enum_class.cpp:63:3:63:20 | ML | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:1:12:1:25 | FunctionalLang | FunctionalLang | +| enum_class.cpp:63:24:63:44 | OCaml | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:1:12:1:25 | FunctionalLang | FunctionalLang | +| enum_class.cpp:64:3:64:23 | OCaml | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:1:12:1:25 | FunctionalLang | FunctionalLang | +| enum_class.cpp:65:3:65:22 | Lisp | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:1:12:1:25 | FunctionalLang | FunctionalLang | +| enum_class.cpp:66:3:66:3 | l | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:1:12:1:25 | FunctionalLang | FunctionalLang | +| enum_class.cpp:66:8:66:28 | OCaml | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:1:12:1:25 | FunctionalLang | FunctionalLang | +| enum_class.cpp:67:3:67:3 | l | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:1:12:1:25 | FunctionalLang | FunctionalLang | +| enum_class.cpp:68:3:68:3 | l | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:1:12:1:25 | FunctionalLang | FunctionalLang | +| enum_class.cpp:69:3:69:3 | l | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:1:12:1:25 | FunctionalLang | FunctionalLang | +| enum_class.cpp:70:3:70:24 | FSharp | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:1:12:1:25 | FunctionalLang | FunctionalLang | +| enum_class.cpp:70:27:70:47 | OCaml | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:1:12:1:25 | FunctionalLang | FunctionalLang | +| enum_class.cpp:85:3:85:3 | a | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:1:12:1:25 | FunctionalLang | FunctionalLang | +| enum_class.cpp:86:3:86:3 | a | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:1:12:1:25 | FunctionalLang | FunctionalLang | +| enum_class.cpp:86:7:86:7 | b | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:1:12:1:25 | FunctionalLang | FunctionalLang | +| enum_class.cpp:87:4:87:4 | a | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:1:12:1:25 | FunctionalLang | FunctionalLang | +| enum_class.cpp:88:3:88:3 | a | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:1:12:1:25 | FunctionalLang | FunctionalLang | +| enum_class.cpp:89:3:89:3 | a | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:1:12:1:25 | FunctionalLang | FunctionalLang | +| enum_class.cpp:90:3:90:3 | b | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:1:12:1:25 | FunctionalLang | FunctionalLang | +| enum_class.cpp:93:3:93:3 | a | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:1:12:1:25 | FunctionalLang | FunctionalLang | +| enum_class.cpp:93:7:93:7 | b | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:1:12:1:25 | FunctionalLang | FunctionalLang | +| enum_class.cpp:94:3:94:3 | a | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:1:12:1:25 | FunctionalLang | FunctionalLang | +| enum_class.cpp:94:8:94:8 | b | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:1:12:1:25 | FunctionalLang | FunctionalLang | +| enum_class.cpp:95:4:95:4 | a | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:1:12:1:25 | FunctionalLang | FunctionalLang | +| enum_class.cpp:98:3:98:3 | a | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:1:12:1:25 | FunctionalLang | FunctionalLang | +| enum_class.cpp:98:7:98:7 | b | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:1:12:1:25 | FunctionalLang | FunctionalLang | +| enum_class.cpp:99:4:99:4 | a | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:1:12:1:25 | FunctionalLang | FunctionalLang | +| enum_class.cpp:100:3:100:3 | a | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:1:12:1:25 | FunctionalLang | FunctionalLang | +| enum_class.cpp:100:7:100:7 | b | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:1:12:1:25 | FunctionalLang | FunctionalLang | +| enum_class.cpp:101:3:101:3 | a | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:1:12:1:25 | FunctionalLang | FunctionalLang | +| enum_class.cpp:102:3:102:3 | a | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:1:12:1:25 | FunctionalLang | FunctionalLang | +| enum_class.cpp:103:3:103:3 | a | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:1:12:1:25 | FunctionalLang | FunctionalLang | +| enum_class.cpp:103:6:103:6 | b | Enum $@ is used as an operand of arithmetic operation. | enum_class.cpp:1:12:1:25 | FunctionalLang | FunctionalLang | diff --git a/cpp/autosar/test/rules/A4-5-1/enum.cpp b/cpp/autosar/test/rules/A4-5-1/enum.cpp index afc4d97504..e6f3f178bc 100644 --- a/cpp/autosar/test/rules/A4-5-1/enum.cpp +++ b/cpp/autosar/test/rules/A4-5-1/enum.cpp @@ -14,7 +14,6 @@ void test_enum() { Avenue <= Avenue; // COMPLIANT Place > Road; // COMPLIANT Boulevard >= Avenue; // COMPLIANT - Place &Avenue; // COMPLIANT arr[Road] = 1; // COMPLIANT // arithmetic @@ -40,6 +39,7 @@ void test_enum() { Road ^= Road; // NON_COMPLIANT Road >>= Road; // NON_COMPLIANT Road <<= Road; // NON_COMPLIANT + Road &Road; // NON_COMPLIANT } void test_enum_var() { @@ -51,7 +51,7 @@ void test_enum_var() { a <= b; // COMPLIANT a > b; // COMPLIANT a >= b; // COMPLIANT - a &b; // COMPLIANT + Street *c = &a; // COMPLIANT // arithmetic a + a; // NON_COMPLIANT @@ -76,4 +76,5 @@ void test_enum_var() { a ^= 1; // NON_COMPLIANT a >>= 1; // NON_COMPLIANT a <<= 1; // NON_COMPLIANT + a &b; // NON_COMPLIANT } \ No newline at end of file diff --git a/cpp/autosar/test/rules/A4-5-1/enum_class.cpp b/cpp/autosar/test/rules/A4-5-1/enum_class.cpp index 6921917aea..0bbd3eb17c 100644 --- a/cpp/autosar/test/rules/A4-5-1/enum_class.cpp +++ b/cpp/autosar/test/rules/A4-5-1/enum_class.cpp @@ -43,7 +43,6 @@ void test_enum_class() { FunctionalLang::Elm <= FunctionalLang::Haskell; // COMPLIANT FunctionalLang::Idris > FunctionalLang::SML; // COMPLIANT FunctionalLang::Haskell >= FunctionalLang::Idris; // COMPLIANT - FunctionalLang::FSharp &FunctionalLang::OCaml; // COMPLIANT // arithmetic FunctionalLang::ML + 1; // NON_COMPLIANT @@ -59,15 +58,16 @@ void test_enum_class() { !FunctionalLang::Scheme; // NON_COMPLIANT // bitwise - FunctionalLang::Elm | FunctionalLang::Racket; // NON_COMPLIANT - ~FunctionalLang::Idris; // NON_COMPLIANT - FunctionalLang::ML ^ FunctionalLang::OCaml; // NON_COMPLIANT - FunctionalLang::OCaml >> 1; // NON_COMPLIANT - FunctionalLang::Lisp << 1; // NON_COMPLIANT - l &= FunctionalLang::OCaml; // NON_COMPLIANT - l ^= 1; // NON_COMPLIANT - l >>= 1; // NON_COMPLIANT - l <<= 1; // NON_COMPLIANT + FunctionalLang::Elm | FunctionalLang::Racket; // NON_COMPLIANT + ~FunctionalLang::Idris; // NON_COMPLIANT + FunctionalLang::ML ^ FunctionalLang::OCaml; // NON_COMPLIANT + FunctionalLang::OCaml >> 1; // NON_COMPLIANT + FunctionalLang::Lisp << 1; // NON_COMPLIANT + l &= FunctionalLang::OCaml; // NON_COMPLIANT + l ^= 1; // NON_COMPLIANT + l >>= 1; // NON_COMPLIANT + l <<= 1; // NON_COMPLIANT + FunctionalLang::FSharp &FunctionalLang::OCaml; // NON_COMPLIANT } void test_enum_class_vars() { @@ -79,7 +79,7 @@ void test_enum_class_vars() { a <= b; // COMPLIANT a > a; // COMPLIANT a >= a; // COMPLIANT - a &b; // COMPLIANT + FunctionalLang *c = &a; // COMPLIANT // arithmetic a + 1; // NON_COMPLIANT @@ -100,4 +100,21 @@ void test_enum_class_vars() { a ^ b; // NON_COMPLIANT a >> 1; // NON_COMPLIANT a << 1; // NON_COMPLIANT + a &b; // NON_COMPLIANT +} + +enum class byte : unsigned char {}; + +byte operator&(byte lhs, byte rhs) { return lhs; } +byte operator|(byte lhs, byte rhs) { return lhs; } +byte operator^(byte lhs, byte rhs) { return lhs; } +byte operator~(byte lhs) { return lhs; } +byte operator&=(byte lhs, byte rhs) { return lhs; } +byte operator|=(byte lhs, byte rhs) { return lhs; } + +void test_bitmasktype_enum_class() { // COMPLIANT - byte implements the + // BitmaskType trait. + byte one, two; + + one &two; } \ No newline at end of file diff --git a/cpp/autosar/test/rules/A4-7-1/test.cpp b/cpp/autosar/test/rules/A4-7-1/test.cpp index 7f6cbb7abe..9e3c27dec8 100644 --- a/cpp/autosar/test/rules/A4-7-1/test.cpp +++ b/cpp/autosar/test/rules/A4-7-1/test.cpp @@ -62,4 +62,14 @@ void test_loop_bound_bad(unsigned int n) { i++) { // NON_COMPLIANT - crement will overflow before loop bound is // reached } +} + +void test_assign_div(int i) { // COMPLIANT + i /= 2; +} + +void test_pointer() { + int *p = nullptr; + p++; // COMPLIANT - not covered by this rule + p--; // COMPLIANT - not covered by this rule } \ No newline at end of file diff --git a/cpp/autosar/test/rules/A7-1-1/DeclarationUnmodifiedParamMissingConstSpecifier.expected b/cpp/autosar/test/rules/A7-1-1/DeclarationUnmodifiedParamMissingConstSpecifier.expected deleted file mode 100644 index dd673a2e68..0000000000 --- a/cpp/autosar/test/rules/A7-1-1/DeclarationUnmodifiedParamMissingConstSpecifier.expected +++ /dev/null @@ -1 +0,0 @@ -| test.cpp:7:14:7:14 | p | Non-constant parameter p points to an object and is not modified. | diff --git a/cpp/autosar/test/rules/A7-1-1/DeclarationUnmodifiedParamMissingConstSpecifier.qlref b/cpp/autosar/test/rules/A7-1-1/DeclarationUnmodifiedParamMissingConstSpecifier.qlref deleted file mode 100644 index 5f5b01f4bc..0000000000 --- a/cpp/autosar/test/rules/A7-1-1/DeclarationUnmodifiedParamMissingConstSpecifier.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/A7-1-1/DeclarationUnmodifiedParamMissingConstSpecifier.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A7-1-1/test.cpp b/cpp/autosar/test/rules/A7-1-1/test.cpp index 2c32dc5aab..745c6719b1 100644 --- a/cpp/autosar/test/rules/A7-1-1/test.cpp +++ b/cpp/autosar/test/rules/A7-1-1/test.cpp @@ -4,7 +4,7 @@ void f1(int *p) { // COMPLIANT *p += 2; } -void f2(int *p) { // NON_COMPLIANT +void f2(int *p) { // COMPLIANT - we ignore parameters for this rule int l4 = 1; // NON_COMPLIANT int *p1 = p; // NON_COMPLIANT } diff --git a/cpp/autosar/test/rules/A7-1-2/VariableMissingConstexpr.expected b/cpp/autosar/test/rules/A7-1-2/VariableMissingConstexpr.expected index 6b6ed61dc8..dbf223e0cf 100644 --- a/cpp/autosar/test/rules/A7-1-2/VariableMissingConstexpr.expected +++ b/cpp/autosar/test/rules/A7-1-2/VariableMissingConstexpr.expected @@ -10,3 +10,14 @@ | test.cpp:55:7:55:8 | m2 | Variable m2 could be marked 'constexpr'. | | test.cpp:130:7:130:8 | m1 | Variable m1 could be marked 'constexpr'. | | test.cpp:141:7:141:8 | m1 | Variable m1 could be marked 'constexpr'. | +| test.cpp:221:7:221:8 | l1 | Variable l1 could be marked 'constexpr'. | +| test.cpp:235:7:235:8 | l6 | Variable l6 could be marked 'constexpr'. | +| test.cpp:237:7:237:8 | l8 | Variable l8 could be marked 'constexpr'. | +| test.cpp:240:7:240:9 | l10 | Variable l10 could be marked 'constexpr'. | +| test.cpp:243:7:243:9 | l12 | Variable l12 could be marked 'constexpr'. | +| test.cpp:248:7:248:9 | l15 | Variable l15 could be marked 'constexpr'. | +| test.cpp:250:7:250:9 | l16 | Variable l16 could be marked 'constexpr'. | +| test.cpp:251:7:251:9 | l17 | Variable l17 could be marked 'constexpr'. | +| test.cpp:257:7:257:9 | l21 | Variable l21 could be marked 'constexpr'. | +| test.cpp:262:7:262:9 | l24 | Variable l24 could be marked 'constexpr'. | +| test.cpp:263:7:263:9 | l25 | Variable l25 could be marked 'constexpr'. | diff --git a/cpp/autosar/test/rules/A7-1-2/test.cpp b/cpp/autosar/test/rules/A7-1-2/test.cpp index 020ba09a2b..a3b7baea83 100644 --- a/cpp/autosar/test/rules/A7-1-2/test.cpp +++ b/cpp/autosar/test/rules/A7-1-2/test.cpp @@ -204,4 +204,64 @@ class ExcludedCases { void operator=(ExcludedCases &) {} // COMPLIANT void operator=(ExcludedCases &&) {} // COMPLIANT -}; \ No newline at end of file +}; + +extern int random(); +constexpr int add(int x, int y) { return x + y; } +// Example with compile time constant literal value as default argument +constexpr int add1(int x, int y = 1) { return x + y; } +// Example with compile time constant function call as default argument +constexpr int add2(int x, int y = add(add1(1), 2)) { return x + y; } +// Example with non compile time constant function call as default argument +constexpr int add3(int x, int y = random()) { return x + y; } +// Example with compile time constant literal value as default arguments +constexpr int add4(int x = 1, int y = 2) { return x + y; } + +constexpr void fp_reported_in_466(int p) { + int l1 = add(1, 2); // NON_COMPLIANT + int l2 = add(1, p); // COMPLIANT + + int l3 = 0; + if (p > 0) { + l3 = 1; + } else { + l3 = p; + } + + constexpr int l4 = add(1, 2); // COMPLIANT + + int l5 = + add(l3, 2); // COMPLIANT - l3 is not compile time constant on all paths + int l6 = add(l4, 2); // NON_COMPLIANT + int l7 = add(l1, 2); // COMPLIANT - l1 is not constexpr + int l8 = + add1(l4, 2); // NON_COMPLIANT - all arguments are compile time constants + int l9 = add1(l1, 2); // COMPLIANT - l1 is not constexpr + int l10 = add1(l4); // NON_COMPLIANT - argument and the default value of the + // second argument are compile time constants + int l11 = add1(l1); // COMPLIANT - l1 is not constexpr + int l12 = add1(1); // NON_COMPLIANT + int l13 = + add1(1, l3); // COMPLIANT - l3 is not compile time constant on all paths + int l14 = + add1(l3); // COMPLIANT - l3 is not compile time constant on all paths + int l15 = add2(1); // NON_COMPLIANT - provided argument and default value are + // compile time constants + int l16 = add2(1, 2); // NON_COMPLIANT + int l17 = add2(l4, 2); // NON_COMPLIANT + int l18 = add2(l1, 2); // COMPLIANT - l1 is not constexpr + int l19 = + add2(l3); // COMPLIANT - l3 is not compile time constant on all paths + int l20 = + add2(l3, 1); // COMPLIANT - l3 is not compile time constant on all paths + int l21 = add3(1, 1); // NON_COMPLIANT + int l22 = add3(1); // COMPLIANT - default value for second argument is not a + // compile time constant + int l23 = + add3(1, l3); // COMPLIANT - l3 is not compile time constant on all paths + int l24 = add4(); // NON_COMPLIANT - default values are compile time constants + int l25 = add4(1); // NON_COMPLIANT - default value for second argument is a + // compile time constant + int l26 = + add4(1, l3); // COMPLIANT - l3 is not compile time constant on all paths +} \ No newline at end of file diff --git a/cpp/autosar/test/rules/A7-1-5/AutoSpecifierNotUsedAppropriatelyInVariableDefinition.expected b/cpp/autosar/test/rules/A7-1-5/AutoSpecifierNotUsedAppropriatelyInVariableDefinition.expected index 03e53068f4..7a5da3abac 100644 --- a/cpp/autosar/test/rules/A7-1-5/AutoSpecifierNotUsedAppropriatelyInVariableDefinition.expected +++ b/cpp/autosar/test/rules/A7-1-5/AutoSpecifierNotUsedAppropriatelyInVariableDefinition.expected @@ -4,4 +4,4 @@ | test.cpp:27:8:27:8 | a | Use of auto in variable definition is not the result of a function call, lambda expression, or non-fundamental type initializer. | | test.cpp:28:8:28:8 | b | Use of auto in variable definition is not the result of a function call, lambda expression, or non-fundamental type initializer. | | test.cpp:81:10:81:10 | a | Use of auto in variable definition is not the result of a function call, lambda expression, or non-fundamental type initializer. | -| test.cpp:111:19:111:19 | a | Use of auto in variable definition is not the result of a function call, lambda expression, or non-fundamental type initializer. | +| test.cpp:111:13:111:13 | a | Use of auto in variable definition is not the result of a function call, lambda expression, or non-fundamental type initializer. | diff --git a/cpp/autosar/test/rules/A7-1-5/test.cpp b/cpp/autosar/test/rules/A7-1-5/test.cpp index 34be754905..ba2ce2be81 100644 --- a/cpp/autosar/test/rules/A7-1-5/test.cpp +++ b/cpp/autosar/test/rules/A7-1-5/test.cpp @@ -106,9 +106,30 @@ void instantiate() { t381.test_381_1(); t381.test_381_2(); } - +class Foo {}; void test_loop() { - for (const auto a : {8, 9, 10}) { + for (auto a : {8, 9, 10}) { // NON_COMPLIANT - a is initialized with a + // non-constant initializer + a; + } + + std::vector v = {1, 2, 3}; + for (auto &a : v) { // COMPLIANT - a is intialized with a function call + a; + } + + Foo f1; + Foo f2; + for (auto &a : {f1, f2}) { // COMPLIANT - initialized with a non-fundamental + // type a; } -} \ No newline at end of file +} + +template void test_template(std::vector v2) { + for (auto &a : v2) { // COMPLIANT - a is intialized with a function call + a; + } +} + +void test_template_instantiation() { test_template({1, 2, 3}); } \ No newline at end of file diff --git a/cpp/autosar/test/rules/A8-4-7/InParametersForCheapToCopyTypesNotPassedByValue.expected b/cpp/autosar/test/rules/A8-4-7/InParametersForCheapToCopyTypesNotPassedByValue.expected index c89e65db90..bc8a9d5f5b 100644 --- a/cpp/autosar/test/rules/A8-4-7/InParametersForCheapToCopyTypesNotPassedByValue.expected +++ b/cpp/autosar/test/rules/A8-4-7/InParametersForCheapToCopyTypesNotPassedByValue.expected @@ -1 +1 @@ -| test.cpp:20:19:20:21 | f5a | Parameter f5a is the trivially copyable type const S1 but it is passed by reference instead of by value. | +| test.cpp:20:19:20:21 | f5a | Parameter 'f5a' is the trivially copyable type 'const S1' but it is passed by reference instead of by value. | diff --git a/cpp/autosar/test/rules/A8-4-7/test.cpp b/cpp/autosar/test/rules/A8-4-7/test.cpp index 70829ef907..80cd3d48e5 100644 --- a/cpp/autosar/test/rules/A8-4-7/test.cpp +++ b/cpp/autosar/test/rules/A8-4-7/test.cpp @@ -37,4 +37,12 @@ inline S1 Value(size_t n, const char *data) {} // COMPLIANT struct A { int n; A(const A &a) : n(a.n) {} // COMPLIANT user-defined copy ctor + A(const A &&other_a); // COMPLIANT user-defined move ctor }; + +class C1 {}; + +class C2 : public C1 { +public: + C2 &operator=(const C2 &); // COMPLIANT +}; \ No newline at end of file diff --git a/cpp/autosar/test/rules/M7-3-6/UsingDeclarationsUsedInHeaderFiles.expected b/cpp/autosar/test/rules/M7-3-6/UsingDeclarationsUsedInHeaderFiles.expected index 23bc5f6560..350c1f0cdc 100644 --- a/cpp/autosar/test/rules/M7-3-6/UsingDeclarationsUsedInHeaderFiles.expected +++ b/cpp/autosar/test/rules/M7-3-6/UsingDeclarationsUsedInHeaderFiles.expected @@ -1 +1,2 @@ | test.h:4:1:4:21 | using namespace std | Using directive or declaration used in a header file test.h. | +| test.h:18:3:18:21 | using namespace std | Using directive or declaration used in a header file test.h. | diff --git a/cpp/autosar/test/rules/M7-3-6/test.h b/cpp/autosar/test/rules/M7-3-6/test.h index 537e8ff3be..1286de2cf9 100644 --- a/cpp/autosar/test/rules/M7-3-6/test.h +++ b/cpp/autosar/test/rules/M7-3-6/test.h @@ -7,11 +7,15 @@ namespace my_namespace { int MY_CONST = 0; }; -int f() { +void f() { using my_namespace::MY_CONST; // COMPLIANT - function scope int x = MY_CONST; } +void test_fn_reported_in_400() { + using namespace std; // NON_COMPLIANT - only using declarations are exempted + // in function scope. +} #endif \ No newline at end of file diff --git a/cpp/autosar/test/rules/M9-3-3/test.cpp b/cpp/autosar/test/rules/M9-3-3/test.cpp index 033414a315..704a4ae5fd 100644 --- a/cpp/autosar/test/rules/M9-3-3/test.cpp +++ b/cpp/autosar/test/rules/M9-3-3/test.cpp @@ -161,3 +161,35 @@ class Z22 : Z1 { void f2() final {} // COMPLIANT void f3() { this->a = 100; } // COMPLIANT }; + +template class Array { +public: + T &back(); + +private: + T data[128]; + unsigned int size; +}; + +template class U> class Stack { +public: + T &Top() { + return this->data.back(); + } // COMPLIANT[FALSE_NEGATIVE|TRUE_NEGATIVE] - exception not specified in the + // standard, we opt to not raise an issue because the template can be both + // compliant and non-compliant depending on instantiations. +private: + U data; +}; + +using IntVectorStack = Stack; + +void test_template() { + IntVectorStack s; + + int i = s.Top(); +} + +class Z3 { + void f(int) = delete; // COMPLIANT +}; diff --git a/cpp/cert/src/rules/CTR56-CPP/DoNotUsePointerArithmeticOnPolymorphicObjects.ql b/cpp/cert/src/rules/CTR56-CPP/DoNotUsePointerArithmeticOnPolymorphicObjects.ql index 3b34500a80..a7756b6a6a 100644 --- a/cpp/cert/src/rules/CTR56-CPP/DoNotUsePointerArithmeticOnPolymorphicObjects.ql +++ b/cpp/cert/src/rules/CTR56-CPP/DoNotUsePointerArithmeticOnPolymorphicObjects.ql @@ -14,7 +14,7 @@ import cpp import codingstandards.cpp.cert import codingstandards.cpp.dataflow.DataFlow -import DataFlow::PathGraph +import NonFinalClassToPointerArithmeticExprFlow::PathGraph class ArrayAccessOrPointerArith extends Expr { ArrayAccessOrPointerArith() { @@ -38,12 +38,8 @@ class AddressOfPointerCreation extends ClassPointerCreation, AddressOfExpr { AddressOfPointerCreation() { this.getAnOperand().getUnderlyingType() instanceof Class } } -class NonFinalClassToPointerArithmeticExprConfig extends DataFlow::Configuration { - NonFinalClassToPointerArithmeticExprConfig() { - this = "NonFinalClassToPointerArithmeticExprConfig" - } - - override predicate isSource(DataFlow::Node source) { +module NonFinalClassToPointerArithmeticExprConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { exists(Class c | source.asExpr() instanceof ClassPointerCreation and source.asExpr().getUnderlyingType().(PointerType).getBaseType() = c @@ -52,17 +48,21 @@ class NonFinalClassToPointerArithmeticExprConfig extends DataFlow::Configuration ) } - override predicate isSink(DataFlow::Node sink) { + predicate isSink(DataFlow::Node sink) { exists(ArrayAccessOrPointerArith e | e.getAnOperand() = sink.asExpr()) } } +module NonFinalClassToPointerArithmeticExprFlow = + DataFlow::Global; + from - ArrayAccessOrPointerArith e, Class clz, Variable v, DataFlow::PathNode source, - DataFlow::PathNode sink + ArrayAccessOrPointerArith e, Class clz, Variable v, + NonFinalClassToPointerArithmeticExprFlow::PathNode source, + NonFinalClassToPointerArithmeticExprFlow::PathNode sink where not isExcluded(e, PointersPackage::doNotUsePointerArithmeticOnPolymorphicObjectsQuery()) and - any(NonFinalClassToPointerArithmeticExprConfig c).hasFlowPath(source, sink) and + NonFinalClassToPointerArithmeticExprFlow::flowPath(source, sink) and v.getAnAssignedValue() = source.getNode().asExpr() and ( e.(PointerArithmeticOperation).getAnOperand() = sink.getNode().asExpr() diff --git a/cpp/cert/src/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql b/cpp/cert/src/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql index 6cb62e9046..bdf6a7973e 100644 --- a/cpp/cert/src/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql +++ b/cpp/cert/src/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql @@ -14,25 +14,25 @@ import cpp import codingstandards.cpp.cert import codingstandards.cpp.dataflow.DataFlow -import DataFlow::PathGraph +import AllocationToDeleteFlow::PathGraph -class AllocationToDeleteConfig extends DataFlow::Configuration { - AllocationToDeleteConfig() { this = "AllocationToDelete" } +module AllocationToDeleteConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { source.asExpr() instanceof NewArrayExpr } - override predicate isSource(DataFlow::Node source) { source.asExpr() instanceof NewArrayExpr } - - override predicate isSink(DataFlow::Node sink) { + predicate isSink(DataFlow::Node sink) { exists(DeleteArrayExpr dae | dae.getExpr() = sink.asExpr()) } } +module AllocationToDeleteFlow = DataFlow::Global; + from - AllocationToDeleteConfig config, DataFlow::PathNode source, DataFlow::PathNode sink, + AllocationToDeleteFlow::PathNode source, AllocationToDeleteFlow::PathNode sink, NewArrayExpr newArray, DeleteArrayExpr deleteArray where not isExcluded(deleteArray.getExpr(), FreedPackage::doNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeQuery()) and - config.hasFlowPath(source, sink) and + AllocationToDeleteFlow::flowPath(source, sink) and newArray = source.getNode().asExpr() and deleteArray.getExpr() = sink.getNode().asExpr() and not newArray.getType().getUnspecifiedType() = deleteArray.getExpr().getType().getUnspecifiedType() diff --git a/cpp/cert/src/rules/MEM52-CPP/DetectAndHandleMemoryAllocationErrors.ql b/cpp/cert/src/rules/MEM52-CPP/DetectAndHandleMemoryAllocationErrors.ql index 64b05ce9d9..c25e1aa0ad 100644 --- a/cpp/cert/src/rules/MEM52-CPP/DetectAndHandleMemoryAllocationErrors.ql +++ b/cpp/cert/src/rules/MEM52-CPP/DetectAndHandleMemoryAllocationErrors.ql @@ -74,22 +74,20 @@ class NotWrappedNoThrowAllocExpr extends NoThrowAllocExpr { /** * A data flow configuration for finding nothrow allocation calls which are checked in some kind of guard. */ -class NoThrowNewErrorCheckConfig extends DataFlow::Configuration { - NoThrowNewErrorCheckConfig() { this = "NoThrowNewErrorCheckConfig" } - - override predicate isSource(DataFlow::Node source) { +module NoThrowNewErrorCheckConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { source.asExpr() instanceof NotWrappedNoThrowAllocExpr } - override predicate isSink(DataFlow::Node sink) { - sink.asExpr() = any(GuardCondition gc).getAChild*() - } + predicate isSink(DataFlow::Node sink) { sink.asExpr() = any(GuardCondition gc).getAChild*() } } +module NoThrowNewErrorCheckFlow = DataFlow::Global; + from NotWrappedNoThrowAllocExpr ae where not isExcluded(ae, AllocationsPackage::detectAndHandleMemoryAllocationErrorsQuery()) and - not any(NoThrowNewErrorCheckConfig nt).hasFlow(DataFlow::exprNode(ae), _) + not NoThrowNewErrorCheckFlow::flow(DataFlow::exprNode(ae), _) select ae, "nothrow new allocation of $@ returns here without a subsequent check to see whether the pointer is valid.", ae.getUnderlyingAlloc() as underlying, underlying.getType().getName() diff --git a/cpp/cert/src/rules/MEM53-CPP/ManuallyManagedLifetime.qll b/cpp/cert/src/rules/MEM53-CPP/ManuallyManagedLifetime.qll index d51151ff95..358a3583fc 100644 --- a/cpp/cert/src/rules/MEM53-CPP/ManuallyManagedLifetime.qll +++ b/cpp/cert/src/rules/MEM53-CPP/ManuallyManagedLifetime.qll @@ -3,7 +3,6 @@ import codingstandards.cpp.Conversion import codingstandards.cpp.TrivialType import ManuallyManagedLifetime import semmle.code.cpp.controlflow.Dominance -import codingstandards.cpp.dataflow.DataFlow2 import codingstandards.cpp.dataflow.TaintTracking /** @@ -11,10 +10,8 @@ import codingstandards.cpp.dataflow.TaintTracking * * We use a taint-tracking configuration because we also want to track sub-sections */ -class AllocToStaticCastConfig extends TaintTracking::Configuration { - AllocToStaticCastConfig() { this = "AllocToStaticCastConfig" } - - override predicate isSource(DataFlow::Node source) { +module AllocToStaticCastConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { exists(AllocationExpr ae | ae.getType().getUnspecifiedType() instanceof VoidPointerType and source.asExpr() = ae and @@ -23,7 +20,7 @@ class AllocToStaticCastConfig extends TaintTracking::Configuration { ) } - override predicate isSink(DataFlow::Node sink) { + predicate isSink(DataFlow::Node sink) { exists(StaticOrCStyleCast sc, Class nonTrivialClass | sc.getExpr() = sink.asExpr() and nonTrivialClass = sc.getType().getUnspecifiedType().(PointerType).getBaseType() and @@ -32,12 +29,14 @@ class AllocToStaticCastConfig extends TaintTracking::Configuration { } } +module AllocToStaticCastFlow = TaintTracking::Global; + /** * A cast of some existing memory, where we believe the resulting pointer has not been properly * constructed. */ class CastWithoutConstruction extends StaticOrCStyleCast { - CastWithoutConstruction() { any(AllocToStaticCastConfig c).hasFlowToExpr(getExpr()) } + CastWithoutConstruction() { AllocToStaticCastFlow::flowToExpr(getExpr()) } } /* @@ -96,18 +95,16 @@ class NonDestructingDeallocationCall extends Expr { * A data flow configuration from a `CastWithoutConstruction` to a free call on the memory without * an intervening destructor invocation. */ -class FreeWithoutDestructorConfig extends DataFlow2::Configuration { - FreeWithoutDestructorConfig() { this = "FreeWithoutDestructorConfig" } - - override predicate isSource(DataFlow::Node source) { +module FreeWithoutDestructorConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { source.asExpr() = any(CastWithoutConstruction c).getExpr() } - override predicate isSink(DataFlow::Node sink) { + predicate isSink(DataFlow::Node sink) { sink.asExpr() = any(NonDestructingDeallocationCall de).getFreedExpr() } - override predicate isBarrier(DataFlow::Node barrier) { + predicate isBarrier(DataFlow::Node barrier) { // Consider any expression which later has a destructor called upon it to be safe. exists(DirectOrIndirectDestructorCall dc | DataFlow::localFlow(barrier, DataFlow::exprNode(dc.getDestructedArgument())) @@ -122,7 +119,9 @@ class FreeWithoutDestructorConfig extends DataFlow2::Configuration { ) } - override predicate isAdditionalFlowStep(DataFlow::Node stepFrom, DataFlow::Node stepTo) { + predicate isAdditionalFlowStep(DataFlow::Node stepFrom, DataFlow::Node stepTo) { stepTo.asExpr().(StaticOrCStyleCast).getExpr() = stepFrom.asExpr() } } + +module FreeWithoutDestructorFlow = DataFlow::Global; diff --git a/cpp/cert/src/rules/MEM53-CPP/MissingConstructorCallForManuallyManagedObject.ql b/cpp/cert/src/rules/MEM53-CPP/MissingConstructorCallForManuallyManagedObject.ql index bc48af3a63..30c5280482 100644 --- a/cpp/cert/src/rules/MEM53-CPP/MissingConstructorCallForManuallyManagedObject.ql +++ b/cpp/cert/src/rules/MEM53-CPP/MissingConstructorCallForManuallyManagedObject.ql @@ -15,16 +15,16 @@ import codingstandards.cpp.cert import codingstandards.cpp.TrivialType import ManuallyManagedLifetime import codingstandards.cpp.dataflow.TaintTracking -import DataFlow::PathGraph +import AllocToStaticCastFlow::PathGraph /* * Find flow from a manual allocation returning void* to a static_cast (or c-style cast) * to a specific type. */ -from AllocToStaticCastConfig config, DataFlow::PathNode source, DataFlow::PathNode sink +from AllocToStaticCastFlow::PathNode source, AllocToStaticCastFlow::PathNode sink where not isExcluded(sink.getNode().asExpr(), AllocationsPackage::missingConstructorCallForManuallyManagedObjectQuery()) and - config.hasFlowPath(source, sink) + AllocToStaticCastFlow::flowPath(source, sink) select sink.getNode(), source, sink, "Allocation to cast without constructor call" diff --git a/cpp/cert/src/rules/MEM53-CPP/MissingDestructorCallForManuallyManagedObject.ql b/cpp/cert/src/rules/MEM53-CPP/MissingDestructorCallForManuallyManagedObject.ql index 26d128a98e..b498729d69 100644 --- a/cpp/cert/src/rules/MEM53-CPP/MissingDestructorCallForManuallyManagedObject.ql +++ b/cpp/cert/src/rules/MEM53-CPP/MissingDestructorCallForManuallyManagedObject.ql @@ -13,12 +13,12 @@ import cpp import codingstandards.cpp.cert import ManuallyManagedLifetime -import codingstandards.cpp.dataflow.DataFlow2 -import DataFlow2::PathGraph +import codingstandards.cpp.dataflow.DataFlow +import FreeWithoutDestructorFlow::PathGraph -from FreeWithoutDestructorConfig dc, DataFlow2::PathNode source, DataFlow2::PathNode sink +from FreeWithoutDestructorFlow::PathNode source, FreeWithoutDestructorFlow::PathNode sink where not isExcluded(sink.getNode().asExpr(), AllocationsPackage::missingDestructorCallForManuallyManagedObjectQuery()) and - dc.hasFlowPath(source, sink) + FreeWithoutDestructorFlow::flowPath(source, sink) select sink.getNode(), source, sink, "Memory freed without an appropriate destructor called." diff --git a/cpp/cert/test/rules/ERR55-CPP/HonorExceptionSpecifications.expected b/cpp/cert/test/rules/ERR55-CPP/HonorExceptionSpecifications.expected index ba234df2b8..5091d1fc2e 100644 --- a/cpp/cert/test/rules/ERR55-CPP/HonorExceptionSpecifications.expected +++ b/cpp/cert/test/rules/ERR55-CPP/HonorExceptionSpecifications.expected @@ -1,8 +1,35 @@ edges +| test_dynamic_specification.cpp:9:6:9:22 | throw_logic_error [logic_error] | test_dynamic_specification.cpp:34:3:34:19 | call to throw_logic_error [logic_error] | +| test_dynamic_specification.cpp:9:6:9:22 | throw_logic_error [logic_error] | test_dynamic_specification.cpp:38:3:38:19 | call to throw_logic_error [logic_error] | +| test_dynamic_specification.cpp:9:6:9:22 | throw_logic_error [logic_error] | test_dynamic_specification.cpp:43:3:43:19 | call to throw_logic_error [logic_error] | +| test_dynamic_specification.cpp:9:28:9:58 | throw ... [logic_error] | test_dynamic_specification.cpp:9:6:9:22 | throw_logic_error [logic_error] | | test_dynamic_specification.cpp:22:3:22:24 | throw ... [exception] | test_dynamic_specification.cpp:20:6:20:49 | test_simple_exception_spec_covered_inherited [exception] | | test_dynamic_specification.cpp:29:3:29:24 | throw ... [exception] | test_dynamic_specification.cpp:28:6:28:30 | test_no_throw_contravened [exception] | -| test_no_except.cpp:8:3:8:14 | throw ... [char *] | test_no_except.cpp:7:6:7:23 | test_noexcept_true [char *] | +| test_dynamic_specification.cpp:33:6:33:31 | indirect_throw_logic_error [logic_error] | test_dynamic_specification.cpp:48:3:48:28 | call to indirect_throw_logic_error [logic_error] | +| test_dynamic_specification.cpp:34:3:34:19 | call to throw_logic_error [logic_error] | test_dynamic_specification.cpp:33:6:33:31 | indirect_throw_logic_error [logic_error] | +| test_dynamic_specification.cpp:38:3:38:19 | call to throw_logic_error [logic_error] | test_dynamic_specification.cpp:37:6:37:46 | indirect_throw_logic_error_but_terminates [logic_error] | +| test_dynamic_specification.cpp:43:3:43:19 | call to throw_logic_error [logic_error] | test_dynamic_specification.cpp:41:6:41:48 | indirect_throw_logic_error_but_terminates_2 [logic_error] | +| test_dynamic_specification.cpp:48:3:48:28 | call to indirect_throw_logic_error [logic_error] | test_dynamic_specification.cpp:47:6:47:25 | test_indirect_throws [logic_error] | +| test_no_except.cpp:4:3:4:20 | throw ... [ExceptionA] | test_no_except.cpp:3:6:3:15 | test_throw [ExceptionA] | +| test_no_except.cpp:7:6:7:11 | throwA [ExceptionA] | test_no_except.cpp:8:25:8:30 | call to throwA [ExceptionA] | +| test_no_except.cpp:7:6:7:11 | throwA [ExceptionA] | test_no_except.cpp:9:42:9:47 | call to throwA [ExceptionA] | +| test_no_except.cpp:7:6:7:11 | throwA [ExceptionA] | test_no_except.cpp:12:3:12:8 | call to throwA [ExceptionA] | +| test_no_except.cpp:7:6:7:11 | throwA [ExceptionA] | test_no_except.cpp:16:3:16:8 | call to throwA [ExceptionA] | +| test_no_except.cpp:7:17:7:34 | throw ... [ExceptionA] | test_no_except.cpp:7:6:7:11 | throwA [ExceptionA] | +| test_no_except.cpp:8:6:8:19 | indirectThrowA [ExceptionA] | test_no_except.cpp:33:3:33:16 | call to indirectThrowA [ExceptionA] | +| test_no_except.cpp:8:25:8:30 | call to throwA [ExceptionA] | test_no_except.cpp:8:6:8:19 | indirectThrowA [ExceptionA] | +| test_no_except.cpp:9:42:9:47 | call to throwA [ExceptionA] | test_no_except.cpp:9:6:9:27 | noexceptIndirectThrowA [ExceptionA] | +| test_no_except.cpp:12:3:12:8 | call to throwA [ExceptionA] | test_no_except.cpp:11:6:11:24 | test_indirect_throw [ExceptionA] | +| test_no_except.cpp:16:3:16:8 | call to throwA [ExceptionA] | test_no_except.cpp:15:6:15:26 | test_indirect_throw_2 [ExceptionA] | +| test_no_except.cpp:33:3:33:16 | call to indirectThrowA [ExceptionA] | test_no_except.cpp:32:6:32:26 | test_indirect_throw_6 [ExceptionA] | #select | test_dynamic_specification.cpp:20:6:20:49 | test_simple_exception_spec_covered_inherited | test_dynamic_specification.cpp:22:3:22:24 | throw ... [exception] | test_dynamic_specification.cpp:20:6:20:49 | test_simple_exception_spec_covered_inherited [exception] | test_simple_exception_spec_covered_inherited can throw an exception of type std::exception but has a dynamic exception specification that does not specify this type. | | test_dynamic_specification.cpp:28:6:28:30 | test_no_throw_contravened | test_dynamic_specification.cpp:29:3:29:24 | throw ... [exception] | test_dynamic_specification.cpp:28:6:28:30 | test_no_throw_contravened [exception] | test_no_throw_contravened can throw an exception of type std::exception but has a dynamic exception specification that does not specify this type. | -| test_no_except.cpp:7:6:7:23 | test_noexcept_true | test_no_except.cpp:8:3:8:14 | throw ... [char *] | test_no_except.cpp:7:6:7:23 | test_noexcept_true [char *] | test_noexcept_true can throw an exception of type char * but is marked noexcept(true). | +| test_dynamic_specification.cpp:37:6:37:46 | indirect_throw_logic_error_but_terminates | test_dynamic_specification.cpp:9:28:9:58 | throw ... [logic_error] | test_dynamic_specification.cpp:37:6:37:46 | indirect_throw_logic_error_but_terminates [logic_error] | indirect_throw_logic_error_but_terminates can throw an exception of type std::logic_error but has a dynamic exception specification that does not specify this type. | +| test_dynamic_specification.cpp:41:6:41:48 | indirect_throw_logic_error_but_terminates_2 | test_dynamic_specification.cpp:9:28:9:58 | throw ... [logic_error] | test_dynamic_specification.cpp:41:6:41:48 | indirect_throw_logic_error_but_terminates_2 [logic_error] | indirect_throw_logic_error_but_terminates_2 can throw an exception of type std::logic_error but has a dynamic exception specification that does not specify this type. | +| test_dynamic_specification.cpp:47:6:47:25 | test_indirect_throws | test_dynamic_specification.cpp:9:28:9:58 | throw ... [logic_error] | test_dynamic_specification.cpp:47:6:47:25 | test_indirect_throws [logic_error] | test_indirect_throws can throw an exception of type std::logic_error but has a dynamic exception specification that does not specify this type. | +| test_no_except.cpp:3:6:3:15 | test_throw | test_no_except.cpp:4:3:4:20 | throw ... [ExceptionA] | test_no_except.cpp:3:6:3:15 | test_throw [ExceptionA] | test_throw can throw an exception of type ExceptionA but is marked noexcept(true). | +| test_no_except.cpp:9:6:9:27 | noexceptIndirectThrowA | test_no_except.cpp:7:17:7:34 | throw ... [ExceptionA] | test_no_except.cpp:9:6:9:27 | noexceptIndirectThrowA [ExceptionA] | noexceptIndirectThrowA can throw an exception of type ExceptionA but is marked noexcept(true). | +| test_no_except.cpp:11:6:11:24 | test_indirect_throw | test_no_except.cpp:7:17:7:34 | throw ... [ExceptionA] | test_no_except.cpp:11:6:11:24 | test_indirect_throw [ExceptionA] | test_indirect_throw can throw an exception of type ExceptionA but is marked noexcept(true). | +| test_no_except.cpp:15:6:15:26 | test_indirect_throw_2 | test_no_except.cpp:7:17:7:34 | throw ... [ExceptionA] | test_no_except.cpp:15:6:15:26 | test_indirect_throw_2 [ExceptionA] | test_indirect_throw_2 can throw an exception of type ExceptionA but is marked noexcept(true). | +| test_no_except.cpp:32:6:32:26 | test_indirect_throw_6 | test_no_except.cpp:7:17:7:34 | throw ... [ExceptionA] | test_no_except.cpp:32:6:32:26 | test_indirect_throw_6 [ExceptionA] | test_indirect_throw_6 can throw an exception of type ExceptionA but is marked noexcept(true). | diff --git a/cpp/cert/test/rules/ERR55-CPP/test_dynamic_specification.cpp b/cpp/cert/test/rules/ERR55-CPP/test_dynamic_specification.cpp index 4b218e1847..82e32bd433 100644 --- a/cpp/cert/test/rules/ERR55-CPP/test_dynamic_specification.cpp +++ b/cpp/cert/test/rules/ERR55-CPP/test_dynamic_specification.cpp @@ -27,4 +27,28 @@ void test_no_throw() throw() { // COMPLIANT void test_no_throw_contravened() throw() { // NON_COMPLIANT throw std::exception(); +} + +class DummyException {}; +void indirect_throw_logic_error() throw(std::logic_error) { + throw_logic_error(); // Exception flows out of function as specification is + // compatible +} +void indirect_throw_logic_error_but_terminates() throw() { // NON_COMPLIANT + throw_logic_error(); // Exception does not flow out of function due to + // specification +} +void indirect_throw_logic_error_but_terminates_2() // NON_COMPLIANT + throw(DummyException) { + throw_logic_error(); // Exception does not flow out of function due to + // specification +} + +void test_indirect_throws() throw() { // NON_COMPLIANT + indirect_throw_logic_error(); +} + +void test_indirect_throws_but_terminated() throw() { // COMPLIANT + indirect_throw_logic_error_but_terminates(); + indirect_throw_logic_error_but_terminates_2(); } \ No newline at end of file diff --git a/cpp/cert/test/rules/ERR55-CPP/test_no_except.cpp b/cpp/cert/test/rules/ERR55-CPP/test_no_except.cpp index 7897bed237..767dbb7ec0 100644 --- a/cpp/cert/test/rules/ERR55-CPP/test_no_except.cpp +++ b/cpp/cert/test/rules/ERR55-CPP/test_no_except.cpp @@ -1,9 +1,34 @@ -#include +class ExceptionA {}; -void test_noexcept_false() { // COMPLIANT - throw "test"; +void test_throw() noexcept(true) { + throw ExceptionA(); // NON_COMPLIANT - function marked as noexcept(true) } -void test_noexcept_true() noexcept(true) { // NON_COMPLIANT - throw "test"; +void throwA() { throw ExceptionA(); } +void indirectThrowA() { throwA(); } +void noexceptIndirectThrowA() noexcept { throwA(); } // NON_COMPLIANT + +void test_indirect_throw() noexcept(true) { + throwA(); // NON_COMPLIANT - function marked as noexcept(true) +} + +void test_indirect_throw_2() noexcept { + throwA(); // NON_COMPLIANT - function marked as noexcept(true) +} + +void test_indirect_throw_3() noexcept(false) { + throwA(); // COMPLIANT - function marked as noexcept(false) +} + +void test_indirect_throw_4() { + throwA(); // COMPLIANT - function marked as noexcept(false) +} + +void test_indirect_throw_5() noexcept { + noexceptIndirectThrowA(); // COMPLIANT - noexceptIndirectThrowA would call + // std::terminate() if ExceptionA is thrown +} + +void test_indirect_throw_6() noexcept { + indirectThrowA(); // NON_COMPLIANT } \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/Concurrency.qll b/cpp/common/src/codingstandards/cpp/Concurrency.qll index ab4b11dffe..d856fa4515 100644 --- a/cpp/common/src/codingstandards/cpp/Concurrency.qll +++ b/cpp/common/src/codingstandards/cpp/Concurrency.qll @@ -610,7 +610,7 @@ abstract class ThreadDependentMutex extends DataFlow::Node { class FlowBasedThreadDependentMutex extends ThreadDependentMutex { FlowBasedThreadDependentMutex() { // some sort of dataflow, likely through parameter passing. - exists(ThreadDependentMutexTaintTrackingConfiguration config | config.hasFlow(this, sink)) + ThreadDependentMutexFlow::flow(this, sink) } } @@ -738,18 +738,16 @@ class DeclarationInitAccessBasedThreadDependentMutex extends ThreadDependentMute override DataFlow::Node getAUsage() { result = DataFlow::exprNode(variableSource.getAnAccess()) } } -class ThreadDependentMutexTaintTrackingConfiguration extends TaintTracking::Configuration { - ThreadDependentMutexTaintTrackingConfiguration() { - this = "ThreadDependentMutexTaintTrackingConfiguration" - } - - override predicate isSource(DataFlow::Node node) { node.asExpr() instanceof MutexSource } +module ThreadDependentMutexConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node node) { node.asExpr() instanceof MutexSource } - override predicate isSink(DataFlow::Node node) { + predicate isSink(DataFlow::Node node) { exists(ThreadCreationFunction f | f.getAnArgument() = node.asExpr()) } } +module ThreadDependentMutexFlow = TaintTracking::Global; + /** * Models expressions that destroy mutexes. */ diff --git a/cpp/common/src/codingstandards/cpp/Cpp14Literal.qll b/cpp/common/src/codingstandards/cpp/Cpp14Literal.qll index afc8cb07a3..c3908008ef 100644 --- a/cpp/common/src/codingstandards/cpp/Cpp14Literal.qll +++ b/cpp/common/src/codingstandards/cpp/Cpp14Literal.qll @@ -24,7 +24,7 @@ module Cpp14Literal { * Octal literals must always start with the digit `0`. */ class OctalLiteral extends IntegerLiteral { - OctalLiteral() { getValueText().regexpMatch("\\s*0[0-7']+[uUlL]*\\s*") } + OctalLiteral() { getValueText().regexpMatch("\\s*0[0-7']*[uUlL]*\\s*") } override string getAPrimaryQlClass() { result = "OctalLiteral" } } diff --git a/cpp/common/src/codingstandards/cpp/Literals.qll b/cpp/common/src/codingstandards/cpp/Literals.qll index 0a6a40aa19..d4e11154fa 100644 --- a/cpp/common/src/codingstandards/cpp/Literals.qll +++ b/cpp/common/src/codingstandards/cpp/Literals.qll @@ -12,3 +12,19 @@ string getTruncatedLiteralText(Literal l) { else result = text ) } + +class WideStringLiteral extends StringLiteral { + WideStringLiteral() { this.getValueText().regexpMatch("(?s)\\s*L\".*") } +} + +class Utf8StringLiteral extends StringLiteral { + Utf8StringLiteral() { this.getValueText().regexpMatch("(?s)\\s*u8\".*") } +} + +class Utf16StringLiteral extends StringLiteral { + Utf16StringLiteral() { this.getValueText().regexpMatch("(?s)\\s*u\".*") } +} + +class Utf32StringLiteral extends StringLiteral { + Utf32StringLiteral() { this.getValueText().regexpMatch("(?s)\\s*U\".*") } +} diff --git a/cpp/common/src/codingstandards/cpp/Nullness.qll b/cpp/common/src/codingstandards/cpp/Nullness.qll index b04c013a2d..d76db4afad 100644 --- a/cpp/common/src/codingstandards/cpp/Nullness.qll +++ b/cpp/common/src/codingstandards/cpp/Nullness.qll @@ -1,19 +1,14 @@ import cpp import codingstandards.cpp.dataflow.DataFlow -import codingstandards.cpp.dataflow.DataFlow2 private class PointerToMember extends Variable { PointerToMember() { this.getType() instanceof PointerToMemberType } } -class NullPointerToPointerMemberExpressionConfig extends DataFlow::Configuration { - NullPointerToPointerMemberExpressionConfig() { - this = "NullPointerToPointerMemberExpressionConfig" - } - - override predicate isSource(DataFlow::Node source) { source.asExpr() instanceof NullValue } +module NullPointerToPointerMemberExpressionConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { source.asExpr() instanceof NullValue } - override predicate isSink(DataFlow::Node sink) { + predicate isSink(DataFlow::Node sink) { // The null value can flow to a pointer-to-member expressions that points to a function exists(VariableCall call, VariableAccess va | call.getQualifier() = va and va = sink.asExpr() | va.getTarget() instanceof PointerToMember @@ -24,12 +19,13 @@ class NullPointerToPointerMemberExpressionConfig extends DataFlow::Configuration } } -class NullValueToAssignmentConfig extends DataFlow2::Configuration { - NullValueToAssignmentConfig() { this = "NullValueToAssignmentConfig" } +module NullPointerToPointerMemberExpressionFlow = + DataFlow::Global; - override predicate isSource(DataFlow::Node source) { source.asExpr() instanceof NullValue } +module NullValueToAssignmentConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { source.asExpr() instanceof NullValue } - override predicate isSink(DataFlow::Node sink) { - exists(Assignment a | a.getRValue() = sink.asExpr()) - } + predicate isSink(DataFlow::Node sink) { exists(Assignment a | a.getRValue() = sink.asExpr()) } } + +module NullValueToAssignmentFlow = DataFlow::Global; diff --git a/cpp/common/src/codingstandards/cpp/Operator.qll b/cpp/common/src/codingstandards/cpp/Operator.qll index 72ee04b68f..b8e703d9f4 100644 --- a/cpp/common/src/codingstandards/cpp/Operator.qll +++ b/cpp/common/src/codingstandards/cpp/Operator.qll @@ -264,3 +264,64 @@ class UserOverloadedOperator extends Function { not this.isCompilerGenerated() } } + +private newtype TOperatorUse = + TBuiltinOperatorUse(Operation op) or + TOverloadedOperatorUse(FunctionCall call, Operator op) { op.getACallToThisFunction() = call } + +/** + * A class to reason about builtin operator and overloaded operator use. + */ +class OperatorUse extends TOperatorUse { + string toString() { + exists(Operation op | result = op.toString() and this = TBuiltinOperatorUse(op)) + or + exists(Operator op | result = op.toString() and this = TOverloadedOperatorUse(_, op)) + } + + predicate isOverloaded() { this = TOverloadedOperatorUse(_, _) } + + Operation asBuiltin() { this = TBuiltinOperatorUse(result) } + + Operator asOverloaded(FunctionCall call) { this = TOverloadedOperatorUse(call, result) } + + Type getType() { + result = this.asBuiltin().getType() + or + result = this.asOverloaded(_).getType() + } + + Parameter getParameter(int index) { result = this.asOverloaded(_).getParameter(index) } + + Parameter getAParameter() { result = this.asOverloaded(_).getParameter(_) } + + Expr getAnOperand() { + result = this.asBuiltin().getAnOperand() + or + exists(FunctionCall call, Operator op | op = this.asOverloaded(call) | + result = call.getAnArgument() + ) + } + + Location getLocation() { + result = this.asBuiltin().getLocation() + or + exists(FunctionCall call, Operator op | op = this.asOverloaded(call) | + result = call.getLocation() + ) + } + + string getOperator() { + result = this.asBuiltin().getOperator() + or + result = this.asOverloaded(_).getName().regexpCapture("^operator(.*)$", 1) + } +} + +class UnaryOperatorUse extends OperatorUse { + UnaryOperatorUse() { + this.asBuiltin() instanceof UnaryOperation + or + this.asOverloaded(_).getNumberOfParameters() = 0 + } +} diff --git a/cpp/common/src/codingstandards/cpp/Overflow.qll b/cpp/common/src/codingstandards/cpp/Overflow.qll index 130e1bb42d..3de3a43bf6 100644 --- a/cpp/common/src/codingstandards/cpp/Overflow.qll +++ b/cpp/common/src/codingstandards/cpp/Overflow.qll @@ -1,5 +1,5 @@ /** - * This module provides predicates for checking whether an operation overflows or wraps. + * This module provides predicates for checking whether an integer operation overflows, underflows or wraps. */ import cpp @@ -10,10 +10,12 @@ import codingstandards.cpp.dataflow.TaintTracking import semmle.code.cpp.valuenumbering.GlobalValueNumbering /** - * An operation that may overflow or underflow. + * An integer operation that may overflow, underflow or wrap. */ class InterestingOverflowingOperation extends Operation { InterestingOverflowingOperation() { + // We are only interested in integer experssions + this.getUnderlyingType() instanceof IntegralType and // Might overflow or underflow ( exprMightOverflowNegatively(this) diff --git a/cpp/common/src/codingstandards/cpp/Type.qll b/cpp/common/src/codingstandards/cpp/Type.qll index a49e30e927..a03790a38a 100644 --- a/cpp/common/src/codingstandards/cpp/Type.qll +++ b/cpp/common/src/codingstandards/cpp/Type.qll @@ -22,3 +22,40 @@ class FundamentalType extends BuiltInType { class IncompleteType extends Class { IncompleteType() { not hasDefinition() } } + +/** + * A type that implements the BitmaskType trait. + * https://en.cppreference.com/w/cpp/named_req/BitmaskType + */ +abstract class BitmaskType extends Type { } + +/** + * Holds if `enum` implements required overload `overload` to implement + * the BitmaskType trait. + */ +private predicate isRequiredEnumOverload(Enum enum, Function overload) { + overload.getName().regexpMatch("operator([&|^~]|&=|\\|=)") and + forex(Parameter p | p = overload.getAParameter() | + ( + p.getType() = enum + or + p.getType().(ReferenceType).getBaseType() = enum + ) + ) +} + +private class EnumBitmaskType extends BitmaskType, Enum { + EnumBitmaskType() { + // Implements all the required overload + count(Function overload | isRequiredEnumOverload(this, overload)) = 6 + } +} + +/** + * A type without `const` and `volatile` specifiers. + */ +Type stripSpecifiers(Type type) { + if type instanceof SpecifiedType + then result = stripSpecifiers(type.(SpecifiedType).getBaseType()) + else result = type +} diff --git a/cpp/common/src/codingstandards/cpp/allocations/PlacementNew.qll b/cpp/common/src/codingstandards/cpp/allocations/PlacementNew.qll index 39451a743b..5547f2e151 100644 --- a/cpp/common/src/codingstandards/cpp/allocations/PlacementNew.qll +++ b/cpp/common/src/codingstandards/cpp/allocations/PlacementNew.qll @@ -158,20 +158,20 @@ class AllocationExprPlacementNewOrigin extends PlacementNewMemoryOrigin { * A data flow configuration that identifies the origin of the placement argument to a placement * new expression. */ -class PlacementNewOriginConfig extends DataFlow::Configuration { - PlacementNewOriginConfig() { this = "PlacementNewOrigin" } +module PlacementNewOriginConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { source instanceof PlacementNewMemoryOrigin } - override predicate isSource(DataFlow::Node source) { source instanceof PlacementNewMemoryOrigin } - - override predicate isSink(DataFlow::Node sink) { + predicate isSink(DataFlow::Node sink) { sink.asExpr() = any(PlacementNewExpr pne).getPlacementExpr() // TODO direct calls to placement operator new? } - override predicate isAdditionalFlowStep(DataFlow::Node stepFrom, DataFlow::Node stepTo) { + predicate isAdditionalFlowStep(DataFlow::Node stepFrom, DataFlow::Node stepTo) { // Slightly surprisingly, we can't see the `StaticOrCStyleCast`s as a source out-of-the-box with data // flow - it's only reported under taint tracking. We therefore add a step through static // casts so that we can see them as sources. stepTo.asExpr().(StaticOrCStyleCast).getExpr() = stepFrom.asExpr() } } + +module PlacementNewOriginFlow = DataFlow::Global; diff --git a/cpp/common/src/codingstandards/cpp/deadcode/UselessAssignments.qll b/cpp/common/src/codingstandards/cpp/deadcode/UselessAssignments.qll index e326f814be..465b023f3f 100644 --- a/cpp/common/src/codingstandards/cpp/deadcode/UselessAssignments.qll +++ b/cpp/common/src/codingstandards/cpp/deadcode/UselessAssignments.qll @@ -43,7 +43,11 @@ class InterestingStackVariable extends StackVariable { // A reference parameter can have an affect outside the enclosing function not mayEscape(this) and // Not a loop control variable, explicitly excluded - not this instanceof LoopControlVariable + not this instanceof LoopControlVariable and + // Ignore variables in uninstantiated templates + not this.isFromUninstantiatedTemplate(_) and + // Ignore compiler generated variables, such as those generated for range based for loops + not this.isCompilerGenerated() } } diff --git a/cpp/common/src/codingstandards/cpp/exceptions/ExceptionFlow.qll b/cpp/common/src/codingstandards/cpp/exceptions/ExceptionFlow.qll index df23fa4e95..5a4e7fee6e 100644 --- a/cpp/common/src/codingstandards/cpp/exceptions/ExceptionFlow.qll +++ b/cpp/common/src/codingstandards/cpp/exceptions/ExceptionFlow.qll @@ -4,6 +4,7 @@ import cpp import codingstandards.cpp.standardlibrary.Exceptions +import codingstandards.cpp.exceptions.ExceptionSpecifications import ThirdPartyExceptions /* @@ -312,7 +313,28 @@ class ReThrowExprThrowingExpr extends ReThrowExpr, ThrowingExpr { /** An expression which calls a function which may throw an exception. */ class FunctionCallThrowingExpr extends FunctionCall, ThrowingExpr { - override ExceptionType getAnExceptionType() { result = getAFunctionThrownType(getTarget(), _) } + override ExceptionType getAnExceptionType() { + exists(Function target | + target = getTarget() and + result = getAFunctionThrownType(target, _) and + // [expect.spec] states that throwing an exception type that is prohibited + // by the specification will result in the program terminating, unless + // a custom `unexpected_handler` is registered that throws an exception type + // which is compatible with the dynamic exception specification, or the + // dynamic exception specification lists `std::bad_exception`, in which case + // a `std::bad_exception` is thrown. + // As dynamic exception specifications and the `unexpected_handler` are both + // deprecated in C++14 and removed in C++17, we assume a default + // `std::unexpected` handler that calls `std::terminate` and therefore + // do not propagate such exceptions to the call sites for the function. + not ( + hasDynamicExceptionSpecification(target) and + not result = getAHandledExceptionType(target.getAThrownType()) + or + isNoExceptTrue(target) + ) + ) + } } module ExceptionPathGraph { diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/Const.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Const.qll index 1245139eb1..09f40388cc 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/cpp/Const.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Const.qll @@ -5,7 +5,6 @@ import codingstandards.cpp.exclusions.RuleMetadata newtype ConstQuery = TRemoveConstOrVolatileQualificationAutosarQuery() or - TDeclarationUnmodifiedParamMissingConstSpecifierQuery() or TDeclarationUnmodifiedObjectMissingConstSpecifierQuery() or TVariableMissingConstexprQuery() or TFunctionMissingConstexprQuery() or @@ -28,15 +27,6 @@ predicate isConstQueryMetadata(Query query, string queryId, string ruleId, strin ruleId = "A5-2-3" and category = "required" or - query = - // `Query` instance for the `declarationUnmodifiedParamMissingConstSpecifier` query - ConstPackage::declarationUnmodifiedParamMissingConstSpecifierQuery() and - queryId = - // `@id` for the `declarationUnmodifiedParamMissingConstSpecifier` query - "cpp/autosar/declaration-unmodified-param-missing-const-specifier" and - ruleId = "A7-1-1" and - category = "required" - or query = // `Query` instance for the `declarationUnmodifiedObjectMissingConstSpecifier` query ConstPackage::declarationUnmodifiedObjectMissingConstSpecifierQuery() and @@ -145,13 +135,6 @@ module ConstPackage { TQueryCPP(TConstPackageQuery(TRemoveConstOrVolatileQualificationAutosarQuery())) } - Query declarationUnmodifiedParamMissingConstSpecifierQuery() { - //autogenerate `Query` type - result = - // `Query` type for `declarationUnmodifiedParamMissingConstSpecifier` query - TQueryCPP(TConstPackageQuery(TDeclarationUnmodifiedParamMissingConstSpecifierQuery())) - } - Query declarationUnmodifiedObjectMissingConstSpecifierQuery() { //autogenerate `Query` type result = diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/Declarations.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Declarations.qll index 5d51fd522f..92a06429c2 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/cpp/Declarations.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Declarations.qll @@ -9,6 +9,7 @@ newtype DeclarationsQuery = TGlobalSizedOperatorDeleteNotDefinedQuery() or TGlobalUnsizedOperatorDeleteNotDefinedQuery() or TVariableWidthIntegerTypesUsedQuery() or + TVariableWidthPlainCharTypeUsedQuery() or TAutoSpecifierNotUsedAppropriatelyInFunctionDefinitionQuery() or TAutoSpecifierNotUsedAppropriatelyInVariableDefinitionQuery() or TIdentifierDeclarationAndInitializationNotOnSeparateLinesQuery() or @@ -68,6 +69,15 @@ predicate isDeclarationsQueryMetadata(Query query, string queryId, string ruleId ruleId = "A3-9-1" and category = "required" or + query = + // `Query` instance for the `variableWidthPlainCharTypeUsed` query + DeclarationsPackage::variableWidthPlainCharTypeUsedQuery() and + queryId = + // `@id` for the `variableWidthPlainCharTypeUsed` query + "cpp/autosar/variable-width-plain-char-type-used" and + ruleId = "A3-9-1" and + category = "required" + or query = // `Query` instance for the `autoSpecifierNotUsedAppropriatelyInFunctionDefinition` query DeclarationsPackage::autoSpecifierNotUsedAppropriatelyInFunctionDefinitionQuery() and @@ -213,6 +223,13 @@ module DeclarationsPackage { TQueryCPP(TDeclarationsPackageQuery(TVariableWidthIntegerTypesUsedQuery())) } + Query variableWidthPlainCharTypeUsedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `variableWidthPlainCharTypeUsed` query + TQueryCPP(TDeclarationsPackageQuery(TVariableWidthPlainCharTypeUsedQuery())) + } + Query autoSpecifierNotUsedAppropriatelyInFunctionDefinitionQuery() { //autogenerate `Query` type result = diff --git a/cpp/common/src/codingstandards/cpp/rules/accessofundefinedmemberthroughnullpointer/AccessOfUndefinedMemberThroughNullPointer.qll b/cpp/common/src/codingstandards/cpp/rules/accessofundefinedmemberthroughnullpointer/AccessOfUndefinedMemberThroughNullPointer.qll index 2ee7036a1c..ab8659efd8 100644 --- a/cpp/common/src/codingstandards/cpp/rules/accessofundefinedmemberthroughnullpointer/AccessOfUndefinedMemberThroughNullPointer.qll +++ b/cpp/common/src/codingstandards/cpp/rules/accessofundefinedmemberthroughnullpointer/AccessOfUndefinedMemberThroughNullPointer.qll @@ -8,21 +8,23 @@ import codingstandards.cpp.Exclusions import codingstandards.cpp.Nullness import codingstandards.cpp.Expr import codingstandards.cpp.dataflow.DataFlow -import DataFlow::PathGraph +import NullPointerToPointerMemberExpressionFlow::PathGraph abstract class AccessOfUndefinedMemberThroughNullPointerSharedQuery extends Query { } Query getQuery() { result instanceof AccessOfUndefinedMemberThroughNullPointerSharedQuery } query predicate problems( - PointerToMemberExpr pointerToMemberExpr, DataFlow::PathNode source, DataFlow::PathNode sink, - string message, Location sourceLocation, string sourceDescription + PointerToMemberExpr pointerToMemberExpr, + NullPointerToPointerMemberExpressionFlow::PathNode source, + NullPointerToPointerMemberExpressionFlow::PathNode sink, string message, Location sourceLocation, + string sourceDescription ) { not isExcluded(pointerToMemberExpr, getQuery()) and message = "A null pointer-to-member value from $@ is passed as the second operand to a pointer-to-member expression." and sink.getNode().asExpr() = pointerToMemberExpr.getPointerExpr() and - any(NullPointerToPointerMemberExpressionConfig config).hasFlowPath(source, sink) and + NullPointerToPointerMemberExpressionFlow::flowPath(source, sink) and sourceLocation = source.getNode().getLocation() and sourceDescription = "initialization" } diff --git a/cpp/common/src/codingstandards/cpp/rules/accessofundefinedmemberthroughuninitializedstaticpointer/AccessOfUndefinedMemberThroughUninitializedStaticPointer.qll b/cpp/common/src/codingstandards/cpp/rules/accessofundefinedmemberthroughuninitializedstaticpointer/AccessOfUndefinedMemberThroughUninitializedStaticPointer.qll index 7055cce296..ca1e2a4282 100644 --- a/cpp/common/src/codingstandards/cpp/rules/accessofundefinedmemberthroughuninitializedstaticpointer/AccessOfUndefinedMemberThroughUninitializedStaticPointer.qll +++ b/cpp/common/src/codingstandards/cpp/rules/accessofundefinedmemberthroughuninitializedstaticpointer/AccessOfUndefinedMemberThroughUninitializedStaticPointer.qll @@ -44,7 +44,7 @@ newtype TStaticMemberPointerAbstractValue = AssignedNullValue(StaticMemberPointer ptr, Expr val) { // A null value tracked via the data flow graph exists(ControlFlowNode n | - any(NullValueToAssignmentConfig config).hasFlow(_, DataFlow::exprNode(val)) and + NullValueToAssignmentFlow::flow(_, DataFlow::exprNode(val)) and n.(Assignment).getLValue() = ptr.getAnAccess() and n.(Assignment).getRValue() = val ) @@ -63,7 +63,7 @@ newtype TStaticMemberPointerAbstractValue = AssignedNonNullValue(StaticMemberPointer ptr, Expr val) { // A non-null value tracked via the data flow graph exists(ControlFlowNode n | - not any(NullValueToAssignmentConfig config).hasFlow(_, DataFlow::exprNode(val)) and + NullValueToAssignmentFlow::flow(_, DataFlow::exprNode(val)) and n.(Assignment).getLValue() = ptr.getAnAccess() and n.(Assignment).getRValue() = val ) diff --git a/cpp/common/src/codingstandards/cpp/rules/constlikereturnvalue/ConstLikeReturnValue.qll b/cpp/common/src/codingstandards/cpp/rules/constlikereturnvalue/ConstLikeReturnValue.qll index 56d1bd3d47..f4636b6b13 100644 --- a/cpp/common/src/codingstandards/cpp/rules/constlikereturnvalue/ConstLikeReturnValue.qll +++ b/cpp/common/src/codingstandards/cpp/rules/constlikereturnvalue/ConstLikeReturnValue.qll @@ -6,7 +6,7 @@ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions import codingstandards.cpp.dataflow.DataFlow -import DataFlow::PathGraph +import DFFlow::PathGraph abstract class ConstLikeReturnValueSharedQuery extends Query { } @@ -41,22 +41,18 @@ class ObjectWrite extends Expr { /** * DF configuration for flows from a `NotModifiableCall` to a object modifications. */ -class DFConf extends DataFlow::Configuration { - DFConf() { this = "DFConf" } +module DFConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { source.asExpr() instanceof NotModifiableCall } - override predicate isSource(DataFlow::Node source) { - source.asExpr() instanceof NotModifiableCall - } - - override predicate isSink(DataFlow::Node sink) { sink.asExpr() instanceof ObjectWrite } + predicate isSink(DataFlow::Node sink) { sink.asExpr() instanceof ObjectWrite } } -query predicate problems( - Element e, DataFlow::PathNode source, DataFlow::PathNode sink, string message -) { +module DFFlow = DataFlow::Global; + +query predicate problems(Element e, DFFlow::PathNode source, DFFlow::PathNode sink, string message) { not isExcluded(e, getQuery()) and // the modified object comes from a call to one of the ENV functions - any(DFConf d).hasFlowPath(source, sink) and + DFFlow::flowPath(source, sink) and e = sink.getNode().asExpr() and message = "The object returned by the function " + diff --git a/cpp/common/src/codingstandards/cpp/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.qll b/cpp/common/src/codingstandards/cpp/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.qll index 20e73e938b..0aa8d64feb 100644 --- a/cpp/common/src/codingstandards/cpp/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.qll +++ b/cpp/common/src/codingstandards/cpp/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.qll @@ -7,48 +7,47 @@ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions import codingstandards.cpp.dataflow.DataFlow -import DataFlow::PathGraph +import ArrayToPointerDiffOperandFlow::PathGraph -class ArrayToPointerDiffOperandConfig extends DataFlow::Configuration { - ArrayToPointerDiffOperandConfig() { this = "ArrayToPointerDiffOperandConfig" } - - override predicate isSource(DataFlow::Node source) { +module ArrayToPointerDiffOperandConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { source.asExpr().(VariableAccess).getType() instanceof ArrayType or // Consider array to pointer decay for parameters. source.asExpr().(VariableAccess).getTarget().(Parameter).getType() instanceof ArrayType } - override predicate isSink(DataFlow::Node sink) { + predicate isSink(DataFlow::Node sink) { exists(PointerDiffExpr e | e.getAnOperand() = sink.asExpr()) } - override predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) { + predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) { // Add a flow step from the base to the array expression to track pointers to elements of the array. exists(ArrayExpr e | e.getArrayBase() = pred.asExpr() and e = succ.asExpr()) } } +module ArrayToPointerDiffOperandFlow = DataFlow::Global; + abstract class DoNotSubtractPointersAddressingDifferentArraysSharedQuery extends Query { } Query getQuery() { result instanceof DoNotSubtractPointersAddressingDifferentArraysSharedQuery } query predicate problems( - DataFlow::Node sinkNode, DataFlow::PathNode source, DataFlow::PathNode sink, string message, - Variable currentOperandPointee, string currentOperandPointeeName, Variable otherOperandPointee, - string otherOperandPointeeName + DataFlow::Node sinkNode, ArrayToPointerDiffOperandFlow::PathNode source, + ArrayToPointerDiffOperandFlow::PathNode sink, string message, Variable currentOperandPointee, + string currentOperandPointeeName, Variable otherOperandPointee, string otherOperandPointeeName ) { exists( - PointerDiffExpr pointerSubtraction, string side, ArrayToPointerDiffOperandConfig c, - Variable sourceLeft, Variable sourceRight + PointerDiffExpr pointerSubtraction, string side, Variable sourceLeft, Variable sourceRight | not isExcluded(pointerSubtraction, getQuery()) and - c.hasFlow(DataFlow::exprNode(sourceLeft.getAnAccess()), + ArrayToPointerDiffOperandFlow::flow(DataFlow::exprNode(sourceLeft.getAnAccess()), DataFlow::exprNode(pointerSubtraction.getLeftOperand())) and - c.hasFlow(DataFlow::exprNode(sourceRight.getAnAccess()), + ArrayToPointerDiffOperandFlow::flow(DataFlow::exprNode(sourceRight.getAnAccess()), DataFlow::exprNode(pointerSubtraction.getRightOperand())) and not sourceLeft = sourceRight and - c.hasFlowPath(source, sink) and + ArrayToPointerDiffOperandFlow::flowPath(source, sink) and ( source.getNode().asExpr() = sourceLeft.getAnAccess() and sink.getNode().asExpr() = pointerSubtraction.getLeftOperand() and diff --git a/cpp/common/src/codingstandards/cpp/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.qll b/cpp/common/src/codingstandards/cpp/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.qll index 5fce6d99fc..dd10b840c5 100644 --- a/cpp/common/src/codingstandards/cpp/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.qll +++ b/cpp/common/src/codingstandards/cpp/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.qll @@ -18,24 +18,22 @@ Query getQuery() { result instanceof DoNotUsePointerArithmeticToAddressDifferent * A data-flow configuration that tracks access to an array to type to an array index expression. * This is used to determine possible pointer to array creations. */ -class ArrayToArrayExprConfig extends DataFlow::Configuration { - ArrayToArrayExprConfig() { this = "ArrayToArrayIndexConfig" } - - override predicate isSource(DataFlow::Node source) { +module ArrayToArrayExprConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { source.asExpr().(VariableAccess).getType() instanceof ArrayType } - override predicate isSink(DataFlow::Node sink) { - exists(ArrayExpr c | c.getArrayBase() = sink.asExpr()) - } + predicate isSink(DataFlow::Node sink) { exists(ArrayExpr c | c.getArrayBase() = sink.asExpr()) } } +module ArrayToArrayExprFlow = DataFlow::Global; + /** Holds if the address taken expression `addressOf` takes the address of an array element at `index` of `array` with size `arraySize`. */ predicate pointerOperandCreation(AddressOfExpr addressOf, Variable array, int arraySize, int index) { arraySize = array.getType().(ArrayType).getArraySize() and exists(ArrayExpr ae | - any(ArrayToArrayExprConfig cfg) - .hasFlow(DataFlow::exprNode(array.getAnAccess()), DataFlow::exprNode(ae.getArrayBase())) and + ArrayToArrayExprFlow::flow(DataFlow::exprNode(array.getAnAccess()), + DataFlow::exprNode(ae.getArrayBase())) and index = lowerBound(ae.getArrayOffset().getFullyConverted()) and addressOf.getOperand() = ae ) diff --git a/cpp/common/src/codingstandards/cpp/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.qll b/cpp/common/src/codingstandards/cpp/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.qll index c8ac2fd873..155ed1a7f4 100644 --- a/cpp/common/src/codingstandards/cpp/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.qll +++ b/cpp/common/src/codingstandards/cpp/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.qll @@ -8,7 +8,7 @@ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions import codingstandards.cpp.dataflow.DataFlow -import DataFlow::PathGraph +import ArrayToRelationalOperationOperandFlow::PathGraph abstract class DoNotUseRelationalOperatorsWithDifferingArraysSharedQuery extends Query { } @@ -32,21 +32,22 @@ class DecayedArrayAccess extends ArraySource { } } -class ArrayToRelationalOperationOperandConfig extends DataFlow::Configuration { - ArrayToRelationalOperationOperandConfig() { this = "ArrayToRelationalOperationOperandConfig" } +module ArrayToRelationalOperationOperandConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { source instanceof ArraySource } - override predicate isSource(DataFlow::Node source) { source instanceof ArraySource } - - override predicate isSink(DataFlow::Node sink) { + predicate isSink(DataFlow::Node sink) { exists(RelationalOperation op | op.getAnOperand() = sink.asExpr()) } - override predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) { + predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) { // Add a flow step from the base to the array expression to track pointers to elements of the array. exists(ArrayExpr e | e.getArrayBase() = pred.asExpr() and e = succ.asExpr()) } } +module ArrayToRelationalOperationOperandFlow = + DataFlow::Global; + predicate isComparingPointers(RelationalOperation op) { forall(Expr operand | operand = op.getAnOperand() | operand.getType() instanceof PointerType or operand.getType() instanceof ArrayType @@ -54,22 +55,20 @@ predicate isComparingPointers(RelationalOperation op) { } query predicate problems( - RelationalOperation compare, DataFlow::PathNode source, DataFlow::PathNode sink, string message, + RelationalOperation compare, ArrayToRelationalOperationOperandFlow::PathNode source, + ArrayToRelationalOperationOperandFlow::PathNode sink, string message, Variable selectedOperandPointee, string selectedOperandPointeeName, Variable otherOperandPointee, string otherOperandPointeeName ) { not isExcluded(compare, getQuery()) and - exists( - ArrayToRelationalOperationOperandConfig c, Variable sourceLeft, Variable sourceRight, - string side - | - c.hasFlow(DataFlow::exprNode(sourceLeft.getAnAccess()), + exists(Variable sourceLeft, Variable sourceRight, string side | + ArrayToRelationalOperationOperandFlow::flow(DataFlow::exprNode(sourceLeft.getAnAccess()), DataFlow::exprNode(compare.getLeftOperand())) and - c.hasFlow(DataFlow::exprNode(sourceRight.getAnAccess()), + ArrayToRelationalOperationOperandFlow::flow(DataFlow::exprNode(sourceRight.getAnAccess()), DataFlow::exprNode(compare.getRightOperand())) and not sourceLeft = sourceRight and isComparingPointers(compare) and - c.hasFlowPath(source, sink) and + ArrayToRelationalOperationOperandFlow::flowPath(source, sink) and ( source.getNode().asExpr() = sourceLeft.getAnAccess() and sink.getNode().asExpr() = compare.getLeftOperand() and diff --git a/cpp/common/src/codingstandards/cpp/rules/nonbooleanifstmt/NonBooleanIfStmt.qll b/cpp/common/src/codingstandards/cpp/rules/nonbooleanifstmt/NonBooleanIfStmt.qll index 18346a8159..bd84597a44 100644 --- a/cpp/common/src/codingstandards/cpp/rules/nonbooleanifstmt/NonBooleanIfStmt.qll +++ b/cpp/common/src/codingstandards/cpp/rules/nonbooleanifstmt/NonBooleanIfStmt.qll @@ -14,6 +14,8 @@ query predicate problems(Expr condition, string message) { not isExcluded(condition, getQuery()) and exists(IfStmt ifStmt, Type explicitConversionType | condition = ifStmt.getCondition() and + //exclude any generated conditions + not condition.isCompilerGenerated() and not ifStmt.isFromUninstantiatedTemplate(_) and explicitConversionType = condition.getExplicitlyConverted().getUnderlyingType() and not explicitConversionType instanceof BoolType and diff --git a/cpp/common/src/codingstandards/cpp/rules/nonbooleaniterationstmt/NonBooleanIterationStmt.qll b/cpp/common/src/codingstandards/cpp/rules/nonbooleaniterationstmt/NonBooleanIterationStmt.qll index f1ee555406..c342811c52 100644 --- a/cpp/common/src/codingstandards/cpp/rules/nonbooleaniterationstmt/NonBooleanIterationStmt.qll +++ b/cpp/common/src/codingstandards/cpp/rules/nonbooleaniterationstmt/NonBooleanIterationStmt.qll @@ -16,6 +16,8 @@ query predicate problems(Loop loopStmt, string message) { condition = loopStmt.getCondition() and explicitConversionType = condition.getExplicitlyConverted().getType().getUnspecifiedType() and not explicitConversionType instanceof BoolType and + //exclude any generated conditions + not condition.isCompilerGenerated() and message = "Iteration condition has non boolean type " + explicitConversionType + "." ) } diff --git a/cpp/common/src/codingstandards/cpp/rules/nonconstantformat/NonConstantFormat.qll b/cpp/common/src/codingstandards/cpp/rules/nonconstantformat/NonConstantFormat.qll index b73a648eeb..91b2b05a3f 100644 --- a/cpp/common/src/codingstandards/cpp/rules/nonconstantformat/NonConstantFormat.qll +++ b/cpp/common/src/codingstandards/cpp/rules/nonconstantformat/NonConstantFormat.qll @@ -106,28 +106,28 @@ predicate isSanitizerNode(DataFlow::Node node) { cannotContainString(node.getType()) } -class NonConstFlow extends TaintTracking::Configuration { - NonConstFlow() { this = "NonConstFlow" } - - override predicate isSource(DataFlow::Node source) { +module NonConstConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { isNonConst(source) and not cannotContainString(source.getType()) } - override predicate isSink(DataFlow::Node sink) { + predicate isSink(DataFlow::Node sink) { exists(FormattingFunctionCall fc | sink.asExpr() = fc.getArgument(fc.getFormatParameterIndex())) } - override predicate isSanitizer(DataFlow::Node node) { isSanitizerNode(node) } + predicate isBarrier(DataFlow::Node node) { isSanitizerNode(node) } } +module NonConstFlow = TaintTracking::Global; + query predicate problems( Expr formatString, string message, FormattingFunctionCall call, string formatStringDescription ) { not isExcluded(formatString, getQuery()) and call.getArgument(call.getFormatParameterIndex()) = formatString and - exists(NonConstFlow cf, DataFlow::Node source, DataFlow::Node sink | - cf.hasFlow(source, sink) and + exists(DataFlow::Node source, DataFlow::Node sink | + NonConstFlow::flow(source, sink) and sink.asExpr() = formatString ) and message = diff --git a/cpp/common/src/codingstandards/cpp/rules/onlyfreememoryallocateddynamicallyshared/OnlyFreeMemoryAllocatedDynamicallyShared.qll b/cpp/common/src/codingstandards/cpp/rules/onlyfreememoryallocateddynamicallyshared/OnlyFreeMemoryAllocatedDynamicallyShared.qll index e8025db05b..bede451e24 100644 --- a/cpp/common/src/codingstandards/cpp/rules/onlyfreememoryallocateddynamicallyshared/OnlyFreeMemoryAllocatedDynamicallyShared.qll +++ b/cpp/common/src/codingstandards/cpp/rules/onlyfreememoryallocateddynamicallyshared/OnlyFreeMemoryAllocatedDynamicallyShared.qll @@ -8,8 +8,7 @@ import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions import codingstandards.cpp.Allocations import codingstandards.cpp.dataflow.DataFlow -import codingstandards.cpp.dataflow.DataFlow2 -import DataFlow::PathGraph +import NonDynamicPointerToFreeFlow::PathGraph /** * A pointer to potentially dynamically allocated memory @@ -69,40 +68,32 @@ class AddressOfExprSourceNode extends Expr { ) ) and // exclude alloc(&allocated_ptr) cases - not any(DynamicMemoryAllocationToAddressOfDefiningArgConfig cfg) - .hasFlowTo(DataFlow::definitionByReferenceNodeFromArgument(this)) + not DynamicMemoryAllocationToAddressOfDefiningArgFlow::flowTo(DataFlow::definitionByReferenceNodeFromArgument(this)) } } /** * A data-flow configuration that tracks flow from an `AllocExprSource` to a `FreeExprSink`. */ -class DynamicMemoryAllocationToAddressOfDefiningArgConfig extends DataFlow2::Configuration { - DynamicMemoryAllocationToAddressOfDefiningArgConfig() { - this = "DynamicMemoryAllocationToAddressOfDefiningArgConfig" - } - - override predicate isSource(DataFlow::Node source) { source instanceof AllocExprSource } +module DynamicMemoryAllocationToAddressOfDefiningArgConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { source instanceof AllocExprSource } - override predicate isSink(DataFlow::Node sink) { - sink.asDefiningArgument() instanceof AddressOfExpr - } + predicate isSink(DataFlow::Node sink) { sink.asDefiningArgument() instanceof AddressOfExpr } } +module DynamicMemoryAllocationToAddressOfDefiningArgFlow = + DataFlow::Global; + /** * A data-flow configuration that tracks flow from a * `NonDynamicallyAllocatedVariableAssignment` to a `FreeExprSink`. */ -class NonDynamicPointerToFreeConfig extends DataFlow::Configuration { - NonDynamicPointerToFreeConfig() { this = "NonDynamicPointerToFreeConfig" } +module NonDynamicPointerToFreeConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { source.asExpr() instanceof AddressOfExprSourceNode } - override predicate isSource(DataFlow::Node source) { - source.asExpr() instanceof AddressOfExprSourceNode - } - - override predicate isSink(DataFlow::Node sink) { sink instanceof FreeExprSink } + predicate isSink(DataFlow::Node sink) { sink instanceof FreeExprSink } - override predicate isBarrierOut(DataFlow::Node node) { + predicate isBarrierOut(DataFlow::Node node) { // the default interprocedural data-flow model flows through any field or array assignment // expressions to the qualifier (array base, pointer dereferenced, or qualifier) instead of the // individual element or field that the assignment modifies. this default behaviour causes @@ -118,21 +109,24 @@ class NonDynamicPointerToFreeConfig extends DataFlow::Configuration { ) } - override predicate isBarrierIn(DataFlow::Node node) { + predicate isBarrierIn(DataFlow::Node node) { // only the last source expression is relevant isSource(node) } } +module NonDynamicPointerToFreeFlow = DataFlow::Global; + abstract class OnlyFreeMemoryAllocatedDynamicallySharedSharedQuery extends Query { } Query getQuery() { result instanceof OnlyFreeMemoryAllocatedDynamicallySharedSharedQuery } query predicate problems( - DataFlow::PathNode element, DataFlow::PathNode source, DataFlow::PathNode sink, string message + NonDynamicPointerToFreeFlow::PathNode element, NonDynamicPointerToFreeFlow::PathNode source, + NonDynamicPointerToFreeFlow::PathNode sink, string message ) { not isExcluded(element.getNode().asExpr(), getQuery()) and element = sink and - any(NonDynamicPointerToFreeConfig cfg).hasFlowPath(source, sink) and + NonDynamicPointerToFreeFlow::flowPath(source, sink) and message = "Free expression frees memory which was not dynamically allocated." } diff --git a/cpp/common/src/codingstandards/cpp/rules/ownedpointervaluestoredinunrelatedsmartpointer/OwnedPointerValueStoredInUnrelatedSmartPointer.qll b/cpp/common/src/codingstandards/cpp/rules/ownedpointervaluestoredinunrelatedsmartpointer/OwnedPointerValueStoredInUnrelatedSmartPointer.qll index eff7873d16..e24fb91539 100644 --- a/cpp/common/src/codingstandards/cpp/rules/ownedpointervaluestoredinunrelatedsmartpointer/OwnedPointerValueStoredInUnrelatedSmartPointer.qll +++ b/cpp/common/src/codingstandards/cpp/rules/ownedpointervaluestoredinunrelatedsmartpointer/OwnedPointerValueStoredInUnrelatedSmartPointer.qll @@ -9,20 +9,18 @@ import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions import codingstandards.cpp.SmartPointers import codingstandards.cpp.dataflow.TaintTracking -import DataFlow::PathGraph +import PointerToSmartPointerConstructorFlowFlow::PathGraph abstract class OwnedPointerValueStoredInUnrelatedSmartPointerSharedQuery extends Query { } Query getQuery() { result instanceof OwnedPointerValueStoredInUnrelatedSmartPointerSharedQuery } -private class PointerToSmartPointerConstructorFlowConfig extends TaintTracking::Configuration { - PointerToSmartPointerConstructorFlowConfig() { this = "PointerToSmartPointerConstructorFlow" } - - override predicate isSource(DataFlow::Node source) { +private module PointerToSmartPointerConstructorFlowConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { exists(Variable v | v.getAnAssignedValue() = source.asExpr()) } - override predicate isSink(DataFlow::Node sink) { + predicate isSink(DataFlow::Node sink) { exists(AutosarSmartPointer sp, ConstructorCall cc | sp.getAConstructorCall() = cc and cc.getArgument(0).getFullyConverted().getType() instanceof PointerType and @@ -30,7 +28,7 @@ private class PointerToSmartPointerConstructorFlowConfig extends TaintTracking:: ) } - override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { + predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { // Summarize flow through constructor calls exists(AutosarSmartPointer sp, ConstructorCall cc | sp.getAConstructorCall() = cc and @@ -46,7 +44,7 @@ private class PointerToSmartPointerConstructorFlowConfig extends TaintTracking:: ) } - override predicate isSanitizerIn(DataFlow::Node node) { + predicate isBarrierIn(DataFlow::Node node) { // Exclude flow into header files outside the source archive which are summarized by the // additional taint steps above. exists(AutosarSmartPointer sp | @@ -59,15 +57,19 @@ private class PointerToSmartPointerConstructorFlowConfig extends TaintTracking:: } } +private module PointerToSmartPointerConstructorFlowFlow = + TaintTracking::Global; + query predicate problems( - DataFlow::Node sinkNode, DataFlow::PathNode source, DataFlow::PathNode sink, string message + DataFlow::Node sinkNode, PointerToSmartPointerConstructorFlowFlow::PathNode source, + PointerToSmartPointerConstructorFlowFlow::PathNode sink, string message ) { not isExcluded(sinkNode.asExpr(), getQuery()) and - exists(PointerToSmartPointerConstructorFlowConfig config, DataFlow::PathNode sink2 | + exists(PointerToSmartPointerConstructorFlowFlow::PathNode sink2 | sink != sink2 and sinkNode = sink.getNode() and - config.hasFlowPath(source, sink) and - config.hasFlowPath(source, sink2) and + PointerToSmartPointerConstructorFlowFlow::flowPath(source, sink) and + PointerToSmartPointerConstructorFlowFlow::flowPath(source, sink2) and message = "Raw pointer flows to initialize multiple unrelated smart pointers." ) } diff --git a/cpp/common/src/codingstandards/cpp/rules/placementnewinsufficientstorage/PlacementNewInsufficientStorage.qll b/cpp/common/src/codingstandards/cpp/rules/placementnewinsufficientstorage/PlacementNewInsufficientStorage.qll index 515779595f..dc26d13b87 100644 --- a/cpp/common/src/codingstandards/cpp/rules/placementnewinsufficientstorage/PlacementNewInsufficientStorage.qll +++ b/cpp/common/src/codingstandards/cpp/rules/placementnewinsufficientstorage/PlacementNewInsufficientStorage.qll @@ -8,24 +8,23 @@ import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions import codingstandards.cpp.allocations.PlacementNew import codingstandards.cpp.dataflow.DataFlow -import DataFlow::PathGraph +import PlacementNewOriginFlow::PathGraph abstract class PlacementNewInsufficientStorageSharedQuery extends Query { } Query getQuery() { result instanceof PlacementNewInsufficientStorageSharedQuery } query predicate problems( - PlacementNewExpr placementNew, DataFlow::PathNode source, DataFlow::PathNode sink, string message, - PlacementNewMemoryOrigin memoryOrigin, string memoryOriginDescription + PlacementNewExpr placementNew, PlacementNewOriginFlow::PathNode source, + PlacementNewOriginFlow::PathNode sink, string message, PlacementNewMemoryOrigin memoryOrigin, + string memoryOriginDescription ) { not isExcluded(placementNew, getQuery()) and message = "Placement new expression is used with an insufficiently large memory allocation from $@." and - exists(PlacementNewOriginConfig config | - memoryOrigin = source.getNode() and - placementNew.getPlacementExpr() = sink.getNode().asExpr() and - memoryOriginDescription = memoryOrigin.toString() and - config.hasFlowPath(source, sink) and - memoryOrigin.getMaximumMemorySize() < placementNew.getMinimumAllocationSize() - ) + memoryOrigin = source.getNode() and + placementNew.getPlacementExpr() = sink.getNode().asExpr() and + memoryOriginDescription = memoryOrigin.toString() and + PlacementNewOriginFlow::flowPath(source, sink) and + memoryOrigin.getMaximumMemorySize() < placementNew.getMinimumAllocationSize() } diff --git a/cpp/common/src/codingstandards/cpp/rules/placementnewnotproperlyaligned/PlacementNewNotProperlyAligned.qll b/cpp/common/src/codingstandards/cpp/rules/placementnewnotproperlyaligned/PlacementNewNotProperlyAligned.qll index 19cbe2fff5..72286f2d79 100644 --- a/cpp/common/src/codingstandards/cpp/rules/placementnewnotproperlyaligned/PlacementNewNotProperlyAligned.qll +++ b/cpp/common/src/codingstandards/cpp/rules/placementnewnotproperlyaligned/PlacementNewNotProperlyAligned.qll @@ -8,7 +8,7 @@ import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions import codingstandards.cpp.allocations.PlacementNew import codingstandards.cpp.dataflow.DataFlow -import DataFlow::PathGraph +import PlacementNewOriginFlow::PathGraph abstract class PlacementNewNotProperlyAlignedSharedQuery extends Query { } @@ -19,20 +19,19 @@ Query getQuery() { result instanceof PlacementNewNotProperlyAlignedSharedQuery } */ query predicate problems( - PlacementNewExpr placementNew, DataFlow::PathNode source, DataFlow::PathNode sink, string message, - PlacementNewMemoryOrigin memoryOrigin, string memoryOriginDescription + PlacementNewExpr placementNew, PlacementNewOriginFlow::PathNode source, + PlacementNewOriginFlow::PathNode sink, string message, PlacementNewMemoryOrigin memoryOrigin, + string memoryOriginDescription ) { not isExcluded(placementNew, getQuery()) and - exists(PlacementNewOriginConfig config | - memoryOrigin = source.getNode() and - placementNew.getPlacementExpr() = sink.getNode().asExpr() and - memoryOriginDescription = memoryOrigin.toString() and - config.hasFlowPath(source, sink) and - exists(int originAlignment | - originAlignment = memoryOrigin.getAlignment() and - // The origin alignment should be exactly divisible by the placement alignment - (originAlignment / placementNew.getAllocatedType().getAlignment()).ceil() = 0 and - message = "Placement new expression is used with inappropriately aligned memory from $@." - ) + memoryOrigin = source.getNode() and + placementNew.getPlacementExpr() = sink.getNode().asExpr() and + memoryOriginDescription = memoryOrigin.toString() and + PlacementNewOriginFlow::flowPath(source, sink) and + exists(int originAlignment | + originAlignment = memoryOrigin.getAlignment() and + // The origin alignment should be exactly divisible by the placement alignment + (originAlignment / placementNew.getAllocatedType().getAlignment()).ceil() = 0 and + message = "Placement new expression is used with inappropriately aligned memory from $@." ) } diff --git a/cpp/common/src/codingstandards/cpp/rules/stringnumberconversionmissingerrorcheck/StringNumberConversionMissingErrorCheck.qll b/cpp/common/src/codingstandards/cpp/rules/stringnumberconversionmissingerrorcheck/StringNumberConversionMissingErrorCheck.qll index e5856ad7c8..98fd51a58f 100644 --- a/cpp/common/src/codingstandards/cpp/rules/stringnumberconversionmissingerrorcheck/StringNumberConversionMissingErrorCheck.qll +++ b/cpp/common/src/codingstandards/cpp/rules/stringnumberconversionmissingerrorcheck/StringNumberConversionMissingErrorCheck.qll @@ -31,8 +31,7 @@ class CharIStreamConstructorCall extends CharIStreamSource, Expr { } override Expr getAUse() { - any(CharIStreamConstructorCallUseConfig c) - .hasFlow(DataFlow::exprNode(this), DataFlow::exprNode(result)) + CharIStreamConstructorCallUseFlow::flow(DataFlow::exprNode(this), DataFlow::exprNode(result)) } } @@ -40,18 +39,16 @@ class CharIStreamConstructorCall extends CharIStreamSource, Expr { * A global taint tracking configuration used to track from `CharIStream` constructor calls to uses * of that stream later in the program. */ -private class CharIStreamConstructorCallUseConfig extends TaintTracking::Configuration { - CharIStreamConstructorCallUseConfig() { this = "CharIStreamUse" } - - override predicate isSource(DataFlow::Node source) { +private module CharIStreamConstructorCallUseConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { source.asExpr() instanceof CharIStreamConstructorCall } - override predicate isSink(DataFlow::Node sink) { + predicate isSink(DataFlow::Node sink) { sink.asExpr().getType().stripType() instanceof CharIStream } - override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { + predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { // By default we do not get flow from ConstructorFieldInit expressions to accesses // of the field in other member functions, so we add it explicitly here. exists(ConstructorFieldInit cfi, Field f | @@ -63,6 +60,9 @@ private class CharIStreamConstructorCallUseConfig extends TaintTracking::Configu } } +private module CharIStreamConstructorCallUseFlow = + TaintTracking::Global; + /** * A `CharIStream` defined externally, and which therefore cannot be tracked as a source by taint tracking. * diff --git a/cpp/common/src/codingstandards/cpp/rules/throwingoperatornewreturnsnull/ThrowingOperatorNewReturnsNull.qll b/cpp/common/src/codingstandards/cpp/rules/throwingoperatornewreturnsnull/ThrowingOperatorNewReturnsNull.qll index a34beef5cd..9dbefeaa75 100644 --- a/cpp/common/src/codingstandards/cpp/rules/throwingoperatornewreturnsnull/ThrowingOperatorNewReturnsNull.qll +++ b/cpp/common/src/codingstandards/cpp/rules/throwingoperatornewreturnsnull/ThrowingOperatorNewReturnsNull.qll @@ -9,16 +9,14 @@ import codingstandards.cpp.allocations.CustomOperatorNewDelete import codingstandards.cpp.exceptions.ExceptionSpecifications import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions -import DataFlow::PathGraph +import NullFlow::PathGraph abstract class ThrowingOperatorNewReturnsNullSharedQuery extends Query { } Query getQuery() { result instanceof ThrowingOperatorNewReturnsNullSharedQuery } -class NullConfig extends DataFlow::Configuration { - NullConfig() { this = "NullConfig" } - - override predicate isSource(DataFlow::Node source) { +module NullConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { source.asExpr() instanceof NullValue or // Call to an allocation function that may return null @@ -32,7 +30,7 @@ class NullConfig extends DataFlow::Configuration { ) } - override predicate isSink(DataFlow::Node sink) { + predicate isSink(DataFlow::Node sink) { exists(CustomOperatorNew co, ReturnStmt rs | co.getNumberOfParameters() = 1 and rs.getEnclosingFunction() = co and @@ -41,11 +39,13 @@ class NullConfig extends DataFlow::Configuration { } } +module NullFlow = DataFlow::Global; + query predicate problems( - ReturnStmt e, DataFlow::PathNode source, DataFlow::PathNode sink, string message + ReturnStmt e, NullFlow::PathNode source, NullFlow::PathNode sink, string message ) { not isExcluded(e, getQuery()) and - any(NullConfig nc).hasFlowPath(source, sink) and + NullFlow::flowPath(source, sink) and sink.getNode().asExpr() = e.getExpr() and exists(CustomOperatorNew op | message = diff --git a/cpp/common/src/codingstandards/cpp/rules/useonlyarrayindexingforpointerarithmetic/UseOnlyArrayIndexingForPointerArithmetic.qll b/cpp/common/src/codingstandards/cpp/rules/useonlyarrayindexingforpointerarithmetic/UseOnlyArrayIndexingForPointerArithmetic.qll index 979918a72b..c421ae3cc9 100644 --- a/cpp/common/src/codingstandards/cpp/rules/useonlyarrayindexingforpointerarithmetic/UseOnlyArrayIndexingForPointerArithmetic.qll +++ b/cpp/common/src/codingstandards/cpp/rules/useonlyarrayindexingforpointerarithmetic/UseOnlyArrayIndexingForPointerArithmetic.qll @@ -10,21 +10,19 @@ import codingstandards.cpp.dataflow.DataFlow abstract class UseOnlyArrayIndexingForPointerArithmeticSharedQuery extends Query { } -class ArrayToArrayBaseConfig extends DataFlow::Configuration { - ArrayToArrayBaseConfig() { this = "ArrayToArrayBaseConfig" } - - override predicate isSource(DataFlow::Node source) { +module ArrayToArrayBaseConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { source.asExpr().(VariableAccess).getType() instanceof ArrayType or // Consider array to pointer decay for parameters. source.asExpr().(VariableAccess).getTarget().(Parameter).getType() instanceof ArrayType } - override predicate isSink(DataFlow::Node sink) { - exists(ArrayExpr e | e.getArrayBase() = sink.asExpr()) - } + predicate isSink(DataFlow::Node sink) { exists(ArrayExpr e | e.getArrayBase() = sink.asExpr()) } } +module ArrayToArrayBaseFlow = DataFlow::Global; + predicate hasPointerResult(PointerArithmeticOperation op) { op instanceof PointerAddExpr or @@ -34,8 +32,7 @@ predicate hasPointerResult(PointerArithmeticOperation op) { predicate shouldBeArray(ArrayExpr arrayExpr) { arrayExpr.getArrayBase().getUnspecifiedType() instanceof PointerType and not exists(VariableAccess va | - any(ArrayToArrayBaseConfig config) - .hasFlow(DataFlow::exprNode(va), DataFlow::exprNode(arrayExpr.getArrayBase())) + ArrayToArrayBaseFlow::flow(DataFlow::exprNode(va), DataFlow::exprNode(arrayExpr.getArrayBase())) ) and not exists(Variable v | v.getAnAssignedValue().getType() instanceof ArrayType and diff --git a/cpp/common/src/codingstandards/cpp/standardlibrary/FileStreams.qll b/cpp/common/src/codingstandards/cpp/standardlibrary/FileStreams.qll index 775159326f..4d495fce3e 100644 --- a/cpp/common/src/codingstandards/cpp/standardlibrary/FileStreams.qll +++ b/cpp/common/src/codingstandards/cpp/standardlibrary/FileStreams.qll @@ -144,8 +144,7 @@ class FileStreamConstructorCall extends FileStreamSource, Expr { } override Expr getAUse() { - any(FileStreamConstructorCallUseConfig c) - .hasFlow(DataFlow::exprNode(this), DataFlow::exprNode(result)) + FileStreamConstructorCallUseFlow::flow(DataFlow::exprNode(this), DataFlow::exprNode(result)) } } @@ -164,18 +163,14 @@ class FileStreamExternGlobal extends FileStreamSource, GlobalOrNamespaceVariable /** * A global taint tracking configuration to track `FileStream` uses in the program. */ -private class FileStreamConstructorCallUseConfig extends TaintTracking::Configuration { - FileStreamConstructorCallUseConfig() { this = "FileStreamUse" } +private module FileStreamConstructorCallUseConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { source.asExpr() instanceof FileStreamConstructorCall } - override predicate isSource(DataFlow::Node source) { - source.asExpr() instanceof FileStreamConstructorCall - } - - override predicate isSink(DataFlow::Node sink) { + predicate isSink(DataFlow::Node sink) { sink.asExpr().getType().stripType() instanceof FileStream } - override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { + predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { // By default we do not get flow from ConstructorFieldInit expressions to accesses // of the field in other member functions, so we add it explicitly here. exists(ConstructorFieldInit cfi, Field f | @@ -186,3 +181,6 @@ private class FileStreamConstructorCallUseConfig extends TaintTracking::Configur ) } } + +private module FileStreamConstructorCallUseFlow = + TaintTracking::Global; diff --git a/cpp/common/test/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.expected b/cpp/common/test/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.expected index 21fe1e3ccd..537228a000 100644 --- a/cpp/common/test/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.expected +++ b/cpp/common/test/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.expected @@ -4,15 +4,19 @@ problems | test.cpp:13:10:13:11 | p4 | test.cpp:5:14:5:15 | l2 | test.cpp:13:10:13:11 | p4 | Subtraction between left operand pointing to array $@ and other operand pointing to array $@. | test.cpp:3:7:3:8 | l2 | l2 | test.cpp:2:7:2:8 | l1 | l1 | | test.cpp:13:15:13:16 | l1 | test.cpp:13:15:13:16 | l1 | test.cpp:13:15:13:16 | l1 | Subtraction between right operand pointing to array $@ and other operand pointing to array $@. | test.cpp:2:7:2:8 | l1 | l1 | test.cpp:3:7:3:8 | l2 | l2 | edges -| test.cpp:4:14:4:15 | l1 | test.cpp:10:10:10:11 | p1 | -| test.cpp:4:14:4:15 | l1 | test.cpp:12:10:12:11 | p1 | -| test.cpp:5:14:5:15 | l2 | test.cpp:11:10:11:11 | p2 | -| test.cpp:5:14:5:15 | l2 | test.cpp:12:15:12:16 | p2 | -| test.cpp:5:14:5:15 | l2 | test.cpp:13:10:13:11 | p4 | -| test.cpp:5:14:5:15 | l2 | test.cpp:14:10:14:11 | p4 | +| test.cpp:4:14:4:15 | l1 | test.cpp:4:14:4:18 | access to array | +| test.cpp:4:14:4:18 | access to array | test.cpp:10:10:10:11 | p1 | +| test.cpp:4:14:4:18 | access to array | test.cpp:12:10:12:11 | p1 | +| test.cpp:5:14:5:15 | l2 | test.cpp:5:14:5:19 | access to array | +| test.cpp:5:14:5:19 | access to array | test.cpp:11:10:11:11 | p2 | +| test.cpp:5:14:5:19 | access to array | test.cpp:12:15:12:16 | p2 | +| test.cpp:5:14:5:19 | access to array | test.cpp:13:10:13:11 | p4 | +| test.cpp:5:14:5:19 | access to array | test.cpp:14:10:14:11 | p4 | nodes | test.cpp:4:14:4:15 | l1 | semmle.label | l1 | +| test.cpp:4:14:4:18 | access to array | semmle.label | access to array | | test.cpp:5:14:5:15 | l2 | semmle.label | l2 | +| test.cpp:5:14:5:19 | access to array | semmle.label | access to array | | test.cpp:10:10:10:11 | p1 | semmle.label | p1 | | test.cpp:10:15:10:16 | l1 | semmle.label | l1 | | test.cpp:11:10:11:11 | p2 | semmle.label | p2 | diff --git a/cpp/common/test/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.expected b/cpp/common/test/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.expected index 1b31174b2f..22ddfd123a 100644 --- a/cpp/common/test/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.expected +++ b/cpp/common/test/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.expected @@ -11,20 +11,26 @@ problems | test.cpp:25:7:25:14 | ... >= ... | test.cpp:25:13:25:14 | l3 | test.cpp:25:13:25:14 | l3 | Compare operation >= comparing right operand pointing to array $@ and other operand pointing to array $@. | test.cpp:4:7:4:8 | l3 | l3 | test.cpp:2:7:2:8 | l1 | l1 | edges | test.cpp:6:13:6:14 | l1 | test.cpp:13:12:13:13 | p0 | -| test.cpp:7:14:7:15 | l1 | test.cpp:11:7:11:8 | p1 | -| test.cpp:7:14:7:15 | l1 | test.cpp:13:7:13:8 | p1 | -| test.cpp:7:14:7:15 | l1 | test.cpp:15:13:15:14 | p1 | -| test.cpp:7:14:7:15 | l1 | test.cpp:17:7:17:8 | p1 | -| test.cpp:7:14:7:15 | l1 | test.cpp:23:13:23:14 | p1 | -| test.cpp:7:14:7:15 | l1 | test.cpp:25:7:25:8 | p1 | -| test.cpp:8:14:8:15 | l1 | test.cpp:11:12:11:13 | p2 | -| test.cpp:8:14:8:15 | l1 | test.cpp:21:7:21:8 | p2 | -| test.cpp:9:14:9:15 | l2 | test.cpp:21:12:21:13 | p3 | +| test.cpp:7:14:7:15 | l1 | test.cpp:7:14:7:18 | access to array | +| test.cpp:7:14:7:18 | access to array | test.cpp:11:7:11:8 | p1 | +| test.cpp:7:14:7:18 | access to array | test.cpp:13:7:13:8 | p1 | +| test.cpp:7:14:7:18 | access to array | test.cpp:15:13:15:14 | p1 | +| test.cpp:7:14:7:18 | access to array | test.cpp:17:7:17:8 | p1 | +| test.cpp:7:14:7:18 | access to array | test.cpp:23:13:23:14 | p1 | +| test.cpp:7:14:7:18 | access to array | test.cpp:25:7:25:8 | p1 | +| test.cpp:8:14:8:15 | l1 | test.cpp:8:14:8:18 | access to array | +| test.cpp:8:14:8:18 | access to array | test.cpp:11:12:11:13 | p2 | +| test.cpp:8:14:8:18 | access to array | test.cpp:21:7:21:8 | p2 | +| test.cpp:9:14:9:15 | l2 | test.cpp:9:14:9:18 | access to array | +| test.cpp:9:14:9:18 | access to array | test.cpp:21:12:21:13 | p3 | nodes | test.cpp:6:13:6:14 | l1 | semmle.label | l1 | | test.cpp:7:14:7:15 | l1 | semmle.label | l1 | +| test.cpp:7:14:7:18 | access to array | semmle.label | access to array | | test.cpp:8:14:8:15 | l1 | semmle.label | l1 | +| test.cpp:8:14:8:18 | access to array | semmle.label | access to array | | test.cpp:9:14:9:15 | l2 | semmle.label | l2 | +| test.cpp:9:14:9:18 | access to array | semmle.label | access to array | | test.cpp:11:7:11:8 | p1 | semmle.label | p1 | | test.cpp:11:12:11:13 | p2 | semmle.label | p2 | | test.cpp:13:7:13:8 | p1 | semmle.label | p1 | diff --git a/cpp/common/test/rules/ownedpointervaluestoredinunrelatedsmartpointer/OwnedPointerValueStoredInUnrelatedSmartPointer.expected b/cpp/common/test/rules/ownedpointervaluestoredinunrelatedsmartpointer/OwnedPointerValueStoredInUnrelatedSmartPointer.expected index d5d138ec19..3d00ff0d6a 100644 --- a/cpp/common/test/rules/ownedpointervaluestoredinunrelatedsmartpointer/OwnedPointerValueStoredInUnrelatedSmartPointer.expected +++ b/cpp/common/test/rules/ownedpointervaluestoredinunrelatedsmartpointer/OwnedPointerValueStoredInUnrelatedSmartPointer.expected @@ -7,10 +7,14 @@ problems | test.cpp:17:27:17:28 | v1 | test.cpp:16:13:16:22 | new | test.cpp:17:27:17:28 | v1 | Raw pointer flows to initialize multiple unrelated smart pointers. | edges | test.cpp:3:14:3:15 | v1 | test.cpp:5:27:5:28 | v1 | -| test.cpp:3:14:3:15 | v1 | test.cpp:6:31:6:33 | call to get | +| test.cpp:3:14:3:15 | v1 | test.cpp:5:27:5:28 | v1 | | test.cpp:3:14:3:15 | v1 | test.cpp:7:28:7:29 | v2 | | test.cpp:4:13:4:14 | v1 | test.cpp:7:28:7:29 | v2 | -| test.cpp:5:27:5:29 | call to shared_ptr | test.cpp:6:31:6:33 | call to get | +| test.cpp:5:27:5:28 | v1 | test.cpp:5:27:5:29 | call to shared_ptr | +| test.cpp:5:27:5:29 | call to shared_ptr | test.cpp:6:28:6:29 | p1 | +| test.cpp:5:27:5:29 | call to shared_ptr | test.cpp:6:28:6:29 | p1 | +| test.cpp:6:28:6:29 | p1 | test.cpp:6:31:6:33 | call to get | +| test.cpp:6:28:6:29 | p1 | test.cpp:6:31:6:33 | call to get | | test.cpp:8:8:8:14 | 0 | test.cpp:9:28:9:29 | v2 | | test.cpp:10:8:10:17 | new | test.cpp:11:28:11:29 | v2 | | test.cpp:10:8:10:17 | new | test.cpp:12:28:12:29 | v2 | @@ -21,7 +25,11 @@ nodes | test.cpp:3:14:3:15 | v1 | semmle.label | v1 | | test.cpp:4:13:4:14 | v1 | semmle.label | v1 | | test.cpp:5:27:5:28 | v1 | semmle.label | v1 | +| test.cpp:5:27:5:28 | v1 | semmle.label | v1 | +| test.cpp:5:27:5:29 | call to shared_ptr | semmle.label | call to shared_ptr | | test.cpp:5:27:5:29 | call to shared_ptr | semmle.label | call to shared_ptr | +| test.cpp:6:28:6:29 | p1 | semmle.label | p1 | +| test.cpp:6:28:6:29 | p1 | semmle.label | p1 | | test.cpp:6:31:6:33 | call to get | semmle.label | call to get | | test.cpp:7:28:7:29 | v2 | semmle.label | v2 | | test.cpp:8:8:8:14 | 0 | semmle.label | 0 | diff --git a/rule_packages/cpp/Const.json b/rule_packages/cpp/Const.json index ca848c2fdc..c574e547bf 100644 --- a/rule_packages/cpp/Const.json +++ b/rule_packages/cpp/Const.json @@ -33,19 +33,6 @@ "obligation": "required" }, "queries": [ - { - "description": "`Constexpr`/`const` specifiers prevent unintentional data modification for parameters intended as immutable.", - "kind": "problem", - "name": "Constexpr or const specifiers shall be used for immutable parameter usage", - "precision": "high", - "severity": "warning", - "short_name": "DeclarationUnmodifiedParamMissingConstSpecifier", - "tags": [ - "correctness", - "maintainability", - "readability" - ] - }, { "description": "`Constexpr`/`const` specifiers prevent unintentional data modification for data intended as immutable.", "kind": "problem", @@ -57,7 +44,10 @@ "correctness", "maintainability", "readability" - ] + ], + "implementation_scope": { + "description": "We exclude function parameters from this rule in line with the rule intention as described in the C++ Core Guidelines Con.1 which excludes function parameters." + } } ], "title": "Constexpr or const specifiers shall be used for immutable data declaration." diff --git a/rule_packages/cpp/Declarations.json b/rule_packages/cpp/Declarations.json index 2b22de6de1..65dfbf781e 100644 --- a/rule_packages/cpp/Declarations.json +++ b/rule_packages/cpp/Declarations.json @@ -78,12 +78,28 @@ }, "queries": [ { - "description": "The basic numerical types of char, int, short, long are not supposed to be used. The specific-length types from header need be used instead.", + "description": "The basic numerical types of signed/unsigned char, int, short, long are not supposed to be used. The specific-length types from header need be used instead.", "kind": "problem", "name": "Use fixed-width integer types instead of basic, variable-width, integer types", "precision": "very-high", "severity": "error", "short_name": "VariableWidthIntegerTypesUsed", + "tags": [ + "correctness", + "security", + "maintainability" + ], + "implementation_scope": { + "description": "This implementation excludes the plain char type from consideration." + } + }, + { + "description": "The basic numerical type char is not supposed to be used. The specific-length types from header need be used instead.", + "kind": "problem", + "name": "Use a fixed-width integer type instead of a char type", + "precision": "very-high", + "severity": "error", + "short_name": "VariableWidthPlainCharTypeUsed", "tags": [ "correctness", "security", diff --git a/scripts/release/requirements.txt b/scripts/release/requirements.txt index 63874950c1..5cdcc51546 100644 --- a/scripts/release/requirements.txt +++ b/scripts/release/requirements.txt @@ -1,5 +1,5 @@ semantic-version==2.10.0 PyGithub==1.59.1 PyYAML==6.0.1 -GitPython==3.1.36 -pytest==7.4.3 \ No newline at end of file +GitPython==3.1.37 +pytest==7.4.3 diff --git a/scripts/release/update-release-notes.py b/scripts/release/update-release-notes.py index 5f317ad988..964fcb339e 100644 --- a/scripts/release/update-release-notes.py +++ b/scripts/release/update-release-notes.py @@ -6,9 +6,9 @@ if TYPE_CHECKING: from argparse import Namespace -def generate_release_notes() -> str: +def generate_release_note(previous_release_tag: str) -> str: script_path = Path(__file__).parent / "generate_release_notes.py" - cp = subprocess.run(["python", str(script_path)], capture_output=True) + cp = subprocess.run(["python", str(script_path), previous_release_tag], capture_output=True) if cp.returncode != 0: raise Exception(f"Error generating release notes: {cp.stderr.decode('utf-8')}") @@ -20,6 +20,7 @@ def main(args: Namespace) -> int: import semantic_version # type: ignore import re import sys + from functools import cmp_to_key repo = Github(auth=Auth.Token(args.github_token)).get_repo(args.repo) @@ -48,16 +49,26 @@ def main(args: Namespace) -> int: print(f"Error: invalid version {release_version} use by release branch. Reason {e}", file=sys.stderr) return 1 - releases = [release for release in repo.get_releases() if release.title == f"v{release_version}"] - if len(releases) != 1: - print(f"Error: expected exactly one release with title {args.version}, but found {len(releases)}", file=sys.stderr) + releases = repo.get_releases() + candidate_releases= [release for release in releases if release.tag_name == f"v{release_version}"] + if len(candidate_releases) != 1: + print(f"Error: expected exactly one release with tag v{release_version}, but found {len(candidate_releases)}", file=sys.stderr) return 1 - release = releases[0] + release = candidate_releases[0] - release_notes = generate_release_notes() + # All the releases that are not draft and have a valid semantic version tag, our current release is assumed to be in draft (i.e. not yet released) + previous_releases = [release for release in releases if semantic_version.validate(release.tag_name[1:]) and not release.draft] # type: ignore + if len(previous_releases) == 0: + print(f"Error: no previous releases found", file=sys.stderr) + return 1 + # Sort them based on their semantic version tags. + previous_releases.sort(key=cmp_to_key(lambda a,b: semantic_version.compare(a.tag_name[1:], b.tag_name[1:])), reverse=True) # type: ignore + previous_release = previous_releases[0].tag_name + print(f"Using previous release: {previous_release}") - release.update_release(name=release.title, message=release_notes, draft=release.draft, prerelease=release.prerelease, tag_name=release.tag_name) + release_notes = generate_release_note(previous_release) + release.update_release(name=release.title, message=release_notes, draft=release.draft, prerelease=release.prerelease, tag_name=release.tag_name) return 0 if __name__ == '__main__':