From 67ab0aa329adbf353fd0315cfe5af70f4022d42d Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Fri, 1 Dec 2023 21:25:45 +0100 Subject: [PATCH] Modernize dataflow configurations --- ...interArithmeticOnNonArrayObjectPointers.ql | 21 +++++----- ...otAddOrSubtractAScaledIntegerToAPointer.ql | 18 +++++---- .../CON30-C/CleanUpThreadSpecificStorage.ql | 16 ++++---- ...PointerToMoreStrictlyAlignedPointerType.ql | 40 +++++++++---------- ...CallFunctionPointerWithIncompatibleType.ql | 16 ++++---- ...essVariableViaPointerOfIncompatibleType.ql | 25 +++++++----- .../EXP40-C/DoNotModifyConstantObjects.ql | 16 ++++---- ...sAliasedPointerToRestrictQualifiedParam.ql | 24 ++++++----- ...trictPointerReferencesOverlappingObject.ql | 18 ++++----- ...uesForFsetposThatAreReturnedFromFgetpos.ql | 12 +++--- ...DoNotModifyAlignmentOfMemoryWithRealloc.ql | 16 ++++---- ...oNotPassInvalidDataToTheAsctimeFunction.ql | 14 +++---- ...ArgOnAVaListThatHasAnIndeterminateValue.ql | 16 ++++---- .../DoNotAttemptToModifyStringLiterals.ql | 18 ++++----- .../src/codingstandards/c/OutOfBounds.qll | 21 +++++----- .../ArrayFunctionArgumentNumberOfElements.ql | 17 ++++---- ...emcmpUsedToCompareNullTerminatedStrings.ql | 27 +++++++------ .../AttemptToWriteToAReadOnlyStream.ql | 14 +++---- ...allBeComparedWithUnmodifiedReturnValues.ql | 16 ++++---- ...AnElementOfAnArrayPassedToASmartPointer.ql | 25 ++++++------ ...hmeticUsedWithPointersToNonFinalClasses.ql | 22 +++++----- 21 files changed, 209 insertions(+), 203 deletions(-) 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..cada60d10f 100644 --- a/c/cert/src/rules/EXP36-C/DoNotCastPointerToMoreStrictlyAlignedPointerType.ql +++ b/c/cert/src/rules/EXP36-C/DoNotCastPointerToMoreStrictlyAlignedPointerType.ql @@ -17,7 +17,7 @@ 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 +96,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 +117,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 +162,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..1962c5b0b0 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 @@ -62,15 +62,15 @@ class IndirectCastReallocatedFlowState extends DataFlow::FlowState { * 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 = DataFlow::FlowState; - 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 +103,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 +111,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 +134,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 +191,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/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/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/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/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()