From 7205b5e339502f81bba4e6bc63ab23974a118e6a Mon Sep 17 00:00:00 2001 From: Remco Vermeulen Date: Wed, 13 Jul 2022 12:16:44 +0200 Subject: [PATCH 0001/2973] Release v2.1.0 --- .github/actions/install-codeql/action.yml | 2 +- .github/workflows/code-scanning-pack-gen.yml | 2 + .vscode/tasks.json | 16 +- c/cert/src/qlpack.yml | 2 +- ...gumentsForSideEffects-implementation.qhelp | 8 + ...tionArgumentsForSideEffects-standard.qhelp | 33 + ...derOfFunctionArgumentsForSideEffects.qhelp | 21 + ...nOrderOfFunctionArgumentsForSideEffects.ql | 129 +++ ...luationForSideEffects-implementation.qhelp | 8 + ...larEvaluationForSideEffects-standard.qhelp | 33 + ...rderOfScalarEvaluationForSideEffects.qhelp | 21 + ...OnOrderOfScalarEvaluationForSideEffects.ql | 30 + .../cert/src/rules/EXP30-C/standard-example.c | 0 ...OperandWithSideEffect-implementation.qhelp | 8 + ...luatedOperandWithSideEffect-standard.qhelp | 33 + .../UnevaluatedOperandWithSideEffect.qhelp | 21 + .../UnevaluatedOperandWithSideEffect.ql | 34 + c/cert/src/rules/EXP44-C/standard-example.c | 0 ...InSelectionStatements-implementation.qhelp | 8 + ...nmentsInSelectionStatements-standard.qhelp | 33 + .../AssignmentsInSelectionStatements.qhelp | 21 + .../AssignmentsInSelectionStatements.ql | 62 + c/cert/src/rules/EXP45-C/standard-example.c | 0 ...eUserInputFromFormatStrings-standard.qhelp | 608 +++++++++- ...arReadFromAFileAndEofOrWeof-standard.qhelp | 568 ++++++++- .../EndOfFileCheckPortability-standard.qhelp | 568 ++++++++- .../DoNotCopyAFileObject-implementation.qhelp | 8 + .../DoNotCopyAFileObject-standard.qhelp | 368 ++++++ .../rules/FIO38-C/DoNotCopyAFileObject.qhelp | 21 + .../src/rules/FIO38-C/DoNotCopyAFileObject.ql | 32 + ...omAStreamWithoutPositioning-standard.qhelp | 407 ++++++- ...nFgetsOrFgetwsFailure-implementation.qhelp | 8 + ...ringsOnFgetsOrFgetwsFailure-standard.qhelp | 219 ++++ .../ResetStringsOnFgetsOrFgetwsFailure.qhelp | 21 + .../ResetStringsOnFgetsOrFgetwsFailure.ql | 114 ++ ...ndPutcWithSideEffects-implementation.qhelp | 8 + ...lGetcAndPutcWithSideEffects-standard.qhelp | 363 ++++++ .../DoNotCallGetcAndPutcWithSideEffects.qhelp | 21 + .../DoNotCallGetcAndPutcWithSideEffects.ql | 24 + ...esWhenTheyAreNoLongerNeeded-standard.qhelp | 623 +++++++++- ...reReturnedFromFgetpos-implementation.qhelp | 8 + ...sThatAreReturnedFromFgetpos-standard.qhelp | 331 ++++++ ...ForFsetposThatAreReturnedFromFgetpos.qhelp | 21 + ...uesForFsetposThatAreReturnedFromFgetpos.ql | 45 + ...ehaviorAccessingAClosedFile-standard.qhelp | 360 +++++- c/cert/test/qlpack.yml | 2 +- ...OfFunctionArgumentsForSideEffects.expected | 1 + ...derOfFunctionArgumentsForSideEffects.qlref | 1 + ...rOfScalarEvaluationForSideEffects.expected | 3 + ...rderOfScalarEvaluationForSideEffects.qlref | 1 + c/cert/test/rules/EXP30-C/test.c | 28 + .../UnevaluatedOperandWithSideEffect.expected | 2 + .../UnevaluatedOperandWithSideEffect.qlref | 1 + c/cert/test/rules/EXP44-C/test.c | 26 + .../AssignmentsInSelectionStatements.expected | 9 + .../AssignmentsInSelectionStatements.qlref | 1 + c/cert/test/rules/EXP45-C/test.c | 57 + ...weenCharReadFromAFileAndEofOrWeof.expected | 1 + .../EndOfFileCheckPortability.expected | 1 + c/cert/test/rules/FIO34-C/test.c | 21 +- .../FIO38-C/DoNotCopyAFileObject.expected | 5 + .../rules/FIO38-C/DoNotCopyAFileObject.qlref | 1 + c/cert/test/rules/FIO38-C/test.c | 43 + ...esetStringsOnFgetsOrFgetwsFailure.expected | 12 + .../ResetStringsOnFgetsOrFgetwsFailure.qlref | 1 + c/cert/test/rules/FIO40-C/test.c | 225 ++++ ...NotCallGetcAndPutcWithSideEffects.expected | 2 + .../DoNotCallGetcAndPutcWithSideEffects.qlref | 1 + c/cert/test/rules/FIO41-C/test.c | 21 + ...FsetposThatAreReturnedFromFgetpos.expected | 2 + ...ForFsetposThatAreReturnedFromFgetpos.qlref | 1 + c/cert/test/rules/FIO44-C/test.c | 34 + c/common/src/codingstandards/c/Expr.qll | 44 + c/common/src/codingstandards/c/Ordering.qll | 76 ++ c/common/src/codingstandards/c/Variable.qll | 8 + .../VariableAccessOrdering.qll | 57 + c/common/src/qlpack.yml | 2 +- c/common/test/expr/FullExpr.expected | 8 + c/common/test/expr/FullExpr.ql | 5 + c/common/test/expr/fullexpr.c | 24 + c/common/test/qlpack.yml | 2 +- .../DoNotAccessAClosedFile.expected | 21 +- .../test/rules/donotaccessaclosedfile/test.c | 19 + c/misra/src/qlpack.yml | 2 +- ...dentifiersInTheSameNameSpaceUnambiguous.ql | 22 + .../src/rules/DIR-4-5/standard-example.cpp | 18 + ...plicitPrecedenceOfOperatorsInExpression.ql | 122 ++ .../RULE-12-1/UnenclosedSizeofOperand.ql | 22 + .../src/rules/RULE-12-1/standard-example.c | 0 ...alizerListsContainPersistentSideEffects.ql | 32 + .../src/rules/RULE-13-1/standard-example.c | 0 ...ltOfAnAssignmentOperatorShouldNotBeUsed.ql | 22 + .../src/rules/RULE-13-4/standard-example.c | 0 ...pressedSideEffectInLogicOperatorOperand.ql | 25 + .../src/rules/RULE-13-5/standard-example.c | 0 .../RULE-13-6/SizeofOperandWithSideEffect.ql | 45 + .../src/rules/RULE-13-6/standard-example.c | 0 ...CharacterSequencesAndUsedWithinAComment.ql | 39 + .../RULE-3-2/LineSplicingUsedInComments.ql | 23 + ...HexadecimalEscapeSequencesNotTerminated.ql | 48 + .../SectionsOfCodeShallNotBeCommentedOut.ql | 23 + .../UOrUSuffixRepresentedInUnsignedType.ql | 24 + .../LowercaseCharacterLUsedInLiteralSuffix.ql | 23 + c/misra/test/qlpack.yml | 2 +- ...fiersInTheSameNameSpaceUnambiguous.testref | 1 + ...PrecedenceOfOperatorsInExpression.expected | 4 + ...citPrecedenceOfOperatorsInExpression.qlref | 1 + .../UnenclosedSizeofOperand.expected | 1 + .../RULE-12-1/UnenclosedSizeofOperand.qlref | 1 + c/misra/test/rules/RULE-12-1/test.c | 36 + ...ListsContainPersistentSideEffects.expected | 3 + ...zerListsContainPersistentSideEffects.qlref | 1 + c/misra/test/rules/RULE-13-1/test.c | 10 + ...AssignmentOperatorShouldNotBeUsed.expected | 3 + ...fAnAssignmentOperatorShouldNotBeUsed.qlref | 1 + c/misra/test/rules/RULE-13-4/test.c | 14 + ...dSideEffectInLogicOperatorOperand.expected | 3 + ...ssedSideEffectInLogicOperatorOperand.qlref | 1 + c/misra/test/rules/RULE-13-5/test.c | 44 + .../SizeofOperandWithSideEffect.expected | 5 + .../SizeofOperandWithSideEffect.qlref | 1 + c/misra/test/rules/RULE-13-6/test.c | 21 + ...terSequencesAndUsedWithinAComment.expected | 3 + ...racterSequencesAndUsedWithinAComment.qlref | 1 + c/misra/test/rules/RULE-3-1/test.c | 23 + .../LineSplicingUsedInComments.expected | 4 + .../RULE-3-2/LineSplicingUsedInComments.qlref | 1 + c/misra/test/rules/RULE-3-2/test.c | 64 ++ ...cimalEscapeSequencesNotTerminated.expected | 21 + ...adecimalEscapeSequencesNotTerminated.qlref | 1 + c/misra/test/rules/RULE-4-1/test.c | 53 + ...ctionsOfCodeShallNotBeCommentedOut.testref | 1 + ...rUSuffixRepresentedInUnsignedType.expected | 5 + .../UOrUSuffixRepresentedInUnsignedType.qlref | 1 + c/misra/test/rules/RULE-7-2/test.c | 39 + ...caseCharacterLUsedInLiteralSuffix.expected | 16 + ...wercaseCharacterLUsedInLiteralSuffix.qlref | 1 + c/misra/test/rules/RULE-7-3/test.c | 44 + c/options | 2 +- codeql_modules/codeql | 2 +- cpp/autosar/src/qlpack.yml | 2 +- .../CopyConstructorShallOnlyCopyObject.ql | 2 + .../MoveConstructorShallOnlyMoveObject.ql | 1 + ...iteralsOperatorsShallNotHaveSideEffects.ql | 1 + .../A2-7-2/SectionsOfCodeCommentedOut.ql | 10 +- ...ressionShouldNotRelyOnOrderOfEvaluation.ql | 1 + .../A6-2-1/CopyOperatorShallOnlyCopyObject.ql | 2 + .../A6-2-1/MoveOperatorShallOnlyMoveObject.ql | 1 + ...dReturnTypeShallHaveExternalSideEffects.ql | 3 + ...dentifiersNotTypographicallyUnambiguous.ql | 91 +- ...UnnecessaryExposedIdentifierDeclaration.ql | 1 + ...fALogicalAndOperatorsContainSideEffects.ql | 1 + ...ndToTheSizeofOperatorContainSideEffects.ql | 1 + .../rules/M6-2-1/AssignmentInSubExpression.ql | 1 + cpp/autosar/test/qlpack.yml | 2 +- .../A2-7-2/SectionsOfCodeCommentedOut.qlref | 1 - .../A2-7-2/SectionsOfCodeCommentedOut.testref | 1 + ...iersNotTypographicallyUnambiguous.expected | 31 - ...tifiersNotTypographicallyUnambiguous.qlref | 1 - ...fiersNotTypographicallyUnambiguous.testref | 1 + cpp/cert/src/qlpack.yml | 2 +- ...exToGoOutOfScopeWhileLocked-standard.qhelp | 134 +-- ...estroyAMutexWhileItIsLocked-standard.qhelp | 134 +-- ...asedOnExceptionalConditions-standard.qhelp | 156 +-- ...itFieldsFromMultipleThreads-standard.qhelp | 137 +-- ...kByLockingInPredefinedOrder-standard.qhelp | 168 +-- ...atCanSpuriouslyWakeUpInLoop-standard.qhelp | 244 +--- ...WhenUsingConditionVariables-standard.qhelp | 330 +----- ...ockALockedNonRecursiveMutex-standard.qhelp | 215 +--- ...ockedNonRecursiveMutexAudit-standard.qhelp | 215 +--- ...AccessWithoutRangeCheckCert-standard.qhelp | 360 +----- ...ValidContainerElementAccess-standard.qhelp | 435 ++----- ...braryFunctionsDoNotOverflow-standard.qhelp | 237 +--- .../UseValidIteratorRanges-standard.qhelp | 209 +--- ...atorsForDifferentContainers-standard.qhelp | 374 +----- ...dditiveOperatorOnAnIterator-standard.qhelp | 114 +- ...thmeticOnPolymorphicObjects-standard.qhelp | 231 +--- ...videAValidOrderingPredicate-standard.qhelp | 164 +-- ...onObjectsShouldNotBeMutable-standard.qhelp | 235 +--- ...fineACStyleVariadicFunction-standard.qhelp | 280 +---- ...numeratorReusesReservedName-standard.qhelp | 477 ++------ .../FunctionReusesReservedName-standard.qhelp | 477 ++------ .../ObjectReusesReservedName-standard.qhelp | 477 ++------ ...finingOfStandardLibraryName-standard.qhelp | 477 ++------ .../ReuseOfReservedIdentifier-standard.qhelp | 477 ++------ ...bleUnderscoreReservedPrefix-standard.qhelp | 477 ++------ ...rvedLiteralSuffixIdentifier-standard.qhelp | 477 ++------ .../UseOfReservedNamePrefix-standard.qhelp | 477 ++------ ...gleUnderscoreReservedPrefix-standard.qhelp | 477 ++------ ...alizedObjectHidesIdentifier-standard.qhelp | 289 +---- .../LocalFunctionDeclaration-standard.qhelp | 289 +---- ...larOverloadOfMemoryFunction-standard.qhelp | 231 +--- ...eakageAcrossTrustBoundaries-standard.qhelp | 346 ++---- ...yclesDuringStaticObjectInit-standard.qhelp | 300 +---- ...torsOrDeallocationFunctions-standard.qhelp | 367 +----- ...tionOfTheStandardNamespaces-standard.qhelp | 360 +----- ...nnamedNamespaceInHeaderFile-standard.qhelp | 382 ++---- .../OneDefinitionRuleNotObeyed-standard.qhelp | 478 +------- ...ablePostConditionFailedCert-standard.qhelp | 592 ++-------- ...tHandlerThrowsExceptionCert-standard.qhelp | 592 ++-------- ...plicitAbruptTerminationCert-standard.qhelp | 592 ++-------- ...ThreadCopiedOrDestroyedCert-standard.qhelp | 592 ++-------- ...rowNestedWithoutCaptureCert-standard.qhelp | 592 ++-------- .../HandleAllExceptions-standard.qhelp | 249 +--- .../DoNotUseSetjmpOrLongjmp-standard.qhelp | 276 +---- ...tructorDestructorCatchBlock-standard.qhelp | 150 +-- .../CatchBlockShadowingCert-standard.qhelp | 167 +-- ...onorExceptionSpecifications-standard.qhelp | 295 +---- .../GuaranteeExceptionSafety-standard.qhelp | 198 +--- ...urcesWhenHandlingExceptions-standard.qhelp | 291 +---- ...wnBeforeMainBeginsExecuting-standard.qhelp | 315 +---- ...onAcrossExecutionBoundaries-standard.qhelp | 126 +- ...tBeNothrowCopyConstructible-standard.qhelp | 229 +--- ...ExceptionsByLvalueReference-standard.qhelp | 300 +---- ...nConvertingAStringToANumber-standard.qhelp | 245 +--- ...ionCallsAsFunctionArguments-standard.qhelp | 599 ++-------- ...ectEvaluationForSideEffects-standard.qhelp | 599 ++-------- ...rOfScalarObjectEvaluationForSideEffects.ql | 2 + ...hAPointerOfTheIncorrectType-standard.qhelp | 134 +-- ...ideEffectsInDeclTypeOperand-standard.qhelp | 301 +---- ...DoNotRelyOnSideEffectsInDeclTypeOperand.ql | 1 + ...eEffectsInDeclValExpression-standard.qhelp | 301 +---- ...NotRelyOnSideEffectsInDeclValExpression.ql | 1 + ...ideEffectsInNoExceptOperand-standard.qhelp | 301 +---- ...DoNotRelyOnSideEffectsInNoExceptOperand.ql | 1 + ...nSideEffectsInSizeOfOperand-standard.qhelp | 301 +---- .../DoNotRelyOnSideEffectsInSizeOfOperand.ql | 1 + ...nSideEffectsInTypeIdOperand-standard.qhelp | 301 +---- ...oNotReadUninitializedMemory-standard.qhelp | 464 ++------ ...ctAccessedAfterLifetimeCert-standard.qhelp | 759 +++--------- ...tAccessedBeforeLifetimeCert-standard.qhelp | 759 +++--------- ...OrVolatileQualificationCert-standard.qhelp | 325 +----- ...thMismatchedLanguageLinkage-standard.qhelp | 238 +--- ...tOfPointerToIncompleteClass-standard.qhelp | 315 +---- ...ingPointerToIncompleteClass-standard.qhelp | 315 +---- ...ssNonTrivialObjectToVaStart-standard.qhelp | 266 +---- ...tablePrimitiveTypeToVaStart-standard.qhelp | 266 +---- .../PassReferenceTypeToVaStart-standard.qhelp | 266 +---- ...etUsedOnInvalidTypeOrMember-standard.qhelp | 328 +----- ...ndardObjectAcrossBoundaries-standard.qhelp | 224 +--- ...bjectWithCaptureByReference-standard.qhelp | 164 +-- ...bjectWithCaptureByReference-standard.qhelp | 164 +-- ...oAccessObjectRepresentation-standard.qhelp | 298 +---- ...oAccessObjectRepresentation-standard.qhelp | 298 +---- ...oAccessObjectRepresentation-standard.qhelp | 298 +---- ...nTheValueOfAMovedFromObject-standard.qhelp | 364 ++---- ...dInputOutputWithoutPosition-standard.qhelp | 230 +--- ...esWhenTheyAreNoLongerNeeded-standard.qhelp | 191 +-- ...nOutOfRangeEnumerationValue-standard.qhelp | 196 +--- .../MEM50-CPP/UseAfterFree-standard.qhelp | 442 ++----- ...namicallyAllocatedResources-standard.qhelp | 1020 +++-------------- ...andleMemoryAllocationErrors-standard.qhelp | 481 +------- ...allForManuallyManagedObject-standard.qhelp | 310 +---- ...allForManuallyManagedObject-standard.qhelp | 310 +---- ...tNewInsufficientStorageCert-standard.qhelp | 307 +---- ...ntNewNotProperlyAlignedCert-standard.qhelp | 307 +---- ...torDeleteMissingPartnerCert-standard.qhelp | 145 +-- ...oThrowOperatorNewDeleteCert-standard.qhelp | 145 +-- ...gOperatorNewReturnsNullCert-standard.qhelp | 145 +-- .../ThrowingOperatorNewReturnsNullCert.md | 81 -- ...wThrowsInvalidExceptionCert-standard.qhelp | 145 +-- ...InUnrelatedSmartPointerCert-standard.qhelp | 392 +------ ...ratorNewForOverAlignedTypes-standard.qhelp | 156 +-- ...neratingPseudorandomNumbers-standard.qhelp | 151 +-- ...SeededRandomNumberGenerator-standard.qhelp | 168 +-- ...idFunctionDoesNotReturnCert-standard.qhelp | 233 +--- ...eturnAttributeConditionCert-standard.qhelp | 173 +-- ...dlerMustBeAPlainOldFunction-standard.qhelp | 249 +--- ...omConstructorsOrDestructors-standard.qhelp | 297 +---- .../DoNotSliceDerivedObjects-standard.qhelp | 270 +---- ...ctWithoutAVirtualDestructor-standard.qhelp | 317 +---- ...CanonicalOrderForMemberInit-standard.qhelp | 221 +--- ...llyHandleSelfCopyAssignment-standard.qhelp | 269 +---- ...alizedStaticPointerToMember-standard.qhelp | 286 +---- ...erToAccessNonexistentMember-standard.qhelp | 286 +---- ...mberToAccessUndefinedMember-standard.qhelp | 286 +---- ...lacementHandlerRequirements-standard.qhelp | 257 +---- ...lacementHandlerRequirements-standard.qhelp | 257 +---- ...ToCStandardLibraryFunctions-standard.qhelp | 413 ++----- ...ustNotMutateTheSourceObject-standard.qhelp | 277 +---- ...gMayNotBeNullTerminatedCert-standard.qhelp | 252 +--- ...llTerminateCStyleStringCert-standard.qhelp | 252 +--- ...eateAStringFromANullPointer-standard.qhelp | 513 ++------- ...ferencesForElementsOfString-standard.qhelp | 270 +---- ...ngeCheckStringElementAccess-standard.qhelp | 232 +--- cpp/cert/test/qlpack.yml | 2 +- cpp/common/src/codingstandards/cpp/Expr.qll | 7 + .../cpp/FgetsErrorManagement.qll | 160 +++ .../src/codingstandards/cpp/Ordering.qll | 1 + .../src/codingstandards/cpp/SideEffect.qll | 234 ++-- .../src/codingstandards/cpp/Variable.qll | 7 + .../codingstandards/cpp/exclusions/c/IO2.qll | 74 ++ .../cpp/exclusions/c/RuleMetadata.qll | 13 +- .../cpp/exclusions/c/SideEffects1.qll | 170 +++ .../cpp/exclusions/c/Syntax.qll | 122 ++ ...entifiersNotTypographicallyUnambiguous.qll | 105 ++ .../DoNotAccessAClosedFile.qll | 2 +- ...icateFunctionObjectsShouldNotBeMutable.qll | 1 + .../SectionsOfCodeShallNotBeCommentedOut.qll | 18 + .../cpp/sideeffect/Customizations.qll | 19 + .../cpp/sideeffect/DefaultEffects.qll | 65 ++ .../cpp/standardlibrary/FileAccess.qll | 4 +- cpp/common/src/qlpack.yml | 2 +- cpp/common/test/qlpack.yml | 2 +- ...iersNotTypographicallyUnambiguous.expected | 31 + ...dentifiersNotTypographicallyUnambiguous.ql | 2 + .../test.cpp | 0 ...alueStoredInUnrelatedSmartPointer.expected | 24 + ...ionsOfCodeShallNotBeCommentedOut.expected} | 0 .../SectionsOfCodeShallNotBeCommentedOut.ql | 2 + .../config.h | 0 .../test.cpp | 0 cpp/misra/src/qlpack.yml | 2 +- cpp/misra/test/qlpack.yml | 2 +- cpp/report/src/qlpack.yml | 2 +- rule_packages/c/IO1.json | 32 +- rule_packages/c/IO2.json | 94 ++ rule_packages/c/SideEffects1.json | 181 +++ rule_packages/c/Syntax.json | 149 +++ rule_packages/cpp/Comments.json | 1 + rule_packages/cpp/IO.json | 7 +- rule_packages/cpp/Naming.json | 1 + rule_packages/cpp/TypeRanges.json | 5 +- rules.csv | 32 +- .../generate_rules/generate_package_files.py | 32 +- .../templates/template-standard.qhelp | 2 +- .../generate_rules/templates/template.qhelp | 2 +- ...-extraction.py => cert-help-extraction.py} | 181 ++- ...Get-TestOrQueryDirectoryForCurrentFile.ps1 | 148 +++ supported_codeql_configs.json | 6 +- 330 files changed, 14322 insertions(+), 32140 deletions(-) create mode 100644 c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects-implementation.qhelp create mode 100644 c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects-standard.qhelp create mode 100644 c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.qhelp create mode 100644 c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.ql create mode 100644 c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects-implementation.qhelp create mode 100644 c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects-standard.qhelp create mode 100644 c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects.qhelp create mode 100644 c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects.ql rename cpp/autosar/test/rules/A2-7-2/config.h => c/cert/src/rules/EXP30-C/standard-example.c (100%) create mode 100644 c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect-implementation.qhelp create mode 100644 c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect-standard.qhelp create mode 100644 c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect.qhelp create mode 100644 c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect.ql create mode 100644 c/cert/src/rules/EXP44-C/standard-example.c create mode 100644 c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements-implementation.qhelp create mode 100644 c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements-standard.qhelp create mode 100644 c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements.qhelp create mode 100644 c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements.ql create mode 100644 c/cert/src/rules/EXP45-C/standard-example.c create mode 100644 c/cert/src/rules/FIO38-C/DoNotCopyAFileObject-implementation.qhelp create mode 100644 c/cert/src/rules/FIO38-C/DoNotCopyAFileObject-standard.qhelp create mode 100644 c/cert/src/rules/FIO38-C/DoNotCopyAFileObject.qhelp create mode 100644 c/cert/src/rules/FIO38-C/DoNotCopyAFileObject.ql create mode 100644 c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure-implementation.qhelp create mode 100644 c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure-standard.qhelp create mode 100644 c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.qhelp create mode 100644 c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.ql create mode 100644 c/cert/src/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects-implementation.qhelp create mode 100644 c/cert/src/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects-standard.qhelp create mode 100644 c/cert/src/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects.qhelp create mode 100644 c/cert/src/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects.ql create mode 100644 c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos-implementation.qhelp create mode 100644 c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos-standard.qhelp create mode 100644 c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.qhelp create mode 100644 c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql create mode 100644 c/cert/test/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.expected create mode 100644 c/cert/test/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.qlref create mode 100644 c/cert/test/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects.expected create mode 100644 c/cert/test/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects.qlref create mode 100644 c/cert/test/rules/EXP30-C/test.c create mode 100644 c/cert/test/rules/EXP44-C/UnevaluatedOperandWithSideEffect.expected create mode 100644 c/cert/test/rules/EXP44-C/UnevaluatedOperandWithSideEffect.qlref create mode 100644 c/cert/test/rules/EXP44-C/test.c create mode 100644 c/cert/test/rules/EXP45-C/AssignmentsInSelectionStatements.expected create mode 100644 c/cert/test/rules/EXP45-C/AssignmentsInSelectionStatements.qlref create mode 100644 c/cert/test/rules/EXP45-C/test.c create mode 100644 c/cert/test/rules/FIO38-C/DoNotCopyAFileObject.expected create mode 100644 c/cert/test/rules/FIO38-C/DoNotCopyAFileObject.qlref create mode 100644 c/cert/test/rules/FIO38-C/test.c create mode 100644 c/cert/test/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.expected create mode 100644 c/cert/test/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.qlref create mode 100644 c/cert/test/rules/FIO40-C/test.c create mode 100644 c/cert/test/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects.expected create mode 100644 c/cert/test/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects.qlref create mode 100644 c/cert/test/rules/FIO41-C/test.c create mode 100644 c/cert/test/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.expected create mode 100644 c/cert/test/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.qlref create mode 100644 c/cert/test/rules/FIO44-C/test.c create mode 100644 c/common/src/codingstandards/c/Expr.qll create mode 100644 c/common/src/codingstandards/c/Ordering.qll create mode 100644 c/common/src/codingstandards/c/Variable.qll create mode 100644 c/common/src/codingstandards/c/orderofevaluation/VariableAccessOrdering.qll create mode 100644 c/common/test/expr/FullExpr.expected create mode 100644 c/common/test/expr/FullExpr.ql create mode 100644 c/common/test/expr/fullexpr.c create mode 100644 c/misra/src/rules/DIR-4-5/IdentifiersInTheSameNameSpaceUnambiguous.ql create mode 100644 c/misra/src/rules/DIR-4-5/standard-example.cpp create mode 100644 c/misra/src/rules/RULE-12-1/ImplicitPrecedenceOfOperatorsInExpression.ql create mode 100644 c/misra/src/rules/RULE-12-1/UnenclosedSizeofOperand.ql create mode 100644 c/misra/src/rules/RULE-12-1/standard-example.c create mode 100644 c/misra/src/rules/RULE-13-1/InitializerListsContainPersistentSideEffects.ql create mode 100644 c/misra/src/rules/RULE-13-1/standard-example.c create mode 100644 c/misra/src/rules/RULE-13-4/ResultOfAnAssignmentOperatorShouldNotBeUsed.ql create mode 100644 c/misra/src/rules/RULE-13-4/standard-example.c create mode 100644 c/misra/src/rules/RULE-13-5/PossibleSuppressedSideEffectInLogicOperatorOperand.ql create mode 100644 c/misra/src/rules/RULE-13-5/standard-example.c create mode 100644 c/misra/src/rules/RULE-13-6/SizeofOperandWithSideEffect.ql create mode 100644 c/misra/src/rules/RULE-13-6/standard-example.c create mode 100644 c/misra/src/rules/RULE-3-1/CharacterSequencesAndUsedWithinAComment.ql create mode 100644 c/misra/src/rules/RULE-3-2/LineSplicingUsedInComments.ql create mode 100644 c/misra/src/rules/RULE-4-1/OctalAndHexadecimalEscapeSequencesNotTerminated.ql create mode 100644 c/misra/src/rules/RULE-4-4/SectionsOfCodeShallNotBeCommentedOut.ql create mode 100644 c/misra/src/rules/RULE-7-2/UOrUSuffixRepresentedInUnsignedType.ql create mode 100644 c/misra/src/rules/RULE-7-3/LowercaseCharacterLUsedInLiteralSuffix.ql create mode 100644 c/misra/test/rules/DIR-4-5/IdentifiersInTheSameNameSpaceUnambiguous.testref create mode 100644 c/misra/test/rules/RULE-12-1/ImplicitPrecedenceOfOperatorsInExpression.expected create mode 100644 c/misra/test/rules/RULE-12-1/ImplicitPrecedenceOfOperatorsInExpression.qlref create mode 100644 c/misra/test/rules/RULE-12-1/UnenclosedSizeofOperand.expected create mode 100644 c/misra/test/rules/RULE-12-1/UnenclosedSizeofOperand.qlref create mode 100644 c/misra/test/rules/RULE-12-1/test.c create mode 100644 c/misra/test/rules/RULE-13-1/InitializerListsContainPersistentSideEffects.expected create mode 100644 c/misra/test/rules/RULE-13-1/InitializerListsContainPersistentSideEffects.qlref create mode 100644 c/misra/test/rules/RULE-13-1/test.c create mode 100644 c/misra/test/rules/RULE-13-4/ResultOfAnAssignmentOperatorShouldNotBeUsed.expected create mode 100644 c/misra/test/rules/RULE-13-4/ResultOfAnAssignmentOperatorShouldNotBeUsed.qlref create mode 100644 c/misra/test/rules/RULE-13-4/test.c create mode 100644 c/misra/test/rules/RULE-13-5/PossibleSuppressedSideEffectInLogicOperatorOperand.expected create mode 100644 c/misra/test/rules/RULE-13-5/PossibleSuppressedSideEffectInLogicOperatorOperand.qlref create mode 100644 c/misra/test/rules/RULE-13-5/test.c create mode 100644 c/misra/test/rules/RULE-13-6/SizeofOperandWithSideEffect.expected create mode 100644 c/misra/test/rules/RULE-13-6/SizeofOperandWithSideEffect.qlref create mode 100644 c/misra/test/rules/RULE-13-6/test.c create mode 100644 c/misra/test/rules/RULE-3-1/CharacterSequencesAndUsedWithinAComment.expected create mode 100644 c/misra/test/rules/RULE-3-1/CharacterSequencesAndUsedWithinAComment.qlref create mode 100644 c/misra/test/rules/RULE-3-1/test.c create mode 100644 c/misra/test/rules/RULE-3-2/LineSplicingUsedInComments.expected create mode 100644 c/misra/test/rules/RULE-3-2/LineSplicingUsedInComments.qlref create mode 100644 c/misra/test/rules/RULE-3-2/test.c create mode 100644 c/misra/test/rules/RULE-4-1/OctalAndHexadecimalEscapeSequencesNotTerminated.expected create mode 100644 c/misra/test/rules/RULE-4-1/OctalAndHexadecimalEscapeSequencesNotTerminated.qlref create mode 100644 c/misra/test/rules/RULE-4-1/test.c create mode 100644 c/misra/test/rules/RULE-4-4/SectionsOfCodeShallNotBeCommentedOut.testref create mode 100644 c/misra/test/rules/RULE-7-2/UOrUSuffixRepresentedInUnsignedType.expected create mode 100644 c/misra/test/rules/RULE-7-2/UOrUSuffixRepresentedInUnsignedType.qlref create mode 100644 c/misra/test/rules/RULE-7-2/test.c create mode 100644 c/misra/test/rules/RULE-7-3/LowercaseCharacterLUsedInLiteralSuffix.expected create mode 100644 c/misra/test/rules/RULE-7-3/LowercaseCharacterLUsedInLiteralSuffix.qlref create mode 100644 c/misra/test/rules/RULE-7-3/test.c delete mode 100644 cpp/autosar/test/rules/A2-7-2/SectionsOfCodeCommentedOut.qlref create mode 100644 cpp/autosar/test/rules/A2-7-2/SectionsOfCodeCommentedOut.testref delete mode 100644 cpp/autosar/test/rules/M2-10-1/DifferentIdentifiersNotTypographicallyUnambiguous.expected delete mode 100644 cpp/autosar/test/rules/M2-10-1/DifferentIdentifiersNotTypographicallyUnambiguous.qlref create mode 100644 cpp/autosar/test/rules/M2-10-1/DifferentIdentifiersNotTypographicallyUnambiguous.testref delete mode 100644 cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewReturnsNullCert.md create mode 100644 cpp/common/src/codingstandards/cpp/FgetsErrorManagement.qll create mode 100644 cpp/common/src/codingstandards/cpp/Variable.qll create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/c/IO2.qll create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/c/SideEffects1.qll create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/c/Syntax.qll create mode 100644 cpp/common/src/codingstandards/cpp/rules/differentidentifiersnottypographicallyunambiguous/DifferentIdentifiersNotTypographicallyUnambiguous.qll create mode 100644 cpp/common/src/codingstandards/cpp/rules/sectionsofcodeshallnotbecommentedout/SectionsOfCodeShallNotBeCommentedOut.qll create mode 100644 cpp/common/src/codingstandards/cpp/sideeffect/Customizations.qll create mode 100644 cpp/common/src/codingstandards/cpp/sideeffect/DefaultEffects.qll create mode 100644 cpp/common/test/rules/differentidentifiersnottypographicallyunambiguous/DifferentIdentifiersNotTypographicallyUnambiguous.expected create mode 100644 cpp/common/test/rules/differentidentifiersnottypographicallyunambiguous/DifferentIdentifiersNotTypographicallyUnambiguous.ql rename cpp/{autosar/test/rules/M2-10-1 => common/test/rules/differentidentifiersnottypographicallyunambiguous}/test.cpp (100%) rename cpp/{autosar/test/rules/A2-7-2/SectionsOfCodeCommentedOut.expected => common/test/rules/sectionsofcodeshallnotbecommentedout/SectionsOfCodeShallNotBeCommentedOut.expected} (100%) create mode 100644 cpp/common/test/rules/sectionsofcodeshallnotbecommentedout/SectionsOfCodeShallNotBeCommentedOut.ql create mode 100644 cpp/common/test/rules/sectionsofcodeshallnotbecommentedout/config.h rename cpp/{autosar/test/rules/A2-7-2 => common/test/rules/sectionsofcodeshallnotbecommentedout}/test.cpp (100%) create mode 100644 rule_packages/c/IO2.json create mode 100644 rule_packages/c/SideEffects1.json create mode 100644 rule_packages/c/Syntax.json rename scripts/help/{cert-cpp-help-extraction.py => cert-help-extraction.py} (70%) create mode 100644 scripts/vscode/Get-TestOrQueryDirectoryForCurrentFile.ps1 diff --git a/.github/actions/install-codeql/action.yml b/.github/actions/install-codeql/action.yml index 25cbb5e123..48913c93e0 100644 --- a/.github/actions/install-codeql/action.yml +++ b/.github/actions/install-codeql/action.yml @@ -90,7 +90,7 @@ runs: if [ "$CODEQL_STDLIB_VERSION" != "latest" ] then - push codeql-stdlib + pushd codeql-stdlib echo "::debug::Switching to revision $CODEQL_STDLIB_VERSION" git checkout $CODEQL_STDLIB_VERSION popd diff --git a/.github/workflows/code-scanning-pack-gen.yml b/.github/workflows/code-scanning-pack-gen.yml index b871acdc8f..7406218e44 100644 --- a/.github/workflows/code-scanning-pack-gen.yml +++ b/.github/workflows/code-scanning-pack-gen.yml @@ -5,11 +5,13 @@ on: branches: - main - "rc/**" + - "c-coding-standards" push: branches: - main - "rc/**" + - "c-coding-standards" env: XARGS_MAX_PROCS: 4 diff --git a/.vscode/tasks.json b/.vscode/tasks.json index a0790f333d..efcee24155 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -12,6 +12,18 @@ }, "problemMatcher": [] }, + + { + "label": "🔃 Standards Automation: Switch To Test or Implementation", + "type": "shell", + "command": "pwsh .${pathSeparator}scripts${pathSeparator}vscode${pathSeparator}Get-TestOrQueryDirectoryForCurrentFile.ps1 -CurrentFile ${file}", + "presentation": { + "reveal": "never", + "panel": "dedicated" + }, + "problemMatcher": [] + }, + { "label": "Standards Automation: Install Deps", "type": "shell", @@ -157,6 +169,7 @@ "BannedTypes", "BannedFunctions", "Classes", + "Comments", "Concurrency", "Const", "Declarations", @@ -171,14 +184,13 @@ "Macros", "Naming", "Scope", - "Side-effects1", - "Side-effects2", "Classes", "SmartPointers1", "SmartPointers2", "SideEffects1", "SideEffects2", "Strings", + "Syntax", "Templates", "Classes", "Freed", diff --git a/c/cert/src/qlpack.yml b/c/cert/src/qlpack.yml index 6523decd27..586a651e22 100644 --- a/c/cert/src/qlpack.yml +++ b/c/cert/src/qlpack.yml @@ -1,4 +1,4 @@ name: cert-c-coding-standards -version: 2.0.0 +version: 2.1.0 suites: codeql-suites libraryPathDependencies: common-c-coding-standards \ No newline at end of file diff --git a/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects-implementation.qhelp b/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects-implementation.qhelp new file mode 100644 index 0000000000..a01fab8d10 --- /dev/null +++ b/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects-implementation.qhelp @@ -0,0 +1,8 @@ + + + +

None

+
+
\ No newline at end of file diff --git a/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects-standard.qhelp b/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects-standard.qhelp new file mode 100644 index 0000000000..458fbe3f7d --- /dev/null +++ b/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects-standard.qhelp @@ -0,0 +1,33 @@ + + +
+
    +
  • required
  • +
  • implementation
  • +
  • automated
  • +
+
+ +
+

+ ... +

+ +
+ +
+

+ ... +

+
+ + + + + +
+
    +
  • ...
  • +
+
+
\ No newline at end of file diff --git a/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.qhelp b/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.qhelp new file mode 100644 index 0000000000..f7783bface --- /dev/null +++ b/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.qhelp @@ -0,0 +1,21 @@ + + + + +

This query implements the CERT-C rule EXP30-C:

+
+

Do not depend on the order of evaluation for side effects

+
+
+ +
+ +
+ +
  • + CERT-C: + EXP30-C: Do not depend on the order of evaluation for side effects + . +
  • +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.ql b/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.ql new file mode 100644 index 0000000000..3070f8d310 --- /dev/null +++ b/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.ql @@ -0,0 +1,129 @@ +/** + * @id c/cert/dependence-on-order-of-function-arguments-for-side-effects + * @name EXP30-C: Do not depend on the order of evaluation of function call arguments for side effects + * @description Depending on the order of evaluation for side effects in function call arguments can + * result in unexpected program behavior. + * @kind problem + * @precision high + * @problem.severity warning + * @tags external/cert/id/exp30-c + * correctness + * external/cert/obligation/rule + */ + +import cpp +import codingstandards.c.cert +import codingstandards.cpp.SideEffect +import semmle.code.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.TaintTracking +import semmle.code.cpp.valuenumbering.GlobalValueNumberingImpl + +/** Holds if the function's return value is derived from the `AliasParamter` p. */ +predicate returnValueDependsOnAliasParameter(AliasParameter p) { + exists(ReturnStmt ret | ret = p.getFunction().getBlock().getAStmt() | + TaintTracking::localTaint(DataFlow::parameterNode(p), DataFlow::exprNode(ret.getExpr())) + or + exists(FieldAccess fa, VariableAccess va | fa.getQualifier() = va and va.getTarget() = p | + TaintTracking::localTaint(DataFlow::exprNode(fa), DataFlow::exprNode(ret.getExpr())) + ) + or + exists(FunctionCall call, VariableAccess va | call.getQualifier() = va and va.getTarget() = p | + TaintTracking::localTaint(DataFlow::exprNode(call), DataFlow::exprNode(ret.getExpr())) + ) + or + exists(VariableAccess va | va.getTarget() = p | ret.getAChild+() = va) + ) + or + exists(FunctionCall call, ReturnStmt ret, int i, AliasParameter q | + ret = p.getFunction().getBlock().getAStmt() and call.getEnclosingFunction() = p.getFunction() + | + DataFlow::localFlow(DataFlow::parameterNode(p), DataFlow::exprNode(call.getArgument(i))) and + q = call.getTarget().getParameter(i) and + returnValueDependsOnAliasParameter(q) and + TaintTracking::localTaint(DataFlow::exprNode(call), DataFlow::exprNode(ret.getExpr())) + ) +} + +/** Holds if the function `f`'s return value is derived from the global variable `v`. */ +predicate returnValueDependsOnGlobalVariable(Function f, GlobalVariable v) { + exists(ReturnStmt ret, VariableAccess va | + ret = f.getBlock().getAStmt() and va.getTarget() = v and va.getEnclosingFunction() = f + | + TaintTracking::localTaint(DataFlow::exprNode(va), DataFlow::exprNode(ret.getExpr())) + ) + or + exists(ReturnStmt ret, FunctionCall call | + ret = f.getBlock().getAStmt() and + call.getEnclosingFunction() = f and + returnValueDependsOnGlobalVariable(call.getTarget(), v) and + TaintTracking::localTaint(DataFlow::exprNode(call), DataFlow::exprNode(ret.getExpr())) + ) +} + +/** Holds if the member function `f`'s return value is derived from the member variable `v`. */ +predicate returnValueDependsOnMemberVariable(MemberFunction f, MemberVariable v) { + exists(ReturnStmt ret, VariableAccess va | + ret = f.getBlock().getAStmt() and + va.getTarget() = v and + va.getEnclosingFunction() = f and + v.getDeclaringType() = f.getDeclaringType() + | + TaintTracking::localTaint(DataFlow::exprNode(va), DataFlow::exprNode(ret.getExpr())) + ) +} + +from + FunctionCall call, Function f1, Function f2, int i, int j, FunctionCall arg1, FunctionCall arg2, + Variable v1, Variable v2 +where + not isExcluded(call, + SideEffects1Package::dependenceOnOrderOfFunctionArgumentsForSideEffectsQuery()) and + arg1 = call.getArgument(i) and + arg2 = call.getArgument(j) and + i < j and + arg1.getTarget() = f1 and + arg2.getTarget() = f2 and + ( + // Considering the shared states: + // - pointer or reference arguments being used in both functions + exists(AliasParameter p1, AliasParameter p2 | + v1 = p1 and + v2 = p2 and + f1.getAParameter() = p1 and + f2.getAParameter() = p2 and + p1.isModified() and + p2.isModified() and + globalValueNumber(arg1.getArgument(p1.getIndex())) = + globalValueNumber(arg2.getArgument(p2.getIndex())) and + returnValueDependsOnAliasParameter(p1) and + returnValueDependsOnAliasParameter(p2) + ) + or + // - global variables being used in both functions + exists(GlobalVariable v, VariableEffect ve1, VariableEffect ve2 | + v1 = v and + v2 = v and + returnValueDependsOnGlobalVariable(f1, v) and + returnValueDependsOnGlobalVariable(f2, v) and + ve1.getTarget() = v and + ve2.getTarget() = v + ) + or + // - member variables that can be modified in both functions + exists(MemberVariable v | + v1 = v and + v2 = v and + returnValueDependsOnMemberVariable(f1, v) and + returnValueDependsOnMemberVariable(f2, v) and + v = getAMemberVariableEffect(f1).getTarget() and + v = getAMemberVariableEffect(f2).getTarget() and + ( + globalValueNumber(arg1.getQualifier()) = globalValueNumber(arg2.getQualifier()) + or + v.isStatic() and arg1.getQualifier().getType() = arg2.getQualifier().getType() + ) + ) + ) +select call, + "Depending on the order of evaluation for the arguments $@ and $@ for side effects on shared state is unspecified and can result in unexpected behavior.", + arg1, arg1.toString(), arg2, arg2.toString() diff --git a/c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects-implementation.qhelp b/c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects-implementation.qhelp new file mode 100644 index 0000000000..a01fab8d10 --- /dev/null +++ b/c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects-implementation.qhelp @@ -0,0 +1,8 @@ + + + +

    None

    +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects-standard.qhelp b/c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects-standard.qhelp new file mode 100644 index 0000000000..458fbe3f7d --- /dev/null +++ b/c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects-standard.qhelp @@ -0,0 +1,33 @@ + + +
    +
      +
    • required
    • +
    • implementation
    • +
    • automated
    • +
    +
    + +
    +

    + ... +

    + +
    + +
    +

    + ... +

    +
    + + + + + +
    +
      +
    • ...
    • +
    +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects.qhelp b/c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects.qhelp new file mode 100644 index 0000000000..6313114ff9 --- /dev/null +++ b/c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects.qhelp @@ -0,0 +1,21 @@ + + + + +

    This query implements the CERT-C rule EXP30-C:

    +
    +

    Do not depend on the order of evaluation for side effects

    +
    +
    + +
    + +
    + +
  • + CERT-C: + EXP30-C: Do not depend on the order of evaluation for side effects + . +
  • +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects.ql b/c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects.ql new file mode 100644 index 0000000000..c478a3d51e --- /dev/null +++ b/c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects.ql @@ -0,0 +1,30 @@ +/** + * @id c/cert/dependence-on-order-of-scalar-evaluation-for-side-effects + * @name EXP30-C: Do not depend on the order of scalar object evaluation for side effects + * @description Depending on the order of evaluation for side effects for evaluation of scalar + * objects that are unsequenced results in undefined behavior. + * @kind problem + * @precision high + * @problem.severity warning + * @tags external/cert/id/exp30-c + * correctness + * external/cert/obligation/rule + */ + +import cpp +import codingstandards.c.cert +import codingstandards.cpp.SideEffect +import codingstandards.c.Ordering +import codingstandards.c.orderofevaluation.VariableAccessOrdering + +from + VariableAccessInFullExpressionOrdering config, FullExpr e, ScalarVariable v, VariableEffect ve, + VariableAccess va1, VariableAccess va2 +where + not isExcluded(e, SideEffects1Package::dependenceOnOrderOfScalarEvaluationForSideEffectsQuery()) and + e = va1.(ConstituentExpr).getFullExpr() and + va1 = ve.getAnAccess() and + config.isUnsequenced(va1, va2) and + v = va1.getTarget() +select e, "Scalar object referenced by $@ has a $@ that is unsequenced in relative to another $@.", + v, v.getName(), ve, "side-effect", va2, "side-effect or value computation" diff --git a/cpp/autosar/test/rules/A2-7-2/config.h b/c/cert/src/rules/EXP30-C/standard-example.c similarity index 100% rename from cpp/autosar/test/rules/A2-7-2/config.h rename to c/cert/src/rules/EXP30-C/standard-example.c diff --git a/c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect-implementation.qhelp b/c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect-implementation.qhelp new file mode 100644 index 0000000000..a01fab8d10 --- /dev/null +++ b/c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect-implementation.qhelp @@ -0,0 +1,8 @@ + + + +

    None

    +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect-standard.qhelp b/c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect-standard.qhelp new file mode 100644 index 0000000000..458fbe3f7d --- /dev/null +++ b/c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect-standard.qhelp @@ -0,0 +1,33 @@ + + +
    +
      +
    • required
    • +
    • implementation
    • +
    • automated
    • +
    +
    + +
    +

    + ... +

    + +
    + +
    +

    + ... +

    +
    + + + + + +
    +
      +
    • ...
    • +
    +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect.qhelp b/c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect.qhelp new file mode 100644 index 0000000000..1069bc4211 --- /dev/null +++ b/c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect.qhelp @@ -0,0 +1,21 @@ + + + + +

    This query implements the CERT-C rule EXP44-C:

    +
    +

    Do not rely on side effects in operands to sizeof, _Alignof, or _Generic

    +
    +
    + +
    + +
    + +
  • + CERT-C: + EXP44-C: Do not rely on side effects in operands to sizeof, _Alignof, or _Generic + . +
  • +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect.ql b/c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect.ql new file mode 100644 index 0000000000..32d30a09ad --- /dev/null +++ b/c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect.ql @@ -0,0 +1,34 @@ +/** + * @id c/cert/unevaluated-operand-with-side-effect + * @name EXP44-C: Do not rely on side effects in operands to sizeof, _Alignof, or _Generic + * @description The operands to sizeof, _Alignof, or _Generic are not evaluated and their side + * effect will not be generated. Using operands with a side effect can result in + * unexpected program behavior. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/cert/id/exp44-c + * correctness + * external/cert/obligation/rule + */ + +import cpp +import codingstandards.c.cert +import codingstandards.cpp.SideEffect +import codingstandards.cpp.sideeffect.DefaultEffects + +class UnevaluatedOperand extends Expr { + UnevaluatedOperand() { + exists(SizeofExprOperator op | op.getExprOperand() = this | + not this.getUnderlyingType().(ArrayType).hasArraySize() + ) + or + exists(AlignofExprOperator op | op.getExprOperand() = this) + } +} + +from UnevaluatedOperand op +where + not isExcluded(op, SideEffects1Package::unevaluatedOperandWithSideEffectQuery()) and + hasSideEffect(op) +select op, "Unevaluated operand with side effect that will not be generated." diff --git a/c/cert/src/rules/EXP44-C/standard-example.c b/c/cert/src/rules/EXP44-C/standard-example.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements-implementation.qhelp b/c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements-implementation.qhelp new file mode 100644 index 0000000000..a01fab8d10 --- /dev/null +++ b/c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements-implementation.qhelp @@ -0,0 +1,8 @@ + + + +

    None

    +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements-standard.qhelp b/c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements-standard.qhelp new file mode 100644 index 0000000000..458fbe3f7d --- /dev/null +++ b/c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements-standard.qhelp @@ -0,0 +1,33 @@ + + +
    +
      +
    • required
    • +
    • implementation
    • +
    • automated
    • +
    +
    + +
    +

    + ... +

    + +
    + +
    +

    + ... +

    +
    + + + + + +
    +
      +
    • ...
    • +
    +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements.qhelp b/c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements.qhelp new file mode 100644 index 0000000000..240fef3e3e --- /dev/null +++ b/c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements.qhelp @@ -0,0 +1,21 @@ + + + + +

    This query implements the CERT-C rule EXP45-C:

    +
    +

    Do not perform assignments in selection statements

    +
    +
    + +
    + +
    + +
  • + CERT-C: + EXP45-C: Do not perform assignments in selection statements + . +
  • +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements.ql b/c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements.ql new file mode 100644 index 0000000000..f6e29eb28c --- /dev/null +++ b/c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements.ql @@ -0,0 +1,62 @@ +/** + * @id c/cert/assignments-in-selection-statements + * @name EXP45-C: Do not perform assignments in selection statements + * @description Assignments in selection statements is indicative of a programmer error and can + * result in unexpected program behavior. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/cert/id/exp45-c + * correctness + * external/cert/obligation/rule + */ + +import cpp +import codingstandards.c.cert +import codingstandards.c.Expr + +Expr getRightMostOperand(CommaExpr e) { + result = e.getRightOperand() and not result instanceof CommaExpr + or + result = getRightMostOperand(e.getRightOperand()) +} + +class SelectionExpr extends Expr { + SelectionExpr() { + exists(Expr selection | + exists(ControlStructure cs | cs.getControllingExpr() = selection) + or + exists(ConditionalExpr ce | ce.getCondition() = selection) + or + exists(LogicalAndExpr land | land.getAnOperand() = selection) + or + exists(LogicalOrExpr lor | lor.getAnOperand() = selection) + | + if selection instanceof CommaExpr + then this = getRightMostOperand(selection) + else + if selection instanceof ConditionalExpr + then + this = selection.(ConditionalExpr).getThen() or + this = selection.(ConditionalExpr).getElse() + else this = selection + ) + } +} + +from AssignExpr e +where + not isExcluded(e, SideEffects1Package::assignmentsInSelectionStatementsQuery()) and + exists(SelectionExpr s | + s.getAChild*() = e and + // Exclude intentional assignment where the result of the assignment is an operand to a comparison + // expression. + not any(ComparisonOperation op).getAnOperand() = e and + // Exclude an assignment where the expression consists of a single primary expression. + not (e instanceof PrimaryExpr and not e.getParent() instanceof Expr) and + // Exclude assignments that are a function argument. + not any(FunctionCall c).getAnArgument() = e and + // Exclude assignments used in an array index. + not any(ArrayExpr ae).getArrayOffset() = e + ) +select e, "Assignment in selection statement." diff --git a/c/cert/src/rules/EXP45-C/standard-example.c b/c/cert/src/rules/EXP45-C/standard-example.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/cert/src/rules/FIO30-C/ExcludeUserInputFromFormatStrings-standard.qhelp b/c/cert/src/rules/FIO30-C/ExcludeUserInputFromFormatStrings-standard.qhelp index 99ace9f40b..53396c7e5b 100644 --- a/c/cert/src/rules/FIO30-C/ExcludeUserInputFromFormatStrings-standard.qhelp +++ b/c/cert/src/rules/FIO30-C/ExcludeUserInputFromFormatStrings-standard.qhelp @@ -1,29 +1,585 @@ -
    -
      -
    • required
    • -
    • implementation
    • -
    • automated
    • -
    -
    - -
    -

    - ... -

    - -
    - -
    -

    - ... -

    -
    - -
    -
      -
    • ...
    • -
    -
    +
    +

    Never call a formatted I/O function with a format string containing a tainted value . An attacker who can fully or partially control the contents of a format string can crash a vulnerable process, view the contents of the stack, view memory content, or write to an arbitrary memory location. Consequently, the attacker can execute arbitrary code with the permissions of the vulnerable process [Seacord 2013b]. Formatted output functions are particularly dangerous because many programmers are unaware of their capabilities. For example, formatted output functions can be used to write an integer value to a specified address using the %n conversion specifier.

    +
    +
    +

    The incorrect_password() function in this noncompliant code example is called during identification and authentication to display an error message if the specified user is not found or the password is incorrect. The function accepts the name of the user as a string referenced by user. This is an exemplar of untrusted data that originates from an unauthenticated user. The function constructs an error message that is then output to stderr using the C Standard fprintf() function.

    + #include <stdio.h> +#include <stdlib.h> +#include <string.h> + +void incorrect_password(const char *user) { + int ret; + /* User names are restricted to 256 or fewer characters */ + static const char msg_format[] = "%s cannot be authenticated.\n"; + size_t len = strlen(user) + sizeof(msg_format); + char *msg = (char *)malloc(len); + if (msg == NULL) { + /* Handle error */ + } + ret = snprintf(msg, len, msg_format, user); + if (ret < 0) { + /* Handle error */ + } else if (ret >= len) { + /* Handle truncated output */ + } + fprintf(stderr, msg); + free(msg); +} + +

    The incorrect_password() function calculates the size of the message, allocates dynamic storage, and then constructs the message in the allocated memory using the snprintf() function. The addition operations are not checked for integer overflow because the string referenced by user is known to have a length of 256 or less. Because the %s characters are replaced by the string referenced by user in the call to snprintf(), the resulting string needs 1 byte less than is allocated. The snprintf() function is commonly used for messages that are displayed in multiple locations or messages that are difficult to build. However, the resulting code contains a format-string vulnerability because the msg includes untrusted user input and is passed as the format-string argument in the call to fprintf().

    +
    +
    +

    This compliant solution fixes the problem by replacing the fprintf() call with a call to fputs(), which outputs msg directly to stderr without evaluating its contents:

    + #include <stdio.h> +#include <stdlib.h> +#include <string.h> + +void incorrect_password(const char *user) { + int ret; + /* User names are restricted to 256 or fewer characters */ + static const char msg_format[] = "%s cannot be authenticated.\n"; + size_t len = strlen(user) + sizeof(msg_format); + char *msg = (char *)malloc(len); + if (msg == NULL) { + /* Handle error */ + } + ret = snprintf(msg, len, msg_format, user); + if (ret < 0) { + /* Handle error */ + } else if (ret >= len) { + /* Handle truncated output */ + } + fputs(msg, stderr); + free(msg); +} + +
    +
    +

    This compliant solution passes the untrusted user input as one of the variadic arguments to fprintf() and not as part of the format string, eliminating the possibility of a format-string vulnerability:

    + #include <stdio.h> + +void incorrect_password(const char *user) { + static const char msg_format[] = "%s cannot be authenticated.\n"; + fprintf(stderr, msg_format, user); +} + +
    +
    +

    This noncompliant code example is similar to the first noncompliant code example but uses the POSIX function syslog() [IEEE Std 1003.1:2013] instead of the fprintf() function. The syslog() function is also susceptible to format-string vulnerabilities.

    + #include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> + +void incorrect_password(const char *user) { + int ret; + /* User names are restricted to 256 or fewer characters */ + static const char msg_format[] = "%s cannot be authenticated.\n"; + size_t len = strlen(user) + sizeof(msg_format); + char *msg = (char *)malloc(len); + if (msg == NULL) { + /* Handle error */ + } + ret = snprintf(msg, len, msg_format, user); + if (ret < 0) { + /* Handle error */ + } else if (ret >= len) { + /* Handle truncated output */ + } + syslog(LOG_INFO, msg); + free(msg); +} + +

    The syslog() function first appeared in BSD 4.2 and is supported by Linux and other modern UNIX implementations. It is not available on Windows systems.

    +
    +
    +

    This compliant solution passes the untrusted user input as one of the variadic arguments to syslog() instead of including it in the format string:

    + #include <syslog.h> + +void incorrect_password(const char *user) { + static const char msg_format[] = "%s cannot be authenticated.\n"; + syslog(LOG_INFO, msg_format, user); +} + +
    +
    +

    Failing to exclude user input from format specifiers may allow an attacker to crash a vulnerable process, view the contents of the stack, view memory content, or write to an arbitrary memory location and consequently execute arbitrary code with the permissions of the vulnerable process.

    + + + + + + + + + + + + + + + + + + + +
    + Rule + + Severity + + Likelihood + + Remediation Cost + + Priority + + Level +
    + FIO30-C + + High + + Likely + + Medium + + P18 + + L1 +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Tool + + Version + + Checker + + Description +
    + + Astrée + + + 20.10 + + + Supported via stubbing/taint analysis +
    + + Axivion Bauhaus Suite + + + 7.2.0 + + CertC-FIO30 + + Partially implemented +
    + + CodeSonar + + + 6.2p0 + + IO.INJ.FMT + MISC.FMT + + Format string injection + Format string +
    + + Compass/ROSE + + + + +
    + + Coverity + + + 2017.07 + + TAINTED_STRING + + Implemented +
    + + GCC + + + 4.3.5 + + + Can detect violations of this rule when the + -Wformat-security + flag is used +
    + + Helix QAC + + + 2021.3 + + C4916, C4917, C4918 + C++4916, C++4917, C++4918 + +
    + + Klocwork + + + 2021.4 + + SV.FMTSTR.GENERIC + SV.TAINTED.FMTSTR + +
    + + LDRA tool suite + + + 9.7.1 + + 86 D + + Partially Implemented +
    + + Parasoft C/C++test + + + 2021.2 + + CERT_C-FIO30-a + CERT_C-FIO30-b + CERT_C-FIO30-c + + Avoid calling functions printf/wprintf with only one argument other than string constant + Avoid using functions fprintf/fwprintf with only two parameters, when second parameter is a variable + Never use unfiltered data from an untrusted user as the format parameter +
    + + PC-lint Plus + + + 1.4 + + 592 + + Partially supported: reports non-literal format strings +
    + + Polyspace Bug Finder + + + R2021a + + + CERT C: Rule FIO30-C + + + Checks for tainted string format (rule partially covered) +
    + + PRQA QA-C + + + 9.7 + + 4916, 4917, 4918 + +
    + + PRQA QA-C++ + + + 4.4 + + 4916, 4917, 4918 + +
    + + PVS-Studio + + + 7.17 + + V618 + +
    + + Splint + + + 3.1.1 + + +
    +
    +
    +

    Two examples of format-string vulnerabilities resulting from a violation of this rule include Ettercap and Samba.

    +

    In Ettercap v.NG-0.7.2, the ncurses user interface suffers from a format-string defect. The curses_msg() function in ec_curses.c calls wdg_scroll_print(), which takes a format string and its parameters and passes it to vw_printw(). The curses_msg() function uses one of its parameters as the format string. This input can include user data, allowing for a format-string vulnerability.

    +

    The Samba AFS ACL mapping VFS plug-in fails to properly sanitize user-controlled file names that are used in a format specifier supplied to snprintf(). This security flaw becomes exploitable when a user can write to a share that uses Samba's afsacl.so library for setting Windows NT access control lists on files residing on an AFS file system.

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    +
    +
    +

    Key here (explains table format and definitions)

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Taxonomy + + Taxonomy item + + Relationship +
    + + CERT Oracle Secure Coding Standard for Java + + + + IDS06-J. Exclude unsanitized user input from format strings + + + Prior to 2018-01-12: CERT: Unspecified Relationship +
    + + CERT Perl Secure Coding Standard + + + + IDS30-PL. Exclude user input from format strings + + + Prior to 2018-01-12: CERT: Unspecified Relationship +
    + + ISO/IEC TR 24772:2013 + + + Injection [RST] + + Prior to 2018-01-12: CERT: Unspecified Relationship +
    + + ISO/IEC TS 17961:2013 + + + Including tainted or out-of-domain input in a format string [usrfmt] + + Prior to 2018-01-12: CERT: Unspecified Relationship +
    + + CWE 2.11 + + + + CWE-134 + + , Uncontrolled Format String + + 2017-05-16: CERT: Exact +
    + + CWE 2.11 + + + + CWE-20 + + , Improper Input Validation + + 2017-05-17: CERT: Rule subset of CWE +
    +
    +
    + + + + + + + + + + + + + + + +
    + [ + + IEEE Std 1003.1:2013 + + ] + + XSH, System Interfaces, + syslog +
    + [ + + Seacord 2013b + + ] + + Chapter 6, "Formatted Output" +
    + [ + + Viega 2005 + + ] + + Section 5.2.23, "Format String Problem" +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO34-C/DistinguishBetweenCharReadFromAFileAndEofOrWeof-standard.qhelp b/c/cert/src/rules/FIO34-C/DistinguishBetweenCharReadFromAFileAndEofOrWeof-standard.qhelp index e822d5cfd4..ea25476294 100644 --- a/c/cert/src/rules/FIO34-C/DistinguishBetweenCharReadFromAFileAndEofOrWeof-standard.qhelp +++ b/c/cert/src/rules/FIO34-C/DistinguishBetweenCharReadFromAFileAndEofOrWeof-standard.qhelp @@ -1,29 +1,547 @@ -
    -
      -
    • required
    • -
    • implementation
    • -
    • automated
    • -
    -
    - -
    -

    - ... -

    - -
    - -
    -

    - ... -

    -
    +
    +

    The EOF macro represents a negative value that is used to indicate that the file is exhausted and no data remains when reading data from a file. EOF is an example of an in-band error indicator. In-band error indicators are problematic to work with, and the creation of new in-band-error indicators is discouraged by ERR02-C. Avoid in-band error indicators.

    +

    The byte I/O functions fgetc(), getc(), and getchar() all read a character from a stream and return it as an int. (See STR00-C. Represent characters using an appropriate type.) If the stream is at the end of the file, the end-of-file indicator for the stream is set and the function returns EOF. If a read error occurs, the error indicator for the stream is set and the function returns EOF. If these functions succeed, they cast the character returned into an unsigned char.

    +

    Because EOF is negative, it should not match any unsigned character value. However, this is only true for implementations where the int type is wider than char. On an implementation where int and char have the same width, a character-reading function can read and return a valid character that has the same bit-pattern as EOF. This could occur, for example, if an attacker inserted a value that looked like EOF into the file or data stream to alter the behavior of the program.

    +

    The C Standard requires only that the int type be able to represent a maximum value of +32767 and that a char type be no larger than an int. Although uncommon, this situation can result in the integer constant expression EOF being indistinguishable from a valid character; that is, (int)(unsigned char)65535 == -1. Consequently, failing to use feof() and ferror() to detect end-of-file and file errors can result in incorrectly identifying the EOF character on rare implementations where sizeof(int) == sizeof(char).

    +

    This problem is much more common when reading wide characters. The fgetwc(), getwc(), and getwchar() functions return a value of type wint_t. This value can represent the next wide character read, or it can represent WEOF, which indicates end-of-file for wide character streams. On most implementations, the wchar_t type has the same width as wint_t, and these functions can return a character indistinguishable from WEOF.

    +

    In the UTF-16 character set, 0xFFFF is guaranteed not to be a character, which allows WEOF to be represented as the value -1. Similarly, all UTF-32 characters are positive when viewed as a signed 32-bit integer. All widely used character sets are designed with at least one value that does not represent a character. Consequently, it would require a custom character set designed without consideration of the C programming language for this problem to occur with wide characters or with ordinary characters that are as wide as int.

    +

    The C Standard feof() and ferror() functions are not subject to the problems associated with character and integer sizes and should be used to verify end-of-file and file errors for susceptible implementations [Kettlewell 2002]. Calling both functions on each iteration of a loop adds significant overhead, so a good strategy is to temporarily trust EOF and WEOF within the loop but verify them with feof() and ferror() following the loop.

    +
    +
    +

    This noncompliant code example loops while the character c is not EOF:

    + #include <stdio.h> + +void func(void) { + int c; + + do { + c = getchar(); + } while (c != EOF); +} + +

    Although EOF is guaranteed to be negative and distinct from the value of any unsigned character, it is not guaranteed to be different from any such value when converted to an int. Consequently, when int has the same width as char, this loop may terminate prematurely.

    +
    +
    +

    This compliant solution uses feof() and ferror() to test whether the EOF was an actual character or a real EOF because of end-of-file or errors:

    + #include <stdio.h> + +void func(void) { + int c; + + do { + c = getchar(); + } while (c != EOF || (!feof(stdin) && !ferror(stdin))); +} + +
    +
    +

    This noncompliant code example uses an assertion to ensure that the code is executed only on architectures where int is wider than char and EOF is guaranteed not to be a valid character value. However, this code example is noncompliant because the variable c is declared as a char rather than an int, making it possible for a valid character value to compare equal to the value of the EOF macro when char is signed because of sign extension:

    + #include <assert.h> +#include <limits.h> +#include <stdio.h> + +void func(void) { + char c; + static_assert(UCHAR_MAX < UINT_MAX, "FIO34-C violation"); + + do { + c = getchar(); + } while (c != EOF); +} + +

    Assuming that a char is a signed 8-bit type and an int is a 32-bit type, if getchar() returns the character value '\xff (decimal 255), it will be interpreted as EOF because this value is sign-extended to 0xFFFFFFFF (the value of EOF) to perform the comparison. (See STR34-C. Cast characters to unsigned char before converting to larger integer sizes.)

    +
    +
    +

    This compliant solution declares c to be an int. Consequently, the loop will terminate only when the file is exhausted.

    + #include <assert.h> +#include <stdio.h> +#include <limits.h> + +void func(void) { + int c; + static_assert(UCHAR_MAX < UINT_MAX, "FIO34-C violation"); + + do { + c = getchar(); + } while (c != EOF); +} + +
    +
    +

    In this noncompliant example, the result of the call to the C standard library function getwc() is stored into a variable of type wchar_t and is subsequently compared with WEOF:

    + #include <stddef.h> +#include <stdio.h> +#include <wchar.h> + +enum { BUFFER_SIZE = 32 }; + +void g(void) { + wchar_t buf[BUFFER_SIZE]; + wchar_t wc; + size_t i = 0; + + while ((wc = getwc(stdin)) != L'\n' && wc != WEOF) { + if (i < (BUFFER_SIZE - 1)) { + buf[i++] = wc; + } + } + buf[i] = L'\0'; +} + +

    This code suffers from two problems. First, the value returned by getwc() is immediately converted to wchar_t before being compared with WEOF. Second, there is no check to ensure that wint_t is wider than wchar_t. Both of these problems make it possible for an attacker to terminate the loop prematurely by supplying the wide-character value matching WEOF in the file.

    +
    +
    +

    This compliant solution declares c to be a wint_t to match the integer type returned by getwc(). Furthermore, it does not rely on WEOF to determine end-of-file definitively.

    + #include <stddef.h> +#include <stdio.h> +#include <wchar.h> + +enum {BUFFER_SIZE = 32 } + +void g(void) { + wchar_t buf[BUFFER_SIZE]; + wint_t wc; + size_t i = 0; -
    -
      -
    • ...
    • -
    -
    + while ((wc = getwc(stdin)) != L'\n' && wc != WEOF) { + if (i < BUFFER_SIZE - 1) { + buf[i++] = wc; + } + } + + if (feof(stdin) || ferror(stdin)) { + buf[i] = L'\0'; + } else { + /* Received a wide character that resembles WEOF; handle error */ + } +} +
    +
    +
    +

    FIO34-C-EX1: A number of C functions do not return characters but can return EOF as a status code. These functions include fclose(), fflush(), fputs(), fscanf(), puts(), scanf(), sscanf(), vfscanf(), and vscanf(). These return values can be compared to EOF without validating the result.

    +
    +
    +

    Incorrectly assuming characters from a file cannot match EOF or WEOF has resulted in significant vulnerabilities, including command injection attacks. (See the *CA-1996-22 advisory.)

    + + + + + + + + + + + + + + + + + + + +
    + Rule + + Severity + + Likelihood + + Remediation Cost + + Priority + + Level +
    + FIO34-C + + High + + Probable + + Medium + + P12 + + L1 +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Tool + + Version + + Checker + + Description +
    + + Axivion Bauhaus Suite + + + 7.2.0 + + CertC-FIO34 + +
    + + CodeSonar + + + 6.2p0 + + LANG.CAST.COERCE + + Coercion alters value +
    + + Compass/ROSE + + + + +
    + + Coverity + + + 2017.07 + + CHAR_IO + + Identifies defects when the return value of + fgetc() + , + getc() + , or + getchar() + is incorrectly assigned to a + char + instead of an + int + . Coverity Prevent cannot discover all violations of this rule, so further verification is necessary +
    + + ECLAIR + + + 1.2 + + CC2.FIO34 + + Partially implemented +
    + + Helix QAC + + + 2021.3 + + C2676, C2678 + C++2676, C++2678, C++3001, C++3010, C++3051, C++3137, C++3717 + +
    + + Klocwork + + + 2021.4 + + CWARN.CMPCHR.EOF + +
    + + LDRA tool suite + + + 9.7.1 + + 662 S + + Fully implemented +
    + + Parasoft C/C++test + + + 2021.2 + + CERT_C-FIO34-a + + The macro EOF should be compared with the unmodified return value from the Standard Library function +
    + + Polyspace Bug Finder + + + R2021a + + + CERT C: Rule FIO34-C + + + Checks for character values absorbed into EOF (rule partially covered) +
    + + PRQA QA-C + + + 9.7 + + 2676, 2678 + +
    + + PRQA QA-C++ + + + 4.4 + + 2676, 2678, 3001, 3010, 3051, 3137, 3717 + +
    + + Splint + + + 3.1.1 + + +
    +
    +
    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    +
    +
    +

    Key here (explains table format and definitions)

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Taxonomy + + Taxonomy item + + Relationship +
    + + CERT C Secure Coding Standard + + + + STR00-C. Represent characters using an appropriate type + + + Prior to 2018-01-12: CERT: Unspecified Relationship +
    + + CERT C Secure Coding Standard + + + + INT31-C. Ensure that integer conversions do not result in lost or misinterpreted data + + + Prior to 2018-01-12: CERT: Unspecified Relationship +
    + + CERT Oracle Secure Coding Standard for Java + + + + FIO08-J. Use an int to capture the return value of methods that read a character or byte + + + Prior to 2018-01-12: CERT: Unspecified Relationship +
    + + ISO/IEC TS 17961:2013 + + + Using character values that are indistinguishable from EOF [chreof] + + Prior to 2018-01-12: CERT: Unspecified Relationship +
    + + CWE 2.11 + + + + CWE-197 + + + 2017-06-14: CERT: Rule subset of CWE +
    +
    +
    +

    Key here for mapping notes

    +

    CWE-197 and FIO34-C

    +

    Independent( FLP34-C, INT31-C) FIO34-C = Subset( INT31-C)

    +

    Therefore: FIO34-C = Subset( CWE-197)

    +
    +
    + + + + + + + + + + + + + + + +
    + [ + + Kettlewell 2002 + + ] + + Section 1.2, "< + stdio.h + > and Character Types" +
    + [ + + NIST 2006 + + ] + + SAMATE Reference Dataset Test Case ID 000-000-088 +
    + [ + + Summit 2005 + + ] + + Question 12.2 +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO34-C/EndOfFileCheckPortability-standard.qhelp b/c/cert/src/rules/FIO34-C/EndOfFileCheckPortability-standard.qhelp index e822d5cfd4..ea25476294 100644 --- a/c/cert/src/rules/FIO34-C/EndOfFileCheckPortability-standard.qhelp +++ b/c/cert/src/rules/FIO34-C/EndOfFileCheckPortability-standard.qhelp @@ -1,29 +1,547 @@ -
    -
      -
    • required
    • -
    • implementation
    • -
    • automated
    • -
    -
    - -
    -

    - ... -

    - -
    - -
    -

    - ... -

    -
    +
    +

    The EOF macro represents a negative value that is used to indicate that the file is exhausted and no data remains when reading data from a file. EOF is an example of an in-band error indicator. In-band error indicators are problematic to work with, and the creation of new in-band-error indicators is discouraged by ERR02-C. Avoid in-band error indicators.

    +

    The byte I/O functions fgetc(), getc(), and getchar() all read a character from a stream and return it as an int. (See STR00-C. Represent characters using an appropriate type.) If the stream is at the end of the file, the end-of-file indicator for the stream is set and the function returns EOF. If a read error occurs, the error indicator for the stream is set and the function returns EOF. If these functions succeed, they cast the character returned into an unsigned char.

    +

    Because EOF is negative, it should not match any unsigned character value. However, this is only true for implementations where the int type is wider than char. On an implementation where int and char have the same width, a character-reading function can read and return a valid character that has the same bit-pattern as EOF. This could occur, for example, if an attacker inserted a value that looked like EOF into the file or data stream to alter the behavior of the program.

    +

    The C Standard requires only that the int type be able to represent a maximum value of +32767 and that a char type be no larger than an int. Although uncommon, this situation can result in the integer constant expression EOF being indistinguishable from a valid character; that is, (int)(unsigned char)65535 == -1. Consequently, failing to use feof() and ferror() to detect end-of-file and file errors can result in incorrectly identifying the EOF character on rare implementations where sizeof(int) == sizeof(char).

    +

    This problem is much more common when reading wide characters. The fgetwc(), getwc(), and getwchar() functions return a value of type wint_t. This value can represent the next wide character read, or it can represent WEOF, which indicates end-of-file for wide character streams. On most implementations, the wchar_t type has the same width as wint_t, and these functions can return a character indistinguishable from WEOF.

    +

    In the UTF-16 character set, 0xFFFF is guaranteed not to be a character, which allows WEOF to be represented as the value -1. Similarly, all UTF-32 characters are positive when viewed as a signed 32-bit integer. All widely used character sets are designed with at least one value that does not represent a character. Consequently, it would require a custom character set designed without consideration of the C programming language for this problem to occur with wide characters or with ordinary characters that are as wide as int.

    +

    The C Standard feof() and ferror() functions are not subject to the problems associated with character and integer sizes and should be used to verify end-of-file and file errors for susceptible implementations [Kettlewell 2002]. Calling both functions on each iteration of a loop adds significant overhead, so a good strategy is to temporarily trust EOF and WEOF within the loop but verify them with feof() and ferror() following the loop.

    +
    +
    +

    This noncompliant code example loops while the character c is not EOF:

    + #include <stdio.h> + +void func(void) { + int c; + + do { + c = getchar(); + } while (c != EOF); +} + +

    Although EOF is guaranteed to be negative and distinct from the value of any unsigned character, it is not guaranteed to be different from any such value when converted to an int. Consequently, when int has the same width as char, this loop may terminate prematurely.

    +
    +
    +

    This compliant solution uses feof() and ferror() to test whether the EOF was an actual character or a real EOF because of end-of-file or errors:

    + #include <stdio.h> + +void func(void) { + int c; + + do { + c = getchar(); + } while (c != EOF || (!feof(stdin) && !ferror(stdin))); +} + +
    +
    +

    This noncompliant code example uses an assertion to ensure that the code is executed only on architectures where int is wider than char and EOF is guaranteed not to be a valid character value. However, this code example is noncompliant because the variable c is declared as a char rather than an int, making it possible for a valid character value to compare equal to the value of the EOF macro when char is signed because of sign extension:

    + #include <assert.h> +#include <limits.h> +#include <stdio.h> + +void func(void) { + char c; + static_assert(UCHAR_MAX < UINT_MAX, "FIO34-C violation"); + + do { + c = getchar(); + } while (c != EOF); +} + +

    Assuming that a char is a signed 8-bit type and an int is a 32-bit type, if getchar() returns the character value '\xff (decimal 255), it will be interpreted as EOF because this value is sign-extended to 0xFFFFFFFF (the value of EOF) to perform the comparison. (See STR34-C. Cast characters to unsigned char before converting to larger integer sizes.)

    +
    +
    +

    This compliant solution declares c to be an int. Consequently, the loop will terminate only when the file is exhausted.

    + #include <assert.h> +#include <stdio.h> +#include <limits.h> + +void func(void) { + int c; + static_assert(UCHAR_MAX < UINT_MAX, "FIO34-C violation"); + + do { + c = getchar(); + } while (c != EOF); +} + +
    +
    +

    In this noncompliant example, the result of the call to the C standard library function getwc() is stored into a variable of type wchar_t and is subsequently compared with WEOF:

    + #include <stddef.h> +#include <stdio.h> +#include <wchar.h> + +enum { BUFFER_SIZE = 32 }; + +void g(void) { + wchar_t buf[BUFFER_SIZE]; + wchar_t wc; + size_t i = 0; + + while ((wc = getwc(stdin)) != L'\n' && wc != WEOF) { + if (i < (BUFFER_SIZE - 1)) { + buf[i++] = wc; + } + } + buf[i] = L'\0'; +} + +

    This code suffers from two problems. First, the value returned by getwc() is immediately converted to wchar_t before being compared with WEOF. Second, there is no check to ensure that wint_t is wider than wchar_t. Both of these problems make it possible for an attacker to terminate the loop prematurely by supplying the wide-character value matching WEOF in the file.

    +
    +
    +

    This compliant solution declares c to be a wint_t to match the integer type returned by getwc(). Furthermore, it does not rely on WEOF to determine end-of-file definitively.

    + #include <stddef.h> +#include <stdio.h> +#include <wchar.h> + +enum {BUFFER_SIZE = 32 } + +void g(void) { + wchar_t buf[BUFFER_SIZE]; + wint_t wc; + size_t i = 0; -
    -
      -
    • ...
    • -
    -
    + while ((wc = getwc(stdin)) != L'\n' && wc != WEOF) { + if (i < BUFFER_SIZE - 1) { + buf[i++] = wc; + } + } + + if (feof(stdin) || ferror(stdin)) { + buf[i] = L'\0'; + } else { + /* Received a wide character that resembles WEOF; handle error */ + } +} +
    +
    +
    +

    FIO34-C-EX1: A number of C functions do not return characters but can return EOF as a status code. These functions include fclose(), fflush(), fputs(), fscanf(), puts(), scanf(), sscanf(), vfscanf(), and vscanf(). These return values can be compared to EOF without validating the result.

    +
    +
    +

    Incorrectly assuming characters from a file cannot match EOF or WEOF has resulted in significant vulnerabilities, including command injection attacks. (See the *CA-1996-22 advisory.)

    + + + + + + + + + + + + + + + + + + + +
    + Rule + + Severity + + Likelihood + + Remediation Cost + + Priority + + Level +
    + FIO34-C + + High + + Probable + + Medium + + P12 + + L1 +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Tool + + Version + + Checker + + Description +
    + + Axivion Bauhaus Suite + + + 7.2.0 + + CertC-FIO34 + +
    + + CodeSonar + + + 6.2p0 + + LANG.CAST.COERCE + + Coercion alters value +
    + + Compass/ROSE + + + + +
    + + Coverity + + + 2017.07 + + CHAR_IO + + Identifies defects when the return value of + fgetc() + , + getc() + , or + getchar() + is incorrectly assigned to a + char + instead of an + int + . Coverity Prevent cannot discover all violations of this rule, so further verification is necessary +
    + + ECLAIR + + + 1.2 + + CC2.FIO34 + + Partially implemented +
    + + Helix QAC + + + 2021.3 + + C2676, C2678 + C++2676, C++2678, C++3001, C++3010, C++3051, C++3137, C++3717 + +
    + + Klocwork + + + 2021.4 + + CWARN.CMPCHR.EOF + +
    + + LDRA tool suite + + + 9.7.1 + + 662 S + + Fully implemented +
    + + Parasoft C/C++test + + + 2021.2 + + CERT_C-FIO34-a + + The macro EOF should be compared with the unmodified return value from the Standard Library function +
    + + Polyspace Bug Finder + + + R2021a + + + CERT C: Rule FIO34-C + + + Checks for character values absorbed into EOF (rule partially covered) +
    + + PRQA QA-C + + + 9.7 + + 2676, 2678 + +
    + + PRQA QA-C++ + + + 4.4 + + 2676, 2678, 3001, 3010, 3051, 3137, 3717 + +
    + + Splint + + + 3.1.1 + + +
    +
    +
    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    +
    +
    +

    Key here (explains table format and definitions)

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Taxonomy + + Taxonomy item + + Relationship +
    + + CERT C Secure Coding Standard + + + + STR00-C. Represent characters using an appropriate type + + + Prior to 2018-01-12: CERT: Unspecified Relationship +
    + + CERT C Secure Coding Standard + + + + INT31-C. Ensure that integer conversions do not result in lost or misinterpreted data + + + Prior to 2018-01-12: CERT: Unspecified Relationship +
    + + CERT Oracle Secure Coding Standard for Java + + + + FIO08-J. Use an int to capture the return value of methods that read a character or byte + + + Prior to 2018-01-12: CERT: Unspecified Relationship +
    + + ISO/IEC TS 17961:2013 + + + Using character values that are indistinguishable from EOF [chreof] + + Prior to 2018-01-12: CERT: Unspecified Relationship +
    + + CWE 2.11 + + + + CWE-197 + + + 2017-06-14: CERT: Rule subset of CWE +
    +
    +
    +

    Key here for mapping notes

    +

    CWE-197 and FIO34-C

    +

    Independent( FLP34-C, INT31-C) FIO34-C = Subset( INT31-C)

    +

    Therefore: FIO34-C = Subset( CWE-197)

    +
    +
    + + + + + + + + + + + + + + + +
    + [ + + Kettlewell 2002 + + ] + + Section 1.2, "< + stdio.h + > and Character Types" +
    + [ + + NIST 2006 + + ] + + SAMATE Reference Dataset Test Case ID 000-000-088 +
    + [ + + Summit 2005 + + ] + + Question 12.2 +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO38-C/DoNotCopyAFileObject-implementation.qhelp b/c/cert/src/rules/FIO38-C/DoNotCopyAFileObject-implementation.qhelp new file mode 100644 index 0000000000..a01fab8d10 --- /dev/null +++ b/c/cert/src/rules/FIO38-C/DoNotCopyAFileObject-implementation.qhelp @@ -0,0 +1,8 @@ + + + +

    None

    +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO38-C/DoNotCopyAFileObject-standard.qhelp b/c/cert/src/rules/FIO38-C/DoNotCopyAFileObject-standard.qhelp new file mode 100644 index 0000000000..64fabbc606 --- /dev/null +++ b/c/cert/src/rules/FIO38-C/DoNotCopyAFileObject-standard.qhelp @@ -0,0 +1,368 @@ + + +
    +

    According to the C Standard, 7.21.3, paragraph 6 [ISO/IEC 9899:2011],

    +
    +

    The address of the FILE object used to control a stream may be significant; a copy of a FILE object need not serve in place of the original.

    +
    +

    Consequently, do not copy a FILE object.

    +
    +
    +

    This noncompliant code example can fail because a by-value copy of stdout is being used in the call to fputs():

    + #include <stdio.h> + +int main(void) { + FILE my_stdout = *stdout; + if (fputs("Hello, World!\n", &my_stdout) == EOF) { + /* Handle error */ + } + return 0; +} + +

    When compiled under Microsoft Visual Studio 2013 and run on Windows, this noncompliant example results in an "access violation" at runtime.

    +
    +
    +

    In this compliant solution, a copy of the stdout pointer to the FILE object is used in the call to fputs():

    + #include <stdio.h> + +int main(void) { + FILE *my_stdout = stdout; + if (fputs("Hello, World!\n", my_stdout) == EOF) { + /* Handle error */ + } + return 0; +} + +
    +
    +

    Using a copy of a FILE object in place of the original may result in a crash, which can be used in a denial-of-service attack.

    + + + + + + + + + + + + + + + + + + + +
    + Rule + + Severity + + Likelihood + + Remediation Cost + + Priority + + Level +
    + FIO38-C + + Low + + Probable + + Medium + + P4 + + L3 +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Tool + + Version + + Checker + + Description +
    + + Astrée + + + 20.10 + + file-dereference + + Partially checked +
    + + Axivion Bauhaus Suite + + + 7.2.0 + + CertC-FIO38 + + Fully implemented +
    + + Clang + + + 3.9 + + misc-non-copyable-objects + + Checked with + clang-tidy +
    + + Compass/ROSE + + + + + Can detect simple violations of this rule +
    + + Coverity + + + 2017.07 + + MISRA C 2012 Rule 22.5 + + Partially implemented +
    + + Helix QAC + + + 2021.3 + + C1485, C5028 + C++3113, C++3114 + +
    + + Klocwork + + + 2021.4 + + MISRA.FILE_PTR.DEREF.2012 + MISRA.FILE_PTR.DEREF.CAST.2012 + MISRA.FILE_PTR.DEREF.INDIRECT.2012 + MISRA.FILE_PTR.DEREF.RETURN.2012 + +
    + + LDRA tool suite + + + 9.7.1 + + 591 S + + Fully implemented +
    + + Parasoft C/C++test + + + 2021.2 + + CERT_C-FIO38-a + + A pointer to a FILE object shall not be dereferenced +
    + + PC-lint Plus + + + 1.4 + + 9047 + + Partially supported: reports when a FILE pointer is dereferenced +
    + + Polyspace Bug Finder + + + R2021a + + + CERT C: Rule FIO38-C + + + Checks for misuse of a FILE object (rule fully covered) +
    + + PRQA QA-C + + + 9.7 + + 1485, 5028 + +
    + + RuleChecker + + + 20.10 + + file-dereference + + Partially checked +
    +
    +
    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    +
    +
    +

    Key here (explains table format and definitions)

    + + + + + + + + + + + + + +
    + Taxonomy + + Taxonomy item + + Relationship +
    + + ISO/IEC TS 17961:2013 + + + Copying a + FILE + object [filecpy] + + Prior to 2018-01-12: CERT: Unspecified Relationship +
    +
    +
    + + + + + + + +
    + [ + + ISO/IEC 9899:2011 + + ] + + 7.21.3, "Files" +
    +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO38-C/DoNotCopyAFileObject.qhelp b/c/cert/src/rules/FIO38-C/DoNotCopyAFileObject.qhelp new file mode 100644 index 0000000000..c9cb5b93ee --- /dev/null +++ b/c/cert/src/rules/FIO38-C/DoNotCopyAFileObject.qhelp @@ -0,0 +1,21 @@ + + + + +

    This query implements the CERT-C rule FIO38-C:

    +
    +

    Do not copy a FILE object

    +
    +
    + +
    + +
    + +
  • + CERT-C: + FIO38-C: Do not copy a FILE object + . +
  • +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO38-C/DoNotCopyAFileObject.ql b/c/cert/src/rules/FIO38-C/DoNotCopyAFileObject.ql new file mode 100644 index 0000000000..e8e897009e --- /dev/null +++ b/c/cert/src/rules/FIO38-C/DoNotCopyAFileObject.ql @@ -0,0 +1,32 @@ +/** + * @id c/cert/do-not-copy-a-file-object + * @name FIO38-C: Do not copy a FILE object + * @description Using a copy of a FILE object may result in program failure. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/cert/id/fio38-c + * correctness + * security + * external/cert/obligation/rule + */ + +import cpp +import codingstandards.c.cert + +/** + * An object being copied as part of an Initialization, Assignment or Function Call + */ +class CopiedObject extends Expr { + CopiedObject() { + this = any(Initializer i).getExpr() or + this = any(Assignment a).getRValue() or + this = any(FunctionCall fc).getAnArgument() + } +} + +from CopiedObject o +where + not isExcluded(o, IO2Package::doNotCopyAFileObjectQuery()) and + o.getType().hasName("FILE") +select o, "A FILE object is being copied." diff --git a/c/cert/src/rules/FIO39-C/DoNotAlternatelyIOFromAStreamWithoutPositioning-standard.qhelp b/c/cert/src/rules/FIO39-C/DoNotAlternatelyIOFromAStreamWithoutPositioning-standard.qhelp index 99ace9f40b..b4bf574812 100644 --- a/c/cert/src/rules/FIO39-C/DoNotAlternatelyIOFromAStreamWithoutPositioning-standard.qhelp +++ b/c/cert/src/rules/FIO39-C/DoNotAlternatelyIOFromAStreamWithoutPositioning-standard.qhelp @@ -1,29 +1,384 @@ -
    -
      -
    • required
    • -
    • implementation
    • -
    • automated
    • -
    -
    - -
    -

    - ... -

    - -
    - -
    -

    - ... -

    -
    - -
    -
      -
    • ...
    • -
    -
    +
    +

    The C Standard, 7.21.5.3, paragraph 7 [ISO/IEC 9899:2011], places the following restrictions on update streams:

    +
    +

    When a file is opened with update mode . . ., both input and output may be performed on the associated stream. However, output shall not be directly followed by input without an intervening call to the fflush function or to a file positioning function (fseek, fsetpos, or rewind), and input shall not be directly followed by output without an intervening call to a file positioning function, unless the input operation encounters end-of-file. Opening (or creating) a text file with update mode may instead open (or create) a binary stream in some implementations.

    +
    +

    The following scenarios can result in undefined behavior. (See undefined behavior 151.)

    +
      +
    • Receiving input from a stream directly following an output to that stream without an intervening call to fflush(), fseek(), fsetpos(), or rewind() if the file is not at end-of-file
    • +
    • Outputting to a stream after receiving input from that stream without a call to fseek(), fsetpos(), or rewind() if the file is not at end-of-file
    • +
    +

    Consequently, a call to fseek(), fflush(), or fsetpos() is necessary between input and output to the same stream. See ERR07-C. Prefer functions that support error checking over equivalent functions that don't for more information on why fseek() is preferred over rewind().

    +
    +
    +

    This noncompliant code example appends data to a file and then reads from the same file:

    + #include <stdio.h> + +enum { BUFFERSIZE = 32 }; + +extern void initialize_data(char *data, size_t size); + +void func(const char *file_name) { + char data[BUFFERSIZE]; + char append_data[BUFFERSIZE]; + FILE *file; + + file = fopen(file_name, "a+"); + if (file == NULL) { + /* Handle error */ + } + + initialize_data(append_data, BUFFERSIZE); + + if (fwrite(append_data, 1, BUFFERSIZE, file) != BUFFERSIZE) { + /* Handle error */ + } + if (fread(data, 1, BUFFERSIZE, file) < BUFFERSIZE) { + /* Handle there not being data */ + } + + if (fclose(file) == EOF) { + /* Handle error */ + } +} +

    Because there is no intervening flush or positioning call between the calls to fread() and fwrite(), the behavior is undefined.

    +
    +
    +

    In this compliant solution, fseek() is called between the output and input, eliminating the undefined behavior:

    + #include <stdio.h> + +enum { BUFFERSIZE = 32 }; +extern void initialize_data(char *data, size_t size); + +void func(const char *file_name) { + char data[BUFFERSIZE]; + char append_data[BUFFERSIZE]; + FILE *file; + + file = fopen(file_name, "a+"); + if (file == NULL) { + /* Handle error */ + } + + initialize_data(append_data, BUFFERSIZE); + if (fwrite(append_data, BUFFERSIZE, 1, file) != BUFFERSIZE) { + /* Handle error */ + } + + if (fseek(file, 0L, SEEK_SET) != 0) { + /* Handle error */ + } + + if (fread(data, BUFFERSIZE, 1, file) != 0) { + /* Handle there not being data */ + } + + if (fclose(file) == EOF) { + /* Handle error */ + } +} +
    +
    +

    Alternately inputting and outputting from a stream without an intervening flush or positioning call is undefined behavior.

    + + + + + + + + + + + + + + + + + + + +
    + Rule + + Severity + + Likelihood + + Remediation Cost + + Priority + + Level +
    + FIO39-C + + Low + + Likely + + Medium + + P6 + + L2 +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Tool + + Version + + Checker + + Description +
    + + Astrée + + + 20.10 + + + Supported, but no explicit checker +
    + + Axivion Bauhaus Suite + + + 7.2.0 + + CertC-FIO39 + +
    + + Compass/ROSE + + + + + Can detect simple violations of this rule +
    + + Helix QAC + + + 2021.3 + + C4711, C4712, C4713 + C++4711, C++4712, C++4713 + +
    + + LDRA tool suite + + + 9.7.1 + + 84 D + + Fully implemented +
    + + Parasoft C/C++test + + + 2021.2 + + CERT_C-FIO39-a + + Do not alternately input and output from a stream without an intervening flush or positioning call +
    + + PC-lint Plus + + + 1.4 + + 2478, 2479 + + Fully supported +
    + + Polyspace Bug Finder + + + R2021a + + + CERT C: Rule FIO39-C + + + Checks for alternating input and output from a stream without flush or positioning call (rule fully covered) +
    + + PRQA QA-C + + + 9.7 + + 5029 + +
    +
    +
    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    +
    +
    +

    Key here (explains table format and definitions)

    + + + + + + + + + + + + + + + + + + + + + + + +
    + Taxonomy + + Taxonomy item + + Relationship +
    + + CERT C + + + + FIO50-CPP. Do not alternately input and output from a file stream without an intervening positioning call + + + Prior to 2018-01-12: CERT: Unspecified Relationship +
    + + ISO/IEC TS 17961:2013 + + + Interleaving stream inputs and outputs without a flush or positioning call [ioileave] + + Prior to 2018-01-12: CERT: Unspecified Relationship +
    + + CWE 2.11 + + + + CWE-664 + + + 2017-07-10: CERT: Rule subset of CWE +
    +
    +
    +

    Key here for mapping notes

    +

    CWE-664 and FIO39-C

    +

    CWE-664 = Union( FIO39-C, list) where list =

    +
      +
    • Improper use of an object (besides alternating reading/writing a file stream without an intervening flush
    • +
    +

    This CWE is vague on what constitutes “improper control of a resource”. It could include any violation of an object’s method constraints (whether they are documented or not). Or it could be narrowly interpreted to mean object creation and object destruction (which are covered by other CWEs).

    +
    +
    + + + + + + + +
    + [ + + ISO/IEC 9899:2011 + + ] + + 7.21.5.3, "The + fopen + Function" +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure-implementation.qhelp b/c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure-implementation.qhelp new file mode 100644 index 0000000000..a01fab8d10 --- /dev/null +++ b/c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure-implementation.qhelp @@ -0,0 +1,8 @@ + + + +

    None

    +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure-standard.qhelp b/c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure-standard.qhelp new file mode 100644 index 0000000000..85898e6966 --- /dev/null +++ b/c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure-standard.qhelp @@ -0,0 +1,219 @@ + + +
    +

    If either of the C Standard fgets() or fgetws() functions fail, the contents of the array being written is indeterminate. (See undefined behavior 170.) It is necessary to reset the string to a known value to avoid errors on subsequent string manipulation functions.

    +
    +
    +

    In this noncompliant code example, an error flag is set if fgets() fails. However, buf is not reset and has indeterminate contents:

    + #include <stdio.h> + +enum { BUFFER_SIZE = 1024 }; +void func(FILE *file) { + char buf[BUFFER_SIZE]; + + if (fgets(buf, sizeof(buf), file) == NULL) { + /* Set error flag and continue */ + } +} +
    +
    +

    In this compliant solution, buf is set to an empty string if fgets() fails. The equivalent solution for fgetws() would set buf to an empty wide string.

    + #include <stdio.h> + +enum { BUFFER_SIZE = 1024 }; + +void func(FILE *file) { + char buf[BUFFER_SIZE]; + + if (fgets(buf, sizeof(buf), file) == NULL) { + /* Set error flag and continue */ + *buf = '\0'; + } +} +
    +
    +

    FIO40-C-EX1: If the string goes out of scope immediately following the call to fgets() or fgetws() or is not referenced in the case of a failure, it need not be reset.

    +
    +
    +

    Making invalid assumptions about the contents of an array modified by fgets() or fgetws() can result in undefined behavior and abnormal program termination.

    + + + + + + + + + + + + + + + + + + + +
    + Rule + + Severity + + Likelihood + + Remediation Cost + + Priority + + Level +
    + FIO40-C + + Low + + Probable + + Medium + + P4 + + L3 +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Tool + + Version + + Checker + + Description +
    + + CodeSonar + + + 6.2p0 + + LANG.MEM.UVAR + + Uninitialized Variable +
    + + Helix QAC + + + 2021.3 + + C4861, C4862, C4863 + C++4861, C++4862, C++4863 + +
    + + LDRA tool suite + + + 9.7.1 + + 44 S + + Enhanced enforcement +
    + + Parasoft C/C++test + + + 2021.2 + + CERT_C-FIO40-a + + Reset strings on fgets() or fgetws() failure +
    + + Polyspace Bug Finder + + + R2021a + + + CERT C: Rule FIO40-C + + + Checks for use of indeterminate string (rule partially covered) +
    + + PRQA QA-C++ + + + 4.4 + + 2956 + +
    + + PVS-Studio + + + 7.17 + + V1024 + +
    +
    +
    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.qhelp b/c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.qhelp new file mode 100644 index 0000000000..d2b9fa3373 --- /dev/null +++ b/c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.qhelp @@ -0,0 +1,21 @@ + + + + +

    This query implements the CERT-C rule FIO40-C:

    +
    +

    Reset strings on fgets() or fgetws() failure

    +
    +
    + +
    + +
    + +
  • + CERT-C: + FIO40-C: Reset strings on fgets() or fgetws() failure + . +
  • +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.ql b/c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.ql new file mode 100644 index 0000000000..30432797ad --- /dev/null +++ b/c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.ql @@ -0,0 +1,114 @@ +/** + * @id c/cert/reset-strings-on-fgets-or-fgetws-failure + * @name FIO40-C: Reset strings on fgets() or fgetws() failure + * @description A string that used in a failing call to fgets() or fgetws() requires a reset before + * being referenced. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/cert/id/fio40-c + * correctness + * security + * external/cert/obligation/rule + */ + +import cpp +import codingstandards.cpp.FgetsErrorManagement +import codingstandards.cpp.Dereferenced +import codingstandards.c.cert + +/* + * Models calls to `memcpy` `strcpy` `strncpy` and their wrappers + */ + +class MemcpyLikeCall extends FunctionCall { + Expr destination; + + MemcpyLikeCall() { + exists(string names | + names = ["memcpy", "memcpy_s", "strcpy", "strcpy_s", "strncpy", "strncpy_s"] and + ( + this.getTarget().hasGlobalName(names) + or + exists(MacroInvocation mi | mi.getMacroName() = names and this = mi.getExpr()) + ) and + ( + destination = this.getArgument(0) + or + exists(MemcpyLikeCall internalCall, int destination_pos | + internalCall.getEnclosingFunction() = this.getTarget() and + // Map destination argument + destination = this.getArgument(destination_pos) and + DataFlow::localFlow(DataFlow::parameterNode(this.getTarget().getParameter(destination_pos)), + DataFlow::exprNode(internalCall.getDestination())) + ) + ) + ) + } + + Expr getDestination() { result = destination } +} + +/* + * Models accesses to the buffer by dereferencing the associated expression + */ + +class BuffAccessExpr extends Expr { + BuffAccessExpr() { + // dereferenced expressions + this instanceof DereferencedExpr + or + // any array access `array[0]` + this = any(ArrayExpr ae).getArrayBase() + or + // any parameter to a function + this = any(FunctionCall fc).getAnArgument() + } +} + +/* + * Models buffer reset by means of overwriting + */ + +class BuffReset extends Expr { + BuffReset() { + // *buf = '' + this = any(Assignment a).getLValue().(PointerDereferenceExpr).getOperand() + or + // buf[0] = '' + this = any(Assignment a).getLValue().(ArrayExpr).getArrayBase() + or + // FgetsLikeCall + this = any(FgetsLikeCall fgets).getBuffer() + or + // MemcpyLikeCall + this = any(MemcpyLikeCall a).getDestination() + } +} + +/* + * CFG nodes that follows a failing call to `fgets` + */ + +ControlFlowNode followsNullFgets(FgetsLikeCall fgets) { + exists(FgetsGuard guard | + fgets = guard.getFgetCall() and + //Stop recursion on buffer reset + not exists(Variable v | + v.getAnAccess() = fgets.getBuffer() and v.getAnAccess() = result.(BuffReset) + ) and + ( + result = guard.getNullSuccessor() + or + result = followsNullFgets(fgets).getASuccessor() + ) + ) +} + +from BuffAccessExpr e, FgetsLikeCall fgets +where + not isExcluded(e, IO2Package::resetStringsOnFgetsOrFgetwsFailureQuery()) and + e = followsNullFgets(fgets) and + exists(Variable v | v.getAnAccess() = fgets.getBuffer() and v.getAnAccess() = e) +select e, "The buffer is not reset before being referenced following a failed $@.", fgets, + fgets.toString() diff --git a/c/cert/src/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects-implementation.qhelp b/c/cert/src/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects-implementation.qhelp new file mode 100644 index 0000000000..a01fab8d10 --- /dev/null +++ b/c/cert/src/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects-implementation.qhelp @@ -0,0 +1,8 @@ + + + +

    None

    +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects-standard.qhelp b/c/cert/src/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects-standard.qhelp new file mode 100644 index 0000000000..12049ae1c2 --- /dev/null +++ b/c/cert/src/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects-standard.qhelp @@ -0,0 +1,363 @@ + + +
    +

    Do not invoke getc() or putc() or their wide-character analogues getwc() and putwc() with a stream argument that has side effects. The stream argument passed to these macros may be evaluated more than once if these functions are implemented as unsafe macros. (See PRE31-C. Avoid side effects in arguments to unsafe macros for more information.)

    +

    This rule does not apply to the character argument in putc() or the wide-character argument in putwc(), which is guaranteed to be evaluated exactly once.

    +
    +
    +

    This noncompliant code example calls the getc() function with an expression as the stream argument. If getc() is implemented as a macro, the file may be opened multiple times. (See FIO24-C. Do not open a file that is already open.)

    + #include <stdio.h> + +void func(const char *file_name) { + FILE *fptr; + + int c = getc(fptr = fopen(file_name, "r")); + if (feof(fptr) || ferror(fptr)) { + /* Handle error */ + } + + if (fclose(fptr) == EOF) { + /* Handle error */ + } +} +

    This noncompliant code example also violates ERR33-C. Detect and handle standard library errors because the value returned by fopen() is not checked for errors.

    +
    +
    +

    In this compliant solution, fopen() is called before getc() and its return value is checked for errors:

    + #include <stdio.h> + +void func(const char *file_name) { + int c; + FILE *fptr; + + fptr = fopen(file_name, "r"); + if (fptr == NULL) { + /* Handle error */ + } + + c = getc(fptr); + if (c == EOF) { + /* Handle error */ + } + + if (fclose(fptr) == EOF) { + /* Handle error */ + } +} +
    +
    +

    In this noncompliant example, putc() is called with an expression as the stream argument. If putc() is implemented as a macro, this expression might be evaluated multiple times.

    + #include <stdio.h> + +void func(const char *file_name) { + FILE *fptr = NULL; + int c = 'a'; + + while (c <= 'z') { + if (putc(c++, fptr ? fptr : + (fptr = fopen(file_name, "w"))) == EOF) { + /* Handle error */ + } + } + + if (fclose(fptr) == EOF) { + /* Handle error */ + } +} +

    This noncompliant code example might appear safe even if the putc() macro evaluates its stream argument multiple times, as the ternary conditional expression ostensibly prevents multiple calls to fopen(). However, the assignment to fptr and the evaluation of fptr as the controlling expression of the ternary conditional expression can take place between the same sequence points, resulting in undefined behavior (a violation of EXP30-C. Do not depend on the order of evaluation for side effects). This code also violates ERR33-C. Detect and handle standard library errors because it fails to check the return value from fopen().

    +
    +
    +

    In this compliant solution, the stream argument to putc() no longer has side effects:

    + #include <stdio.h> + +void func(const char *file_name) { + int c = 'a'; + FILE *fptr = fopen(file_name, "w"); + + if (fptr == NULL) { + /* Handle error */ + } + + while (c <= 'z') { + if (putc(c++, fptr) == EOF) { + /* Handle error */ + } + } + + if (fclose(fptr) == EOF) { + /* Handle error */ + } +} +

    The expression c++ is perfectly safe because putc() guarantees to evaluate its character argument exactly once.

    +

    NOTE: The output of this compliant solution differs depending on the character set. For example, when run on a machine using an ASCII-derived code set such as ISO-8859 or Unicode, this solution will print out the 26 lowercase letters of the English alphabet. However, if run with an EBCDIC-based code set, such as Codepage 037 or Codepage 285, punctuation marks or symbols may be output between the letters.

    +
    +
    +

    Using an expression that has side effects as the stream argument to getc(), putc(), or getwc() can result in unexpected behavior and abnormal program termination.

    + + + + + + + + + + + + + + + + + + + +
    + Rule + + Severity + + Likelihood + + Remediation Cost + + Priority + + Level +
    + FIO41-C + + Low + + Unlikely + + Medium + + P2 + + L3 +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Tool + + Version + + Checker + + Description +
    + + Astrée + + + 20.10 + + stream-argument-with-side-effects + + Fully checked +
    + + Axivion Bauhaus Suite + + + 7.2.0 + + CertC-FIO41 + +
    + + Helix QAC + + + 2021.3 + + C5036 + C++3225, C++3229 + +
    + + LDRA tool suite + + + 9.7.1 + + 35 D, 1 Q, 9 S,30 S, 134 S + + Fully implemented +
    + + Parasoft C/C++test + + + 2021.2 + + CERT_C-FIO41-a + CERT_C-FIO41-b + CERT_C-FIO41-c + CERT_C-FIO41-d + CERT_C-FIO41-e + + The value of an expression shall be the same under any order of evaluation that the standard permits + Don't write code that depends on the order of evaluation of function arguments + Don't write code that depends on the order of evaluation of function designator and function arguments + Don't write code that depends on the order of evaluation of expression that involves a function call + A full expression containing an increment (++) or decrement (--) operator should have no other potential side effects +
    + + Polyspace Bug Finder + + + R2021a + + + CERT C: Rule FIO41-C + + + Checks for stream arguments with possibly unintended side effects (rule fully covered) +
    + + PRQA QA-C + + + 9.7 + + 5036 + +
    + + PRQA QA-C++ + + + 4.4 + + 3225, 3229 + +
    + + RuleChecker + + + 20.10 + + stream-argument-with-side-effects + + Fully checked +
    +
    +
    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    +
    +
    +

    Key here (explains table format and definitions)

    + + + + + + + + + + + + + + + + + + +
    + Taxonomy + + Taxonomy item + + Relationship +
    + + CERT C Secure Coding Standard + + + + FIO24-C. Do not open a file that is already open + + + Prior to 2018-01-12: CERT: Unspecified Relationship +
    + + CERT C Secure Coding Standard + + + + EXP30-C. Do not depend on the order of evaluation for side effects + + + Prior to 2018-01-12: CERT: Unspecified Relationship +
    +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects.qhelp b/c/cert/src/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects.qhelp new file mode 100644 index 0000000000..0468a54e20 --- /dev/null +++ b/c/cert/src/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects.qhelp @@ -0,0 +1,21 @@ + + + + +

    This query implements the CERT-C rule FIO41-C:

    +
    +

    Do not call getc(), putc(), getwc(), or putwc() with a stream argument that has side effects

    +
    +
    + +
    + +
    + +
  • + CERT-C: + FIO41-C: Do not call getc(), putc(), getwc(), or putwc() with a stream argument that has side effects + . +
  • +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects.ql b/c/cert/src/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects.ql new file mode 100644 index 0000000000..7fc1c11d26 --- /dev/null +++ b/c/cert/src/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects.ql @@ -0,0 +1,24 @@ +/** + * @id c/cert/do-not-call-getc-and-putc-with-side-effects + * @name FIO41-C: Do not call getc(), putc(), getwc(), or putwc() with a stream argument that has side effects + * @description Using an expression that has side effects as the stream argument to `getc()` or + * `putc()` can result in unexpected behavior. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/cert/id/fio41-c + * correctness + * external/cert/obligation/rule + */ + +import cpp +import codingstandards.c.cert +import codingstandards.cpp.standardlibrary.FileAccess + +from FileAccess fa +where + not isExcluded(fa.getFileExpr(), IO2Package::doNotCallGetcAndPutcWithSideEffectsQuery()) and + fa.getTarget().hasGlobalName(["getc", "putc", "getwc", "putwc"]) and + not fa.getFileExpr().isPure() +select fa.getFileExpr(), + "The stream argument has side effects and might be evaluated more then once." diff --git a/c/cert/src/rules/FIO42-C/CloseFilesWhenTheyAreNoLongerNeeded-standard.qhelp b/c/cert/src/rules/FIO42-C/CloseFilesWhenTheyAreNoLongerNeeded-standard.qhelp index e822d5cfd4..6343d9015a 100644 --- a/c/cert/src/rules/FIO42-C/CloseFilesWhenTheyAreNoLongerNeeded-standard.qhelp +++ b/c/cert/src/rules/FIO42-C/CloseFilesWhenTheyAreNoLongerNeeded-standard.qhelp @@ -1,29 +1,604 @@ -
    -
      -
    • required
    • -
    • implementation
    • -
    • automated
    • -
    -
    - -
    -

    - ... -

    +
    +

    A call to the fopen() or freopen() function must be matched with a call to fclose() before the lifetime of the last pointer that stores the return value of the call has ended or before normal program termination, whichever occurs first.

    +

    In general, this rule should also be applied to other functions with open and close resources, such as the POSIX open() and close() functions, or the Microsoft Windows CreateFile() and CloseHandle() functions.

    +
    +
    +

    This code example is noncompliant because the file opened by the call to fopen() is not closed before function func() returns:

    + #include <stdio.h> + +int func(const char *filename) { + FILE *f = fopen(filename, "r"); + if (NULL == f) { + return -1; + } + /* ... */ + return 0; +} +
    +
    +

    In this compliant solution, the file pointed to by f is closed before returning to the caller:

    + #include <stdio.h> + +int func(const char *filename) { + FILE *f = fopen(filename, "r"); + if (NULL == f) { + return -1; + } + /* ... */ + if (fclose(f) == EOF) { + return -1; + } + return 0; +} +
    +
    +

    This code example is noncompliant because the resource allocated by the call to fopen() is not closed before the program terminates. Although exit() closes the file, the program has no way of determining if an error occurs while flushing or closing the file.

    + #include <stdio.h> +#include <stdlib.h> + +int main(void) { + FILE *f = fopen(filename, "w"); + if (NULL == f) { + exit(EXIT_FAILURE); + } + /* ... */ + exit(EXIT_SUCCESS); +} +
    +
    +

    In this compliant solution, the program closes f explicitly before calling exit(), allowing any error that occurs when flushing or closing the file to be handled appropriately:

    + #include <stdio.h> +#include <stdlib.h> -
    +int main(void) { + FILE *f = fopen(filename, "w"); + if (NULL == f) { + /* Handle error */ + } + /* ... */ + if (fclose(f) == EOF) { + /* Handle error */ + } + exit(EXIT_SUCCESS); +} +
    +
    +

    This code example is noncompliant because the resource allocated by the call to open() is not closed before function func() returns:

    + #include <stdio.h> +#include <fcntl.h> + +int func(const char *filename) { + int fd = open(filename, O_RDONLY, S_IRUSR); + if (-1 == fd) { + return -1; + } + /* ... */ + return 0; +} +
    +
    +

    In this compliant solution, fd is closed before returning to the caller:

    + #include <stdio.h> +#include <fcntl.h> +#include <unistd.h> + +int func(const char *filename) { + int fd = open(filename, O_RDONLY, S_IRUSR); + if (-1 == fd) { + return -1 + } + /* ... */ + if (-1 == close(fd)) { + return -1; + } + return 0; +} +
    +
    +

    In this noncompliant code example, the file opened by the Microsoft Windows CreateFile() function is not closed before func() returns:

    + #include <Windows.h> -
    -

    - ... -

    -
    - -
    -
      -
    • ...
    • -
    -
    +int func(LPCTSTR filename) { + HANDLE hFile = CreateFile(filename, GENERIC_READ, 0, NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + if (INVALID_HANDLE_VALUE == hFile) { + return -1; + } + /* ... */ + return 0; +}
    +
    +
    +

    In this compliant solution, hFile is closed by invoking the CloseHandle() function before returning to the caller:

    + #include <Windows.h> + +int func(LPCTSTR filename) { + HANDLE hFile = CreateFile(filename, GENERIC_READ, 0, NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + if (INVALID_HANDLE_VALUE == hFile) { + return -1; + } + /* ... */ + if (!CloseHandle(hFile)) { + return -1; + } + + return 0; +} +
    +
    +

    Failing to properly close files may allow an attacker to exhaust system resources and can increase the risk that data written into in-memory file buffers will not be flushed in the event of abnormal program termination.

    + + + + + + + + + + + + + + + + + + + +
    + Rule + + Severity + + Likelihood + + Remediation Cost + + Priority + + Level +
    + FIO42-C + + Medium + + Unlikely + + Medium + + P4 + + L3 +
    +
    +
    +

    This rule is stricter than rule [fileclose] in ISO/IEC TS 17961:2013. Analyzers that conform to the technical standard may not detect all violations of this rule.

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Tool + + Version + + Checker + + Description +
    + + Astrée + + + 20.10 + + + Supported, but no explicit checker +
    + + CodeSonar + + + 6.2p0 + + ALLOC.LEAK + + Leak +
    + + Compass/ROSE + + + + +
    + + Coverity + + + 2017.07 + + RESOURCE_LEAK (partial) + + Partially implemented +
    + + Helix QAC + + + 2021.3 + + C2701, C2702, C2703 + C++2701, C++2702, C++2703 + +
    + + Klocwork + + + 2021.4 + + RH.LEAK + +
    + + LDRA tool suite + + + 9.7.1 + + 49 D + + Partially implemented +
    + + Parasoft C/C++test + + + 2021.2 + + CERT_C-FIO42-a + + Ensure resources are freed +
    + + PC-lint Plus + + + 1.4 + + 429 + + Partially supported +
    + + Polyspace Bug Finder + + + R2021a + + + CERT C: Rule FIO42-C + + + Checks for resource leak (rule partially covered) +
    + + PRQA QA-C + + + 9.7 + + 2701, 2702, 2703 + +
    + + PRQA QA-C++ + + + 4.4 + + 2701, 2702, 2703 + +
    + + SonarQube C/C++ Plugin + + + 3.11 + + S2095 + +
    +
    +
    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    +
    +
    +

    Key here (explains table format and definitions)

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Taxonomy + + Taxonomy item + + Relationship +
    + + CERT C + + + + FIO51-CPP. Close files when they are no longer needed + + + Prior to 2018-01-12: CERT: Unspecified Relationship +
    + + CERT Oracle Secure Coding Standard for Java + + + + FIO04-J. Release resources when they are no longer needed + + + Prior to 2018-01-12: CERT: Unspecified Relationship +
    + + ISO/IEC TS 17961:2013 + + + Failing to close files or free dynamic memory when they are no longer needed [fileclose] + + Prior to 2018-01-12: CERT: Unspecified Relationship +
    + + CWE 2.11 + + + + CWE-404 + + , Improper Resource Shutdown or Release + + 2017-07-06: CERT: Rule subset of CWE +
    + + CWE 2.11 + + + + CWE-459 + + + 2017-07-06: CERT: Rule subset of CWE +
    + + CWE 2.11 + + + + CWE-772 + + + 2017-07-06: CERT: Rule subset of CWE +
    + + CWE 2.11 + + + + CWE-773 + + + 2017-07-06: CERT: Rule subset of CWE +
    + + CWE 2.11 + + + + CWE-775 + + + 2017-07-06: CERT: Rule subset of CWE +
    + + CWE 2.11 + + + + CWE-403 + + + 2017-10-30:MITRE:Unspecified Relationship + 2018-10-18:CERT: + Partial overlap +
    +
    +
    +

    Key here for mapping notes

    +

    CWE-773/CWE-775 and FIO42-C

    +

    CWE-773 = CWE-775

    +

    CWE-773 = Union( FIO42-C, list) where list =

    +
      +
    • Failure to free resource handles besides files
    • +
    +

    CWE-404/CWE-459/CWE-771/CWE-772 and FIO42-C/MEM31-C

    +

    Intersection( FIO42-C, MEM31-C) = Ø

    +

    CWE-404 = CWE-459 = CWE-771 = CWE-772

    +

    CWE-404 = Union( FIO42-C, MEM31-C list) where list =

    +
      +
    • Failure to free resources besides files or memory chunks, such as mutexes)
    • +
    +

    CWE-403 and FIO42-C

    +

    CWE-403 - FIO42-C = list, where list =

    +
      +
    • A process opens and closes a sensitive file descriptor, but also executes a child process while the file descriptor is open.
    • +
    +

    FIO42-C - CWE-403 = SPECIAL_CASES, where SPECIAL_CASES =

    +
      +
    • A program opens a file descriptor and fails to close it, but does not invoke any child processes while the file descriptor is open.
    • +
    +
    +
    + + + + + + + +
    + [ + + IEEE Std 1003.1:2013 + + ] + + XSH, System Interfaces, + open +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos-implementation.qhelp b/c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos-implementation.qhelp new file mode 100644 index 0000000000..a01fab8d10 --- /dev/null +++ b/c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos-implementation.qhelp @@ -0,0 +1,8 @@ + + + +

    None

    +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos-standard.qhelp b/c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos-standard.qhelp new file mode 100644 index 0000000000..2246be232f --- /dev/null +++ b/c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos-standard.qhelp @@ -0,0 +1,331 @@ + + +
    +

    The C Standard, 7.21.9.3 [ISO/IEC 9899:2011], defines the following behavior for fsetpos():

    +
    +

    The fsetpos function sets the mbstate_t object (if any) and file position indicator for the stream pointed to by stream according to the value of the object pointed to by pos, which shall be a value obtained from an earlier successful call to the fgetpos function on a stream associated with the same file.

    +
    +

    Invoking the fsetpos() function with any other values for pos is undefined behavior.

    +
    +
    +

    This noncompliant code example attempts to read three values from a file and then set the file position pointer back to the beginning of the file:

    + #include <stdio.h> +#include <string.h> + +int opener(FILE *file) { + int rc; + fpos_t offset; + + memset(&offset, 0, sizeof(offset)); + + if (file == NULL) { + return -1; + } + + /* Read in data from file */ + + rc = fsetpos(file, &offset); + if (rc != 0 ) { + return rc; + } + + return 0; +} + +

    Only the return value of an fgetpos() call is a valid argument to fsetpos(); passing a value of type fpos_t that was created in any other way is undefined behavior.

    +
    +
    +

    In this compliant solution, the initial file position indicator is stored by first calling fgetpos(), which is used to restore the state to the beginning of the file in the later call to fsetpos():

    + #include <stdio.h> +#include <string.h> + +int opener(FILE *file) { + int rc; + fpos_t offset; + + if (file == NULL) { + return -1; + } + + rc = fgetpos(file, &offset); + if (rc != 0 ) { + return rc; + } + + /* Read in data from file */ + + rc = fsetpos(file, &offset); + if (rc != 0 ) { + return rc; + } + + return 0; +} + +
    +
    +

    Misuse of the fsetpos() function can position a file position indicator to an unintended location in the file.

    + + + + + + + + + + + + + + + + + + + +
    + Rule + + Severity + + Likelihood + + Remediation Cost + + Priority + + Level +
    + FIO44-C + + Medium + + Unlikely + + Medium + + P4 + + L3 +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Tool + + Version + + Checker + + Description +
    + + CodeSonar + + + 6.2p0 + + (customization) + + Users can add a custom check for violations of this constraint. +
    + + Compass/ROSE + + + + + Can detect common violations of this rule. However, it cannot handle cases in which the value returned by + fgetpos() + is copied between several variables before being passed to + fsetpos() +
    + + Helix QAC + + + 2021.3 + + C4841, C4842, C4843 + C++4841, C++4842, C++4843 + +
    + + LDRA tool suite + + + 9.7.1 + + 82 D + + Fully implemented +
    + + Parasoft C/C++test + + + 2021.2 + + CERT_C-FIO44-a + + Only use values for fsetpos() that are returned from fgetpos() +
    + + Polyspace Bug Finder + + + + + CERT C: Rule FIO44-C + + + Checks for invalid file position (rule partially covered) +
    + + PRQA QA-C + + + 9.7 + + 4841, 4842, 4843 + + Enforced by QAC +
    + + PRQA QA-C++ + + + 4.4 + + 4841, 4842, 4843 + +
    + + PVS-Studio + + + 7.17 + + V1035 + +
    +
    +
    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    +
    +
    +

    Key here (explains table format and definitions)

    + + + + + + + + + + + + + +
    + Taxonomy + + Taxonomy item + + Relationship +
    + + ISO/IEC TS 17961:2013 + + + Using a value for fsetpos other than a value returned from fgetpos [xfilepos] + + Prior to 2018-01-12: CERT: Unspecified Relationship +
    +
    +
    + + + + + + + +
    + [ + + ISO/IEC 9899:2011 + + ] + + 7.21.9.3, "The + fsetpos + Function" +
    +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.qhelp b/c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.qhelp new file mode 100644 index 0000000000..cdbaab7a86 --- /dev/null +++ b/c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.qhelp @@ -0,0 +1,21 @@ + + + + +

    This query implements the CERT-C rule FIO44-C:

    +
    +

    Only use values for fsetpos() that are returned from fgetpos()

    +
    +
    + +
    + +
    + +
  • + CERT-C: + FIO44-C: Only use values for fsetpos() that are returned from fgetpos() + . +
  • +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql b/c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql new file mode 100644 index 0000000000..9d5058507e --- /dev/null +++ b/c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql @@ -0,0 +1,45 @@ +/** + * @id c/cert/only-use-values-for-fsetpos-that-are-returned-from-fgetpos + * @name FIO44-C: Only use values for fsetpos() that are returned from fgetpos() + * @description Arguments for `fsetpos()` can only be obtained from calls to `fgetpos()`. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/cert/id/fio44-c + * correctness + * external/cert/obligation/rule + */ + +import cpp +import codingstandards.c.cert +import semmle.code.cpp.dataflow.DataFlow + +class FgetposCall extends FunctionCall { + FgetposCall() { this.getTarget().hasGlobalOrStdName("fgetpos") } +} + +class FsetposCall extends FunctionCall { + FsetposCall() { this.getTarget().hasGlobalOrStdName("fsetpos") } +} + +class FposDFConf extends DataFlow::Configuration { + FposDFConf() { this = "FposDFConf" } + + override 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) { + // sink must be the second parameter of a FsetposCall call + sink.asExpr() = any(FsetposCall c).getArgument(1) + } +} + +from FsetposCall fsetpos +where + not isExcluded(fsetpos.getArgument(1), + IO2Package::onlyUseValuesForFsetposThatAreReturnedFromFgetposQuery()) and + not any(FposDFConf dfConf).hasFlowToExpr(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/FIO46-C/UndefinedBehaviorAccessingAClosedFile-standard.qhelp b/c/cert/src/rules/FIO46-C/UndefinedBehaviorAccessingAClosedFile-standard.qhelp index e822d5cfd4..1f54ed624e 100644 --- a/c/cert/src/rules/FIO46-C/UndefinedBehaviorAccessingAClosedFile-standard.qhelp +++ b/c/cert/src/rules/FIO46-C/UndefinedBehaviorAccessingAClosedFile-standard.qhelp @@ -1,29 +1,339 @@ -
    -
      -
    • required
    • -
    • implementation
    • -
    • automated
    • -
    -
    +
    +

    Using the value of a pointer to a FILE object after the associated file is closed is undefined behavior. (See undefined behavior 148.) Programs that close the standard streams (especially stdout but also stderr and stdin) must be careful not to use these streams in subsequent function calls, particularly those that implicitly operate on them (such as printf(), perror(), and getc()).

    +

    This rule can be generalized to other file representations.

    +
    +
    +

    In this noncompliant code example, the stdout stream is used after it is closed:

    + #include <stdio.h> + +int close_stdout(void) { + if (fclose(stdout) == EOF) { + return -1; + } + + printf("stdout successfully closed.\n"); + return 0; +} +
    +
    +

    In this compliant solution, stdout is not used again after it is closed. This must remain true for the remainder of the program, or stdout must be assigned the address of an open file object.

    + #include <stdio.h> + +int close_stdout(void) { + if (fclose(stdout) == EOF) { + return -1; + } -
    -

    - ... -

    - -
    - -
    -

    - ... -

    -
    - -
    -
      -
    • ...
    • -
    -
    + fputs("stdout successfully closed.", stderr); + return 0; +}
    +
    +
    +

    Using the value of a pointer to a FILE object after the associated file is closed is undefined behavior.

    + + + + + + + + + + + + + + + + + + + +
    + Rule + + Severity + + Likelihood + + Remediation Cost + + Priority + + Level +
    + FIO46-C + + Medium + + Unlikely + + Medium + + P4 + + L3 +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Tool + + Version + + Checker + + Description +
    + + Astrée + + + 20.10 + + + Supported +
    + + CodeSonar + + + 6.2p0 + + IO.UAC + + Use after close +
    + + Compass/ROSE + + + + +
    + + Coverity + + + 2017.07 + + USE_AFTER_FREE + + Implemented +
    + + Helix QAC + + + 2021.3 + + C2696, C2697, C2698 + C++2696, C++2697, C++2698 + +
    + + Klocwork + + + 2021.4 + + SV.INCORRECT_RESOURCE_HANDLING.URH + +
    + + LDRA tool suite + + + 9.7.1 + + 48 D + + Partially implemented +
    + + Parasoft C/C++test + + + 2021.2 + + CERT_C-FIO46-a + + Do not use resources that have been freed +
    + + PC-lint Plus + + + 1.4 + + 2471 + + Fully supported +
    + + Polyspace Bug Finder + + + R2021a + + + CERT C: Rule FIO46-C + + + Checks for use of previously closed resource (rule partially covered) +
    + + PRQA QA-C + + + 9.7 + + 2696, 2697, 2698 + +
    + + PRQA QA-C++ + + + 4.4 + + 2696, 2697, 2698 + +
    + + SonarQube C/C++ Plugin + + + 3.11 + + S3588 + +
    +
    +
    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    +
    +
    + + + + + + + + + + + +
    + [ + + IEEE Std 1003.1:2013 + + ] + + XSH, System Interfaces, + open +
    + [ + + ISO/IEC 9899:2011 + + ] + + Subclause 7.21.3, "Files" + Subclause 7.21.5.1, "The + fclose + Function" +
    +
    \ No newline at end of file diff --git a/c/cert/test/qlpack.yml b/c/cert/test/qlpack.yml index ff93297bfd..2ff75c7471 100644 --- a/c/cert/test/qlpack.yml +++ b/c/cert/test/qlpack.yml @@ -1,4 +1,4 @@ name: cert-c-coding-standards-tests -version: 2.0.0 +version: 2.1.0 libraryPathDependencies: cert-c-coding-standards extractor: cpp \ No newline at end of file diff --git a/c/cert/test/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.expected b/c/cert/test/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.expected new file mode 100644 index 0000000000..3ea1a05fd7 --- /dev/null +++ b/c/cert/test/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.expected @@ -0,0 +1 @@ +| test.c:20:3:20:4 | call to f1 | Depending on the order of evaluation for the arguments $@ and $@ for side effects on shared state is unspecified and can result in unexpected behavior. | test.c:20:6:20:7 | call to f2 | call to f2 | test.c:20:12:20:13 | call to f3 | call to f3 | diff --git a/c/cert/test/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.qlref b/c/cert/test/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.qlref new file mode 100644 index 0000000000..c855957959 --- /dev/null +++ b/c/cert/test/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.qlref @@ -0,0 +1 @@ +rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.ql \ No newline at end of file diff --git a/c/cert/test/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects.expected b/c/cert/test/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects.expected new file mode 100644 index 0000000000..0d5e9af565 --- /dev/null +++ b/c/cert/test/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects.expected @@ -0,0 +1,3 @@ +| test.c:15:3:15:15 | ... = ... | Scalar object referenced by $@ has a $@ that is unsequenced in relative to another $@. | test.c:9:7:9:8 | l1 | l1 | test.c:15:8:15:11 | ++ ... | side-effect | test.c:15:3:15:4 | l1 | side-effect or value computation | +| test.c:16:3:16:15 | ... = ... | Scalar object referenced by $@ has a $@ that is unsequenced in relative to another $@. | test.c:9:7:9:8 | l1 | l1 | test.c:16:6:16:9 | ... ++ | side-effect | test.c:16:14:16:15 | l1 | side-effect or value computation | +| test.c:18:3:18:4 | call to f1 | Scalar object referenced by $@ has a $@ that is unsequenced in relative to another $@. | test.c:9:7:9:8 | l1 | l1 | test.c:18:10:18:13 | ... ++ | side-effect | test.c:18:6:18:7 | l1 | side-effect or value computation | diff --git a/c/cert/test/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects.qlref b/c/cert/test/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects.qlref new file mode 100644 index 0000000000..27f4de766e --- /dev/null +++ b/c/cert/test/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects.qlref @@ -0,0 +1 @@ +rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects.ql \ No newline at end of file diff --git a/c/cert/test/rules/EXP30-C/test.c b/c/cert/test/rules/EXP30-C/test.c new file mode 100644 index 0000000000..b307fd8e21 --- /dev/null +++ b/c/cert/test/rules/EXP30-C/test.c @@ -0,0 +1,28 @@ +extern void f1(int, int); + +int f2(void); +int f3(void); + +int g1; + +void test() { + int l1; + int l2[10] = {0}; + + l1 = l1 + 1; + l2[l1] = l1; // COMPLIANT + + l1 = ++l1 + 1; // NON_COMPLIANT + l2[l1++] = l1; // NON_COMPLIANT + + f1(l1, l1++); // NON_COMPLIANT + + f1(f2(), f3()); // NON_COMPLIANT +} + +int f2(void) { return g1 + 1; } + +int f3(void) { + g1 = 0; + return g1; +} \ No newline at end of file diff --git a/c/cert/test/rules/EXP44-C/UnevaluatedOperandWithSideEffect.expected b/c/cert/test/rules/EXP44-C/UnevaluatedOperandWithSideEffect.expected new file mode 100644 index 0000000000..186cadac9f --- /dev/null +++ b/c/cert/test/rules/EXP44-C/UnevaluatedOperandWithSideEffect.expected @@ -0,0 +1,2 @@ +| test.c:4:19:4:22 | ... ++ | Unevaluated operand with side effect that will not be generated. | +| test.c:15:21:15:24 | ++ ... | Unevaluated operand with side effect that will not be generated. | diff --git a/c/cert/test/rules/EXP44-C/UnevaluatedOperandWithSideEffect.qlref b/c/cert/test/rules/EXP44-C/UnevaluatedOperandWithSideEffect.qlref new file mode 100644 index 0000000000..e41838bcba --- /dev/null +++ b/c/cert/test/rules/EXP44-C/UnevaluatedOperandWithSideEffect.qlref @@ -0,0 +1 @@ +rules/EXP44-C/UnevaluatedOperandWithSideEffect.ql \ No newline at end of file diff --git a/c/cert/test/rules/EXP44-C/test.c b/c/cert/test/rules/EXP44-C/test.c new file mode 100644 index 0000000000..6bf7068103 --- /dev/null +++ b/c/cert/test/rules/EXP44-C/test.c @@ -0,0 +1,26 @@ +void test_sizeof(void) { + int l1 = 0; + int l2 = sizeof(l1); // COMPLIANT + int l3 = sizeof(l1++); // NON_COMPLIANT + int l4 = + sizeof(int[++l1]); // COMPLIANT - see ISO/IEC 9899:201x 6.5.3.4 point 2 + int l5 = sizeof( + int[++l1 % 1 + 1]); // NON_COMPLIANT[FALSE_NEGATIVE] - we cannot determine + // for all cases whether the size of the VLA is + // affected requiring the evaluation of the operand. +} + +void test_alignof(void) { + int l1 = 0; + int l2 = _Alignof(++l1); // NON_COMPLIANT + int l3 = _Alignof(int[++l1]); // NON_COMPLIANT[FALSE_NEGATIVE] + l1++; + int l4 = _Alignof(int[l1]); // COMPLIANT +} + +void test_generic(void) { + int l1 = 0; + + int l2 = _Generic(++l1, int : 1, double : 2, long double : 3, + default : 0); // NON_COMPLIANT[FALSE_NEGATIVE] +} \ No newline at end of file diff --git a/c/cert/test/rules/EXP45-C/AssignmentsInSelectionStatements.expected b/c/cert/test/rules/EXP45-C/AssignmentsInSelectionStatements.expected new file mode 100644 index 0000000000..bf3190bf5a --- /dev/null +++ b/c/cert/test/rules/EXP45-C/AssignmentsInSelectionStatements.expected @@ -0,0 +1,9 @@ +| test.c:7:7:7:12 | ... = ... | Assignment in selection statement. | +| test.c:22:12:22:17 | ... = ... | Assignment in selection statement. | +| test.c:24:19:24:23 | ... = ... | Assignment in selection statement. | +| test.c:28:13:28:18 | ... = ... | Assignment in selection statement. | +| test.c:32:15:32:20 | ... = ... | Assignment in selection statement. | +| test.c:33:26:33:31 | ... = ... | Assignment in selection statement. | +| test.c:34:15:34:20 | ... = ... | Assignment in selection statement. | +| test.c:35:26:35:31 | ... = ... | Assignment in selection statement. | +| test.c:41:15:41:20 | ... = ... | Assignment in selection statement. | diff --git a/c/cert/test/rules/EXP45-C/AssignmentsInSelectionStatements.qlref b/c/cert/test/rules/EXP45-C/AssignmentsInSelectionStatements.qlref new file mode 100644 index 0000000000..c894744ff7 --- /dev/null +++ b/c/cert/test/rules/EXP45-C/AssignmentsInSelectionStatements.qlref @@ -0,0 +1 @@ +rules/EXP45-C/AssignmentsInSelectionStatements.ql \ No newline at end of file diff --git a/c/cert/test/rules/EXP45-C/test.c b/c/cert/test/rules/EXP45-C/test.c new file mode 100644 index 0000000000..a9298c0b73 --- /dev/null +++ b/c/cert/test/rules/EXP45-C/test.c @@ -0,0 +1,57 @@ +extern int g1; +extern int f1(int); + +void test() { + int l1; + + if (l1 = 1) // NON_COMPLIANT + { + } + + if ((l1 = g1)) // COMPLIANT - exception when the assignment consists of a + // single primary expression. + { + } + + if ((l1 = g1) != 0) // COMPLIANT - assignment is itself an operand to a + // comparison or relational expression. + { + } + + do { + } while (l1 = 1); // NON_COMPLIANT + + for (int i = 0; i = 1; i++) // NON_COMPLIANT + { + } + + int l2 = (l1 = 1) ? 1 : 2; // NON_COMPLIANT + int l3 = l1 ? l1 = 1 : 2; // COMPLIANT + int l4 = l1 ? 1 : (l1 = 2); // COMPLIANT + + _Bool l5 = (l1 = 1) && l1 != 2; // NON_COMPLIANT + _Bool l6 = l1 != 2 && (l1 = 1); // NON_COMPLIANT + _Bool l7 = (l1 = 1) || l1 != 2; // NON_COMPLIANT + _Bool l8 = l1 != 2 || (l1 = 1); // NON_COMPLIANT + + if (((l1 = g1) != 0) && l5) // COMPLIANT - the assignment is intended + { + } + + if (l1 > 2, l1 = 3) // NON_COMPLIANT + { + } + + while (l1 = 2, l2 == l3) // COMPLIANT + { + } + + if (f1(l1 = l2)) // COMPLIANT + { + } + + int l9[2] = {0}; + if (l9[l1 = 1]) // COMPLIANT + { + } +} \ No newline at end of file diff --git a/c/cert/test/rules/FIO34-C/DistinguishBetweenCharReadFromAFileAndEofOrWeof.expected b/c/cert/test/rules/FIO34-C/DistinguishBetweenCharReadFromAFileAndEofOrWeof.expected index c2857bb5f0..9d99dcf8f6 100644 --- a/c/cert/test/rules/FIO34-C/DistinguishBetweenCharReadFromAFileAndEofOrWeof.expected +++ b/c/cert/test/rules/FIO34-C/DistinguishBetweenCharReadFromAFileAndEofOrWeof.expected @@ -7,3 +7,4 @@ | test.c:130:9:130:15 | call to getchar | The file read is not checked for errors and end of file. | | test.c:146:7:146:10 | call to getc | The file read is not checked for errors and end of file. | | test.c:148:8:148:11 | call to getc | The file read is not checked for errors and end of file. | +| test.c:160:9:160:15 | call to getchar | The file read is not checked for errors and end of file. | diff --git a/c/cert/test/rules/FIO34-C/EndOfFileCheckPortability.expected b/c/cert/test/rules/FIO34-C/EndOfFileCheckPortability.expected index fa49b52d30..38df60ea29 100644 --- a/c/cert/test/rules/FIO34-C/EndOfFileCheckPortability.expected +++ b/c/cert/test/rules/FIO34-C/EndOfFileCheckPortability.expected @@ -10,3 +10,4 @@ | test.c:137:10:137:25 | ... != ... | This check is only portable to platforms where type `char` is less wide than type `int`. | | test.c:149:7:149:14 | ... != ... | This check is only portable to platforms where type `char` is less wide than type `int`. | | test.c:151:7:151:14 | ... != ... | This check is only portable to platforms where type `char` is less wide than type `int`. | +| test.c:171:12:171:19 | ... == ... | This check is only portable to platforms where type `char` is less wide than type `int`. | diff --git a/c/cert/test/rules/FIO34-C/test.c b/c/cert/test/rules/FIO34-C/test.c index 293529dfc1..7bf1119c00 100644 --- a/c/cert/test/rules/FIO34-C/test.c +++ b/c/cert/test/rules/FIO34-C/test.c @@ -150,4 +150,23 @@ void f9(void) { ; if (d != EOF) // NON_PORTABLE ; -} \ No newline at end of file +} + +int helper() { return ((!feof(stdin) && !ferror(stdin))); } +void finter(void) { + int c; + + do { + c = getchar(); // COMPLIANT[FALSE_POSITIVE] + } while (helper()); +} + +// the char is compared to EOF +// but the result is not handled corectly +void fmishandling(void) { + int c; + + do { + c = getchar(); // NON_COMPLIANT[FALSE_NEGATIVE] + } while (c == EOF); // NON_PORTABLE +} diff --git a/c/cert/test/rules/FIO38-C/DoNotCopyAFileObject.expected b/c/cert/test/rules/FIO38-C/DoNotCopyAFileObject.expected new file mode 100644 index 0000000000..50449f4a2f --- /dev/null +++ b/c/cert/test/rules/FIO38-C/DoNotCopyAFileObject.expected @@ -0,0 +1,5 @@ +| test.c:4:20:4:26 | * ... | A FILE object is being copied. | +| test.c:11:21:11:30 | * ... | A FILE object is being copied. | +| test.c:17:21:17:31 | * ... | A FILE object is being copied. | +| test.c:23:15:23:21 | * ... | A FILE object is being copied. | +| test.c:36:19:36:28 | * ... | A FILE object is being copied. | diff --git a/c/cert/test/rules/FIO38-C/DoNotCopyAFileObject.qlref b/c/cert/test/rules/FIO38-C/DoNotCopyAFileObject.qlref new file mode 100644 index 0000000000..43db2e54f0 --- /dev/null +++ b/c/cert/test/rules/FIO38-C/DoNotCopyAFileObject.qlref @@ -0,0 +1 @@ +rules/FIO38-C/DoNotCopyAFileObject.ql \ No newline at end of file diff --git a/c/cert/test/rules/FIO38-C/test.c b/c/cert/test/rules/FIO38-C/test.c new file mode 100644 index 0000000000..f1b3f616ca --- /dev/null +++ b/c/cert/test/rules/FIO38-C/test.c @@ -0,0 +1,43 @@ +#include + +int f1(void) { + FILE my_stdout = *stdout; // NON_COMPLIANT + return fputs("Hello, World!\n", &my_stdout); +} + +int f2(void) { + FILE *my_stdout; + my_stdout = stdout; // COMPLIANT + FILE my_stdout2 = *my_stdout; // NON_COMPLIANT + return fputs("Hello, World!\n", my_stdout); +} +int f2b(void) { + FILE *const *my_stdout; + my_stdout = &stdout; // COMPLIANT + FILE my_stdout2 = **my_stdout; // NON_COMPLIANT + return fputs("Hello, World!\n", *my_stdout); +} + +int f3(void) { + FILE my_stdout; + my_stdout = *stdout; // NON_COMPLIANT + return fputs("Hello, World!\n", &my_stdout); +} + +int f4(void) { + FILE *my_stdout; + my_stdout = fopen("file.txt", "w"); // COMPLIANT + return fputs("Hello, World!\n", my_stdout); +} + +int f5helper(FILE my_stdout) { return fputs("Hello, World!\n", &my_stdout); } +int f5(void) { + FILE *my_stdout = fopen("file.txt", "w"); // COMPLIANT + return f5helper(*my_stdout); // NON_COMPLIANT +} + +int f6helper(FILE *my_stdout) { return fputs("Hello, World!\n", my_stdout); } +int f6(void) { + FILE *my_stdout = fopen("file.txt", "w"); // COMPLIANT + return f6helper(my_stdout); // COMPLIANT +} diff --git a/c/cert/test/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.expected b/c/cert/test/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.expected new file mode 100644 index 0000000000..20c108cfa0 --- /dev/null +++ b/c/cert/test/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.expected @@ -0,0 +1,12 @@ +| test.c:20:10:20:12 | buf | The buffer is not reset before being referenced following a failed $@. | test.c:15:7:15:11 | call to fgets | call to fgets | +| test.c:57:10:57:12 | buf | The buffer is not reset before being referenced following a failed $@. | test.c:52:7:52:11 | call to fgets | call to fgets | +| test.c:66:18:66:20 | buf | The buffer is not reset before being referenced following a failed $@. | test.c:61:7:61:11 | call to fgets | call to fgets | +| test.c:68:10:68:12 | buf | The buffer is not reset before being referenced following a failed $@. | test.c:61:7:61:11 | call to fgets | call to fgets | +| test.c:87:10:87:12 | buf | The buffer is not reset before being referenced following a failed $@. | test.c:82:9:82:13 | call to fgets | call to fgets | +| test.c:96:10:96:12 | buf | The buffer is not reset before being referenced following a failed $@. | test.c:91:10:91:14 | call to fgets | call to fgets | +| test.c:114:10:114:12 | buf | The buffer is not reset before being referenced following a failed $@. | test.c:107:15:107:19 | call to fgets | call to fgets | +| test.c:137:10:137:12 | buf | The buffer is not reset before being referenced following a failed $@. | test.c:130:15:130:19 | call to fgets | call to fgets | +| test.c:176:10:176:12 | buf | The buffer is not reset before being referenced following a failed $@. | test.c:173:15:173:19 | call to fgets | call to fgets | +| test.c:197:10:197:12 | buf | The buffer is not reset before being referenced following a failed $@. | test.c:192:10:192:14 | call to fgets | call to fgets | +| test.c:207:10:207:12 | buf | The buffer is not reset before being referenced following a failed $@. | test.c:202:17:202:21 | call to fgets | call to fgets | +| test.c:213:12:213:14 | buf | The buffer is not reset before being referenced following a failed $@. | test.c:211:8:211:12 | call to fgets | call to fgets | diff --git a/c/cert/test/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.qlref b/c/cert/test/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.qlref new file mode 100644 index 0000000000..eb5a3c687c --- /dev/null +++ b/c/cert/test/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.qlref @@ -0,0 +1 @@ +rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.ql \ No newline at end of file diff --git a/c/cert/test/rules/FIO40-C/test.c b/c/cert/test/rules/FIO40-C/test.c new file mode 100644 index 0000000000..2b4e445dcd --- /dev/null +++ b/c/cert/test/rules/FIO40-C/test.c @@ -0,0 +1,225 @@ +#include +#include +#include + +char buf[1024]; +char buf2[sizeof(buf)]; + +void f0(FILE *file) { + // covered by rule ERR33-C + fgets(buf, sizeof(buf), file); // COMPLIANT + return; +} + +char f1(FILE *file) { + if (fgets(buf, sizeof(buf), file) == NULL) { + /*null*/ + f0(file); + sizeof(buf); // COMPLIANT + } + return buf[0]; // NON_COMPLIANT +} + +char f2a(FILE *file) { + if (fgets(buf, sizeof(buf), file) == NULL) { + /*null*/ + *buf = '\0'; // COMPLIANT + sizeof(buf); // COMPLIANT + } + return buf[0]; // COMPLIANT +} + +char f2b(FILE *file) { + if (fgets(buf, sizeof(buf), file) == 0) { + /*null*/ + buf[0] = '\0'; // COMPLIANT + sizeof(buf); // COMPLIANT + } + return buf[0]; // COMPLIANT +} + +char f3a(FILE *file) { + if (fgets(buf, sizeof(buf), file) != NULL) { + // ... + } else { + /*null*/ + strcpy(buf, buf2); // COMPLIANT + } + return buf[0]; // COMPLIANT +} + +char f3b(FILE *file) { + if (fgets(buf, sizeof(buf), file)) { + // ... + } else { + /*null*/ + } + return buf[0]; // NON_COMPLIANT +} + +char f3c(FILE *file) { + if (fgets(buf, sizeof(buf), file) != NULL) { + // ... + } else { + /*null*/ + // resetting a different buffer + strcpy(buf2, buf); // NON_COMPLIANT + } + return buf[0]; // NON_COMPLIANT +} + +char f4(FILE *file) { + if (fgets(buf, sizeof(buf), file)) { + // ... + } else { + /*null*/ + fgets(buf, sizeof(buf), file); // COMPLIANT + } + return buf[0]; // COMPLIANT +} + +char f4b(FILE *file) { + if (!(fgets(buf, sizeof(buf), file) == NULL)) { + // ... + } + /*null*/ + + return buf[0]; // NON_COMPLIANT +} + +char f5a(FILE *file) { + while (fgets(buf, sizeof(buf), file)) { + // ... + } + /*null*/ + + return buf[0]; // NON_COMPLIANT +} +char f5b(FILE *file) { + while (fgets(buf, sizeof(buf), file) == NULL) { + /*null*/ + } + + return buf[0]; // COMPLIANT +} + +char f6(FILE *file, int input) { + char *ret = fgets(buf, sizeof(buf), file); + bool flag = (ret != NULL); + if (flag) { + // ... + } else { + /*null*/ + } + return buf[0]; // NON_COMPLIANT +} + +char f7(FILE *file, int input) { + char *ret = fgets(buf, sizeof(buf), file); // COMPLIANT + bool flag = (ret != NULL); + if (flag) { + // ... + } else { + /*null*/ + *buf = '\0'; + } + return buf[0]; +} + +char f8(FILE *file, int input) { + char *ret = fgets(buf, sizeof(buf), file); + bool flag = (ret == NULL); + if (!(flag || input)) { + // ... + } else { + /*null*/ + } + return buf[0]; // NON_COMPLIANT +} + +void f9(FILE *file, int input) { + char *ret = fgets(buf, sizeof(buf), file); // COMPLIANT + bool flag = (ret != NULL); + if (flag) { + // ... + } else { + /*null*/ + // *buf = '\0'; + } + // buf is not accessed + return; +} + +// fgets wrapper +static inline char *my_fgets(char *str, int size, FILE *file) { + char *result; + result = fgets(str, size, file); + return result; +} + +char f10(FILE *file) { + if (my_fgets(buf, sizeof(buf), file) == NULL) + memcpy(buf, buf2, sizeof(buf)); + return buf[0]; // COMPLIANT +} + +char f11(FILE *file, bool cond) { + if (cond && fgets(buf, sizeof(buf), file) == NULL) + /*null*/ + fprintf(stderr, "EOF error.\n"); + return '\0'; // COMPLIANT +} +char f12(FILE *file, bool cond) { + if (cond && fgets(buf, sizeof(buf), file) == NULL) + /*null*/ + fprintf(stderr, "Error.\n"); + return buf[0]; // NON_COMPLIANT +} + +char f13(FILE *file) { + while (true) { + if (!fgets(buf, sizeof buf, file)) { + /*null*/ + break; + } + return buf[0]; // COMPLIANT + } + return '\0'; // COMPLIANT +} + +char f14(FILE *file) { + while (true) { + if (!fgets(buf, sizeof buf, file)) { + /*null*/ + break; + } + } + return buf[0]; // NON_COMPLIANT +} + +char f15(FILE *file) { + while (1) { + char *key = fgets(buf, sizeof(buf), file); + if (key == NULL || strlen(buf) >= (sizeof(buf) - 1)) + break; + } + /*null*/ + return buf[0]; // NON_COMPLIANT +} + +char f16(FILE *file) { + if (!fgets(buf, sizeof(buf), file) || strcmp(buf, "end\n")) { + /*null*/ + return buf[0]; // NON_COMPLIANT + } + return 0; // COMPLIANT +} + +char f17(FILE *file) { + if (!fgets(buf, sizeof(buf), file) || strcmp(buf, "end\n")) { + /*null*/ + strcpy(buf, buf2); + return buf[0]; // COMPLIANT + } + return 0; // COMPLIANT +} diff --git a/c/cert/test/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects.expected b/c/cert/test/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects.expected new file mode 100644 index 0000000000..e5dfa5bcca --- /dev/null +++ b/c/cert/test/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects.expected @@ -0,0 +1,2 @@ +| test.c:5:8:5:34 | ... = ... | The stream argument has side effects and might be evaluated more then once. | +| test.c:15:13:15:51 | ... ? ... : ... | The stream argument has side effects and might be evaluated more then once. | diff --git a/c/cert/test/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects.qlref b/c/cert/test/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects.qlref new file mode 100644 index 0000000000..bd188d07f2 --- /dev/null +++ b/c/cert/test/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects.qlref @@ -0,0 +1 @@ +rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects.ql \ No newline at end of file diff --git a/c/cert/test/rules/FIO41-C/test.c b/c/cert/test/rules/FIO41-C/test.c new file mode 100644 index 0000000000..b1d4fc5433 --- /dev/null +++ b/c/cert/test/rules/FIO41-C/test.c @@ -0,0 +1,21 @@ +#include + +void f1() { + FILE *fp; + getc(fp = fopen("file.txt", "r")); // NON_COMPLIANT +} + +void f2() { + FILE *fp = fopen("file.txt", "r"); + getc(fp); // COMPLIANT +} + +void f3() { + FILE *fp = NULL; + putc('a', fp ? fp : (fp = fopen("file.txt", "w"))); // NON_COMPLIANT +} + +void f4() { + FILE *fp = fopen("file.txt", "w"); + putc('a', fp); // COMPLIANT +} \ No newline at end of file diff --git a/c/cert/test/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.expected b/c/cert/test/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.expected new file mode 100644 index 0000000000..8074710738 --- /dev/null +++ b/c/cert/test/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.expected @@ -0,0 +1,2 @@ +| test.c:7:24:7:30 | & ... | The position argument of a call to `fsetpos()` should be obtained from a call to `fgetpos()`. | +| test.c:33:24:33:30 | & ... | The position argument of a call to `fsetpos()` should be obtained from a call to `fgetpos()`. | diff --git a/c/cert/test/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.qlref b/c/cert/test/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.qlref new file mode 100644 index 0000000000..c5194e7d03 --- /dev/null +++ b/c/cert/test/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.qlref @@ -0,0 +1 @@ +rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql \ No newline at end of file diff --git a/c/cert/test/rules/FIO44-C/test.c b/c/cert/test/rules/FIO44-C/test.c new file mode 100644 index 0000000000..bb81e7c354 --- /dev/null +++ b/c/cert/test/rules/FIO44-C/test.c @@ -0,0 +1,34 @@ +#include +#include + +int f1(FILE *file) { + fpos_t offset; + memset(&offset, 0, sizeof(offset)); + return fsetpos(file, &offset); // NON_COMPLIANT +} + +int f2(FILE *file) { + fpos_t offset; + fgetpos(file, &offset); + return fsetpos(file, &offset); // COMPLIANT +} + +fpos_t f3a_helper(FILE *file) { + fpos_t offset; + fgetpos(file, &offset); + return offset; +} +int f3a_inter(FILE *file) { + fpos_t offset = f3a_helper(file); + return fsetpos(file, &offset); // COMPLIANT +} + +fpos_t f3b_helper() { + fpos_t offset; + memset(&offset, 0, sizeof(offset)); + return offset; +} +int f3b_inter(FILE *file) { + fpos_t offset = f3b_helper(); + return fsetpos(file, &offset); // NON_COMPLIANT +} diff --git a/c/common/src/codingstandards/c/Expr.qll b/c/common/src/codingstandards/c/Expr.qll new file mode 100644 index 0000000000..200f67ff7b --- /dev/null +++ b/c/common/src/codingstandards/c/Expr.qll @@ -0,0 +1,44 @@ +import cpp + +/* A full expression as defined in ISO/IEC 9899:2011 Annex C point 1. */ +class FullExpr extends Expr { + FullExpr() { + // An initializer that is not part of a compound literal (see 6.7.9). + this instanceof AssignExpr and not this.getParent+() instanceof AggregateLiteral + or + // The expression in an expression statement (see 6.8.3) + any(ExprStmt s).getExpr() = this + or + // The controlling expression of a selection statement (see 6.8.4) or + // the controlling expression of a `while`, `do`, or `for` statement (see 6.8.5) + any(ControlStructure s).getControllingExpr() = this + or + // Each of the possible optional expressions, besides the controlling expression, + // of a `for` statement (see 6.8.5.3). Note that if `clause-1` will be an expression statement if + // it is an expression and is therefore handle in the expression statement case. + any(ForStmt s).getUpdate() = this + or + // The expression in a `return` statement, if any (see 6.8.6.4) + any(ReturnStmt s).getExpr() = this + } +} + +/* A constituent expression is a sub-expression of a full expression. */ +class ConstituentExpr extends Expr { + ConstituentExpr() { not this instanceof FullExpr } + + FullExpr getFullExpr() { result = this.getParent+() } +} + +/* A primary expression as defined in ISO/IEC 9899:201x 6.5.1 */ +class PrimaryExpr extends Expr { + PrimaryExpr() { + exists(VariableAccess va | va.isLValue() and this = va) + or + exists(Literal l | this = l) + or + this.isParenthesised() + // or a generic selection _Generic that is a compile time evaluated + // expression that we can't model because of missing support. + } +} diff --git a/c/common/src/codingstandards/c/Ordering.qll b/c/common/src/codingstandards/c/Ordering.qll new file mode 100644 index 0000000000..14f776f93e --- /dev/null +++ b/c/common/src/codingstandards/c/Ordering.qll @@ -0,0 +1,76 @@ +import cpp +import codingstandards.cpp.SideEffect +import codingstandards.c.Expr +import codingstandards.cpp.Variable + +module Ordering { + abstract class Configuration extends string { + bindingset[this] + Configuration() { any() } + + abstract predicate isCandidate(Expr e1, Expr e2); + + /** + * Holds if `e1` is sequenced before `e2` as defined by Annex C in ISO/IEC 9899:2011 + * This limits to expression and we do not consider the sequence points that are not amenable to modelling: + * - after a full declarator as described in 6.7.6 point 3. + * - before a library function returns (see 7.1.4 point 3). + * - after the actions associated with each formatted I/O function conversion specifier (see 7.21.6 point 1 & 7.29.2 point 1). + * - between the expr before and after a call to a comparison function, + * between any call to a comparison function, and any movement of the objects passed + * as arguments to that call (see 7.22.5 point 5). + */ + predicate isSequencedBefore(Expr e1, Expr e2) { + isCandidate(e1, e2) and + not e1 = e2 and + ( + // 6.5.2.2 point 10 - The evaluation of the function designator and the actual arguments are sequenced + // before the actual call. + exists(Call call | + ( + call.getAnArgument() = e1 + or + // Postfix expression designating the called function + // We current only handle call through function pointers because the postfix expression + // of regular function calls is not available. That is, identifying `f` in `f(...)` + call.(ExprCall).getExpr() = e1 + ) and + call.getTarget() = e2.getEnclosingFunction() + ) + or + // 6.5.13 point 4 & 6.5.14 point 4 - The operators guarantee left-to-righ evaluation and there is + // a sequence point between the first and second operand if the latter is evaluated. + exists(BinaryLogicalOperation blop | + blop instanceof LogicalAndExpr or blop instanceof LogicalOrExpr + | + blop.getLeftOperand() = e1 and blop.getRightOperand() = e2 + ) + or + // 6.5.17 point 2 - There is a sequence pointt between the left operand and the right operand. + exists(CommaExpr ce, Expr lhs, Expr rhs | + lhs = ce.getLeftOperand() and + rhs = ce.getRightOperand() + | + lhs = e1.getParent*() and rhs = e2.getParent*() + ) + or + // 6.5.15 point 4 - There is a sequence point between the first operand and the evaluation of the second or third. + exists(ConditionalExpr cond | + cond.getCondition() = e1 and + (cond.getThen() = e2 or cond.getElse() = e2) + ) + or + // Between the evaluation of a full expression and the next to be evaluated full expression. + // Note we don't strictly check if `e2` is the next to be evaluated full expression and rely on the + // `isCandidate` configuration to minimze the scope or related full expressions. + e1 instanceof FullExpr and e2 instanceof FullExpr + ) + } + + predicate isUnsequenced(Expr e1, Expr e2) { + isCandidate(e1, e2) and + not isSequencedBefore(e1, e2) and + not isSequencedBefore(e2, e1) + } + } +} diff --git a/c/common/src/codingstandards/c/Variable.qll b/c/common/src/codingstandards/c/Variable.qll new file mode 100644 index 0000000000..c6061c99c1 --- /dev/null +++ b/c/common/src/codingstandards/c/Variable.qll @@ -0,0 +1,8 @@ +import cpp + +class VlaVariable extends Variable { + VlaVariable() { exists(VlaDeclStmt s | s.getVariable() = this) } + + /* Extractor workaround do determine if a VLA array has the specifier volatile.*/ + override predicate isVolatile() { this.getType().(ArrayType).getBaseType().isVolatile() } +} diff --git a/c/common/src/codingstandards/c/orderofevaluation/VariableAccessOrdering.qll b/c/common/src/codingstandards/c/orderofevaluation/VariableAccessOrdering.qll new file mode 100644 index 0000000000..4c041e8e4c --- /dev/null +++ b/c/common/src/codingstandards/c/orderofevaluation/VariableAccessOrdering.qll @@ -0,0 +1,57 @@ +import cpp +import codingstandards.c.Ordering + +class VariableAccessInFullExpressionOrdering extends Ordering::Configuration { + VariableAccessInFullExpressionOrdering() { this = "VariableAccessInFullExpressionOrdering" } + + override predicate isCandidate(Expr e1, Expr e2) { isCandidate(_, e1, e2) } +} + +pragma[noinline] +private predicate isConstituentOf(FullExpr e, VariableAccess ce) { + ce.(ConstituentExpr).getFullExpr() = e +} + +// Disable magic to prevent a CP between variable accesses +pragma[nomagic] +predicate isCandidatePair( + FullExpr e, VariableAccess va1, VariableAccess va2, Variable v1, Variable v2 +) { + isConstituentOf(e, va1) and + isConstituentOf(e, va2) and + not va1 = va2 and + va1.getTarget() = v1 and + va2.getTarget() = v2 +} + +/** + * Holds if variable access `va1` and variable access `va2`, part of `e`, are to be considered for order of evaluation validation. + * Note that this limits candidates to full-expression so we use a few shortcuts to exclude cases where an effect is known to be part of + * an other full expression that is sequenced after the value computation (and therefore cannot influence them at that point in the evaluation). + */ +predicate isCandidate(FullExpr e, VariableAccess va1, VariableAccess va2) { + exists(Variable v, VariableEffect ve | + isCandidatePair(e, va1, va2, v, v) and + ve.getAnAccess() = va1 and + not e = ve and + // Exclude partial effects, such as changing a value of a field or an array entry, because we currently cannot properly + // match those to determine an unsequenced value computation and side-effects. + not ve.isPartial() and + ( + e instanceof Operation and + // Prevent side-effects that are sequenced after the value computation and side-effects of the candidates. + // For example, `x = foo(y, &y)` where `foo` modifies `y` through the second argument. + not exists(Call call | + call.getAnArgument().getAChild*() = va1 and + call.getAnArgument().getAChild*() = va2 and + // if the side-effect occurs in the callee, it is sequenced after the argument value computation. + call.getTarget().calls*(ve.getEnclosingFunction()) + ) + or + e instanceof Call and + // if the side-effect occurs in the callee, it is sequenced after the argument value computation. + not e.(Call).getTarget().calls*(ve.getEnclosingFunction()) + ) and + not e.isAffectedByMacro() + ) +} diff --git a/c/common/src/qlpack.yml b/c/common/src/qlpack.yml index 02210d5b3a..d5851968b6 100644 --- a/c/common/src/qlpack.yml +++ b/c/common/src/qlpack.yml @@ -1,3 +1,3 @@ name: common-c-coding-standards -version: 2.0.0 +version: 2.1.0 libraryPathDependencies: common-cpp-coding-standards diff --git a/c/common/test/expr/FullExpr.expected b/c/common/test/expr/FullExpr.expected new file mode 100644 index 0000000000..b25672bc29 --- /dev/null +++ b/c/common/test/expr/FullExpr.expected @@ -0,0 +1,8 @@ +| fullexpr.c:11:3:11:5 | ... ++ | +| fullexpr.c:13:7:13:7 | i | +| fullexpr.c:15:10:15:10 | i | +| fullexpr.c:18:12:18:12 | i | +| fullexpr.c:20:8:20:12 | ... = ... | +| fullexpr.c:20:15:20:20 | ... < ... | +| fullexpr.c:20:23:20:25 | ++ ... | +| fullexpr.c:23:10:23:10 | i | diff --git a/c/common/test/expr/FullExpr.ql b/c/common/test/expr/FullExpr.ql new file mode 100644 index 0000000000..de7edf85c1 --- /dev/null +++ b/c/common/test/expr/FullExpr.ql @@ -0,0 +1,5 @@ +import cpp +import codingstandards.c.Expr + +from FullExpr e +select e diff --git a/c/common/test/expr/fullexpr.c b/c/common/test/expr/fullexpr.c new file mode 100644 index 0000000000..f4229e3bd3 --- /dev/null +++ b/c/common/test/expr/fullexpr.c @@ -0,0 +1,24 @@ +struct foo { + int i; + int j; +}; + +void full_expr() { + int i; + struct foo f = (struct foo){ + .i = 0, .j = 0}; // Not a full expression, part of a compound expression. + + i++; // Full expression, part of expression statement + + if (i) { // i is a full expression + } + while (i) { // i is a full expression + } + do { + } while (i); // i is a full expression + + for (i = 0; i < 10; ++i) { // i is a full expression in clause 1-3. + } + + return i; // i is a full expression +} \ No newline at end of file diff --git a/c/common/test/qlpack.yml b/c/common/test/qlpack.yml index cade2e140a..7f28bccc17 100644 --- a/c/common/test/qlpack.yml +++ b/c/common/test/qlpack.yml @@ -1,4 +1,4 @@ name: common-c-coding-standards-tests -version: 2.0.0 +version: 2.1.0 libraryPathDependencies: common-c-coding-standards extractor: cpp diff --git a/c/common/test/rules/donotaccessaclosedfile/DoNotAccessAClosedFile.expected b/c/common/test/rules/donotaccessaclosedfile/DoNotAccessAClosedFile.expected index 47b81d0c4f..e14443e4d5 100644 --- a/c/common/test/rules/donotaccessaclosedfile/DoNotAccessAClosedFile.expected +++ b/c/common/test/rules/donotaccessaclosedfile/DoNotAccessAClosedFile.expected @@ -1,10 +1,11 @@ -| test.c:6:3:6:8 | call to printf | Access of closed filestdoutwhich was closed at $@ | test.c:4:3:4:8 | call to fclose | this location. | -| test.c:7:3:7:6 | call to puts | Access of closed filestdoutwhich was closed at $@ | test.c:4:3:4:8 | call to fclose | this location. | -| test.c:16:13:16:18 | stderr | Access of closed filestderrwhich was closed at $@ | test.c:13:3:13:8 | call to fclose | this location. | -| test.c:17:3:17:8 | call to perror | Access of closed filestderrwhich was closed at $@ | test.c:13:3:13:8 | call to fclose | this location. | -| test.c:24:8:24:12 | stdin | Access of closed filestdinwhich was closed at $@ | test.c:22:3:22:8 | call to fclose | this location. | -| test.c:25:3:25:9 | call to getchar | Access of closed filestdinwhich was closed at $@ | test.c:22:3:22:8 | call to fclose | this location. | -| test.c:34:18:34:18 | f | Access of closed filefwhich was closed at $@ | test.c:31:3:31:8 | call to fclose | this location. | -| test.c:35:15:35:15 | f | Access of closed filefwhich was closed at $@ | test.c:31:3:31:8 | call to fclose | this location. | -| test.c:70:11:70:12 | fp | Access of closed filefpwhich was closed at $@ | test.c:69:3:69:8 | call to fclose | this location. | -| test.c:71:7:71:8 | fp | Access of closed filefpwhich was closed at $@ | test.c:69:3:69:8 | call to fclose | this location. | +| test.c:6:3:6:8 | call to printf | Access of closed filestdout which was closed at $@ | test.c:4:3:4:8 | call to fclose | this location. | +| test.c:7:3:7:6 | call to puts | Access of closed filestdout which was closed at $@ | test.c:4:3:4:8 | call to fclose | this location. | +| test.c:16:13:16:18 | stderr | Access of closed filestderr which was closed at $@ | test.c:13:3:13:8 | call to fclose | this location. | +| test.c:17:3:17:8 | call to perror | Access of closed filestderr which was closed at $@ | test.c:13:3:13:8 | call to fclose | this location. | +| test.c:24:8:24:12 | stdin | Access of closed filestdin which was closed at $@ | test.c:22:3:22:8 | call to fclose | this location. | +| test.c:25:3:25:9 | call to getchar | Access of closed filestdin which was closed at $@ | test.c:22:3:22:8 | call to fclose | this location. | +| test.c:34:18:34:18 | f | Access of closed filef which was closed at $@ | test.c:31:3:31:8 | call to fclose | this location. | +| test.c:35:15:35:15 | f | Access of closed filef which was closed at $@ | test.c:31:3:31:8 | call to fclose | this location. | +| test.c:70:11:70:12 | fp | Access of closed filefp which was closed at $@ | test.c:69:3:69:8 | call to fclose | this location. | +| test.c:71:7:71:8 | fp | Access of closed filefp which was closed at $@ | test.c:69:3:69:8 | call to fclose | this location. | +| test.c:81:17:81:17 | f | Access of closed filef which was closed at $@ | test.c:80:3:80:8 | call to fclose | this location. | diff --git a/c/common/test/rules/donotaccessaclosedfile/test.c b/c/common/test/rules/donotaccessaclosedfile/test.c index b24ff1137c..3123c09b83 100644 --- a/c/common/test/rules/donotaccessaclosedfile/test.c +++ b/c/common/test/rules/donotaccessaclosedfile/test.c @@ -70,4 +70,23 @@ int f7(void) { fprintf(fp, ""); // NON_COMPLIANT p = fp; // NON_COMPLIANT return 0; +} + +void finter_helper(FILE *f) { + fputs("write", f); // NON_COMPLIANT +} +int finter(void) { + FILE *f = fopen("myfile", "rw"); + fclose(f); + finter_helper(f); +} + +FILE *g_f; +void fglobal_helper() { + fputs("write", g_f); // NON_COMPLIANT[FALSE_NEGATIVE] +} +int fglobal(void) { + g_f = fopen("myfile", "rw"); + fclose(g_f); + fglobal_helper(); } \ No newline at end of file diff --git a/c/misra/src/qlpack.yml b/c/misra/src/qlpack.yml index ac60340e88..2002dd53e5 100644 --- a/c/misra/src/qlpack.yml +++ b/c/misra/src/qlpack.yml @@ -1,4 +1,4 @@ name: misra-c-coding-standards -version: 2.0.0 +version: 2.1.0 suites: codeql-suites libraryPathDependencies: common-c-coding-standards diff --git a/c/misra/src/rules/DIR-4-5/IdentifiersInTheSameNameSpaceUnambiguous.ql b/c/misra/src/rules/DIR-4-5/IdentifiersInTheSameNameSpaceUnambiguous.ql new file mode 100644 index 0000000000..954bdf687b --- /dev/null +++ b/c/misra/src/rules/DIR-4-5/IdentifiersInTheSameNameSpaceUnambiguous.ql @@ -0,0 +1,22 @@ +/** + * @id c/misra/identifiers-in-the-same-name-space-unambiguous + * @name DIR-4-5: Identifiers in the same name space with overlapping visibility should be typographically unambiguous + * @description Typographically ambiguous identifiers can lead to developer confusion. + * @kind problem + * @precision very-high + * @problem.severity recommendation + * @tags external/misra/id/dir-4-5 + * readability + * maintainability + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.rules.differentidentifiersnottypographicallyunambiguous.DifferentIdentifiersNotTypographicallyUnambiguous + +class IdentifiersInTheSameNameSpaceUnambiguousQuery extends DifferentIdentifiersNotTypographicallyUnambiguousSharedQuery { + IdentifiersInTheSameNameSpaceUnambiguousQuery() { + this = SyntaxPackage::identifiersInTheSameNameSpaceUnambiguousQuery() + } +} diff --git a/c/misra/src/rules/DIR-4-5/standard-example.cpp b/c/misra/src/rules/DIR-4-5/standard-example.cpp new file mode 100644 index 0000000000..aaaa1de8cf --- /dev/null +++ b/c/misra/src/rules/DIR-4-5/standard-example.cpp @@ -0,0 +1,18 @@ +int32_t id1_a_b_c; +int32_t id1_abc; // Non-compliant +int32_t id2_abc; // Non-compliant +int32_t id2_ABC; // Non-compliant +int32_t id3_a_bc; +int32_t id3_ab_c; // Non-compliant +int32_t id4_a_bc; +int32_t id4_ab_c; // Non-compliant +int32_t id5_ii; +int32_t id5_11; // Non-compliant +int32_t id6_i0; +int32_t id6_1O; // Non-compliant +int32_t id7_in; +int32_t id7_1h; // Non-compliant +int32_t id8_Z5; +int32_t id8_2S; // Non-compliant +int32_t id9_ZS; +int32_t id9_25; // Non-compliant \ No newline at end of file diff --git a/c/misra/src/rules/RULE-12-1/ImplicitPrecedenceOfOperatorsInExpression.ql b/c/misra/src/rules/RULE-12-1/ImplicitPrecedenceOfOperatorsInExpression.ql new file mode 100644 index 0000000000..005fffa32d --- /dev/null +++ b/c/misra/src/rules/RULE-12-1/ImplicitPrecedenceOfOperatorsInExpression.ql @@ -0,0 +1,122 @@ +/** + * @id c/misra/implicit-precedence-of-operators-in-expression + * @name RULE-12-1: The precedence of operators within expressions should be made explicit + * @description The relative precedences of operators are not intuitive and can lead to mistakes. + * The use of parentheses to make the precedence of operators explicit removes the + * possibility of incorrect expectations. + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/misra/id/rule-12-1 + * correctness + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.Expr + +int getPrecedence(Expr e) { + e instanceof PrimaryExpr and result = 16 + or + ( + e instanceof PostfixCrementOperation + or + e instanceof ClassAggregateLiteral + or + e instanceof ArrayExpr + or + e instanceof FunctionCall + or + e instanceof DotFieldAccess + or + e instanceof PointerFieldAccess + ) and + result = 15 + or + ( + e instanceof PrefixCrementOperation + or + e instanceof AddressOfExpr + or + e instanceof PointerDereferenceExpr + or + e instanceof UnaryPlusExpr + or + e instanceof UnaryMinusExpr + or + e instanceof ComplementExpr + or + e instanceof NotExpr + or + e instanceof SizeofOperator + or + e instanceof AlignofOperator + ) and + result = 14 + or + e instanceof Cast and result = 13 + or + ( + e instanceof MulExpr + or + e instanceof DivExpr + or + e instanceof RemExpr + ) and + result = 12 + or + ( + e instanceof AddExpr + or + e instanceof SubExpr + ) and + result = 11 + or + ( + e instanceof LShiftExpr + or + e instanceof RShiftExpr + ) and + result = 10 + or + e instanceof RelationalOperation and result = 9 + or + e instanceof EqualityOperation and result = 8 + or + e instanceof BitwiseAndExpr and result = 7 + or + e instanceof BitwiseXorExpr and result = 6 + or + e instanceof BitwiseOrExpr and result = 5 + or + e instanceof LogicalAndExpr and result = 4 + or + e instanceof LogicalOrExpr and result = 3 + or + e instanceof ConditionalExpr and result = 2 + or + e instanceof Assignment and result = 1 + or + e instanceof CommaExpr and result = 0 +} + +from Expr e, Expr operand +where + not isExcluded(e, SideEffects1Package::implicitPrecedenceOfOperatorsInExpressionQuery()) and + getPrecedence(e) in [2 .. 12] and + e.getAChild() = operand and + getPrecedence(operand) > getPrecedence(e) and + getPrecedence(operand) < 13 and + ( + if operand instanceof SizeofExprOperator + then not operand.(SizeofExprOperator).getExprOperand().isParenthesised() + else not operand.isParenthesised() + ) and + // Exclude the requirement for (v), (1), ("foo"), or macro calls like `assert(x==y)` that can be expanded to `x == y ? ... : ...` + not ( + operand instanceof VariableAccess or + operand instanceof Literal or + e.isInMacroExpansion() + ) +select e, "Operand $@ is not enclosed by parentheses.", operand, operand.toString() diff --git a/c/misra/src/rules/RULE-12-1/UnenclosedSizeofOperand.ql b/c/misra/src/rules/RULE-12-1/UnenclosedSizeofOperand.ql new file mode 100644 index 0000000000..8975e7dff7 --- /dev/null +++ b/c/misra/src/rules/RULE-12-1/UnenclosedSizeofOperand.ql @@ -0,0 +1,22 @@ +/** + * @id c/misra/unenclosed-sizeof-operand + * @name RULE-12-1: The operand of the sizeof operator should be enclosed in parentheses + * @description The relative precedences of operators are not intuitive and can lead to mistakes. + * The use of parentheses to make the precedence of operators explicit removes the + * possibility of incorrect expectations. + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/misra/id/rule-12-1 + * correctness + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.c.misra + +from SizeofExprOperator op +where + not isExcluded(op, SideEffects1Package::unenclosedSizeofOperandQuery()) and + not op.getExprOperand().isParenthesised() +select op, "The operand of the sizeof operator is not enclosed in parentheses." diff --git a/c/misra/src/rules/RULE-12-1/standard-example.c b/c/misra/src/rules/RULE-12-1/standard-example.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/misra/src/rules/RULE-13-1/InitializerListsContainPersistentSideEffects.ql b/c/misra/src/rules/RULE-13-1/InitializerListsContainPersistentSideEffects.ql new file mode 100644 index 0000000000..3c97fc06ca --- /dev/null +++ b/c/misra/src/rules/RULE-13-1/InitializerListsContainPersistentSideEffects.ql @@ -0,0 +1,32 @@ +/** + * @id c/misra/initializer-lists-contain-persistent-side-effects + * @name RULE-13-1: Initializer lists shall not contain persistent side effects + * @description The order in which side effects occur during the evaluation of the expressions in an + * initializer list is unspecified and can result in unexpected program behavior. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-13-1 + * correctness + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.SideEffect +import codingstandards.cpp.sideeffect.DefaultEffects +import codingstandards.cpp.sideeffect.Customizations + +class CrementEffect extends LocalSideEffect::Range { + CrementEffect() { this instanceof CrementOperation } +} + +from AggregateLiteral initList, SideEffect effect +where + not isExcluded(initList, SideEffects1Package::initializerListsContainPersistentSideEffectsQuery()) and + ( + initList.(ArrayOrVectorAggregateLiteral).getElementExpr(_) = effect + or + initList.(ClassAggregateLiteral).getFieldExpr(_) = effect + ) +select initList, "Initializer list constains persistent $@", effect, "side effect" diff --git a/c/misra/src/rules/RULE-13-1/standard-example.c b/c/misra/src/rules/RULE-13-1/standard-example.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/misra/src/rules/RULE-13-4/ResultOfAnAssignmentOperatorShouldNotBeUsed.ql b/c/misra/src/rules/RULE-13-4/ResultOfAnAssignmentOperatorShouldNotBeUsed.ql new file mode 100644 index 0000000000..6938f8e627 --- /dev/null +++ b/c/misra/src/rules/RULE-13-4/ResultOfAnAssignmentOperatorShouldNotBeUsed.ql @@ -0,0 +1,22 @@ +/** + * @id c/misra/result-of-an-assignment-operator-should-not-be-used + * @name RULE-13-4: The result of an assignment operator should not be used + * @description The use of an assignment operator can impair the readability of the code and the + * introduced side effect may result in undefined behavior. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-13-4 + * correctness + * readability + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.c.misra + +from AssignExpr e +where + not isExcluded(e, SideEffects1Package::resultOfAnAssignmentOperatorShouldNotBeUsedQuery()) and + not exists(ExprStmt s | s.getExpr() = e) +select e, "Use of an assignment operator's result." diff --git a/c/misra/src/rules/RULE-13-4/standard-example.c b/c/misra/src/rules/RULE-13-4/standard-example.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/misra/src/rules/RULE-13-5/PossibleSuppressedSideEffectInLogicOperatorOperand.ql b/c/misra/src/rules/RULE-13-5/PossibleSuppressedSideEffectInLogicOperatorOperand.ql new file mode 100644 index 0000000000..90faf9ec23 --- /dev/null +++ b/c/misra/src/rules/RULE-13-5/PossibleSuppressedSideEffectInLogicOperatorOperand.ql @@ -0,0 +1,25 @@ +/** + * @id c/misra/possible-suppressed-side-effect-in-logic-operator-operand + * @name RULE-13-5: The right hand operand of a logical && or || operator shall not contain persistent side effects + * @description The evaluation of the right-hand operand of the && and || operators is conditional + * on the value of the left-hand operand. Any side effects in the right-hand operand + * may or may not occur and may result in unexpected program behavior. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-13-5 + * correctness + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.SideEffect +import codingstandards.cpp.sideeffect.DefaultEffects + +from BinaryLogicalOperation blop, SideEffect s +where + not isExcluded(blop, + SideEffects1Package::possibleSuppressedSideEffectInLogicOperatorOperandQuery()) and + s = getAnExternalOrGlobalSideEffect(blop.getRightOperand()) +select blop, "The right hand operand generates the persistent $@", s, "side effect" diff --git a/c/misra/src/rules/RULE-13-5/standard-example.c b/c/misra/src/rules/RULE-13-5/standard-example.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/misra/src/rules/RULE-13-6/SizeofOperandWithSideEffect.ql b/c/misra/src/rules/RULE-13-6/SizeofOperandWithSideEffect.ql new file mode 100644 index 0000000000..10317b1169 --- /dev/null +++ b/c/misra/src/rules/RULE-13-6/SizeofOperandWithSideEffect.ql @@ -0,0 +1,45 @@ +/** + * @id c/misra/sizeof-operand-with-side-effect + * @name RULE-13-6: The operand of the sizeof operator shall not contain any expression which has potential side effects + * @description The operand to sizeof is not evaluated and its side effect will not be generated. + * Using an operand with a side effect can result in unexpected program behavior. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-13-6 + * correctness + * external/misra/obligation/mandatory + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.Variable +import codingstandards.cpp.SideEffect +import codingstandards.cpp.sideeffect.DefaultEffects +import codingstandards.cpp.sideeffect.Customizations + +class FunctionCallEffect extends GlobalSideEffect::Range { + FunctionCallEffect() { this instanceof FunctionCall } +} + +class CrementEffect extends LocalSideEffect::Range { + CrementEffect() { this instanceof CrementOperation } +} + +from SizeofExprOperator op, Expr operand, SideEffect effect +where + not isExcluded(op, SideEffects1Package::sizeofOperandWithSideEffectQuery()) and + operand = op.getExprOperand() and + effect = getASideEffect(operand) and + // Exclude side-effects in called functions because we already consider any + // function call to generate side-effects in line with the rule. + not exists(FunctionCall call | + operand.getAChild*() = call and getASideEffectInFunction(call.getTarget()) = effect + ) and + ( + effect.(VariableAccess).getTarget().isVolatile() + implies + effect.(VariableAccess).getTarget() instanceof VlaVariable + ) +select op, "The sizeof $@ is not evaluated but has a potential $@.", operand, "operand", effect, + "side effect" diff --git a/c/misra/src/rules/RULE-13-6/standard-example.c b/c/misra/src/rules/RULE-13-6/standard-example.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/misra/src/rules/RULE-3-1/CharacterSequencesAndUsedWithinAComment.ql b/c/misra/src/rules/RULE-3-1/CharacterSequencesAndUsedWithinAComment.ql new file mode 100644 index 0000000000..b7d01b4eae --- /dev/null +++ b/c/misra/src/rules/RULE-3-1/CharacterSequencesAndUsedWithinAComment.ql @@ -0,0 +1,39 @@ +/** + * @id c/misra/character-sequences-and-used-within-a-comment + * @name RULE-3-1: The character sequences /* and // shall not be used within a comment + * @description A /* or // character sequence within a comment is sometimes indicative of a missed + * comment and should not be allowed. + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/misra/id/rule-3-1 + * maintainability + * readability + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra + +class IllegalCCommentCharacter extends string { + IllegalCCommentCharacter(){ + this = "/*" or + this = "//" + } +} + +class IllegalCPPCommentCharacter extends string { + IllegalCPPCommentCharacter(){ + this = "/*" + } +} + +from Comment comment, string illegalSequence +where + not isExcluded(comment, SyntaxPackage::characterSequencesAndUsedWithinACommentQuery()) + and + ( + exists(IllegalCCommentCharacter c | illegalSequence = c | comment.(CStyleComment).getContents().indexOf(illegalSequence) > 0) or + exists(IllegalCPPCommentCharacter c | illegalSequence = c | comment.(CppStyleComment).getContents().indexOf(illegalSequence) > 0) + ) +select comment, "Comment contains an illegal sequence '" + illegalSequence + "'" diff --git a/c/misra/src/rules/RULE-3-2/LineSplicingUsedInComments.ql b/c/misra/src/rules/RULE-3-2/LineSplicingUsedInComments.ql new file mode 100644 index 0000000000..cf6a2bb547 --- /dev/null +++ b/c/misra/src/rules/RULE-3-2/LineSplicingUsedInComments.ql @@ -0,0 +1,23 @@ +/** + * @id c/misra/line-splicing-used-in-comments + * @name RULE-3-2: Line-splicing shall not be used in // comments + * @description Entering a newline following a '\' character can erroneously commenting out regions + * of code. + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/misra/id/rule-3-2 + * maintainability + * readability + * correctness + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra + +from CppStyleComment c +where + not isExcluded(c, SyntaxPackage::lineSplicingUsedInCommentsQuery()) and + (c.getContents().indexOf("\\") + 1) = c.getContents().indexOf("\n") +select c, "Line splicing in //-style comment." diff --git a/c/misra/src/rules/RULE-4-1/OctalAndHexadecimalEscapeSequencesNotTerminated.ql b/c/misra/src/rules/RULE-4-1/OctalAndHexadecimalEscapeSequencesNotTerminated.ql new file mode 100644 index 0000000000..a7fdf080a7 --- /dev/null +++ b/c/misra/src/rules/RULE-4-1/OctalAndHexadecimalEscapeSequencesNotTerminated.ql @@ -0,0 +1,48 @@ +/** + * @id c/misra/octal-and-hexadecimal-escape-sequences-not-terminated + * @name RULE-4-1: Octal and hexadecimal escape sequences shall be terminated + * @description Not explicitly terminating octal and hexadecimal escape sequences can results in + * developer confusion and lead to programming errors. + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/misra/id/rule-4-1 + * maintainability + * readability + * correctness + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra + +bindingset[s] +predicate isOctalEscape(string s) { + s.charAt(0) = "\\" and + exists(int i | i = [0 .. 7] | i.toString() = s.charAt(1)) +} + +bindingset[s] +predicate isHexEscape(string s) { s.indexOf("\\x") = 0 } + +from Literal l, string escapeKind, string s +where + not isExcluded(l, SyntaxPackage::octalAndHexadecimalEscapeSequencesNotTerminatedQuery()) and + exists(int idx, string sl | + sl = l.getValueText() and + idx = sl.indexOf("\\") and + s = sl.substring(idx, sl.length()) and + // Note: Octal representations must be 1-3 digits. There is no limitation on a + // Hex literal as long as the characters are valid. This query does not consider + // if the hex literal being constructed will overflow. + ( + isHexEscape(s) and + not s.regexpMatch("^((\\\\x[0-9A-F]+(?=[\"'\\\\])))[\\s\\S]*") and + escapeKind = "hexadecimal" + or + isOctalEscape(s) and + not s.regexpMatch("^(((\\\\[0-7]{1,3})(?=[\"'\\\\])))[\\s\\S]*") and + escapeKind = "octal" + ) + ) +select l, "Invalid " + escapeKind + " escape in string literal at '" + s + "'." diff --git a/c/misra/src/rules/RULE-4-4/SectionsOfCodeShallNotBeCommentedOut.ql b/c/misra/src/rules/RULE-4-4/SectionsOfCodeShallNotBeCommentedOut.ql new file mode 100644 index 0000000000..52adbac29d --- /dev/null +++ b/c/misra/src/rules/RULE-4-4/SectionsOfCodeShallNotBeCommentedOut.ql @@ -0,0 +1,23 @@ +/** + * @id c/misra/sections-of-code-shall-not-be-commented-out + * @name RULE-4-4: Sections of code should not be commented out + * @description Commented out code may become out of date leading to developer confusion. + * @kind problem + * @precision high + * @problem.severity warning + * @tags external/misra/id/rule-4-4 + * maintainability + * readability + * correctness + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.rules.sectionsofcodeshallnotbecommentedout.SectionsOfCodeShallNotBeCommentedOut + +class SectionsOfCodeShallNotBeCommentedOutQuery extends SectionsOfCodeShallNotBeCommentedOutSharedQuery { + SectionsOfCodeShallNotBeCommentedOutQuery() { + this = SyntaxPackage::sectionsOfCodeShallNotBeCommentedOutQuery() + } +} diff --git a/c/misra/src/rules/RULE-7-2/UOrUSuffixRepresentedInUnsignedType.ql b/c/misra/src/rules/RULE-7-2/UOrUSuffixRepresentedInUnsignedType.ql new file mode 100644 index 0000000000..b1dca9ac4a --- /dev/null +++ b/c/misra/src/rules/RULE-7-2/UOrUSuffixRepresentedInUnsignedType.ql @@ -0,0 +1,24 @@ +/** + * @id c/misra/u-or-u-suffix-represented-in-unsigned-type + * @name RULE-7-2: A 'U' or 'u' suffix shall be applied to all unsigned integers constants + * @description A 'U' or 'u' suffix shall be applied to all integer constants that are represented + * in an unsigned type. + * @kind problem + * @precision very-high + * @problem.severity recommendation + * @tags external/misra/id/rule-7-2 + * maintainability + * readability + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra + +from Literal l +where + not isExcluded(l, SyntaxPackage::uOrUSuffixRepresentedInUnsignedTypeQuery()) and + not l instanceof StringLiteral and + l.getImplicitlyConverted().getType().(IntegralType).isUnsigned() and + not exists(l.getValueText().toUpperCase().indexOf("U")) +select l, "Unsigned literal does not explicitly express sign with a 'U' or 'u' suffix." diff --git a/c/misra/src/rules/RULE-7-3/LowercaseCharacterLUsedInLiteralSuffix.ql b/c/misra/src/rules/RULE-7-3/LowercaseCharacterLUsedInLiteralSuffix.ql new file mode 100644 index 0000000000..311831d2b8 --- /dev/null +++ b/c/misra/src/rules/RULE-7-3/LowercaseCharacterLUsedInLiteralSuffix.ql @@ -0,0 +1,23 @@ +/** + * @id c/misra/lowercase-character-l-used-in-literal-suffix + * @name RULE-7-3: The lowercase character l shall not be used in a literal suffix + * @description Using the lowercase letter l in a literal suffix can be mistaken for other + * characters such as 1. + * @kind problem + * @precision very-high + * @problem.severity recommendation + * @tags external/misra/id/rule-7-3 + * maintainability + * readability + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra + +from Literal 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/test/qlpack.yml b/c/misra/test/qlpack.yml index 66838930da..c91e0ca32f 100644 --- a/c/misra/test/qlpack.yml +++ b/c/misra/test/qlpack.yml @@ -1,4 +1,4 @@ name: misra-c-coding-standards-tests -version: 2.0.0 +version: 2.1.0 libraryPathDependencies: misra-c-coding-standards extractor: cpp \ No newline at end of file diff --git a/c/misra/test/rules/DIR-4-5/IdentifiersInTheSameNameSpaceUnambiguous.testref b/c/misra/test/rules/DIR-4-5/IdentifiersInTheSameNameSpaceUnambiguous.testref new file mode 100644 index 0000000000..dffdbb26b8 --- /dev/null +++ b/c/misra/test/rules/DIR-4-5/IdentifiersInTheSameNameSpaceUnambiguous.testref @@ -0,0 +1 @@ +cpp/common/test/rules/differentidentifiersnottypographicallyunambiguous/DifferentIdentifiersNotTypographicallyUnambiguous.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-12-1/ImplicitPrecedenceOfOperatorsInExpression.expected b/c/misra/test/rules/RULE-12-1/ImplicitPrecedenceOfOperatorsInExpression.expected new file mode 100644 index 0000000000..3e3c114fd4 --- /dev/null +++ b/c/misra/test/rules/RULE-12-1/ImplicitPrecedenceOfOperatorsInExpression.expected @@ -0,0 +1,4 @@ +| test.c:21:12:21:34 | ... ? ... : ... | Operand $@ is not enclosed by parentheses. | test.c:21:12:21:19 | ... == ... | ... == ... | +| test.c:21:12:21:34 | ... ? ... : ... | Operand $@ is not enclosed by parentheses. | test.c:21:28:21:34 | ... - ... | ... - ... | +| test.c:27:7:27:19 | ... && ... | Operand $@ is not enclosed by parentheses. | test.c:27:7:27:13 | ... > ... | ... > ... | +| test.c:31:7:31:19 | ... && ... | Operand $@ is not enclosed by parentheses. | test.c:31:13:31:19 | ... < ... | ... < ... | diff --git a/c/misra/test/rules/RULE-12-1/ImplicitPrecedenceOfOperatorsInExpression.qlref b/c/misra/test/rules/RULE-12-1/ImplicitPrecedenceOfOperatorsInExpression.qlref new file mode 100644 index 0000000000..abadc93925 --- /dev/null +++ b/c/misra/test/rules/RULE-12-1/ImplicitPrecedenceOfOperatorsInExpression.qlref @@ -0,0 +1 @@ +rules/RULE-12-1/ImplicitPrecedenceOfOperatorsInExpression.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-12-1/UnenclosedSizeofOperand.expected b/c/misra/test/rules/RULE-12-1/UnenclosedSizeofOperand.expected new file mode 100644 index 0000000000..49dd3f842d --- /dev/null +++ b/c/misra/test/rules/RULE-12-1/UnenclosedSizeofOperand.expected @@ -0,0 +1 @@ +| test.c:4:12:4:20 | sizeof() | The operand of the sizeof operator is not enclosed in parentheses. | diff --git a/c/misra/test/rules/RULE-12-1/UnenclosedSizeofOperand.qlref b/c/misra/test/rules/RULE-12-1/UnenclosedSizeofOperand.qlref new file mode 100644 index 0000000000..de1b0d9e9b --- /dev/null +++ b/c/misra/test/rules/RULE-12-1/UnenclosedSizeofOperand.qlref @@ -0,0 +1 @@ +rules/RULE-12-1/UnenclosedSizeofOperand.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-12-1/test.c b/c/misra/test/rules/RULE-12-1/test.c new file mode 100644 index 0000000000..7937ec9c24 --- /dev/null +++ b/c/misra/test/rules/RULE-12-1/test.c @@ -0,0 +1,36 @@ +void test_sizeof() { + int l1 = sizeof(int); // COMPLIANT + int l2 = sizeof(l1 + 1); // COMPLIANT + int l3 = sizeof l1 + 1; // NON_COMPLIANT +} + +extern int f1(int); +extern int f2(int, int); + +void test_precedence(int p1, int p2) { + int l1, l2, l3, l4; + l1 + l2; // COMPLIANT + l1 + l2 + l3; // COMPLIANT + (l1 + l2) + l3; // COMPLIANT + l1 + l2 - l3 + l4; // COMPLIANT + (l1 + l2) - (l3 + l4); // COMPLIANT + + int l5 = f2(l1 + l2, l3); // COMPLIANT + + int l6 = (l1 == l2) ? l3 : (l3 - l4); // COMPLIANT + int l7 = l1 == l2 ? l3 : l3 - l4; // NON_COMPLIANT + + if (l1 && l2 && l3) // COMPLIANT + { + } + + if (l1 > l2 && l3) // NON_COMPLIANT + { + } + + if (l1 && l3 < l4 && l5) // NON_COMPLIANT + { + } + + int l8 = f1(l1) + l2; // COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-13-1/InitializerListsContainPersistentSideEffects.expected b/c/misra/test/rules/RULE-13-1/InitializerListsContainPersistentSideEffects.expected new file mode 100644 index 0000000000..8bf12c68c5 --- /dev/null +++ b/c/misra/test/rules/RULE-13-1/InitializerListsContainPersistentSideEffects.expected @@ -0,0 +1,3 @@ +| test.c:6:14:6:21 | {...} | Initializer list constains persistent $@ | test.c:6:19:6:20 | l1 | side effect | +| test.c:8:14:8:20 | {...} | Initializer list constains persistent $@ | test.c:8:16:8:19 | ... ++ | side effect | +| test.c:9:6:9:19 | {...} | Initializer list constains persistent $@ | test.c:9:15:9:18 | ... ++ | side effect | diff --git a/c/misra/test/rules/RULE-13-1/InitializerListsContainPersistentSideEffects.qlref b/c/misra/test/rules/RULE-13-1/InitializerListsContainPersistentSideEffects.qlref new file mode 100644 index 0000000000..9fc44ad8ef --- /dev/null +++ b/c/misra/test/rules/RULE-13-1/InitializerListsContainPersistentSideEffects.qlref @@ -0,0 +1 @@ +rules/RULE-13-1/InitializerListsContainPersistentSideEffects.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-13-1/test.c b/c/misra/test/rules/RULE-13-1/test.c new file mode 100644 index 0000000000..2619411cb9 --- /dev/null +++ b/c/misra/test/rules/RULE-13-1/test.c @@ -0,0 +1,10 @@ +extern void f1(int *); + +void test(int p1, int p2) { + volatile int l1; + + int l2[2] = {0, l1}; // NON_COMPLIANT + int l3[1] = {p1 + p2}; // COMPLIANT + int l4[1] = {p1++}; // NON_COMPLIANT + f1((int[1]){p1++}); // NON_COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-13-4/ResultOfAnAssignmentOperatorShouldNotBeUsed.expected b/c/misra/test/rules/RULE-13-4/ResultOfAnAssignmentOperatorShouldNotBeUsed.expected new file mode 100644 index 0000000000..57f90043e1 --- /dev/null +++ b/c/misra/test/rules/RULE-13-4/ResultOfAnAssignmentOperatorShouldNotBeUsed.expected @@ -0,0 +1,3 @@ +| test.c:7:7:7:12 | ... = ... | Use of an assignment operator's result. | +| test.c:11:11:11:16 | ... = ... | Use of an assignment operator's result. | +| test.c:13:8:13:13 | ... = ... | Use of an assignment operator's result. | diff --git a/c/misra/test/rules/RULE-13-4/ResultOfAnAssignmentOperatorShouldNotBeUsed.qlref b/c/misra/test/rules/RULE-13-4/ResultOfAnAssignmentOperatorShouldNotBeUsed.qlref new file mode 100644 index 0000000000..16d027d915 --- /dev/null +++ b/c/misra/test/rules/RULE-13-4/ResultOfAnAssignmentOperatorShouldNotBeUsed.qlref @@ -0,0 +1 @@ +rules/RULE-13-4/ResultOfAnAssignmentOperatorShouldNotBeUsed.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-13-4/test.c b/c/misra/test/rules/RULE-13-4/test.c new file mode 100644 index 0000000000..aeabb60fac --- /dev/null +++ b/c/misra/test/rules/RULE-13-4/test.c @@ -0,0 +1,14 @@ +void test() { + int l1, l2; + int l3[1]; + + l1 = l2; // COMPLIANT + + if (l1 = 1) // NON_COMPLIANT + { + } + + l1 = l3[l2 = 0]; // NON_COMPLIANT + + l1 = l2 = 0; // NON_COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-13-5/PossibleSuppressedSideEffectInLogicOperatorOperand.expected b/c/misra/test/rules/RULE-13-5/PossibleSuppressedSideEffectInLogicOperatorOperand.expected new file mode 100644 index 0000000000..7216a221f5 --- /dev/null +++ b/c/misra/test/rules/RULE-13-5/PossibleSuppressedSideEffectInLogicOperatorOperand.expected @@ -0,0 +1,3 @@ +| test.c:29:7:29:22 | ... && ... | The right hand operand generates the persistent $@ | test.c:13:3:13:13 | ... = ... | side effect | +| test.c:33:7:33:22 | ... && ... | The right hand operand generates the persistent $@ | test.c:19:3:19:13 | ... = ... | side effect | +| test.c:38:7:38:28 | ... \|\| ... | The right hand operand generates the persistent $@ | test.c:38:21:38:22 | l2 | side effect | diff --git a/c/misra/test/rules/RULE-13-5/PossibleSuppressedSideEffectInLogicOperatorOperand.qlref b/c/misra/test/rules/RULE-13-5/PossibleSuppressedSideEffectInLogicOperatorOperand.qlref new file mode 100644 index 0000000000..0098c2d0bf --- /dev/null +++ b/c/misra/test/rules/RULE-13-5/PossibleSuppressedSideEffectInLogicOperatorOperand.qlref @@ -0,0 +1 @@ +rules/RULE-13-5/PossibleSuppressedSideEffectInLogicOperatorOperand.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-13-5/test.c b/c/misra/test/rules/RULE-13-5/test.c new file mode 100644 index 0000000000..7690e9ae04 --- /dev/null +++ b/c/misra/test/rules/RULE-13-5/test.c @@ -0,0 +1,44 @@ +#include + +int g1; + +int f1(int p1) { + int l1 = p1 + 1; // Non-persistent side-effect for the caller of f1. + + return l1; +} + +int f2(int p1) { + static int l1 = 0; + l1 = p1 + 1; // Persistent side-effect for the caller of f2. + + return l1; +} + +int f3(int p1) { + g1 = p1 + 1; // Persistent side-effect for the caller of f3. + + return g1; +} + +void test(int p1) { + if (g1 && f1(p1) > 0) // COMPLIANT + { + } + + if (g1 && f2(p1) > 0) // NON_COMPLIANT + { + } + + if (g1 && f3(p1) > 0) // NON_COMPLIANT + { + } + + volatile int l1, l2; + if ((l1 == 0) || (l2 == 0)) // NON_COMPLIANT + { + } + + int (*fp)(int) = NULL; + (fp != NULL) && (*fp)(0); // NON_COMPLIANT[FALSE_NEGATIVE] +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-13-6/SizeofOperandWithSideEffect.expected b/c/misra/test/rules/RULE-13-6/SizeofOperandWithSideEffect.expected new file mode 100644 index 0000000000..bf5a01fcbc --- /dev/null +++ b/c/misra/test/rules/RULE-13-6/SizeofOperandWithSideEffect.expected @@ -0,0 +1,5 @@ +| test.c:13:12:13:23 | sizeof() | The sizeof $@ is not evaluated but has a potential $@. | test.c:13:19:13:22 | ... ++ | operand | test.c:13:19:13:22 | ... ++ | side effect | +| test.c:14:12:14:23 | sizeof() | The sizeof $@ is not evaluated but has a potential $@. | test.c:14:19:14:22 | ... ++ | operand | test.c:14:19:14:22 | ... ++ | side effect | +| test.c:16:12:16:26 | sizeof() | The sizeof $@ is not evaluated but has a potential $@. | test.c:16:19:16:20 | call to f1 | operand | test.c:16:19:16:20 | call to f1 | side effect | +| test.c:17:12:17:23 | sizeof() | The sizeof $@ is not evaluated but has a potential $@. | test.c:17:19:17:20 | call to f2 | operand | test.c:17:19:17:20 | call to f2 | side effect | +| test.c:20:12:20:21 | sizeof() | The sizeof $@ is not evaluated but has a potential $@. | test.c:20:19:20:20 | l8 | operand | test.c:20:19:20:20 | l8 | side effect | diff --git a/c/misra/test/rules/RULE-13-6/SizeofOperandWithSideEffect.qlref b/c/misra/test/rules/RULE-13-6/SizeofOperandWithSideEffect.qlref new file mode 100644 index 0000000000..85544bb700 --- /dev/null +++ b/c/misra/test/rules/RULE-13-6/SizeofOperandWithSideEffect.qlref @@ -0,0 +1 @@ +rules/RULE-13-6/SizeofOperandWithSideEffect.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-13-6/test.c b/c/misra/test/rules/RULE-13-6/test.c new file mode 100644 index 0000000000..f1af4de696 --- /dev/null +++ b/c/misra/test/rules/RULE-13-6/test.c @@ -0,0 +1,21 @@ + +int f1(int *p1) { return *p1++; } +extern int f2(); + +int g1; + +void test(int p1) { + int l1 = sizeof(int); // COMPLIANT + volatile int l2; + + int l3 = sizeof(l2); // COMPLIANT - per exception + + int l4 = sizeof(g1++); // NON_COMPLIANT + int l5 = sizeof(p1++); // NON_COMPLIANT + + int l6 = sizeof(f1(&l1)); // NON_COMPLIANT + int l7 = sizeof(f2()); // NON_COMPLIANT + + volatile int l8[p1]; + int l9 = sizeof(l8); // NON_COMPLIANT +} diff --git a/c/misra/test/rules/RULE-3-1/CharacterSequencesAndUsedWithinAComment.expected b/c/misra/test/rules/RULE-3-1/CharacterSequencesAndUsedWithinAComment.expected new file mode 100644 index 0000000000..5e876cecc3 --- /dev/null +++ b/c/misra/test/rules/RULE-3-1/CharacterSequencesAndUsedWithinAComment.expected @@ -0,0 +1,3 @@ +| test.c:9:1:9:8 | /* /* */ | Comment contains an illegal sequence '/*' | +| test.c:12:1:12:8 | /* // */ | Comment contains an illegal sequence '//' | +| test.c:21:1:21:7 | // /* | Comment contains an illegal sequence '/*' | diff --git a/c/misra/test/rules/RULE-3-1/CharacterSequencesAndUsedWithinAComment.qlref b/c/misra/test/rules/RULE-3-1/CharacterSequencesAndUsedWithinAComment.qlref new file mode 100644 index 0000000000..a61b65c8df --- /dev/null +++ b/c/misra/test/rules/RULE-3-1/CharacterSequencesAndUsedWithinAComment.qlref @@ -0,0 +1 @@ +rules/RULE-3-1/CharacterSequencesAndUsedWithinAComment.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-3-1/test.c b/c/misra/test/rules/RULE-3-1/test.c new file mode 100644 index 0000000000..c1a135f972 --- /dev/null +++ b/c/misra/test/rules/RULE-3-1/test.c @@ -0,0 +1,23 @@ +// clang-format off +// Note that in this file the COMPLIANT/NON_COMPLIANT markers are above the +// item + +// COMPLIANT +/* ... */ + +// NON_COMPLIANT +/* /* */ + +// NON_COMPLIANT +/* // */ + +// COMPLIANT +// // / / + +// COMPLIANT +// / + +// NON_COMPLIANT +// /* + +void f(){} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-3-2/LineSplicingUsedInComments.expected b/c/misra/test/rules/RULE-3-2/LineSplicingUsedInComments.expected new file mode 100644 index 0000000000..dd396cd9ed --- /dev/null +++ b/c/misra/test/rules/RULE-3-2/LineSplicingUsedInComments.expected @@ -0,0 +1,4 @@ +| test.c:6:12:7:13 | // \\\n if(a > 1) | Line splicing in //-style comment. | +| test.c:16:12:17:13 | // \\\\\n if(a > 1) | Line splicing in //-style comment. | +| test.c:26:12:27:13 | // \\\n if(a > 1) | Line splicing in //-style comment. | +| test.c:36:12:37:13 | // \\\\\n if(a > 1) | Line splicing in //-style comment. | diff --git a/c/misra/test/rules/RULE-3-2/LineSplicingUsedInComments.qlref b/c/misra/test/rules/RULE-3-2/LineSplicingUsedInComments.qlref new file mode 100644 index 0000000000..469fabd28c --- /dev/null +++ b/c/misra/test/rules/RULE-3-2/LineSplicingUsedInComments.qlref @@ -0,0 +1 @@ +rules/RULE-3-2/LineSplicingUsedInComments.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-3-2/test.c b/c/misra/test/rules/RULE-3-2/test.c new file mode 100644 index 0000000000..a46b44fc61 --- /dev/null +++ b/c/misra/test/rules/RULE-3-2/test.c @@ -0,0 +1,64 @@ +// clang-format off + +void f0(){ + + // NON_COMPLIANT + int a; // \ + if(a > 1) + { + a++; + } +} + +void f1(){ + + // NON_COMPLIANT + int a; // \\ + if(a > 1) + { + a++; + } +} + +void f2(){ + + // COMPLIANT[FALSE_POSITIVE] - has a space + int a; // \ + if(a > 1) + { + a++; + } +} + +void f3(){ + + // COMPLIANT[FALSE_POSITIVE] - has a space + int a; // \\ + if(a > 1) + { + a++; + } +} + + + + +void f4(){ + + // COMPLIANT + int a; // \ n + if(a > 1) + { + a++; + } +} + +void f5(){ + + // COMPLIANT + int a; // \\ n + if(a > 1) + { + a++; + } +} diff --git a/c/misra/test/rules/RULE-4-1/OctalAndHexadecimalEscapeSequencesNotTerminated.expected b/c/misra/test/rules/RULE-4-1/OctalAndHexadecimalEscapeSequencesNotTerminated.expected new file mode 100644 index 0000000000..39d5aa5d85 --- /dev/null +++ b/c/misra/test/rules/RULE-4-1/OctalAndHexadecimalEscapeSequencesNotTerminated.expected @@ -0,0 +1,21 @@ +| test.c:9:18:9:24 | \u001aG | Invalid hexadecimal escape in string literal at '\\x1AG"'. | +| test.c:12:18:12:23 | \u00029 | Invalid octal escape in string literal at '\\029"'. | +| test.c:15:18:15:24 | \n7 | Invalid octal escape in string literal at '\\0127"'. | +| test.c:16:18:16:24 | \r7 | Invalid octal escape in string literal at '\\0157"'. | +| test.c:18:19:18:29 | \n\n9 | Invalid octal escape in string literal at '\\0129"'. | +| test.c:19:19:19:28 | \n\u00019 | Invalid octal escape in string literal at '\\019"'. | +| test.c:22:19:22:31 | \nAAA\u000f | Invalid octal escape in string literal at '\\012AAA\\017"'. | +| test.c:25:19:25:39 | Some Data \n\u000fA | Invalid octal escape in string literal at '\\017A"'. | +| test.c:26:19:27:21 | Some Data \n\u000fA5 | Invalid octal escape in string literal at '\\017A"\n "5"'. | +| test.c:28:19:30:25 | Some Data \n\u000fA\n1 | Invalid octal escape in string literal at '\\0121"'. | +| test.c:34:19:35:26 | \u0011G\u00012 | Invalid octal escape in string literal at '\\0012"'. | +| test.c:36:19:37:25 | \u0011GG\u0001 | Invalid hexadecimal escape in string literal at '\\x11G"\n "G\\001"'. | +| test.c:38:19:39:26 | \u0011GG\u00013 | Invalid hexadecimal escape in string literal at '\\x11G"\n "G\\0013"'. | +| test.c:38:19:39:26 | \u0011GG\u00013 | Invalid octal escape in string literal at '\\0013"'. | +| test.c:45:18:45:42 | Some Data \n\u000fA5 | Invalid octal escape in string literal at '\\017A" "5"'. | +| test.c:46:18:46:49 | Some Data \n\u000fA\n1 | Invalid octal escape in string literal at '\\0121"'. | +| test.c:48:18:48:32 | \u0011G\u00012 | Invalid octal escape in string literal at '\\0012"'. | +| test.c:49:18:49:32 | \u0011GG\u0001 | Invalid hexadecimal escape in string literal at '\\x11G" "G\\001"'. | +| test.c:50:18:50:33 | \u0011GG\u00013 | Invalid hexadecimal escape in string literal at '\\x11G" "G\\0013"'. | +| test.c:50:18:50:33 | \u0011GG\u00013 | Invalid octal escape in string literal at '\\0013"'. | +| test.c:53:11:53:16 | 10 | Invalid hexadecimal escape in string literal at '\\x0a''. | diff --git a/c/misra/test/rules/RULE-4-1/OctalAndHexadecimalEscapeSequencesNotTerminated.qlref b/c/misra/test/rules/RULE-4-1/OctalAndHexadecimalEscapeSequencesNotTerminated.qlref new file mode 100644 index 0000000000..fbdd187532 --- /dev/null +++ b/c/misra/test/rules/RULE-4-1/OctalAndHexadecimalEscapeSequencesNotTerminated.qlref @@ -0,0 +1 @@ +rules/RULE-4-1/OctalAndHexadecimalEscapeSequencesNotTerminated.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-4-1/test.c b/c/misra/test/rules/RULE-4-1/test.c new file mode 100644 index 0000000000..4a0dcaa6ac --- /dev/null +++ b/c/misra/test/rules/RULE-4-1/test.c @@ -0,0 +1,53 @@ +const char *a1 = "\x11" + "G"; // COMPLIANT + +const char *a2 = "\x1" + "G"; // COMPLIANT + +const char *a3 = "\x1A"; // COMPLIANT + +const char *a4 = "\x1AG"; // NON_COMPLIANT + +const char *a5 = "\021"; // COMPLIANT +const char *a6 = "\029"; // NON_COMPLIANT +const char *a7 = "\0" + "0"; // COMPLIANT +const char *a8 = "\0127"; // NON_COMPLIANT +const char *a9 = "\0157"; // NON_COMPLIANT + +const char *a10 = "\012\0129"; // NON_COMPLIANT (1x) +const char *a11 = "\012\019"; // NON_COMPLIANT +const char *a12 = "\012\017"; // COMPLIANT + +const char *a13 = "\012AAA\017"; // NON_COMPLIANT (1x) + +const char *a14 = "Some Data \012\017"; // COMPLIANT +const char *a15 = "Some Data \012\017A"; // NON_COMPLIANT (1x) +const char *a16 = "Some Data \012\017A" + "5"; // NON_COMPLIANT (1x) +const char *a17 = "Some Data \012\017" + "A" + "\0121"; // NON_COMPLIANT (1x) + +const char *a18 = "\x11" + "G\001"; // COMPLIANT +const char *a19 = "\x11" + "G\0012"; // NON_COMPLIANT (1x) +const char *a20 = "\x11G" + "G\001"; // NON_COMPLIANT (1x) +const char *a21 = "\x11G" + "G\0013"; // NON_COMPLIANT (2x) + +// clang-format off +const char *b1 = "\x11" "G"; // COMPLIANT +const char *b2 = "\x1" "G"; // COMPLIANT +const char *b3 = "\0" "0"; // COMPLIANT +const char *b4 = "Some Data \012\017A" "5"; // NON_COMPLIANT (1x) +const char *b5 = "Some Data \012\017" "A" "\0121"; // NON_COMPLIANT (1x) +const char *b6 = "\x11" "G\001"; // COMPLIANT +const char *b7 = "\x11" "G\0012"; // NON_COMPLIANT (1x) +const char *b8 = "\x11G" "G\001"; // NON_COMPLIANT (1x) +const char *b9 = "\x11G" "G\0013"; // NON_COMPLIANT (2x) + +char c1 = '\023'; // COMPLIANT +char c2 = '\x0a'; // COMPLIANT diff --git a/c/misra/test/rules/RULE-4-4/SectionsOfCodeShallNotBeCommentedOut.testref b/c/misra/test/rules/RULE-4-4/SectionsOfCodeShallNotBeCommentedOut.testref new file mode 100644 index 0000000000..303a38a19b --- /dev/null +++ b/c/misra/test/rules/RULE-4-4/SectionsOfCodeShallNotBeCommentedOut.testref @@ -0,0 +1 @@ +cpp/common/test/rules/sectionsofcodeshallnotbecommentedout/SectionsOfCodeShallNotBeCommentedOut.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-7-2/UOrUSuffixRepresentedInUnsignedType.expected b/c/misra/test/rules/RULE-7-2/UOrUSuffixRepresentedInUnsignedType.expected new file mode 100644 index 0000000000..4a131f4eaa --- /dev/null +++ b/c/misra/test/rules/RULE-7-2/UOrUSuffixRepresentedInUnsignedType.expected @@ -0,0 +1,5 @@ +| test.c:8:20:8:21 | 0 | Unsigned literal does not explicitly express sign with a 'U' or 'u' suffix. | +| test.c:9:20:9:22 | 0 | Unsigned literal does not explicitly express sign with a 'U' or 'u' suffix. | +| test.c:33:6:33:6 | 1 | Unsigned literal does not explicitly express sign with a 'U' or 'u' suffix. | +| test.c:35:6:35:9 | 1 | Unsigned literal does not explicitly express sign with a 'U' or 'u' suffix. | +| test.c:37:6:37:8 | 1 | Unsigned literal does not explicitly express sign with a 'U' or 'u' suffix. | diff --git a/c/misra/test/rules/RULE-7-2/UOrUSuffixRepresentedInUnsignedType.qlref b/c/misra/test/rules/RULE-7-2/UOrUSuffixRepresentedInUnsignedType.qlref new file mode 100644 index 0000000000..bb517fb7e3 --- /dev/null +++ b/c/misra/test/rules/RULE-7-2/UOrUSuffixRepresentedInUnsignedType.qlref @@ -0,0 +1 @@ +rules/RULE-7-2/UOrUSuffixRepresentedInUnsignedType.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-7-2/test.c b/c/misra/test/rules/RULE-7-2/test.c new file mode 100644 index 0000000000..da62825755 --- /dev/null +++ b/c/misra/test/rules/RULE-7-2/test.c @@ -0,0 +1,39 @@ + +long a1 = 0L; // COMPLIANT +long a2 = 0LL; // COMPLIANT +long a3 = 0uL; // COMPLIANT +long a4 = 0Lu; // COMPLIANT +long a5 = 0LU; // COMPLIANT + +unsigned long b1 = 0L; // NON_COMPLIANT +unsigned long b2 = 0LL; // NON_COMPLIANT +unsigned long b3 = 0uL; // COMPLIANT +unsigned long b4 = 0Lu; // COMPLIANT +unsigned long b5 = 0LU; // COMPLIANT + +signed long c1 = 0L; // COMPLIANT +signed long c2 = 0LL; // COMPLIANT +signed long c3 = 0uL; // COMPLIANT +signed long c4 = 0Lu; // COMPLIANT +signed long c5 = 0LU; // COMPLIANT + +void f0(int a) {} + +void f1(unsigned int a) {} + +void f2() { + + f0(1); // COMPLIANT + f0(1U); // COMPLIANT + f0(0x01); // COMPLIANT + f0(0x01U); // COMPLIANT + f0(001); // COMPLIANT + f0(001U); // COMPLIANT + + f1(1); // NON_COMPLIANT + f1(1U); // COMPLIANT + f1(0x01); // NON_COMPLIANT + f1(0x01U); // COMPLIANT + f1(001); // NON_COMPLIANT + f1(001U); // COMPLIANT +} diff --git a/c/misra/test/rules/RULE-7-3/LowercaseCharacterLUsedInLiteralSuffix.expected b/c/misra/test/rules/RULE-7-3/LowercaseCharacterLUsedInLiteralSuffix.expected new file mode 100644 index 0000000000..279fd7e621 --- /dev/null +++ b/c/misra/test/rules/RULE-7-3/LowercaseCharacterLUsedInLiteralSuffix.expected @@ -0,0 +1,16 @@ +| test.c:3:10:3:11 | 0 | Lowercase 'l' used as a literal suffix. | +| test.c:4:10:4:12 | 0 | Lowercase 'l' used as a literal suffix. | +| test.c:7:10:7:12 | 0 | Lowercase 'l' used as a literal suffix. | +| test.c:8:10:8:12 | 0 | Lowercase 'l' used as a literal suffix. | +| test.c:13:11:13:12 | 0 | Lowercase 'l' used as a literal suffix. | +| test.c:14:11:14:13 | 0 | Lowercase 'l' used as a literal suffix. | +| test.c:17:11:17:13 | 0 | Lowercase 'l' used as a literal suffix. | +| test.c:18:11:18:13 | 0 | Lowercase 'l' used as a literal suffix. | +| test.c:23:10:23:14 | 1 | Lowercase 'l' used as a literal suffix. | +| test.c:24:10:24:15 | 1 | Lowercase 'l' used as a literal suffix. | +| test.c:27:10:27:15 | 1 | Lowercase 'l' used as a literal suffix. | +| test.c:28:10:28:15 | 1 | Lowercase 'l' used as a literal suffix. | +| test.c:33:11:33:14 | 1 | Lowercase 'l' used as a literal suffix. | +| test.c:34:11:34:15 | 1 | Lowercase 'l' used as a literal suffix. | +| test.c:37:11:37:15 | 1 | Lowercase 'l' used as a literal suffix. | +| test.c:38:11:38:15 | 1 | Lowercase 'l' used as a literal suffix. | diff --git a/c/misra/test/rules/RULE-7-3/LowercaseCharacterLUsedInLiteralSuffix.qlref b/c/misra/test/rules/RULE-7-3/LowercaseCharacterLUsedInLiteralSuffix.qlref new file mode 100644 index 0000000000..464efc3b2f --- /dev/null +++ b/c/misra/test/rules/RULE-7-3/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/test.c b/c/misra/test/rules/RULE-7-3/test.c new file mode 100644 index 0000000000..00a61817aa --- /dev/null +++ b/c/misra/test/rules/RULE-7-3/test.c @@ -0,0 +1,44 @@ + +int a1 = 0L; // COMPLIANT +int a2 = 0l; // NON_COMPLIANT +int a3 = 0ll; // NON_COMPLIANT +int a4 = 0LL; // COMPLIANT +int a5 = 0uL; // COMPLIANT +int a6 = 0ul; // NON_COMPLIANT +int a7 = 0lu; // NON_COMPLIANT +int a8 = 0Lu; // COMPLIANT +int a9 = 0LU; // COMPLIANT + +long b1 = 0L; // COMPLIANT +long b2 = 0l; // NON_COMPLIANT +long b3 = 0ll; // NON_COMPLIANT +long b4 = 0LL; // COMPLIANT +long b5 = 0uL; // COMPLIANT +long b6 = 0ul; // NON_COMPLIANT +long b7 = 0lu; // NON_COMPLIANT +long b8 = 0Lu; // COMPLIANT +long b9 = 0LU; // COMPLIANT + +int c1 = 0x01L; // COMPLIANT +int c2 = 0x01l; // NON_COMPLIANT +int c3 = 0x01ll; // NON_COMPLIANT +int c4 = 0x01LL; // COMPLIANT +int c5 = 0x01uL; // COMPLIANT +int c6 = 0x01ul; // NON_COMPLIANT +int c7 = 0x01lu; // NON_COMPLIANT +int c8 = 0x01Lu; // COMPLIANT +int c9 = 0x01LU; // COMPLIANT + +long d1 = 001L; // COMPLIANT +long d2 = 001l; // NON_COMPLIANT +long d3 = 001ll; // NON_COMPLIANT +long d4 = 001LL; // COMPLIANT +long d5 = 001uL; // COMPLIANT +long d6 = 001ul; // NON_COMPLIANT +long d7 = 001lu; // NON_COMPLIANT +long d8 = 001Lu; // COMPLIANT +long d9 = 001LU; // COMPLIANT + +char *e1 = ""; +char *e2 = "ul"; +char *e3 = "UL"; diff --git a/c/options b/c/options index 367678d1cf..e3aa5bdbf1 100644 --- a/c/options +++ b/c/options @@ -1 +1 @@ -semmle-extractor-options:--clangg -std=c99 --edg --diag_error=implicit_func_decl -nostdinc -I../../../../common/test/includes/standard-library \ No newline at end of file +semmle-extractor-options:--clang -std=c11 --edg --diag_error=implicit_func_decl -nostdinc -I../../../../common/test/includes/standard-library \ No newline at end of file diff --git a/codeql_modules/codeql b/codeql_modules/codeql index 06b36f742e..a1cdf256ad 160000 --- a/codeql_modules/codeql +++ b/codeql_modules/codeql @@ -1 +1 @@ -Subproject commit 06b36f742e88b610e0c2b75e2668603fc3a0f359 +Subproject commit a1cdf256ad6b7c3e9984db9069671647e5f47921 diff --git a/cpp/autosar/src/qlpack.yml b/cpp/autosar/src/qlpack.yml index cdc63a6ec0..21a87c80cc 100644 --- a/cpp/autosar/src/qlpack.yml +++ b/cpp/autosar/src/qlpack.yml @@ -1,4 +1,4 @@ name: autosar-cpp-coding-standards -version: 2.0.0 +version: 2.1.0 suites: codeql-suites libraryPathDependencies: common-cpp-coding-standards diff --git a/cpp/autosar/src/rules/A12-8-1/CopyConstructorShallOnlyCopyObject.ql b/cpp/autosar/src/rules/A12-8-1/CopyConstructorShallOnlyCopyObject.ql index 526fef161a..9f767fe054 100644 --- a/cpp/autosar/src/rules/A12-8-1/CopyConstructorShallOnlyCopyObject.ql +++ b/cpp/autosar/src/rules/A12-8-1/CopyConstructorShallOnlyCopyObject.ql @@ -17,6 +17,8 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.SideEffect import codingstandards.cpp.SideEffect::PathGraph +import codingstandards.cpp.sideeffect.Customizations +import codingstandards.cpp.sideeffect.DefaultEffects import codingstandards.cpp.Constructor import codingstandards.cpp.Operator diff --git a/cpp/autosar/src/rules/A12-8-1/MoveConstructorShallOnlyMoveObject.ql b/cpp/autosar/src/rules/A12-8-1/MoveConstructorShallOnlyMoveObject.ql index 15c0955609..25b02ad759 100644 --- a/cpp/autosar/src/rules/A12-8-1/MoveConstructorShallOnlyMoveObject.ql +++ b/cpp/autosar/src/rules/A12-8-1/MoveConstructorShallOnlyMoveObject.ql @@ -16,6 +16,7 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.SideEffect import codingstandards.cpp.SideEffect::PathGraph +import codingstandards.cpp.sideeffect.Customizations import codingstandards.cpp.Constructor class ModifyClassObjectMember extends GlobalSideEffect::Range { diff --git a/cpp/autosar/src/rules/A13-1-3/UserDefinedLiteralsOperatorsShallNotHaveSideEffects.ql b/cpp/autosar/src/rules/A13-1-3/UserDefinedLiteralsOperatorsShallNotHaveSideEffects.ql index e4ef53df09..0cbb9f101e 100644 --- a/cpp/autosar/src/rules/A13-1-3/UserDefinedLiteralsOperatorsShallNotHaveSideEffects.ql +++ b/cpp/autosar/src/rules/A13-1-3/UserDefinedLiteralsOperatorsShallNotHaveSideEffects.ql @@ -16,6 +16,7 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.UserDefinedLiteral import codingstandards.cpp.SideEffect +import codingstandards.cpp.sideeffect.DefaultEffects from UserDefinedLiteral udl, SideEffect e where diff --git a/cpp/autosar/src/rules/A2-7-2/SectionsOfCodeCommentedOut.ql b/cpp/autosar/src/rules/A2-7-2/SectionsOfCodeCommentedOut.ql index 7252bebccc..f47085b54d 100644 --- a/cpp/autosar/src/rules/A2-7-2/SectionsOfCodeCommentedOut.ql +++ b/cpp/autosar/src/rules/A2-7-2/SectionsOfCodeCommentedOut.ql @@ -16,8 +16,10 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.CommentedOutCode +import codingstandards.cpp.rules.sectionsofcodeshallnotbecommentedout.SectionsOfCodeShallNotBeCommentedOut -from CommentedOutCode comment -where not isExcluded(comment, CommentsPackage::sectionsOfCodeCommentedOutQuery()) -select comment, "This comment appears to contain commented-out code." +class SectionsOfCodeCommentedOutQuery extends SectionsOfCodeShallNotBeCommentedOutSharedQuery { + SectionsOfCodeCommentedOutQuery() { + this = CommentsPackage::sectionsOfCodeCommentedOutQuery() + } +} diff --git a/cpp/autosar/src/rules/A5-0-1/ExpressionShouldNotRelyOnOrderOfEvaluation.ql b/cpp/autosar/src/rules/A5-0-1/ExpressionShouldNotRelyOnOrderOfEvaluation.ql index 236b6e062d..656613003e 100644 --- a/cpp/autosar/src/rules/A5-0-1/ExpressionShouldNotRelyOnOrderOfEvaluation.ql +++ b/cpp/autosar/src/rules/A5-0-1/ExpressionShouldNotRelyOnOrderOfEvaluation.ql @@ -16,6 +16,7 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.SideEffect +import codingstandards.cpp.sideeffect.DefaultEffects import codingstandards.cpp.Ordering import codingstandards.cpp.orderofevaluation.VariableAccessOrdering diff --git a/cpp/autosar/src/rules/A6-2-1/CopyOperatorShallOnlyCopyObject.ql b/cpp/autosar/src/rules/A6-2-1/CopyOperatorShallOnlyCopyObject.ql index 4b1dd166cf..428a147644 100644 --- a/cpp/autosar/src/rules/A6-2-1/CopyOperatorShallOnlyCopyObject.ql +++ b/cpp/autosar/src/rules/A6-2-1/CopyOperatorShallOnlyCopyObject.ql @@ -17,6 +17,8 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.SideEffect import codingstandards.cpp.SideEffect::PathGraph +import codingstandards.cpp.sideeffect.DefaultEffects +import codingstandards.cpp.sideeffect.Customizations import codingstandards.cpp.Operator class ModifyClassObjectMember extends GlobalSideEffect::Range { diff --git a/cpp/autosar/src/rules/A6-2-1/MoveOperatorShallOnlyMoveObject.ql b/cpp/autosar/src/rules/A6-2-1/MoveOperatorShallOnlyMoveObject.ql index 5733c54607..090390c8b0 100644 --- a/cpp/autosar/src/rules/A6-2-1/MoveOperatorShallOnlyMoveObject.ql +++ b/cpp/autosar/src/rules/A6-2-1/MoveOperatorShallOnlyMoveObject.ql @@ -16,6 +16,7 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.SideEffect import codingstandards.cpp.SideEffect::PathGraph +import codingstandards.cpp.sideeffect.Customizations import codingstandards.cpp.Operator class ModifyClassObjectMember extends GlobalSideEffect::Range { diff --git a/cpp/autosar/src/rules/M0-1-8/FunctionsWithVoidReturnTypeShallHaveExternalSideEffects.ql b/cpp/autosar/src/rules/M0-1-8/FunctionsWithVoidReturnTypeShallHaveExternalSideEffects.ql index 17c7f1af7c..e5351af0f2 100644 --- a/cpp/autosar/src/rules/M0-1-8/FunctionsWithVoidReturnTypeShallHaveExternalSideEffects.ql +++ b/cpp/autosar/src/rules/M0-1-8/FunctionsWithVoidReturnTypeShallHaveExternalSideEffects.ql @@ -16,6 +16,9 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.SideEffect +import codingstandards.cpp.sideeffect.DefaultEffects +import codingstandards.cpp.sideeffect.Customizations +import codingstandards.cpp.exceptions.ExceptionFlow class ThrownExceptionNotCaughtInSameFunction extends GlobalSideEffect::Range { ThrownExceptionNotCaughtInSameFunction() { diff --git a/cpp/autosar/src/rules/M2-10-1/DifferentIdentifiersNotTypographicallyUnambiguous.ql b/cpp/autosar/src/rules/M2-10-1/DifferentIdentifiersNotTypographicallyUnambiguous.ql index 3fa4b07492..9fe2bc2887 100644 --- a/cpp/autosar/src/rules/M2-10-1/DifferentIdentifiersNotTypographicallyUnambiguous.ql +++ b/cpp/autosar/src/rules/M2-10-1/DifferentIdentifiersNotTypographicallyUnambiguous.ql @@ -17,91 +17,10 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.Scope +import codingstandards.cpp.rules.differentidentifiersnottypographicallyunambiguous.DifferentIdentifiersNotTypographicallyUnambiguous -string getCanon(UserVariable v) { - result = - v.getName() - .toLowerCase() - .replaceAll("_", "") - .regexpReplaceAll("[il]", "1") - .replaceAll("s", "5") - .replaceAll("z", "2") - .replaceAll("b", "8") - .replaceAll("h", "n") - .replaceAll("m", "rn") - .replaceAll("o", "0") +class DifferentIdentifiersNotTypographicallyUnambiguousQuery extends DifferentIdentifiersNotTypographicallyUnambiguousSharedQuery { + DifferentIdentifiersNotTypographicallyUnambiguousQuery() { + this = NamingPackage::differentIdentifiersNotTypographicallyUnambiguousQuery() + } } - -string step1(string s) { - s = "ACDEFGHJKLMNPQRTUVWXY".charAt(_) and result = s.toLowerCase() - or - s = "O" and result in ["0", "o"] - or - s = "I" and result in ["1", "l", "i"] - or - s = "l" and result = "1" - or - s = "S" and result in ["5", "s"] - or - s = "Z" and result in ["2", "z"] - or - s = "n" and result = "h" - or - s = "B" and result in ["8", "b"] -} - -string step2(string s) { s = "m_" and result = "rn" } - -predicate violation(UserVariable v1, UserVariable v2) { - v2 = getPotentialScopeOfVariable(v1) and - exists(string s1, string s2 | - // over-approximate a match, because it is cheaper to compute - getCanon(v1) = getCanon(v2) and - v1 != v2 and - not v1.getName() = v2.getName() and - // expand 'm' to 'm_' to match either 'm_' or 'rn' - s1 = v1.getName().replaceAll("_", "").replaceAll("m", "m_") and - s2 = v2.getName().replaceAll("_", "").replaceAll("m", "m_") and - // at this point the strings must have equal length, the substitutions do not expand nor contract the string - s1.length() = s2.length() and - forall(int i | i in [0 .. s1.length() - 1] | - exists(string c1, string c2 | - c1 = s1.charAt(i) and - c2 = s2.charAt(i) - | - c1 = c2 - or - step1(c1) = c2 // c1 and c2 are typographically unambiguous - or - step1(c2) = c1 // c1 and c2 are typographically unamibiguous - or - // Check for '[m]_' = '[r]n' and 'm[_]' = 'r[n]' where the character in brackets - // denote the character at index i. - // Note: because of the `forall` we need to make sure the above conjuction is true since 'n' = '_' is a contradiction. - exists(string c1_2, string c2_2 | - c1_2 = c1 + s1.charAt(i + 1) and - c2_2 = c2 + s2.charAt(i + 1) - or - c1_2 = s1.charAt(i - 1) + c1 and - c2_2 = s2.charAt(i - 1) + c2 - | - step2(c1_2) = c2_2 or - step2(c2_2) = c1_2 - ) - ) - ) - ) -} - -from UserVariable v1, UserVariable v2 -where - not isExcluded(v1) and - not isExcluded(v2, NamingPackage::differentIdentifiersNotTypographicallyUnambiguousQuery()) and - // Exclude member variables because it is common to have function/construct parameters named after member variables.class - not (v1.isMember() or v2.isMember()) and - // Exclude variables that are fully or partially generated by macro's. The final name is not visible to the developer. - not (v1.isAffectedByMacro() or v2.isAffectedByMacro()) and - violation(v1, v2) -select v2, "The identifier $@ is not typographically unambiguous from the identifier $@", v2, - v2.getName(), v1, v1.getName() diff --git a/cpp/autosar/src/rules/M3-4-1/UnnecessaryExposedIdentifierDeclaration.ql b/cpp/autosar/src/rules/M3-4-1/UnnecessaryExposedIdentifierDeclaration.ql index 82400b9cb1..6a99cb820a 100644 --- a/cpp/autosar/src/rules/M3-4-1/UnnecessaryExposedIdentifierDeclaration.ql +++ b/cpp/autosar/src/rules/M3-4-1/UnnecessaryExposedIdentifierDeclaration.ql @@ -17,6 +17,7 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.Scope import codingstandards.cpp.SideEffect +import codingstandards.cpp.sideeffect.Customizations class ExternalCall extends Call { ExternalCall() { diff --git a/cpp/autosar/src/rules/M5-14-1/RightHandOperandOfALogicalAndOperatorsContainSideEffects.ql b/cpp/autosar/src/rules/M5-14-1/RightHandOperandOfALogicalAndOperatorsContainSideEffects.ql index 9772d2effa..0819259a25 100644 --- a/cpp/autosar/src/rules/M5-14-1/RightHandOperandOfALogicalAndOperatorsContainSideEffects.ql +++ b/cpp/autosar/src/rules/M5-14-1/RightHandOperandOfALogicalAndOperatorsContainSideEffects.ql @@ -17,6 +17,7 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.SideEffect +import codingstandards.cpp.sideeffect.DefaultEffects from BinaryLogicalOperation op, Expr rhs where diff --git a/cpp/autosar/src/rules/M5-3-4/EvaluationOfTheOperandToTheSizeofOperatorContainSideEffects.ql b/cpp/autosar/src/rules/M5-3-4/EvaluationOfTheOperandToTheSizeofOperatorContainSideEffects.ql index af9cede51d..ad029c6c25 100644 --- a/cpp/autosar/src/rules/M5-3-4/EvaluationOfTheOperandToTheSizeofOperatorContainSideEffects.ql +++ b/cpp/autosar/src/rules/M5-3-4/EvaluationOfTheOperandToTheSizeofOperatorContainSideEffects.ql @@ -16,6 +16,7 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.SideEffect +import codingstandards.cpp.sideeffect.DefaultEffects from SizeofExprOperator op, Expr e where diff --git a/cpp/autosar/src/rules/M6-2-1/AssignmentInSubExpression.ql b/cpp/autosar/src/rules/M6-2-1/AssignmentInSubExpression.ql index 8b440202b3..fb41c3b6b9 100644 --- a/cpp/autosar/src/rules/M6-2-1/AssignmentInSubExpression.ql +++ b/cpp/autosar/src/rules/M6-2-1/AssignmentInSubExpression.ql @@ -16,6 +16,7 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.SideEffect +import codingstandards.cpp.Expr from AssignExpr assignment where diff --git a/cpp/autosar/test/qlpack.yml b/cpp/autosar/test/qlpack.yml index 0267a585e7..ec8efd6777 100644 --- a/cpp/autosar/test/qlpack.yml +++ b/cpp/autosar/test/qlpack.yml @@ -1,4 +1,4 @@ name: autosar-cpp-coding-standards-tests -version: 2.0.0 +version: 2.1.0 libraryPathDependencies: autosar-cpp-coding-standards extractor: cpp diff --git a/cpp/autosar/test/rules/A2-7-2/SectionsOfCodeCommentedOut.qlref b/cpp/autosar/test/rules/A2-7-2/SectionsOfCodeCommentedOut.qlref deleted file mode 100644 index 7196cc62fc..0000000000 --- a/cpp/autosar/test/rules/A2-7-2/SectionsOfCodeCommentedOut.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/A2-7-2/SectionsOfCodeCommentedOut.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A2-7-2/SectionsOfCodeCommentedOut.testref b/cpp/autosar/test/rules/A2-7-2/SectionsOfCodeCommentedOut.testref new file mode 100644 index 0000000000..303a38a19b --- /dev/null +++ b/cpp/autosar/test/rules/A2-7-2/SectionsOfCodeCommentedOut.testref @@ -0,0 +1 @@ +cpp/common/test/rules/sectionsofcodeshallnotbecommentedout/SectionsOfCodeShallNotBeCommentedOut.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M2-10-1/DifferentIdentifiersNotTypographicallyUnambiguous.expected b/cpp/autosar/test/rules/M2-10-1/DifferentIdentifiersNotTypographicallyUnambiguous.expected deleted file mode 100644 index 7997db32c9..0000000000 --- a/cpp/autosar/test/rules/M2-10-1/DifferentIdentifiersNotTypographicallyUnambiguous.expected +++ /dev/null @@ -1,31 +0,0 @@ -| test.cpp:1:5:1:13 | case1_foo | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:1:5:1:13 | case1_foo | case1_foo | test.cpp:2:5:2:13 | case1_FOO | case1_FOO | -| test.cpp:1:5:1:13 | case1_foo | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:1:5:1:13 | case1_foo | case1_foo | test.cpp:3:5:3:13 | case1_fOo | case1_fOo | -| test.cpp:3:5:3:13 | case1_fOo | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:3:5:3:13 | case1_fOo | case1_fOo | test.cpp:2:5:2:13 | case1_FOO | case1_FOO | -| test.cpp:5:5:5:13 | case2_foo | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:5:5:5:13 | case2_foo | case2_foo | test.cpp:6:5:6:15 | case2_f_o_o | case2_f_o_o | -| test.cpp:8:5:8:13 | case3_fOO | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:8:5:8:13 | case3_fOO | case3_fOO | test.cpp:9:5:9:13 | case3_fO0 | case3_fO0 | -| test.cpp:11:5:11:12 | case4_II | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:11:5:11:12 | case4_II | case4_II | test.cpp:12:5:12:12 | case4_I1 | case4_I1 | -| test.cpp:13:5:13:12 | case4_Il | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:13:5:13:12 | case4_Il | case4_Il | test.cpp:11:5:11:12 | case4_II | case4_II | -| test.cpp:13:5:13:12 | case4_Il | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:13:5:13:12 | case4_Il | case4_Il | test.cpp:12:5:12:12 | case4_I1 | case4_I1 | -| test.cpp:15:5:15:11 | case5_S | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:15:5:15:11 | case5_S | case5_S | test.cpp:16:5:16:11 | case5_5 | case5_5 | -| test.cpp:18:5:18:11 | case6_Z | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:18:5:18:11 | case6_Z | case6_Z | test.cpp:19:5:19:11 | case6_2 | case6_2 | -| test.cpp:21:5:21:11 | case7_n | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:21:5:21:11 | case7_n | case7_n | test.cpp:22:5:22:11 | case7_h | case7_h | -| test.cpp:24:5:24:11 | case8_B | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:24:5:24:11 | case8_B | case8_B | test.cpp:25:5:25:11 | case8_8 | case8_8 | -| test.cpp:27:5:27:12 | case9_rn | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:27:5:27:12 | case9_rn | case9_rn | test.cpp:28:5:28:11 | case9_m | case9_m | -| test.cpp:27:5:27:12 | case9_rn | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:27:5:27:12 | case9_rn | case9_rn | test.cpp:29:5:29:12 | case9_rh | case9_rh | -| test.cpp:31:5:31:17 | case10_xrnrnx | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:31:5:31:17 | case10_xrnrnx | case10_xrnrnx | test.cpp:32:5:32:15 | case10_xmmx | case10_xmmx | -| test.cpp:31:5:31:17 | case10_xrnrnx | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:31:5:31:17 | case10_xrnrnx | case10_xrnrnx | test.cpp:33:5:33:16 | case10_xmrnx | case10_xmrnx | -| test.cpp:31:5:31:17 | case10_xrnrnx | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:31:5:31:17 | case10_xrnrnx | case10_xrnrnx | test.cpp:34:5:34:16 | case10_xrnmx | case10_xrnmx | -| test.cpp:31:5:31:17 | case10_xrnrnx | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:31:5:31:17 | case10_xrnrnx | case10_xrnrnx | test.cpp:35:5:35:17 | case10_xrnrhx | case10_xrnrhx | -| test.cpp:31:5:31:17 | case10_xrnrnx | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:31:5:31:17 | case10_xrnrnx | case10_xrnrnx | test.cpp:36:5:36:17 | case10_xrhrhx | case10_xrhrhx | -| test.cpp:31:5:31:17 | case10_xrnrnx | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:31:5:31:17 | case10_xrnrnx | case10_xrnrnx | test.cpp:37:5:37:16 | case10_xmrhx | case10_xmrhx | -| test.cpp:31:5:31:17 | case10_xrnrnx | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:31:5:31:17 | case10_xrnrnx | case10_xrnrnx | test.cpp:38:5:38:16 | case10_xrhmx | case10_xrhmx | -| test.cpp:33:5:33:16 | case10_xmrnx | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:33:5:33:16 | case10_xmrnx | case10_xmrnx | test.cpp:32:5:32:15 | case10_xmmx | case10_xmmx | -| test.cpp:33:5:33:16 | case10_xmrnx | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:33:5:33:16 | case10_xmrnx | case10_xmrnx | test.cpp:37:5:37:16 | case10_xmrhx | case10_xmrhx | -| test.cpp:34:5:34:16 | case10_xrnmx | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:34:5:34:16 | case10_xrnmx | case10_xrnmx | test.cpp:32:5:32:15 | case10_xmmx | case10_xmmx | -| test.cpp:34:5:34:16 | case10_xrnmx | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:34:5:34:16 | case10_xrnmx | case10_xrnmx | test.cpp:33:5:33:16 | case10_xmrnx | case10_xmrnx | -| test.cpp:34:5:34:16 | case10_xrnmx | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:34:5:34:16 | case10_xrnmx | case10_xrnmx | test.cpp:38:5:38:16 | case10_xrhmx | case10_xrhmx | -| test.cpp:35:5:35:17 | case10_xrnrhx | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:35:5:35:17 | case10_xrnrhx | case10_xrnrhx | test.cpp:33:5:33:16 | case10_xmrnx | case10_xmrnx | -| test.cpp:35:5:35:17 | case10_xrnrhx | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:35:5:35:17 | case10_xrnrhx | case10_xrnrhx | test.cpp:36:5:36:17 | case10_xrhrhx | case10_xrhrhx | -| test.cpp:35:5:35:17 | case10_xrnrhx | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:35:5:35:17 | case10_xrnrhx | case10_xrnrhx | test.cpp:37:5:37:16 | case10_xmrhx | case10_xmrhx | -| test.cpp:40:5:40:12 | case11_o | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:40:5:40:12 | case11_o | case11_o | test.cpp:40:15:40:22 | case11_O | case11_O | -| test.cpp:42:5:42:14 | case12_BBb | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:42:5:42:14 | case12_BBb | case12_BBb | test.cpp:43:5:43:14 | case12_8bB | case12_8bB | diff --git a/cpp/autosar/test/rules/M2-10-1/DifferentIdentifiersNotTypographicallyUnambiguous.qlref b/cpp/autosar/test/rules/M2-10-1/DifferentIdentifiersNotTypographicallyUnambiguous.qlref deleted file mode 100644 index d2966e1b6e..0000000000 --- a/cpp/autosar/test/rules/M2-10-1/DifferentIdentifiersNotTypographicallyUnambiguous.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/M2-10-1/DifferentIdentifiersNotTypographicallyUnambiguous.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M2-10-1/DifferentIdentifiersNotTypographicallyUnambiguous.testref b/cpp/autosar/test/rules/M2-10-1/DifferentIdentifiersNotTypographicallyUnambiguous.testref new file mode 100644 index 0000000000..dffdbb26b8 --- /dev/null +++ b/cpp/autosar/test/rules/M2-10-1/DifferentIdentifiersNotTypographicallyUnambiguous.testref @@ -0,0 +1 @@ +cpp/common/test/rules/differentidentifiersnottypographicallyunambiguous/DifferentIdentifiersNotTypographicallyUnambiguous.ql \ No newline at end of file diff --git a/cpp/cert/src/qlpack.yml b/cpp/cert/src/qlpack.yml index 13f090082b..26346cf48b 100644 --- a/cpp/cert/src/qlpack.yml +++ b/cpp/cert/src/qlpack.yml @@ -1,4 +1,4 @@ name: cert-cpp-coding-standards -version: 2.0.0 +version: 2.1.0 suites: codeql-suites libraryPathDependencies: common-cpp-coding-standards diff --git a/cpp/cert/src/rules/CON50-CPP/DoNotAllowAMutexToGoOutOfScopeWhileLocked-standard.qhelp b/cpp/cert/src/rules/CON50-CPP/DoNotAllowAMutexToGoOutOfScopeWhileLocked-standard.qhelp index 51a1caec5b..1c3104a8f6 100644 --- a/cpp/cert/src/rules/CON50-CPP/DoNotAllowAMutexToGoOutOfScopeWhileLocked-standard.qhelp +++ b/cpp/cert/src/rules/CON50-CPP/DoNotAllowAMutexToGoOutOfScopeWhileLocked-standard.qhelp @@ -1,74 +1,17 @@
    -

    - Mutex objects are used to protect shared data from being concurrently accessed. If a mutex object is destroyed while a thread is blocked waiting for the lock, - - critical sections - - and shared data are no longer protected. -

    -

    - The C++ Standard, [thread.mutex.class], paragraph 5 [ - - ISO/IEC 14882-2014 - - ], states the following: -

    +

    Mutex objects are used to protect shared data from being concurrently accessed. If a mutex object is destroyed while a thread is blocked waiting for the lock, critical sections and shared data are no longer protected.

    +

    The C++ Standard, [thread.mutex.class], paragraph 5 [ISO/IEC 14882-2014], states the following:

    -

    - The behavior of a program is undefined if it destroys a - - mutex - - object owned by any thread or a thread terminates while owning a - - mutex - - object. -

    +

    The behavior of a program is undefined if it destroys a mutex object owned by any thread or a thread terminates while owning a mutex object.

    -

    - Similar wording exists for - - std::recursive_mutex - - , - - std::timed_mutex - - , - - std::recursive_timed_mutex - - , and - - std::shared_timed_mutex - - . These statements imply that destroying a mutex object while a thread is waiting on it is - - undefined behavior - - . -

    +

    Similar wording exists for std::recursive_mutex, std::timed_mutex, std::recursive_timed_mutex, and std::shared_timed_mutex. These statements imply that destroying a mutex object while a thread is waiting on it is undefined behavior.

    -

    - This noncompliant code example creates several threads that each invoke the - - do_work() - - function, passing a unique number as an ID. -

    -

    - Unfortunately, this code contains a race condition, allowing the mutex to be destroyed while it is still owned, because - - start_threads() - - may invoke the mutex's destructor before all of the threads have exited. -

    - - #include <mutex> +

    This noncompliant code example creates several threads that each invoke the do_work() function, passing a unique number as an ID.

    +

    Unfortunately, this code contains a race condition, allowing the mutex to be destroyed while it is still owned, because start_threads() may invoke the mutex's destructor before all of the threads have exited.

    + #include <mutex> #include <thread> const size_t maxThreads = 10; @@ -87,14 +30,11 @@ void start_threads() { threads[i] = std::thread(do_work, i, &m); } } - +
    -

    - This compliant solution eliminates the race condition by extending the lifetime of the mutex. -

    - - #include <mutex> +

    This compliant solution eliminates the race condition by extending the lifetime of the mutex.

    + #include <mutex> #include <thread> const size_t maxThreads = 10; @@ -114,14 +54,11 @@ void start_threads() { threads[i] = std::thread(do_work, i, &m); } } - +
    -

    - This compliant solution eliminates the race condition by joining the threads before the mutex's destructor is invoked. -

    - - #include <mutex> +

    This compliant solution eliminates the race condition by joining the threads before the mutex's destructor is invoked.

    + #include <mutex> #include <thread> const size_t maxThreads = 10; @@ -142,13 +79,10 @@ void run_threads() { for (size_t i = 0; i < maxThreads; ++i) { threads[i].join(); } -} - +}
    -

    - Destroying a mutex while it is locked may result in invalid control flow and data corruption. -

    +

    Destroying a mutex while it is locked may result in invalid control flow and data corruption.

    @@ -185,14 +119,10 @@ void run_threads() { High @@ -225,9 +155,7 @@ void run_threads() { 2021.2 @@ -242,11 +170,7 @@ void run_threads() { 2021.4 @@ -261,9 +185,7 @@ void run_threads() { 2021.2 @@ -308,17 +228,7 @@ void run_threads() {
    - - P4 - + P4 - - L3 - + L3
    - - C++4961, C++4962 - + C++4961, C++4962 - - - CERT.CONC.MUTEX.DESTROY_WHILE_LOCKED - - + CERT.CONC.MUTEX.DESTROY_WHILE_LOCKED - - CERT_CPP-CON50-a - + CERT_CPP-CON50-a Do not destroy another thread's mutex @@ -297,9 +219,7 @@ void run_threads() { 4.4 - - 4961, 4962 - + 4961, 4962
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/CON50-CPP/DoNotDestroyAMutexWhileItIsLocked-standard.qhelp b/cpp/cert/src/rules/CON50-CPP/DoNotDestroyAMutexWhileItIsLocked-standard.qhelp index 51a1caec5b..1c3104a8f6 100644 --- a/cpp/cert/src/rules/CON50-CPP/DoNotDestroyAMutexWhileItIsLocked-standard.qhelp +++ b/cpp/cert/src/rules/CON50-CPP/DoNotDestroyAMutexWhileItIsLocked-standard.qhelp @@ -1,74 +1,17 @@
    -

    - Mutex objects are used to protect shared data from being concurrently accessed. If a mutex object is destroyed while a thread is blocked waiting for the lock, - - critical sections - - and shared data are no longer protected. -

    -

    - The C++ Standard, [thread.mutex.class], paragraph 5 [ - - ISO/IEC 14882-2014 - - ], states the following: -

    +

    Mutex objects are used to protect shared data from being concurrently accessed. If a mutex object is destroyed while a thread is blocked waiting for the lock, critical sections and shared data are no longer protected.

    +

    The C++ Standard, [thread.mutex.class], paragraph 5 [ISO/IEC 14882-2014], states the following:

    -

    - The behavior of a program is undefined if it destroys a - - mutex - - object owned by any thread or a thread terminates while owning a - - mutex - - object. -

    +

    The behavior of a program is undefined if it destroys a mutex object owned by any thread or a thread terminates while owning a mutex object.

    -

    - Similar wording exists for - - std::recursive_mutex - - , - - std::timed_mutex - - , - - std::recursive_timed_mutex - - , and - - std::shared_timed_mutex - - . These statements imply that destroying a mutex object while a thread is waiting on it is - - undefined behavior - - . -

    +

    Similar wording exists for std::recursive_mutex, std::timed_mutex, std::recursive_timed_mutex, and std::shared_timed_mutex. These statements imply that destroying a mutex object while a thread is waiting on it is undefined behavior.

    -

    - This noncompliant code example creates several threads that each invoke the - - do_work() - - function, passing a unique number as an ID. -

    -

    - Unfortunately, this code contains a race condition, allowing the mutex to be destroyed while it is still owned, because - - start_threads() - - may invoke the mutex's destructor before all of the threads have exited. -

    - - #include <mutex> +

    This noncompliant code example creates several threads that each invoke the do_work() function, passing a unique number as an ID.

    +

    Unfortunately, this code contains a race condition, allowing the mutex to be destroyed while it is still owned, because start_threads() may invoke the mutex's destructor before all of the threads have exited.

    + #include <mutex> #include <thread> const size_t maxThreads = 10; @@ -87,14 +30,11 @@ void start_threads() { threads[i] = std::thread(do_work, i, &m); } } - +
    -

    - This compliant solution eliminates the race condition by extending the lifetime of the mutex. -

    - - #include <mutex> +

    This compliant solution eliminates the race condition by extending the lifetime of the mutex.

    + #include <mutex> #include <thread> const size_t maxThreads = 10; @@ -114,14 +54,11 @@ void start_threads() { threads[i] = std::thread(do_work, i, &m); } } - +
    -

    - This compliant solution eliminates the race condition by joining the threads before the mutex's destructor is invoked. -

    - - #include <mutex> +

    This compliant solution eliminates the race condition by joining the threads before the mutex's destructor is invoked.

    + #include <mutex> #include <thread> const size_t maxThreads = 10; @@ -142,13 +79,10 @@ void run_threads() { for (size_t i = 0; i < maxThreads; ++i) { threads[i].join(); } -} - +}
    -

    - Destroying a mutex while it is locked may result in invalid control flow and data corruption. -

    +

    Destroying a mutex while it is locked may result in invalid control flow and data corruption.

    @@ -185,14 +119,10 @@ void run_threads() { High @@ -225,9 +155,7 @@ void run_threads() { 2021.2 @@ -242,11 +170,7 @@ void run_threads() { 2021.4 @@ -261,9 +185,7 @@ void run_threads() { 2021.2 @@ -308,17 +228,7 @@ void run_threads() {
    - - P4 - + P4 - - L3 - + L3
    - - C++4961, C++4962 - + C++4961, C++4962 - - - CERT.CONC.MUTEX.DESTROY_WHILE_LOCKED - - + CERT.CONC.MUTEX.DESTROY_WHILE_LOCKED - - CERT_CPP-CON50-a - + CERT_CPP-CON50-a Do not destroy another thread's mutex @@ -297,9 +219,7 @@ void run_threads() { 4.4 - - 4961, 4962 - + 4961, 4962
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/CON51-CPP/EnsureActivelyHeldLocksAreReleasedOnExceptionalConditions-standard.qhelp b/cpp/cert/src/rules/CON51-CPP/EnsureActivelyHeldLocksAreReleasedOnExceptionalConditions-standard.qhelp index db6911a010..0adadc06f5 100644 --- a/cpp/cert/src/rules/CON51-CPP/EnsureActivelyHeldLocksAreReleasedOnExceptionalConditions-standard.qhelp +++ b/cpp/cert/src/rules/CON51-CPP/EnsureActivelyHeldLocksAreReleasedOnExceptionalConditions-standard.qhelp @@ -1,85 +1,12 @@
    -

    - Mutexes that are used to protect accesses to shared data may be locked using the - - lock() - - member function and unlocked using the - - unlock() - - member function. If an exception occurs between the call to - - lock() - - and the call to - - unlock() - - , and the exception changes control flow such that - - unlock() - - is not called, the mutex will be left in the locked state and no - - critical sections - - protected by that mutex will be allowed to execute. This is likely to lead to deadlock. -

    -

    - The throwing of an exception must not allow a mutex to remain locked indefinitely. If a mutex was locked and an exception occurs within the critical section protected by that mutex, the mutex must be unlocked as part of exception handling before rethrowing the exception or continuing execution unless subsequent control flow will unlock the mutex. -

    -

    - C++ supplies the lock classes - - lock_guard - - , - - unique_lock - - , and - - shared_lock - - , which can be initialized with a mutex. In its constructor, the lock object locks the mutex, and in its destructor, it unlocks the mutex. The - - lock_guard - - class provides a simple - - RAII - - wrapper around a mutex. The - - unique_lock - - and - - shared_lock - - classes also use RAII and provide additional functionality, such as manual control over the locking strategy. The - - unique_lock - - class prevents the lock from being copied, although it allows the lock ownership to be moved to another lock. The - - shared_lock - - class allows the mutex to be shared by several locks. For all three classes, if an exception occurs and takes control flow out of the scope of the lock, the destructor will unlock the mutex and the program can continue working normally. These lock objects are the preferred way to ensure that a mutex is properly released when an exception is thrown. -

    -

    - Noncompliant Code Example -

    -

    - This noncompliant code example manipulates shared data and protects the critical section by locking the mutex. When it is finished, it unlocks the mutex. - However, if an exception occurs while manipulating the shared data, the mutex will remain locked - . -

    - - #include <mutex> +

    Mutexes that are used to protect accesses to shared data may be locked using the lock() member function and unlocked using the unlock() member function. If an exception occurs between the call to lock() and the call to unlock(), and the exception changes control flow such that unlock() is not called, the mutex will be left in the locked state and no critical sections protected by that mutex will be allowed to execute. This is likely to lead to deadlock.

    +

    The throwing of an exception must not allow a mutex to remain locked indefinitely. If a mutex was locked and an exception occurs within the critical section protected by that mutex, the mutex must be unlocked as part of exception handling before rethrowing the exception or continuing execution unless subsequent control flow will unlock the mutex.

    +

    C++ supplies the lock classes lock_guard, unique_lock, and shared_lock, which can be initialized with a mutex. In its constructor, the lock object locks the mutex, and in its destructor, it unlocks the mutex. The lock_guard class provides a simple RAII wrapper around a mutex. The unique_lock and shared_lock classes also use RAII and provide additional functionality, such as manual control over the locking strategy. The unique_lock class prevents the lock from being copied, although it allows the lock ownership to be moved to another lock. The shared_lock class allows the mutex to be shared by several locks. For all three classes, if an exception occurs and takes control flow out of the scope of the lock, the destructor will unlock the mutex and the program can continue working normally. These lock objects are the preferred way to ensure that a mutex is properly released when an exception is thrown.

    +

    Noncompliant Code Example

    +

    This noncompliant code example manipulates shared data and protects the critical section by locking the mutex. When it is finished, it unlocks the mutex. However, if an exception occurs while manipulating the shared data, the mutex will remain locked.

    + #include <mutex> void manipulate_shared_data(std::mutex &pm) { pm.lock(); @@ -88,14 +15,11 @@ void manipulate_shared_data(std::mutex &pm) { pm.unlock(); } - +
    -

    - This compliant solution catches any exceptions thrown when performing work on the shared data and unlocks the mutex before rethrowing the exception. -

    - - #include <mutex> +

    This compliant solution catches any exceptions thrown when performing work on the shared data and unlocks the mutex before rethrowing the exception.

    + #include <mutex> void manipulate_shared_data(std::mutex &pm) { pm.lock(); @@ -106,31 +30,21 @@ void manipulate_shared_data(std::mutex &pm) { throw; } pm.unlock(); // in case no exceptions occur -} - +}
    -

    - This compliant solution uses a - - lock_guard - - object to ensure that the mutex will be unlocked, even if an exception occurs, without relying on exception handling machinery and manual resource management. -

    - - #include <mutex> +

    This compliant solution uses a lock_guard object to ensure that the mutex will be unlocked, even if an exception occurs, without relying on exception handling machinery and manual resource management.

    + #include <mutex> void manipulate_shared_data(std::mutex &pm) { std::lock_guard<std::mutex> lk(pm); // Perform work on shared data. } - +
    -

    - If an exception occurs while a mutex is locked, deadlock may result. -

    +

    If an exception occurs while a mutex is locked, deadlock may result.

    @@ -167,14 +81,10 @@ void manipulate_shared_data(std::mutex &pm) { Low @@ -207,9 +117,7 @@ void manipulate_shared_data(std::mutex &pm) { 2021.2 @@ -224,9 +132,7 @@ void manipulate_shared_data(std::mutex &pm) { 2021.2 @@ -253,28 +157,10 @@ void manipulate_shared_data(std::mutex &pm) {
    - - P6 - + P6 - - L2 - + L2
    - - C++5018 - + C++5018 - - CERT_CPP-CON51-a - + CERT_CPP-CON51-a Do not call lock() directly on a mutex @@ -242,9 +148,7 @@ void manipulate_shared_data(std::mutex &pm) { 4.4 - - 5018 - + 5018
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    -

    - - This rule is a subset of - - ERR56-CPP. Guarantee exception safety - - . - -

    +

    This rule is a subset of ERR56-CPP. Guarantee exception safety.

    diff --git a/cpp/cert/src/rules/CON52-CPP/PreventDataRacesWhenAccessingBitFieldsFromMultipleThreads-standard.qhelp b/cpp/cert/src/rules/CON52-CPP/PreventDataRacesWhenAccessingBitFieldsFromMultipleThreads-standard.qhelp index d8671cfca6..742e22be15 100644 --- a/cpp/cert/src/rules/CON52-CPP/PreventDataRacesWhenAccessingBitFieldsFromMultipleThreads-standard.qhelp +++ b/cpp/cert/src/rules/CON52-CPP/PreventDataRacesWhenAccessingBitFieldsFromMultipleThreads-standard.qhelp @@ -1,26 +1,13 @@
    -

    - When accessing a bit-field, a thread may inadvertently access a separate bit-field in adjacent memory. This is because compilers are required to store multiple adjacent bit-fields in one storage unit whenever they fit. Consequently, data races may exist not just on a bit-field accessed by multiple threads but also on other bit-fields sharing the same byte or word. The problem is difficult to diagnose because it may not be obvious that the same memory location is being modified by multiple threads. -

    -

    - One approach for preventing data races in concurrent programming is to use a mutex. When properly observed by all threads, a mutex can provide safe and secure access to a shared object. However, mutexes provide no guarantees with regard to other objects that might be accessed when the mutex is not controlled by the accessing thread. Unfortunately, there is no portable way to determine which adjacent bit-fields may be stored along with the desired bit-field. -

    -

    - Another approach is to insert a non-bit-field member between any two bit-fields to ensure that each bit-field is the only one accessed within its storage unit. This technique effectively guarantees that no two bit-fields are accessed simultaneously. -

    +

    When accessing a bit-field, a thread may inadvertently access a separate bit-field in adjacent memory. This is because compilers are required to store multiple adjacent bit-fields in one storage unit whenever they fit. Consequently, data races may exist not just on a bit-field accessed by multiple threads but also on other bit-fields sharing the same byte or word. The problem is difficult to diagnose because it may not be obvious that the same memory location is being modified by multiple threads.

    +

    One approach for preventing data races in concurrent programming is to use a mutex. When properly observed by all threads, a mutex can provide safe and secure access to a shared object. However, mutexes provide no guarantees with regard to other objects that might be accessed when the mutex is not controlled by the accessing thread. Unfortunately, there is no portable way to determine which adjacent bit-fields may be stored along with the desired bit-field.

    +

    Another approach is to insert a non-bit-field member between any two bit-fields to ensure that each bit-field is the only one accessed within its storage unit. This technique effectively guarantees that no two bit-fields are accessed simultaneously.

    -

    - Adjacent bit-fields may be stored in a single memory location. Consequently, modifying adjacent bit-fields in different threads is - - undefined behavior - - , as shown in this noncompliant code example. -

    - - struct MultiThreadedFlags { +

    Adjacent bit-fields may be stored in a single memory location. Consequently, modifying adjacent bit-fields in different threads is undefined behavior, as shown in this noncompliant code example.

    + struct MultiThreadedFlags { unsigned int flag1 : 2; unsigned int flag2 : 2; }; @@ -34,28 +21,21 @@ void thread1() { void thread2() { flags.flag2 = 2; } - -

    - For example, the following instruction sequence is possible. -

    - - Thread 1: register 0 = flags + +

    For example, the following instruction sequence is possible.

    + Thread 1: register 0 = flags Thread 1: register 0 &= ~mask(flag1) Thread 2: register 0 = flags Thread 2: register 0 &= ~mask(flag2) Thread 1: register 0 |= 1 << shift(flag1) Thread 1: flags = register 0 Thread 2: register 0 |= 2 << shift(flag2) -Thread 2: flags = register 0 - +Thread 2: flags = register 0
    -

    - This compliant solution protects all accesses of the flags with a mutex, thereby preventing any data races. -

    - - #include <mutex> -  +

    This compliant solution protects all accesses of the flags with a mutex, thereby preventing any data races.

    + #include <mutex> + struct MultiThreadedFlags { unsigned int flag1 : 2; unsigned int flag2 : 2; @@ -77,14 +57,11 @@ void thread2() { std::lock_guard<std::mutex> lk(flags.mutex); flags.s.flag2 = 2; } - +
    -

    - In this compliant solution, two threads simultaneously modify two distinct non-bit-field members of a structure. Because the members occupy different bytes in memory, no concurrency protection is required. -

    - - struct MultiThreadedFlags { +

    In this compliant solution, two threads simultaneously modify two distinct non-bit-field members of a structure. Because the members occupy different bytes in memory, no concurrency protection is required.

    + struct MultiThreadedFlags { unsigned char flag1; unsigned char flag2; }; @@ -97,44 +74,15 @@ void thread1() { void thread2() { flags.flag2 = 2; -} - -

    - Unlike earlier versions of the standard, C++11 and later explicitly define a memory location and provide the following note in [intro.memory] paragraph 4 [ - - ISO/IEC 14882-2014 - - ]: -

    +}
    +

    Unlike earlier versions of the standard, C++11 and later explicitly define a memory location and provide the following note in [intro.memory] paragraph 4 [ISO/IEC 14882-2014]:

    -

    - [ - - Note: - - Thus a bit-field and an adjacent non-bit-field are in separate memory locations, and therefore can be concurrently updated by two threads of execution without interference.  The same applies to two bit-fields, if one is declared inside a nested struct declaration and the other is not, or if the two are separated by a zero-length bit-field declaration, or if they are separated by a non-bit-field declaration.  It is not safe to concurrently update two bit-fields in the same struct if all fields between them are also bit-fields of non-zero width.  – - - end note - - ] -

    +

    [Note: Thus a bit-field and an adjacent non-bit-field are in separate memory locations, and therefore can be concurrently updated by two threads of execution without interference. The same applies to two bit-fields, if one is declared inside a nested struct declaration and the other is not, or if the two are separated by a zero-length bit-field declaration, or if they are separated by a non-bit-field declaration. It is not safe to concurrently update two bit-fields in the same struct if all fields between them are also bit-fields of non-zero width. – end note]

    -

    - It is almost certain that - - flag1 - - and - - flag2 - - are stored in the same word. Using a compiler that conforms to earlier versions of the standard, if both assignments occur on a thread-scheduling interleaving that ends with both stores occurring after one another, it is possible that only one of the flags will be set as intended, and the other flag will contain its previous value because both members are represented by the same word, which is the smallest unit the processor can work on. Before the changes made to the C++ Standard for C++11, there were no guarantees that these flags could be modified concurrently. -

    +

    It is almost certain that flag1 and flag2 are stored in the same word. Using a compiler that conforms to earlier versions of the standard, if both assignments occur on a thread-scheduling interleaving that ends with both stores occurring after one another, it is possible that only one of the flags will be set as intended, and the other flag will contain its previous value because both members are represented by the same word, which is the smallest unit the processor can work on. Before the changes made to the C++ Standard for C++11, there were no guarantees that these flags could be modified concurrently.

    -

    - Although the race window is narrow, an assignment or an expression can evaluate improperly because of misinterpreted data resulting in a corrupted running state or unintended information disclosure. -

    +

    Although the race window is narrow, an assignment or an expression can evaluate improperly because of misinterpreted data resulting in a corrupted running state or unintended information disclosure.

    @@ -171,14 +119,10 @@ void thread2() { Medium @@ -211,10 +155,7 @@ void thread2() { 20.10 @@ -247,9 +186,7 @@ void thread2() { 6.5 @@ -282,9 +217,7 @@ void thread2() { 2021.2
    - - P8 - + P8 - - L2 - + L2
    - - read_write_data_race - write_write_data_race - + read_write_data_racewrite_write_data_race Supported @@ -230,9 +171,7 @@ void thread2() { 7.2.0 - - CertC++-CON52 - + CertC++-CON52 - - RACE_CONDITION - + RACE_CONDITION Fully implemented @@ -265,9 +202,7 @@ void thread2() { 2021.2 - - C++1774, C++1775 - + C++1774, C++1775 - - CERT_CPP-CON52-a - + CERT_CPP-CON52-a Use locks to prevent race conditions when modifying bit fields @@ -318,9 +251,7 @@ void thread2() { 4.4 - - 1774, 1775 - + 1774, 1775 Enforced by MTA @@ -330,17 +261,7 @@ void thread2() {
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/CON53-CPP/DeadlockByLockingInPredefinedOrder-standard.qhelp b/cpp/cert/src/rules/CON53-CPP/DeadlockByLockingInPredefinedOrder-standard.qhelp index aeace2b6a4..d2225b8ec5 100644 --- a/cpp/cert/src/rules/CON53-CPP/DeadlockByLockingInPredefinedOrder-standard.qhelp +++ b/cpp/cert/src/rules/CON53-CPP/DeadlockByLockingInPredefinedOrder-standard.qhelp @@ -1,61 +1,18 @@
    -

    - Mutexes are used to prevent multiple threads from causing a - - data race - - by accessing the same shared resource at the same time. Sometimes, when locking mutexes, multiple threads hold each other's lock, and the program consequently - - deadlocks - - . Four conditions are required for deadlock to occur: -

    +

    Mutexes are used to prevent multiple threads from causing a data race by accessing the same shared resource at the same time. Sometimes, when locking mutexes, multiple threads hold each other's lock, and the program consequently deadlocks. Four conditions are required for deadlock to occur:

      -
    • - mutual exclusion (At least one nonshareable resource must be held.), -
    • -
    • - hold and wait (A thread must hold a resource while awaiting availability of another resource.), -
    • -
    • - no preemption (Resources cannot be taken away from a thread while they are in-use.), and -
    • -
    • - circular wait (A thread must await a resource held by another thread which is, in turn, awaiting a resource held by the first thread.). -
    • +
    • mutual exclusion (At least one nonshareable resource must be held.),
    • +
    • hold and wait (A thread must hold a resource while awaiting availability of another resource.),
    • +
    • no preemption (Resources cannot be taken away from a thread while they are in-use.), and
    • +
    • circular wait (A thread must await a resource held by another thread which is, in turn, awaiting a resource held by the first thread.).
    -

    - Deadlock needs all four conditions, so preventing deadlock requires preventing any one of the four conditions. One simple solution is to lock the mutexes in a predefined order, which prevents circular wait. -

    +

    Deadlock needs all four conditions, so preventing deadlock requires preventing any one of the four conditions. One simple solution is to lock the mutexes in a predefined order, which prevents circular wait.

    -

    - The behavior of this noncompliant code example depends on the runtime environment and the platform's scheduler. The program is susceptible to deadlock if thread - - thr1 - - attempts to lock - - ba2 - - 's mutex at the same time thread - - thr2 - - attempts to lock - - ba1 - - 's mutex in the - - deposit() - - function. -

    - - #include <mutex> +

    The behavior of this noncompliant code example depends on the runtime environment and the platform's scheduler. The program is susceptible to deadlock if thread thr1 attempts to lock ba2's mutex at the same time thread thr2 attempts to lock ba1's mutex in the deposit() function.

    + #include <mutex> #include <thread> class BankAccount { @@ -89,27 +46,11 @@ void f(BankAccount *ba1, BankAccount *ba2) { std::thread thr2(deposit, ba2, ba1, 100); thr1.join(); thr2.join(); -} - +}
    -

    - This compliant solution eliminates the circular wait condition by establishing a predefined order for locking in the - - deposit() - - function. Each thread will lock on the basis of the - - BankAccount - - ID, which is set when the - - BankAccount - - object is initialized. -

    - - #include <atomic> +

    This compliant solution eliminates the circular wait condition by establishing a predefined order for locking in the deposit() function. Each thread will lock on the basis of the BankAccount ID, which is set when the BankAccount object is initialized.

    + #include <atomic> #include <mutex> #include <thread> @@ -155,42 +96,18 @@ int deposit(BankAccount *from, BankAccount *to, int amount) { } return -1; } -  + void f(BankAccount *ba1, BankAccount *ba2) { // Perform the deposits. std::thread thr1(deposit, ba1, ba2, 100); std::thread thr2(deposit, ba2, ba1, 100); thr1.join(); thr2.join(); -} - +}
    -

    - This compliant solution uses Standard Template Library facilities to ensure that deadlock does not occur due to circular wait conditions. The - - std::lock() - - function takes a variable number of lockable objects and attempts to lock them such that deadlock does not occur [ - - ISO/IEC 14882-2014 - - ]. In typical implementations, this is done by using a combination of - - lock() - - , - - try_lock() - - , and - - unlock() - - to attempt to lock the object and backing off if the lock is not acquired, which may have worse performance than a solution that locks in predefined order explicitly. -

    - - #include <mutex> +

    This compliant solution uses Standard Template Library facilities to ensure that deadlock does not occur due to circular wait conditions. The std::lock() function takes a variable number of lockable objects and attempts to lock them such that deadlock does not occur [ISO/IEC 14882-2014]. In typical implementations, this is done by using a combination of lock(), try_lock(), and unlock() to attempt to lock the object and backing off if the lock is not acquired, which may have worse performance than a solution that locks in predefined order explicitly.

    + #include <mutex> #include <thread> class BankAccount { @@ -218,24 +135,17 @@ int deposit(BankAccount *from, BankAccount *to, int amount) { } return -1; } -  + void f(BankAccount *ba1, BankAccount *ba2) { // Perform the deposits. std::thread thr1(deposit, ba1, ba2, 100); std::thread thr2(deposit, ba2, ba1, 100); thr1.join(); thr2.join(); -} - +}
    -

    - Deadlock prevents multiple threads from progressing, halting program execution. A - - denial-of-service attack - - is possible if the attacker can create the conditions for deadlock. -

    +

    Deadlock prevents multiple threads from progressing, halting program execution. A denial-of-service attack is possible if the attacker can create the conditions for deadlock.

    @@ -272,14 +182,10 @@ void f(BankAccount *ba1, BankAccount *ba2) { Medium @@ -309,12 +215,10 @@ void f(BankAccount *ba1, BankAccount *ba2) { @@ -365,9 +265,7 @@ void f(BankAccount *ba1, BankAccount *ba2) { 2021.2
    - - P4 - + P4 - - L3 - + L3
    - 6.1p0 + 6.2p0 - - CONCURRENCY.LOCK.ORDER - + CONCURRENCY.LOCK.ORDER Conflicting lock order @@ -330,9 +234,7 @@ void f(BankAccount *ba1, BankAccount *ba2) { 6.5 - - DEADLOCK - + DEADLOCK Fully implemented @@ -348,9 +250,7 @@ void f(BankAccount *ba1, BankAccount *ba2) { 2021.2 - - C++1772, C++1773 - + C++1772, C++1773 - - CERT_CPP-CON53-a - + CERT_CPP-CON53-a Do not acquire locks in different order @@ -401,9 +299,7 @@ void f(BankAccount *ba1, BankAccount *ba2) { 4.4 - - 1772, 1773 - + 1772, 1773 Enforced by MTA @@ -413,17 +309,7 @@ void f(BankAccount *ba1, BankAccount *ba2) {
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/CON54-CPP/WrapFunctionsThatCanSpuriouslyWakeUpInLoop-standard.qhelp b/cpp/cert/src/rules/CON54-CPP/WrapFunctionsThatCanSpuriouslyWakeUpInLoop-standard.qhelp index c8069ccc50..8bd65ce187 100644 --- a/cpp/cert/src/rules/CON54-CPP/WrapFunctionsThatCanSpuriouslyWakeUpInLoop-standard.qhelp +++ b/cpp/cert/src/rules/CON54-CPP/WrapFunctionsThatCanSpuriouslyWakeUpInLoop-standard.qhelp @@ -1,58 +1,9 @@
    -

    - The - - wait() - - , - - wait_for() - - , and - - wait_until() - - member functions of the - - std::condition_variable - - class temporarily cede possession of a mutex so that other threads that may be requesting the mutex can proceed. These functions must always be called from code that is protected by locking a mutex. The waiting thread resumes execution only after it has been notified, generally as the result of the invocation of the - - notify_one() - - or - - notify_all() - - member functions invoked by another thread. -

    -

    - The - - wait() - - function must be invoked from a loop that checks whether a - - condition predicate - - holds. A condition predicate is an expression constructed from the variables of a function that must be true for a thread to be allowed to continue execution. The thread pauses execution via - - wait() - - , - - wait_for() - - , - - wait_until() - - , or some other mechanism, and is resumed later, presumably when the condition predicate is true and the thread is notified. -

    - - #include <condition_variable> +

    The wait(), wait_for(), and wait_until() member functions of the std::condition_variable class temporarily cede possession of a mutex so that other threads that may be requesting the mutex can proceed. These functions must always be called from code that is protected by locking a mutex. The waiting thread resumes execution only after it has been notified, generally as the result of the invocation of the notify_one() or notify_all() member functions invoked by another thread.

    +

    The wait() function must be invoked from a loop that checks whether a condition predicate holds. A condition predicate is an expression constructed from the variables of a function that must be true for a thread to be allowed to continue execution. The thread pauses execution via wait(), wait_for(), wait_until(), or some other mechanism, and is resumed later, presumably when the condition predicate is true and the thread is notified.

    + #include <condition_variable> #include <mutex> extern bool until_finish(void); @@ -67,71 +18,15 @@ void func(void) { } // Resume when condition holds. -} - -

    - The notification mechanism notifies the waiting thread and allows it to check its condition predicate. The invocation of - - notify_all() - - in another thread cannot precisely determine which waiting thread will be resumed. Condition predicate statements allow notified threads to determine whether they should resume upon receiving the notification. -

    +}
    +

    The notification mechanism notifies the waiting thread and allows it to check its condition predicate. The invocation of notify_all() in another thread cannot precisely determine which waiting thread will be resumed. Condition predicate statements allow notified threads to determine whether they should resume upon receiving the notification.

    -

    - This noncompliant code example monitors a linked list and assigns one thread to consume list elements when the list is nonempty. -

    -

    - This thread pauses execution using - - wait() - - and resumes when notified, presumably when the list has elements to be consumed. It is possible for the thread to be notified even if the list is still empty, perhaps because the notifying thread used - - notify_all() - - , which notifies all threads. Notification using - - notify_all() - - is frequently preferred over using - - notify_one() - - . (See - - CON55-CPP. Preserve thread safety and liveness when using condition variables - - for more information.) -

    -

    - A condition predicate is typically the negation of the condition expression in the loop. In this noncompliant code example, the condition predicate for removing an element from a linked list is - - (list->next != nullptr) - - , whereas the condition expression for the - - while - - loop condition is - - (list->next == nullptr) - - . -

    -

    - This noncompliant code example nests the call to - - wait() - - inside an - - if - - block and consequently fails to check the condition predicate after the notification is received. If the notification was spurious or malicious, the thread would wake up prematurely. -

    - - #include <condition_variable> +

    This noncompliant code example monitors a linked list and assigns one thread to consume list elements when the list is nonempty.

    +

    This thread pauses execution using wait() and resumes when notified, presumably when the list has elements to be consumed. It is possible for the thread to be notified even if the list is still empty, perhaps because the notifying thread used notify_all(), which notifies all threads. Notification using notify_all() is frequently preferred over using notify_one(). (See CON55-CPP. Preserve thread safety and liveness when using condition variables for more information.)

    +

    A condition predicate is typically the negation of the condition expression in the loop. In this noncompliant code example, the condition predicate for removing an element from a linked list is (list->next != nullptr), whereas the condition expression for the while loop condition is (list->next == nullptr).

    +

    This noncompliant code example nests the call to wait() inside an if block and consequently fails to check the condition predicate after the notification is received. If the notification was spurious or malicious, the thread would wake up prematurely.

    + #include <condition_variable> #include <mutex> struct Node { @@ -151,27 +46,11 @@ void consume_list_element(std::condition_variable &condition) { } // Proceed when condition holds. -} - +}
    -

    - This compliant solution calls the - - wait() - - member function from within a - - while - - loop to check the condition both before and after the call to - - wait() - - . -

    - - #include <condition_variable> +

    This compliant solution calls the wait() member function from within a while loop to check the condition both before and after the call to wait().

    + #include <condition_variable> #include <mutex> struct Node { @@ -191,31 +70,11 @@ void consume_list_element() { } // Proceed when condition holds. -} - +}
    -

    - The - - std::condition_variable::wait() - - function has an overloaded form that accepts a function object representing the predicate. This form of - - wait() - - behaves as if it were implemented as - - while (!pred()) wait(lock); - - . This compliant solution uses a lambda as a predicate and passes it to the - - wait() - - function. The predicate is expected to return true when it is safe to proceed, which reverses the predicate logic from the compliant solution using an explicit loop predicate. -

    - - #include <condition_variable> +

    The std::condition_variable::wait() function has an overloaded form that accepts a function object representing the predicate. This form of wait() behaves as if it were implemented as while (!pred()) wait(lock);. This compliant solution uses a lambda as a predicate and passes it to the wait() function. The predicate is expected to return true when it is safe to proceed, which reverses the predicate logic from the compliant solution using an explicit loop predicate.

    + #include <condition_variable> #include <mutex> struct Node { @@ -229,36 +88,13 @@ static std::condition_variable condition; void consume_list_element() { std::unique_lock<std::mutex> lk(m); -  + condition.wait(lk, []{ return list.next; }); // Proceed when condition holds. -} - +}
    -

    - Failure to enclose calls to the - - wait() - - , - - wait_for() - - , or - - wait_until() - - member functions inside a - - while - - loop can lead to indefinite blocking and - - denial of service - - (DoS). -

    +

    Failure to enclose calls to the wait(), wait_for(), or wait_until() member functions inside a while loop can lead to indefinite blocking and denial of service (DoS).

    @@ -295,14 +131,10 @@ void consume_list_element() { Medium @@ -335,9 +167,7 @@ void consume_list_element() { 2021.2 @@ -352,11 +182,7 @@ void consume_list_element() { 2021.4 @@ -371,9 +197,7 @@ void consume_list_element() { 2021.2 @@ -418,17 +240,7 @@ void consume_list_element() {
    - - P2 - + P2 - - L3 - + L3
    - - C++5019 - + C++5019 - - - CERT.CONC.WAKE_IN_LOOP - - + CERT.CONC.WAKE_IN_LOOP - - CERT_CPP-CON54-a - + CERT_CPP-CON54-a Wrap functions that can spuriously wake up in a loop @@ -407,9 +231,7 @@ void consume_list_element() { 4.4 - - 5019 - + 5019
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    @@ -485,9 +297,7 @@ void consume_list_element() { diff --git a/cpp/cert/src/rules/CON55-CPP/PreserveThreadSafetyAndLivenessWhenUsingConditionVariables-standard.qhelp b/cpp/cert/src/rules/CON55-CPP/PreserveThreadSafetyAndLivenessWhenUsingConditionVariables-standard.qhelp index cbd34c40dd..4be9e63e12 100644 --- a/cpp/cert/src/rules/CON55-CPP/PreserveThreadSafetyAndLivenessWhenUsingConditionVariables-standard.qhelp +++ b/cpp/cert/src/rules/CON55-CPP/PreserveThreadSafetyAndLivenessWhenUsingConditionVariables-standard.qhelp @@ -1,168 +1,26 @@
    -

    - Both thread safety and - - liveness - - are concerns when using condition variables. The - - thread-safety - - property requires that all objects maintain consistent states in a multithreaded environment [ - - Lea 2000 - - ]. The - - liveness - - property requires that every operation or function invocation execute to completion without interruption; for example, there is no deadlock. -

    -

    - Condition variables must be used inside a - - while - - loop. (See - - CON54-CPP. Wrap functions that can spuriously wake up in a loop - - for more information.) To guarantee liveness, programs must test the - - while - - loop condition before invoking the - - condition_variable::wait() - - member function. This early test checks whether another thread has already satisfied the - - condition predicate - - and has sent a notification. Invoking - - wait() - - after the notification has been sent results in indefinite blocking. -

    -

    - To guarantee thread safety, programs must test the - - while - - loop condition after returning from - - wait() - - . When a given thread invokes - - wait() - - , it will attempt to block until its condition variable is signaled by a call to - - condition_variable::notify_all() - - or to - - condition_variable::notify_one() - - . -

    -

    - The - - notify_one() - - member function unblocks one of the threads that are blocked on the specified condition variable at the time of the call. If multiple threads are waiting on the same condition variable, the scheduler can select any of those threads to be awakened (assuming that all threads have the same priority level). -

    -

    - The - - notify_all() - - member function unblocks all of the threads that are blocked on the specified condition variable at the time of the call. The order in which threads execute following a call to - - notify_all() - - is unspecified. Consequently, an unrelated thread could start executing, discover that its condition predicate is satisfied, and resume execution even though it was supposed to remain dormant. -

    -

    - For these reasons, threads must check the condition predicate after the - - wait() - - function returns. A - - while - - loop is the best choice for checking the condition predicate both before and after invoking - - wait() - - . -

    -

    - The use of - - notify_one() - - is safe if each thread uses a unique condition variable. If multiple threads share a condition variable, the use of - - notify_one() - - is safe only if the following conditions are met: -

    +

    Both thread safety and liveness are concerns when using condition variables. The thread-safety property requires that all objects maintain consistent states in a multithreaded environment [Lea 2000]. The liveness property requires that every operation or function invocation execute to completion without interruption; for example, there is no deadlock.

    +

    Condition variables must be used inside a while loop. (See CON54-CPP. Wrap functions that can spuriously wake up in a loop for more information.) To guarantee liveness, programs must test the while loop condition before invoking the condition_variable::wait() member function. This early test checks whether another thread has already satisfied the condition predicate and has sent a notification. Invoking wait() after the notification has been sent results in indefinite blocking.

    +

    To guarantee thread safety, programs must test the while loop condition after returning from wait(). When a given thread invokes wait(), it will attempt to block until its condition variable is signaled by a call to condition_variable::notify_all() or to condition_variable::notify_one().

    +

    The notify_one() member function unblocks one of the threads that are blocked on the specified condition variable at the time of the call. If multiple threads are waiting on the same condition variable, the scheduler can select any of those threads to be awakened (assuming that all threads have the same priority level).

    +

    The notify_all() member function unblocks all of the threads that are blocked on the specified condition variable at the time of the call. The order in which threads execute following a call to notify_all() is unspecified. Consequently, an unrelated thread could start executing, discover that its condition predicate is satisfied, and resume execution even though it was supposed to remain dormant.

    +

    For these reasons, threads must check the condition predicate after the wait() function returns. A while loop is the best choice for checking the condition predicate both before and after invoking wait().

    +

    The use of notify_one() is safe if each thread uses a unique condition variable. If multiple threads share a condition variable, the use of notify_one() is safe only if the following conditions are met:

      -
    • - All threads must perform the same set of operations after waking up, which means that any thread can be selected to wake up and resume for a single invocation of - - notify_one() - - . -
    • -
    • - Only one thread is required to wake upon receiving the signal. -
    • +
    • All threads must perform the same set of operations after waking up, which means that any thread can be selected to wake up and resume for a single invocation of notify_one().
    • +
    • Only one thread is required to wake upon receiving the signal.
    -

    - The - - notify_all() - - function can be used to unblock all of the threads that are blocked on the specified condition variable if the use of - - notify_one() - - is unsafe. -

    +

    The notify_all() function can be used to unblock all of the threads that are blocked on the specified condition variable if the use of notify_one() is unsafe.

    -

    - This noncompliant code example uses five threads that are intended to execute sequentially according to the step level assigned to each thread when it is created (serialized processing). The - - currentStep - - variable holds the current step level and is incremented when the respective thread completes. Finally, another thread is signaled so that the next step can be executed. Each thread waits until its step level is ready, and the - - wait() - - call is wrapped inside a - - while - - loop, in compliance with - - CON54-CPP. Wrap functions that can spuriously wake up in a loop. - -

    - - #include <condition_variable> +

    This noncompliant code example uses five threads that are intended to execute sequentially according to the step level assigned to each thread when it is created (serialized processing). The currentStep variable holds the current step level and is incremented when the respective thread completes. Finally, another thread is signaled so that the next step can be executed. Each thread waits until its step level is ready, and the wait() call is wrapped inside a while loop, in compliance with CON54-CPP. Wrap functions that can spuriously wake up in a loop.

    + #include <condition_variable> #include <iostream> #include <mutex> #include <thread> -  + std::mutex mutex; std::condition_variable cond; @@ -201,20 +59,9 @@ int main() { for (size_t i = numThreads; i != 0; --i) { threads[i - 1].join(); } -} - -

    - In this example, all threads share a single condition variable. Each thread has its own distinct condition predicate because each thread requires - - currentStep - - to have a different value before proceeding. When the condition variable is signaled, any of the waiting threads can wake up. The following table illustrates a possible scenario in which the liveness property is violated. If, by chance, the notified thread is not the thread with the next step value, that thread will wait again. No additional notifications can occur, and eventually the pool of available threads will be exhausted. -

    -

    - - Deadlock: Out-of-Sequence Step Value - -

    +}
    +

    In this example, all threads share a single condition variable. Each thread has its own distinct condition predicate because each thread requires currentStep to have a different value before proceeding. When the condition variable is signaled, any of the waiting threads can wake up. The following table illustrates a possible scenario in which the liveness property is violated. If, by chance, the notified thread is not the thread with the next step value, that thread will wait again. No additional notifications can occur, and eventually the pool of available threads will be exhausted.

    +

    Deadlock: Out-of-Sequence Step Value

    7.17.7.4, "The - - atomic_compare_exchange - + atomic_compare_exchange Generic Functions"
    @@ -224,15 +71,11 @@ int main() { @@ -266,10 +107,8 @@ int main() { 0 @@ -283,10 +122,8 @@ int main() { 0 @@ -301,9 +138,7 @@ int main() { @@ -318,9 +153,7 @@ int main() { @@ -335,9 +168,7 @@ int main() { @@ -351,32 +182,17 @@ int main() { —
    Thread # ( - - my_step - + my_step ) - - current_step - + current_step Action @@ -250,9 +93,7 @@ int main() { Thread 3 executes the first time: the predicate is - - false -> wait() - + false -> wait()
    - Thread 2 executes the first time: the predicate is - - false -> wait() - + Thread 2 executes the first time: the predicate is + false -> wait()
    - Thread 4 executes the first time: the predicate is - - false -> wait() - + Thread 4 executes the first time: the predicate is + false -> wait()
    Thread 0 executes the first time: the predicate is - - true -> currentStep++; notify_one() - + true -> currentStep++; notify_one()
    Thread 1 executes the first time: the predicate is - - true -> currentStep++; notify_one() - + true -> currentStep++; notify_one()
    Thread 3 wakes up (scheduler choice): the predicate is - - false -> wait() - + false -> wait()
    - - Thread exhaustion! - + Thread exhaustion! There are no more threads to run, and a conditional variable signal is needed to wake up the others.
    -

    - This noncompliant code example violates the liveness property. -

    +

    This noncompliant code example violates the liveness property.

    -

    - This compliant solution uses - - notify_all() - - to signal all waiting threads instead of a single random thread. Only the - - run_step() - - thread code from the noncompliant code example is modified. -

    - - #include <condition_variable> +

    This compliant solution uses notify_all() to signal all waiting threads instead of a single random thread. Only the run_step() thread code from the noncompliant code example is modified.

    + #include <condition_variable> #include <iostream> #include <mutex> #include <thread> @@ -405,31 +221,14 @@ void run_step(size_t myStep) { std::cout << "Thread " << myStep << " is exiting..." << std::endl; } -  -// ... main() unchanged ... - -

    - Awakening all threads guarantees the liveness property because each thread will execute its condition predicate test, and exactly one will succeed and continue execution. -

    + +// ... main() unchanged ...
    +

    Awakening all threads guarantees the liveness property because each thread will execute its condition predicate test, and exactly one will succeed and continue execution.

    -

    - Another compliant solution is to use a unique condition variable for each thread (all associated with the same mutex). In this case, - - notify_one() - - wakes up only the thread that is waiting on it. - This solution is more efficient than using - - notify_all() - - because only the desired thread is awakened. -

    -

    - The condition predicate of the signaled thread must be true; otherwise, a deadlock will occur. -

    - - #include <condition_variable> +

    Another compliant solution is to use a unique condition variable for each thread (all associated with the same mutex). In this case, notify_one() wakes up only the thread that is waiting on it. This solution is more efficient than using notify_all() because only the desired thread is awakened.

    +

    The condition predicate of the signaled thread must be true; otherwise, a deadlock will occur.

    + #include <condition_variable> #include <iostream> #include <mutex> #include <thread> @@ -463,17 +262,10 @@ void run_step(size_t myStep) { std::cout << "Thread " << myStep << " is exiting..." << std::endl; } -// ... main() unchanged ... - +// ... main() unchanged ...
    -

    - Failing to preserve the thread safety and liveness of a program when using condition variables can lead to indefinite blocking and - - denial of service - - (DoS). -

    +

    Failing to preserve the thread safety and liveness of a program when using condition variables can lead to indefinite blocking and denial of service (DoS).

    @@ -510,14 +302,10 @@ void run_step(size_t myStep) { Medium @@ -550,9 +338,7 @@ void run_step(size_t myStep) { 2021.2 @@ -567,11 +353,7 @@ void run_step(size_t myStep) { 2021.4 @@ -586,9 +368,7 @@ void run_step(size_t myStep) { 2021.2 @@ -615,17 +393,7 @@ void run_step(size_t myStep) {
    - - P2 - + P2 - - L3 - + L3
    - - C++1778, C++1779 - + C++1778, C++1779 - - - CERT.CONC.UNSAFE_COND_VAR - - + CERT.CONC.UNSAFE_COND_VAR - - CERT_CPP-CON55-a - + CERT_CPP-CON55-a Do not use the 'notify_one()' function when multiple threads are waiting on the same condition variable @@ -604,9 +384,7 @@ void run_step(size_t myStep) { 4.4 - - 5020 - + 5020
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    @@ -682,13 +450,9 @@ void run_step(size_t myStep) { diff --git a/cpp/cert/src/rules/CON56-CPP/DoNotSpeculativelyLockALockedNonRecursiveMutex-standard.qhelp b/cpp/cert/src/rules/CON56-CPP/DoNotSpeculativelyLockALockedNonRecursiveMutex-standard.qhelp index 31945b5715..d08bb5af65 100644 --- a/cpp/cert/src/rules/CON56-CPP/DoNotSpeculativelyLockALockedNonRecursiveMutex-standard.qhelp +++ b/cpp/cert/src/rules/CON56-CPP/DoNotSpeculativelyLockALockedNonRecursiveMutex-standard.qhelp @@ -1,175 +1,24 @@
    -

    - The C++ Standard Library supplies both recursive and non-recursive mutex classes used to protect - - critical sections - - . The recursive mutex classes ( - - std::recursive_mutex - - and - - std::recursive_timed_mutex - - ) differ from the non-recursive mutex classes ( - - std::mutex - - , - - std::timed_mutex - - , and - - std::shared_timed_mutex - - ) in that a recursive mutex may be locked recursively by the thread that currently owns the mutex. All mutex classes support the ability to speculatively lock the mutex through functions such as - - try_lock() - - , - - try_lock_for() - - , - - try_lock_until() - - , - - try_lock_shared_for() - - , and - - try_lock_shared_until() - - . These speculative locking functions attempt to obtain ownership of the mutex for the calling thread, but will not block in the event the ownership cannot be obtained. Instead, they return a Boolean value specifying whether the ownership of the mutex was obtained or not. -

    -

    - The C++ Standard, [thread.mutex.requirements.mutex], paragraphs 14 and 15 [ - - ISO/IEC 14882-2014 - - ], state the following: -

    +

    The C++ Standard Library supplies both recursive and non-recursive mutex classes used to protect critical sections. The recursive mutex classes (std::recursive_mutex and std::recursive_timed_mutex) differ from the non-recursive mutex classes (std::mutex, std::timed_mutex, and std::shared_timed_mutex) in that a recursive mutex may be locked recursively by the thread that currently owns the mutex. All mutex classes support the ability to speculatively lock the mutex through functions such as try_lock(), try_lock_for(), try_lock_until(), try_lock_shared_for(), and try_lock_shared_until(). These speculative locking functions attempt to obtain ownership of the mutex for the calling thread, but will not block in the event the ownership cannot be obtained. Instead, they return a Boolean value specifying whether the ownership of the mutex was obtained or not.

    +

    The C++ Standard, [thread.mutex.requirements.mutex], paragraphs 14 and 15 [ISO/IEC 14882-2014], state the following:

    -

    - The expression - - m.try_lock() - - shall be well-formed and have the following semantics: - Requires: If - - m - - is of type - - std::mutex - - , - - std::timed_mutex - - , or - - std::shared_timed_mutex - - , the calling thread does not own the mutex. -

    +

    The expression m.try_lock() shall be well-formed and have the following semantics:Requires: If m is of type std::mutex, std::timed_mutex, or std::shared_timed_mutex, the calling thread does not own the mutex.

    -

    - Further, - [thread.timedmutex.class], paragraph 3, in part, states the following: -

    +

    Further, [thread.timedmutex.class], paragraph 3, in part, states the following:

    -

    - The behavior of a program is undefined if: - — a thread that owns a - - timed_mutex - - object calls - - lock() - - , - - try_lock() - - , - - try_lock_for() - - , or - - try_lock_until() - - on that object -

    +

    The behavior of a program is undefined if:— a thread that owns a timed_mutex object calls lock(), try_lock(), try_lock_for(), or try_lock_until() on that object

    -

    - Finally, [thread.sharedtimedmutex.class], paragraph 3, in part, states the following: -

    +

    Finally, [thread.sharedtimedmutex.class], paragraph 3, in part, states the following:

    -

    - The behavior of a program is undefined if: - — a thread attempts to recursively gain any ownership of a - - shared_timed_mutex - - . -

    +

    The behavior of a program is undefined if:— a thread attempts to recursively gain any ownership of a shared_timed_mutex.

    -

    - Thus, attempting to speculatively lock a non-recursive mutex object that is already owned by the calling thread is - - undefined behavior - - . Do not call - - try_lock() - - , - - try_lock_for() - - , - - try_lock_until() - - , - - try_lock_shared_for() - - , or - - try_lock_shared_until() - - on a non-recursive mutex object from a thread that already owns that mutex object. -

    +

    Thus, attempting to speculatively lock a non-recursive mutex object that is already owned by the calling thread is undefined behavior. Do not call try_lock(), try_lock_for(), try_lock_until(), try_lock_shared_for(), or try_lock_shared_until() on a non-recursive mutex object from a thread that already owns that mutex object.

    -

    - In this noncompliant code example, the mutex - - m - - is locked by the thread's initial entry point and is speculatively locked in the - - do_work() - - function from the same thread, resulting in undefined behavior because it is not a recursive mutex. With common implementations, this may result in - - deadlock - - . -

    - - #include <mutex> +

    In this noncompliant code example, the mutex m is locked by the thread's initial entry point and is speculatively locked in the do_work() function from the same thread, resulting in undefined behavior because it is not a recursive mutex. With common implementations, this may result in deadlock.

    + #include <mutex> #include <thread> std::mutex m; @@ -206,14 +55,11 @@ int main() { t.join(); } - +
    -

    - This compliant solution removes the lock from the thread's initial entry point, allowing the mutex to be speculatively locked, but not recursively. -

    - - #include <mutex> +

    This compliant solution removes the lock from the thread's initial entry point, allowing the mutex to be speculatively locked, but not recursively.

    + #include <mutex> #include <thread> std::mutex m; @@ -247,13 +93,10 @@ int main() { do_work(); t.join(); -} - +}
    -

    - Speculatively locking a non-recursive mutex in a recursive manner is undefined behavior that can lead to deadlock. -

    +

    Speculatively locking a non-recursive mutex in a recursive manner is undefined behavior that can lead to deadlock.

    XSH, System Interfaces, - - pthread_cond_broadcast - + pthread_cond_broadcast XSH, System Interfaces, - - pthread_cond_signal - + pthread_cond_signal
    @@ -290,14 +133,10 @@ int main() { High @@ -330,9 +169,7 @@ int main() { 2021.2 @@ -347,9 +184,7 @@ int main() { 2021.2
    - - P1 - + P1 - - L3 - + L3
    - - C++4986, C++4987 - + C++4986, C++4987 - - CERT_CPP-CON56-a - + CERT_CPP-CON56-a Avoid double locking @@ -359,17 +194,7 @@ int main() {
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/CON56-CPP/LockedALockedNonRecursiveMutexAudit-standard.qhelp b/cpp/cert/src/rules/CON56-CPP/LockedALockedNonRecursiveMutexAudit-standard.qhelp index 31945b5715..d08bb5af65 100644 --- a/cpp/cert/src/rules/CON56-CPP/LockedALockedNonRecursiveMutexAudit-standard.qhelp +++ b/cpp/cert/src/rules/CON56-CPP/LockedALockedNonRecursiveMutexAudit-standard.qhelp @@ -1,175 +1,24 @@
    -

    - The C++ Standard Library supplies both recursive and non-recursive mutex classes used to protect - - critical sections - - . The recursive mutex classes ( - - std::recursive_mutex - - and - - std::recursive_timed_mutex - - ) differ from the non-recursive mutex classes ( - - std::mutex - - , - - std::timed_mutex - - , and - - std::shared_timed_mutex - - ) in that a recursive mutex may be locked recursively by the thread that currently owns the mutex. All mutex classes support the ability to speculatively lock the mutex through functions such as - - try_lock() - - , - - try_lock_for() - - , - - try_lock_until() - - , - - try_lock_shared_for() - - , and - - try_lock_shared_until() - - . These speculative locking functions attempt to obtain ownership of the mutex for the calling thread, but will not block in the event the ownership cannot be obtained. Instead, they return a Boolean value specifying whether the ownership of the mutex was obtained or not. -

    -

    - The C++ Standard, [thread.mutex.requirements.mutex], paragraphs 14 and 15 [ - - ISO/IEC 14882-2014 - - ], state the following: -

    +

    The C++ Standard Library supplies both recursive and non-recursive mutex classes used to protect critical sections. The recursive mutex classes (std::recursive_mutex and std::recursive_timed_mutex) differ from the non-recursive mutex classes (std::mutex, std::timed_mutex, and std::shared_timed_mutex) in that a recursive mutex may be locked recursively by the thread that currently owns the mutex. All mutex classes support the ability to speculatively lock the mutex through functions such as try_lock(), try_lock_for(), try_lock_until(), try_lock_shared_for(), and try_lock_shared_until(). These speculative locking functions attempt to obtain ownership of the mutex for the calling thread, but will not block in the event the ownership cannot be obtained. Instead, they return a Boolean value specifying whether the ownership of the mutex was obtained or not.

    +

    The C++ Standard, [thread.mutex.requirements.mutex], paragraphs 14 and 15 [ISO/IEC 14882-2014], state the following:

    -

    - The expression - - m.try_lock() - - shall be well-formed and have the following semantics: - Requires: If - - m - - is of type - - std::mutex - - , - - std::timed_mutex - - , or - - std::shared_timed_mutex - - , the calling thread does not own the mutex. -

    +

    The expression m.try_lock() shall be well-formed and have the following semantics:Requires: If m is of type std::mutex, std::timed_mutex, or std::shared_timed_mutex, the calling thread does not own the mutex.

    -

    - Further, - [thread.timedmutex.class], paragraph 3, in part, states the following: -

    +

    Further, [thread.timedmutex.class], paragraph 3, in part, states the following:

    -

    - The behavior of a program is undefined if: - — a thread that owns a - - timed_mutex - - object calls - - lock() - - , - - try_lock() - - , - - try_lock_for() - - , or - - try_lock_until() - - on that object -

    +

    The behavior of a program is undefined if:— a thread that owns a timed_mutex object calls lock(), try_lock(), try_lock_for(), or try_lock_until() on that object

    -

    - Finally, [thread.sharedtimedmutex.class], paragraph 3, in part, states the following: -

    +

    Finally, [thread.sharedtimedmutex.class], paragraph 3, in part, states the following:

    -

    - The behavior of a program is undefined if: - — a thread attempts to recursively gain any ownership of a - - shared_timed_mutex - - . -

    +

    The behavior of a program is undefined if:— a thread attempts to recursively gain any ownership of a shared_timed_mutex.

    -

    - Thus, attempting to speculatively lock a non-recursive mutex object that is already owned by the calling thread is - - undefined behavior - - . Do not call - - try_lock() - - , - - try_lock_for() - - , - - try_lock_until() - - , - - try_lock_shared_for() - - , or - - try_lock_shared_until() - - on a non-recursive mutex object from a thread that already owns that mutex object. -

    +

    Thus, attempting to speculatively lock a non-recursive mutex object that is already owned by the calling thread is undefined behavior. Do not call try_lock(), try_lock_for(), try_lock_until(), try_lock_shared_for(), or try_lock_shared_until() on a non-recursive mutex object from a thread that already owns that mutex object.

    -

    - In this noncompliant code example, the mutex - - m - - is locked by the thread's initial entry point and is speculatively locked in the - - do_work() - - function from the same thread, resulting in undefined behavior because it is not a recursive mutex. With common implementations, this may result in - - deadlock - - . -

    - - #include <mutex> +

    In this noncompliant code example, the mutex m is locked by the thread's initial entry point and is speculatively locked in the do_work() function from the same thread, resulting in undefined behavior because it is not a recursive mutex. With common implementations, this may result in deadlock.

    + #include <mutex> #include <thread> std::mutex m; @@ -206,14 +55,11 @@ int main() { t.join(); } - +
    -

    - This compliant solution removes the lock from the thread's initial entry point, allowing the mutex to be speculatively locked, but not recursively. -

    - - #include <mutex> +

    This compliant solution removes the lock from the thread's initial entry point, allowing the mutex to be speculatively locked, but not recursively.

    + #include <mutex> #include <thread> std::mutex m; @@ -247,13 +93,10 @@ int main() { do_work(); t.join(); -} - +}
    -

    - Speculatively locking a non-recursive mutex in a recursive manner is undefined behavior that can lead to deadlock. -

    +

    Speculatively locking a non-recursive mutex in a recursive manner is undefined behavior that can lead to deadlock.

    @@ -290,14 +133,10 @@ int main() { High @@ -330,9 +169,7 @@ int main() { 2021.2 @@ -347,9 +184,7 @@ int main() { 2021.2
    - - P1 - + P1 - - L3 - + L3
    - - C++4986, C++4987 - + C++4986, C++4987 - - CERT_CPP-CON56-a - + CERT_CPP-CON56-a Avoid double locking @@ -359,17 +194,7 @@ int main() {
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/CTR50-CPP/ContainerAccessWithoutRangeCheckCert-standard.qhelp b/cpp/cert/src/rules/CTR50-CPP/ContainerAccessWithoutRangeCheckCert-standard.qhelp index 0d08776b1d..f6e745c17b 100644 --- a/cpp/cert/src/rules/CTR50-CPP/ContainerAccessWithoutRangeCheckCert-standard.qhelp +++ b/cpp/cert/src/rules/CTR50-CPP/ContainerAccessWithoutRangeCheckCert-standard.qhelp @@ -1,96 +1,35 @@
    -

    - Ensuring that array references are within the bounds of the array is almost entirely the responsibility of the programmer. Likewise, when using standard template library vectors, the programmer is responsible for ensuring integer indexes are within the bounds of the vector. -

    +

    Ensuring that array references are within the bounds of the array is almost entirely the responsibility of the programmer. Likewise, when using standard template library vectors, the programmer is responsible for ensuring integer indexes are within the bounds of the vector.

    -

    - This noncompliant code example shows a function, - - insert_in_table() - - , that has two - - int - - parameters, - - pos - - and - - value - - , both of which can be influenced by data originating from untrusted sources. The function performs a range check to ensure that - - pos - - does not exceed the upper bound of the array, specified by - - tableSize - - , but fails to check the lower bound. Because - - pos - - is declared as a (signed) - - int - - , this parameter can assume a negative value, resulting in a write outside the bounds of the memory referenced by - - table - - . -

    - - #include <cstddef> -  +

    This noncompliant code example shows a function, insert_in_table(), that has two int parameters, pos and value, both of which can be influenced by data originating from untrusted sources. The function performs a range check to ensure that pos does not exceed the upper bound of the array, specified by tableSize, but fails to check the lower bound. Because pos is declared as a (signed) int, this parameter can assume a negative value, resulting in a write outside the bounds of the memory referenced by table.

    + #include <cstddef> + void insert_in_table(int *table, std::size_t tableSize, int pos, int value) { if (pos >= tableSize) { // Handle error return; } table[pos] = value; -} - +}
    -

    - In this compliant solution, the parameter - - pos - - is declared as - - size_t - - , which prevents the passing of negative arguments. -

    - - #include <cstddef> -  +

    In this compliant solution, the parameter pos is declared as size_t, which prevents the passing of negative arguments.

    + #include <cstddef> + void insert_in_table(int *table, std::size_t tableSize, std::size_t pos, int value) { if (pos >= tableSize) { // Handle error return; } table[pos] = value; -} - +}
    -

    - Non-type templates can be used to define functions accepting an array type where the array bounds are deduced at compile time. This compliant solution is functionally equivalent to the previous bounds-checking one except that it additionally supports calling - - insert_in_table() - - with an array of known bounds. -

    - - #include <cstddef> +

    Non-type templates can be used to define functions accepting an array type where the array bounds are deduced at compile time. This compliant solution is functionally equivalent to the previous bounds-checking one except that it additionally supports calling insert_in_table() with an array of known bounds.

    + #include <cstddef> #include <new> void insert_in_table(int *table, std::size_t tableSize, std::size_t pos, int value) { // #1 @@ -105,7 +44,7 @@ template <std::size_t N> void insert_in_table(int (&table)[N], std::size_t pos, int value) { // #2 insert_in_table(table, N, pos, value); } -  + void f() { // Exposition only int table1[100]; @@ -115,51 +54,11 @@ void f() { insert_in_table(table1, 100, 0, 0); // Calls #1 insert_in_table(table2, 100, 0, 0); // Calls #1 delete [] table2; -} - +}
    -

    - In this noncompliant code example, a - - std::vector - - is used in place of a pointer and size pair. The function performs a range check to ensure that - - pos - - does not exceed the upper bound of the container. Because - - pos - - is declared as a (signed) - - long long - - , this parameter can assume a negative value. On systems where - - std::vector::size_type - - is ultimately implemented as an - - unsigned int - - (such as with - - Microsoft Visual Studio - - 2013), the usual arithmetic conversions applied for the comparison expression will convert the unsigned value to a signed value. If - - pos - - has a negative value, this comparison will not fail, resulting in a write outside the bounds of the - - std::vector - - object when the negative value is interpreted as a large unsigned value in the indexing operator. -

    - - #include <vector> +

    In this noncompliant code example, a std::vector is used in place of a pointer and size pair. The function performs a range check to ensure that pos does not exceed the upper bound of the container. Because pos is declared as a (signed) long long, this parameter can assume a negative value. On systems where std::vector::size_type is ultimately implemented as an unsigned int (such as with Microsoft Visual Studio 2013), the usual arithmetic conversions applied for the comparison expression will convert the unsigned value to a signed value. If pos has a negative value, this comparison will not fail, resulting in a write outside the bounds of the std::vector object when the negative value is interpreted as a large unsigned value in the indexing operator.

    + #include <vector> void insert_in_table(std::vector<int> &table, long long pos, int value) { if (pos >= table.size()) { @@ -168,22 +67,11 @@ void insert_in_table(std::vector<int> &table, long long pos, int value } table[pos] = value; } - +
    -

    - In this compliant solution, the parameter - - pos - - is declared as - - size_t - - , which ensures that the comparison expression will fail when a large, positive value (converted from a negative argument) is given. -

    - - #include <vector> +

    In this compliant solution, the parameter pos is declared as size_t, which ensures that the comparison expression will fail when a large, positive value (converted from a negative argument) is given.

    + #include <vector> void insert_in_table(std::vector<int> &table, std::size_t pos, int value) { if (pos >= table.size()) { @@ -192,75 +80,20 @@ void insert_in_table(std::vector<int> &table, std::size_t pos, int val } table[pos] = value; } - +
    -

    - In this compliant solution, access to the vector is accomplished with the - - at() - - method. This method provides bounds checking, throwing a - - std::out_of_range - - exception if - - pos - - is not a valid index value. The - - insert_in_table() - - function is declared with - - noexcept(false) - - in compliance with - - ERR55-CPP. Honor exception specifications - - . -

    - - #include <vector> +

    In this compliant solution, access to the vector is accomplished with the at() method. This method provides bounds checking, throwing a std::out_of_range exception if pos is not a valid index value. The insert_in_table() function is declared with noexcept(false) in compliance with ERR55-CPP. Honor exception specifications.

    + #include <vector> void insert_in_table(std::vector<int> &table, std::size_t pos, int value) noexcept(false) { table.at(pos) = value; -} - +}
    -

    - In this noncompliant code example, the - - f_imp() - - function is given the (correct) ending iterator - - e - - for a container, and - - b - - is an iterator from the same container. However, it is possible that - - b - - is not within the valid range of its container. For instance, if the container were empty, - - b - - would equal - - e - - and be improperly dereferenced. -

    - - #include <iterator> -  +

    In this noncompliant code example, the f_imp() function is given the (correct) ending iterator e for a container, and b is an iterator from the same container. However, it is possible that b is not within the valid range of its container. For instance, if the container were empty, b would equal e and be improperly dereferenced.

    + #include <iterator> + template <typename ForwardIterator> void f_imp(ForwardIterator b, ForwardIterator e, int val, std::forward_iterator_tag) { do { @@ -272,18 +105,11 @@ template <typename ForwardIterator> void f(ForwardIterator b, ForwardIterator e, int val) { typename std::iterator_traits<ForwardIterator>::iterator_category cat; f_imp(b, e, val, cat); -} - +}
    -

    - This compliant solution tests for iterator validity before attempting to dereference - - b. - -

    - - #include <iterator> +

    This compliant solution tests for iterator validity before attempting to dereference b.

    + #include <iterator> template <typename ForwardIterator> void f_imp(ForwardIterator b, ForwardIterator e, int val, std::forward_iterator_tag) { @@ -296,17 +122,10 @@ template <typename ForwardIterator> void f(ForwardIterator b, ForwardIterator e, int val) { typename std::iterator_traits<ForwardIterator>::iterator_category cat; f_imp(b, e, val, cat); -} - +}
    -

    - Using an invalid array or container index can result in an arbitrary memory overwrite or - - abnormal program termination - - . -

    +

    Using an invalid array or container index can result in an arbitrary memory overwrite or abnormal program termination.

    @@ -343,14 +162,10 @@ void f(ForwardIterator b, ForwardIterator e, int val) { High @@ -383,9 +198,7 @@ void f(ForwardIterator b, ForwardIterator e, int val) { 20.10 @@ -397,24 +210,13 @@ void f(ForwardIterator b, ForwardIterator e, int val) { @@ -453,46 +253,14 @@ void f(ForwardIterator b, ForwardIterator e, int val) { 2021.4 @@ -506,9 +274,7 @@ void f(ForwardIterator b, ForwardIterator e, int val) { @@ -562,9 +326,7 @@ void f(ForwardIterator b, ForwardIterator e, int val) { 4.4 @@ -576,14 +338,10 @@ void f(ForwardIterator b, ForwardIterator e, int val) { @@ -592,17 +350,7 @@ void f(ForwardIterator b, ForwardIterator e, int val) {
    - - P9 - + P9 - - L2 - + L2
    - - overflow_upon_dereference - + overflow_upon_dereference - 6.1p0 + 6.2p0 - - LANG.MEM.BO - LANG.MEM.BU - LANG.MEM.TO - LANG.MEM.TU - - - LANG.MEM.TBA - - - LANG.STRUCT.PBB - - - LANG.STRUCT.PPE - + LANG.MEM.BOLANG.MEM.BULANG.MEM.TOLANG.MEM.TU + LANG.MEM.TBA + LANG.STRUCT.PBB + LANG.STRUCT.PPE Buffer overrun @@ -436,9 +238,7 @@ void f(ForwardIterator b, ForwardIterator e, int val) { 2021.2 - - C++2891, C++3139, C++3140 - + C++2891, C++3139, C++3140 - - - ABV.ANY_SIZE_ARRAY - - - - - ABV.GENERAL - - - - - ABV.STACK - - - - - ABV.TAINTED - - - - - SV.TAINTED.ALLOC_SIZE - - - - - SV.TAINTED.CALL.INDEX_ACCESS - - - - - SV.TAINTED.CALL.LOOP_BOUND - - - - - SV.TAINTED.INDEX_ACCESS - - + ABV.ANY_SIZE_ARRAY + ABV.GENERAL + ABV.STACK + ABV.TAINTED + SV.TAINTED.ALLOC_SIZE + SV.TAINTED.CALL.INDEX_ACCESS + SV.TAINTED.CALL.LOOP_BOUND + SV.TAINTED.INDEX_ACCESS - - 45 D, 47 S, 476 S, 489 S, 64 X, 66 X, 68 X, 69 X, 70 X, 71 X, 79 X - + 45 D, 47 S, 476 S, 489 S, 64 X, 66 X, 68 X, 69 X, 70 X, 71 X, 79 X Partially implemented @@ -524,9 +290,7 @@ void f(ForwardIterator b, ForwardIterator e, int val) { 2021.2 - - CERT_CPP-CTR50-a - + CERT_CPP-CTR50-a Guarantee that container indices are within the valid range @@ -548,7 +312,7 @@ void f(ForwardIterator b, ForwardIterator e, int val) { Checks for: - Array access out of bounds, array access with tainted index, pointer dereference with tainted offset. + Array access out of boundsrray access out of bounds, array access with tainted indexrray access with tainted index, pointer dereference with tainted offsetointer dereference with tainted offset. Rule partially covered.
    - - 2891, 3139, 3140 - + 2891, 3139, 3140 - 7.16 + 7.17 - - - V781 - - + V781
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/CTR51-CPP/UsesValidContainerElementAccess-standard.qhelp b/cpp/cert/src/rules/CTR51-CPP/UsesValidContainerElementAccess-standard.qhelp index 601c5aff51..5c6dfc87ba 100644 --- a/cpp/cert/src/rules/CTR51-CPP/UsesValidContainerElementAccess-standard.qhelp +++ b/cpp/cert/src/rules/CTR51-CPP/UsesValidContainerElementAccess-standard.qhelp @@ -1,44 +1,13 @@
    -

    - Iterators are a generalization of pointers that allow a C++ program to work with different data structures (containers) in a uniform manner [ - - ISO/IEC 14882-2014 - - ]. Pointers, references, and iterators share a close relationship in which it is required that referencing values be done through a valid iterator, pointer, or reference. Storing an iterator, reference, or pointer to an element within a container for any length of time comes with a risk that the underlying container may be modified such that the stored iterator, pointer, or reference becomes invalid. For instance, when a sequence container such as - - std::vector - - requires an underlying reallocation, outstanding iterators, pointers, and references will be invalidated [ - - Kalev 99 - - ]. Use only a - - valid pointer - - , reference, or iterator to refer to an element of a container. -

    -

    - The C++ Standard, [container.requirements.general], paragraph 12 - [ - - ISO/IEC 14882-2014 - - ] states the following: -

    +

    Iterators are a generalization of pointers that allow a C++ program to work with different data structures (containers) in a uniform manner [ISO/IEC 14882-2014]. Pointers, references, and iterators share a close relationship in which it is required that referencing values be done through a valid iterator, pointer, or reference. Storing an iterator, reference, or pointer to an element within a container for any length of time comes with a risk that the underlying container may be modified such that the stored iterator, pointer, or reference becomes invalid. For instance, when a sequence container such as std::vector requires an underlying reallocation, outstanding iterators, pointers, and references will be invalidated [Kalev 99]. Use only a valid pointer, reference, or iterator to refer to an element of a container.

    +

    The C++ Standard, [container.requirements.general], paragraph 12 [ISO/IEC 14882-2014] states the following:

    -

    - Unless otherwise specified (either explicitly or by defining a function in terms of other functions), invoking a container member function or passing a container as an argument to a library function shall not invalidate iterators to, or change the values of, objects within that container. -

    +

    Unless otherwise specified (either explicitly or by defining a function in terms of other functions), invoking a container member function or passing a container as an argument to a library function shall not invalidate iterators to, or change the values of, objects within that container.

    -

    - The C++ Standard allows references and pointers to be invalidated independently for the same operation, which may result in an invalidated reference but not an invalidated pointer. However, relying on this distinction is insecure because the object pointed to by the pointer may be different than expected even if the pointer is valid. For instance, it is possible to retrieve a pointer to an element from a container, erase that element (invalidating references when destroying the underlying object), then insert a new element at the same location within the container causing the extant pointer to now point to a valid, but distinct object. Thus, any operation that invalidates a pointer or a reference should be treated as though it invalidates both pointers and references. -

    -

    - The following container functions can invalidate iterators, references, and pointers under certain circumstances. -

    +

    The C++ Standard allows references and pointers to be invalidated independently for the same operation, which may result in an invalidated reference but not an invalidated pointer. However, relying on this distinction is insecure because the object pointed to by the pointer may be different than expected even if the pointer is valid. For instance, it is possible to retrieve a pointer to an element from a container, erase that element (invalidating references when destroying the underlying object), then insert a new element at the same location within the container causing the extant pointer to now point to a valid, but distinct object. Thus, any operation that invalidates a pointer or a reference should be treated as though it invalidates both pointers and references.

    +

    The following container functions can invalidate iterators, references, and pointers under certain circumstances.

    @@ -60,9 +29,7 @@ @@ -77,29 +44,17 @@ @@ -176,17 +121,11 @@ @@ -205,13 +142,9 @@ @@ -264,33 +193,19 @@ @@ -343,9 +254,7 @@ @@ -377,21 +278,13 @@ @@ -483,13 +360,9 @@ @@ -532,13 +397,9 @@ @@ -660,60 +503,23 @@
    - - std::deque - + std::deque - - insert() - + insert() , - - emplace_front() - + emplace_front() , - - emplace_back() - + emplace_back() , - - emplace() - + emplace() , - - push_front() - + push_front() , - - push_back() - + push_back() X @@ -116,17 +71,11 @@ - - erase() - + erase() , - - pop_back() - + pop_back() , - - resize() - + resize() X @@ -143,9 +92,7 @@ - - clear() - + clear() X @@ -159,9 +106,7 @@
    - - std::forward_list - + std::forward_list - - erase_after() - + erase_after() , - - pop_front() - + pop_front() , - - resize() - + resize() X @@ -195,9 +134,7 @@ X - - erase_after - + erase_after shall invalidate only iterators and references to the erased elements. ([forwardlist.modifiers], paragraph 1)
    - - remove() - + remove() , - - unique() - + unique() X @@ -227,9 +160,7 @@ - - clear() - + clear() X @@ -247,9 +178,7 @@
    - - std::list - + std::list - - erase() - + erase() , - - pop_front() - + pop_front() , - - pop_back() - + pop_back() , - - clear() - + clear() , - - remove() - + remove() , - - remove_if() - + remove_if() , - - unique() - + unique() X @@ -306,9 +221,7 @@ - - clear() - + clear() X @@ -326,9 +239,7 @@
    - - std::vector - + std::vector - - reserve() - + reserve() X @@ -355,21 +264,13 @@ After - - reserve() - + reserve() , - - capacity() - + capacity() is greater or equal to the argument of - - reserve - + reserve if reallocation happens and is equal to the previous value of - - capacity() - + capacity() otherwise. Reallocation invalidates all the references, pointers, and iterators referring to the elements in the sequence. ([vector.capacity], paragraph 3 & paragraph 6)
    - - insert() - + insert() , - - emplace_back() - + emplace_back() , - - emplace() - + emplace() , - - push_back() - + push_back() X @@ -407,17 +300,11 @@ - - erase() - + erase() , - - pop_back() - + pop_back() , - - resize() - + resize() X @@ -434,9 +321,7 @@ - - clear() - + clear() X @@ -454,21 +339,13 @@
    - - std::set - + std::set , - - std::multiset - + std::multiset , - - std::map - + std::map , - - std::multimap - + std::multimap - - erase() - + erase() , - - clear() - + clear() X @@ -503,21 +376,13 @@
    - - std::unordered_set - + std::unordered_set , - - std::unordered_multiset - + std::unordered_multiset , - - std::unordered_map - + std::unordered_map , - - std::unordered_multimap - + std::unordered_multimap - - erase() - + erase() , - - clear() - + clear() X @@ -554,13 +415,9 @@ - - insert() - + insert() , - - emplace() - + emplace() X @@ -569,13 +426,9 @@ The - - insert - + insert and - - emplace - + emplace members shall not affect the validity of iterators if ( N @@ -597,9 +450,7 @@ N is the number of elements in the container prior to the - - insert - + insert operation, n @@ -620,13 +471,9 @@ - - rehash() - + rehash() , - - reserve() - + reserve() X @@ -640,14 +487,10 @@
    - - std::valarray - + std::valarray - - resize() - + resize()
    -

    - A - - std::basic_string - - object is also a container to which this rule applies. For more specific information pertaining to - - std::basic_string - - containers, see - - STR52-CPP. Use valid references, pointers, and iterators to reference elements of a basic_string - - . -

    +

    A std::basic_string object is also a container to which this rule applies. For more specific information pertaining to std::basic_string containers, see STR52-CPP. Use valid references, pointers, and iterators to reference elements of a basic_string.

    -

    - In this noncompliant code example, - - pos - - is invalidated after the first call to - - insert() - - , and subsequent loop iterations have - - undefined behavior - - . -

    - - #include <deque> -  +

    In this noncompliant code example, pos is invalidated after the first call to insert(), and subsequent loop iterations have undefined behavior.

    + #include <deque> + void f(const double *items, std::size_t count) { std::deque<double> d; auto pos = d.begin(); for (std::size_t i = 0; i < count; ++i, ++pos) { d.insert(pos, items[i] + 41.0); } -} - +}
    -

    - In this compliant solution, - - pos - - is assigned a valid iterator on each insertion, preventing undefined behavior. -

    - - #include <deque> +

    In this compliant solution, pos is assigned a valid iterator on each insertion, preventing undefined behavior.

    + #include <deque> void f(const double *items, std::size_t count) { std::deque<double> d; @@ -722,30 +528,11 @@ void f(const double *items, std::size_t count) { pos = d.insert(pos, items[i] + 41.0); } } - +
    -

    - This compliant solution replaces the handwritten loop with the generic standard template library algorithm - - std::transform() - - . The call to - - std::transform() - - accepts the range of elements to transform, the location to store the transformed values (which, in this case, is a - - std::inserter - - object to insert them at the beginning of - - d - - ), and the transformation function to apply (which, in this case, is a simple lambda). -

    - - #include <algorithm> +

    This compliant solution replaces the handwritten loop with the generic standard template library algorithm std::transform(). The call to std::transform() accepts the range of elements to transform, the location to store the transformed values (which, in this case, is a std::inserter object to insert them at the beginning of d), and the transformation function to apply (which, in this case, is a simple lambda).

    + #include <algorithm> #include <deque> #include <iterator> @@ -754,12 +541,10 @@ void f(const double *items, std::size_t count) { std::transform(items, items + count, std::inserter(d, d.begin()), [](double d) { return d + 41.0; }); } - +
    -

    - Using invalid references, pointers, or iterators to reference elements of a container results in undefined behavior. -

    +

    Using invalid references, pointers, or iterators to reference elements of a container results in undefined behavior.

    @@ -796,14 +581,10 @@ void f(const double *items, std::size_t count) { High @@ -836,11 +617,25 @@ void f(const double *items, std::size_t count) { 20.10 + + + + + + @@ -853,9 +648,7 @@ void f(const double *items, std::size_t count) { 2021.2 @@ -870,9 +663,7 @@ void f(const double *items, std::size_t count) { 2021.4 @@ -887,9 +678,7 @@ void f(const double *items, std::size_t count) { 2021.2 @@ -918,17 +703,7 @@ void f(const double *items, std::size_t count) {
    - - P6 - + P6 - - L2 - + L2
    - - overflow_upon_dereference - + overflow_upon_dereference + +
    + + CodeSonar + + + 6.2p0 + + ALLOC.UAF + Use After Free
    - - C++4746, C++4747, C++4748, C++4749 - + C++4746, C++4747, C++4748, C++4749 - - ITER.CONTAINER.MODIFIED - + ITER.CONTAINER.MODIFIED - - CERT_CPP-CTR51-a - + CERT_CPP-CTR51-a Do not modify container while iterating over it @@ -902,14 +691,10 @@ void f(const double *items, std::size_t count) { - 7.16 + 7.17 - - - V783 - - + V783
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow-standard.qhelp b/cpp/cert/src/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow-standard.qhelp index a5a74acb4c..a7b546f675 100644 --- a/cpp/cert/src/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow-standard.qhelp +++ b/cpp/cert/src/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow-standard.qhelp @@ -1,81 +1,13 @@
    -

    - Copying data into a container that is not large enough to hold that data results in a buffer overflow. To prevent such errors, data copied to the destination container must be restricted on the basis of the destination container's size, or preferably, the destination container must be guaranteed to be large enough to hold the data to be copied. -

    -

    - - Vulnerabilities - - that result from copying data to an undersized buffer can also involve null-terminated strings. Consult - - STR50-CPP. Guarantee that storage for strings has sufficient space for character data and the null terminator - - for specific examples of this rule that involve strings. -

    -

    - Copies can be made with the - - std::memcpy() - - function. However, the - - std::memmove() - - and - - std::memset() - - functions can also have the same vulnerabilities because they overwrite a block of memory without checking that the block is valid. Such issues are not limited to C standard library functions; standard template library (STL) generic algorithms, such as - - std::copy() - - , - - std::fill() - - , and - - std::transform() - - , also assume valid output buffer sizes [ - - ISO/IEC 14882-2014 - - ]. -

    +

    Copying data into a container that is not large enough to hold that data results in a buffer overflow. To prevent such errors, data copied to the destination container must be restricted on the basis of the destination container's size, or preferably, the destination container must be guaranteed to be large enough to hold the data to be copied.

    +

    Vulnerabilities that result from copying data to an undersized buffer can also involve null-terminated strings. Consult STR50-CPP. Guarantee that storage for strings has sufficient space for character data and the null terminator for specific examples of this rule that involve strings.

    +

    Copies can be made with the std::memcpy() function. However, the std::memmove() and std::memset() functions can also have the same vulnerabilities because they overwrite a block of memory without checking that the block is valid. Such issues are not limited to C standard library functions; standard template library (STL) generic algorithms, such as std::copy(), std::fill(), and std::transform(), also assume valid output buffer sizes [ISO/IEC 14882-2014].

    -

    - STL containers can be subject to the same vulnerabilities as array data types. The - - std::copy() - - algorithm provides no inherent bounds checking and can lead to a buffer overflow. In this noncompliant code example, a vector of integers is copied from - - src - - to - - dest - - using - - std::copy() - - . Because - - std::copy() - - does nothing to expand the - - dest - - vector, the program will overflow the buffer on copying the first element. -

    - - #include <algorithm> +

    STL containers can be subject to the same vulnerabilities as array data types. The std::copy() algorithm provides no inherent bounds checking and can lead to a buffer overflow. In this noncompliant code example, a vector of integers is copied from src to dest using std::copy(). Because std::copy() does nothing to expand the dest vector, the program will overflow the buffer on copying the first element.

    + #include <algorithm> #include <vector> void f(const std::vector<int> &src) { @@ -83,21 +15,12 @@ void f(const std::vector<int> &src) { std::copy(src.begin(), src.end(), dest.begin()); // ... } - -

    - This hazard applies to any algorithm that takes a destination iterator, expecting to fill it with values. Most of the STL algorithms expect the destination container to have sufficient space to hold the values provided. -

    +
    +

    This hazard applies to any algorithm that takes a destination iterator, expecting to fill it with values. Most of the STL algorithms expect the destination container to have sufficient space to hold the values provided.

    -

    - The proper way to use - - std::copy() - - is to ensure the destination container can hold all the elements being copied to it. This compliant solution enlarges the capacity of the vector prior to the copy operation. -

    - - #include <algorithm> +

    The proper way to use std::copy() is to ensure the destination container can hold all the elements being copied to it. This compliant solution enlarges the capacity of the vector prior to the copy operation.

    + #include <algorithm> #include <vector> void f(const std::vector<int> &src) { // Initialize dest with src.size() default-inserted elements @@ -105,18 +28,11 @@ void f(const std::vector<int> &src) { std::copy(src.begin(), src.end(), dest.begin()); // ... } - +
    -

    - An alternative approach is to supply a - - std::back_insert_iterator - - as the destination argument. This iterator expands the destination container by one element for each element supplied by the algorithm, which guarantees the destination container will become sufficiently large to hold the elements provided. -

    - - #include <algorithm> +

    An alternative approach is to supply a std::back_insert_iterator as the destination argument. This iterator expands the destination container by one element for each element supplied by the algorithm, which guarantees the destination container will become sufficiently large to hold the elements provided.

    + #include <algorithm> #include <iterator> #include <vector> @@ -124,106 +40,49 @@ void f(const std::vector<int> &src) { std::vector<int> dest; std::copy(src.begin(), src.end(), std::back_inserter(dest)); // ... -} - +}
    -

    - The simplest solution is to construct - - dest - - from - - src - - directly, as in this compliant solution. -

    - - #include <vector> +

    The simplest solution is to construct dest from src directly, as in this compliant solution.

    + #include <vector> void f(const std::vector<int> &src) { std::vector<int> dest(src); // ... -} - +}
    -

    - In this noncompliant code example, - - std::fill_n() - - is used to fill a buffer with 10 instances of the value - - 0x42 - - . However, the buffer has not allocated any space for the elements, so this operation results in a buffer overflow. -

    - - #include <algorithm> +

    In this noncompliant code example, std::fill_n() is used to fill a buffer with 10 instances of the value 0x42. However, the buffer has not allocated any space for the elements, so this operation results in a buffer overflow.

    + #include <algorithm> #include <vector> void f() { std::vector<int> v; std::fill_n(v.begin(), 10, 0x42); -} - +}
    -

    - This compliant solution ensures the capacity of the vector is sufficient before attempting to fill the container. -

    - - #include <algorithm> +

    This compliant solution ensures the capacity of the vector is sufficient before attempting to fill the container.

    + #include <algorithm> #include <vector> void f() { std::vector<int> v(10); std::fill_n(v.begin(), 10, 0x42); -} - -

    - However, this compliant solution is inefficient. The constructor will default-construct 10 elements of type - - int - - , which are subsequently replaced by the call to - - std::fill_n() - - , meaning that each element in the container is initialized twice. -

    +}
    +

    However, this compliant solution is inefficient. The constructor will default-construct 10 elements of type int, which are subsequently replaced by the call to std::fill_n(), meaning that each element in the container is initialized twice.

    -

    - This compliant solution initializes - - v - - to 10 elements whose values are all - - 0x42 - - . -

    - - #include <algorithm> +

    This compliant solution initializes v to 10 elements whose values are all 0x42.

    + #include <algorithm> #include <vector> void f() { std::vector<int> v(10, 0x42); -} - +}
    -

    - Copying data to a buffer that is too small to hold the data results in a buffer overflow. Attackers can - - exploit - - this condition to execute arbitrary code. -

    +

    Copying data to a buffer that is too small to hold the data results in a buffer overflow. Attackers can exploit this condition to execute arbitrary code.

    @@ -260,14 +119,10 @@ void f() { Medium @@ -300,9 +155,7 @@ void f() { 20.10 @@ -314,15 +167,11 @@ void f() { @@ -356,9 +203,7 @@ void f() { 2021.2
    - - P18 - + P18 - - L1 - + L1
    - - invalid_pointer_dereference - + invalid_pointer_dereference - 6.1p0 + 6.2p0 - - BADFUNC.BO.* - - - LANG.MEM.BO - + BADFUNC.BO.* + LANG.MEM.BO A collection of warning classes that report uses of library functions prone to internal buffer overflows. @@ -339,9 +188,7 @@ void f() { 2021.2 - - C++3526, C++3527, C++3528, C++3529, C++3530, C++3531, C++3532, C++3533, C++3534 - + C++3526, C++3527, C++3528, C++3529, C++3530, C++3531, C++3532, C++3533, C++3534 - - CERT_CPP-CTR52-a - + CERT_CPP-CTR52-a Do not pass empty container iterators to std algorithms as destinations @@ -368,17 +213,7 @@ void f() {
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/CTR53-CPP/UseValidIteratorRanges-standard.qhelp b/cpp/cert/src/rules/CTR53-CPP/UseValidIteratorRanges-standard.qhelp index 0746b4a421..fbed267755 100644 --- a/cpp/cert/src/rules/CTR53-CPP/UseValidIteratorRanges-standard.qhelp +++ b/cpp/cert/src/rules/CTR53-CPP/UseValidIteratorRanges-standard.qhelp @@ -1,130 +1,61 @@
    -

    - When iterating over elements of a container, the iterators used must iterate over a valid range. An iterator range is a pair of iterators that refer to the first and past-the-end elements of the range respectively. -

    -

    - A valid iterator range has all of the following characteristics: -

    +

    When iterating over elements of a container, the iterators used must iterate over a valid range. An iterator range is a pair of iterators that refer to the first and past-the-end elements of the range respectively.

    +

    A valid iterator range has all of the following characteristics:

    -

    - An empty iterator range (where the two iterators are valid and equivalent) is considered to be valid. -

    -

    - Using a range of two iterators that are invalidated or do not refer into the same container results in - - undefined behavior - - . -

    +

    An empty iterator range (where the two iterators are valid and equivalent) is considered to be valid.

    +

    Using a range of two iterators that are invalidated or do not refer into the same container results in undefined behavior.

    -

    - In this noncompliant example, the two iterators that delimit the range point into the same container, but the first iterator does not precede the second. On each iteration of its internal loop, - - std::for_each() - - compares the first iterator (after incrementing it) with the second for equality; as long as they are not equal, it will continue to increment the first iterator. Incrementing the iterator representing the past-the-end element of the range results in - - undefined behavior - - . -

    - - #include <algorithm> +

    In this noncompliant example, the two iterators that delimit the range point into the same container, but the first iterator does not precede the second. On each iteration of its internal loop, std::for_each() compares the first iterator (after incrementing it) with the second for equality; as long as they are not equal, it will continue to increment the first iterator. Incrementing the iterator representing the past-the-end element of the range results in undefined behavior.

    + #include <algorithm> #include <iostream> #include <vector> -  + void f(const std::vector<int> &c) { std::for_each(c.end(), c.begin(), [](int i) { std::cout << i; }); -} - -

    - Invalid iterator ranges can also result from comparison functions that return true for equal values. See - - CTR57-CPP. Provide a valid ordering predicate - - for more information about comparators. -

    +}
    +

    Invalid iterator ranges can also result from comparison functions that return true for equal values. See CTR57-CPP. Provide a valid ordering predicate for more information about comparators.

    -

    - In this compliant solution, the iterator values passed to - - std::for_each() - - are passed in the proper order. -

    - - #include <algorithm> +

    In this compliant solution, the iterator values passed to std::for_each() are passed in the proper order.

    + #include <algorithm> #include <iostream> #include <vector> void f(const std::vector<int> &c) { std::for_each(c.begin(), c.end(), [](int i) { std::cout << i; }); -} - +}
    -

    - In this noncompliant code example, iterators from different containers are passed for the same iterator range. Although many STL - - implementations - - will compile this code and the program may behave as the developer expects, there is no requirement that an STL implementation treat a default-initialized iterator as a synonym for the iterator returned by - - end() - - . -

    - - #include <algorithm> +

    In this noncompliant code example, iterators from different containers are passed for the same iterator range. Although many STL implementations will compile this code and the program may behave as the developer expects, there is no requirement that an STL implementation treat a default-initialized iterator as a synonym for the iterator returned by end().

    + #include <algorithm> #include <iostream> #include <vector> void f(const std::vector<int> &c) { std::vector<int>::const_iterator e; std::for_each(c.begin(), e, [](int i) { std::cout << i; }); -} - +}
    -

    - In this compliant solution, the proper iterator generated by a call to - - end() - - is passed. -

    - - #include <algorithm> +

    In this compliant solution, the proper iterator generated by a call to end() is passed.

    + #include <algorithm> #include <iostream> #include <vector> void f(const std::vector<int> &c) { std::for_each(c.begin(), c.end(), [](int i) { std::cout << i; }); } - +
    -

    - Using an invalid iterator range is similar to allowing a buffer overflow, which can lead to an attacker running arbitrary code. -

    +

    Using an invalid iterator range is similar to allowing a buffer overflow, which can lead to an attacker running arbitrary code.

    @@ -161,14 +92,10 @@ void f(const std::vector<int> &c) { High @@ -201,11 +128,25 @@ void f(const std::vector<int> &c) { 20.10 + + + + + + @@ -218,9 +159,7 @@ void f(const std::vector<int> &c) { 2021.2 @@ -235,12 +174,8 @@ void f(const std::vector<int> &c) { 2021.2 @@ -271,26 +204,14 @@ void f(const std::vector<int> &c) { @@ -299,32 +220,8 @@ void f(const std::vector<int> &c) {
    - - P6 - + P6 - - L2 - + L2
    - - overflow_upon_dereference - + overflow_upon_dereference + +
    + + CodeSonar + + + 6.2p0 + + LANG.MEM.BO + Buffer Overrun
    - - C++3802 - + C++3802 - - CERT_CPP-CTR53-a - - - CERT_CPP-CTR53-b - + CERT_CPP-CTR53-a + CERT_CPP-CTR53-b Do not use an iterator range that isn't really a range @@ -257,9 +192,7 @@ void f(const std::vector<int> &c) { 4.4 - - 3802 - + 3802 - 7.16 + 7.17 - - V539 - - - + V539 , - - V662 - - - + V662 , - - - V789 - - + V789
    -

    - In - - Fun with erase() - - , Chris Rohlf discusses the exploit potential of a program that calls - - vector::erase() - - with invalid iterator ranges [ - - Rohlf 2009 - - ]. -

    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    In Fun with erase(), Chris Rohlf discusses the exploit potential of a program that calls vector::erase() with invalid iterator ranges [Rohlf 2009].

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    @@ -373,9 +270,7 @@ void f(const std::vector<int> &c) { diff --git a/cpp/cert/src/rules/CTR54-CPP/DoNotSubtractIteratorsForDifferentContainers-standard.qhelp b/cpp/cert/src/rules/CTR54-CPP/DoNotSubtractIteratorsForDifferentContainers-standard.qhelp index 404b05a8e8..98471d8e1a 100644 --- a/cpp/cert/src/rules/CTR54-CPP/DoNotSubtractIteratorsForDifferentContainers-standard.qhelp +++ b/cpp/cert/src/rules/CTR54-CPP/DoNotSubtractIteratorsForDifferentContainers-standard.qhelp @@ -1,53 +1,12 @@
    -

    - When two pointers are subtracted, both must point to elements of the same array object or to one past the last element of the array object; the result is the difference of the subscripts of the two array elements. Similarly, when two iterators are subtracted (including via - - std::distance() - - ), both iterators must refer to the same container object or must be obtained via a call to - - end() - - (or - - cend() - - ) on the same container object. -

    -

    - If two unrelated iterators (including pointers) are subtracted, the operation results in - - undefined behavior - - [ - - ISO/IEC 14882-2014 - - ] - . Do not subtract two iterators (including pointers) unless both point into the same container or one past the end of the same container. -

    +

    When two pointers are subtracted, both must point to elements of the same array object or to one past the last element of the array object; the result is the difference of the subscripts of the two array elements. Similarly, when two iterators are subtracted (including via std::distance()), both iterators must refer to the same container object or must be obtained via a call to end() (or cend()) on the same container object.

    +

    If two unrelated iterators (including pointers) are subtracted, the operation results in undefined behavior [ISO/IEC 14882-2014]. Do not subtract two iterators (including pointers) unless both point into the same container or one past the end of the same container.

    -

    - This noncompliant code example attempts to determine whether the - pointer - - test - - is within the range - - [r, r + n] - - . However, when - - test - - does not point within the given range, as in this example, the subtraction produces undefined behavior. -

    - - #include <cstddef> +

    This noncompliant code example attempts to determine whether the pointer test is within the range [r, r + n]. However, when test does not point within the given range, as in this example, the subtraction produces undefined behavior.

    + #include <cstddef> #include <iostream> template <typename Ty> @@ -60,115 +19,15 @@ void f() { double *x = &foo[0]; double bar; std::cout << std::boolalpha << in_range(&bar, x, 10); -} - +}
    -

    - In this noncompliant code example, the - - in_range() - - function is implemented using a comparison expression instead of subtraction. The C++ Standard, [expr.rel], paragraph 4 [ - - ISO/IEC 14882-2014 - - ], states the following: -

    +

    In this noncompliant code example, the in_range() function is implemented using a comparison expression instead of subtraction. The C++ Standard, [expr.rel], paragraph 4 [ISO/IEC 14882-2014], states the following:

    -

    - If two operands - - p - - and - - q - - compare equal, - - p<=q - - and - - p>=q - - both yield - - true - - and - - p<q - - and - - p>q - - both yield - - false - - . Otherwise, if a pointer - - p - - compares greater than a pointer - - q - - , - - p>=q - - , - - p>q - - , - - q<=p - - , and - - q<p - - all yield - - true - - and - - p<=q - - , - - p<q - - , - - q>=p - - , and - - q>p - - all yield - - false - - . Otherwise, the result of each of the operators is unspecified. -

    +

    If two operands p and q compare equal, p<=q and p>=q both yield true and p<q and p>q both yield false. Otherwise, if a pointer p compares greater than a pointer q, p>=q, p>q, q<=p, and q<p all yield true and p<=q, p<q, q>=p, and q>p all yield false. Otherwise, the result of each of the operators is unspecified.

    -

    - Thus, comparing two pointers that do not point into the same container or one past the end of the container results in - - unspecified behavior - - . Although the following example is an improvement over the previous noncompliant code example, it does not result in portable code and may fail when executed on a segmented memory architecture (such as some antiquated x86 variants). Consequently, it is noncompliant. -

    - - #include <iostream> +

    Thus, comparing two pointers that do not point into the same container or one past the end of the container results in unspecified behavior. Although the following example is an improvement over the previous noncompliant code example, it does not result in portable code and may fail when executed on a segmented memory architecture (such as some antiquated x86 variants). Consequently, it is noncompliant.

    + #include <iostream> template <typename Ty> bool in_range(const Ty *test, const Ty *r, size_t n) { @@ -180,39 +39,11 @@ void f() { double *x = &foo[0]; double bar; std::cout << std::boolalpha << in_range(&bar, x, 10); -} - +}
    -

    - This noncompliant code example is roughly equivalent to the previous example, except that it uses iterators in place of raw pointers. As with the previous example, the - - in_range_impl() - - function exhibits - - unspecified behavior - - when the iterators do not refer into the same container because the operational semantics of - - a < b - - on a random access iterator are - - b - a > 0 - - , and - - >= - - is implemented in terms of - - < - - . -

    - - #include <iostream> +

    This noncompliant code example is roughly equivalent to the previous example, except that it uses iterators in place of raw pointers. As with the previous example, the in_range_impl() function exhibits unspecified behavior when the iterators do not refer into the same container because the operational semantics of a < b on a random access iterator are b - a > 0, and >= is implemented in terms of <.

    + #include <iostream> #include <iterator> #include <vector> @@ -231,95 +62,15 @@ void f() { std::vector<double> foo(10); std::vector<double> bar(1); std::cout << std::boolalpha << in_range(bar.begin(), foo.begin(), foo.end()); -} - +}
    -

    - In this noncompliant code example, - - std::less<> - - is used in place of the - - < - - operator. The C++ Standard, [comparisons], paragraph 14 [ - - ISO/IEC 14882-2014 - - ], states the following: -

    +

    In this noncompliant code example, std::less<> is used in place of the < operator. The C++ Standard, [comparisons], paragraph 14 [ISO/IEC 14882-2014], states the following:

    -

    - For templates - - greater - - , - - less - - , - - greater_equal - - , and - - less_equal - - , the specializations for any pointer type yield a total order, even if the built-in operators - - < - - , - - > - - , - - <= - - , - - >= - - do not. -

    +

    For templates greater, less, greater_equal, and less_equal, the specializations for any pointer type yield a total order, even if the built-in operators <, >, <=, >= do not.

    -

    - Although this approach yields a total ordering, the definition of that total ordering is still unspecified by the - - implementation - - . For instance, the following statement could result in the assertion triggering for a given, unrelated pair of pointers, - - a - - and - - b - - : - - assert(std::less<T *>()(a, b) == std::greater<T *>()(a, b)); - - . Consequently, this noncompliant code example is still nonportable and, on common implementations of - - std::less<> - - , may even result in - - undefined behavior - - when the - - < - - operator is invoked. -

    - - #include <functional> +

    Although this approach yields a total ordering, the definition of that total ordering is still unspecified by the implementation. For instance, the following statement could result in the assertion triggering for a given, unrelated pair of pointers, a and b: assert(std::less<T *>()(a, b) == std::greater<T *>()(a, b));. Consequently, this noncompliant code example is still nonportable and, on common implementations of std::less<>, may even result in undefined behavior when the < operator is invoked.

    + #include <functional> #include <iostream> template <typename Ty> @@ -333,27 +84,11 @@ void f() { double *x = &foo[0]; double bar; std::cout << std::boolalpha << in_range(&bar, x, 10); -} - +}
    -

    - This compliant solution demonstrates a fully portable, but likely inefficient, implementation of - - in_range() - - that compares - - test - - against each possible address in the range - - [r, n] - - . A compliant solution that is both efficient and fully portable is currently unknown. -

    - - #include <iostream> +

    This compliant solution demonstrates a fully portable, but likely inefficient, implementation of in_range() that compares test against each possible address in the range [r, n]. A compliant solution that is both efficient and fully portable is currently unknown.

    + #include <iostream> template <typename Ty> bool in_range(const Ty *test, const Ty *r, size_t n) { @@ -375,7 +110,7 @@ void f() { double bar; std::cout << std::boolalpha << in_range(&bar, x, 10); } - +
    Item 32, "Follow Remove-Like Algorithms with - - erase - + erase If You Really Want to Remove Something"
    @@ -414,14 +149,10 @@ void f() { Medium @@ -454,12 +185,27 @@ void f() { 20.10 + + + + + + @@ -472,9 +218,7 @@ void f() { 2021.2 @@ -488,9 +232,7 @@ void f() {
    - - P8 - + P8 - - L2 - + L2
    - - invalid_pointer_subtraction - invalid_pointer_comparison - + invalid_pointer_subtractioninvalid_pointer_comparison + +
    + + CodeSonar + + + 6.2p0 + + LANG.STRUCT.CUP + LANG.STRUCT.SUP + Comparison of Unrelated Pointers + Subtraction of Unrelated Pointers
    - - C++2668, C++2761, C++2762, C++2763, C++2766, C++2767, C++2768 - + C++2668, C++2761, C++2762, C++2763, C++2766, C++2767, C++2768 - - 70 S, 87 S, 437 S, 438 S - + 70 S, 87 S, 437 S, 438 S Enhanced Enforcement @@ -506,15 +248,9 @@ void f() { 2021.2 - - CERT_CPP-CTR54-a - - - CERT_CPP-CTR54-b - - - CERT_CPP-CTR54-c - + CERT_CPP-CTR54-a + CERT_CPP-CTR54-b + CERT_CPP-CTR54-c Do not compare iterators from different containers @@ -532,9 +268,7 @@ void f() { 4.4 - - 2668, 2761, 2762, 2763, 2766, 2767, 2768 - + 2668, 2761, 2762, 2763, 2766, 2767, 2768 Enforced by QA-CPP @@ -544,17 +278,7 @@ void f() {
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator-standard.qhelp b/cpp/cert/src/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator-standard.qhelp index 0ca34019ef..cc113fc3d3 100644 --- a/cpp/cert/src/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator-standard.qhelp +++ b/cpp/cert/src/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator-standard.qhelp @@ -1,75 +1,30 @@
    -

    - Expressions that have an integral type can be added to or subtracted from a pointer, resulting in a value of the pointer type. If the resulting pointer is not a valid member of the container, or one past the last element of the container, the behavior of the additive operator is - - undefined - - . The C++ Standard, [expr.add], paragraph 5 [ - - ISO/IEC 14882-2014 - - ], in part, states the following: -

    +

    Expressions that have an integral type can be added to or subtracted from a pointer, resulting in a value of the pointer type. If the resulting pointer is not a valid member of the container, or one past the last element of the container, the behavior of the additive operator is undefined. The C++ Standard, [expr.add], paragraph 5 [ISO/IEC 14882-2014], in part, states the following:

    -

    - If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined. -

    +

    If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined.

    -

    - Because iterators are a generalization of pointers, the same constraints apply to additive operators with random access iterators. Specifically, the C++ Standard, [iterator.requirements.general], paragraph 5, states the following: -

    +

    Because iterators are a generalization of pointers, the same constraints apply to additive operators with random access iterators. Specifically, the C++ Standard, [iterator.requirements.general], paragraph 5, states the following:

    -

    - Just as a regular pointer to an array guarantees that there is a pointer value pointing past the last element of the array, so for any iterator type there is an iterator value that points past the last element of a corresponding sequence. These values are called - - past-the-end - - values. Values of an iterator - - i - - for which the expression - - *i - - is defined are called - - dereferenceable - - . The library never assumes that past-the-end values are dereferenceable. -

    +

    Just as a regular pointer to an array guarantees that there is a pointer value pointing past the last element of the array, so for any iterator type there is an iterator value that points past the last element of a corresponding sequence. These values are called past-the-end values. Values of an iterator i for which the expression *i is defined are called dereferenceable. The library never assumes that past-the-end values are dereferenceable.

    -

    - Do not allow an expression of integral type to add to or subtract from a pointer or random access iterator when the resulting value would overflow the bounds of the container. -

    +

    Do not allow an expression of integral type to add to or subtract from a pointer or random access iterator when the resulting value would overflow the bounds of the container.

    -

    - In this noncompliant code example, a random access iterator from a - - std::vector - - is used in an additive expression, but the resulting value could be outside the bounds of the container rather than a past-the-end value. -

    - - #include <iostream> +

    In this noncompliant code example, a random access iterator from a std::vector is used in an additive expression, but the resulting value could be outside the bounds of the container rather than a past-the-end value.

    + #include <iostream> #include <vector> -  + void f(const std::vector<int> &c) { for (auto i = c.begin(), e = i + 20; i != e; ++i) { std::cout << *i << std::endl; } -} - +}
    -

    - This compliant solution assumes that the programmer's intention was to process up to 20 items in the container. Instead of assuming all containers will have 20 or more elements, the size of the container is used to determine the upper bound on the addition. -

    - - #include <algorithm> +

    This compliant solution assumes that the programmer's intention was to process up to 20 items in the container. Instead of assuming all containers will have 20 or more elements, the size of the container is used to determine the upper bound on the addition.

    + #include <algorithm> #include <vector> void f(const std::vector<int> &c) { @@ -77,21 +32,10 @@ void f(const std::vector<int> &c) { for (auto i = c.begin(), e = i + std::min(maxSize, c.size()); i != e; ++i) { // ... } -} - +}
    -

    - If adding or subtracting an integer to a pointer results in a reference to an element outside the array or one past the last element of the array object, the behavior is - - undefined - - but frequently leads to a buffer overflow or buffer underrun, which can often be - - exploited - - to run arbitrary code. Iterators and standard template library containers exhibit the same behavior and caveats as pointers and arrays. -

    +

    If adding or subtracting an integer to a pointer results in a reference to an element outside the array or one past the last element of the array object, the behavior is undefined but frequently leads to a buffer overflow or buffer underrun, which can often be exploited to run arbitrary code. Iterators and standard template library containers exhibit the same behavior and caveats as pointers and arrays.

    @@ -128,14 +72,10 @@ void f(const std::vector<int> &c) { Medium @@ -168,9 +108,7 @@ void f(const std::vector<int> &c) { 2021.2 @@ -184,9 +122,7 @@ void f(const std::vector<int> &c) {
    - - P18 - + P18 - - L1 - + L1
    - - C++3526, C++3527, C++3528, C++3529, C++3530, C++3531, C++3532, C++3533, C++3534 - + C++3526, C++3527, C++3528, C++3529, C++3530, C++3531, C++3532, C++3533, C++3534 - - 567 S - + 567 S Enhanced Enforcement @@ -202,9 +138,7 @@ void f(const std::vector<int> &c) { 2021.2 - - CERT_CPP-CTR55-a - + CERT_CPP-CTR55-a Do not add or subtract a constant with a value greater than one from an iterator @@ -214,17 +148,7 @@ void f(const std::vector<int> &c) {
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/CTR56-CPP/DoNotUsePointerArithmeticOnPolymorphicObjects-standard.qhelp b/cpp/cert/src/rules/CTR56-CPP/DoNotUsePointerArithmeticOnPolymorphicObjects-standard.qhelp index 722e393d68..687cd9d486 100644 --- a/cpp/cert/src/rules/CTR56-CPP/DoNotUsePointerArithmeticOnPolymorphicObjects-standard.qhelp +++ b/cpp/cert/src/rules/CTR56-CPP/DoNotUsePointerArithmeticOnPolymorphicObjects-standard.qhelp @@ -1,84 +1,18 @@
    -

    - The definition of - - pointer arithmetic - - from the C++ Standard, [expr.add], paragraph 7 [ - - ISO/IEC 14882-2014 - - ], states the following: -

    +

    The definition of pointer arithmetic from the C++ Standard, [expr.add], paragraph 7 [ISO/IEC 14882-2014], states the following:

    -

    - For addition or subtraction, if the expressions - - P - - or - - Q - - have type “pointer to - - cv - - - T - - ”, where - - T - - is different from the cv-unqualified array element type, the behavior is undefined. [ - - Note: - - In particular, a pointer to a base class cannot be used for pointer arithmetic when the array contains objects of a derived class type. — - - end note - - ] -

    +

    For addition or subtraction, if the expressions P or Q have type “pointer to cv T”, where T is different from the cv-unqualified array element type, the behavior is undefined. [Note: In particular, a pointer to a base class cannot be used for pointer arithmetic when the array contains objects of a derived class type. —end note]

    -

    - Pointer arithmetic does not account for polymorphic object sizes, and attempting to perform pointer arithmetic on a polymorphic object value results in - - undefined behavior - - . -

    -

    - The C++ Standard, [expr.sub], paragraph 1 [ - - ISO/IEC 14882-2014 - - ], defines array subscripting as being identical to pointer arithmetic. Specifically, it states the following: -

    +

    Pointer arithmetic does not account for polymorphic object sizes, and attempting to perform pointer arithmetic on a polymorphic object value results in undefined behavior.

    +

    The C++ Standard, [expr.sub], paragraph 1 [ISO/IEC 14882-2014], defines array subscripting as being identical to pointer arithmetic. Specifically, it states the following:

    -

    - The expression - - E1[E2] - - is identical (by definition) to - - *((E1)+(E2)) - - . -

    +

    The expression E1[E2] is identical (by definition) to *((E1)+(E2)).

    -

    - Do not use pointer arithmetic, including array subscripting, on polymorphic objects. -

    -

    - The following code examples assume the following static variables and class definitions. -

    - - int globI; +

    Do not use pointer arithmetic, including array subscripting, on polymorphic objects.

    +

    The following code examples assume the following static variables and class definitions.

    + int globI; double globD; struct S { @@ -91,44 +25,12 @@ struct T : S { double d; T() : S(), d(globD++) {} -}; - +};
    -

    - In this noncompliant code example, - - f() - - accepts an array of - - S - - objects as its first parameter. However, - - main() - - passes an array of - - T - - objects as the first argument to - - f() - - , which results in - - undefined behavior - - due to the pointer arithmetic used within the - - for - - loop. -

    - - #include <iostream> -  +

    In this noncompliant code example, f() accepts an array of S objects as its first parameter. However, main() passes an array of T objects as the first argument to f(), which results in undefined behavior due to the pointer arithmetic used within the for loop.

    + #include <iostream> + // ... definitions for S, T, globI, globD ... void f(const S *someSes, std::size_t count) { @@ -141,20 +43,12 @@ int main() { T test[5]; f(test, 5); } - +
    -

    - In this noncompliant code example, the - - for - - loop uses array subscripting. Since array subscripts are computed using pointer arithmetic, this code also results in undefined behavior - . -

    - - #include <iostream> -  +

    In this noncompliant code example, the for loop uses array subscripting. Since array subscripts are computed using pointer arithmetic, this code also results in undefined behavior.

    + #include <iostream> + // ... definitions for S, T, globI, globD ... void f(const S *someSes, std::size_t count) { @@ -166,15 +60,11 @@ void f(const S *someSes, std::size_t count) { int main() { T test[5]; f(test, 5); -} - +}
    -

    - Instead of having an array of objects, an array of pointers solves the problem of the objects being of different sizes, as in this compliant solution. -

    - - #include <iostream> +

    Instead of having an array of objects, an array of pointers solves the problem of the objects being of different sizes, as in this compliant solution.

    + #include <iostream> // ... definitions for S, T, globI, globD ... @@ -191,25 +81,12 @@ int main() { delete v; } } - -

    - The elements in the arrays are no longer polymorphic objects (instead, they are pointers to polymorphic objects), and so there is no - - undefined behavior - - with the pointer arithmetic. -

    +
    +

    The elements in the arrays are no longer polymorphic objects (instead, they are pointers to polymorphic objects), and so there is no undefined behavior with the pointer arithmetic.

    -

    - Another approach is to use a standard template library (STL) container instead of an array and have - - f() - - accept iterators as parameters, as in this compliant solution. However, because STL containers require homogeneous elements, pointers are still required within the container. -

    - - #include <iostream> +

    Another approach is to use a standard template library (STL) container instead of an array and have f() accept iterators as parameters, as in this compliant solution. However, because STL containers require homogeneous elements, pointers are still required within the container.

    + #include <iostream> #include <vector> // ... definitions for S, T, globI, globD ... @@ -227,12 +104,10 @@ int main() { delete v; } } - +
    -

    - Using arrays polymorphically can result in memory corruption, which could lead to an attacker being able to execute arbitrary code. -

    +

    Using arrays polymorphically can result in memory corruption, which could lead to an attacker being able to execute arbitrary code.

    @@ -269,14 +144,10 @@ int main() { High @@ -309,9 +180,7 @@ int main() { 7.2.0 @@ -326,9 +195,7 @@ int main() { 2021.2 @@ -343,15 +210,9 @@ int main() { 2021.2 @@ -400,14 +257,10 @@ int main() { @@ -416,17 +269,7 @@ int main() {
    - - P9 - + P9 - - L2 - + L2
    - - CertC++-CTR56 - + CertC++-CTR56 - - C++3073 - + C++3073 - - CERT_CPP-CTR56-a - - - CERT_CPP-CTR56-b - - - CERT_CPP-CTR56-c - + CERT_CPP-CTR56-a + CERT_CPP-CTR56-b + CERT_CPP-CTR56-c Don't treat arrays polymorphically @@ -368,9 +229,7 @@ int main() { - - 567 S - + 567 S Enhanced Enforcement @@ -386,9 +245,7 @@ int main() { 4.4 - - 3073 - + 3073 - 7.16 + 7.17 - - - V777 - - + V777
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/CTR57-CPP/ProvideAValidOrderingPredicate-standard.qhelp b/cpp/cert/src/rules/CTR57-CPP/ProvideAValidOrderingPredicate-standard.qhelp index 45e1aea530..76484f51be 100644 --- a/cpp/cert/src/rules/CTR57-CPP/ProvideAValidOrderingPredicate-standard.qhelp +++ b/cpp/cert/src/rules/CTR57-CPP/ProvideAValidOrderingPredicate-standard.qhelp @@ -1,96 +1,17 @@
    -

    - Associative containers place a strict weak ordering requirement on their key comparison predicates - [ - - ISO/IEC 14882-2014 - - ] - . A strict weak ordering has the following properties: -

    +

    Associative containers place a strict weak ordering requirement on their key comparison predicates [ISO/IEC 14882-2014]. A strict weak ordering has the following properties:

      -
    • - for all - - x - - : - - x < x == false - - (irreflexivity) -
    • -
    • - for all - - x - - , - - y - - : if - - x < y - - then - - !(y < x) - - (asymmetry) -
    • -
    • - for all - - x - - , - - y - - , - - z - - : if - - x < y && y < z - - then - - x < z - - (transitivity) -
    • +
    • for all x: x < x == false (irreflexivity)
    • +
    • for all x, y: if x < y then !(y < x) (asymmetry)
    • +
    • for all x, y, z: if x < y && y < z then x < z (transitivity)
    -

    - Providing an invalid ordering predicate for an associative container (e.g., sets, maps, multisets, and multimaps), or as a comparison criterion with the sorting algorithms, can result in erratic behavior or infinite loops [ - - Meyers 01 - - ]. When an ordering predicate is required for an associative container or a generic standard template library algorithm, the predicate must meet the requirements for inducing a strict weak ordering. -

    +

    Providing an invalid ordering predicate for an associative container (e.g., sets, maps, multisets, and multimaps), or as a comparison criterion with the sorting algorithms, can result in erratic behavior or infinite loops [Meyers 01]. When an ordering predicate is required for an associative container or a generic standard template library algorithm, the predicate must meet the requirements for inducing a strict weak ordering.

    -

    - In this noncompliant code example, the - - std::set - - object is created with a comparator that does not adhere to the strict weak ordering requirement. Specifically, it fails to return false for equivalent values. As a result, the behavior of iterating over the results from - - std::set::equal_range - - results in - - unspecified behavior - - . -

    - - #include <functional> +

    In this noncompliant code example, the std::set object is created with a comparator that does not adhere to the strict weak ordering requirement. Specifically, it fails to return false for equivalent values. As a result, the behavior of iterating over the results from std::set::equal_range results in unspecified behavior.

    + #include <functional> #include <iostream> #include <set> @@ -100,18 +21,11 @@ void f() { std::cout << *r.first << std::endl; } } - +
    -

    - This compliant solution uses the default comparator with - - std::set - - instead of providing an invalid one. -

    - - #include <iostream> +

    This compliant solution uses the default comparator with std::set instead of providing an invalid one.

    + #include <iostream> #include <set> void f() { @@ -120,14 +34,11 @@ void f() { std::cout << *r.first << std::endl; } } - +
    -

    - In this noncompliant code example, the objects stored in the std::set have an overloaded operator< implementation, allowing the objects to be compared with std::less. However, the comparison operation does not provide a strict weak ordering. Specifically, two sets, x and y, whose i values are both 1, but have differing j values can result in a situation where comp(x, y) and comp(y, x) are both false, failing the asymmetry requirements. -

    - - #include <iostream> +

    In this noncompliant code example, the objects stored in the std::set have an overloaded operator< implementation, allowing the objects to be compared with std::less. However, the comparison operation does not provide a strict weak ordering. Specifically, two sets, x and y, whose i values are both 1, but have differing j values can result in a situation where comp(x, y) and comp(y, x) are both false, failing the asymmetry requirements.

    + #include <iostream> #include <set> class S { @@ -151,21 +62,17 @@ void f() { for (auto v : t) { std::cout << v << std::endl; } -} - +}
    -

    - This compliant solution uses std::tie() to properly implement the strict weak ordering operator< predicate. -

    - - #include <iostream> +

    This compliant solution uses std::tie() to properly implement the strict weak ordering operator< predicate.

    + #include <iostream> #include <set> #include <tuple> -  + class S { int i, j; -  + public: S(int i, int j) : i(i), j(j) {} @@ -184,13 +91,10 @@ void f() { for (auto v : t) { std::cout << v << std::endl; } -} - +}
    -

    - Using an invalid ordering rule can lead to erratic behavior or infinite loops. -

    +

    Using an invalid ordering rule can lead to erratic behavior or infinite loops.

    @@ -227,14 +131,10 @@ void f() { High @@ -267,9 +167,7 @@ void f() { 2021.2 @@ -284,9 +182,7 @@ void f() { 2021.2
    - - P2 - + P2 - - L3 - + L3
    - - C++3293 - + C++3293 - - CERT_CPP-CTR57-a - + CERT_CPP-CTR57-a For associative containers never use comparison function returning true for equal values @@ -296,17 +192,7 @@ void f() {
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/CTR58-CPP/PredicateFunctionObjectsShouldNotBeMutable-standard.qhelp b/cpp/cert/src/rules/CTR58-CPP/PredicateFunctionObjectsShouldNotBeMutable-standard.qhelp index 8cd1ef3b95..c79d22f220 100644 --- a/cpp/cert/src/rules/CTR58-CPP/PredicateFunctionObjectsShouldNotBeMutable-standard.qhelp +++ b/cpp/cert/src/rules/CTR58-CPP/PredicateFunctionObjectsShouldNotBeMutable-standard.qhelp @@ -1,82 +1,25 @@
    -

    - The C++ standard library implements numerous common algorithms that accept a predicate function object. The C++ Standard, [algorithms.general], paragraph 10 - [ - - ISO/IEC 14882-2014 - - ] - , states the following: -

    +

    The C++ standard library implements numerous common algorithms that accept a predicate function object. The C++ Standard, [algorithms.general], paragraph 10 [ISO/IEC 14882-2014], states the following:

    -

    - [ - - Note: - - Unless otherwise specified, algorithms that take function objects as arguments are permitted to copy those function objects freely. Programmers for whom object identity is important should consider using a wrapper class that points to a noncopied implementation object such as - - reference_wrapper<T> - - , or some equivalent solution. — - - end note - - ] -

    +

    [Note: Unless otherwise specified, algorithms that take function objects as arguments are permitted to copy those function objects freely. Programmers for whom object identity is important should consider using a wrapper class that points to a noncopied implementation object such as reference_wrapper<T>, or some equivalent solution. — end note]

    -

    - Because it is - - implementation-defined - - whether an algorithm copies a predicate function object, any such object must either -

    +

    Because it is implementation-defined whether an algorithm copies a predicate function object, any such object must either

      -
    • - implement a function call operator that does not mutate state related to the function object's identity, such as nonstatic data members or captured values, or -
    • -
    • - wrap the predicate function object in a - - std::reference_wrapper<T> - - (or an equivalent solution). -
    • +
    • implement a function call operator that does not mutate state related to the function object's identity, such as nonstatic data members or captured values, or
    • +
    • wrap the predicate function object in a std::reference_wrapper<T> (or an equivalent solution).
    -

    - Marking the function call operator as - - const - - is beneficial, but insufficient, because data members with the - - mutable - - storage class specifier may still be modified within a - - const - - member function. -

    +

    Marking the function call operator as const is beneficial, but insufficient, because data members with the mutable storage class specifier may still be modified within a const member function.

    -

    - This noncompliant code example attempts to remove the third item in a container using a predicate that returns - - true - - only on its third invocation. -

    - - #include <algorithm> +

    This noncompliant code example attempts to remove the third item in a container using a predicate that returns true only on its third invocation.

    + #include <algorithm> #include <functional> #include <iostream> #include <iterator> #include <vector> -   + class MutablePredicate : public std::unary_function<int, bool> { size_t timesCalled; public: @@ -86,14 +29,14 @@ public: return ++timesCalled == 3; } }; -  + template <typename Iter> void print_container(Iter b, Iter e) { std::cout << "Contains: "; std::copy(b, e, std::ostream_iterator<decltype(*b)>(std::cout, " ")); std::cout << std::endl; } -  + void f() { std::vector<int> v{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; print_container(v.begin(), v.end()); @@ -101,75 +44,28 @@ void f() { v.erase(std::remove_if(v.begin(), v.end(), MutablePredicate()), v.end()); print_container(v.begin(), v.end()); } - -

    - However, - - std::remove_if() - - is permitted to construct and use extra copies of its predicate function. Any such extra copies may result in unexpected output. -

    -

    - - Implementation Details - -

    -

    - This program produces the following results using - - gcc - - 4.8.1 with - - libstdc++ - - . -

    - - Contains: 0 1 2 3 4 5 6 7 8 9 -Contains: 0 1 3 4 6 7 8 9 - -

    - This result arises because - - std::remove_if - - makes two copies of the predicate before invoking it. The first copy is used to determine the location of the first element in the sequence for which the predicate returns - - true - - . The subsequent copy is used for removing other elements in the sequence. This results in the third element ( - - 2 - - ) and sixth element ( - - 5 - - ) being removed; two distinct predicate functions are used. -

    +
    +

    However, std::remove_if() is permitted to construct and use extra copies of its predicate function. Any such extra copies may result in unexpected output.

    +

    Implementation Details

    +

    This program produces the following results using gcc 4.8.1 with libstdc++.

    + Contains: 0 1 2 3 4 5 6 7 8 9 +Contains: 0 1 3 4 6 7 8 9 +

    This result arises because std::remove_if makes two copies of the predicate before invoking it. The first copy is used to determine the location of the first element in the sequence for which the predicate returns true. The subsequent copy is used for removing other elements in the sequence. This results in the third element (2) and sixth element (5) being removed; two distinct predicate functions are used.

    -

    - Similar to the functor noncompliant code example, this noncompliant code example attempts to remove the third item in a container using a predicate lambda function that returns - - true - - only on its third invocation. As with the functor, this lambda carries local state information, which it attempts to mutate within its function call operator. -

    - - #include <algorithm> +

    Similar to the functor noncompliant code example, this noncompliant code example attempts to remove the third item in a container using a predicate lambda function that returns true only on its third invocation. As with the functor, this lambda carries local state information, which it attempts to mutate within its function call operator.

    + #include <algorithm> #include <iostream> #include <iterator> #include <vector> -   + template <typename Iter> void print_container(Iter b, Iter e) { std::cout << "Contains: "; std::copy(b, e, std::ostream_iterator<decltype(*b)>(std::cout, " ")); std::cout << std::endl; } -  + void f() { std::vector<int> v{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; print_container(v.begin(), v.end()); @@ -177,23 +73,11 @@ void f() { int timesCalled = 0; v.erase(std::remove_if(v.begin(), v.end(), [timesCalled](const int &) mutable { return ++timesCalled == 3; }), v.end()); print_container(v.begin(), v.end()); -} - +}
    -

    - This compliant solution uses - - std::ref - - to wrap the predicate in a - - std::reference_wrapper<T> - - object, ensuring that copies of the wrapper object all refer to the same underlying predicate object. -

    - - #include <algorithm> +

    This compliant solution uses std::ref to wrap the predicate in a std::reference_wrapper<T> object, ensuring that copies of the wrapper object all refer to the same underlying predicate object.

    + #include <algorithm> #include <functional> #include <iostream> #include <iterator> @@ -223,28 +107,14 @@ void f() { MutablePredicate mp; v.erase(std::remove_if(v.begin(), v.end(), std::ref(mp)), v.end()); print_container(v.begin(), v.end()); -} - -

    - The above com - pliant solution demonstrates using a reference wrapper over a functor object but can similarly be used with a stateful lambda. - The code produces the expected results, where only the third element is removed. -

    - - Contains: 0 1 2 3 4 5 6 7 8 9 -Contains: 0 1 3 4 5 6 7 8 9 - +}
    +

    The above compliant solution demonstrates using a reference wrapper over a functor object but can similarly be used with a stateful lambda. The code produces the expected results, where only the third element is removed.

    + Contains: 0 1 2 3 4 5 6 7 8 9 +Contains: 0 1 3 4 5 6 7 8 9
    -

    - Removing a specific element of a container does not require a predicate function but can instead simply use - - std::vector::erase() - - , as in this compliant solution. -

    - - #include <algorithm> +

    Removing a specific element of a container does not require a predicate function but can instead simply use std::vector::erase(), as in this compliant solution.

    + #include <algorithm> #include <iostream> #include <iterator> #include <vector> @@ -261,13 +131,10 @@ void f() { print_container(v.begin(), v.end()); v.erase(v.begin() + 3); print_container(v.begin(), v.end()); -} - +}
    -

    - Using a predicate function object that contains state can produce unexpected values. -

    +

    Using a predicate function object that contains state can produce unexpected values.

    @@ -304,14 +171,10 @@ void f() { High @@ -344,9 +207,7 @@ void f() { 2021.2 @@ -361,9 +222,7 @@ void f() { 2021.2 @@ -393,17 +248,7 @@ void f() {
    - - P3 - + P3 - - L3 - + L3
    - - C++3225, C++3226, C++3227, C++3228, C++3229, C++3230, C++3231, C++3232, C++3233, C++3234 - + C++3225, C++3226, C++3227, C++3228, C++3229, C++3230, C++3231, C++3232, C++3233, C++3234 - - CERT_CPP-CTR58-a - + CERT_CPP-CTR58-a Make predicates const pure functions @@ -379,12 +238,8 @@ void f() { 4.4 - - 3225, 3226, 3227, 3228, 3229, - - - 3230, 3231, 3232, 3233, 3234 - + 3225, 3226, 3227, 3228, 3229, + 3230, 3231, 3232, 3233, 3234
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/DCL50-CPP/DoNotDefineACStyleVariadicFunction-standard.qhelp b/cpp/cert/src/rules/DCL50-CPP/DoNotDefineACStyleVariadicFunction-standard.qhelp index b7802d78ed..65ac0a950c 100644 --- a/cpp/cert/src/rules/DCL50-CPP/DoNotDefineACStyleVariadicFunction-standard.qhelp +++ b/cpp/cert/src/rules/DCL50-CPP/DoNotDefineACStyleVariadicFunction-standard.qhelp @@ -1,62 +1,13 @@
    -

    - Functions can be defined to accept more formal arguments at the call site than are specified by the parameter declaration clause. Such functions are called - - variadic - - functions because they can accept a variable number of arguments from a caller. C++ provides two mechanisms by which a variadic function can be defined: function parameter packs and use of a C-style ellipsis as the final parameter declaration. -

    -

    - Variadic functions are flexible because they accept a varying number of arguments of differing types. However, they can also be hazardous. A variadic function using a C-style ellipsis (hereafter called a - - C-style variadic function - - ) has no mechanisms to check the type safety of arguments being passed to the function or to check that the number of arguments being passed matches the semantics of the function definition. Consequently, a runtime call to a C-style variadic function that passes inappropriate arguments yields undefined behavior. Such - - undefined behavior - - could be - - exploited - - to run arbitrary code. -

    -

    - Do not define C-style variadic functions. (The declaration of a C-style variadic function that is never defined is permitted, as it is not harmful and can be useful in unevaluated contexts.) -

    -

    - Issues with C-style variadic functions can be avoided by using variadic functions defined with function parameter packs for situations in which a variable number of arguments should be passed to a function. Additionally, function currying can be used as a replacement to variadic functions. For example, in contrast to C's - - printf() - - family of functions, C++ output is implemented with the overloaded single-argument - - std::cout::operator<<() - - operators. -

    -

    - Noncompliant Code Example -

    -

    - This noncompliant code example uses a C-style variadic function to add a series of integers together. The function reads arguments until the value - - 0 - - is found. Calling this function without passing the value - - 0 - - as an argument (after the first two arguments) results in undefined behavior. Furthermore, passing any type other than an - - int - - also results in undefined behavior. -

    - - #include <cstdarg> +

    Functions can be defined to accept more formal arguments at the call site than are specified by the parameter declaration clause. Such functions are called variadic functions because they can accept a variable number of arguments from a caller. C++ provides two mechanisms by which a variadic function can be defined: function parameter packs and use of a C-style ellipsis as the final parameter declaration.

    +

    Variadic functions are flexible because they accept a varying number of arguments of differing types. However, they can also be hazardous. A variadic function using a C-style ellipsis (hereafter called a C-style variadic function) has no mechanisms to check the type safety of arguments being passed to the function or to check that the number of arguments being passed matches the semantics of the function definition. Consequently, a runtime call to a C-style variadic function that passes inappropriate arguments yields undefined behavior. Such undefined behavior could be exploited to run arbitrary code.

    +

    Do not define C-style variadic functions. (The declaration of a C-style variadic function that is never defined is permitted, as it is not harmful and can be useful in unevaluated contexts.)

    +

    Issues with C-style variadic functions can be avoided by using variadic functions defined with function parameter packs for situations in which a variable number of arguments should be passed to a function. Additionally, function currying can be used as a replacement to variadic functions. For example, in contrast to C's printf() family of functions, C++ output is implemented with the overloaded single-argument std::cout::operator<<() operators.

    +

    Noncompliant Code Example

    +

    This noncompliant code example uses a C-style variadic function to add a series of integers together. The function reads arguments until the value 0 is found. Calling this function without passing the value 0 as an argument (after the first two arguments) results in undefined behavior. Furthermore, passing any type other than an int also results in undefined behavior.

    + #include <cstdarg> int add(int first, int second, ...) { int r = first + second; @@ -68,54 +19,26 @@ int add(int first, int second, ...) { va_end(va); return r; } - +
    -

    - In this compliant solution, a variadic function using a function parameter pack is used to implement the - - add() - - function, allowing identical behavior for call sites. Unlike the C-style variadic function used in the noncompliant code example, this compliant solution does not result in undefined behavior if the list of parameters is not terminated with - - 0 - - . Additionally, if any of the values passed to the function are not integers, the code is - - ill-formed - - rather than producing undefined behavior. -

    - - #include <type_traits> -  +

    In this compliant solution, a variadic function using a function parameter pack is used to implement the add() function, allowing identical behavior for call sites. Unlike the C-style variadic function used in the noncompliant code example, this compliant solution does not result in undefined behavior if the list of parameters is not terminated with 0. Additionally, if any of the values passed to the function are not integers, the code is ill-formed rather than producing undefined behavior.

    + #include <type_traits> + template <typename Arg, typename std::enable_if<std::is_integral<Arg>::value>::type * = nullptr> int add(Arg f, Arg s) { return f + s; } -  + template <typename Arg, typename... Ts, typename std::enable_if<std::is_integral<Arg>::value>::type * = nullptr> int add(Arg f, Ts... rest) { return f + add(rest...); } - -

    - This compliant solution makes use of - - std::enable_if - - to ensure that any nonintegral argument value results in an ill-formed program. -

    +
    +

    This compliant solution makes use of std::enable_if to ensure that any nonintegral argument value results in an ill-formed program.

    -

    - An alternative compliant solution that does not require recursive expansion of the function parameter pack instead expands the function parameter pack into a list of values as part of a braced initializer list. Since narrowing conversions are not allowed in a braced initializer list, the type safety is preserved despite the - - std::enable_if - - not involving any of the variadic arguments. -

    - - #include <type_traits> -  +

    An alternative compliant solution that does not require recursive expansion of the function parameter pack instead expands the function parameter pack into a list of values as part of a braced initializer list. Since narrowing conversions are not allowed in a braced initializer list, the type safety is preserved despite the std::enable_if not involving any of the variadic arguments.

    + #include <type_traits> + template <typename Arg, typename... Ts, typename std::enable_if<std::is_integral<Arg>::value>::type * = nullptr> int add(Arg i, Arg j, Ts... all) { int values[] = { j, all... }; @@ -124,32 +47,12 @@ int add(Arg i, Arg j, Ts... all) { r += v; } return r; -} - +}
    -

    - - DCL50-CPP-EX1: - - It is permissible to define a C-style variadic function if that function also has external C language linkage. For instance, the function may be a definition used in a C library API that is implemented in C++. -

    -

    - - DCL50-CPP-EX2 - - : As stated in the normative text, C-style variadic functions that are declared but never defined are permitted. For example, when a function call expression appears in an unevaluated context, such as the argument in a - - sizeof - - expression, overload resolution is performed to determine the result type of the call but does not require a function definition. Some template metaprogramming techniques that employ - - SFINAE - - use variadic function declarations to implement compile-time type queries, as in the following example. -

    - - template <typename Ty> +

    DCL50-CPP-EX1: It is permissible to define a C-style variadic function if that function also has external C language linkage. For instance, the function may be a definition used in a C library API that is implemented in C++.

    +

    DCL50-CPP-EX2: As stated in the normative text, C-style variadic functions that are declared but never defined are permitted. For example, when a function call expression appears in an unevaluated context, such as the argument in a sizeof expression, overload resolution is performed to determine the result type of the call but does not require a function definition. Some template metaprogramming techniques that employ SFINAE use variadic function declarations to implement compile-time type queries, as in the following example.

    + template <typename Ty> class has_foo_function { typedef char yes[1]; typedef char no[2]; @@ -162,68 +65,11 @@ class has_foo_function { public: static const bool value = sizeof(test<Ty>(nullptr)) == sizeof(yes); -}; - -

    - In this example, the value of - - value - - is determined on the basis of which overload of - - test() - - is selected. The declaration of - - Inner *I - - allows use of the variable - - I - - within the - - decltype - - specifier, which results in a pointer of some (possibly - - void - - ) type, with a default value of - - nullptr - - . However, if there is no declaration of - - Inner::foo() - - , the - - decltype - - specifier will be ill-formed, and that variant of - - test() - - will not be a candidate function for overload resolution due to SFINAE. The result is that the C-style variadic function variant of - - test() - - will be the only function in the candidate set. Both - - test() - - functions are declared but never defined because their definitions are not required for use within an unevaluated expression context. -

    +};
    +

    In this example, the value of value is determined on the basis of which overload of test() is selected. The declaration of Inner *I allows use of the variable I within the decltype specifier, which results in a pointer of some (possibly void) type, with a default value of nullptr. However, if there is no declaration of Inner::foo(), the decltype specifier will be ill-formed, and that variant of test() will not be a candidate function for overload resolution due to SFINAE. The result is that the C-style variadic function variant of test() will be the only function in the candidate set. Both test() functions are declared but never defined because their definitions are not required for use within an unevaluated expression context.

    -

    - Incorrectly using a variadic function can result in - - abnormal program termination - - , unintended information disclosure, or execution of arbitrary code. -

    +

    Incorrectly using a variadic function can result in abnormal program termination, unintended information disclosure, or execution of arbitrary code.

    @@ -260,14 +106,10 @@ public: Medium @@ -300,9 +142,7 @@ public: 20.10 @@ -335,15 +173,11 @@ public: 3.9 @@ -354,12 +188,10 @@ public: @@ -392,11 +222,7 @@ public: 2021.4 @@ -410,9 +236,7 @@ public: @@ -484,9 +302,7 @@ public: 20.10 @@ -515,17 +327,7 @@ public:
    - - P12 - + P12 - - L1 - + L1
    - - function-ellipsis - + function-ellipsis Fully checked @@ -318,9 +158,7 @@ public: 7.2.0 - - CertC++-DCL50 - + CertC++-DCL50 - - cert-dcl50-cpp - + cert-dcl50-cpp Checked by - - clang-tidy - + clang-tidy .
    - 6.1p0 + 6.2p0 - - LANG.STRUCT.ELLIPSIS - + LANG.STRUCT.ELLIPSIS Ellipsis @@ -375,9 +207,7 @@ public: 2021.2 - - C++2012, C++2625 - + C++2012, C++2625 - - - MISRA.FUNC.VARARG - - + MISRA.FUNC.VARARG - - 41 S - + 41 S Fully Implemented @@ -428,9 +252,7 @@ public: 2021.2 - - CERT_CPP-DCL50-a - + CERT_CPP-DCL50-a Functions shall not be defined with a variable number of arguments @@ -464,12 +286,8 @@ public: 4.4 - - 2012, - - - 2625 - + 2012, + 2625 - - function-ellipsis - + function-ellipsis Fully checked @@ -502,11 +318,7 @@ public: 4.10 - - - FunctionEllipsis - - + FunctionEllipsis
    -

    - Search for other - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for other vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/DCL51-CPP/EnumeratorReusesReservedName-standard.qhelp b/cpp/cert/src/rules/DCL51-CPP/EnumeratorReusesReservedName-standard.qhelp index 9c074f0ea6..da543df152 100644 --- a/cpp/cert/src/rules/DCL51-CPP/EnumeratorReusesReservedName-standard.qhelp +++ b/cpp/cert/src/rules/DCL51-CPP/EnumeratorReusesReservedName-standard.qhelp @@ -1,246 +1,60 @@
    -

    - The C++ Standard, [reserved.names] - [ - - ISO/IEC 14882-2014 - - ] - , specifies the following rules regarding reserved names - : -

    +

    The C++ Standard, [reserved.names] [ISO/IEC 14882-2014], specifies the following rules regarding reserved names:

      -
    • - A translation unit that includes a standard library header shall not - - #define - - or - - #undef - - names declared in any standard library header. -
    • -
    • - A translation unit shall not - - #define - - or - - #undef - - names lexically identical to keywords, to the identifiers listed in Table 3, or to the - - attribute-token - - s described in 7.6. -
    • -
    • - Each name that contains a double underscore - - __ - - or begins with an underscore followed by an uppercase letter is reserved to the implementation for any use. -
    • -
    • - Each name that begins with an underscore is reserved to the implementation for use as a name in the global namespace. -
    • -
    • - Each name declared as an object with external linkage in a header is reserved to the implementation to designate that library object with external linkage, both in namespace - - std - - and in the global namespace. -
    • -
    • - Each global function signature declared with external linkage in a header is reserved to the implementation to designate that function signature with external linkage. -
    • -
    • - Each name from the Standard C library declared with external linkage is reserved to the implementation for use as a name with - - extern "C" - - linkage, both in namespace - - std - - and in the global namespace. -
    • -
    • - Each function signature from the Standard C library declared with external linkage is reserved to the implementation for use as a function signature with both - - extern "C" - - and - - extern "C++" - - linkage, or as a name of namespace scope in the global namespace. -
    • -
    • - For each type - - T - - from the Standard C library, the types - - ::T - - and - - std::T - - are reserved to the implementation and, when defined, - - ::T - - shall be identical to - - std::T - - . -
    • -
    • - Literal suffix identifiers that do not start with an underscore are reserved for future standardization. -
    • +
    • A translation unit that includes a standard library header shall not #define or #undef names declared in any standard library header.
    • +
    • A translation unit shall not #define or #undef names lexically identical to keywords, to the identifiers listed in Table 3, or to the attribute-tokens described in 7.6.
    • +
    • Each name that contains a double underscore __ or begins with an underscore followed by an uppercase letter is reserved to the implementation for any use.
    • +
    • Each name that begins with an underscore is reserved to the implementation for use as a name in the global namespace.
    • +
    • Each name declared as an object with external linkage in a header is reserved to the implementation to designate that library object with external linkage, both in namespace std and in the global namespace.
    • +
    • Each global function signature declared with external linkage in a header is reserved to the implementation to designate that function signature with external linkage.
    • +
    • Each name from the Standard C library declared with external linkage is reserved to the implementation for use as a name with extern "C" linkage, both in namespace std and in the global namespace.
    • +
    • Each function signature from the Standard C library declared with external linkage is reserved to the implementation for use as a function signature with both extern "C" and extern "C++" linkage, or as a name of namespace scope in the global namespace.
    • +
    • For each type T from the Standard C library, the types ::T and std::T are reserved to the implementation and, when defined, ::T shall be identical to std::T.
    • +
    • Literal suffix identifiers that do not start with an underscore are reserved for future standardization.
    -

    - The identifiers and attribute names referred to in the preceding excerpt are - - override - - , - - final - - , - - alignas - - , - - carries_dependency - - , - - deprecated - - , and - - noreturn - - . -

    -

    - No other identifiers are reserved. Declaring or defining an identifier in a context in which it is reserved results in - - undefined behavior - - . Do not declare or define a reserved identifier. -

    +

    The identifiers and attribute names referred to in the preceding excerpt are override, final, alignas, carries_dependency, deprecated, and noreturn.

    +

    No other identifiers are reserved. Declaring or defining an identifier in a context in which it is reserved results in undefined behavior. Do not declare or define a reserved identifier.

    -

    - A common practice is to use a macro in a preprocessor conditional that guards against multiple inclusions of a header file. While this is a recommended practice, many programs use reserved names as the header guards. Such a name may clash with reserved names defined by the implementation of the C++ standard template library in its headers or with reserved names implicitly predefined by the compiler even when no C++ standard library header is included. -

    - - #ifndef _MY_HEADER_H_ +

    A common practice is to use a macro in a preprocessor conditional that guards against multiple inclusions of a header file. While this is a recommended practice, many programs use reserved names as the header guards. Such a name may clash with reserved names defined by the implementation of the C++ standard template library in its headers or with reserved names implicitly predefined by the compiler even when no C++ standard library header is included.

    + #ifndef _MY_HEADER_H_ #define _MY_HEADER_H_ // Contents of <my_header.h> #endif // _MY_HEADER_H_ - +
    -

    - This compliant solution avoids using leading or trailing underscores in the name of the header guard. -

    - - #ifndef MY_HEADER_H +

    This compliant solution avoids using leading or trailing underscores in the name of the header guard.

    + #ifndef MY_HEADER_H #define MY_HEADER_H // Contents of <my_header.h> #endif // MY_HEADER_H - +
    -

    - In this noncompliant code example, a user-defined literal - operator"" x - is declared. However, literal suffix identifiers are required to start with an underscore; literal suffixes without the underscore prefix are reserved for future library implementations. -

    - - #include <cstddef> -  -unsigned int operator"" x(const char *, std::size_t); - +

    In this noncompliant code example, a user-defined literal operator"" x is declared. However, literal suffix identifiers are required to start with an underscore; literal suffixes without the underscore prefix are reserved for future library implementations.

    + #include <cstddef> + +unsigned int operator"" x(const char *, std::size_t);
    -

    - In this compliant solution, the user-defined literal is named - - operator"" _x - - , which is not a reserved identifier. -

    - - #include <cstddef> -  -unsigned int operator"" _x(const char *, std::size_t); - -

    - The name of the user-defined literal is - - operator"" _x - - and not - - _x - - , which would have otherwise been reserved for the global namespace. -

    +

    In this compliant solution, the user-defined literal is named operator"" _x, which is not a reserved identifier.

    + #include <cstddef> + +unsigned int operator"" _x(const char *, std::size_t); +

    The name of the user-defined literal is operator"" _x and not _x, which would have otherwise been reserved for the global namespace.

    -

    - In this noncompliant code example, the names of the file scope objects - - _max_limit - - and - - _limit - - both begin with an underscore. Because it is - - static - - , the declaration of - - _max_limit - - might seem to be impervious to clashes with names defined by the implementation. However, because the header - - <cstddef> - - is included to define - - std::size_t - - , a potential for a name clash exists. (Note, however, that a conforming compiler may implicitly declare reserved names regardless of whether any C++ standard template library header has been explicitly included.) In addition, because - - _limit - - has external linkage, it may clash with a symbol with the same name defined in the language runtime library even if such a symbol is not declared in any header. Consequently, it is unsafe to start the name of any file scope identifier with an underscore even if its linkage limits its visibility to a single translation unit. -

    - - #include <cstddef> // std::for size_t +

    In this noncompliant code example, the names of the file scope objects _max_limit and _limit both begin with an underscore. Because it is static, the declaration of _max_limit might seem to be impervious to clashes with names defined by the implementation. However, because the header <cstddef> is included to define std::size_t, a potential for a name clash exists. (Note, however, that a conforming compiler may implicitly declare reserved names regardless of whether any C++ standard template library header has been explicitly included.) In addition, because _limit has external linkage, it may clash with a symbol with the same name defined in the language runtime library even if such a symbol is not declared in any header. Consequently, it is unsafe to start the name of any file scope identifier with an underscore even if its linkage limits its visibility to a single translation unit.

    + #include <cstddef> // std::for size_t static const std::size_t _max_limit = 1024; std::size_t _limit = 100; @@ -248,14 +62,11 @@ std::size_t _limit = 100; unsigned int get_value(unsigned int count) { return count < _limit ? count : _limit; } - +
    -

    - In this compliant solution, file scope identifiers do not begin with an underscore. -

    - - #include <cstddef> // for size_t +

    In this compliant solution, file scope identifiers do not begin with an underscore.

    + #include <cstddef> // for size_t static const std::size_t max_limit = 1024; std::size_t limit = 100; @@ -263,100 +74,48 @@ std::size_t limit = 100; unsigned int get_value(unsigned int count) { return count < limit ? count : limit; } - +
    -

    - In this noncompliant code example, because the C++ standard template library header - - <cinttypes> - - is specified to include - - <cstdint> - - , as per [c.files] paragraph 4 - [ - - ISO/IEC 14882-2014 - - ] - , the name - - MAX_SIZE - - conflicts with the name of the - - <cstdint> - - header macro used to denote the upper limit of - - std:size_t. - -

    - - #include <cinttypes> // for int_fast16_t +

    In this noncompliant code example, because the C++ standard template library header <cinttypes> is specified to include <cstdint>, as per [c.files] paragraph 4 [ISO/IEC 14882-2014], the name MAX_SIZE conflicts with the name of the <cstdint> header macro used to denote the upper limit of std:size_t.

    + #include <cinttypes> // for int_fast16_t void f(std::int_fast16_t val) { enum { MAX_SIZE = 80 }; // ... } - +
    -

    - This compliant solution avoids redefining reserved names. -

    - - #include <cinttypes> // for std::int_fast16_t +

    This compliant solution avoids redefining reserved names.

    + #include <cinttypes> // for std::int_fast16_t void f(std::int_fast16_t val) { enum { BufferSize = 80 }; // ... -} - +}
    -

    - - DCL51-CPP-EX1: - - For compatibility with other compiler vendors or language standard modes, it is acceptable to create a macro identifier that is the same as a reserved identifier so long as the behavior is semantically identical, as in this example. -

    - - // Sometimes generated by configuration tools such as autoconf +

    DCL51-CPP-EX1: For compatibility with other compiler vendors or language standard modes, it is acceptable to create a macro identifier that is the same as a reserved identifier so long as the behavior is semantically identical, as in this example.

    + // Sometimes generated by configuration tools such as autoconf #define const const -  + // Allowed compilers with semantically equivalent extension behavior -#define inline __inline - -

    - - DCL51-CPP-EX2: - - As a compiler vendor or standard library developer, it is acceptable to use identifiers reserved for your implementation. Reserved identifiers may be defined by the compiler, in standard library headers, or in headers included by a standard library header, as in this example declaration from the - - libc++ - - STL implementation. -

    - - // The following declaration of a reserved identifier exists in the libc++ implementation of +#define inline __inline +

    DCL51-CPP-EX2: As a compiler vendor or standard library developer, it is acceptable to use identifiers reserved for your implementation. Reserved identifiers may be defined by the compiler, in standard library headers, or in headers included by a standard library header, as in this example declaration from the libc++ STL implementation.

    + // The following declaration of a reserved identifier exists in the libc++ implementation of // std::basic_string as a public member. The original source code may be found at: // http://llvm.org/svn/llvm-project/libcxx/trunk/include/string -  + template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT>> class basic_string { // ... -  + bool __invariants() const; -}; - +};
    -

    - Using reserved identifiers can lead to incorrect program operation. -

    +

    Using reserved identifiers can lead to incorrect program operation.

    @@ -393,14 +152,10 @@ class basic_string { Low @@ -433,9 +188,7 @@ class basic_string { 20.10 @@ -468,26 +219,16 @@ class basic_string { 3.9 @@ -499,15 +240,11 @@ class basic_string { @@ -541,24 +276,12 @@ class basic_string { 2021.4 @@ -572,9 +295,7 @@ class basic_string { @@ -660,14 +367,10 @@ class basic_string { @@ -682,9 +385,7 @@ class basic_string { 20.10 @@ -713,17 +410,7 @@ class basic_string {
    - - P3 - + P3 - - L3 - + L3
    - - reserved-identifier - + reserved-identifier Partially checked @@ -451,9 +204,7 @@ class basic_string { 7.2.0 - - CertC++-DCL51 - + CertC++-DCL51 - - -Wreserved-id-macro - - - -Wuser-defined-literals - + -Wreserved-id-macro + -Wuser-defined-literals The - - -Wreserved-id-macro - + -Wreserved-id-macro flag is not enabled by default or with - - -Wall - + -Wall , but is enabled with - - -Weverything - + -Weverything . This flag does not catch all instances of this rule, such as redefining reserved names. - 6.1p0 + 6.2p0 - - LANG.ID.NU.MK - - - LANG.STRUCT.DECL.RESERVED - + LANG.ID.NU.MK + LANG.STRUCT.DECL.RESERVED Macro name is C keyword @@ -524,9 +261,7 @@ class basic_string { 2021.2 - - C++5003 - + C++5003 - - MISRA.DEFINE.WRONGNAME - - - MISRA.DEFINE.WRONGNAME.UNDERSCORE - - - MISRA.UNDEF.WRONGNAME - - - MISRA.UNDEF.WRONGNAME.UNDERSCORE - - - MISRA.STDLIB.WRONGNAME - - - MISRA.STDLIB.WRONGNAME.UNDERSCORE - + MISRA.DEFINE.WRONGNAME + MISRA.DEFINE.WRONGNAME.UNDERSCORE + MISRA.UNDEF.WRONGNAME + MISRA.UNDEF.WRONGNAME.UNDERSCORE + MISRA.STDLIB.WRONGNAME + MISRA.STDLIB.WRONGNAME.UNDERSCORE - - 86 S, 218 S, 219 S, 580 S - + 86 S, 218 S, 219 S, 580 S Fully implemented @@ -590,24 +311,12 @@ class basic_string { 2021.2 - - CERT_CPP-DCL51-a - - - CERT_CPP-DCL51-b - - - CERT_CPP-DCL51-c - - - CERT_CPP-DCL51-d - - - CERT_CPP-DCL51-e - - - CERT_CPP-DCL51-f - + CERT_CPP-DCL51-a + CERT_CPP-DCL51-b + CERT_CPP-DCL51-c + CERT_CPP-DCL51-d + CERT_CPP-DCL51-e + CERT_CPP-DCL51-f Do not #define or #undef identifiers with names which start with underscore @@ -646,9 +355,7 @@ class basic_string { 4.4 - - 5003 - + 5003 - 7.16 + 7.17 - - - V1059 - - + V1059 - - reserved-identifier - + reserved-identifier Partially checked @@ -700,11 +401,7 @@ class basic_string { 4.10 - - - 978 - - + 978
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/DCL51-CPP/FunctionReusesReservedName-standard.qhelp b/cpp/cert/src/rules/DCL51-CPP/FunctionReusesReservedName-standard.qhelp index 9c074f0ea6..da543df152 100644 --- a/cpp/cert/src/rules/DCL51-CPP/FunctionReusesReservedName-standard.qhelp +++ b/cpp/cert/src/rules/DCL51-CPP/FunctionReusesReservedName-standard.qhelp @@ -1,246 +1,60 @@
    -

    - The C++ Standard, [reserved.names] - [ - - ISO/IEC 14882-2014 - - ] - , specifies the following rules regarding reserved names - : -

    +

    The C++ Standard, [reserved.names] [ISO/IEC 14882-2014], specifies the following rules regarding reserved names:

      -
    • - A translation unit that includes a standard library header shall not - - #define - - or - - #undef - - names declared in any standard library header. -
    • -
    • - A translation unit shall not - - #define - - or - - #undef - - names lexically identical to keywords, to the identifiers listed in Table 3, or to the - - attribute-token - - s described in 7.6. -
    • -
    • - Each name that contains a double underscore - - __ - - or begins with an underscore followed by an uppercase letter is reserved to the implementation for any use. -
    • -
    • - Each name that begins with an underscore is reserved to the implementation for use as a name in the global namespace. -
    • -
    • - Each name declared as an object with external linkage in a header is reserved to the implementation to designate that library object with external linkage, both in namespace - - std - - and in the global namespace. -
    • -
    • - Each global function signature declared with external linkage in a header is reserved to the implementation to designate that function signature with external linkage. -
    • -
    • - Each name from the Standard C library declared with external linkage is reserved to the implementation for use as a name with - - extern "C" - - linkage, both in namespace - - std - - and in the global namespace. -
    • -
    • - Each function signature from the Standard C library declared with external linkage is reserved to the implementation for use as a function signature with both - - extern "C" - - and - - extern "C++" - - linkage, or as a name of namespace scope in the global namespace. -
    • -
    • - For each type - - T - - from the Standard C library, the types - - ::T - - and - - std::T - - are reserved to the implementation and, when defined, - - ::T - - shall be identical to - - std::T - - . -
    • -
    • - Literal suffix identifiers that do not start with an underscore are reserved for future standardization. -
    • +
    • A translation unit that includes a standard library header shall not #define or #undef names declared in any standard library header.
    • +
    • A translation unit shall not #define or #undef names lexically identical to keywords, to the identifiers listed in Table 3, or to the attribute-tokens described in 7.6.
    • +
    • Each name that contains a double underscore __ or begins with an underscore followed by an uppercase letter is reserved to the implementation for any use.
    • +
    • Each name that begins with an underscore is reserved to the implementation for use as a name in the global namespace.
    • +
    • Each name declared as an object with external linkage in a header is reserved to the implementation to designate that library object with external linkage, both in namespace std and in the global namespace.
    • +
    • Each global function signature declared with external linkage in a header is reserved to the implementation to designate that function signature with external linkage.
    • +
    • Each name from the Standard C library declared with external linkage is reserved to the implementation for use as a name with extern "C" linkage, both in namespace std and in the global namespace.
    • +
    • Each function signature from the Standard C library declared with external linkage is reserved to the implementation for use as a function signature with both extern "C" and extern "C++" linkage, or as a name of namespace scope in the global namespace.
    • +
    • For each type T from the Standard C library, the types ::T and std::T are reserved to the implementation and, when defined, ::T shall be identical to std::T.
    • +
    • Literal suffix identifiers that do not start with an underscore are reserved for future standardization.
    -

    - The identifiers and attribute names referred to in the preceding excerpt are - - override - - , - - final - - , - - alignas - - , - - carries_dependency - - , - - deprecated - - , and - - noreturn - - . -

    -

    - No other identifiers are reserved. Declaring or defining an identifier in a context in which it is reserved results in - - undefined behavior - - . Do not declare or define a reserved identifier. -

    +

    The identifiers and attribute names referred to in the preceding excerpt are override, final, alignas, carries_dependency, deprecated, and noreturn.

    +

    No other identifiers are reserved. Declaring or defining an identifier in a context in which it is reserved results in undefined behavior. Do not declare or define a reserved identifier.

    -

    - A common practice is to use a macro in a preprocessor conditional that guards against multiple inclusions of a header file. While this is a recommended practice, many programs use reserved names as the header guards. Such a name may clash with reserved names defined by the implementation of the C++ standard template library in its headers or with reserved names implicitly predefined by the compiler even when no C++ standard library header is included. -

    - - #ifndef _MY_HEADER_H_ +

    A common practice is to use a macro in a preprocessor conditional that guards against multiple inclusions of a header file. While this is a recommended practice, many programs use reserved names as the header guards. Such a name may clash with reserved names defined by the implementation of the C++ standard template library in its headers or with reserved names implicitly predefined by the compiler even when no C++ standard library header is included.

    + #ifndef _MY_HEADER_H_ #define _MY_HEADER_H_ // Contents of <my_header.h> #endif // _MY_HEADER_H_ - +
    -

    - This compliant solution avoids using leading or trailing underscores in the name of the header guard. -

    - - #ifndef MY_HEADER_H +

    This compliant solution avoids using leading or trailing underscores in the name of the header guard.

    + #ifndef MY_HEADER_H #define MY_HEADER_H // Contents of <my_header.h> #endif // MY_HEADER_H - +
    -

    - In this noncompliant code example, a user-defined literal - operator"" x - is declared. However, literal suffix identifiers are required to start with an underscore; literal suffixes without the underscore prefix are reserved for future library implementations. -

    - - #include <cstddef> -  -unsigned int operator"" x(const char *, std::size_t); - +

    In this noncompliant code example, a user-defined literal operator"" x is declared. However, literal suffix identifiers are required to start with an underscore; literal suffixes without the underscore prefix are reserved for future library implementations.

    + #include <cstddef> + +unsigned int operator"" x(const char *, std::size_t);
    -

    - In this compliant solution, the user-defined literal is named - - operator"" _x - - , which is not a reserved identifier. -

    - - #include <cstddef> -  -unsigned int operator"" _x(const char *, std::size_t); - -

    - The name of the user-defined literal is - - operator"" _x - - and not - - _x - - , which would have otherwise been reserved for the global namespace. -

    +

    In this compliant solution, the user-defined literal is named operator"" _x, which is not a reserved identifier.

    + #include <cstddef> + +unsigned int operator"" _x(const char *, std::size_t); +

    The name of the user-defined literal is operator"" _x and not _x, which would have otherwise been reserved for the global namespace.

    -

    - In this noncompliant code example, the names of the file scope objects - - _max_limit - - and - - _limit - - both begin with an underscore. Because it is - - static - - , the declaration of - - _max_limit - - might seem to be impervious to clashes with names defined by the implementation. However, because the header - - <cstddef> - - is included to define - - std::size_t - - , a potential for a name clash exists. (Note, however, that a conforming compiler may implicitly declare reserved names regardless of whether any C++ standard template library header has been explicitly included.) In addition, because - - _limit - - has external linkage, it may clash with a symbol with the same name defined in the language runtime library even if such a symbol is not declared in any header. Consequently, it is unsafe to start the name of any file scope identifier with an underscore even if its linkage limits its visibility to a single translation unit. -

    - - #include <cstddef> // std::for size_t +

    In this noncompliant code example, the names of the file scope objects _max_limit and _limit both begin with an underscore. Because it is static, the declaration of _max_limit might seem to be impervious to clashes with names defined by the implementation. However, because the header <cstddef> is included to define std::size_t, a potential for a name clash exists. (Note, however, that a conforming compiler may implicitly declare reserved names regardless of whether any C++ standard template library header has been explicitly included.) In addition, because _limit has external linkage, it may clash with a symbol with the same name defined in the language runtime library even if such a symbol is not declared in any header. Consequently, it is unsafe to start the name of any file scope identifier with an underscore even if its linkage limits its visibility to a single translation unit.

    + #include <cstddef> // std::for size_t static const std::size_t _max_limit = 1024; std::size_t _limit = 100; @@ -248,14 +62,11 @@ std::size_t _limit = 100; unsigned int get_value(unsigned int count) { return count < _limit ? count : _limit; } - +
    -

    - In this compliant solution, file scope identifiers do not begin with an underscore. -

    - - #include <cstddef> // for size_t +

    In this compliant solution, file scope identifiers do not begin with an underscore.

    + #include <cstddef> // for size_t static const std::size_t max_limit = 1024; std::size_t limit = 100; @@ -263,100 +74,48 @@ std::size_t limit = 100; unsigned int get_value(unsigned int count) { return count < limit ? count : limit; } - +
    -

    - In this noncompliant code example, because the C++ standard template library header - - <cinttypes> - - is specified to include - - <cstdint> - - , as per [c.files] paragraph 4 - [ - - ISO/IEC 14882-2014 - - ] - , the name - - MAX_SIZE - - conflicts with the name of the - - <cstdint> - - header macro used to denote the upper limit of - - std:size_t. - -

    - - #include <cinttypes> // for int_fast16_t +

    In this noncompliant code example, because the C++ standard template library header <cinttypes> is specified to include <cstdint>, as per [c.files] paragraph 4 [ISO/IEC 14882-2014], the name MAX_SIZE conflicts with the name of the <cstdint> header macro used to denote the upper limit of std:size_t.

    + #include <cinttypes> // for int_fast16_t void f(std::int_fast16_t val) { enum { MAX_SIZE = 80 }; // ... } - +
    -

    - This compliant solution avoids redefining reserved names. -

    - - #include <cinttypes> // for std::int_fast16_t +

    This compliant solution avoids redefining reserved names.

    + #include <cinttypes> // for std::int_fast16_t void f(std::int_fast16_t val) { enum { BufferSize = 80 }; // ... -} - +}
    -

    - - DCL51-CPP-EX1: - - For compatibility with other compiler vendors or language standard modes, it is acceptable to create a macro identifier that is the same as a reserved identifier so long as the behavior is semantically identical, as in this example. -

    - - // Sometimes generated by configuration tools such as autoconf +

    DCL51-CPP-EX1: For compatibility with other compiler vendors or language standard modes, it is acceptable to create a macro identifier that is the same as a reserved identifier so long as the behavior is semantically identical, as in this example.

    + // Sometimes generated by configuration tools such as autoconf #define const const -  + // Allowed compilers with semantically equivalent extension behavior -#define inline __inline - -

    - - DCL51-CPP-EX2: - - As a compiler vendor or standard library developer, it is acceptable to use identifiers reserved for your implementation. Reserved identifiers may be defined by the compiler, in standard library headers, or in headers included by a standard library header, as in this example declaration from the - - libc++ - - STL implementation. -

    - - // The following declaration of a reserved identifier exists in the libc++ implementation of +#define inline __inline +

    DCL51-CPP-EX2: As a compiler vendor or standard library developer, it is acceptable to use identifiers reserved for your implementation. Reserved identifiers may be defined by the compiler, in standard library headers, or in headers included by a standard library header, as in this example declaration from the libc++ STL implementation.

    + // The following declaration of a reserved identifier exists in the libc++ implementation of // std::basic_string as a public member. The original source code may be found at: // http://llvm.org/svn/llvm-project/libcxx/trunk/include/string -  + template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT>> class basic_string { // ... -  + bool __invariants() const; -}; - +};
    -

    - Using reserved identifiers can lead to incorrect program operation. -

    +

    Using reserved identifiers can lead to incorrect program operation.

    @@ -393,14 +152,10 @@ class basic_string { Low @@ -433,9 +188,7 @@ class basic_string { 20.10 @@ -468,26 +219,16 @@ class basic_string { 3.9 @@ -499,15 +240,11 @@ class basic_string { @@ -541,24 +276,12 @@ class basic_string { 2021.4 @@ -572,9 +295,7 @@ class basic_string { @@ -660,14 +367,10 @@ class basic_string { @@ -682,9 +385,7 @@ class basic_string { 20.10 @@ -713,17 +410,7 @@ class basic_string {
    - - P3 - + P3 - - L3 - + L3
    - - reserved-identifier - + reserved-identifier Partially checked @@ -451,9 +204,7 @@ class basic_string { 7.2.0 - - CertC++-DCL51 - + CertC++-DCL51 - - -Wreserved-id-macro - - - -Wuser-defined-literals - + -Wreserved-id-macro + -Wuser-defined-literals The - - -Wreserved-id-macro - + -Wreserved-id-macro flag is not enabled by default or with - - -Wall - + -Wall , but is enabled with - - -Weverything - + -Weverything . This flag does not catch all instances of this rule, such as redefining reserved names. - 6.1p0 + 6.2p0 - - LANG.ID.NU.MK - - - LANG.STRUCT.DECL.RESERVED - + LANG.ID.NU.MK + LANG.STRUCT.DECL.RESERVED Macro name is C keyword @@ -524,9 +261,7 @@ class basic_string { 2021.2 - - C++5003 - + C++5003 - - MISRA.DEFINE.WRONGNAME - - - MISRA.DEFINE.WRONGNAME.UNDERSCORE - - - MISRA.UNDEF.WRONGNAME - - - MISRA.UNDEF.WRONGNAME.UNDERSCORE - - - MISRA.STDLIB.WRONGNAME - - - MISRA.STDLIB.WRONGNAME.UNDERSCORE - + MISRA.DEFINE.WRONGNAME + MISRA.DEFINE.WRONGNAME.UNDERSCORE + MISRA.UNDEF.WRONGNAME + MISRA.UNDEF.WRONGNAME.UNDERSCORE + MISRA.STDLIB.WRONGNAME + MISRA.STDLIB.WRONGNAME.UNDERSCORE - - 86 S, 218 S, 219 S, 580 S - + 86 S, 218 S, 219 S, 580 S Fully implemented @@ -590,24 +311,12 @@ class basic_string { 2021.2 - - CERT_CPP-DCL51-a - - - CERT_CPP-DCL51-b - - - CERT_CPP-DCL51-c - - - CERT_CPP-DCL51-d - - - CERT_CPP-DCL51-e - - - CERT_CPP-DCL51-f - + CERT_CPP-DCL51-a + CERT_CPP-DCL51-b + CERT_CPP-DCL51-c + CERT_CPP-DCL51-d + CERT_CPP-DCL51-e + CERT_CPP-DCL51-f Do not #define or #undef identifiers with names which start with underscore @@ -646,9 +355,7 @@ class basic_string { 4.4 - - 5003 - + 5003 - 7.16 + 7.17 - - - V1059 - - + V1059 - - reserved-identifier - + reserved-identifier Partially checked @@ -700,11 +401,7 @@ class basic_string { 4.10 - - - 978 - - + 978
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/DCL51-CPP/ObjectReusesReservedName-standard.qhelp b/cpp/cert/src/rules/DCL51-CPP/ObjectReusesReservedName-standard.qhelp index 9c074f0ea6..da543df152 100644 --- a/cpp/cert/src/rules/DCL51-CPP/ObjectReusesReservedName-standard.qhelp +++ b/cpp/cert/src/rules/DCL51-CPP/ObjectReusesReservedName-standard.qhelp @@ -1,246 +1,60 @@
    -

    - The C++ Standard, [reserved.names] - [ - - ISO/IEC 14882-2014 - - ] - , specifies the following rules regarding reserved names - : -

    +

    The C++ Standard, [reserved.names] [ISO/IEC 14882-2014], specifies the following rules regarding reserved names:

      -
    • - A translation unit that includes a standard library header shall not - - #define - - or - - #undef - - names declared in any standard library header. -
    • -
    • - A translation unit shall not - - #define - - or - - #undef - - names lexically identical to keywords, to the identifiers listed in Table 3, or to the - - attribute-token - - s described in 7.6. -
    • -
    • - Each name that contains a double underscore - - __ - - or begins with an underscore followed by an uppercase letter is reserved to the implementation for any use. -
    • -
    • - Each name that begins with an underscore is reserved to the implementation for use as a name in the global namespace. -
    • -
    • - Each name declared as an object with external linkage in a header is reserved to the implementation to designate that library object with external linkage, both in namespace - - std - - and in the global namespace. -
    • -
    • - Each global function signature declared with external linkage in a header is reserved to the implementation to designate that function signature with external linkage. -
    • -
    • - Each name from the Standard C library declared with external linkage is reserved to the implementation for use as a name with - - extern "C" - - linkage, both in namespace - - std - - and in the global namespace. -
    • -
    • - Each function signature from the Standard C library declared with external linkage is reserved to the implementation for use as a function signature with both - - extern "C" - - and - - extern "C++" - - linkage, or as a name of namespace scope in the global namespace. -
    • -
    • - For each type - - T - - from the Standard C library, the types - - ::T - - and - - std::T - - are reserved to the implementation and, when defined, - - ::T - - shall be identical to - - std::T - - . -
    • -
    • - Literal suffix identifiers that do not start with an underscore are reserved for future standardization. -
    • +
    • A translation unit that includes a standard library header shall not #define or #undef names declared in any standard library header.
    • +
    • A translation unit shall not #define or #undef names lexically identical to keywords, to the identifiers listed in Table 3, or to the attribute-tokens described in 7.6.
    • +
    • Each name that contains a double underscore __ or begins with an underscore followed by an uppercase letter is reserved to the implementation for any use.
    • +
    • Each name that begins with an underscore is reserved to the implementation for use as a name in the global namespace.
    • +
    • Each name declared as an object with external linkage in a header is reserved to the implementation to designate that library object with external linkage, both in namespace std and in the global namespace.
    • +
    • Each global function signature declared with external linkage in a header is reserved to the implementation to designate that function signature with external linkage.
    • +
    • Each name from the Standard C library declared with external linkage is reserved to the implementation for use as a name with extern "C" linkage, both in namespace std and in the global namespace.
    • +
    • Each function signature from the Standard C library declared with external linkage is reserved to the implementation for use as a function signature with both extern "C" and extern "C++" linkage, or as a name of namespace scope in the global namespace.
    • +
    • For each type T from the Standard C library, the types ::T and std::T are reserved to the implementation and, when defined, ::T shall be identical to std::T.
    • +
    • Literal suffix identifiers that do not start with an underscore are reserved for future standardization.
    -

    - The identifiers and attribute names referred to in the preceding excerpt are - - override - - , - - final - - , - - alignas - - , - - carries_dependency - - , - - deprecated - - , and - - noreturn - - . -

    -

    - No other identifiers are reserved. Declaring or defining an identifier in a context in which it is reserved results in - - undefined behavior - - . Do not declare or define a reserved identifier. -

    +

    The identifiers and attribute names referred to in the preceding excerpt are override, final, alignas, carries_dependency, deprecated, and noreturn.

    +

    No other identifiers are reserved. Declaring or defining an identifier in a context in which it is reserved results in undefined behavior. Do not declare or define a reserved identifier.

    -

    - A common practice is to use a macro in a preprocessor conditional that guards against multiple inclusions of a header file. While this is a recommended practice, many programs use reserved names as the header guards. Such a name may clash with reserved names defined by the implementation of the C++ standard template library in its headers or with reserved names implicitly predefined by the compiler even when no C++ standard library header is included. -

    - - #ifndef _MY_HEADER_H_ +

    A common practice is to use a macro in a preprocessor conditional that guards against multiple inclusions of a header file. While this is a recommended practice, many programs use reserved names as the header guards. Such a name may clash with reserved names defined by the implementation of the C++ standard template library in its headers or with reserved names implicitly predefined by the compiler even when no C++ standard library header is included.

    + #ifndef _MY_HEADER_H_ #define _MY_HEADER_H_ // Contents of <my_header.h> #endif // _MY_HEADER_H_ - +
    -

    - This compliant solution avoids using leading or trailing underscores in the name of the header guard. -

    - - #ifndef MY_HEADER_H +

    This compliant solution avoids using leading or trailing underscores in the name of the header guard.

    + #ifndef MY_HEADER_H #define MY_HEADER_H // Contents of <my_header.h> #endif // MY_HEADER_H - +
    -

    - In this noncompliant code example, a user-defined literal - operator"" x - is declared. However, literal suffix identifiers are required to start with an underscore; literal suffixes without the underscore prefix are reserved for future library implementations. -

    - - #include <cstddef> -  -unsigned int operator"" x(const char *, std::size_t); - +

    In this noncompliant code example, a user-defined literal operator"" x is declared. However, literal suffix identifiers are required to start with an underscore; literal suffixes without the underscore prefix are reserved for future library implementations.

    + #include <cstddef> + +unsigned int operator"" x(const char *, std::size_t);
    -

    - In this compliant solution, the user-defined literal is named - - operator"" _x - - , which is not a reserved identifier. -

    - - #include <cstddef> -  -unsigned int operator"" _x(const char *, std::size_t); - -

    - The name of the user-defined literal is - - operator"" _x - - and not - - _x - - , which would have otherwise been reserved for the global namespace. -

    +

    In this compliant solution, the user-defined literal is named operator"" _x, which is not a reserved identifier.

    + #include <cstddef> + +unsigned int operator"" _x(const char *, std::size_t); +

    The name of the user-defined literal is operator"" _x and not _x, which would have otherwise been reserved for the global namespace.

    -

    - In this noncompliant code example, the names of the file scope objects - - _max_limit - - and - - _limit - - both begin with an underscore. Because it is - - static - - , the declaration of - - _max_limit - - might seem to be impervious to clashes with names defined by the implementation. However, because the header - - <cstddef> - - is included to define - - std::size_t - - , a potential for a name clash exists. (Note, however, that a conforming compiler may implicitly declare reserved names regardless of whether any C++ standard template library header has been explicitly included.) In addition, because - - _limit - - has external linkage, it may clash with a symbol with the same name defined in the language runtime library even if such a symbol is not declared in any header. Consequently, it is unsafe to start the name of any file scope identifier with an underscore even if its linkage limits its visibility to a single translation unit. -

    - - #include <cstddef> // std::for size_t +

    In this noncompliant code example, the names of the file scope objects _max_limit and _limit both begin with an underscore. Because it is static, the declaration of _max_limit might seem to be impervious to clashes with names defined by the implementation. However, because the header <cstddef> is included to define std::size_t, a potential for a name clash exists. (Note, however, that a conforming compiler may implicitly declare reserved names regardless of whether any C++ standard template library header has been explicitly included.) In addition, because _limit has external linkage, it may clash with a symbol with the same name defined in the language runtime library even if such a symbol is not declared in any header. Consequently, it is unsafe to start the name of any file scope identifier with an underscore even if its linkage limits its visibility to a single translation unit.

    + #include <cstddef> // std::for size_t static const std::size_t _max_limit = 1024; std::size_t _limit = 100; @@ -248,14 +62,11 @@ std::size_t _limit = 100; unsigned int get_value(unsigned int count) { return count < _limit ? count : _limit; } - +
    -

    - In this compliant solution, file scope identifiers do not begin with an underscore. -

    - - #include <cstddef> // for size_t +

    In this compliant solution, file scope identifiers do not begin with an underscore.

    + #include <cstddef> // for size_t static const std::size_t max_limit = 1024; std::size_t limit = 100; @@ -263,100 +74,48 @@ std::size_t limit = 100; unsigned int get_value(unsigned int count) { return count < limit ? count : limit; } - +
    -

    - In this noncompliant code example, because the C++ standard template library header - - <cinttypes> - - is specified to include - - <cstdint> - - , as per [c.files] paragraph 4 - [ - - ISO/IEC 14882-2014 - - ] - , the name - - MAX_SIZE - - conflicts with the name of the - - <cstdint> - - header macro used to denote the upper limit of - - std:size_t. - -

    - - #include <cinttypes> // for int_fast16_t +

    In this noncompliant code example, because the C++ standard template library header <cinttypes> is specified to include <cstdint>, as per [c.files] paragraph 4 [ISO/IEC 14882-2014], the name MAX_SIZE conflicts with the name of the <cstdint> header macro used to denote the upper limit of std:size_t.

    + #include <cinttypes> // for int_fast16_t void f(std::int_fast16_t val) { enum { MAX_SIZE = 80 }; // ... } - +
    -

    - This compliant solution avoids redefining reserved names. -

    - - #include <cinttypes> // for std::int_fast16_t +

    This compliant solution avoids redefining reserved names.

    + #include <cinttypes> // for std::int_fast16_t void f(std::int_fast16_t val) { enum { BufferSize = 80 }; // ... -} - +}
    -

    - - DCL51-CPP-EX1: - - For compatibility with other compiler vendors or language standard modes, it is acceptable to create a macro identifier that is the same as a reserved identifier so long as the behavior is semantically identical, as in this example. -

    - - // Sometimes generated by configuration tools such as autoconf +

    DCL51-CPP-EX1: For compatibility with other compiler vendors or language standard modes, it is acceptable to create a macro identifier that is the same as a reserved identifier so long as the behavior is semantically identical, as in this example.

    + // Sometimes generated by configuration tools such as autoconf #define const const -  + // Allowed compilers with semantically equivalent extension behavior -#define inline __inline - -

    - - DCL51-CPP-EX2: - - As a compiler vendor or standard library developer, it is acceptable to use identifiers reserved for your implementation. Reserved identifiers may be defined by the compiler, in standard library headers, or in headers included by a standard library header, as in this example declaration from the - - libc++ - - STL implementation. -

    - - // The following declaration of a reserved identifier exists in the libc++ implementation of +#define inline __inline +

    DCL51-CPP-EX2: As a compiler vendor or standard library developer, it is acceptable to use identifiers reserved for your implementation. Reserved identifiers may be defined by the compiler, in standard library headers, or in headers included by a standard library header, as in this example declaration from the libc++ STL implementation.

    + // The following declaration of a reserved identifier exists in the libc++ implementation of // std::basic_string as a public member. The original source code may be found at: // http://llvm.org/svn/llvm-project/libcxx/trunk/include/string -  + template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT>> class basic_string { // ... -  + bool __invariants() const; -}; - +};
    -

    - Using reserved identifiers can lead to incorrect program operation. -

    +

    Using reserved identifiers can lead to incorrect program operation.

    @@ -393,14 +152,10 @@ class basic_string { Low @@ -433,9 +188,7 @@ class basic_string { 20.10 @@ -468,26 +219,16 @@ class basic_string { 3.9 @@ -499,15 +240,11 @@ class basic_string { @@ -541,24 +276,12 @@ class basic_string { 2021.4 @@ -572,9 +295,7 @@ class basic_string { @@ -660,14 +367,10 @@ class basic_string { @@ -682,9 +385,7 @@ class basic_string { 20.10 @@ -713,17 +410,7 @@ class basic_string {
    - - P3 - + P3 - - L3 - + L3
    - - reserved-identifier - + reserved-identifier Partially checked @@ -451,9 +204,7 @@ class basic_string { 7.2.0 - - CertC++-DCL51 - + CertC++-DCL51 - - -Wreserved-id-macro - - - -Wuser-defined-literals - + -Wreserved-id-macro + -Wuser-defined-literals The - - -Wreserved-id-macro - + -Wreserved-id-macro flag is not enabled by default or with - - -Wall - + -Wall , but is enabled with - - -Weverything - + -Weverything . This flag does not catch all instances of this rule, such as redefining reserved names. - 6.1p0 + 6.2p0 - - LANG.ID.NU.MK - - - LANG.STRUCT.DECL.RESERVED - + LANG.ID.NU.MK + LANG.STRUCT.DECL.RESERVED Macro name is C keyword @@ -524,9 +261,7 @@ class basic_string { 2021.2 - - C++5003 - + C++5003 - - MISRA.DEFINE.WRONGNAME - - - MISRA.DEFINE.WRONGNAME.UNDERSCORE - - - MISRA.UNDEF.WRONGNAME - - - MISRA.UNDEF.WRONGNAME.UNDERSCORE - - - MISRA.STDLIB.WRONGNAME - - - MISRA.STDLIB.WRONGNAME.UNDERSCORE - + MISRA.DEFINE.WRONGNAME + MISRA.DEFINE.WRONGNAME.UNDERSCORE + MISRA.UNDEF.WRONGNAME + MISRA.UNDEF.WRONGNAME.UNDERSCORE + MISRA.STDLIB.WRONGNAME + MISRA.STDLIB.WRONGNAME.UNDERSCORE - - 86 S, 218 S, 219 S, 580 S - + 86 S, 218 S, 219 S, 580 S Fully implemented @@ -590,24 +311,12 @@ class basic_string { 2021.2 - - CERT_CPP-DCL51-a - - - CERT_CPP-DCL51-b - - - CERT_CPP-DCL51-c - - - CERT_CPP-DCL51-d - - - CERT_CPP-DCL51-e - - - CERT_CPP-DCL51-f - + CERT_CPP-DCL51-a + CERT_CPP-DCL51-b + CERT_CPP-DCL51-c + CERT_CPP-DCL51-d + CERT_CPP-DCL51-e + CERT_CPP-DCL51-f Do not #define or #undef identifiers with names which start with underscore @@ -646,9 +355,7 @@ class basic_string { 4.4 - - 5003 - + 5003 - 7.16 + 7.17 - - - V1059 - - + V1059 - - reserved-identifier - + reserved-identifier Partially checked @@ -700,11 +401,7 @@ class basic_string { 4.10 - - - 978 - - + 978
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/DCL51-CPP/RedefiningOfStandardLibraryName-standard.qhelp b/cpp/cert/src/rules/DCL51-CPP/RedefiningOfStandardLibraryName-standard.qhelp index 9c074f0ea6..da543df152 100644 --- a/cpp/cert/src/rules/DCL51-CPP/RedefiningOfStandardLibraryName-standard.qhelp +++ b/cpp/cert/src/rules/DCL51-CPP/RedefiningOfStandardLibraryName-standard.qhelp @@ -1,246 +1,60 @@
    -

    - The C++ Standard, [reserved.names] - [ - - ISO/IEC 14882-2014 - - ] - , specifies the following rules regarding reserved names - : -

    +

    The C++ Standard, [reserved.names] [ISO/IEC 14882-2014], specifies the following rules regarding reserved names:

      -
    • - A translation unit that includes a standard library header shall not - - #define - - or - - #undef - - names declared in any standard library header. -
    • -
    • - A translation unit shall not - - #define - - or - - #undef - - names lexically identical to keywords, to the identifiers listed in Table 3, or to the - - attribute-token - - s described in 7.6. -
    • -
    • - Each name that contains a double underscore - - __ - - or begins with an underscore followed by an uppercase letter is reserved to the implementation for any use. -
    • -
    • - Each name that begins with an underscore is reserved to the implementation for use as a name in the global namespace. -
    • -
    • - Each name declared as an object with external linkage in a header is reserved to the implementation to designate that library object with external linkage, both in namespace - - std - - and in the global namespace. -
    • -
    • - Each global function signature declared with external linkage in a header is reserved to the implementation to designate that function signature with external linkage. -
    • -
    • - Each name from the Standard C library declared with external linkage is reserved to the implementation for use as a name with - - extern "C" - - linkage, both in namespace - - std - - and in the global namespace. -
    • -
    • - Each function signature from the Standard C library declared with external linkage is reserved to the implementation for use as a function signature with both - - extern "C" - - and - - extern "C++" - - linkage, or as a name of namespace scope in the global namespace. -
    • -
    • - For each type - - T - - from the Standard C library, the types - - ::T - - and - - std::T - - are reserved to the implementation and, when defined, - - ::T - - shall be identical to - - std::T - - . -
    • -
    • - Literal suffix identifiers that do not start with an underscore are reserved for future standardization. -
    • +
    • A translation unit that includes a standard library header shall not #define or #undef names declared in any standard library header.
    • +
    • A translation unit shall not #define or #undef names lexically identical to keywords, to the identifiers listed in Table 3, or to the attribute-tokens described in 7.6.
    • +
    • Each name that contains a double underscore __ or begins with an underscore followed by an uppercase letter is reserved to the implementation for any use.
    • +
    • Each name that begins with an underscore is reserved to the implementation for use as a name in the global namespace.
    • +
    • Each name declared as an object with external linkage in a header is reserved to the implementation to designate that library object with external linkage, both in namespace std and in the global namespace.
    • +
    • Each global function signature declared with external linkage in a header is reserved to the implementation to designate that function signature with external linkage.
    • +
    • Each name from the Standard C library declared with external linkage is reserved to the implementation for use as a name with extern "C" linkage, both in namespace std and in the global namespace.
    • +
    • Each function signature from the Standard C library declared with external linkage is reserved to the implementation for use as a function signature with both extern "C" and extern "C++" linkage, or as a name of namespace scope in the global namespace.
    • +
    • For each type T from the Standard C library, the types ::T and std::T are reserved to the implementation and, when defined, ::T shall be identical to std::T.
    • +
    • Literal suffix identifiers that do not start with an underscore are reserved for future standardization.
    -

    - The identifiers and attribute names referred to in the preceding excerpt are - - override - - , - - final - - , - - alignas - - , - - carries_dependency - - , - - deprecated - - , and - - noreturn - - . -

    -

    - No other identifiers are reserved. Declaring or defining an identifier in a context in which it is reserved results in - - undefined behavior - - . Do not declare or define a reserved identifier. -

    +

    The identifiers and attribute names referred to in the preceding excerpt are override, final, alignas, carries_dependency, deprecated, and noreturn.

    +

    No other identifiers are reserved. Declaring or defining an identifier in a context in which it is reserved results in undefined behavior. Do not declare or define a reserved identifier.

    -

    - A common practice is to use a macro in a preprocessor conditional that guards against multiple inclusions of a header file. While this is a recommended practice, many programs use reserved names as the header guards. Such a name may clash with reserved names defined by the implementation of the C++ standard template library in its headers or with reserved names implicitly predefined by the compiler even when no C++ standard library header is included. -

    - - #ifndef _MY_HEADER_H_ +

    A common practice is to use a macro in a preprocessor conditional that guards against multiple inclusions of a header file. While this is a recommended practice, many programs use reserved names as the header guards. Such a name may clash with reserved names defined by the implementation of the C++ standard template library in its headers or with reserved names implicitly predefined by the compiler even when no C++ standard library header is included.

    + #ifndef _MY_HEADER_H_ #define _MY_HEADER_H_ // Contents of <my_header.h> #endif // _MY_HEADER_H_ - +
    -

    - This compliant solution avoids using leading or trailing underscores in the name of the header guard. -

    - - #ifndef MY_HEADER_H +

    This compliant solution avoids using leading or trailing underscores in the name of the header guard.

    + #ifndef MY_HEADER_H #define MY_HEADER_H // Contents of <my_header.h> #endif // MY_HEADER_H - +
    -

    - In this noncompliant code example, a user-defined literal - operator"" x - is declared. However, literal suffix identifiers are required to start with an underscore; literal suffixes without the underscore prefix are reserved for future library implementations. -

    - - #include <cstddef> -  -unsigned int operator"" x(const char *, std::size_t); - +

    In this noncompliant code example, a user-defined literal operator"" x is declared. However, literal suffix identifiers are required to start with an underscore; literal suffixes without the underscore prefix are reserved for future library implementations.

    + #include <cstddef> + +unsigned int operator"" x(const char *, std::size_t);
    -

    - In this compliant solution, the user-defined literal is named - - operator"" _x - - , which is not a reserved identifier. -

    - - #include <cstddef> -  -unsigned int operator"" _x(const char *, std::size_t); - -

    - The name of the user-defined literal is - - operator"" _x - - and not - - _x - - , which would have otherwise been reserved for the global namespace. -

    +

    In this compliant solution, the user-defined literal is named operator"" _x, which is not a reserved identifier.

    + #include <cstddef> + +unsigned int operator"" _x(const char *, std::size_t); +

    The name of the user-defined literal is operator"" _x and not _x, which would have otherwise been reserved for the global namespace.

    -

    - In this noncompliant code example, the names of the file scope objects - - _max_limit - - and - - _limit - - both begin with an underscore. Because it is - - static - - , the declaration of - - _max_limit - - might seem to be impervious to clashes with names defined by the implementation. However, because the header - - <cstddef> - - is included to define - - std::size_t - - , a potential for a name clash exists. (Note, however, that a conforming compiler may implicitly declare reserved names regardless of whether any C++ standard template library header has been explicitly included.) In addition, because - - _limit - - has external linkage, it may clash with a symbol with the same name defined in the language runtime library even if such a symbol is not declared in any header. Consequently, it is unsafe to start the name of any file scope identifier with an underscore even if its linkage limits its visibility to a single translation unit. -

    - - #include <cstddef> // std::for size_t +

    In this noncompliant code example, the names of the file scope objects _max_limit and _limit both begin with an underscore. Because it is static, the declaration of _max_limit might seem to be impervious to clashes with names defined by the implementation. However, because the header <cstddef> is included to define std::size_t, a potential for a name clash exists. (Note, however, that a conforming compiler may implicitly declare reserved names regardless of whether any C++ standard template library header has been explicitly included.) In addition, because _limit has external linkage, it may clash with a symbol with the same name defined in the language runtime library even if such a symbol is not declared in any header. Consequently, it is unsafe to start the name of any file scope identifier with an underscore even if its linkage limits its visibility to a single translation unit.

    + #include <cstddef> // std::for size_t static const std::size_t _max_limit = 1024; std::size_t _limit = 100; @@ -248,14 +62,11 @@ std::size_t _limit = 100; unsigned int get_value(unsigned int count) { return count < _limit ? count : _limit; } - +
    -

    - In this compliant solution, file scope identifiers do not begin with an underscore. -

    - - #include <cstddef> // for size_t +

    In this compliant solution, file scope identifiers do not begin with an underscore.

    + #include <cstddef> // for size_t static const std::size_t max_limit = 1024; std::size_t limit = 100; @@ -263,100 +74,48 @@ std::size_t limit = 100; unsigned int get_value(unsigned int count) { return count < limit ? count : limit; } - +
    -

    - In this noncompliant code example, because the C++ standard template library header - - <cinttypes> - - is specified to include - - <cstdint> - - , as per [c.files] paragraph 4 - [ - - ISO/IEC 14882-2014 - - ] - , the name - - MAX_SIZE - - conflicts with the name of the - - <cstdint> - - header macro used to denote the upper limit of - - std:size_t. - -

    - - #include <cinttypes> // for int_fast16_t +

    In this noncompliant code example, because the C++ standard template library header <cinttypes> is specified to include <cstdint>, as per [c.files] paragraph 4 [ISO/IEC 14882-2014], the name MAX_SIZE conflicts with the name of the <cstdint> header macro used to denote the upper limit of std:size_t.

    + #include <cinttypes> // for int_fast16_t void f(std::int_fast16_t val) { enum { MAX_SIZE = 80 }; // ... } - +
    -

    - This compliant solution avoids redefining reserved names. -

    - - #include <cinttypes> // for std::int_fast16_t +

    This compliant solution avoids redefining reserved names.

    + #include <cinttypes> // for std::int_fast16_t void f(std::int_fast16_t val) { enum { BufferSize = 80 }; // ... -} - +}
    -

    - - DCL51-CPP-EX1: - - For compatibility with other compiler vendors or language standard modes, it is acceptable to create a macro identifier that is the same as a reserved identifier so long as the behavior is semantically identical, as in this example. -

    - - // Sometimes generated by configuration tools such as autoconf +

    DCL51-CPP-EX1: For compatibility with other compiler vendors or language standard modes, it is acceptable to create a macro identifier that is the same as a reserved identifier so long as the behavior is semantically identical, as in this example.

    + // Sometimes generated by configuration tools such as autoconf #define const const -  + // Allowed compilers with semantically equivalent extension behavior -#define inline __inline - -

    - - DCL51-CPP-EX2: - - As a compiler vendor or standard library developer, it is acceptable to use identifiers reserved for your implementation. Reserved identifiers may be defined by the compiler, in standard library headers, or in headers included by a standard library header, as in this example declaration from the - - libc++ - - STL implementation. -

    - - // The following declaration of a reserved identifier exists in the libc++ implementation of +#define inline __inline +

    DCL51-CPP-EX2: As a compiler vendor or standard library developer, it is acceptable to use identifiers reserved for your implementation. Reserved identifiers may be defined by the compiler, in standard library headers, or in headers included by a standard library header, as in this example declaration from the libc++ STL implementation.

    + // The following declaration of a reserved identifier exists in the libc++ implementation of // std::basic_string as a public member. The original source code may be found at: // http://llvm.org/svn/llvm-project/libcxx/trunk/include/string -  + template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT>> class basic_string { // ... -  + bool __invariants() const; -}; - +};
    -

    - Using reserved identifiers can lead to incorrect program operation. -

    +

    Using reserved identifiers can lead to incorrect program operation.

    @@ -393,14 +152,10 @@ class basic_string { Low @@ -433,9 +188,7 @@ class basic_string { 20.10 @@ -468,26 +219,16 @@ class basic_string { 3.9 @@ -499,15 +240,11 @@ class basic_string { @@ -541,24 +276,12 @@ class basic_string { 2021.4 @@ -572,9 +295,7 @@ class basic_string { @@ -660,14 +367,10 @@ class basic_string { @@ -682,9 +385,7 @@ class basic_string { 20.10 @@ -713,17 +410,7 @@ class basic_string {
    - - P3 - + P3 - - L3 - + L3
    - - reserved-identifier - + reserved-identifier Partially checked @@ -451,9 +204,7 @@ class basic_string { 7.2.0 - - CertC++-DCL51 - + CertC++-DCL51 - - -Wreserved-id-macro - - - -Wuser-defined-literals - + -Wreserved-id-macro + -Wuser-defined-literals The - - -Wreserved-id-macro - + -Wreserved-id-macro flag is not enabled by default or with - - -Wall - + -Wall , but is enabled with - - -Weverything - + -Weverything . This flag does not catch all instances of this rule, such as redefining reserved names. - 6.1p0 + 6.2p0 - - LANG.ID.NU.MK - - - LANG.STRUCT.DECL.RESERVED - + LANG.ID.NU.MK + LANG.STRUCT.DECL.RESERVED Macro name is C keyword @@ -524,9 +261,7 @@ class basic_string { 2021.2 - - C++5003 - + C++5003 - - MISRA.DEFINE.WRONGNAME - - - MISRA.DEFINE.WRONGNAME.UNDERSCORE - - - MISRA.UNDEF.WRONGNAME - - - MISRA.UNDEF.WRONGNAME.UNDERSCORE - - - MISRA.STDLIB.WRONGNAME - - - MISRA.STDLIB.WRONGNAME.UNDERSCORE - + MISRA.DEFINE.WRONGNAME + MISRA.DEFINE.WRONGNAME.UNDERSCORE + MISRA.UNDEF.WRONGNAME + MISRA.UNDEF.WRONGNAME.UNDERSCORE + MISRA.STDLIB.WRONGNAME + MISRA.STDLIB.WRONGNAME.UNDERSCORE - - 86 S, 218 S, 219 S, 580 S - + 86 S, 218 S, 219 S, 580 S Fully implemented @@ -590,24 +311,12 @@ class basic_string { 2021.2 - - CERT_CPP-DCL51-a - - - CERT_CPP-DCL51-b - - - CERT_CPP-DCL51-c - - - CERT_CPP-DCL51-d - - - CERT_CPP-DCL51-e - - - CERT_CPP-DCL51-f - + CERT_CPP-DCL51-a + CERT_CPP-DCL51-b + CERT_CPP-DCL51-c + CERT_CPP-DCL51-d + CERT_CPP-DCL51-e + CERT_CPP-DCL51-f Do not #define or #undef identifiers with names which start with underscore @@ -646,9 +355,7 @@ class basic_string { 4.4 - - 5003 - + 5003 - 7.16 + 7.17 - - - V1059 - - + V1059 - - reserved-identifier - + reserved-identifier Partially checked @@ -700,11 +401,7 @@ class basic_string { 4.10 - - - 978 - - + 978
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/DCL51-CPP/ReuseOfReservedIdentifier-standard.qhelp b/cpp/cert/src/rules/DCL51-CPP/ReuseOfReservedIdentifier-standard.qhelp index 9c074f0ea6..da543df152 100644 --- a/cpp/cert/src/rules/DCL51-CPP/ReuseOfReservedIdentifier-standard.qhelp +++ b/cpp/cert/src/rules/DCL51-CPP/ReuseOfReservedIdentifier-standard.qhelp @@ -1,246 +1,60 @@
    -

    - The C++ Standard, [reserved.names] - [ - - ISO/IEC 14882-2014 - - ] - , specifies the following rules regarding reserved names - : -

    +

    The C++ Standard, [reserved.names] [ISO/IEC 14882-2014], specifies the following rules regarding reserved names:

      -
    • - A translation unit that includes a standard library header shall not - - #define - - or - - #undef - - names declared in any standard library header. -
    • -
    • - A translation unit shall not - - #define - - or - - #undef - - names lexically identical to keywords, to the identifiers listed in Table 3, or to the - - attribute-token - - s described in 7.6. -
    • -
    • - Each name that contains a double underscore - - __ - - or begins with an underscore followed by an uppercase letter is reserved to the implementation for any use. -
    • -
    • - Each name that begins with an underscore is reserved to the implementation for use as a name in the global namespace. -
    • -
    • - Each name declared as an object with external linkage in a header is reserved to the implementation to designate that library object with external linkage, both in namespace - - std - - and in the global namespace. -
    • -
    • - Each global function signature declared with external linkage in a header is reserved to the implementation to designate that function signature with external linkage. -
    • -
    • - Each name from the Standard C library declared with external linkage is reserved to the implementation for use as a name with - - extern "C" - - linkage, both in namespace - - std - - and in the global namespace. -
    • -
    • - Each function signature from the Standard C library declared with external linkage is reserved to the implementation for use as a function signature with both - - extern "C" - - and - - extern "C++" - - linkage, or as a name of namespace scope in the global namespace. -
    • -
    • - For each type - - T - - from the Standard C library, the types - - ::T - - and - - std::T - - are reserved to the implementation and, when defined, - - ::T - - shall be identical to - - std::T - - . -
    • -
    • - Literal suffix identifiers that do not start with an underscore are reserved for future standardization. -
    • +
    • A translation unit that includes a standard library header shall not #define or #undef names declared in any standard library header.
    • +
    • A translation unit shall not #define or #undef names lexically identical to keywords, to the identifiers listed in Table 3, or to the attribute-tokens described in 7.6.
    • +
    • Each name that contains a double underscore __ or begins with an underscore followed by an uppercase letter is reserved to the implementation for any use.
    • +
    • Each name that begins with an underscore is reserved to the implementation for use as a name in the global namespace.
    • +
    • Each name declared as an object with external linkage in a header is reserved to the implementation to designate that library object with external linkage, both in namespace std and in the global namespace.
    • +
    • Each global function signature declared with external linkage in a header is reserved to the implementation to designate that function signature with external linkage.
    • +
    • Each name from the Standard C library declared with external linkage is reserved to the implementation for use as a name with extern "C" linkage, both in namespace std and in the global namespace.
    • +
    • Each function signature from the Standard C library declared with external linkage is reserved to the implementation for use as a function signature with both extern "C" and extern "C++" linkage, or as a name of namespace scope in the global namespace.
    • +
    • For each type T from the Standard C library, the types ::T and std::T are reserved to the implementation and, when defined, ::T shall be identical to std::T.
    • +
    • Literal suffix identifiers that do not start with an underscore are reserved for future standardization.
    -

    - The identifiers and attribute names referred to in the preceding excerpt are - - override - - , - - final - - , - - alignas - - , - - carries_dependency - - , - - deprecated - - , and - - noreturn - - . -

    -

    - No other identifiers are reserved. Declaring or defining an identifier in a context in which it is reserved results in - - undefined behavior - - . Do not declare or define a reserved identifier. -

    +

    The identifiers and attribute names referred to in the preceding excerpt are override, final, alignas, carries_dependency, deprecated, and noreturn.

    +

    No other identifiers are reserved. Declaring or defining an identifier in a context in which it is reserved results in undefined behavior. Do not declare or define a reserved identifier.

    -

    - A common practice is to use a macro in a preprocessor conditional that guards against multiple inclusions of a header file. While this is a recommended practice, many programs use reserved names as the header guards. Such a name may clash with reserved names defined by the implementation of the C++ standard template library in its headers or with reserved names implicitly predefined by the compiler even when no C++ standard library header is included. -

    - - #ifndef _MY_HEADER_H_ +

    A common practice is to use a macro in a preprocessor conditional that guards against multiple inclusions of a header file. While this is a recommended practice, many programs use reserved names as the header guards. Such a name may clash with reserved names defined by the implementation of the C++ standard template library in its headers or with reserved names implicitly predefined by the compiler even when no C++ standard library header is included.

    + #ifndef _MY_HEADER_H_ #define _MY_HEADER_H_ // Contents of <my_header.h> #endif // _MY_HEADER_H_ - +
    -

    - This compliant solution avoids using leading or trailing underscores in the name of the header guard. -

    - - #ifndef MY_HEADER_H +

    This compliant solution avoids using leading or trailing underscores in the name of the header guard.

    + #ifndef MY_HEADER_H #define MY_HEADER_H // Contents of <my_header.h> #endif // MY_HEADER_H - +
    -

    - In this noncompliant code example, a user-defined literal - operator"" x - is declared. However, literal suffix identifiers are required to start with an underscore; literal suffixes without the underscore prefix are reserved for future library implementations. -

    - - #include <cstddef> -  -unsigned int operator"" x(const char *, std::size_t); - +

    In this noncompliant code example, a user-defined literal operator"" x is declared. However, literal suffix identifiers are required to start with an underscore; literal suffixes without the underscore prefix are reserved for future library implementations.

    + #include <cstddef> + +unsigned int operator"" x(const char *, std::size_t);
    -

    - In this compliant solution, the user-defined literal is named - - operator"" _x - - , which is not a reserved identifier. -

    - - #include <cstddef> -  -unsigned int operator"" _x(const char *, std::size_t); - -

    - The name of the user-defined literal is - - operator"" _x - - and not - - _x - - , which would have otherwise been reserved for the global namespace. -

    +

    In this compliant solution, the user-defined literal is named operator"" _x, which is not a reserved identifier.

    + #include <cstddef> + +unsigned int operator"" _x(const char *, std::size_t); +

    The name of the user-defined literal is operator"" _x and not _x, which would have otherwise been reserved for the global namespace.

    -

    - In this noncompliant code example, the names of the file scope objects - - _max_limit - - and - - _limit - - both begin with an underscore. Because it is - - static - - , the declaration of - - _max_limit - - might seem to be impervious to clashes with names defined by the implementation. However, because the header - - <cstddef> - - is included to define - - std::size_t - - , a potential for a name clash exists. (Note, however, that a conforming compiler may implicitly declare reserved names regardless of whether any C++ standard template library header has been explicitly included.) In addition, because - - _limit - - has external linkage, it may clash with a symbol with the same name defined in the language runtime library even if such a symbol is not declared in any header. Consequently, it is unsafe to start the name of any file scope identifier with an underscore even if its linkage limits its visibility to a single translation unit. -

    - - #include <cstddef> // std::for size_t +

    In this noncompliant code example, the names of the file scope objects _max_limit and _limit both begin with an underscore. Because it is static, the declaration of _max_limit might seem to be impervious to clashes with names defined by the implementation. However, because the header <cstddef> is included to define std::size_t, a potential for a name clash exists. (Note, however, that a conforming compiler may implicitly declare reserved names regardless of whether any C++ standard template library header has been explicitly included.) In addition, because _limit has external linkage, it may clash with a symbol with the same name defined in the language runtime library even if such a symbol is not declared in any header. Consequently, it is unsafe to start the name of any file scope identifier with an underscore even if its linkage limits its visibility to a single translation unit.

    + #include <cstddef> // std::for size_t static const std::size_t _max_limit = 1024; std::size_t _limit = 100; @@ -248,14 +62,11 @@ std::size_t _limit = 100; unsigned int get_value(unsigned int count) { return count < _limit ? count : _limit; } - +
    -

    - In this compliant solution, file scope identifiers do not begin with an underscore. -

    - - #include <cstddef> // for size_t +

    In this compliant solution, file scope identifiers do not begin with an underscore.

    + #include <cstddef> // for size_t static const std::size_t max_limit = 1024; std::size_t limit = 100; @@ -263,100 +74,48 @@ std::size_t limit = 100; unsigned int get_value(unsigned int count) { return count < limit ? count : limit; } - +
    -

    - In this noncompliant code example, because the C++ standard template library header - - <cinttypes> - - is specified to include - - <cstdint> - - , as per [c.files] paragraph 4 - [ - - ISO/IEC 14882-2014 - - ] - , the name - - MAX_SIZE - - conflicts with the name of the - - <cstdint> - - header macro used to denote the upper limit of - - std:size_t. - -

    - - #include <cinttypes> // for int_fast16_t +

    In this noncompliant code example, because the C++ standard template library header <cinttypes> is specified to include <cstdint>, as per [c.files] paragraph 4 [ISO/IEC 14882-2014], the name MAX_SIZE conflicts with the name of the <cstdint> header macro used to denote the upper limit of std:size_t.

    + #include <cinttypes> // for int_fast16_t void f(std::int_fast16_t val) { enum { MAX_SIZE = 80 }; // ... } - +
    -

    - This compliant solution avoids redefining reserved names. -

    - - #include <cinttypes> // for std::int_fast16_t +

    This compliant solution avoids redefining reserved names.

    + #include <cinttypes> // for std::int_fast16_t void f(std::int_fast16_t val) { enum { BufferSize = 80 }; // ... -} - +}
    -

    - - DCL51-CPP-EX1: - - For compatibility with other compiler vendors or language standard modes, it is acceptable to create a macro identifier that is the same as a reserved identifier so long as the behavior is semantically identical, as in this example. -

    - - // Sometimes generated by configuration tools such as autoconf +

    DCL51-CPP-EX1: For compatibility with other compiler vendors or language standard modes, it is acceptable to create a macro identifier that is the same as a reserved identifier so long as the behavior is semantically identical, as in this example.

    + // Sometimes generated by configuration tools such as autoconf #define const const -  + // Allowed compilers with semantically equivalent extension behavior -#define inline __inline - -

    - - DCL51-CPP-EX2: - - As a compiler vendor or standard library developer, it is acceptable to use identifiers reserved for your implementation. Reserved identifiers may be defined by the compiler, in standard library headers, or in headers included by a standard library header, as in this example declaration from the - - libc++ - - STL implementation. -

    - - // The following declaration of a reserved identifier exists in the libc++ implementation of +#define inline __inline +

    DCL51-CPP-EX2: As a compiler vendor or standard library developer, it is acceptable to use identifiers reserved for your implementation. Reserved identifiers may be defined by the compiler, in standard library headers, or in headers included by a standard library header, as in this example declaration from the libc++ STL implementation.

    + // The following declaration of a reserved identifier exists in the libc++ implementation of // std::basic_string as a public member. The original source code may be found at: // http://llvm.org/svn/llvm-project/libcxx/trunk/include/string -  + template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT>> class basic_string { // ... -  + bool __invariants() const; -}; - +};
    -

    - Using reserved identifiers can lead to incorrect program operation. -

    +

    Using reserved identifiers can lead to incorrect program operation.

    @@ -393,14 +152,10 @@ class basic_string { Low @@ -433,9 +188,7 @@ class basic_string { 20.10 @@ -468,26 +219,16 @@ class basic_string { 3.9 @@ -499,15 +240,11 @@ class basic_string { @@ -541,24 +276,12 @@ class basic_string { 2021.4 @@ -572,9 +295,7 @@ class basic_string { @@ -660,14 +367,10 @@ class basic_string { @@ -682,9 +385,7 @@ class basic_string { 20.10 @@ -713,17 +410,7 @@ class basic_string {
    - - P3 - + P3 - - L3 - + L3
    - - reserved-identifier - + reserved-identifier Partially checked @@ -451,9 +204,7 @@ class basic_string { 7.2.0 - - CertC++-DCL51 - + CertC++-DCL51 - - -Wreserved-id-macro - - - -Wuser-defined-literals - + -Wreserved-id-macro + -Wuser-defined-literals The - - -Wreserved-id-macro - + -Wreserved-id-macro flag is not enabled by default or with - - -Wall - + -Wall , but is enabled with - - -Weverything - + -Weverything . This flag does not catch all instances of this rule, such as redefining reserved names. - 6.1p0 + 6.2p0 - - LANG.ID.NU.MK - - - LANG.STRUCT.DECL.RESERVED - + LANG.ID.NU.MK + LANG.STRUCT.DECL.RESERVED Macro name is C keyword @@ -524,9 +261,7 @@ class basic_string { 2021.2 - - C++5003 - + C++5003 - - MISRA.DEFINE.WRONGNAME - - - MISRA.DEFINE.WRONGNAME.UNDERSCORE - - - MISRA.UNDEF.WRONGNAME - - - MISRA.UNDEF.WRONGNAME.UNDERSCORE - - - MISRA.STDLIB.WRONGNAME - - - MISRA.STDLIB.WRONGNAME.UNDERSCORE - + MISRA.DEFINE.WRONGNAME + MISRA.DEFINE.WRONGNAME.UNDERSCORE + MISRA.UNDEF.WRONGNAME + MISRA.UNDEF.WRONGNAME.UNDERSCORE + MISRA.STDLIB.WRONGNAME + MISRA.STDLIB.WRONGNAME.UNDERSCORE - - 86 S, 218 S, 219 S, 580 S - + 86 S, 218 S, 219 S, 580 S Fully implemented @@ -590,24 +311,12 @@ class basic_string { 2021.2 - - CERT_CPP-DCL51-a - - - CERT_CPP-DCL51-b - - - CERT_CPP-DCL51-c - - - CERT_CPP-DCL51-d - - - CERT_CPP-DCL51-e - - - CERT_CPP-DCL51-f - + CERT_CPP-DCL51-a + CERT_CPP-DCL51-b + CERT_CPP-DCL51-c + CERT_CPP-DCL51-d + CERT_CPP-DCL51-e + CERT_CPP-DCL51-f Do not #define or #undef identifiers with names which start with underscore @@ -646,9 +355,7 @@ class basic_string { 4.4 - - 5003 - + 5003 - 7.16 + 7.17 - - - V1059 - - + V1059 - - reserved-identifier - + reserved-identifier Partially checked @@ -700,11 +401,7 @@ class basic_string { 4.10 - - - 978 - - + 978
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/DCL51-CPP/UseOfDoubleUnderscoreReservedPrefix-standard.qhelp b/cpp/cert/src/rules/DCL51-CPP/UseOfDoubleUnderscoreReservedPrefix-standard.qhelp index 9c074f0ea6..da543df152 100644 --- a/cpp/cert/src/rules/DCL51-CPP/UseOfDoubleUnderscoreReservedPrefix-standard.qhelp +++ b/cpp/cert/src/rules/DCL51-CPP/UseOfDoubleUnderscoreReservedPrefix-standard.qhelp @@ -1,246 +1,60 @@
    -

    - The C++ Standard, [reserved.names] - [ - - ISO/IEC 14882-2014 - - ] - , specifies the following rules regarding reserved names - : -

    +

    The C++ Standard, [reserved.names] [ISO/IEC 14882-2014], specifies the following rules regarding reserved names:

      -
    • - A translation unit that includes a standard library header shall not - - #define - - or - - #undef - - names declared in any standard library header. -
    • -
    • - A translation unit shall not - - #define - - or - - #undef - - names lexically identical to keywords, to the identifiers listed in Table 3, or to the - - attribute-token - - s described in 7.6. -
    • -
    • - Each name that contains a double underscore - - __ - - or begins with an underscore followed by an uppercase letter is reserved to the implementation for any use. -
    • -
    • - Each name that begins with an underscore is reserved to the implementation for use as a name in the global namespace. -
    • -
    • - Each name declared as an object with external linkage in a header is reserved to the implementation to designate that library object with external linkage, both in namespace - - std - - and in the global namespace. -
    • -
    • - Each global function signature declared with external linkage in a header is reserved to the implementation to designate that function signature with external linkage. -
    • -
    • - Each name from the Standard C library declared with external linkage is reserved to the implementation for use as a name with - - extern "C" - - linkage, both in namespace - - std - - and in the global namespace. -
    • -
    • - Each function signature from the Standard C library declared with external linkage is reserved to the implementation for use as a function signature with both - - extern "C" - - and - - extern "C++" - - linkage, or as a name of namespace scope in the global namespace. -
    • -
    • - For each type - - T - - from the Standard C library, the types - - ::T - - and - - std::T - - are reserved to the implementation and, when defined, - - ::T - - shall be identical to - - std::T - - . -
    • -
    • - Literal suffix identifiers that do not start with an underscore are reserved for future standardization. -
    • +
    • A translation unit that includes a standard library header shall not #define or #undef names declared in any standard library header.
    • +
    • A translation unit shall not #define or #undef names lexically identical to keywords, to the identifiers listed in Table 3, or to the attribute-tokens described in 7.6.
    • +
    • Each name that contains a double underscore __ or begins with an underscore followed by an uppercase letter is reserved to the implementation for any use.
    • +
    • Each name that begins with an underscore is reserved to the implementation for use as a name in the global namespace.
    • +
    • Each name declared as an object with external linkage in a header is reserved to the implementation to designate that library object with external linkage, both in namespace std and in the global namespace.
    • +
    • Each global function signature declared with external linkage in a header is reserved to the implementation to designate that function signature with external linkage.
    • +
    • Each name from the Standard C library declared with external linkage is reserved to the implementation for use as a name with extern "C" linkage, both in namespace std and in the global namespace.
    • +
    • Each function signature from the Standard C library declared with external linkage is reserved to the implementation for use as a function signature with both extern "C" and extern "C++" linkage, or as a name of namespace scope in the global namespace.
    • +
    • For each type T from the Standard C library, the types ::T and std::T are reserved to the implementation and, when defined, ::T shall be identical to std::T.
    • +
    • Literal suffix identifiers that do not start with an underscore are reserved for future standardization.
    -

    - The identifiers and attribute names referred to in the preceding excerpt are - - override - - , - - final - - , - - alignas - - , - - carries_dependency - - , - - deprecated - - , and - - noreturn - - . -

    -

    - No other identifiers are reserved. Declaring or defining an identifier in a context in which it is reserved results in - - undefined behavior - - . Do not declare or define a reserved identifier. -

    +

    The identifiers and attribute names referred to in the preceding excerpt are override, final, alignas, carries_dependency, deprecated, and noreturn.

    +

    No other identifiers are reserved. Declaring or defining an identifier in a context in which it is reserved results in undefined behavior. Do not declare or define a reserved identifier.

    -

    - A common practice is to use a macro in a preprocessor conditional that guards against multiple inclusions of a header file. While this is a recommended practice, many programs use reserved names as the header guards. Such a name may clash with reserved names defined by the implementation of the C++ standard template library in its headers or with reserved names implicitly predefined by the compiler even when no C++ standard library header is included. -

    - - #ifndef _MY_HEADER_H_ +

    A common practice is to use a macro in a preprocessor conditional that guards against multiple inclusions of a header file. While this is a recommended practice, many programs use reserved names as the header guards. Such a name may clash with reserved names defined by the implementation of the C++ standard template library in its headers or with reserved names implicitly predefined by the compiler even when no C++ standard library header is included.

    + #ifndef _MY_HEADER_H_ #define _MY_HEADER_H_ // Contents of <my_header.h> #endif // _MY_HEADER_H_ - +
    -

    - This compliant solution avoids using leading or trailing underscores in the name of the header guard. -

    - - #ifndef MY_HEADER_H +

    This compliant solution avoids using leading or trailing underscores in the name of the header guard.

    + #ifndef MY_HEADER_H #define MY_HEADER_H // Contents of <my_header.h> #endif // MY_HEADER_H - +
    -

    - In this noncompliant code example, a user-defined literal - operator"" x - is declared. However, literal suffix identifiers are required to start with an underscore; literal suffixes without the underscore prefix are reserved for future library implementations. -

    - - #include <cstddef> -  -unsigned int operator"" x(const char *, std::size_t); - +

    In this noncompliant code example, a user-defined literal operator"" x is declared. However, literal suffix identifiers are required to start with an underscore; literal suffixes without the underscore prefix are reserved for future library implementations.

    + #include <cstddef> + +unsigned int operator"" x(const char *, std::size_t);
    -

    - In this compliant solution, the user-defined literal is named - - operator"" _x - - , which is not a reserved identifier. -

    - - #include <cstddef> -  -unsigned int operator"" _x(const char *, std::size_t); - -

    - The name of the user-defined literal is - - operator"" _x - - and not - - _x - - , which would have otherwise been reserved for the global namespace. -

    +

    In this compliant solution, the user-defined literal is named operator"" _x, which is not a reserved identifier.

    + #include <cstddef> + +unsigned int operator"" _x(const char *, std::size_t); +

    The name of the user-defined literal is operator"" _x and not _x, which would have otherwise been reserved for the global namespace.

    -

    - In this noncompliant code example, the names of the file scope objects - - _max_limit - - and - - _limit - - both begin with an underscore. Because it is - - static - - , the declaration of - - _max_limit - - might seem to be impervious to clashes with names defined by the implementation. However, because the header - - <cstddef> - - is included to define - - std::size_t - - , a potential for a name clash exists. (Note, however, that a conforming compiler may implicitly declare reserved names regardless of whether any C++ standard template library header has been explicitly included.) In addition, because - - _limit - - has external linkage, it may clash with a symbol with the same name defined in the language runtime library even if such a symbol is not declared in any header. Consequently, it is unsafe to start the name of any file scope identifier with an underscore even if its linkage limits its visibility to a single translation unit. -

    - - #include <cstddef> // std::for size_t +

    In this noncompliant code example, the names of the file scope objects _max_limit and _limit both begin with an underscore. Because it is static, the declaration of _max_limit might seem to be impervious to clashes with names defined by the implementation. However, because the header <cstddef> is included to define std::size_t, a potential for a name clash exists. (Note, however, that a conforming compiler may implicitly declare reserved names regardless of whether any C++ standard template library header has been explicitly included.) In addition, because _limit has external linkage, it may clash with a symbol with the same name defined in the language runtime library even if such a symbol is not declared in any header. Consequently, it is unsafe to start the name of any file scope identifier with an underscore even if its linkage limits its visibility to a single translation unit.

    + #include <cstddef> // std::for size_t static const std::size_t _max_limit = 1024; std::size_t _limit = 100; @@ -248,14 +62,11 @@ std::size_t _limit = 100; unsigned int get_value(unsigned int count) { return count < _limit ? count : _limit; } - +
    -

    - In this compliant solution, file scope identifiers do not begin with an underscore. -

    - - #include <cstddef> // for size_t +

    In this compliant solution, file scope identifiers do not begin with an underscore.

    + #include <cstddef> // for size_t static const std::size_t max_limit = 1024; std::size_t limit = 100; @@ -263,100 +74,48 @@ std::size_t limit = 100; unsigned int get_value(unsigned int count) { return count < limit ? count : limit; } - +
    -

    - In this noncompliant code example, because the C++ standard template library header - - <cinttypes> - - is specified to include - - <cstdint> - - , as per [c.files] paragraph 4 - [ - - ISO/IEC 14882-2014 - - ] - , the name - - MAX_SIZE - - conflicts with the name of the - - <cstdint> - - header macro used to denote the upper limit of - - std:size_t. - -

    - - #include <cinttypes> // for int_fast16_t +

    In this noncompliant code example, because the C++ standard template library header <cinttypes> is specified to include <cstdint>, as per [c.files] paragraph 4 [ISO/IEC 14882-2014], the name MAX_SIZE conflicts with the name of the <cstdint> header macro used to denote the upper limit of std:size_t.

    + #include <cinttypes> // for int_fast16_t void f(std::int_fast16_t val) { enum { MAX_SIZE = 80 }; // ... } - +
    -

    - This compliant solution avoids redefining reserved names. -

    - - #include <cinttypes> // for std::int_fast16_t +

    This compliant solution avoids redefining reserved names.

    + #include <cinttypes> // for std::int_fast16_t void f(std::int_fast16_t val) { enum { BufferSize = 80 }; // ... -} - +}
    -

    - - DCL51-CPP-EX1: - - For compatibility with other compiler vendors or language standard modes, it is acceptable to create a macro identifier that is the same as a reserved identifier so long as the behavior is semantically identical, as in this example. -

    - - // Sometimes generated by configuration tools such as autoconf +

    DCL51-CPP-EX1: For compatibility with other compiler vendors or language standard modes, it is acceptable to create a macro identifier that is the same as a reserved identifier so long as the behavior is semantically identical, as in this example.

    + // Sometimes generated by configuration tools such as autoconf #define const const -  + // Allowed compilers with semantically equivalent extension behavior -#define inline __inline - -

    - - DCL51-CPP-EX2: - - As a compiler vendor or standard library developer, it is acceptable to use identifiers reserved for your implementation. Reserved identifiers may be defined by the compiler, in standard library headers, or in headers included by a standard library header, as in this example declaration from the - - libc++ - - STL implementation. -

    - - // The following declaration of a reserved identifier exists in the libc++ implementation of +#define inline __inline +

    DCL51-CPP-EX2: As a compiler vendor or standard library developer, it is acceptable to use identifiers reserved for your implementation. Reserved identifiers may be defined by the compiler, in standard library headers, or in headers included by a standard library header, as in this example declaration from the libc++ STL implementation.

    + // The following declaration of a reserved identifier exists in the libc++ implementation of // std::basic_string as a public member. The original source code may be found at: // http://llvm.org/svn/llvm-project/libcxx/trunk/include/string -  + template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT>> class basic_string { // ... -  + bool __invariants() const; -}; - +};
    -

    - Using reserved identifiers can lead to incorrect program operation. -

    +

    Using reserved identifiers can lead to incorrect program operation.

    @@ -393,14 +152,10 @@ class basic_string { Low @@ -433,9 +188,7 @@ class basic_string { 20.10 @@ -468,26 +219,16 @@ class basic_string { 3.9 @@ -499,15 +240,11 @@ class basic_string { @@ -541,24 +276,12 @@ class basic_string { 2021.4 @@ -572,9 +295,7 @@ class basic_string { @@ -660,14 +367,10 @@ class basic_string { @@ -682,9 +385,7 @@ class basic_string { 20.10 @@ -713,17 +410,7 @@ class basic_string {
    - - P3 - + P3 - - L3 - + L3
    - - reserved-identifier - + reserved-identifier Partially checked @@ -451,9 +204,7 @@ class basic_string { 7.2.0 - - CertC++-DCL51 - + CertC++-DCL51 - - -Wreserved-id-macro - - - -Wuser-defined-literals - + -Wreserved-id-macro + -Wuser-defined-literals The - - -Wreserved-id-macro - + -Wreserved-id-macro flag is not enabled by default or with - - -Wall - + -Wall , but is enabled with - - -Weverything - + -Weverything . This flag does not catch all instances of this rule, such as redefining reserved names. - 6.1p0 + 6.2p0 - - LANG.ID.NU.MK - - - LANG.STRUCT.DECL.RESERVED - + LANG.ID.NU.MK + LANG.STRUCT.DECL.RESERVED Macro name is C keyword @@ -524,9 +261,7 @@ class basic_string { 2021.2 - - C++5003 - + C++5003 - - MISRA.DEFINE.WRONGNAME - - - MISRA.DEFINE.WRONGNAME.UNDERSCORE - - - MISRA.UNDEF.WRONGNAME - - - MISRA.UNDEF.WRONGNAME.UNDERSCORE - - - MISRA.STDLIB.WRONGNAME - - - MISRA.STDLIB.WRONGNAME.UNDERSCORE - + MISRA.DEFINE.WRONGNAME + MISRA.DEFINE.WRONGNAME.UNDERSCORE + MISRA.UNDEF.WRONGNAME + MISRA.UNDEF.WRONGNAME.UNDERSCORE + MISRA.STDLIB.WRONGNAME + MISRA.STDLIB.WRONGNAME.UNDERSCORE - - 86 S, 218 S, 219 S, 580 S - + 86 S, 218 S, 219 S, 580 S Fully implemented @@ -590,24 +311,12 @@ class basic_string { 2021.2 - - CERT_CPP-DCL51-a - - - CERT_CPP-DCL51-b - - - CERT_CPP-DCL51-c - - - CERT_CPP-DCL51-d - - - CERT_CPP-DCL51-e - - - CERT_CPP-DCL51-f - + CERT_CPP-DCL51-a + CERT_CPP-DCL51-b + CERT_CPP-DCL51-c + CERT_CPP-DCL51-d + CERT_CPP-DCL51-e + CERT_CPP-DCL51-f Do not #define or #undef identifiers with names which start with underscore @@ -646,9 +355,7 @@ class basic_string { 4.4 - - 5003 - + 5003 - 7.16 + 7.17 - - - V1059 - - + V1059 - - reserved-identifier - + reserved-identifier Partially checked @@ -700,11 +401,7 @@ class basic_string { 4.10 - - - 978 - - + 978
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/DCL51-CPP/UseOfReservedLiteralSuffixIdentifier-standard.qhelp b/cpp/cert/src/rules/DCL51-CPP/UseOfReservedLiteralSuffixIdentifier-standard.qhelp index 9c074f0ea6..da543df152 100644 --- a/cpp/cert/src/rules/DCL51-CPP/UseOfReservedLiteralSuffixIdentifier-standard.qhelp +++ b/cpp/cert/src/rules/DCL51-CPP/UseOfReservedLiteralSuffixIdentifier-standard.qhelp @@ -1,246 +1,60 @@
    -

    - The C++ Standard, [reserved.names] - [ - - ISO/IEC 14882-2014 - - ] - , specifies the following rules regarding reserved names - : -

    +

    The C++ Standard, [reserved.names] [ISO/IEC 14882-2014], specifies the following rules regarding reserved names:

      -
    • - A translation unit that includes a standard library header shall not - - #define - - or - - #undef - - names declared in any standard library header. -
    • -
    • - A translation unit shall not - - #define - - or - - #undef - - names lexically identical to keywords, to the identifiers listed in Table 3, or to the - - attribute-token - - s described in 7.6. -
    • -
    • - Each name that contains a double underscore - - __ - - or begins with an underscore followed by an uppercase letter is reserved to the implementation for any use. -
    • -
    • - Each name that begins with an underscore is reserved to the implementation for use as a name in the global namespace. -
    • -
    • - Each name declared as an object with external linkage in a header is reserved to the implementation to designate that library object with external linkage, both in namespace - - std - - and in the global namespace. -
    • -
    • - Each global function signature declared with external linkage in a header is reserved to the implementation to designate that function signature with external linkage. -
    • -
    • - Each name from the Standard C library declared with external linkage is reserved to the implementation for use as a name with - - extern "C" - - linkage, both in namespace - - std - - and in the global namespace. -
    • -
    • - Each function signature from the Standard C library declared with external linkage is reserved to the implementation for use as a function signature with both - - extern "C" - - and - - extern "C++" - - linkage, or as a name of namespace scope in the global namespace. -
    • -
    • - For each type - - T - - from the Standard C library, the types - - ::T - - and - - std::T - - are reserved to the implementation and, when defined, - - ::T - - shall be identical to - - std::T - - . -
    • -
    • - Literal suffix identifiers that do not start with an underscore are reserved for future standardization. -
    • +
    • A translation unit that includes a standard library header shall not #define or #undef names declared in any standard library header.
    • +
    • A translation unit shall not #define or #undef names lexically identical to keywords, to the identifiers listed in Table 3, or to the attribute-tokens described in 7.6.
    • +
    • Each name that contains a double underscore __ or begins with an underscore followed by an uppercase letter is reserved to the implementation for any use.
    • +
    • Each name that begins with an underscore is reserved to the implementation for use as a name in the global namespace.
    • +
    • Each name declared as an object with external linkage in a header is reserved to the implementation to designate that library object with external linkage, both in namespace std and in the global namespace.
    • +
    • Each global function signature declared with external linkage in a header is reserved to the implementation to designate that function signature with external linkage.
    • +
    • Each name from the Standard C library declared with external linkage is reserved to the implementation for use as a name with extern "C" linkage, both in namespace std and in the global namespace.
    • +
    • Each function signature from the Standard C library declared with external linkage is reserved to the implementation for use as a function signature with both extern "C" and extern "C++" linkage, or as a name of namespace scope in the global namespace.
    • +
    • For each type T from the Standard C library, the types ::T and std::T are reserved to the implementation and, when defined, ::T shall be identical to std::T.
    • +
    • Literal suffix identifiers that do not start with an underscore are reserved for future standardization.
    -

    - The identifiers and attribute names referred to in the preceding excerpt are - - override - - , - - final - - , - - alignas - - , - - carries_dependency - - , - - deprecated - - , and - - noreturn - - . -

    -

    - No other identifiers are reserved. Declaring or defining an identifier in a context in which it is reserved results in - - undefined behavior - - . Do not declare or define a reserved identifier. -

    +

    The identifiers and attribute names referred to in the preceding excerpt are override, final, alignas, carries_dependency, deprecated, and noreturn.

    +

    No other identifiers are reserved. Declaring or defining an identifier in a context in which it is reserved results in undefined behavior. Do not declare or define a reserved identifier.

    -

    - A common practice is to use a macro in a preprocessor conditional that guards against multiple inclusions of a header file. While this is a recommended practice, many programs use reserved names as the header guards. Such a name may clash with reserved names defined by the implementation of the C++ standard template library in its headers or with reserved names implicitly predefined by the compiler even when no C++ standard library header is included. -

    - - #ifndef _MY_HEADER_H_ +

    A common practice is to use a macro in a preprocessor conditional that guards against multiple inclusions of a header file. While this is a recommended practice, many programs use reserved names as the header guards. Such a name may clash with reserved names defined by the implementation of the C++ standard template library in its headers or with reserved names implicitly predefined by the compiler even when no C++ standard library header is included.

    + #ifndef _MY_HEADER_H_ #define _MY_HEADER_H_ // Contents of <my_header.h> #endif // _MY_HEADER_H_ - +
    -

    - This compliant solution avoids using leading or trailing underscores in the name of the header guard. -

    - - #ifndef MY_HEADER_H +

    This compliant solution avoids using leading or trailing underscores in the name of the header guard.

    + #ifndef MY_HEADER_H #define MY_HEADER_H // Contents of <my_header.h> #endif // MY_HEADER_H - +
    -

    - In this noncompliant code example, a user-defined literal - operator"" x - is declared. However, literal suffix identifiers are required to start with an underscore; literal suffixes without the underscore prefix are reserved for future library implementations. -

    - - #include <cstddef> -  -unsigned int operator"" x(const char *, std::size_t); - +

    In this noncompliant code example, a user-defined literal operator"" x is declared. However, literal suffix identifiers are required to start with an underscore; literal suffixes without the underscore prefix are reserved for future library implementations.

    + #include <cstddef> + +unsigned int operator"" x(const char *, std::size_t);
    -

    - In this compliant solution, the user-defined literal is named - - operator"" _x - - , which is not a reserved identifier. -

    - - #include <cstddef> -  -unsigned int operator"" _x(const char *, std::size_t); - -

    - The name of the user-defined literal is - - operator"" _x - - and not - - _x - - , which would have otherwise been reserved for the global namespace. -

    +

    In this compliant solution, the user-defined literal is named operator"" _x, which is not a reserved identifier.

    + #include <cstddef> + +unsigned int operator"" _x(const char *, std::size_t); +

    The name of the user-defined literal is operator"" _x and not _x, which would have otherwise been reserved for the global namespace.

    -

    - In this noncompliant code example, the names of the file scope objects - - _max_limit - - and - - _limit - - both begin with an underscore. Because it is - - static - - , the declaration of - - _max_limit - - might seem to be impervious to clashes with names defined by the implementation. However, because the header - - <cstddef> - - is included to define - - std::size_t - - , a potential for a name clash exists. (Note, however, that a conforming compiler may implicitly declare reserved names regardless of whether any C++ standard template library header has been explicitly included.) In addition, because - - _limit - - has external linkage, it may clash with a symbol with the same name defined in the language runtime library even if such a symbol is not declared in any header. Consequently, it is unsafe to start the name of any file scope identifier with an underscore even if its linkage limits its visibility to a single translation unit. -

    - - #include <cstddef> // std::for size_t +

    In this noncompliant code example, the names of the file scope objects _max_limit and _limit both begin with an underscore. Because it is static, the declaration of _max_limit might seem to be impervious to clashes with names defined by the implementation. However, because the header <cstddef> is included to define std::size_t, a potential for a name clash exists. (Note, however, that a conforming compiler may implicitly declare reserved names regardless of whether any C++ standard template library header has been explicitly included.) In addition, because _limit has external linkage, it may clash with a symbol with the same name defined in the language runtime library even if such a symbol is not declared in any header. Consequently, it is unsafe to start the name of any file scope identifier with an underscore even if its linkage limits its visibility to a single translation unit.

    + #include <cstddef> // std::for size_t static const std::size_t _max_limit = 1024; std::size_t _limit = 100; @@ -248,14 +62,11 @@ std::size_t _limit = 100; unsigned int get_value(unsigned int count) { return count < _limit ? count : _limit; } - +
    -

    - In this compliant solution, file scope identifiers do not begin with an underscore. -

    - - #include <cstddef> // for size_t +

    In this compliant solution, file scope identifiers do not begin with an underscore.

    + #include <cstddef> // for size_t static const std::size_t max_limit = 1024; std::size_t limit = 100; @@ -263,100 +74,48 @@ std::size_t limit = 100; unsigned int get_value(unsigned int count) { return count < limit ? count : limit; } - +
    -

    - In this noncompliant code example, because the C++ standard template library header - - <cinttypes> - - is specified to include - - <cstdint> - - , as per [c.files] paragraph 4 - [ - - ISO/IEC 14882-2014 - - ] - , the name - - MAX_SIZE - - conflicts with the name of the - - <cstdint> - - header macro used to denote the upper limit of - - std:size_t. - -

    - - #include <cinttypes> // for int_fast16_t +

    In this noncompliant code example, because the C++ standard template library header <cinttypes> is specified to include <cstdint>, as per [c.files] paragraph 4 [ISO/IEC 14882-2014], the name MAX_SIZE conflicts with the name of the <cstdint> header macro used to denote the upper limit of std:size_t.

    + #include <cinttypes> // for int_fast16_t void f(std::int_fast16_t val) { enum { MAX_SIZE = 80 }; // ... } - +
    -

    - This compliant solution avoids redefining reserved names. -

    - - #include <cinttypes> // for std::int_fast16_t +

    This compliant solution avoids redefining reserved names.

    + #include <cinttypes> // for std::int_fast16_t void f(std::int_fast16_t val) { enum { BufferSize = 80 }; // ... -} - +}
    -

    - - DCL51-CPP-EX1: - - For compatibility with other compiler vendors or language standard modes, it is acceptable to create a macro identifier that is the same as a reserved identifier so long as the behavior is semantically identical, as in this example. -

    - - // Sometimes generated by configuration tools such as autoconf +

    DCL51-CPP-EX1: For compatibility with other compiler vendors or language standard modes, it is acceptable to create a macro identifier that is the same as a reserved identifier so long as the behavior is semantically identical, as in this example.

    + // Sometimes generated by configuration tools such as autoconf #define const const -  + // Allowed compilers with semantically equivalent extension behavior -#define inline __inline - -

    - - DCL51-CPP-EX2: - - As a compiler vendor or standard library developer, it is acceptable to use identifiers reserved for your implementation. Reserved identifiers may be defined by the compiler, in standard library headers, or in headers included by a standard library header, as in this example declaration from the - - libc++ - - STL implementation. -

    - - // The following declaration of a reserved identifier exists in the libc++ implementation of +#define inline __inline +

    DCL51-CPP-EX2: As a compiler vendor or standard library developer, it is acceptable to use identifiers reserved for your implementation. Reserved identifiers may be defined by the compiler, in standard library headers, or in headers included by a standard library header, as in this example declaration from the libc++ STL implementation.

    + // The following declaration of a reserved identifier exists in the libc++ implementation of // std::basic_string as a public member. The original source code may be found at: // http://llvm.org/svn/llvm-project/libcxx/trunk/include/string -  + template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT>> class basic_string { // ... -  + bool __invariants() const; -}; - +};
    -

    - Using reserved identifiers can lead to incorrect program operation. -

    +

    Using reserved identifiers can lead to incorrect program operation.

    @@ -393,14 +152,10 @@ class basic_string { Low @@ -433,9 +188,7 @@ class basic_string { 20.10 @@ -468,26 +219,16 @@ class basic_string { 3.9 @@ -499,15 +240,11 @@ class basic_string { @@ -541,24 +276,12 @@ class basic_string { 2021.4 @@ -572,9 +295,7 @@ class basic_string { @@ -660,14 +367,10 @@ class basic_string { @@ -682,9 +385,7 @@ class basic_string { 20.10 @@ -713,17 +410,7 @@ class basic_string {
    - - P3 - + P3 - - L3 - + L3
    - - reserved-identifier - + reserved-identifier Partially checked @@ -451,9 +204,7 @@ class basic_string { 7.2.0 - - CertC++-DCL51 - + CertC++-DCL51 - - -Wreserved-id-macro - - - -Wuser-defined-literals - + -Wreserved-id-macro + -Wuser-defined-literals The - - -Wreserved-id-macro - + -Wreserved-id-macro flag is not enabled by default or with - - -Wall - + -Wall , but is enabled with - - -Weverything - + -Weverything . This flag does not catch all instances of this rule, such as redefining reserved names. - 6.1p0 + 6.2p0 - - LANG.ID.NU.MK - - - LANG.STRUCT.DECL.RESERVED - + LANG.ID.NU.MK + LANG.STRUCT.DECL.RESERVED Macro name is C keyword @@ -524,9 +261,7 @@ class basic_string { 2021.2 - - C++5003 - + C++5003 - - MISRA.DEFINE.WRONGNAME - - - MISRA.DEFINE.WRONGNAME.UNDERSCORE - - - MISRA.UNDEF.WRONGNAME - - - MISRA.UNDEF.WRONGNAME.UNDERSCORE - - - MISRA.STDLIB.WRONGNAME - - - MISRA.STDLIB.WRONGNAME.UNDERSCORE - + MISRA.DEFINE.WRONGNAME + MISRA.DEFINE.WRONGNAME.UNDERSCORE + MISRA.UNDEF.WRONGNAME + MISRA.UNDEF.WRONGNAME.UNDERSCORE + MISRA.STDLIB.WRONGNAME + MISRA.STDLIB.WRONGNAME.UNDERSCORE - - 86 S, 218 S, 219 S, 580 S - + 86 S, 218 S, 219 S, 580 S Fully implemented @@ -590,24 +311,12 @@ class basic_string { 2021.2 - - CERT_CPP-DCL51-a - - - CERT_CPP-DCL51-b - - - CERT_CPP-DCL51-c - - - CERT_CPP-DCL51-d - - - CERT_CPP-DCL51-e - - - CERT_CPP-DCL51-f - + CERT_CPP-DCL51-a + CERT_CPP-DCL51-b + CERT_CPP-DCL51-c + CERT_CPP-DCL51-d + CERT_CPP-DCL51-e + CERT_CPP-DCL51-f Do not #define or #undef identifiers with names which start with underscore @@ -646,9 +355,7 @@ class basic_string { 4.4 - - 5003 - + 5003 - 7.16 + 7.17 - - - V1059 - - + V1059 - - reserved-identifier - + reserved-identifier Partially checked @@ -700,11 +401,7 @@ class basic_string { 4.10 - - - 978 - - + 978
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/DCL51-CPP/UseOfReservedNamePrefix-standard.qhelp b/cpp/cert/src/rules/DCL51-CPP/UseOfReservedNamePrefix-standard.qhelp index 9c074f0ea6..da543df152 100644 --- a/cpp/cert/src/rules/DCL51-CPP/UseOfReservedNamePrefix-standard.qhelp +++ b/cpp/cert/src/rules/DCL51-CPP/UseOfReservedNamePrefix-standard.qhelp @@ -1,246 +1,60 @@
    -

    - The C++ Standard, [reserved.names] - [ - - ISO/IEC 14882-2014 - - ] - , specifies the following rules regarding reserved names - : -

    +

    The C++ Standard, [reserved.names] [ISO/IEC 14882-2014], specifies the following rules regarding reserved names:

      -
    • - A translation unit that includes a standard library header shall not - - #define - - or - - #undef - - names declared in any standard library header. -
    • -
    • - A translation unit shall not - - #define - - or - - #undef - - names lexically identical to keywords, to the identifiers listed in Table 3, or to the - - attribute-token - - s described in 7.6. -
    • -
    • - Each name that contains a double underscore - - __ - - or begins with an underscore followed by an uppercase letter is reserved to the implementation for any use. -
    • -
    • - Each name that begins with an underscore is reserved to the implementation for use as a name in the global namespace. -
    • -
    • - Each name declared as an object with external linkage in a header is reserved to the implementation to designate that library object with external linkage, both in namespace - - std - - and in the global namespace. -
    • -
    • - Each global function signature declared with external linkage in a header is reserved to the implementation to designate that function signature with external linkage. -
    • -
    • - Each name from the Standard C library declared with external linkage is reserved to the implementation for use as a name with - - extern "C" - - linkage, both in namespace - - std - - and in the global namespace. -
    • -
    • - Each function signature from the Standard C library declared with external linkage is reserved to the implementation for use as a function signature with both - - extern "C" - - and - - extern "C++" - - linkage, or as a name of namespace scope in the global namespace. -
    • -
    • - For each type - - T - - from the Standard C library, the types - - ::T - - and - - std::T - - are reserved to the implementation and, when defined, - - ::T - - shall be identical to - - std::T - - . -
    • -
    • - Literal suffix identifiers that do not start with an underscore are reserved for future standardization. -
    • +
    • A translation unit that includes a standard library header shall not #define or #undef names declared in any standard library header.
    • +
    • A translation unit shall not #define or #undef names lexically identical to keywords, to the identifiers listed in Table 3, or to the attribute-tokens described in 7.6.
    • +
    • Each name that contains a double underscore __ or begins with an underscore followed by an uppercase letter is reserved to the implementation for any use.
    • +
    • Each name that begins with an underscore is reserved to the implementation for use as a name in the global namespace.
    • +
    • Each name declared as an object with external linkage in a header is reserved to the implementation to designate that library object with external linkage, both in namespace std and in the global namespace.
    • +
    • Each global function signature declared with external linkage in a header is reserved to the implementation to designate that function signature with external linkage.
    • +
    • Each name from the Standard C library declared with external linkage is reserved to the implementation for use as a name with extern "C" linkage, both in namespace std and in the global namespace.
    • +
    • Each function signature from the Standard C library declared with external linkage is reserved to the implementation for use as a function signature with both extern "C" and extern "C++" linkage, or as a name of namespace scope in the global namespace.
    • +
    • For each type T from the Standard C library, the types ::T and std::T are reserved to the implementation and, when defined, ::T shall be identical to std::T.
    • +
    • Literal suffix identifiers that do not start with an underscore are reserved for future standardization.
    -

    - The identifiers and attribute names referred to in the preceding excerpt are - - override - - , - - final - - , - - alignas - - , - - carries_dependency - - , - - deprecated - - , and - - noreturn - - . -

    -

    - No other identifiers are reserved. Declaring or defining an identifier in a context in which it is reserved results in - - undefined behavior - - . Do not declare or define a reserved identifier. -

    +

    The identifiers and attribute names referred to in the preceding excerpt are override, final, alignas, carries_dependency, deprecated, and noreturn.

    +

    No other identifiers are reserved. Declaring or defining an identifier in a context in which it is reserved results in undefined behavior. Do not declare or define a reserved identifier.

    -

    - A common practice is to use a macro in a preprocessor conditional that guards against multiple inclusions of a header file. While this is a recommended practice, many programs use reserved names as the header guards. Such a name may clash with reserved names defined by the implementation of the C++ standard template library in its headers or with reserved names implicitly predefined by the compiler even when no C++ standard library header is included. -

    - - #ifndef _MY_HEADER_H_ +

    A common practice is to use a macro in a preprocessor conditional that guards against multiple inclusions of a header file. While this is a recommended practice, many programs use reserved names as the header guards. Such a name may clash with reserved names defined by the implementation of the C++ standard template library in its headers or with reserved names implicitly predefined by the compiler even when no C++ standard library header is included.

    + #ifndef _MY_HEADER_H_ #define _MY_HEADER_H_ // Contents of <my_header.h> #endif // _MY_HEADER_H_ - +
    -

    - This compliant solution avoids using leading or trailing underscores in the name of the header guard. -

    - - #ifndef MY_HEADER_H +

    This compliant solution avoids using leading or trailing underscores in the name of the header guard.

    + #ifndef MY_HEADER_H #define MY_HEADER_H // Contents of <my_header.h> #endif // MY_HEADER_H - +
    -

    - In this noncompliant code example, a user-defined literal - operator"" x - is declared. However, literal suffix identifiers are required to start with an underscore; literal suffixes without the underscore prefix are reserved for future library implementations. -

    - - #include <cstddef> -  -unsigned int operator"" x(const char *, std::size_t); - +

    In this noncompliant code example, a user-defined literal operator"" x is declared. However, literal suffix identifiers are required to start with an underscore; literal suffixes without the underscore prefix are reserved for future library implementations.

    + #include <cstddef> + +unsigned int operator"" x(const char *, std::size_t);
    -

    - In this compliant solution, the user-defined literal is named - - operator"" _x - - , which is not a reserved identifier. -

    - - #include <cstddef> -  -unsigned int operator"" _x(const char *, std::size_t); - -

    - The name of the user-defined literal is - - operator"" _x - - and not - - _x - - , which would have otherwise been reserved for the global namespace. -

    +

    In this compliant solution, the user-defined literal is named operator"" _x, which is not a reserved identifier.

    + #include <cstddef> + +unsigned int operator"" _x(const char *, std::size_t); +

    The name of the user-defined literal is operator"" _x and not _x, which would have otherwise been reserved for the global namespace.

    -

    - In this noncompliant code example, the names of the file scope objects - - _max_limit - - and - - _limit - - both begin with an underscore. Because it is - - static - - , the declaration of - - _max_limit - - might seem to be impervious to clashes with names defined by the implementation. However, because the header - - <cstddef> - - is included to define - - std::size_t - - , a potential for a name clash exists. (Note, however, that a conforming compiler may implicitly declare reserved names regardless of whether any C++ standard template library header has been explicitly included.) In addition, because - - _limit - - has external linkage, it may clash with a symbol with the same name defined in the language runtime library even if such a symbol is not declared in any header. Consequently, it is unsafe to start the name of any file scope identifier with an underscore even if its linkage limits its visibility to a single translation unit. -

    - - #include <cstddef> // std::for size_t +

    In this noncompliant code example, the names of the file scope objects _max_limit and _limit both begin with an underscore. Because it is static, the declaration of _max_limit might seem to be impervious to clashes with names defined by the implementation. However, because the header <cstddef> is included to define std::size_t, a potential for a name clash exists. (Note, however, that a conforming compiler may implicitly declare reserved names regardless of whether any C++ standard template library header has been explicitly included.) In addition, because _limit has external linkage, it may clash with a symbol with the same name defined in the language runtime library even if such a symbol is not declared in any header. Consequently, it is unsafe to start the name of any file scope identifier with an underscore even if its linkage limits its visibility to a single translation unit.

    + #include <cstddef> // std::for size_t static const std::size_t _max_limit = 1024; std::size_t _limit = 100; @@ -248,14 +62,11 @@ std::size_t _limit = 100; unsigned int get_value(unsigned int count) { return count < _limit ? count : _limit; } - +
    -

    - In this compliant solution, file scope identifiers do not begin with an underscore. -

    - - #include <cstddef> // for size_t +

    In this compliant solution, file scope identifiers do not begin with an underscore.

    + #include <cstddef> // for size_t static const std::size_t max_limit = 1024; std::size_t limit = 100; @@ -263,100 +74,48 @@ std::size_t limit = 100; unsigned int get_value(unsigned int count) { return count < limit ? count : limit; } - +
    -

    - In this noncompliant code example, because the C++ standard template library header - - <cinttypes> - - is specified to include - - <cstdint> - - , as per [c.files] paragraph 4 - [ - - ISO/IEC 14882-2014 - - ] - , the name - - MAX_SIZE - - conflicts with the name of the - - <cstdint> - - header macro used to denote the upper limit of - - std:size_t. - -

    - - #include <cinttypes> // for int_fast16_t +

    In this noncompliant code example, because the C++ standard template library header <cinttypes> is specified to include <cstdint>, as per [c.files] paragraph 4 [ISO/IEC 14882-2014], the name MAX_SIZE conflicts with the name of the <cstdint> header macro used to denote the upper limit of std:size_t.

    + #include <cinttypes> // for int_fast16_t void f(std::int_fast16_t val) { enum { MAX_SIZE = 80 }; // ... } - +
    -

    - This compliant solution avoids redefining reserved names. -

    - - #include <cinttypes> // for std::int_fast16_t +

    This compliant solution avoids redefining reserved names.

    + #include <cinttypes> // for std::int_fast16_t void f(std::int_fast16_t val) { enum { BufferSize = 80 }; // ... -} - +}
    -

    - - DCL51-CPP-EX1: - - For compatibility with other compiler vendors or language standard modes, it is acceptable to create a macro identifier that is the same as a reserved identifier so long as the behavior is semantically identical, as in this example. -

    - - // Sometimes generated by configuration tools such as autoconf +

    DCL51-CPP-EX1: For compatibility with other compiler vendors or language standard modes, it is acceptable to create a macro identifier that is the same as a reserved identifier so long as the behavior is semantically identical, as in this example.

    + // Sometimes generated by configuration tools such as autoconf #define const const -  + // Allowed compilers with semantically equivalent extension behavior -#define inline __inline - -

    - - DCL51-CPP-EX2: - - As a compiler vendor or standard library developer, it is acceptable to use identifiers reserved for your implementation. Reserved identifiers may be defined by the compiler, in standard library headers, or in headers included by a standard library header, as in this example declaration from the - - libc++ - - STL implementation. -

    - - // The following declaration of a reserved identifier exists in the libc++ implementation of +#define inline __inline +

    DCL51-CPP-EX2: As a compiler vendor or standard library developer, it is acceptable to use identifiers reserved for your implementation. Reserved identifiers may be defined by the compiler, in standard library headers, or in headers included by a standard library header, as in this example declaration from the libc++ STL implementation.

    + // The following declaration of a reserved identifier exists in the libc++ implementation of // std::basic_string as a public member. The original source code may be found at: // http://llvm.org/svn/llvm-project/libcxx/trunk/include/string -  + template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT>> class basic_string { // ... -  + bool __invariants() const; -}; - +};
    -

    - Using reserved identifiers can lead to incorrect program operation. -

    +

    Using reserved identifiers can lead to incorrect program operation.

    @@ -393,14 +152,10 @@ class basic_string { Low @@ -433,9 +188,7 @@ class basic_string { 20.10 @@ -468,26 +219,16 @@ class basic_string { 3.9 @@ -499,15 +240,11 @@ class basic_string { @@ -541,24 +276,12 @@ class basic_string { 2021.4 @@ -572,9 +295,7 @@ class basic_string { @@ -660,14 +367,10 @@ class basic_string { @@ -682,9 +385,7 @@ class basic_string { 20.10 @@ -713,17 +410,7 @@ class basic_string {
    - - P3 - + P3 - - L3 - + L3
    - - reserved-identifier - + reserved-identifier Partially checked @@ -451,9 +204,7 @@ class basic_string { 7.2.0 - - CertC++-DCL51 - + CertC++-DCL51 - - -Wreserved-id-macro - - - -Wuser-defined-literals - + -Wreserved-id-macro + -Wuser-defined-literals The - - -Wreserved-id-macro - + -Wreserved-id-macro flag is not enabled by default or with - - -Wall - + -Wall , but is enabled with - - -Weverything - + -Weverything . This flag does not catch all instances of this rule, such as redefining reserved names. - 6.1p0 + 6.2p0 - - LANG.ID.NU.MK - - - LANG.STRUCT.DECL.RESERVED - + LANG.ID.NU.MK + LANG.STRUCT.DECL.RESERVED Macro name is C keyword @@ -524,9 +261,7 @@ class basic_string { 2021.2 - - C++5003 - + C++5003 - - MISRA.DEFINE.WRONGNAME - - - MISRA.DEFINE.WRONGNAME.UNDERSCORE - - - MISRA.UNDEF.WRONGNAME - - - MISRA.UNDEF.WRONGNAME.UNDERSCORE - - - MISRA.STDLIB.WRONGNAME - - - MISRA.STDLIB.WRONGNAME.UNDERSCORE - + MISRA.DEFINE.WRONGNAME + MISRA.DEFINE.WRONGNAME.UNDERSCORE + MISRA.UNDEF.WRONGNAME + MISRA.UNDEF.WRONGNAME.UNDERSCORE + MISRA.STDLIB.WRONGNAME + MISRA.STDLIB.WRONGNAME.UNDERSCORE - - 86 S, 218 S, 219 S, 580 S - + 86 S, 218 S, 219 S, 580 S Fully implemented @@ -590,24 +311,12 @@ class basic_string { 2021.2 - - CERT_CPP-DCL51-a - - - CERT_CPP-DCL51-b - - - CERT_CPP-DCL51-c - - - CERT_CPP-DCL51-d - - - CERT_CPP-DCL51-e - - - CERT_CPP-DCL51-f - + CERT_CPP-DCL51-a + CERT_CPP-DCL51-b + CERT_CPP-DCL51-c + CERT_CPP-DCL51-d + CERT_CPP-DCL51-e + CERT_CPP-DCL51-f Do not #define or #undef identifiers with names which start with underscore @@ -646,9 +355,7 @@ class basic_string { 4.4 - - 5003 - + 5003 - 7.16 + 7.17 - - - V1059 - - + V1059 - - reserved-identifier - + reserved-identifier Partially checked @@ -700,11 +401,7 @@ class basic_string { 4.10 - - - 978 - - + 978
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/DCL51-CPP/UseOfSingleUnderscoreReservedPrefix-standard.qhelp b/cpp/cert/src/rules/DCL51-CPP/UseOfSingleUnderscoreReservedPrefix-standard.qhelp index 9c074f0ea6..da543df152 100644 --- a/cpp/cert/src/rules/DCL51-CPP/UseOfSingleUnderscoreReservedPrefix-standard.qhelp +++ b/cpp/cert/src/rules/DCL51-CPP/UseOfSingleUnderscoreReservedPrefix-standard.qhelp @@ -1,246 +1,60 @@
    -

    - The C++ Standard, [reserved.names] - [ - - ISO/IEC 14882-2014 - - ] - , specifies the following rules regarding reserved names - : -

    +

    The C++ Standard, [reserved.names] [ISO/IEC 14882-2014], specifies the following rules regarding reserved names:

      -
    • - A translation unit that includes a standard library header shall not - - #define - - or - - #undef - - names declared in any standard library header. -
    • -
    • - A translation unit shall not - - #define - - or - - #undef - - names lexically identical to keywords, to the identifiers listed in Table 3, or to the - - attribute-token - - s described in 7.6. -
    • -
    • - Each name that contains a double underscore - - __ - - or begins with an underscore followed by an uppercase letter is reserved to the implementation for any use. -
    • -
    • - Each name that begins with an underscore is reserved to the implementation for use as a name in the global namespace. -
    • -
    • - Each name declared as an object with external linkage in a header is reserved to the implementation to designate that library object with external linkage, both in namespace - - std - - and in the global namespace. -
    • -
    • - Each global function signature declared with external linkage in a header is reserved to the implementation to designate that function signature with external linkage. -
    • -
    • - Each name from the Standard C library declared with external linkage is reserved to the implementation for use as a name with - - extern "C" - - linkage, both in namespace - - std - - and in the global namespace. -
    • -
    • - Each function signature from the Standard C library declared with external linkage is reserved to the implementation for use as a function signature with both - - extern "C" - - and - - extern "C++" - - linkage, or as a name of namespace scope in the global namespace. -
    • -
    • - For each type - - T - - from the Standard C library, the types - - ::T - - and - - std::T - - are reserved to the implementation and, when defined, - - ::T - - shall be identical to - - std::T - - . -
    • -
    • - Literal suffix identifiers that do not start with an underscore are reserved for future standardization. -
    • +
    • A translation unit that includes a standard library header shall not #define or #undef names declared in any standard library header.
    • +
    • A translation unit shall not #define or #undef names lexically identical to keywords, to the identifiers listed in Table 3, or to the attribute-tokens described in 7.6.
    • +
    • Each name that contains a double underscore __ or begins with an underscore followed by an uppercase letter is reserved to the implementation for any use.
    • +
    • Each name that begins with an underscore is reserved to the implementation for use as a name in the global namespace.
    • +
    • Each name declared as an object with external linkage in a header is reserved to the implementation to designate that library object with external linkage, both in namespace std and in the global namespace.
    • +
    • Each global function signature declared with external linkage in a header is reserved to the implementation to designate that function signature with external linkage.
    • +
    • Each name from the Standard C library declared with external linkage is reserved to the implementation for use as a name with extern "C" linkage, both in namespace std and in the global namespace.
    • +
    • Each function signature from the Standard C library declared with external linkage is reserved to the implementation for use as a function signature with both extern "C" and extern "C++" linkage, or as a name of namespace scope in the global namespace.
    • +
    • For each type T from the Standard C library, the types ::T and std::T are reserved to the implementation and, when defined, ::T shall be identical to std::T.
    • +
    • Literal suffix identifiers that do not start with an underscore are reserved for future standardization.
    -

    - The identifiers and attribute names referred to in the preceding excerpt are - - override - - , - - final - - , - - alignas - - , - - carries_dependency - - , - - deprecated - - , and - - noreturn - - . -

    -

    - No other identifiers are reserved. Declaring or defining an identifier in a context in which it is reserved results in - - undefined behavior - - . Do not declare or define a reserved identifier. -

    +

    The identifiers and attribute names referred to in the preceding excerpt are override, final, alignas, carries_dependency, deprecated, and noreturn.

    +

    No other identifiers are reserved. Declaring or defining an identifier in a context in which it is reserved results in undefined behavior. Do not declare or define a reserved identifier.

    -

    - A common practice is to use a macro in a preprocessor conditional that guards against multiple inclusions of a header file. While this is a recommended practice, many programs use reserved names as the header guards. Such a name may clash with reserved names defined by the implementation of the C++ standard template library in its headers or with reserved names implicitly predefined by the compiler even when no C++ standard library header is included. -

    - - #ifndef _MY_HEADER_H_ +

    A common practice is to use a macro in a preprocessor conditional that guards against multiple inclusions of a header file. While this is a recommended practice, many programs use reserved names as the header guards. Such a name may clash with reserved names defined by the implementation of the C++ standard template library in its headers or with reserved names implicitly predefined by the compiler even when no C++ standard library header is included.

    + #ifndef _MY_HEADER_H_ #define _MY_HEADER_H_ // Contents of <my_header.h> #endif // _MY_HEADER_H_ - +
    -

    - This compliant solution avoids using leading or trailing underscores in the name of the header guard. -

    - - #ifndef MY_HEADER_H +

    This compliant solution avoids using leading or trailing underscores in the name of the header guard.

    + #ifndef MY_HEADER_H #define MY_HEADER_H // Contents of <my_header.h> #endif // MY_HEADER_H - +
    -

    - In this noncompliant code example, a user-defined literal - operator"" x - is declared. However, literal suffix identifiers are required to start with an underscore; literal suffixes without the underscore prefix are reserved for future library implementations. -

    - - #include <cstddef> -  -unsigned int operator"" x(const char *, std::size_t); - +

    In this noncompliant code example, a user-defined literal operator"" x is declared. However, literal suffix identifiers are required to start with an underscore; literal suffixes without the underscore prefix are reserved for future library implementations.

    + #include <cstddef> + +unsigned int operator"" x(const char *, std::size_t);
    -

    - In this compliant solution, the user-defined literal is named - - operator"" _x - - , which is not a reserved identifier. -

    - - #include <cstddef> -  -unsigned int operator"" _x(const char *, std::size_t); - -

    - The name of the user-defined literal is - - operator"" _x - - and not - - _x - - , which would have otherwise been reserved for the global namespace. -

    +

    In this compliant solution, the user-defined literal is named operator"" _x, which is not a reserved identifier.

    + #include <cstddef> + +unsigned int operator"" _x(const char *, std::size_t); +

    The name of the user-defined literal is operator"" _x and not _x, which would have otherwise been reserved for the global namespace.

    -

    - In this noncompliant code example, the names of the file scope objects - - _max_limit - - and - - _limit - - both begin with an underscore. Because it is - - static - - , the declaration of - - _max_limit - - might seem to be impervious to clashes with names defined by the implementation. However, because the header - - <cstddef> - - is included to define - - std::size_t - - , a potential for a name clash exists. (Note, however, that a conforming compiler may implicitly declare reserved names regardless of whether any C++ standard template library header has been explicitly included.) In addition, because - - _limit - - has external linkage, it may clash with a symbol with the same name defined in the language runtime library even if such a symbol is not declared in any header. Consequently, it is unsafe to start the name of any file scope identifier with an underscore even if its linkage limits its visibility to a single translation unit. -

    - - #include <cstddef> // std::for size_t +

    In this noncompliant code example, the names of the file scope objects _max_limit and _limit both begin with an underscore. Because it is static, the declaration of _max_limit might seem to be impervious to clashes with names defined by the implementation. However, because the header <cstddef> is included to define std::size_t, a potential for a name clash exists. (Note, however, that a conforming compiler may implicitly declare reserved names regardless of whether any C++ standard template library header has been explicitly included.) In addition, because _limit has external linkage, it may clash with a symbol with the same name defined in the language runtime library even if such a symbol is not declared in any header. Consequently, it is unsafe to start the name of any file scope identifier with an underscore even if its linkage limits its visibility to a single translation unit.

    + #include <cstddef> // std::for size_t static const std::size_t _max_limit = 1024; std::size_t _limit = 100; @@ -248,14 +62,11 @@ std::size_t _limit = 100; unsigned int get_value(unsigned int count) { return count < _limit ? count : _limit; } - +
    -

    - In this compliant solution, file scope identifiers do not begin with an underscore. -

    - - #include <cstddef> // for size_t +

    In this compliant solution, file scope identifiers do not begin with an underscore.

    + #include <cstddef> // for size_t static const std::size_t max_limit = 1024; std::size_t limit = 100; @@ -263,100 +74,48 @@ std::size_t limit = 100; unsigned int get_value(unsigned int count) { return count < limit ? count : limit; } - +
    -

    - In this noncompliant code example, because the C++ standard template library header - - <cinttypes> - - is specified to include - - <cstdint> - - , as per [c.files] paragraph 4 - [ - - ISO/IEC 14882-2014 - - ] - , the name - - MAX_SIZE - - conflicts with the name of the - - <cstdint> - - header macro used to denote the upper limit of - - std:size_t. - -

    - - #include <cinttypes> // for int_fast16_t +

    In this noncompliant code example, because the C++ standard template library header <cinttypes> is specified to include <cstdint>, as per [c.files] paragraph 4 [ISO/IEC 14882-2014], the name MAX_SIZE conflicts with the name of the <cstdint> header macro used to denote the upper limit of std:size_t.

    + #include <cinttypes> // for int_fast16_t void f(std::int_fast16_t val) { enum { MAX_SIZE = 80 }; // ... } - +
    -

    - This compliant solution avoids redefining reserved names. -

    - - #include <cinttypes> // for std::int_fast16_t +

    This compliant solution avoids redefining reserved names.

    + #include <cinttypes> // for std::int_fast16_t void f(std::int_fast16_t val) { enum { BufferSize = 80 }; // ... -} - +}
    -

    - - DCL51-CPP-EX1: - - For compatibility with other compiler vendors or language standard modes, it is acceptable to create a macro identifier that is the same as a reserved identifier so long as the behavior is semantically identical, as in this example. -

    - - // Sometimes generated by configuration tools such as autoconf +

    DCL51-CPP-EX1: For compatibility with other compiler vendors or language standard modes, it is acceptable to create a macro identifier that is the same as a reserved identifier so long as the behavior is semantically identical, as in this example.

    + // Sometimes generated by configuration tools such as autoconf #define const const -  + // Allowed compilers with semantically equivalent extension behavior -#define inline __inline - -

    - - DCL51-CPP-EX2: - - As a compiler vendor or standard library developer, it is acceptable to use identifiers reserved for your implementation. Reserved identifiers may be defined by the compiler, in standard library headers, or in headers included by a standard library header, as in this example declaration from the - - libc++ - - STL implementation. -

    - - // The following declaration of a reserved identifier exists in the libc++ implementation of +#define inline __inline +

    DCL51-CPP-EX2: As a compiler vendor or standard library developer, it is acceptable to use identifiers reserved for your implementation. Reserved identifiers may be defined by the compiler, in standard library headers, or in headers included by a standard library header, as in this example declaration from the libc++ STL implementation.

    + // The following declaration of a reserved identifier exists in the libc++ implementation of // std::basic_string as a public member. The original source code may be found at: // http://llvm.org/svn/llvm-project/libcxx/trunk/include/string -  + template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT>> class basic_string { // ... -  + bool __invariants() const; -}; - +};
    -

    - Using reserved identifiers can lead to incorrect program operation. -

    +

    Using reserved identifiers can lead to incorrect program operation.

    @@ -393,14 +152,10 @@ class basic_string { Low @@ -433,9 +188,7 @@ class basic_string { 20.10 @@ -468,26 +219,16 @@ class basic_string { 3.9 @@ -499,15 +240,11 @@ class basic_string { @@ -541,24 +276,12 @@ class basic_string { 2021.4 @@ -572,9 +295,7 @@ class basic_string { @@ -660,14 +367,10 @@ class basic_string { @@ -682,9 +385,7 @@ class basic_string { 20.10 @@ -713,17 +410,7 @@ class basic_string {
    - - P3 - + P3 - - L3 - + L3
    - - reserved-identifier - + reserved-identifier Partially checked @@ -451,9 +204,7 @@ class basic_string { 7.2.0 - - CertC++-DCL51 - + CertC++-DCL51 - - -Wreserved-id-macro - - - -Wuser-defined-literals - + -Wreserved-id-macro + -Wuser-defined-literals The - - -Wreserved-id-macro - + -Wreserved-id-macro flag is not enabled by default or with - - -Wall - + -Wall , but is enabled with - - -Weverything - + -Weverything . This flag does not catch all instances of this rule, such as redefining reserved names. - 6.1p0 + 6.2p0 - - LANG.ID.NU.MK - - - LANG.STRUCT.DECL.RESERVED - + LANG.ID.NU.MK + LANG.STRUCT.DECL.RESERVED Macro name is C keyword @@ -524,9 +261,7 @@ class basic_string { 2021.2 - - C++5003 - + C++5003 - - MISRA.DEFINE.WRONGNAME - - - MISRA.DEFINE.WRONGNAME.UNDERSCORE - - - MISRA.UNDEF.WRONGNAME - - - MISRA.UNDEF.WRONGNAME.UNDERSCORE - - - MISRA.STDLIB.WRONGNAME - - - MISRA.STDLIB.WRONGNAME.UNDERSCORE - + MISRA.DEFINE.WRONGNAME + MISRA.DEFINE.WRONGNAME.UNDERSCORE + MISRA.UNDEF.WRONGNAME + MISRA.UNDEF.WRONGNAME.UNDERSCORE + MISRA.STDLIB.WRONGNAME + MISRA.STDLIB.WRONGNAME.UNDERSCORE - - 86 S, 218 S, 219 S, 580 S - + 86 S, 218 S, 219 S, 580 S Fully implemented @@ -590,24 +311,12 @@ class basic_string { 2021.2 - - CERT_CPP-DCL51-a - - - CERT_CPP-DCL51-b - - - CERT_CPP-DCL51-c - - - CERT_CPP-DCL51-d - - - CERT_CPP-DCL51-e - - - CERT_CPP-DCL51-f - + CERT_CPP-DCL51-a + CERT_CPP-DCL51-b + CERT_CPP-DCL51-c + CERT_CPP-DCL51-d + CERT_CPP-DCL51-e + CERT_CPP-DCL51-f Do not #define or #undef identifiers with names which start with underscore @@ -646,9 +355,7 @@ class basic_string { 4.4 - - 5003 - + 5003 - 7.16 + 7.17 - - - V1059 - - + V1059 - - reserved-identifier - + reserved-identifier Partially checked @@ -700,11 +401,7 @@ class basic_string { 4.10 - - - 978 - - + 978
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/DCL53-CPP/LocalConstructorInitializedObjectHidesIdentifier-standard.qhelp b/cpp/cert/src/rules/DCL53-CPP/LocalConstructorInitializedObjectHidesIdentifier-standard.qhelp index 669f269362..16d518d07f 100644 --- a/cpp/cert/src/rules/DCL53-CPP/LocalConstructorInitializedObjectHidesIdentifier-standard.qhelp +++ b/cpp/cert/src/rules/DCL53-CPP/LocalConstructorInitializedObjectHidesIdentifier-standard.qhelp @@ -1,72 +1,19 @@
    -

    - It is possible to devise syntax that can ambiguously be interpreted as either an expression statement or a declaration. Syntax of this sort is called a - - vexing parse - - because the compiler must use disambiguation rules to determine the semantic results. The C++ Standard, [stmt.ambig], paragraph 1 [ - - ISO/IEC 14882-2014 - - ], in part, states the following: -

    +

    It is possible to devise syntax that can ambiguously be interpreted as either an expression statement or a declaration. Syntax of this sort is called a vexing parse because the compiler must use disambiguation rules to determine the semantic results. The C++ Standard, [stmt.ambig], paragraph 1 [ISO/IEC 14882-2014], in part, states the following:

    -

    - There is an ambiguity in the grammar involving - - expression-statement - - s and declarations: An - - expression-statement - - with a function-style explicit type conversion as its leftmost subexpression can be indistinguishable from a declaration where the first declarator starts with a - - ( - - . In those cases the statement is a declaration. [Note: To disambiguate, the whole statement might have to be examined to determine if it is an - - expression-statement - - or a declaration. ... -

    +

    There is an ambiguity in the grammar involving expression-statements and declarations: An expression-statement with a function-style explicit type conversion as its leftmost subexpression can be indistinguishable from a declaration where the first declarator starts with a (. In those cases the statement is a declaration. [Note: To disambiguate, the whole statement might have to be examined to determine if it is an expression-statement or a declaration. ...

    -

    - A similarly vexing parse exists within the context of a declaration where syntax can be ambiguously interpreted as either a function declaration or a declaration with a function-style cast as the initializer. The C++ Standard, [dcl.ambig.res], paragraph 1, in part, states the following: -

    +

    A similarly vexing parse exists within the context of a declaration where syntax can be ambiguously interpreted as either a function declaration or a declaration with a function-style cast as the initializer. The C++ Standard, [dcl.ambig.res], paragraph 1, in part, states the following:

    -

    - The ambiguity arising from the similarity between a function-style cast and a declaration mentioned in 6.8 can also occur in the context of a declaration. In that context, the choice is between a function declaration with a redundant set of parentheses around a parameter name and an object declaration with a function-style cast as the initializer. Just as for the ambiguities mentioned in 6.8, the resolution is to consider any construct that could possibly be a declaration a declaration. -

    +

    The ambiguity arising from the similarity between a function-style cast and a declaration mentioned in 6.8 can also occur in the context of a declaration. In that context, the choice is between a function declaration with a redundant set of parentheses around a parameter name and an object declaration with a function-style cast as the initializer. Just as for the ambiguities mentioned in 6.8, the resolution is to consider any construct that could possibly be a declaration a declaration.

    -

    - Do not write a syntactically ambiguous declaration. With the advent of uniform initialization syntax using a braced-init-list, there is now syntax that unambiguously specifies a declaration instead of an expression statement. Declarations can also be disambiguated by using nonfunction-style casts, by initializing using =, or by removing extraneous parenthesis around the parameter name. -

    +

    Do not write a syntactically ambiguous declaration. With the advent of uniform initialization syntax using a braced-init-list, there is now syntax that unambiguously specifies a declaration instead of an expression statement. Declarations can also be disambiguated by using nonfunction-style casts, by initializing using =, or by removing extraneous parenthesis around the parameter name.

    -

    - In this noncompliant code example, an anonymous local variable of type - - std::unique_lock - - is expected to lock and unlock the mutex - - m - - by virtue of - - RAII. - - However, the declaration is syntactically ambiguous as it can be interpreted as declaring an anonymous object and calling its single-argument converting constructor or interpreted as declaring an object named - - m - - and default constructing it. The syntax used in this example defines the latter instead of the former, and so the mutex object is never locked. -

    - - #include <mutex> +

    In this noncompliant code example, an anonymous local variable of type std::unique_lock is expected to lock and unlock the mutex m by virtue of RAII. However, the declaration is syntactically ambiguous as it can be interpreted as declaring an anonymous object and calling its single-argument converting constructor or interpreted as declaring an object named m and default constructing it. The syntax used in this example defines the latter instead of the former, and so the mutex object is never locked.

    + #include <mutex> static std::mutex m; static int shared_resource; @@ -74,52 +21,24 @@ static int shared_resource; void increment_by_42() { std::unique_lock<std::mutex>(m); shared_resource += 42; -} - +}
    -

    - In this compliant solution, the lock object is given an identifier (other than - - m - - ) and the proper converting constructor is called. -

    - - #include <mutex> -  +

    In this compliant solution, the lock object is given an identifier (other than m) and the proper converting constructor is called.

    + #include <mutex> + static std::mutex m; static int shared_resource; void increment_by_42() { std::unique_lock<std::mutex> lock(m); shared_resource += 42; -} - +}
    -

    - In this noncompliant code example, an attempt is made to declare a local variable, - - w - - , of type - - Widget - - while executing the default constructor. However, this declaration is syntactically ambiguous where the code could be either a declaration of a function pointer accepting no arguments and returning a - - Widget - - or a declaration of a local variable of type - - Widget - - . The syntax used in this example defines the former instead of the latter. -

    - - #include <iostream> -  +

    In this noncompliant code example, an attempt is made to declare a local variable, w, of type Widget while executing the default constructor. However, this declaration is syntactically ambiguous where the code could be either a declaration of a function pointer accepting no arguments and returning a Widget or a declaration of a local variable of type Widget. The syntax used in this example defines the former instead of the latter.

    + #include <iostream> + struct Widget { Widget() { std::cout << "Constructed" << std::endl; } }; @@ -127,21 +46,12 @@ struct Widget { void f() { Widget w(); } - -

    - As a result, this program compiles and prints no output because the default constructor is never actually invoked. -

    +
    +

    As a result, this program compiles and prints no output because the default constructor is never actually invoked.

    -

    - This compliant solution shows two equally compliant ways to write the declaration. The first way is to elide the parentheses after the variable declaration, which ensures the syntax is that of a variable declaration instead of a function declaration. The second way is to use a - - braced-init-list - - to direct-initialize the local variable. -

    - - #include <iostream> +

    This compliant solution shows two equally compliant ways to write the declaration. The first way is to elide the parentheses after the variable declaration, which ensures the syntax is that of a variable declaration instead of a function declaration. The second way is to use a braced-init-list to direct-initialize the local variable.

    + #include <iostream> struct Widget { Widget() { std::cout << "Constructed" << std::endl; } @@ -151,37 +61,12 @@ void f() { Widget w1; // Elide the parentheses Widget w2{}; // Use direct initialization } - -

    - Running this program produces the output - - Constructed - - twice, once for - - w1 - - and once for - - w2 - - . -

    +
    +

    Running this program produces the output Constructed twice, once for w1 and once for w2.

    -

    - This noncompliant code example demonstrates a vexing parse. The declaration - - Gadget g(Widget(i)); - - is not parsed as declaring a - - Gadget - - object with a single argument. It is instead parsed as a function declaration with a redundant set of parentheses around a parameter. -

    - - #include <iostream> +

    This noncompliant code example demonstrates a vexing parse. The declaration Gadget g(Widget(i)); is not parsed as declaring a Gadget object with a single argument. It is instead parsed as a function declaration with a redundant set of parentheses around a parameter.

    + #include <iostream> struct Widget { explicit Widget(int i) { std::cout << "Widget constructed" << std::endl; } @@ -196,51 +81,15 @@ void f() { Gadget g(Widget(i)); std::cout << i << std::endl; } - -

    - Parentheses around parameter names are optional, so the following is a semantically identical spelling of the declaration. -

    - - Gadget g(Widget i); - -

    - As a result, this program is well-formed and prints only - - 3 - - as output because no - - Gadget - - or - - Widget - - objects are constructed. -

    +
    +

    Parentheses around parameter names are optional, so the following is a semantically identical spelling of the declaration.

    + Gadget g(Widget i); + +

    As a result, this program is well-formed and prints only 3 as output because no Gadget or Widget objects are constructed.

    -

    - This compliant solution demonstrates two equally compliant ways to write the declaration of - - g - - . The first declaration, - - g1 - - , uses an extra set of parentheses around the argument to the constructor call, forcing the compiler to parse it as a local variable declaration of type - - Gadget - - instead of as a function declaration. The second declaration, - - g2 - - , uses direct initialization to similar effect. -

    - - #include <iostream> +

    This compliant solution demonstrates two equally compliant ways to write the declaration of g. The first declaration, g1, uses an extra set of parentheses around the argument to the constructor call, forcing the compiler to parse it as a local variable declaration of type Gadget instead of as a function declaration. The second declaration, g2, uses direct initialization to similar effect.

    + #include <iostream> struct Widget { explicit Widget(int i) { std::cout << "Widget constructed" << std::endl; } @@ -256,22 +105,16 @@ void f() { Gadget g2{Widget(i)}; // Use direct initialization std::cout << i << std::endl; } - -

    - Running this program produces the expected output. -

    - - Widget constructed + +

    Running this program produces the expected output.

    + Widget constructed Gadget constructed Widget constructed Gadget constructed -3 - +3
    -

    - Syntactically ambiguous declarations can lead to unexpected program execution. However, it is likely that rudimentary testing would uncover violations of this rule. -

    +

    Syntactically ambiguous declarations can lead to unexpected program execution. However, it is likely that rudimentary testing would uncover violations of this rule.

    @@ -308,14 +151,10 @@ Gadget constructed Medium @@ -348,9 +187,7 @@ Gadget constructed 2021.2 @@ -365,11 +202,7 @@ Gadget constructed 2021.4 @@ -383,11 +216,8 @@ Gadget constructed @@ -447,9 +272,7 @@ Gadget constructed 4.4 @@ -464,9 +287,7 @@ Gadget constructed 3.9 @@ -481,11 +302,7 @@ Gadget constructed 4.10 @@ -494,17 +311,7 @@ Gadget constructed
    - - P2 - + P2 - - L3 - + L3
    - - C++2502, C++2510 - + C++2502, C++2510 - - - CERT.DCL.AMBIGUOUS_DECL - - + CERT.DCL.AMBIGUOUS_DECL - - 296 S - - - + 296 S + Partially implemented @@ -403,13 +233,8 @@ Gadget constructed 2021.2 - - CERT_CPP-DCL53-a - - - CERT_CPP-DCL53-b - CERT_CPP-DCL53-c - + CERT_CPP-DCL53-a + CERT_CPP-DCL53-bCERT_CPP-DCL53-c Parameter names in function declarations should not be enclosed in parentheses @@ -433,7 +258,7 @@ Gadget constructed Checks for declarations that can be confused between: - Function and object declaration, unnamed object or function parameter declaration. + Function and object declarationunction and object declaration, unnamed object or function parameter declarationnnamed object or function parameter declaration. Rule fully covered.
    - - 2502, 2510 - + 2502, 2510 - - -Wvexing-parse - + -Wvexing-parse - - - S3468 - - + S3468
    -

    - Search for other - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for other vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/DCL53-CPP/LocalFunctionDeclaration-standard.qhelp b/cpp/cert/src/rules/DCL53-CPP/LocalFunctionDeclaration-standard.qhelp index 669f269362..16d518d07f 100644 --- a/cpp/cert/src/rules/DCL53-CPP/LocalFunctionDeclaration-standard.qhelp +++ b/cpp/cert/src/rules/DCL53-CPP/LocalFunctionDeclaration-standard.qhelp @@ -1,72 +1,19 @@
    -

    - It is possible to devise syntax that can ambiguously be interpreted as either an expression statement or a declaration. Syntax of this sort is called a - - vexing parse - - because the compiler must use disambiguation rules to determine the semantic results. The C++ Standard, [stmt.ambig], paragraph 1 [ - - ISO/IEC 14882-2014 - - ], in part, states the following: -

    +

    It is possible to devise syntax that can ambiguously be interpreted as either an expression statement or a declaration. Syntax of this sort is called a vexing parse because the compiler must use disambiguation rules to determine the semantic results. The C++ Standard, [stmt.ambig], paragraph 1 [ISO/IEC 14882-2014], in part, states the following:

    -

    - There is an ambiguity in the grammar involving - - expression-statement - - s and declarations: An - - expression-statement - - with a function-style explicit type conversion as its leftmost subexpression can be indistinguishable from a declaration where the first declarator starts with a - - ( - - . In those cases the statement is a declaration. [Note: To disambiguate, the whole statement might have to be examined to determine if it is an - - expression-statement - - or a declaration. ... -

    +

    There is an ambiguity in the grammar involving expression-statements and declarations: An expression-statement with a function-style explicit type conversion as its leftmost subexpression can be indistinguishable from a declaration where the first declarator starts with a (. In those cases the statement is a declaration. [Note: To disambiguate, the whole statement might have to be examined to determine if it is an expression-statement or a declaration. ...

    -

    - A similarly vexing parse exists within the context of a declaration where syntax can be ambiguously interpreted as either a function declaration or a declaration with a function-style cast as the initializer. The C++ Standard, [dcl.ambig.res], paragraph 1, in part, states the following: -

    +

    A similarly vexing parse exists within the context of a declaration where syntax can be ambiguously interpreted as either a function declaration or a declaration with a function-style cast as the initializer. The C++ Standard, [dcl.ambig.res], paragraph 1, in part, states the following:

    -

    - The ambiguity arising from the similarity between a function-style cast and a declaration mentioned in 6.8 can also occur in the context of a declaration. In that context, the choice is between a function declaration with a redundant set of parentheses around a parameter name and an object declaration with a function-style cast as the initializer. Just as for the ambiguities mentioned in 6.8, the resolution is to consider any construct that could possibly be a declaration a declaration. -

    +

    The ambiguity arising from the similarity between a function-style cast and a declaration mentioned in 6.8 can also occur in the context of a declaration. In that context, the choice is between a function declaration with a redundant set of parentheses around a parameter name and an object declaration with a function-style cast as the initializer. Just as for the ambiguities mentioned in 6.8, the resolution is to consider any construct that could possibly be a declaration a declaration.

    -

    - Do not write a syntactically ambiguous declaration. With the advent of uniform initialization syntax using a braced-init-list, there is now syntax that unambiguously specifies a declaration instead of an expression statement. Declarations can also be disambiguated by using nonfunction-style casts, by initializing using =, or by removing extraneous parenthesis around the parameter name. -

    +

    Do not write a syntactically ambiguous declaration. With the advent of uniform initialization syntax using a braced-init-list, there is now syntax that unambiguously specifies a declaration instead of an expression statement. Declarations can also be disambiguated by using nonfunction-style casts, by initializing using =, or by removing extraneous parenthesis around the parameter name.

    -

    - In this noncompliant code example, an anonymous local variable of type - - std::unique_lock - - is expected to lock and unlock the mutex - - m - - by virtue of - - RAII. - - However, the declaration is syntactically ambiguous as it can be interpreted as declaring an anonymous object and calling its single-argument converting constructor or interpreted as declaring an object named - - m - - and default constructing it. The syntax used in this example defines the latter instead of the former, and so the mutex object is never locked. -

    - - #include <mutex> +

    In this noncompliant code example, an anonymous local variable of type std::unique_lock is expected to lock and unlock the mutex m by virtue of RAII. However, the declaration is syntactically ambiguous as it can be interpreted as declaring an anonymous object and calling its single-argument converting constructor or interpreted as declaring an object named m and default constructing it. The syntax used in this example defines the latter instead of the former, and so the mutex object is never locked.

    + #include <mutex> static std::mutex m; static int shared_resource; @@ -74,52 +21,24 @@ static int shared_resource; void increment_by_42() { std::unique_lock<std::mutex>(m); shared_resource += 42; -} - +}
    -

    - In this compliant solution, the lock object is given an identifier (other than - - m - - ) and the proper converting constructor is called. -

    - - #include <mutex> -  +

    In this compliant solution, the lock object is given an identifier (other than m) and the proper converting constructor is called.

    + #include <mutex> + static std::mutex m; static int shared_resource; void increment_by_42() { std::unique_lock<std::mutex> lock(m); shared_resource += 42; -} - +}
    -

    - In this noncompliant code example, an attempt is made to declare a local variable, - - w - - , of type - - Widget - - while executing the default constructor. However, this declaration is syntactically ambiguous where the code could be either a declaration of a function pointer accepting no arguments and returning a - - Widget - - or a declaration of a local variable of type - - Widget - - . The syntax used in this example defines the former instead of the latter. -

    - - #include <iostream> -  +

    In this noncompliant code example, an attempt is made to declare a local variable, w, of type Widget while executing the default constructor. However, this declaration is syntactically ambiguous where the code could be either a declaration of a function pointer accepting no arguments and returning a Widget or a declaration of a local variable of type Widget. The syntax used in this example defines the former instead of the latter.

    + #include <iostream> + struct Widget { Widget() { std::cout << "Constructed" << std::endl; } }; @@ -127,21 +46,12 @@ struct Widget { void f() { Widget w(); } - -

    - As a result, this program compiles and prints no output because the default constructor is never actually invoked. -

    +
    +

    As a result, this program compiles and prints no output because the default constructor is never actually invoked.

    -

    - This compliant solution shows two equally compliant ways to write the declaration. The first way is to elide the parentheses after the variable declaration, which ensures the syntax is that of a variable declaration instead of a function declaration. The second way is to use a - - braced-init-list - - to direct-initialize the local variable. -

    - - #include <iostream> +

    This compliant solution shows two equally compliant ways to write the declaration. The first way is to elide the parentheses after the variable declaration, which ensures the syntax is that of a variable declaration instead of a function declaration. The second way is to use a braced-init-list to direct-initialize the local variable.

    + #include <iostream> struct Widget { Widget() { std::cout << "Constructed" << std::endl; } @@ -151,37 +61,12 @@ void f() { Widget w1; // Elide the parentheses Widget w2{}; // Use direct initialization } - -

    - Running this program produces the output - - Constructed - - twice, once for - - w1 - - and once for - - w2 - - . -

    +
    +

    Running this program produces the output Constructed twice, once for w1 and once for w2.

    -

    - This noncompliant code example demonstrates a vexing parse. The declaration - - Gadget g(Widget(i)); - - is not parsed as declaring a - - Gadget - - object with a single argument. It is instead parsed as a function declaration with a redundant set of parentheses around a parameter. -

    - - #include <iostream> +

    This noncompliant code example demonstrates a vexing parse. The declaration Gadget g(Widget(i)); is not parsed as declaring a Gadget object with a single argument. It is instead parsed as a function declaration with a redundant set of parentheses around a parameter.

    + #include <iostream> struct Widget { explicit Widget(int i) { std::cout << "Widget constructed" << std::endl; } @@ -196,51 +81,15 @@ void f() { Gadget g(Widget(i)); std::cout << i << std::endl; } - -

    - Parentheses around parameter names are optional, so the following is a semantically identical spelling of the declaration. -

    - - Gadget g(Widget i); - -

    - As a result, this program is well-formed and prints only - - 3 - - as output because no - - Gadget - - or - - Widget - - objects are constructed. -

    +
    +

    Parentheses around parameter names are optional, so the following is a semantically identical spelling of the declaration.

    + Gadget g(Widget i); + +

    As a result, this program is well-formed and prints only 3 as output because no Gadget or Widget objects are constructed.

    -

    - This compliant solution demonstrates two equally compliant ways to write the declaration of - - g - - . The first declaration, - - g1 - - , uses an extra set of parentheses around the argument to the constructor call, forcing the compiler to parse it as a local variable declaration of type - - Gadget - - instead of as a function declaration. The second declaration, - - g2 - - , uses direct initialization to similar effect. -

    - - #include <iostream> +

    This compliant solution demonstrates two equally compliant ways to write the declaration of g. The first declaration, g1, uses an extra set of parentheses around the argument to the constructor call, forcing the compiler to parse it as a local variable declaration of type Gadget instead of as a function declaration. The second declaration, g2, uses direct initialization to similar effect.

    + #include <iostream> struct Widget { explicit Widget(int i) { std::cout << "Widget constructed" << std::endl; } @@ -256,22 +105,16 @@ void f() { Gadget g2{Widget(i)}; // Use direct initialization std::cout << i << std::endl; } - -

    - Running this program produces the expected output. -

    - - Widget constructed + +

    Running this program produces the expected output.

    + Widget constructed Gadget constructed Widget constructed Gadget constructed -3 - +3
    -

    - Syntactically ambiguous declarations can lead to unexpected program execution. However, it is likely that rudimentary testing would uncover violations of this rule. -

    +

    Syntactically ambiguous declarations can lead to unexpected program execution. However, it is likely that rudimentary testing would uncover violations of this rule.

    @@ -308,14 +151,10 @@ Gadget constructed Medium @@ -348,9 +187,7 @@ Gadget constructed 2021.2 @@ -365,11 +202,7 @@ Gadget constructed 2021.4 @@ -383,11 +216,8 @@ Gadget constructed @@ -447,9 +272,7 @@ Gadget constructed 4.4 @@ -464,9 +287,7 @@ Gadget constructed 3.9 @@ -481,11 +302,7 @@ Gadget constructed 4.10 @@ -494,17 +311,7 @@ Gadget constructed
    - - P2 - + P2 - - L3 - + L3
    - - C++2502, C++2510 - + C++2502, C++2510 - - - CERT.DCL.AMBIGUOUS_DECL - - + CERT.DCL.AMBIGUOUS_DECL - - 296 S - - - + 296 S + Partially implemented @@ -403,13 +233,8 @@ Gadget constructed 2021.2 - - CERT_CPP-DCL53-a - - - CERT_CPP-DCL53-b - CERT_CPP-DCL53-c - + CERT_CPP-DCL53-a + CERT_CPP-DCL53-bCERT_CPP-DCL53-c Parameter names in function declarations should not be enclosed in parentheses @@ -433,7 +258,7 @@ Gadget constructed Checks for declarations that can be confused between: - Function and object declaration, unnamed object or function parameter declaration. + Function and object declarationunction and object declaration, unnamed object or function parameter declarationnnamed object or function parameter declaration. Rule fully covered.
    - - 2502, 2510 - + 2502, 2510 - - -Wvexing-parse - + -Wvexing-parse - - - S3468 - - + S3468
    -

    - Search for other - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for other vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/DCL54-CPP/SingularOverloadOfMemoryFunction-standard.qhelp b/cpp/cert/src/rules/DCL54-CPP/SingularOverloadOfMemoryFunction-standard.qhelp index d9d60d4bf4..bc316eb78e 100644 --- a/cpp/cert/src/rules/DCL54-CPP/SingularOverloadOfMemoryFunction-standard.qhelp +++ b/cpp/cert/src/rules/DCL54-CPP/SingularOverloadOfMemoryFunction-standard.qhelp @@ -1,59 +1,16 @@
    -

    - Allocation and deallocation functions can be overloaded at both global and class scopes. -

    -

    - If an allocation function is overloaded in a given scope, the corresponding deallocation function must also be overloaded in the same scope (and vice versa). -

    -

    - Failure to overload the corresponding dynamic storage function is likely to violate rules such as - - MEM51-CPP. Properly deallocate dynamically allocated resources - - . For instance, if an overloaded allocation function uses a private heap to perform its allocations, passing a pointer returned by it to the default deallocation function will likely cause - - undefined behavior - - . Even in situations in which the allocation function ultimately uses the default allocator to obtain a pointer to memory, failing to overload a corresponding deallocation function may leave the program in an unexpected state by not updating internal data for the custom allocator. -

    -

    - It is acceptable to define a deleted allocation or deallocation function without its corresponding - - free store - - function. For instance, it is a common practice to define a deleted non-placement allocation or deallocation function as a class member function when the class also defines a placement - - new - - function. This prevents accidental allocation via calls to - - new - - for that class type or deallocation via calls to - - delete - - on pointers to an object of that class type. It is acceptable to declare, but not define, a private allocation or deallocation function without its corresponding free store function for similar reasons. However, a definition must not be provided as that still allows access to the free store function within a class member function. -

    +

    Allocation and deallocation functions can be overloaded at both global and class scopes.

    +

    If an allocation function is overloaded in a given scope, the corresponding deallocation function must also be overloaded in the same scope (and vice versa).

    +

    Failure to overload the corresponding dynamic storage function is likely to violate rules such as MEM51-CPP. Properly deallocate dynamically allocated resources. For instance, if an overloaded allocation function uses a private heap to perform its allocations, passing a pointer returned by it to the default deallocation function will likely cause undefined behavior. Even in situations in which the allocation function ultimately uses the default allocator to obtain a pointer to memory, failing to overload a corresponding deallocation function may leave the program in an unexpected state by not updating internal data for the custom allocator.

    +

    It is acceptable to define a deleted allocation or deallocation function without its corresponding free store function. For instance, it is a common practice to define a deleted non-placement allocation or deallocation function as a class member function when the class also defines a placement new function. This prevents accidental allocation via calls to new for that class type or deallocation via calls to delete on pointers to an object of that class type. It is acceptable to declare, but not define, a private allocation or deallocation function without its corresponding free store function for similar reasons. However, a definition must not be provided as that still allows access to the free store function within a class member function.

    -

    - In this noncompliant code example, an allocation function is overloaded at global scope. However, the corresponding deallocation function is not declared. Were an object to be allocated with the overloaded allocation function, any attempt to delete the object would result in - - undefined behavior - - in violation of - - MEM51-CPP. Properly deallocate dynamically allocated resources - - . -

    - - #include <Windows.h> +

    In this noncompliant code example, an allocation function is overloaded at global scope. However, the corresponding deallocation function is not declared. Were an object to be allocated with the overloaded allocation function, any attempt to delete the object would result in undefined behavior in violation of MEM51-CPP. Properly deallocate dynamically allocated resources.

    + #include <Windows.h> #include <new> -  + void *operator new(std::size_t size) noexcept(false) { static HANDLE h = ::HeapCreate(0, 0, 0); // Private, expandable heap. if (h) { @@ -61,94 +18,66 @@ void *operator new(std::size_t size) noexcept(false) { } throw std::bad_alloc(); } -  -// No corresponding global delete operator defined. - + +// No corresponding global delete operator defined.
    -

    - In this compliant solution, the corresponding deallocation function is also defined at global scope. -

    - - #include <Windows.h> +

    In this compliant solution, the corresponding deallocation function is also defined at global scope.

    + #include <Windows.h> #include <new> class HeapAllocator { static HANDLE h; static bool init; -  + public: static void *alloc(std::size_t size) noexcept(false) { if (!init) { h = ::HeapCreate(0, 0, 0); // Private, expandable heap. init = true; } -  + if (h) { return ::HeapAlloc(h, 0, size); } throw std::bad_alloc(); } -  + static void dealloc(void *ptr) noexcept { if (h) { (void)::HeapFree(h, 0, ptr); } } }; -  + HANDLE HeapAllocator::h = nullptr; bool HeapAllocator::init = false; void *operator new(std::size_t size) noexcept(false) { return HeapAllocator::alloc(size); } -  + void operator delete(void *ptr) noexcept { return HeapAllocator::dealloc(ptr); -} - +}
    -

    - In this noncompliant code example, - - operator new() - - is overloaded at class scope, but - - operator delete() - - is not similarly overloaded at class scope. Despite that the overloaded allocation function calls through to the default global allocation function, were an object of type - - S - - to be allocated, any attempt to delete the object would result in leaving the program in an indeterminate state due to failing to update allocation bookkeeping accordingly. -

    - - #include <new> -  +

    In this noncompliant code example, operator new() is overloaded at class scope, but operator delete() is not similarly overloaded at class scope. Despite that the overloaded allocation function calls through to the default global allocation function, were an object of type S to be allocated, any attempt to delete the object would result in leaving the program in an indeterminate state due to failing to update allocation bookkeeping accordingly.

    + #include <new> + extern "C++" void update_bookkeeping(void *allocated_ptr, std::size_t size, bool alloc); -  + struct S { void *operator new(std::size_t size) noexcept(false) { void *ptr = ::operator new(size); update_bookkeeping(ptr, size, true); return ptr; } -}; - +};
    -

    - In this compliant solution, the corresponding - - operator delete() - - is overloaded at the same class scope. -

    - - #include <new> +

    In this compliant solution, the corresponding operator delete() is overloaded at the same class scope.

    + #include <new> extern "C++" void update_bookkeeping(void *allocated_ptr, std::size_t size, bool alloc); @@ -158,58 +87,18 @@ struct S { update_bookkeeping(ptr, size, true); return ptr; } -  + void operator delete(void *ptr, std::size_t size) noexcept { ::operator delete(ptr); update_bookkeeping(ptr, size, false); } -}; - +};
    -

    - - DCL54-CPP-EX1: - - A placement deallocation function may be elided for a corresponding placement allocation function, but only if the object placement allocation and object construction are guaranteed to be - - noexcept(true) - - . Because placement deallocation functions are automatically invoked when the object initialization terminates by throwing an exception, it is safe to elide the placement deallocation function when exceptions cannot be thrown. For instance, some vendors implement compiler flags disabling exception support (such as -fno-cxx-exceptions in - - Clang - - and /EHs-c- in - - Microsoft Visual Studio - - ), which has - - implementation-defined behavior - - when an exception is thrown but generally results in program termination similar to calling - - abort() - - . -

    +

    DCL54-CPP-EX1: A placement deallocation function may be elided for a corresponding placement allocation function, but only if the object placement allocation and object construction are guaranteed to be noexcept(true). Because placement deallocation functions are automatically invoked when the object initialization terminates by throwing an exception, it is safe to elide the placement deallocation function when exceptions cannot be thrown. For instance, some vendors implement compiler flags disabling exception support (such as -fno-cxx-exceptions in Clang and /EHs-c- in Microsoft Visual Studio), which has implementation-defined behavior when an exception is thrown but generally results in program termination similar to calling abort().

    -

    - Mismatched usage of - - new - - and - - delete - - could lead to a - - denial-of-service attack - - . -

    +

    Mismatched usage of new and delete could lead to a denial-of-service attack.

    @@ -246,14 +135,10 @@ struct S { Low @@ -286,9 +171,7 @@ struct S { 20.10 @@ -321,15 +202,11 @@ struct S { 3.9 @@ -343,9 +220,7 @@ struct S { 2021.2 @@ -360,11 +235,7 @@ struct S { 2021.4 @@ -379,9 +250,7 @@ struct S { 2021.2 @@ -432,9 +299,7 @@ struct S { 20.10 @@ -463,17 +324,7 @@ struct S {
    - - P6 - + P6 - - L2 - + L2
    - - new-delete-pairwise - + new-delete-pairwise Partially checked @@ -304,9 +187,7 @@ struct S { 7.2.0 - - CertC++-DCL54 - + CertC++-DCL54 - - misc-new-delete-overloads - + misc-new-delete-overloads Checked with - - clang-tidy - + clang-tidy .
    - - C++2160 - + C++2160 - - - CERT.DCL.SAME_SCOPE_ALLOC_DEALLOC - - + CERT.DCL.SAME_SCOPE_ALLOC_DEALLOC - - CERT_CPP-DCL54-a - + CERT_CPP-DCL54-a Always provide new and delete together @@ -415,9 +284,7 @@ struct S { 4.4 - - 2160 - + 2160 - - new-delete-pairwise - + new-delete-pairwise Partially checked @@ -450,11 +315,7 @@ struct S { 4.10 - - - S1265 - - + S1265
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/DCL55-CPP/InformationLeakageAcrossTrustBoundaries-standard.qhelp b/cpp/cert/src/rules/DCL55-CPP/InformationLeakageAcrossTrustBoundaries-standard.qhelp index 0c27e8be72..30bc946966 100644 --- a/cpp/cert/src/rules/DCL55-CPP/InformationLeakageAcrossTrustBoundaries-standard.qhelp +++ b/cpp/cert/src/rules/DCL55-CPP/InformationLeakageAcrossTrustBoundaries-standard.qhelp @@ -1,131 +1,62 @@
    -

    - The C++ Standard, [class.mem], paragraph 13 [ - - ISO/IEC 14882-2014 - - ], describes the layout of non-static data members of a non-union class, specifying the following: -

    +

    The C++ Standard, [class.mem], paragraph 13 [ISO/IEC 14882-2014], describes the layout of non-static data members of a non-union class, specifying the following:

    -

    - Nonstatic data members of a (non-union) class with the same access control are allocated so that later members have higher addresses within a class object. The order of allocation of non-static data members with different access control is unspecified. Implementation alignment requirements might cause two adjacent members not to be allocated immediately after each other; so might requirements for space for managing virtual functions and virtual base classes. -

    +

    Nonstatic data members of a (non-union) class with the same access control are allocated so that later members have higher addresses within a class object. The order of allocation of non-static data members with different access control is unspecified. Implementation alignment requirements might cause two adjacent members not to be allocated immediately after each other; so might requirements for space for managing virtual functions and virtual base classes.

    -

    - Further, [class.bit], paragraph 1, in part, states the following: -

    +

    Further, [class.bit], paragraph 1, in part, states the following:

    -

    - Allocation of bit-fields within a class object is implementation-defined. Alignment of bit-fields is implementation-defined. Bit-fields are packed into some addressable allocation unit. -

    +

    Allocation of bit-fields within a class object is implementation-defined. Alignment of bit-fields is implementation-defined. Bit-fields are packed into some addressable allocation unit.

    -

    - Thus, padding bits may be present at any location within a class object instance (including at the beginning of the object, in the case of an unnamed bit-field as the first member declared in a class). Unless initialized by zero-initialization, padding bits contain - - indeterminate values - - that may contain sensitive information. -

    -

    - When passing a pointer to a class object instance across a - - trust boundary - - to a different trusted domain, the programmer must ensure that the padding bits of such an object do not contain sensitive information. -

    +

    Thus, padding bits may be present at any location within a class object instance (including at the beginning of the object, in the case of an unnamed bit-field as the first member declared in a class). Unless initialized by zero-initialization, padding bits contain indeterminate values that may contain sensitive information.

    +

    When passing a pointer to a class object instance across a trust boundary to a different trusted domain, the programmer must ensure that the padding bits of such an object do not contain sensitive information.

    -

    - This noncompliant code example runs in kernel space and copies data from - - arg - - to user space. However, padding bits may be used within the object, for example, to ensure the proper alignment of class data members. These padding bits may contain sensitive information that may then be leaked when the data is copied to user space, regardless of how the data is copied. -

    - - #include <cstddef> -  +

    This noncompliant code example runs in kernel space and copies data from arg to user space. However, padding bits may be used within the object, for example, to ensure the proper alignment of class data members. These padding bits may contain sensitive information that may then be leaked when the data is copied to user space, regardless of how the data is copied.

    + #include <cstddef> + struct test { int a; char b; int c; }; -  + // Safely copy bytes to user space extern int copy_to_user(void *dest, void *src, std::size_t size); -  + void do_stuff(void *usr_buf) { test arg{1, 2, 3}; copy_to_user(usr_buf, &arg, sizeof(arg)); -} - +}
    -

    - In this noncompliant code example, - - arg - - is value-initialized through direct initialization. Because - - test - - does not have a user-provided default constructor, the value-initialization is preceded by a zero-initialization that guarantees the padding bits are initialized to - - 0 - - before any further initialization occurs. It is akin to using - - std::memset() - - to initialize all of the bits in the object to - - 0 - - . -

    - - #include <cstddef> -  +

    In this noncompliant code example, arg is value-initialized through direct initialization. Because test does not have a user-provided default constructor, the value-initialization is preceded by a zero-initialization that guarantees the padding bits are initialized to 0 before any further initialization occurs. It is akin to using std::memset() to initialize all of the bits in the object to 0.

    + #include <cstddef> + struct test { int a; char b; int c; }; -  + // Safely copy bytes to user space extern int copy_to_user(void *dest, void *src, std::size_t size); -  + void do_stuff(void *usr_buf) { test arg{}; -  + arg.a = 1; arg.b = 2; arg.c = 3; -  + copy_to_user(usr_buf, &arg, sizeof(arg)); -} - -

    - However, compilers are free to implement - - arg.b = 2 - - by setting the low byte of a 32-bit register to - - 2 - - , leaving the high bytes unchanged, and storing all 32 bits of the register into memory. This could leak the high-order bytes resident in the register to a user. -

    +}
    +

    However, compilers are free to implement arg.b = 2 by setting the low byte of a 32-bit register to 2, leaving the high bytes unchanged, and storing all 32 bits of the register into memory. This could leak the high-order bytes resident in the register to a user.

    -

    - This compliant solution serializes the structure data before copying it to an untrusted context. -

    - - #include <cstddef> +

    This compliant solution serializes the structure data before copying it to an untrusted context.

    + #include <cstddef> #include <cstring> struct test { @@ -151,29 +82,19 @@ void do_stuff(void *usr_buf) { offset += sizeof(arg.c); copy_to_user(usr_buf, buf, offset /* size of info copied */); -} - -

    - This code ensures that no uninitialized padding bits are copied to unprivileged users. The structure copied to user space is now a packed structure and the - - copy_to_user() - - function would need to unpack it to recreate the original, padded structure. -

    +}
    +

    This code ensures that no uninitialized padding bits are copied to unprivileged users. The structure copied to user space is now a packed structure and the copy_to_user() function would need to unpack it to recreate the original, padded structure.

    -

    - Padding bits can be explicitly declared as fields within the structure. This solution is not portable, however, because it depends on the implementation and target memory architecture. The following solution is specific to the x86-32 architecture. -

    - - #include <cstddef> +

    Padding bits can be explicitly declared as fields within the structure. This solution is not portable, however, because it depends on the implementation and target memory architecture. The following solution is specific to the x86-32 architecture.

    + #include <cstddef> struct test { int a; char b; char padding_1, padding_2, padding_3; int c; -  + test(int a, char b, int c) : a(a), b(b), padding_1(0), padding_2(0), padding_3(0), c(c) {} @@ -193,60 +114,22 @@ extern int copy_to_user(void *dest, void *src, std::size_t size); void do_stuff(void *usr_buf) { test arg{1, 2, 3}; copy_to_user(usr_buf, &arg, sizeof(arg)); -} - -

    - The - - static_assert() - - declaration accepts a constant expression and an - - error message - - . The expression is evaluated at compile time and, if false, the compilation is terminated and the error message is used as the diagnostic. The explicit insertion of the padding bytes into the - - struct - - should ensure that no additional padding bytes are added by the compiler, and consequently both static assertions should be true. However, it is necessary to validate these assumptions to ensure that the solution is correct for a particular implementation. -

    +}
    +

    The static_assert() declaration accepts a constant expression and an error message. The expression is evaluated at compile time and, if false, the compilation is terminated and the error message is used as the diagnostic. The explicit insertion of the padding bytes into the struct should ensure that no additional padding bytes are added by the compiler, and consequently both static assertions should be true. However, it is necessary to validate these assumptions to ensure that the solution is correct for a particular implementation.

    -

    - In this noncompliant code example, padding bits may abound, including -

    +

    In this noncompliant code example, padding bits may abound, including

      -
    • - alignment padding bits after a virtual method table or virtual base class data to align a subsequent data member, -
    • -
    • - alignment padding bits to position a subsequent data member on a properly aligned boundary, -
    • -
    • - alignment padding bits to position data members of varying access control levels. -
    • -
    • - bit-field padding bits when the sequential set of bit-fields does not fill an entire allocation unit, -
    • -
    • - bit-field padding bits when two adjacent bit-fields are declared with different underlying types, -
    • -
    • - padding bits when a bit-field is declared with a length greater than the number of bits in the underlying allocation unit, or -
    • -
    • - padding bits to ensure a class instance will be appropriately aligned for use within an array. -
    • +
    • alignment padding bits after a virtual method table or virtual base class data to align a subsequent data member,
    • +
    • alignment padding bits to position a subsequent data member on a properly aligned boundary,
    • +
    • alignment padding bits to position data members of varying access control levels.
    • +
    • bit-field padding bits when the sequential set of bit-fields does not fill an entire allocation unit,
    • +
    • bit-field padding bits when two adjacent bit-fields are declared with different underlying types,
    • +
    • padding bits when a bit-field is declared with a length greater than the number of bits in the underlying allocation unit, or
    • +
    • padding bits to ensure a class instance will be appropriately aligned for use within an array.
    -

    - This code example runs in kernel space and copies data from - - arg - - to user space. However, the padding bits within the object instance may contain sensitive information that will then be leaked when the data is copied to user space. -

    - - #include <cstddef> +

    This code example runs in kernel space and copies data from arg to user space. However, the padding bits within the object instance may contain sensitive information that will then be leaked when the data is copied to user space.

    + #include <cstddef> class base { public: @@ -278,19 +161,8 @@ extern int copy_to_user(void *dest, void *src, std::size_t size); void do_stuff(void *usr_buf) { test arg{0.0, 1, 2, 3, 4, 5, 6, 7.0}; copy_to_user(usr_buf, &arg, sizeof(arg)); -} - -

    - Padding bits are implementation-defined, so the layout of the class object may differ between compilers or architectures. When compiled with - - GCC - - 5.3.0 for x86-32, the - - test - - object requires 96 bytes of storage to accommodate 29 bytes of data (33 bytes including the vtable) and has the following layout. -

    +}
    +

    Padding bits are implementation-defined, so the layout of the class object may differ between compilers or architectures. When compiled with GCC 5.3.0 for x86-32, the test object requires 96 bytes of storage to accommodate 29 bytes of data (33 bytes including the vtable) and has the following layout.

    @@ -334,9 +206,7 @@ void do_stuff(void *usr_buf) { 4 (32) @@ -358,9 +228,7 @@ void do_stuff(void *usr_buf) { 0 (4) @@ -371,9 +239,7 @@ void do_stuff(void *usr_buf) { 8 (64) @@ -384,9 +250,7 @@ void do_stuff(void *usr_buf) { 0 (3) @@ -397,9 +261,7 @@ void do_stuff(void *usr_buf) { 1 (8) @@ -433,9 +295,7 @@ void do_stuff(void *usr_buf) { 1 (8) @@ -446,9 +306,7 @@ void do_stuff(void *usr_buf) { 4 (32) @@ -481,9 +339,7 @@ void do_stuff(void *usr_buf) { 8 (64) @@ -512,11 +368,8 @@ void do_stuff(void *usr_buf) {
    - - unsigned k - + unsigned k
    - - unsigned l : 4 - + unsigned l : 4
    - - double h - + double h - - unsigned short m : 3 - + unsigned short m : 3
    - - char i - + char i - - char n - + char n
    - - unsigned j : 80 - + unsigned j : 80 - - double o - + double o
    -

    - Due to the complexity of the data structure, this compliant solution serializes the object data before copying it to an untrusted context instead of attempting to account for all of the padding bytes manually. -

    - - #include <cstddef> +

    Due to the complexity of the data structure, this compliant solution serializes the object data before copying it to an untrusted context instead of attempting to account for all of the padding bytes manually.

    + #include <cstddef> #include <cstring> class base { @@ -586,20 +439,11 @@ void do_stuff(void *usr_buf) { } else { // Handle error } -} - -

    - This code ensures that no uninitialized padding bits are copied to unprivileged users. The structure copied to user space is now a packed structure and the - - copy_to_user() - - function would need to unpack it to re-create the original, padded structure. -

    +}
    +

    This code ensures that no uninitialized padding bits are copied to unprivileged users. The structure copied to user space is now a packed structure and the copy_to_user() function would need to unpack it to re-create the original, padded structure.

    -

    - Padding bits might inadvertently contain sensitive data such as pointers to kernel data structures or passwords. A pointer to such a structure could be passed to other functions, causing information leakage. -

    +

    Padding bits might inadvertently contain sensitive data such as pointers to kernel data structures or passwords. A pointer to such a structure could be passed to other functions, causing information leakage.

    @@ -636,14 +480,10 @@ void do_stuff(void *usr_buf) { High @@ -676,9 +516,7 @@ void do_stuff(void *usr_buf) { 7.2.0 @@ -693,9 +531,7 @@ void do_stuff(void *usr_buf) { 2021.2 @@ -710,9 +546,7 @@ void do_stuff(void *usr_buf) { 2021.2
    - - P1 - + P1 - - L3 - + L3
    - - CertC++-DCL55 - + CertC++-DCL55 - - C++4941, C++4942, C++4943 - + C++4941, C++4942, C++4943 - - CERT_CPP-DCL55-a - + CERT_CPP-DCL55-a A pointer to a structure should not be passed to a function that can copy data to the user space @@ -722,61 +556,11 @@ void do_stuff(void *usr_buf) {
    -

    - Numerous vulnerabilities in the Linux Kernel have resulted from violations of this rule. -

    -

    - - CVE-2010-4083 - - describes a vulnerability - in which the - - semctl() - - system call allows unprivileged users to read uninitialized kernel stack memory because various fields of a - - semid_ds struct - - declared on the stack are not altered or zeroed before being copied back to the user. -

    -

    - - CVE-2010-3881 - - describes a vulnerability in which structure padding and reserved fields in certain data structures in - - QEMU-KVM - - were not initialized properly before being copied to user space. A privileged host user with access to - - /dev/kvm - - could use this - flaw - to leak kernel stack memory to user space. -

    -

    - - CVE-2010-3477 - - describes a kernel information leak in - - act_police - - where incorrectly initialized structures in the traffic-control dump code may allow the disclosure of kernel memory to user space applications. -

    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Numerous vulnerabilities in the Linux Kernel have resulted from violations of this rule.

    +

    CVE-2010-4083 describes a vulnerability in which the semctl() system call allows unprivileged users to read uninitialized kernel stack memory because various fields of a semid_ds struct declared on the stack are not altered or zeroed before being copied back to the user.

    +

    CVE-2010-3881 describes a vulnerability in which structure padding and reserved fields in certain data structures in QEMU-KVM were not initialized properly before being copied to user space. A privileged host user with access to /dev/kvm could use this flaw to leak kernel stack memory to user space.

    +

    CVE-2010-3477 describes a kernel information leak in act_police where incorrectly initialized structures in the traffic-control dump code may allow the disclosure of kernel memory to user space applications.

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/DCL56-CPP/CyclesDuringStaticObjectInit-standard.qhelp b/cpp/cert/src/rules/DCL56-CPP/CyclesDuringStaticObjectInit-standard.qhelp index d5737e0b1b..8fc2bf64eb 100644 --- a/cpp/cert/src/rules/DCL56-CPP/CyclesDuringStaticObjectInit-standard.qhelp +++ b/cpp/cert/src/rules/DCL56-CPP/CyclesDuringStaticObjectInit-standard.qhelp @@ -1,58 +1,21 @@
    -

    - The C++ Standard, [stmt.dcl], paragraph 4 - [ - - ISO/IEC 14882-2014 - - ] - , states the following: -

    +

    The C++ Standard, [stmt.dcl], paragraph 4 [ISO/IEC 14882-2014], states the following:

    -

    - The zero-initialization (8.5) of all block-scope variables with static storage duration (3.7.1) or thread storage duration (3.7.2) is performed before any other initialization takes place. Constant initialization (3.6.2) of a block-scope entity with static storage duration, if applicable, is performed before its block is first entered. An implementation is permitted to perform early initialization of other block-scope variables with static or thread storage duration under the same conditions that an implementation is permitted to statically initialize a variable with static or thread storage duration in namespace scope (3.6.2). Otherwise such a variable is initialized the first time control passes through its declaration; such a variable is considered initialized upon the completion of its initialization. If the initialization exits by throwing an exception, the initialization is not complete, so it will be tried again the next time control enters the declaration. If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization. If control re-enters the declaration recursively while the variable is being initialized, the behavior is undefined. -

    +

    The zero-initialization (8.5) of all block-scope variables with static storage duration (3.7.1) or thread storage duration (3.7.2) is performed before any other initialization takes place. Constant initialization (3.6.2) of a block-scope entity with static storage duration, if applicable, is performed before its block is first entered. An implementation is permitted to perform early initialization of other block-scope variables with static or thread storage duration under the same conditions that an implementation is permitted to statically initialize a variable with static or thread storage duration in namespace scope (3.6.2). Otherwise such a variable is initialized the first time control passes through its declaration; such a variable is considered initialized upon the completion of its initialization. If the initialization exits by throwing an exception, the initialization is not complete, so it will be tried again the next time control enters the declaration. If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization. If control re-enters the declaration recursively while the variable is being initialized, the behavior is undefined.

    -

    - Do not reenter a function during the initialization of a static variable declaration. If a function is reentered during the constant initialization of a static object inside that function, the behavior of the program is - - undefined - - . Infinite recursion is not required to trigger undefined behavior, the function need only recur once as part of the initialization. Due to thread-safe initialization of variables, a single, recursive call will often result in a - - deadlock - - due to locking a non-recursive synchronization primitive. -

    -

    - Additionally, the C++ Standard, [basic.start.init], paragraph 2, in part, states the following: -

    +

    Do not reenter a function during the initialization of a static variable declaration. If a function is reentered during the constant initialization of a static object inside that function, the behavior of the program is undefined. Infinite recursion is not required to trigger undefined behavior, the function need only recur once as part of the initialization. Due to thread-safe initialization of variables, a single, recursive call will often result in a deadlock due to locking a non-recursive synchronization primitive.

    +

    Additionally, the C++ Standard, [basic.start.init], paragraph 2, in part, states the following:

    -

    - Dynamic initialization of a non-local variable with static storage duration is either ordered or unordered. Definitions of explicitly specialized class template static data members have ordered initialization. Other class template static data members (i.e., implicitly or explicitly instantiated specializations) have unordered initialization. Other non-local variables with static storage duration have ordered initialization. Variables with ordered initialization defined within a single translation unit shall be initialized in the order of their definitions in the translation unit. If a program starts a thread, the subsequent initialization of a variable is unsequenced with respect to the initialization of a variable defined in a different translation unit. Otherwise, the initialization of a variable is indeterminately sequenced with respect to the initialization of a variable defined in a different translation unit. If a program starts a thread, the subsequent unordered initialization of a variable is unsequenced with respect to every other dynamic initialization. Otherwise, the unordered initialization of a variable is indeterminately sequenced with respect to every other dynamic initialization. -

    +

    Dynamic initialization of a non-local variable with static storage duration is either ordered or unordered. Definitions of explicitly specialized class template static data members have ordered initialization. Other class template static data members (i.e., implicitly or explicitly instantiated specializations) have unordered initialization. Other non-local variables with static storage duration have ordered initialization. Variables with ordered initialization defined within a single translation unit shall be initialized in the order of their definitions in the translation unit. If a program starts a thread, the subsequent initialization of a variable is unsequenced with respect to the initialization of a variable defined in a different translation unit. Otherwise, the initialization of a variable is indeterminately sequenced with respect to the initialization of a variable defined in a different translation unit. If a program starts a thread, the subsequent unordered initialization of a variable is unsequenced with respect to every other dynamic initialization. Otherwise, the unordered initialization of a variable is indeterminately sequenced with respect to every other dynamic initialization.

    -

    - Do not create an initialization interdependency between static objects with dynamic initialization unless they are ordered with respect to one another. Unordered initialization, especially prevalent across translation unit boundaries, results in - - unspecified behavior - - . -

    +

    Do not create an initialization interdependency between static objects with dynamic initialization unless they are ordered with respect to one another. Unordered initialization, especially prevalent across translation unit boundaries, results in unspecified behavior.

    -

    - This noncompliant example attempts to implement an efficient factorial function using caching. Because the initialization of the static local array - - cache - - involves recursion, the behavior of the function is undefined, even though the recursion is not infinite. -

    - - #include <stdexcept> -  +

    This noncompliant example attempts to implement an efficient factorial function using caching. Because the initialization of the static local array cache involves recursion, the behavior of the function is undefined, even though the recursion is not infinite.

    + #include <stdexcept> + int fact(int i) noexcept(false) { if (i < 0) { // Negative factorials are undefined. @@ -71,39 +34,14 @@ int fact(int i) noexcept(false) { return i > 0 ? i * fact(i - 1) : 1; } - -

    - - Implementation Details - -

    -

    - In - - Microsoft Visual Studio - - 2015 and - - GCC - - 6.1.0, the recursive initialization of - - cache - - deadlocks while initializing the static variable in a thread-safe manner. -

    +
    +

    Implementation Details

    +

    In Microsoft Visual Studio 2015 and GCC 6.1.0, the recursive initialization of cache deadlocks while initializing the static variable in a thread-safe manner.

    -

    - This compliant solution avoids initializing the static local array - - cache - - and instead relies on zero-initialization to determine whether each member of the array has been assigned a value yet and, if not, recursively computes its value. It then returns the cached value when possible or computes the value as needed. -

    - - #include <stdexcept> -  +

    This compliant solution avoids initializing the static local array cache and instead relies on zero-initialization to determine whether each member of the array has been assigned a value yet and, if not, recursively computes its value. It then returns the cached value when possible or computes the value as needed.

    + #include <stdexcept> + int fact(int i) noexcept(false) { if (i < 0) { // Negative factorials are undefined. @@ -118,163 +56,50 @@ int fact(int i) noexcept(false) { } return cache[i]; } -  + return i > 0 ? i * fact(i - 1) : 1; } - +
    -

    - In this noncompliant code example, the value of - - numWheels - - in - - file1.cpp - - relies on - - c - - being initialized. However, because - - c - - is defined in a different translation unit ( - - file2.cpp - - ) than - - numWheels - - , there is no guarantee that - - c - - will be initialized by calling - - get_default_car() - - before - - numWheels - - is initialized by calling - - c.get_num_wheels() - - . This is often referred to as the " - - static initialization order fiasco - - ," and the resulting behavior is unspecified. -

    - - // file.h +

    In this noncompliant code example, the value of numWheels in file1.cpp relies on c being initialized. However, because c is defined in a different translation unit (file2.cpp) than numWheels, there is no guarantee that c will be initialized by calling get_default_car() before numWheels is initialized by calling c.get_num_wheels(). This is often referred to as the "static initialization order fiasco," and the resulting behavior is unspecified.

    + // file.h #ifndef FILE_H #define FILE_H -  + class Car { int numWheels; -  + public: Car() : numWheels(4) {} explicit Car(int numWheels) : numWheels(numWheels) {} -  + int get_num_wheels() const { return numWheels; } }; #endif // FILE_H -  + // file1.cpp #include "file.h" #include <iostream> -  + extern Car c; int numWheels = c.get_num_wheels(); -  + int main() { std::cout << numWheels << std::endl; } -  + // file2.cpp #include "file.h" -  + Car get_default_car() { return Car(6); } -Car c = get_default_car(); - -

    - - Implementation Details - -

    -

    - The value printed to the standard output stream will often rely on the order in which the translation units are linked. For instance, with - - Clang - - 3.8.0 on x86 Linux, the command - - clang++ file1.cpp file2.cpp && ./a.out - - will write - - 0 - - while - - clang++ file2.cpp file1.cpp && ./a.out - - will write - - 6 - - . -

    +Car c = get_default_car();
    +

    Implementation Details

    +

    The value printed to the standard output stream will often rely on the order in which the translation units are linked. For instance, with Clang 3.8.0 on x86 Linux, the command clang++ file1.cpp file2.cpp && ./a.out will write 0 while clang++ file2.cpp file1.cpp && ./a.out will write 6.

    -

    - This compliant solution uses the "construct on first use" idiom to resolve the static initialization order issue. The code for - - file.h - - and - - file2.cpp - - are unchanged; only the static - - numWheels - - in - - file1.cpp - - is moved into the body of a function. Consequently, the initialization of - - numWheels - - is guaranteed to happen when control flows over the point of declaration, ensuring control over the order. The global object - - c - - is initialized before execution of - - main() - - begins, so by the time - - get_num_wheels() - - is called, - - c - - is guaranteed to have already been dynamically initialized. -

    - - // file.h +

    This compliant solution uses the "construct on first use" idiom to resolve the static initialization order issue. The code for file.h and file2.cpp are unchanged; only the static numWheels in file1.cpp is moved into the body of a function. Consequently, the initialization of numWheels is guaranteed to happen when control flows over the point of declaration, ensuring control over the order. The global object c is initialized before execution of main() begins, so by the time get_num_wheels() is called, c is guaranteed to have already been dynamically initialized.

    + // file.h #ifndef FILE_H #define FILE_H @@ -307,17 +132,10 @@ int main() { #include "file.h" Car get_default_car() { return Car(6); } -Car c = get_default_car(); - +Car c = get_default_car();
    -

    - Recursively reentering a function during the initialization of one of its static objects can result in an attacker being able to cause a crash or - - denial of service - - . Indeterminately ordered dynamic initialization can lead to undefined behavior due to accessing an uninitialized object. -

    +

    Recursively reentering a function during the initialization of one of its static objects can result in an attacker being able to cause a crash or denial of service. Indeterminately ordered dynamic initialization can lead to undefined behavior due to accessing an uninitialized object.

    @@ -354,14 +172,10 @@ Car c = get_default_car(); Medium @@ -384,6 +198,24 @@ Car c = get_default_car(); Description + + + + + + @@ -410,9 +240,7 @@ Car c = get_default_car();
    - - P2 - + P2 - - L3 - + L3
    + + CodeSonar + + + 6.2p0 + + LANG.STRUCT.INIT.CYCLE + LANG.STRUCT.INIT.UNORDERED + + Initialization Cycle + Unordered Initialization +
    @@ -394,9 +226,7 @@ Car c = get_default_car(); 2021.2 - - C++1552, C++1554, C++1704 - + C++1552, C++1554, C++1704 - - 6 D - + 6 D Enhanced Enforcement @@ -428,9 +256,7 @@ Car c = get_default_car(); 2021.2 - - CERT_CPP-DCL56-a - + CERT_CPP-DCL56-a Avoid initialization order problems across translation units by replacing non-local static objects with local static objects @@ -440,17 +266,7 @@ Car c = get_default_car();
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/DCL57-CPP/DoNotLetExceptionsEscapeFromDestructorsOrDeallocationFunctions-standard.qhelp b/cpp/cert/src/rules/DCL57-CPP/DoNotLetExceptionsEscapeFromDestructorsOrDeallocationFunctions-standard.qhelp index d5f3ddb61a..9af0a14d9e 100644 --- a/cpp/cert/src/rules/DCL57-CPP/DoNotLetExceptionsEscapeFromDestructorsOrDeallocationFunctions-standard.qhelp +++ b/cpp/cert/src/rules/DCL57-CPP/DoNotLetExceptionsEscapeFromDestructorsOrDeallocationFunctions-standard.qhelp @@ -1,146 +1,31 @@
    -

    - Under certain circumstances, terminating a destructor, - - operator delete - - , or - - operator delete[] - - by throwing an exception can trigger - - undefined behavior - - . -

    -

    - For instance, the C++ Standard, [basic.stc.dynamic.deallocation], paragraph 3 [ - - ISO/IEC 14882-2014 - - ], in part, states the following: -

    +

    Under certain circumstances, terminating a destructor, operator delete, or operator delete[] by throwing an exception can trigger undefined behavior.

    +

    For instance, the C++ Standard, [basic.stc.dynamic.deallocation], paragraph 3 [ISO/IEC 14882-2014], in part, states the following:

    -

    - If a deallocation function terminates by throwing an exception, the behavior is undefined. -

    +

    If a deallocation function terminates by throwing an exception, the behavior is undefined.

    -

    - In these situations, the function must logically be declared - - noexcept - - because throwing an exception from the function can never have well-defined behavior. The C++ Standard, [except.spec], paragraph 15, states the following: -

    +

    In these situations, the function must logically be declared noexcept because throwing an exception from the function can never have well-defined behavior. The C++ Standard, [except.spec], paragraph 15, states the following:

    -

    - A deallocation function with no explicit exception-specification is treated as if it were specified with noexcept(true). -

    +

    A deallocation function with no explicit exception-specification is treated as if it were specified with noexcept(true).

    -

    - As such, deallocation functions (object, array, and placement forms at either global or class scope) must not terminate by throwing an exception. Do not declare such functions to be - - noexcept(false) - - . However, it is acceptable to rely on the implicit - - noexcept(true) - - specification or declare - - noexcept - - explicitly on the function signature. -

    -

    - Object destructors are likely to be called during stack unwinding as a result of an exception being thrown. If the destructor itself throws an exception, having been called as the result of an exception being thrown, then the function - - std::terminate() - - is called with the default effect of calling - - std::abort() - - [ - - ISO/IEC 14882-2014 - - ] - . - When - - std::abort() - - is called, no further objects are destroyed, resulting in an indeterminate program state and undefined behavior. Do not terminate a destructor by throwing an exception. -

    -

    - The C++ Standard, [class.dtor], paragraph 3, states [ - - ISO/IEC 14882-2014 - - ] the following: -

    +

    As such, deallocation functions (object, array, and placement forms at either global or class scope) must not terminate by throwing an exception. Do not declare such functions to be noexcept(false). However, it is acceptable to rely on the implicit noexcept(true) specification or declare noexcept explicitly on the function signature.

    +

    Object destructors are likely to be called during stack unwinding as a result of an exception being thrown. If the destructor itself throws an exception, having been called as the result of an exception being thrown, then the function std::terminate() is called with the default effect of calling std::abort() [ISO/IEC 14882-2014]. When std::abort() is called, no further objects are destroyed, resulting in an indeterminate program state and undefined behavior. Do not terminate a destructor by throwing an exception.

    +

    The C++ Standard, [class.dtor], paragraph 3, states [ISO/IEC 14882-2014] the following:

    -

    - A declaration of a destructor that does not have an exception-specification is implicitly considered to have the same exception-specification as an implicit declaration. -

    +

    A declaration of a destructor that does not have an exception-specification is implicitly considered to have the same exception-specification as an implicit declaration.

    -

    - An implicit declaration of a destructor is considered to be - - noexcept(true) - - according to [except.spec], paragraph 14. As such, destructors must not be declared - - noexcept(false) - - but may instead rely on the implicit - - noexcept(true) - - or declare - - noexcept - - explicitly. -

    -

    - Any - - noexcept - - function that terminates by throwing an exception violates - - ERR55-CPP. Honor exception specifications - - . -

    +

    An implicit declaration of a destructor is considered to be noexcept(true) according to [except.spec], paragraph 14. As such, destructors must not be declared noexcept(false) but may instead rely on the implicit noexcept(true) or declare noexcept explicitly.

    +

    Any noexcept function that terminates by throwing an exception violates ERR55-CPP. Honor exception specifications.

    -

    - In this noncompliant code example, the class destructor does not meet the implicit - - noexcept - - guarantee because it may throw an exception even if it was called as the result of an exception being thrown. Consequently, it is declared as - - noexcept(false) - - but still can trigger - - undefined behavior - - . -

    - - #include <stdexcept> -  +

    In this noncompliant code example, the class destructor does not meet the implicit noexcept guarantee because it may throw an exception even if it was called as the result of an exception being thrown. Consequently, it is declared as noexcept(false) but still can trigger undefined behavior.

    + #include <stdexcept> + class S { bool has_error() const; -  + public: ~S() noexcept(false) { // Normal processing @@ -148,19 +33,11 @@ public: throw std::logic_error("Something bad"); } } -}; - +};
    -

    - Use of - - std::uncaught_exception() - - in the destructor solves the termination problem by avoiding the propagation of the exception if an existing exception is being processed, as demonstrated in this noncompliant code example. However, by circumventing normal destructor processing, this approach may keep the destructor from releasing important resources. -

    - - #include <exception> +

    Use of std::uncaught_exception() in the destructor solves the termination problem by avoiding the propagation of the exception if an existing exception is being processed, as demonstrated in this noncompliant code example. However, by circumventing normal destructor processing, this approach may keep the destructor from releasing important resources.

    + #include <exception> #include <stdexcept> class S { @@ -173,41 +50,18 @@ public: throw std::logic_error("Something bad"); } } -}; - +};
    -

    - This noncompliant code example, as well as the following compliant solution, presumes the existence of a - - Bad - - class with a destructor that can throw. Although the class violates this rule, it is presumed that the class cannot be modified to comply with this rule. -

    - - // Assume that this class is provided by a 3rd party and it is not something +

    This noncompliant code example, as well as the following compliant solution, presumes the existence of a Bad class with a destructor that can throw. Although the class violates this rule, it is presumed that the class cannot be modified to comply with this rule.

    + // Assume that this class is provided by a 3rd party and it is not something // that can be modified by the user. class Bad { ~Bad() noexcept(false); }; - -

    - To safely use the - - Bad - - class, the - - SomeClass - - destructor attempts to handle exceptions thrown from the - - Bad - - destructor by absorbing them. -

    - - class SomeClass { + +

    To safely use the Bad class, the SomeClass destructor attempts to handle exceptions thrown from the Bad destructor by absorbing them.

    + class SomeClass { Bad bad_member; public: ~SomeClass() @@ -217,61 +71,16 @@ public: // Handle the exception thrown from the Bad destructor. } }; - -

    - However, the C++ Standard, [except.handle], paragraph 15 [ - - ISO/IEC 14882-2014 - - ], in part, states the following: -

    +
    +

    However, the C++ Standard, [except.handle], paragraph 15 [ISO/IEC 14882-2014], in part, states the following:

    -

    - The currently handled exception is rethrown if control reaches the end of a handler of the function-try-block of a constructor or destructor. -

    +

    The currently handled exception is rethrown if control reaches the end of a handler of the function-try-block of a constructor or destructor.

    -

    - Consequently, the caught exception will inevitably escape from the - - SomeClass - - destructor because it is implicitly rethrown when control reaches the end of the - - function-try-block - - handler. -

    +

    Consequently, the caught exception will inevitably escape from the SomeClass destructor because it is implicitly rethrown when control reaches the end of the function-try-block handler.

    -

    - A destructor should perform the same way whether or not there is an active exception. Typically, this means that it should invoke only operations that do not throw exceptions, or it should handle all exceptions and not rethrow them (even implicitly). This compliant solution differs from the previous noncompliant code example by having an explicit - - return - - statement in the - - SomeClass - - destructor. This statement prevents control from reaching the end of the exception handler. Consequently, this handler will catch the exception thrown by - - Bad::~Bad() - - when - - bad_member - - is destroyed. It will also catch any exceptions thrown within the compound statement of the - - function-try-block - - , but the - - SomeClass - - destructor will not terminate by throwing an exception. -

    - - class SomeClass { +

    A destructor should perform the same way whether or not there is an active exception. Typically, this means that it should invoke only operations that do not throw exceptions, or it should handle all exceptions and not rethrow them (even implicitly). This compliant solution differs from the previous noncompliant code example by having an explicit return statement in the SomeClass destructor. This statement prevents control from reaching the end of the exception handler. Consequently, this handler will catch the exception thrown by Bad::~Bad() when bad_member is destroyed. It will also catch any exceptions thrown within the compound statement of the function-try-block, but the SomeClass destructor will not terminate by throwing an exception.

    + class SomeClass { Bad bad_member; public: ~SomeClass() @@ -286,39 +95,23 @@ public: // return statement will prevent that from happening. return; } -}; - +};
    -

    - In this noncompliant code example, a global deallocation is declared - - noexcept(false) - - and throws an exception if some conditions are not properly met. However, throwing from a deallocation function results in - - undefined behavior - - . -

    - - #include <stdexcept> -  +

    In this noncompliant code example, a global deallocation is declared noexcept(false) and throws an exception if some conditions are not properly met. However, throwing from a deallocation function results in undefined behavior.

    + #include <stdexcept> + bool perform_dealloc(void *); -  + void operator delete(void *ptr) noexcept(false) { if (perform_dealloc(ptr)) { throw std::logic_error("Something bad"); } -} - +}
    -

    - The compliant solution does not throw exceptions in the event the deallocation fails but instead fails as gracefully as possible. -

    - - #include <cstdlib> +

    The compliant solution does not throw exceptions in the event the deallocation fails but instead fails as gracefully as possible.

    + #include <cstdlib> #include <stdexcept> bool perform_dealloc(void *); @@ -329,17 +122,10 @@ void operator delete(void *ptr) noexcept(true) { log_failure("Deallocation of pointer failed"); std::exit(1); // Fail, but still call destructors } -} - +}
    -

    - Attempting to throw exceptions from destructors or deallocation functions can result in undefined behavior, leading to resource leaks or - - denial-of-service attacks - - . -

    +

    Attempting to throw exceptions from destructors or deallocation functions can result in undefined behavior, leading to resource leaks or denial-of-service attacks.

    @@ -376,14 +162,10 @@ void operator delete(void *ptr) noexcept(true) { Medium @@ -416,10 +198,7 @@ void operator delete(void *ptr) noexcept(true) { 20.10 @@ -452,9 +229,7 @@ void operator delete(void *ptr) noexcept(true) { 2021.2 @@ -469,9 +244,7 @@ void operator delete(void *ptr) noexcept(true) { 2021.4 @@ -485,9 +258,7 @@ void operator delete(void *ptr) noexcept(true) { @@ -566,12 +325,8 @@ void operator delete(void *ptr) noexcept(true) { 20.10
    - - P6 - + P6 - - L2 - + L2
    - - destructor-without-noexcept - delete-without-noexcept - + destructor-without-noexceptdelete-without-noexcept Fully checked @@ -435,9 +214,7 @@ void operator delete(void *ptr) noexcept(true) { 7.2.0 - - CertC++-DCL57 - + CertC++-DCL57 - - C++2045, C++2047, C++4032, C++4631 - + C++2045, C++2047, C++4032, C++4631 - - MISRA.DTOR.THROW - + MISRA.DTOR.THROW - - 453 S - + 453 S Partially implemented @@ -503,12 +274,8 @@ void operator delete(void *ptr) noexcept(true) { 2021.2 - - CERT_CPP-DCL57-a - - - CERT_CPP-DCL57-b - + CERT_CPP-DCL57-a + CERT_CPP-DCL57-b Never allow an exception to be thrown from a destructor, deallocation, and swap @@ -540,18 +307,10 @@ void operator delete(void *ptr) noexcept(true) { - 7.16 + 7.17 - - - V509 - - , - - V1045 - - + V509, V1045 - - destructor-without-noexcept - - - delete-without-noexcept - + destructor-without-noexcept + delete-without-noexcept Fully checked @@ -581,17 +336,7 @@ void operator delete(void *ptr) noexcept(true) {
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    @@ -676,9 +421,7 @@ void operator delete(void *ptr) noexcept(true) { diff --git a/cpp/cert/src/rules/DCL58-CPP/ModificationOfTheStandardNamespaces-standard.qhelp b/cpp/cert/src/rules/DCL58-CPP/ModificationOfTheStandardNamespaces-standard.qhelp index 8b30845686..c2fd4c9a7a 100644 --- a/cpp/cert/src/rules/DCL58-CPP/ModificationOfTheStandardNamespaces-standard.qhelp +++ b/cpp/cert/src/rules/DCL58-CPP/ModificationOfTheStandardNamespaces-standard.qhelp @@ -1,229 +1,48 @@
    -

    - Namespaces introduce new declarative regions for declarations, reducing the likelihood of conflicting identifiers with other declarative regions. One feature of namespaces is that they can be further extended, even within separate translation units. For instance, the following declarations are well-formed. -

    - - namespace MyNamespace { +

    Namespaces introduce new declarative regions for declarations, reducing the likelihood of conflicting identifiers with other declarative regions. One feature of namespaces is that they can be further extended, even within separate translation units. For instance, the following declarations are well-formed.

    + namespace MyNamespace { int length; } -  + namespace MyNamespace { int width; } -  + void f() { MyNamespace::length = MyNamespace::width = 12; -} - -

    - The standard library introduces the namespace - - std - - for standards-provided declarations such as - - std::string - - , - - std::vector - - , and - - std::for_each - - . However, it is - - undefined behavior - - to introduce new declarations in namespace - - std - - except under special circumstances. The C++ Standard, [namespace.std], paragraphs 1 and 2 [ - - ISO/IEC 14882-2014 - - ], states the following: -

    +}
    +

    The standard library introduces the namespace std for standards-provided declarations such as std::string, std::vector, and std::for_each. However, it is undefined behavior to introduce new declarations in namespace std except under special circumstances. The C++ Standard, [namespace.std], paragraphs 1 and 2 [ISO/IEC 14882-2014], states the following:

    -

    - - 1 - - The behavior of a C++ program is undefined if it adds declarations or definitions to namespace - - std - - or to a namespace within namespace - - std - - unless otherwise specified. A program may add a template specialization for any standard library template to namespace - - std - - only if the declaration depends on a user-defined type and the specialization meets the standard library requirements for the original template and is not explicitly prohibited. -

    -

    - - 2 - - The behavior of a C++ program is undefined if it declares -

    -

    - — an explicit specialization of any member function of a standard library class template, or - — an explicit specialization of any member function template of a standard library class or class template, or - — an explicit or partial specialization of any member class template of a standard library class or class template. -

    +

    1 The behavior of a C++ program is undefined if it adds declarations or definitions to namespace std or to a namespace within namespace std unless otherwise specified. A program may add a template specialization for any standard library template to namespace std only if the declaration depends on a user-defined type and the specialization meets the standard library requirements for the original template and is not explicitly prohibited.

    +

    2 The behavior of a C++ program is undefined if it declares

    +

    — an explicit specialization of any member function of a standard library class template, or— an explicit specialization of any member function template of a standard library class or class template, or— an explicit or partial specialization of any member class template of a standard library class or class template.

    -

    - In addition to restricting extensions to the the namespace - - std - - , the C++ Standard, [namespace.posix], paragraph 1, further states the following: -

    +

    In addition to restricting extensions to the the namespace std, the C++ Standard, [namespace.posix], paragraph 1, further states the following:

    -

    - The behavior of a C++ program is undefined if it adds declarations or definitions to namespace - - posix - - or to a namespace within namespace - - posix - - unless otherwise specified. The namespace - - posix - - is reserved for use by ISO/IEC 9945 and other POSIX standards. -

    +

    The behavior of a C++ program is undefined if it adds declarations or definitions to namespace posix or to a namespace within namespace posix unless otherwise specified. The namespace posix is reserved for use by ISO/IEC 9945 and other POSIX standards.

    -

    - Do not add declarations or definitions to the standard namespaces - - std - - or - - posix - - , or to a namespace contained therein, except for a template specialization that depends on a user-defined type that meets the standard library requirements for the original template. -

    -

    - The Library Working Group, responsible for the wording of the Standard Library section of the C++ Standard, has an unresolved - - issue - - on the definition of - - user-defined type - - . Although the Library Working Group has no official stance on the definition [ - - INCITS 2014 - - ], we define it to be any - - class - - , - - struct - - , - - union - - , or - - enum - - that is not defined within namespace - - std - - or a namespace contained within namespace - - std - - . Effectively, it is a user-provided type instead of a standard library–provided type. -

    +

    Do not add declarations or definitions to the standard namespaces std or posix, or to a namespace contained therein, except for a template specialization that depends on a user-defined type that meets the standard library requirements for the original template.

    +

    The Library Working Group, responsible for the wording of the Standard Library section of the C++ Standard, has an unresolved issue on the definition of user-defined type. Although the Library Working Group has no official stance on the definition [INCITS 2014], we define it to be any class, struct, union, or enum that is not defined within namespace std or a namespace contained within namespace std. Effectively, it is a user-provided type instead of a standard library–provided type.

    -

    - In this noncompliant code example, the declaration of - - x - - is added to the namespace - - std - - , resulting in - - undefined behavior - - . -

    - - namespace std { +

    In this noncompliant code example, the declaration of x is added to the namespace std, resulting in undefined behavior.

    + namespace std { int x; } - +
    -

    - This compliant solution assumes the intention of the programmer was to place the declaration of - - x - - into a namespace to prevent collisions with other global identifiers. Instead of placing the declaration into the namespace - - std - - , the declaration is placed into a namespace without a reserved name. -

    - - namespace nonstd { +

    This compliant solution assumes the intention of the programmer was to place the declaration of x into a namespace to prevent collisions with other global identifiers. Instead of placing the declaration into the namespace std, the declaration is placed into a namespace without a reserved name.

    + namespace nonstd { int x; } - +
    -

    - In this noncompliant code example, a template specialization of - - std::plus - - is added to the namespace - - std - - in an attempt to allow - - std::plus - - to concatenate a - - std::string - - and - - MyString - - object. However, because the template specialization is of a standard library–provided type ( - - std::string - - ), this code results in undefined behavior. -

    - - #include <functional> +

    In this noncompliant code example, a template specialization of std::plus is added to the namespace std in an attempt to allow std::plus to concatenate a std::string and MyString object. However, because the template specialization is of a standard library–provided type (std::string), this code results in undefined behavior.

    + #include <functional> #include <iostream> #include <string> @@ -252,38 +71,11 @@ void f() { std::cout << p(s1, s2) << std::endl; } - +
    -

    - The interface for - - std::plus - - requires that both arguments to the function call operator and the return type are of the same type. Because the attempted specialization in the noncompliant code example results in - - undefined behavior - - , this compliant solution defines a new - - std::binary_function - - derivative that can add a - - std::string - - to a - - MyString - - object without requiring modification of the namespace - - std - - . -

    - - #include <functional> +

    The interface for std::plus requires that both arguments to the function call operator and the return type are of the same type. Because the attempted specialization in the noncompliant code example results in undefined behavior, this compliant solution defines a new std::binary_function derivative that can add a std::string to a MyString object without requiring modification of the namespace std.

    + #include <functional> #include <iostream> #include <string> @@ -308,31 +100,11 @@ void f() { my_plus p; std::cout << p(s1, s2) << std::endl; -} - +}
    -

    - In this compliant solution, a specialization of - - std::plus - - is added to the - - std - - namespace, but the specialization depends on a user-defined type and meets the Standard Template Library requirements for the original template, so it complies with this rule. However, because - - MyString - - can be constructed from - - std::string - - , this compliant solution involves invoking a converting constructor whereas the previous compliant solution does not. -

    - - #include <functional> +

    In this compliant solution, a specialization of std::plus is added to the std namespace, but the specialization depends on a user-defined type and meets the Standard Template Library requirements for the original template, so it complies with this rule. However, because MyString can be constructed from std::string, this compliant solution involves invoking a converting constructor whereas the previous compliant solution does not.

    + #include <functional> #include <iostream> #include <string> @@ -360,17 +132,10 @@ void f() { std::plus<MyString> p; std::cout << p(s1, s2).get_data() << std::endl; -} - +}
    -

    - Altering the standard namespace can cause - - undefined behavior - - in the C++ standard library. -

    +

    Altering the standard namespace can cause undefined behavior in the C++ standard library.

    "Never allow exceptions from escaping destructors or from an overloaded - - operator delete() - + operator delete() " (p. 29)
    @@ -407,14 +172,10 @@ void f() { Medium @@ -447,9 +208,7 @@ void f() { 7.2.0 @@ -464,9 +223,7 @@ void f() { 2021.2 @@ -481,11 +238,7 @@ void f() { 2021.4 @@ -500,9 +253,7 @@ void f() { 2021.2 @@ -553,14 +299,10 @@ void f() { @@ -575,11 +317,7 @@ void f() { 4.10 @@ -588,17 +326,7 @@ void f() {
    - - P6 - + P6 - - L2 - + L2
    - - CertC++-DCL58 - + CertC++-DCL58 - - C++3180, C++3181, C++3182 - + C++3180, C++3181, C++3182 - - - CERT.DCL.STD_NS_MODIFIED - - + CERT.DCL.STD_NS_MODIFIED - - CERT_CPP-DCL58-a - + CERT_CPP-DCL58-a Do not modify the standard namespaces 'std' and 'posix' @@ -536,12 +287,7 @@ void f() { 4.4 - - 4032, 4035, - - 4631 - - + 4032, 4035, 4631 - 7.16 + 7.17 - - - V1061 - - + V1061 - - - S3470 - - + S3470
    -

    - Search for other - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for other vulnerabilities resulting from the violation of this rule on the CERT website.

    @@ -647,14 +375,10 @@ void f() { diff --git a/cpp/cert/src/rules/DCL59-CPP/UnnamedNamespaceInHeaderFile-standard.qhelp b/cpp/cert/src/rules/DCL59-CPP/UnnamedNamespaceInHeaderFile-standard.qhelp index 66798590f1..ef3567af38 100644 --- a/cpp/cert/src/rules/DCL59-CPP/UnnamedNamespaceInHeaderFile-standard.qhelp +++ b/cpp/cert/src/rules/DCL59-CPP/UnnamedNamespaceInHeaderFile-standard.qhelp @@ -1,136 +1,61 @@
    -

    - Unnamed namespaces are used to define a namespace that is unique to the translation unit, where the names contained within have internal linkage by default. The C++ Standard, [namespace.unnamed], paragraph 1 [ - - ISO/IEC 14882-2014 - - ], states the following: -

    +

    Unnamed namespaces are used to define a namespace that is unique to the translation unit, where the names contained within have internal linkage by default. The C++ Standard, [namespace.unnamed], paragraph 1 [ISO/IEC 14882-2014], states the following:

    -

    - An - - unnamed-namespace-definition - - behaves as if it were replaced by: -

    -
      inline namespace unique { /* empty body */ }  using namespace unique ;  namespace unique { namespace-body }
    -

    - where - - inline - - appears if and only if it appears in the - - unnamed-namespace-definition - - , all occurrences of - - unique - - in a translation unit are replaced by the same identifier, and this identifier differs from all other identifiers in the entire program. -

    +

    An unnamed-namespace-definition behaves as if it were replaced by:

    +
      inline namespace unique { /* empty body */ }  using namespace unique ;  namespace unique { namespace-body }
    +

    where inline appears if and only if it appears in the unnamed-namespace-definition, all occurrences of unique in a translation unit are replaced by the same identifier, and this identifier differs from all other identifiers in the entire program.

    -

    - Production-quality C++ code frequently uses - - header files - - as a means to share code between translation units. A header file is any file that is inserted into a translation unit through an - - #include - - directive. Do not define an unnamed namespace in a header file. When an unnamed namespace is defined in a header file, it can lead to surprising results. Due to default internal linkage, each translation unit will define its own unique instance of members of the unnamed namespace that are - - ODR-used - - within that translation unit. This can cause unexpected results, bloat the resulting executable, or inadvertently trigger - - undefined behavior - - due to one-definition rule (ODR) violations. -

    +

    Production-quality C++ code frequently uses header files as a means to share code between translation units. A header file is any file that is inserted into a translation unit through an #include directive. Do not define an unnamed namespace in a header file. When an unnamed namespace is defined in a header file, it can lead to surprising results. Due to default internal linkage, each translation unit will define its own unique instance of members of the unnamed namespace that are ODR-used within that translation unit. This can cause unexpected results, bloat the resulting executable, or inadvertently trigger undefined behavior due to one-definition rule (ODR) violations.

    -

    - In this noncompliant code example, the variable - - v - - is defined in an unnamed namespace within a header file and is accessed from two separate translation units. Each translation unit prints the current value of - - v - - and then assigns a new value into it. However, because - - v - - is defined within an unnamed namespace, each translation unit operates on its own instance of - - v - - , resulting in unexpected output. -

    - - // a.h +

    In this noncompliant code example, the variable v is defined in an unnamed namespace within a header file and is accessed from two separate translation units. Each translation unit prints the current value of v and then assigns a new value into it. However, because v is defined within an unnamed namespace, each translation unit operates on its own instance of v, resulting in unexpected output.

    + // a.h #ifndef A_HEADER_FILE #define A_HEADER_FILE -  + namespace { int v; } -  + #endif // A_HEADER_FILE -  + // a.cpp #include "a.h" #include <iostream> -  + void f() { std::cout << "f(): " << v << std::endl; v = 42; // ... } -  + // b.cpp #include "a.h" #include <iostream> -  + void g() { std::cout << "g(): " << v << std::endl; v = 100; } -  + int main() { extern void f(); f(); // Prints v, sets it to 42 g(); // Prints v, sets it to 100 f(); g(); -} - -

    - When executed, this program prints the following. -

    - - f(): 0 +} +

    When executed, this program prints the following.

    + f(): 0 g(): 0 f(): 42 -g(): 100 - +g(): 100
    -

    - In this compliant solution, - - v - - is defined in only one translation unit but is externally visible to all translation units, resulting in the expected behavior. -

    - - // a.h +

    In this compliant solution, v is defined in only one translation unit but is externally visible to all translation units, resulting in the expected behavior.

    + // a.h #ifndef A_HEADER_FILE #define A_HEADER_FILE @@ -165,104 +90,50 @@ int main() { g(); // Prints v, sets it to 100 f(); // Prints v, sets it back to 42 g(); // Prints v, sets it back to 100 -} - -

    - When executed, this program prints the following. -

    - - f(): 0 +} +

    When executed, this program prints the following.

    + f(): 0 g(): 42 f(): 100 -g(): 42 - +g(): 42
    -

    - In this noncompliant code example, the variable - - v - - is defined in an unnamed namespace within a header file, and an inline function, - - get_v() - - , is defined, which accesses that variable. ODR-using the inline function from multiple translation units (as shown in the implementation of - - f() - - and - - g() - - ) violates the - - one-definition rule - - because the definition of - - get_v() - - is not identical in all translation units due to referencing a unique - - v - - in each translation unit. -

    - - // a.h +

    In this noncompliant code example, the variable v is defined in an unnamed namespace within a header file, and an inline function, get_v(), is defined, which accesses that variable. ODR-using the inline function from multiple translation units (as shown in the implementation of f() and g()) violates the one-definition rule because the definition of get_v() is not identical in all translation units due to referencing a unique v in each translation unit.

    + // a.h #ifndef A_HEADER_FILE #define A_HEADER_FILE -  + namespace { int v; } -  + inline int get_v() { return v; } -  + #endif // A_HEADER_FILE -  + // a.cpp #include "a.h" -  + void f() { int i = get_v(); // ... } -  + // b.cpp #include "a.h" -  + void g() { int i = get_v(); // ... -} - -

    - See - - DCL60-CPP. Obey the one-definition rule - - for more information on violations of the one-definition rule. -

    +}
    +

    See DCL60-CPP. Obey the one-definition rule for more information on violations of the one-definition rule.

    -

    - In this compliant solution, - - v - - is defined in only one translation unit but is externally visible to all translation units and can be accessed from the inline - - get_v() - - function. -

    - - // a.h +

    In this compliant solution, v is defined in only one translation unit but is externally visible to all translation units and can be accessed from the inline get_v() function.

    + // a.h #ifndef A_HEADER_FILE #define A_HEADER_FILE -  + extern int v; inline int get_v() { @@ -273,7 +144,7 @@ inline int get_v() { // a.cpp #include "a.h" -  + // Externally used by get_v(); int v; @@ -288,85 +159,49 @@ void f() { void g() { int i = get_v(); // ... -} - +}
    -

    - In this noncompliant code example, the function - - f() - - is defined within a header file. However, including the header file in multiple translation units causes a violation of the one-definition rule that usually results in an error diagnostic generated at link time due to multiple definitions of a function with the same name. -

    - - // a.h +

    In this noncompliant code example, the function f() is defined within a header file. However, including the header file in multiple translation units causes a violation of the one-definition rule that usually results in an error diagnostic generated at link time due to multiple definitions of a function with the same name.

    + // a.h #ifndef A_HEADER_FILE #define A_HEADER_FILE -  + void f() { /* ... */ } -  + #endif // A_HEADER_FILE -  + // a.cpp #include "a.h" // ... -  + // b.cpp #include "a.h" -// ... - +// ...
    -

    - This noncompliant code example attempts to resolve the link-time errors by defining - - f() - - within an unnamed namespace. However, it produces multiple, unique definitions of - - f() - - in the resulting executable. If - - a.h - - is included from many translation units, it can lead to increased link times, a larger executable file, and reduced performance. -

    - - // a.h +

    This noncompliant code example attempts to resolve the link-time errors by defining f() within an unnamed namespace. However, it produces multiple, unique definitions of f() in the resulting executable. If a.h is included from many translation units, it can lead to increased link times, a larger executable file, and reduced performance.

    + // a.h #ifndef A_HEADER_FILE #define A_HEADER_FILE -  -namespace {  + +namespace { void f() { /* ... */ } } -  + #endif // A_HEADER_FILE -  + // a.cpp #include "a.h" // ... -  + // b.cpp #include "a.h" -// ... - +// ...
    -

    - In this compliant solution, - - f() - - is not defined with an unnamed namespace and is instead defined as an inline function. Inline functions are required to be defined identically in all the translation units in which they are used, which allows an - - implementation - - to generate only a single instance of the function at runtime in the event the body of the function does not get generated for each call site. -

    - - // a.h +

    In this compliant solution, f() is not defined with an unnamed namespace and is instead defined as an inline function. Inline functions are required to be defined identically in all the translation units in which they are used, which allows an implementation to generate only a single instance of the function at runtime in the event the body of the function does not get generated for each call site.

    + // a.h #ifndef A_HEADER_FILE #define A_HEADER_FILE @@ -380,17 +215,10 @@ inline void f() { /* ... */ } // b.cpp #include "a.h" -// ... - +// ...
    -

    - Defining an unnamed namespace within a header file can cause data integrity violations and performance problems but is unlikely to go unnoticed with sufficient testing. One-definition rule violations result in - - undefined behavior - - . -

    +

    Defining an unnamed namespace within a header file can cause data integrity violations and performance problems but is unlikely to go unnoticed with sufficient testing. One-definition rule violations result in undefined behavior.

    Subclause 17.6.4.2.1, "Namespace - - std - + std " Subclause 17.6.4.2.2, "Namespace - - posix - + posix "
    @@ -427,20 +255,16 @@ inline void f() { /* ... */ } Medium
    - - P4 - + P4 - - L3 - + L3
    -
    +
    @@ -467,9 +291,7 @@ inline void f() { /* ... */ } 20.10 @@ -502,15 +322,27 @@ inline void f() { /* ... */ } 3.9 + + + + + + @@ -523,9 +355,7 @@ inline void f() { /* ... */ } 2021.2 @@ -540,9 +370,7 @@ inline void f() { /* ... */ } 2021.4 @@ -556,9 +384,7 @@ inline void f() { /* ... */ } @@ -647,9 +465,7 @@ inline void f() { /* ... */ } 4.4 @@ -661,14 +477,10 @@ inline void f() { /* ... */ } @@ -677,17 +489,7 @@ inline void f() { /* ... */ }
    - - unnamed-namespace-header - + unnamed-namespace-header Fully checked @@ -485,9 +307,7 @@ inline void f() { /* ... */ } 7.2.0 - - CertC++-DCL59 - + CertC++-DCL59 - - cert-dcl59-cpp - + cert-dcl59-cpp Checked by - - clang-tidy - + clang-tidy +
    + + CodeSonar + + + 6.2p0 + + LANG.STRUCT.DECL.ANH + + Anonymous Namespace in Header File
    - - C++2518 - + C++2518 - - MISRA.NAMESPACE.UNMD - + MISRA.NAMESPACE.UNMD - - 286 S, 512 S - + 286 S, 512 S Fully implemented @@ -574,9 +400,7 @@ inline void f() { /* ... */ } 2021.2 - - CERT_CPP-DCL59-a - + CERT_CPP-DCL59-a There shall be no unnamed namespaces in header files @@ -610,9 +434,7 @@ inline void f() { /* ... */ } 20.10 - - unnamed-namespace-header - + unnamed-namespace-header Fully checked @@ -628,11 +450,7 @@ inline void f() { /* ... */ } 4.10 - - - UnnamedNamespaceInHeader - - + UnnamedNamespaceInHeader - - 2518 - + 2518 - 7.16 + 7.17 - - - V1068 - - + V1068
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/DCL60-CPP/OneDefinitionRuleNotObeyed-standard.qhelp b/cpp/cert/src/rules/DCL60-CPP/OneDefinitionRuleNotObeyed-standard.qhelp index 2bf3183369..dec783194e 100644 --- a/cpp/cert/src/rules/DCL60-CPP/OneDefinitionRuleNotObeyed-standard.qhelp +++ b/cpp/cert/src/rules/DCL60-CPP/OneDefinitionRuleNotObeyed-standard.qhelp @@ -1,125 +1,46 @@
    -

    - Nontrivial C++ programs are generally divided into multiple translation units that are later linked together to form an executable. To support such a model, C++ restricts named object definitions to ensure that linking will behave deterministically by requiring a single definition for an object across all translation units. This model is called the o - - ne-definition rule - - (ODR), which is defined by the C++ Standard, [basic.def.odr], in paragraph 4 [ - - ISO/IEC 14882-2014 - - ]: -

    -

    - Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program; no diagnostic required. The definition can appear explicitly in the program, it can be found in the standard or a user-defined library, or (when appropriate) it is implicitly-defined. An inline function shall be defined in every translation unit in which it is odr-used. -

    -

    - The most common approach to multitranslation unit compilation involves declarations residing in a header file that is subsequently made available to a source file via - - #include - - . These declarations are often also definitions, such as class and function template definitions. This approach is allowed by an exception defined in paragraph 6, which, in part, states the following: -

    +

    Nontrivial C++ programs are generally divided into multiple translation units that are later linked together to form an executable. To support such a model, C++ restricts named object definitions to ensure that linking will behave deterministically by requiring a single definition for an object across all translation units. This model is called the one-definition rule (ODR), which is defined by the C++ Standard, [basic.def.odr], in paragraph 4 [ISO/IEC 14882-2014]:

    +

    Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program; no diagnostic required. The definition can appear explicitly in the program, it can be found in the standard or a user-defined library, or (when appropriate) it is implicitly-defined. An inline function shall be defined in every translation unit in which it is odr-used.

    +

    The most common approach to multitranslation unit compilation involves declarations residing in a header file that is subsequently made available to a source file via #include. These declarations are often also definitions, such as class and function template definitions. This approach is allowed by an exception defined in paragraph 6, which, in part, states the following:

    -

    - There can be more than one definition of a class type, enumeration type, inline function with external linkage, class template, non-static function template, static data member of a class template, member function of a class template, or template specialization for which some template parameters are not specified in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements. Given such an entity named - - D - - defined in more than one translation unit.... -

    -

    - If the definitions of - - D - - satisfy all these requirements, then the program shall behave as if there were a single definition of - - D - - . If the definitions of - - D - - do not satisfy these requirements, then the behavior is undefined. -

    +

    There can be more than one definition of a class type, enumeration type, inline function with external linkage, class template, non-static function template, static data member of a class template, member function of a class template, or template specialization for which some template parameters are not specified in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements. Given such an entity named D defined in more than one translation unit....

    +

    If the definitions of D satisfy all these requirements, then the program shall behave as if there were a single definition of D. If the definitions of D do not satisfy these requirements, then the behavior is undefined.

    -

    - The requirements specified by paragraph 6 essentially state that that two definitions must be identical (not simply equivalent). Consequently, a definition introduced in two separate translation units by an - - #include - - directive generally will not violate the ODR because the definitions are identical in both translation units. -

    -

    - However, it is possible to violate the ODR of a definition introduced via - - #include - - using block language linkage specifications, vendor-specific language extensions, and so on. A more likely scenario for ODR violations is that accidental definitions of differing objects will exist in different translation units. -

    -

    - Do not violate the one-definition rule; violations result in - - undefined behavior - - . -

    +

    The requirements specified by paragraph 6 essentially state that that two definitions must be identical (not simply equivalent). Consequently, a definition introduced in two separate translation units by an #include directive generally will not violate the ODR because the definitions are identical in both translation units.

    +

    However, it is possible to violate the ODR of a definition introduced via #include using block language linkage specifications, vendor-specific language extensions, and so on. A more likely scenario for ODR violations is that accidental definitions of differing objects will exist in different translation units.

    +

    Do not violate the one-definition rule; violations result in undefined behavior.

    -

    - In this noncompliant code example, two different translation units define a class of the same name with differing definitions. Although the two definitions are functionally equivalent (they both define a class named - - S - - with a single, public, nonstatic data member - - int a - - ), they are not defined using the same sequence of tokens. This code example violates the ODR and results in - - undefined behavior - - . -

    - - // a.cpp +

    In this noncompliant code example, two different translation units define a class of the same name with differing definitions. Although the two definitions are functionally equivalent (they both define a class named S with a single, public, nonstatic data member int a), they are not defined using the same sequence of tokens. This code example violates the ODR and results in undefined behavior.

    + // a.cpp struct S { int a; }; -  + // b.cpp class S { public: int a; -}; - +};
    -

    - The correct mitigation depends on programmer intent. If the programmer intends for the same class definition to be visible in both translation units because of common usage, the solution is to use a header file to introduce the object into both translation units, as shown in this compliant solution. -

    - - // S.h +

    The correct mitigation depends on programmer intent. If the programmer intends for the same class definition to be visible in both translation units because of common usage, the solution is to use a header file to introduce the object into both translation units, as shown in this compliant solution.

    + // S.h struct S { int a; }; -  + // a.cpp #include "S.h" // b.cpp -#include "S.h" - +#include "S.h"
    -

    - If the ODR violation was a result of accidental name collision, the best mitigation solution is to ensure that both class definitions are unique, as in this compliant solution. -

    - - // a.cpp +

    If the ODR violation was a result of accidental name collision, the best mitigation solution is to ensure that both class definitions are unique, as in this compliant solution.

    + // a.cpp namespace { struct S { int a; @@ -132,136 +53,43 @@ class S { public: int a; }; -} - -

    - Alternatively, the classes could be given distinct names in each translation unit to avoid violating the ODR. -

    +}
    +

    Alternatively, the classes could be given distinct names in each translation unit to avoid violating the ODR.

    -

    - In this noncompliant code example, a class definition is introduced into two translation units using - - #include - - . However, one of the translation units uses an - - implementation-defined - - - #pragma - - that is supported by Microsoft Visual Studio to specify structure field alignment requirements. Consequently, the two class definitions may have differing layouts in each translation unit, which is a violation of the ODR. -

    - - // s.h +

    In this noncompliant code example, a class definition is introduced into two translation units using #include. However, one of the translation units uses an implementation-defined #pragma that is supported by Microsoft Visual Studio to specify structure field alignment requirements. Consequently, the two class definitions may have differing layouts in each translation unit, which is a violation of the ODR.

    + // s.h struct S { char c; int a; }; -  + void init_s(S &s); -  + // s.cpp #include "s.h" -  + void init_s(S &s); { s.c = 'a'; s.a = 12; } -  + // a.cpp #pragma pack(push, 1) #include "s.h" #pragma pack(pop) -  + void f() { S s; init_s(s); -} - -

    - - Implementation Details - -

    -

    - It is possible for the preceding noncompliant code example to result in - - a.cpp - - allocating space for an object with a different size than expected by - - init_s() - - in - - s.cpp - - . When translating - - s.cpp - - , the layout of the structure may include padding bytes between the - - c - - and - - a - - data members. When translating - - a.cpp - - , the layout of the structure may remove those padding bytes as a result of the - - #pragma pack - - directive, so the object passed to - - init_s() - - may be smaller than expected. Consequently, when - - init_s() - - initializes the data members of - - s - - , it may result in a buffer overrun. -

    -

    - For more information on the behavior of - - #pragma pack - - , see the vendor documentation for your - - implementation - - , such as - - Microsoft Visual Studio - - or - - GCC - - . -

    +}
    +

    Implementation Details

    +

    It is possible for the preceding noncompliant code example to result in a.cpp allocating space for an object with a different size than expected by init_s() in s.cpp. When translating s.cpp, the layout of the structure may include padding bytes between the c and a data members. When translating a.cpp, the layout of the structure may remove those padding bytes as a result of the #pragma pack directive, so the object passed to init_s() may be smaller than expected. Consequently, when init_s() initializes the data members of s, it may result in a buffer overrun.

    +

    For more information on the behavior of #pragma pack, see the vendor documentation for your implementation, such as Microsoft Visual Studio or GCC.

    -

    - In this compliant solution, the implementation-defined structure member-alignment directive is removed, ensuring that all definitions of - - S - - comply with the ODR. -

    - - // s.h +

    In this compliant solution, the implementation-defined structure member-alignment directive is removed, ensuring that all definitions of S comply with the ODR.

    + // s.h struct S { char c; int a; @@ -283,146 +111,32 @@ void init_s(S &s); { void f() { S s; init_s(s); -} - +}
    -

    - In this noncompliant code example, the constant object - - n - - has internal linkage but is - - odr-used - - within - - f() - - , which has external linkage. Because - - f() - - is declared as an inline function, the definition of - - f() - - must be identical in all translation units. However, each translation unit has a unique instance of - - n - - , resulting in a violation of the ODR. -

    - - const int n = 42; -  +

    In this noncompliant code example, the constant object n has internal linkage but is odr-used within f(), which has external linkage. Because f() is declared as an inline function, the definition of f() must be identical in all translation units. However, each translation unit has a unique instance of n, resulting in a violation of the ODR.

    + const int n = 42; + int g(const int &lhs, const int &rhs); inline int f(int k) { return g(k, n); -} - +}
    -

    - A compliant solution must change one of three factors: (1) it must not odr-use - - n - - within - - f() - - , (2) it must declare - - n - - such that it has external linkage, or (3) it must not use an inline definition of - - f() - - . -

    -

    - If circumstances allow modification of the signature of - - g() - - to accept parameters by value instead of by reference, then - - n - - will not be odr-used within - - f() - - because - - n - - would then qualify as a constant expression. This solution is compliant but it is not ideal. It may not be possible (or desirable) to modify the signature of - - g(), - - such as if - - g() - - represented - - std::max() - - from - - <algorithm> - - . Also, because of the differing linkage used by - - n - - and - - f() - - , accidental violations of the ODR are still likely if the definition of - - f() - - is modified to odr-use - - n - - . -

    - - const int n = 42; -  +

    A compliant solution must change one of three factors: (1) it must not odr-use n within f(), (2) it must declare n such that it has external linkage, or (3) it must not use an inline definition of f().

    +

    If circumstances allow modification of the signature of g() to accept parameters by value instead of by reference, then n will not be odr-used within f() because n would then qualify as a constant expression. This solution is compliant but it is not ideal. It may not be possible (or desirable) to modify the signature of g(), such as if g() represented std::max() from <algorithm>. Also, because of the differing linkage used by n and f(), accidental violations of the ODR are still likely if the definition of f() is modified to odr-use n.

    + const int n = 42; + int g(int lhs, int rhs); inline int f(int k) { return g(k, n); -} - +}
    -

    - In this compliant solution, the constant object - - n - - is replaced with an enumerator of the same name. Named enumerations defined at namespace scope have the same linkage as the namespace they are contained in. The global namespace has external linkage, so the definition of the named enumeration and its contained enumerators also have external linkage. Although less aesthetically pleasing, this compliant solution does not suffer from the same maintenance burdens of the previous code because - - n - - and - - f() - - have the same linkage. -

    - - enum Constants { +

    In this compliant solution, the constant object n is replaced with an enumerator of the same name. Named enumerations defined at namespace scope have the same linkage as the namespace they are contained in. The global namespace has external linkage, so the definition of the named enumeration and its contained enumerators also have external linkage. Although less aesthetically pleasing, this compliant solution does not suffer from the same maintenance burdens of the previous code because n and f() have the same linkage.

    + enum Constants { N = 42 }; @@ -430,32 +144,10 @@ int g(const int &lhs, const int &rhs); inline int f(int k) { return g(k, N); -} - +}
    -

    - Violating the ODR causes - - undefined behavior - - , which can result in exploits as well as - - denial-of-service attacks - - . As shown in "Support for Whole-Program Analysis and the Verification of the One-Definition Rule in C++" [ - - Quinlan 06 - - ], failing to enforce the ODR enables a virtual function pointer attack known as the - - VPTR - - exploit - - - . In this exploit, an object's virtual function table is corrupted so that calling a virtual function on the object results in malicious code being executed. See the paper by Quinlan and colleagues for more details. However, note that to introduce the malicious class, the attacker must have access to the system building the code. -

    +

    Violating the ODR causes undefined behavior, which can result in exploits as well as denial-of-service attacks. As shown in "Support for Whole-Program Analysis and the Verification of the One-Definition Rule in C++" [Quinlan 06], failing to enforce the ODR enables a virtual function pointer attack known as the VPTR exploit. In this exploit, an object's virtual function table is corrupted so that calling a virtual function on the object results in malicious code being executed. See the paper by Quinlan and colleagues for more details. However, note that to introduce the malicious class, the attacker must have access to the system building the code.

    @@ -492,14 +184,10 @@ inline int f(int k) { High @@ -532,14 +220,7 @@ inline int f(int k) { 20.10 @@ -569,13 +248,10 @@ inline int f(int k) { @@ -608,9 +282,7 @@ inline int f(int k) {
    - - P3 - + P3 - - L3 - + L3
    - - type-compatibility - definition-duplicate - undefined-extern - undefined-extern-pure-virtual - external-file-spreading - type-file-spreading - + type-compatibilitydefinition-duplicateundefined-externundefined-extern-pure-virtualexternal-file-spreadingtype-file-spreading Partially checked @@ -555,9 +236,7 @@ inline int f(int k) { 7.2.0 - - CertC++-DCL60 - + CertC++-DCL60 - 6.1p0 + 6.2p0 - - LANG.STRUCT.DEF.FDH - LANG.STRUCT.DEF.ODH - + LANG.STRUCT.DEF.FDHLANG.STRUCT.DEF.ODH Function defined in header file @@ -592,9 +268,7 @@ inline int f(int k) { 2021.2 - - C++1067, C++1509, C++1510 - + C++1067, C++1509, C++1510 - - 286 S, 287 S - + 286 S, 287 S Fully implemented @@ -626,9 +298,7 @@ inline int f(int k) { 2021.2 - - CERT_CPP-DCL60-a - + CERT_CPP-DCL60-a A class, union or enum name (including qualification, if any) shall be a unique identifier @@ -662,24 +332,12 @@ inline int f(int k) { 20.10 - - type-compatibility - - - definition-duplicate - - - undefined-extern - - - undefined-extern-pure-virtual - - - external-file-spreading - - - type-file-spreading - + type-compatibility + definition-duplicate + undefined-extern + undefined-extern-pure-virtual + external-file-spreading + type-file-spreading Partially checked @@ -689,17 +347,7 @@ inline int f(int k) {
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/ERR50-CPP/ConditionVariablePostConditionFailedCert-standard.qhelp b/cpp/cert/src/rules/ERR50-CPP/ConditionVariablePostConditionFailedCert-standard.qhelp index ddb56f87a3..cdcf65adda 100644 --- a/cpp/cert/src/rules/ERR50-CPP/ConditionVariablePostConditionFailedCert-standard.qhelp +++ b/cpp/cert/src/rules/ERR50-CPP/ConditionVariablePostConditionFailedCert-standard.qhelp @@ -1,381 +1,57 @@
    -

    - The - - std::abort() - - , - - std::quick_exit() - - , and - - std::_Exit() - - functions are used to terminate the program in an immediate fashion. They do so without calling exit handlers registered with - - std::atexit() - - and without executing destructors for objects with automatic, thread, or static storage duration. How a system manages open streams when a program ends is - - implementation-defined - - [ - - ISO/IEC 9899:1999 - - ]. Open streams with unwritten buffered data may or may not be flushed, open streams may or may not be closed, and temporary files may or may not be removed. Because these functions can leave external resources, such as files and network communications, in an indeterminate state, they should be called explicitly only in direct response to a critical error in the application. (See ERR50-CPP-EX1 for more information.) -

    -

    - The - - std::terminate() - - function calls the current - - terminate_handler - - function, which defaults to calling - - std::abort() - - . -

    -

    - The C++ Standard defines several ways in which - - std::terminate() - - may be called implicitly by an - - implementation - - [ - - ISO/IEC 14882-2014 - - ]: -

    +

    The std::abort(), std::quick_exit(), and std::_Exit() functions are used to terminate the program in an immediate fashion. They do so without calling exit handlers registered with std::atexit() and without executing destructors for objects with automatic, thread, or static storage duration. How a system manages open streams when a program ends is implementation-defined [ISO/IEC 9899:1999]. Open streams with unwritten buffered data may or may not be flushed, open streams may or may not be closed, and temporary files may or may not be removed. Because these functions can leave external resources, such as files and network communications, in an indeterminate state, they should be called explicitly only in direct response to a critical error in the application. (See ERR50-CPP-EX1 for more information.)

    +

    The std::terminate() function calls the current terminate_handler function, which defaults to calling std::abort().

    +

    The C++ Standard defines several ways in which std::terminate() may be called implicitly by an implementation [ISO/IEC 14882-2014]:

      -
    1. - When the exception handling mechanism, after completing the initialization of the exception object but before activation of a handler for the exception, calls a function that exits via an exception ([except.throw], paragraph 7) - See - - ERR60-CPP. Exception objects must be nothrow copy constructible - - for more information. -
    2. -
    3. - When a - - throw-expression - - with no operand attempts to rethrow an exception and no exception is being handled ([except.throw], paragraph 9) -
    4. -
    5. - When the exception handling mechanism cannot find a handler for a thrown exception ([except.handle], paragraph 9) - See - - ERR51-CPP. Handle all exceptions - - for more information. -
    6. -
    7. - When the search for a handler encounters the outermost block of a function with a - - noexcept-specification - - that does not allow the exception ([except.spec], paragraph 9) - See - - ERR55-CPP. Honor exception specifications - - for more information. -
    8. -
    9. - When the destruction of an object during stack unwinding terminates by throwing an exception ([except.ctor], paragraph 3) - See - - DCL57-CPP. Do not let exceptions escape from destructors or deallocation functions - - for more information. -
    10. -
    11. - When initialization of a nonlocal variable with static or thread storage duration exits via an exception ([basic.start.init], paragraph 6) - See - - ERR58-CPP. Handle all exceptions thrown before main() begins executing - - for more information. -
    12. -
    13. - When destruction of an object with static or thread storage duration exits via an exception ([basic.start.term], paragraph 1) - See - - DCL57-CPP. Do not let exceptions escape from destructors or deallocation functions - - for more information. -
    14. -
    15. - When execution of a function registered with - - std::atexit() - - or - - std::at_quick_exit() - - exits via an exception ([support.start.term], paragraphs 8 and 12) -
    16. -
    17. - When the implementation’s default unexpected exception handler is called ([except.unexpected], paragraph 2) - Note that - - std::unexpected() - - is currently deprecated. -
    18. -
    19. - When - - std::unexpected() - - throws an exception that is not allowed by the previously violated - - dynamic-exception-specification - - , and - - std::bad_exception() - - is not included in that - - dynamic-exception-specification - - ([except.unexpected], paragraph 3) -
    20. -
    21. - When the function - - std::nested_exception::rethrow_nested() - - is called for an object that has captured no exception ([except.nested], paragraph 4) -
    22. -
    23. - When execution of the initial function of a thread exits via an exception ([thread.thread.constr], paragraph 5) - See - - ERR51-CPP. Handle all exceptions - - for more information. -
    24. -
    25. - When the destructor is invoked on an object of type - - std::thread - - that refers to a joinable thread ([thread.thread.destr], paragraph 1) -
    26. -
    27. - When the copy assignment operator is invoked on an object of type - - std::thread - - that refers to a joinable thread ([thread.thread.assign], paragraph 1) -
    28. -
    29. - When calling - - condition_variable::wait() - - , - - condition_variable::wait_until() - - , or - - condition_variable::wait_for() - - results in a failure to meet the postcondition: - - lock.owns_lock() == true - - or - - lock.mutex() - - is not locked by the calling thread ([thread.condition.condvar], paragraphs 11, 16, 21, 28, 33, and 40) -
    30. -
    31. - When calling - - condition_variable_any::wait() - - , - - condition_variable_any::wait_until() - - , or - - condition_variable_any::wait_for() - - results in a failure to meet the postcondition: - - lock - - is not locked by the calling thread ([thread.condition.condvarany], paragraphs 11, 16, and 22) -
    32. +
    33. When the exception handling mechanism, after completing the initialization of the exception object but before activation of a handler for the exception, calls a function that exits via an exception ([except.throw], paragraph 7)See ERR60-CPP. Exception objects must be nothrow copy constructible for more information.
    34. +
    35. When a throw-expression with no operand attempts to rethrow an exception and no exception is being handled ([except.throw], paragraph 9)
    36. +
    37. When the exception handling mechanism cannot find a handler for a thrown exception ([except.handle], paragraph 9)See ERR51-CPP. Handle all exceptions for more information.
    38. +
    39. When the search for a handler encounters the outermost block of a function with a noexcept-specification that does not allow the exception ([except.spec], paragraph 9)See ERR55-CPP. Honor exception specifications for more information.
    40. +
    41. When the destruction of an object during stack unwinding terminates by throwing an exception ([except.ctor], paragraph 3)See DCL57-CPP. Do not let exceptions escape from destructors or deallocation functions for more information.
    42. +
    43. When initialization of a nonlocal variable with static or thread storage duration exits via an exception ([basic.start.init], paragraph 6)See ERR58-CPP. Handle all exceptions thrown before main() begins executing for more information.
    44. +
    45. When destruction of an object with static or thread storage duration exits via an exception ([basic.start.term], paragraph 1)See DCL57-CPP. Do not let exceptions escape from destructors or deallocation functions for more information.
    46. +
    47. When execution of a function registered with std::atexit()or std::at_quick_exit() exits via an exception ([support.start.term], paragraphs 8 and 12)
    48. +
    49. When the implementation’s default unexpected exception handler is called ([except.unexpected], paragraph 2) Note that std::unexpected() is currently deprecated.
    50. +
    51. When std::unexpected() throws an exception that is not allowed by the previously violated dynamic-exception-specification, and std::bad_exception() is not included in that dynamic-exception-specification ([except.unexpected], paragraph 3)
    52. +
    53. When the function std::nested_exception::rethrow_nested() is called for an object that has captured no exception ([except.nested], paragraph 4)
    54. +
    55. When execution of the initial function of a thread exits via an exception ([thread.thread.constr], paragraph 5)See ERR51-CPP. Handle all exceptions for more information.
    56. +
    57. When the destructor is invoked on an object of type std::thread that refers to a joinable thread ([thread.thread.destr], paragraph 1)
    58. +
    59. When the copy assignment operator is invoked on an object of type std::thread that refers to a joinable thread ([thread.thread.assign], paragraph 1)
    60. +
    61. When calling condition_variable::wait(), condition_variable::wait_until(), or condition_variable::wait_for() results in a failure to meet the postcondition: lock.owns_lock() == true or lock.mutex() is not locked by the calling thread ([thread.condition.condvar], paragraphs 11, 16, 21, 28, 33, and 40)
    62. +
    63. When calling condition_variable_any::wait(), condition_variable_any::wait_until(), or condition_variable_any::wait_for() results in a failure to meet the postcondition: lock is not locked by the calling thread ([thread.condition.condvarany], paragraphs 11, 16, and 22)
    -

    - In many circumstances, the call stack will not be unwound in response to an implicit call to - - std::terminate() - - , and in a few cases, it is implementation-defined whether or not stack unwinding will occur. The C++ Standard, [except.terminate], paragraph 2 [ - - ISO/IEC 14882-2014 - - ], in part, states the following: -

    +

    In many circumstances, the call stack will not be unwound in response to an implicit call to std::terminate(), and in a few cases, it is implementation-defined whether or not stack unwinding will occur. The C++ Standard, [except.terminate], paragraph 2 [ISO/IEC 14882-2014], in part, states the following:

    -

    - In the situation where no matching handler is found, it is implementation-defined whether or not the stack is unwound before - - std::terminate() - - is called. In the situation where the search for a handler encounters the outermost block of a function with a - - noexcept-specification - - that does not allow the exception, it is implementation-defined whether the stack is unwound, unwound partially, or not unwound at all before - - std::terminate() - - is called. In all other situations, the stack shall not be unwound before - - std::terminate() - - is called. -

    +

    In the situation where no matching handler is found, it is implementation-defined whether or not the stack is unwound before std::terminate() is called. In the situation where the search for a handler encounters the outermost block of a function with a noexcept-specification that does not allow the exception, it is implementation-defined whether the stack is unwound, unwound partially, or not unwound at all before std::terminate() is called. In all other situations, the stack shall not be unwound before std::terminate() is called.

    -

    - Do not explicitly or implicitly call - - std::quick_exit() - - , - - std::abort() - - , or - - std::_Exit() - - . When the default - - terminate_handler - - is installed or the current - - terminate_handler - - responds by calling - - std::abort() - - or - - std::_Exit() - - , do not explicitly or implicitly call - - std::terminate() - - . - - Abnormal process termination - - is the typical vector for - - denial-of-service attacks - - . -

    -

    - The - - std::exit() - - function is more complex. The C++ Standard, - [basic.start.main], paragraph 4, states: -

    +

    Do not explicitly or implicitly call std::quick_exit(), std::abort(), or std::_Exit(). When the default terminate_handler is installed or the current terminate_handler responds by calling std::abort() or std::_Exit(), do not explicitly or implicitly call std::terminate(). Abnormal process termination is the typical vector for denial-of-service attacks.

    +

    The std::exit() function is more complex. The C++ Standard, [basic.start.main], paragraph 4, states:

    -

    - Terminating the program without leaving the current block (e.g., by calling the function std::exit(int) (17.5)) does not destroy any objects with automatic storage duration (11.4.6). If std::exit is called to end a program during the destruction of an object with static or thread storage duration, the program has undefined behavior. -

    +

    Terminating the program without leaving the current block (e.g., by calling the function std::exit(int) (17.5)) does not destroy any objects with automatic storage duration (11.4.6). If std::exit is called to end a program during the destruction of an object with static or thread storage duration, the program has undefined behavior.

    -

    - You may call - - std::exit() - - only in a program that has not yet initialized any objects with automatic storage duration. -

    -

    - Noncompliant Code Example -

    -

    - In this noncompliant code example, the call to - - f() - - , which was registered as an exit handler with - - std::at_exit() - - , may result in a call to - - std::terminate() - - because - - throwing_func() - - may throw an exception. -

    - - #include <cstdlib> -  +

    You may call std::exit() only in a program that has not yet initialized any objects with automatic storage duration.

    +

    Noncompliant Code Example

    +

    In this noncompliant code example, the call to f(), which was registered as an exit handler with std::at_exit(), may result in a call to std::terminate() because throwing_func() may throw an exception.

    + #include <cstdlib> + void throwing_func() noexcept(false); -  + void f() { // Not invoked by the program except as an exit handler. throwing_func(); } -  + int main() { if (0 != std::atexit(f)) { // Handle error } // ... -} - +}
    -

    - In this compliant solution, - - f() - - handles all exceptions thrown by - - throwing_func() - - and does not rethrow. -

    - - #include <cstdlib> +

    In this compliant solution, f() handles all exceptions thrown by throwing_func() and does not rethrow.

    + #include <cstdlib> void throwing_func() noexcept(false); @@ -392,78 +68,34 @@ int main() { // Handle error } // ... -} - +}
    -

    - - ERR50-CPP-EX1: - - It is acceptable, after indicating the nature of the problem to the operator, to explicitly call - - std::abort() - - , - - std::_Exit() - - , or - - std::terminate() - - in response to a critical program error for which no recovery is possible, as in this example. -

    - - #include <exception> +

    ERR50-CPP-EX1: It is acceptable, after indicating the nature of the problem to the operator, to explicitly call std::abort(), std::_Exit(), or std::terminate() in response to a critical program error for which no recovery is possible, as in this example.

    + #include <exception> void report(const char *msg) noexcept; [[noreturn]] void fast_fail(const char *msg) { // Report error message to operator report(msg); -  + // Terminate std::terminate(); } -  + void critical_function_that_fails() noexcept(false); -  + void f() { try { critical_function_that_fails(); } catch (...) { fast_fail("Critical function failure"); } -} - -

    - The - - assert() - - macro is permissible under this exception because failed assertions will notify the operator on the standard error stream in an - - implementation-defined - - manner before calling - - std::abort() - - . -

    +}
    +

    The assert() macro is permissible under this exception because failed assertions will notify the operator on the standard error stream in an implementation-defined manner before calling std::abort().

    -

    - Allowing the application to - - abnormally terminate - - can lead to resources not being freed, closed, and so on. It is frequently a vector for - - denial-of-service attacks - - . -

    +

    Allowing the application to abnormally terminate can lead to resources not being freed, closed, and so on. It is frequently a vector for denial-of-service attacks.

    @@ -500,14 +132,10 @@ void f() { Medium @@ -540,9 +168,7 @@ void f() { 20.10 @@ -595,12 +216,8 @@ void f() { 2021.4 @@ -614,9 +231,7 @@ void f() { @@ -732,18 +318,10 @@ void f() { @@ -758,9 +336,7 @@ void f() { 20.10 @@ -789,17 +361,7 @@ void f() {
    - - P4 - + P4 - - L3 - + L3
    - - stdlib-use - + stdlib-use Partially checked @@ -555,13 +181,10 @@ void f() { - 6.1p0 + 6.2p0 - - BADFUNC.ABORT - BADFUNC.EXIT - + BADFUNC.ABORTBADFUNC.EXIT Use of abort @@ -578,9 +201,7 @@ void f() { 2021.2 - - C++5014 - + C++5014 - - MISRA.TERMINATE - - - CERT.ERR.ABRUPT_TERM - + MISRA.TERMINATE + CERT.ERR.ABRUPT_TERM - - 122 S - + 122 S Enhanced Enforcement @@ -632,46 +247,19 @@ void f() { 2021.2 - - CERT_CPP-ERR50-a - - - CERT_CPP-ERR50-b - - - CERT_CPP-ERR50-c - - - CERT_CPP-ERR50-d - - - CERT_CPP-ERR50-e - - - CERT_CPP-ERR50-f - - - CERT_CPP-ERR50-g - - - CERT_CPP-ERR50-h - - - CERT_CPP-ERR50-i - - - CERT_CPP-ERR50-j - - - CERT_CPP-ERR50-k - - - CERT_CPP-ERR50-l - - - CERT_CPP-ERR50-m - CERT_CPP-ERR50-n - + CERT_CPP-ERR50-a + CERT_CPP-ERR50-b + CERT_CPP-ERR50-c + CERT_CPP-ERR50-d + CERT_CPP-ERR50-e + CERT_CPP-ERR50-f + CERT_CPP-ERR50-g + CERT_CPP-ERR50-h + CERT_CPP-ERR50-i + CERT_CPP-ERR50-j + CERT_CPP-ERR50-k + CERT_CPP-ERR50-l + CERT_CPP-ERR50-mCERT_CPP-ERR50-n The execution of a function registered with 'std::atexit()' or 'std::at_quick_exit()' should not exit via an exception @@ -718,9 +306,7 @@ void f() { 4.4 - - 5014 - + 5014 - 7.16 + 7.17 - - - V667 - - , - - V2014 - - + V667, V2014 - - stdlib-use - + stdlib-use Partially checked @@ -776,11 +352,7 @@ void f() { 4.10 - - - S990 - - + S990
    -

    - Search for other - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for other vulnerabilities resulting from the violation of this rule on the CERT website.

    @@ -851,14 +413,10 @@ void f() { @@ -872,9 +430,7 @@ void f() { diff --git a/cpp/cert/src/rules/ERR50-CPP/ExitHandlerThrowsExceptionCert-standard.qhelp b/cpp/cert/src/rules/ERR50-CPP/ExitHandlerThrowsExceptionCert-standard.qhelp index ddb56f87a3..cdcf65adda 100644 --- a/cpp/cert/src/rules/ERR50-CPP/ExitHandlerThrowsExceptionCert-standard.qhelp +++ b/cpp/cert/src/rules/ERR50-CPP/ExitHandlerThrowsExceptionCert-standard.qhelp @@ -1,381 +1,57 @@
    -

    - The - - std::abort() - - , - - std::quick_exit() - - , and - - std::_Exit() - - functions are used to terminate the program in an immediate fashion. They do so without calling exit handlers registered with - - std::atexit() - - and without executing destructors for objects with automatic, thread, or static storage duration. How a system manages open streams when a program ends is - - implementation-defined - - [ - - ISO/IEC 9899:1999 - - ]. Open streams with unwritten buffered data may or may not be flushed, open streams may or may not be closed, and temporary files may or may not be removed. Because these functions can leave external resources, such as files and network communications, in an indeterminate state, they should be called explicitly only in direct response to a critical error in the application. (See ERR50-CPP-EX1 for more information.) -

    -

    - The - - std::terminate() - - function calls the current - - terminate_handler - - function, which defaults to calling - - std::abort() - - . -

    -

    - The C++ Standard defines several ways in which - - std::terminate() - - may be called implicitly by an - - implementation - - [ - - ISO/IEC 14882-2014 - - ]: -

    +

    The std::abort(), std::quick_exit(), and std::_Exit() functions are used to terminate the program in an immediate fashion. They do so without calling exit handlers registered with std::atexit() and without executing destructors for objects with automatic, thread, or static storage duration. How a system manages open streams when a program ends is implementation-defined [ISO/IEC 9899:1999]. Open streams with unwritten buffered data may or may not be flushed, open streams may or may not be closed, and temporary files may or may not be removed. Because these functions can leave external resources, such as files and network communications, in an indeterminate state, they should be called explicitly only in direct response to a critical error in the application. (See ERR50-CPP-EX1 for more information.)

    +

    The std::terminate() function calls the current terminate_handler function, which defaults to calling std::abort().

    +

    The C++ Standard defines several ways in which std::terminate() may be called implicitly by an implementation [ISO/IEC 14882-2014]:

      -
    1. - When the exception handling mechanism, after completing the initialization of the exception object but before activation of a handler for the exception, calls a function that exits via an exception ([except.throw], paragraph 7) - See - - ERR60-CPP. Exception objects must be nothrow copy constructible - - for more information. -
    2. -
    3. - When a - - throw-expression - - with no operand attempts to rethrow an exception and no exception is being handled ([except.throw], paragraph 9) -
    4. -
    5. - When the exception handling mechanism cannot find a handler for a thrown exception ([except.handle], paragraph 9) - See - - ERR51-CPP. Handle all exceptions - - for more information. -
    6. -
    7. - When the search for a handler encounters the outermost block of a function with a - - noexcept-specification - - that does not allow the exception ([except.spec], paragraph 9) - See - - ERR55-CPP. Honor exception specifications - - for more information. -
    8. -
    9. - When the destruction of an object during stack unwinding terminates by throwing an exception ([except.ctor], paragraph 3) - See - - DCL57-CPP. Do not let exceptions escape from destructors or deallocation functions - - for more information. -
    10. -
    11. - When initialization of a nonlocal variable with static or thread storage duration exits via an exception ([basic.start.init], paragraph 6) - See - - ERR58-CPP. Handle all exceptions thrown before main() begins executing - - for more information. -
    12. -
    13. - When destruction of an object with static or thread storage duration exits via an exception ([basic.start.term], paragraph 1) - See - - DCL57-CPP. Do not let exceptions escape from destructors or deallocation functions - - for more information. -
    14. -
    15. - When execution of a function registered with - - std::atexit() - - or - - std::at_quick_exit() - - exits via an exception ([support.start.term], paragraphs 8 and 12) -
    16. -
    17. - When the implementation’s default unexpected exception handler is called ([except.unexpected], paragraph 2) - Note that - - std::unexpected() - - is currently deprecated. -
    18. -
    19. - When - - std::unexpected() - - throws an exception that is not allowed by the previously violated - - dynamic-exception-specification - - , and - - std::bad_exception() - - is not included in that - - dynamic-exception-specification - - ([except.unexpected], paragraph 3) -
    20. -
    21. - When the function - - std::nested_exception::rethrow_nested() - - is called for an object that has captured no exception ([except.nested], paragraph 4) -
    22. -
    23. - When execution of the initial function of a thread exits via an exception ([thread.thread.constr], paragraph 5) - See - - ERR51-CPP. Handle all exceptions - - for more information. -
    24. -
    25. - When the destructor is invoked on an object of type - - std::thread - - that refers to a joinable thread ([thread.thread.destr], paragraph 1) -
    26. -
    27. - When the copy assignment operator is invoked on an object of type - - std::thread - - that refers to a joinable thread ([thread.thread.assign], paragraph 1) -
    28. -
    29. - When calling - - condition_variable::wait() - - , - - condition_variable::wait_until() - - , or - - condition_variable::wait_for() - - results in a failure to meet the postcondition: - - lock.owns_lock() == true - - or - - lock.mutex() - - is not locked by the calling thread ([thread.condition.condvar], paragraphs 11, 16, 21, 28, 33, and 40) -
    30. -
    31. - When calling - - condition_variable_any::wait() - - , - - condition_variable_any::wait_until() - - , or - - condition_variable_any::wait_for() - - results in a failure to meet the postcondition: - - lock - - is not locked by the calling thread ([thread.condition.condvarany], paragraphs 11, 16, and 22) -
    32. +
    33. When the exception handling mechanism, after completing the initialization of the exception object but before activation of a handler for the exception, calls a function that exits via an exception ([except.throw], paragraph 7)See ERR60-CPP. Exception objects must be nothrow copy constructible for more information.
    34. +
    35. When a throw-expression with no operand attempts to rethrow an exception and no exception is being handled ([except.throw], paragraph 9)
    36. +
    37. When the exception handling mechanism cannot find a handler for a thrown exception ([except.handle], paragraph 9)See ERR51-CPP. Handle all exceptions for more information.
    38. +
    39. When the search for a handler encounters the outermost block of a function with a noexcept-specification that does not allow the exception ([except.spec], paragraph 9)See ERR55-CPP. Honor exception specifications for more information.
    40. +
    41. When the destruction of an object during stack unwinding terminates by throwing an exception ([except.ctor], paragraph 3)See DCL57-CPP. Do not let exceptions escape from destructors or deallocation functions for more information.
    42. +
    43. When initialization of a nonlocal variable with static or thread storage duration exits via an exception ([basic.start.init], paragraph 6)See ERR58-CPP. Handle all exceptions thrown before main() begins executing for more information.
    44. +
    45. When destruction of an object with static or thread storage duration exits via an exception ([basic.start.term], paragraph 1)See DCL57-CPP. Do not let exceptions escape from destructors or deallocation functions for more information.
    46. +
    47. When execution of a function registered with std::atexit()or std::at_quick_exit() exits via an exception ([support.start.term], paragraphs 8 and 12)
    48. +
    49. When the implementation’s default unexpected exception handler is called ([except.unexpected], paragraph 2) Note that std::unexpected() is currently deprecated.
    50. +
    51. When std::unexpected() throws an exception that is not allowed by the previously violated dynamic-exception-specification, and std::bad_exception() is not included in that dynamic-exception-specification ([except.unexpected], paragraph 3)
    52. +
    53. When the function std::nested_exception::rethrow_nested() is called for an object that has captured no exception ([except.nested], paragraph 4)
    54. +
    55. When execution of the initial function of a thread exits via an exception ([thread.thread.constr], paragraph 5)See ERR51-CPP. Handle all exceptions for more information.
    56. +
    57. When the destructor is invoked on an object of type std::thread that refers to a joinable thread ([thread.thread.destr], paragraph 1)
    58. +
    59. When the copy assignment operator is invoked on an object of type std::thread that refers to a joinable thread ([thread.thread.assign], paragraph 1)
    60. +
    61. When calling condition_variable::wait(), condition_variable::wait_until(), or condition_variable::wait_for() results in a failure to meet the postcondition: lock.owns_lock() == true or lock.mutex() is not locked by the calling thread ([thread.condition.condvar], paragraphs 11, 16, 21, 28, 33, and 40)
    62. +
    63. When calling condition_variable_any::wait(), condition_variable_any::wait_until(), or condition_variable_any::wait_for() results in a failure to meet the postcondition: lock is not locked by the calling thread ([thread.condition.condvarany], paragraphs 11, 16, and 22)
    -

    - In many circumstances, the call stack will not be unwound in response to an implicit call to - - std::terminate() - - , and in a few cases, it is implementation-defined whether or not stack unwinding will occur. The C++ Standard, [except.terminate], paragraph 2 [ - - ISO/IEC 14882-2014 - - ], in part, states the following: -

    +

    In many circumstances, the call stack will not be unwound in response to an implicit call to std::terminate(), and in a few cases, it is implementation-defined whether or not stack unwinding will occur. The C++ Standard, [except.terminate], paragraph 2 [ISO/IEC 14882-2014], in part, states the following:

    -

    - In the situation where no matching handler is found, it is implementation-defined whether or not the stack is unwound before - - std::terminate() - - is called. In the situation where the search for a handler encounters the outermost block of a function with a - - noexcept-specification - - that does not allow the exception, it is implementation-defined whether the stack is unwound, unwound partially, or not unwound at all before - - std::terminate() - - is called. In all other situations, the stack shall not be unwound before - - std::terminate() - - is called. -

    +

    In the situation where no matching handler is found, it is implementation-defined whether or not the stack is unwound before std::terminate() is called. In the situation where the search for a handler encounters the outermost block of a function with a noexcept-specification that does not allow the exception, it is implementation-defined whether the stack is unwound, unwound partially, or not unwound at all before std::terminate() is called. In all other situations, the stack shall not be unwound before std::terminate() is called.

    -

    - Do not explicitly or implicitly call - - std::quick_exit() - - , - - std::abort() - - , or - - std::_Exit() - - . When the default - - terminate_handler - - is installed or the current - - terminate_handler - - responds by calling - - std::abort() - - or - - std::_Exit() - - , do not explicitly or implicitly call - - std::terminate() - - . - - Abnormal process termination - - is the typical vector for - - denial-of-service attacks - - . -

    -

    - The - - std::exit() - - function is more complex. The C++ Standard, - [basic.start.main], paragraph 4, states: -

    +

    Do not explicitly or implicitly call std::quick_exit(), std::abort(), or std::_Exit(). When the default terminate_handler is installed or the current terminate_handler responds by calling std::abort() or std::_Exit(), do not explicitly or implicitly call std::terminate(). Abnormal process termination is the typical vector for denial-of-service attacks.

    +

    The std::exit() function is more complex. The C++ Standard, [basic.start.main], paragraph 4, states:

    -

    - Terminating the program without leaving the current block (e.g., by calling the function std::exit(int) (17.5)) does not destroy any objects with automatic storage duration (11.4.6). If std::exit is called to end a program during the destruction of an object with static or thread storage duration, the program has undefined behavior. -

    +

    Terminating the program without leaving the current block (e.g., by calling the function std::exit(int) (17.5)) does not destroy any objects with automatic storage duration (11.4.6). If std::exit is called to end a program during the destruction of an object with static or thread storage duration, the program has undefined behavior.

    -

    - You may call - - std::exit() - - only in a program that has not yet initialized any objects with automatic storage duration. -

    -

    - Noncompliant Code Example -

    -

    - In this noncompliant code example, the call to - - f() - - , which was registered as an exit handler with - - std::at_exit() - - , may result in a call to - - std::terminate() - - because - - throwing_func() - - may throw an exception. -

    - - #include <cstdlib> -  +

    You may call std::exit() only in a program that has not yet initialized any objects with automatic storage duration.

    +

    Noncompliant Code Example

    +

    In this noncompliant code example, the call to f(), which was registered as an exit handler with std::at_exit(), may result in a call to std::terminate() because throwing_func() may throw an exception.

    + #include <cstdlib> + void throwing_func() noexcept(false); -  + void f() { // Not invoked by the program except as an exit handler. throwing_func(); } -  + int main() { if (0 != std::atexit(f)) { // Handle error } // ... -} - +}
    -

    - In this compliant solution, - - f() - - handles all exceptions thrown by - - throwing_func() - - and does not rethrow. -

    - - #include <cstdlib> +

    In this compliant solution, f() handles all exceptions thrown by throwing_func() and does not rethrow.

    + #include <cstdlib> void throwing_func() noexcept(false); @@ -392,78 +68,34 @@ int main() { // Handle error } // ... -} - +}
    -

    - - ERR50-CPP-EX1: - - It is acceptable, after indicating the nature of the problem to the operator, to explicitly call - - std::abort() - - , - - std::_Exit() - - , or - - std::terminate() - - in response to a critical program error for which no recovery is possible, as in this example. -

    - - #include <exception> +

    ERR50-CPP-EX1: It is acceptable, after indicating the nature of the problem to the operator, to explicitly call std::abort(), std::_Exit(), or std::terminate() in response to a critical program error for which no recovery is possible, as in this example.

    + #include <exception> void report(const char *msg) noexcept; [[noreturn]] void fast_fail(const char *msg) { // Report error message to operator report(msg); -  + // Terminate std::terminate(); } -  + void critical_function_that_fails() noexcept(false); -  + void f() { try { critical_function_that_fails(); } catch (...) { fast_fail("Critical function failure"); } -} - -

    - The - - assert() - - macro is permissible under this exception because failed assertions will notify the operator on the standard error stream in an - - implementation-defined - - manner before calling - - std::abort() - - . -

    +}
    +

    The assert() macro is permissible under this exception because failed assertions will notify the operator on the standard error stream in an implementation-defined manner before calling std::abort().

    -

    - Allowing the application to - - abnormally terminate - - can lead to resources not being freed, closed, and so on. It is frequently a vector for - - denial-of-service attacks - - . -

    +

    Allowing the application to abnormally terminate can lead to resources not being freed, closed, and so on. It is frequently a vector for denial-of-service attacks.

    Subclause 7.20.4.1, "The - - abort - + abort Function" Subclause 7.20.4.4, "The - - _Exit - + _Exit Function"
    Subclause 15.5.1, "The - - std::terminate() - + std::terminate() Function" Subclause 18.5, "Start and Termination"
    @@ -500,14 +132,10 @@ void f() { Medium @@ -540,9 +168,7 @@ void f() { 20.10 @@ -595,12 +216,8 @@ void f() { 2021.4 @@ -614,9 +231,7 @@ void f() { @@ -732,18 +318,10 @@ void f() { @@ -758,9 +336,7 @@ void f() { 20.10 @@ -789,17 +361,7 @@ void f() {
    - - P4 - + P4 - - L3 - + L3
    - - stdlib-use - + stdlib-use Partially checked @@ -555,13 +181,10 @@ void f() { - 6.1p0 + 6.2p0 - - BADFUNC.ABORT - BADFUNC.EXIT - + BADFUNC.ABORTBADFUNC.EXIT Use of abort @@ -578,9 +201,7 @@ void f() { 2021.2 - - C++5014 - + C++5014 - - MISRA.TERMINATE - - - CERT.ERR.ABRUPT_TERM - + MISRA.TERMINATE + CERT.ERR.ABRUPT_TERM - - 122 S - + 122 S Enhanced Enforcement @@ -632,46 +247,19 @@ void f() { 2021.2 - - CERT_CPP-ERR50-a - - - CERT_CPP-ERR50-b - - - CERT_CPP-ERR50-c - - - CERT_CPP-ERR50-d - - - CERT_CPP-ERR50-e - - - CERT_CPP-ERR50-f - - - CERT_CPP-ERR50-g - - - CERT_CPP-ERR50-h - - - CERT_CPP-ERR50-i - - - CERT_CPP-ERR50-j - - - CERT_CPP-ERR50-k - - - CERT_CPP-ERR50-l - - - CERT_CPP-ERR50-m - CERT_CPP-ERR50-n - + CERT_CPP-ERR50-a + CERT_CPP-ERR50-b + CERT_CPP-ERR50-c + CERT_CPP-ERR50-d + CERT_CPP-ERR50-e + CERT_CPP-ERR50-f + CERT_CPP-ERR50-g + CERT_CPP-ERR50-h + CERT_CPP-ERR50-i + CERT_CPP-ERR50-j + CERT_CPP-ERR50-k + CERT_CPP-ERR50-l + CERT_CPP-ERR50-mCERT_CPP-ERR50-n The execution of a function registered with 'std::atexit()' or 'std::at_quick_exit()' should not exit via an exception @@ -718,9 +306,7 @@ void f() { 4.4 - - 5014 - + 5014 - 7.16 + 7.17 - - - V667 - - , - - V2014 - - + V667, V2014 - - stdlib-use - + stdlib-use Partially checked @@ -776,11 +352,7 @@ void f() { 4.10 - - - S990 - - + S990
    -

    - Search for other - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for other vulnerabilities resulting from the violation of this rule on the CERT website.

    @@ -851,14 +413,10 @@ void f() { @@ -872,9 +430,7 @@ void f() { diff --git a/cpp/cert/src/rules/ERR50-CPP/ExplicitAbruptTerminationCert-standard.qhelp b/cpp/cert/src/rules/ERR50-CPP/ExplicitAbruptTerminationCert-standard.qhelp index ddb56f87a3..cdcf65adda 100644 --- a/cpp/cert/src/rules/ERR50-CPP/ExplicitAbruptTerminationCert-standard.qhelp +++ b/cpp/cert/src/rules/ERR50-CPP/ExplicitAbruptTerminationCert-standard.qhelp @@ -1,381 +1,57 @@
    -

    - The - - std::abort() - - , - - std::quick_exit() - - , and - - std::_Exit() - - functions are used to terminate the program in an immediate fashion. They do so without calling exit handlers registered with - - std::atexit() - - and without executing destructors for objects with automatic, thread, or static storage duration. How a system manages open streams when a program ends is - - implementation-defined - - [ - - ISO/IEC 9899:1999 - - ]. Open streams with unwritten buffered data may or may not be flushed, open streams may or may not be closed, and temporary files may or may not be removed. Because these functions can leave external resources, such as files and network communications, in an indeterminate state, they should be called explicitly only in direct response to a critical error in the application. (See ERR50-CPP-EX1 for more information.) -

    -

    - The - - std::terminate() - - function calls the current - - terminate_handler - - function, which defaults to calling - - std::abort() - - . -

    -

    - The C++ Standard defines several ways in which - - std::terminate() - - may be called implicitly by an - - implementation - - [ - - ISO/IEC 14882-2014 - - ]: -

    +

    The std::abort(), std::quick_exit(), and std::_Exit() functions are used to terminate the program in an immediate fashion. They do so without calling exit handlers registered with std::atexit() and without executing destructors for objects with automatic, thread, or static storage duration. How a system manages open streams when a program ends is implementation-defined [ISO/IEC 9899:1999]. Open streams with unwritten buffered data may or may not be flushed, open streams may or may not be closed, and temporary files may or may not be removed. Because these functions can leave external resources, such as files and network communications, in an indeterminate state, they should be called explicitly only in direct response to a critical error in the application. (See ERR50-CPP-EX1 for more information.)

    +

    The std::terminate() function calls the current terminate_handler function, which defaults to calling std::abort().

    +

    The C++ Standard defines several ways in which std::terminate() may be called implicitly by an implementation [ISO/IEC 14882-2014]:

      -
    1. - When the exception handling mechanism, after completing the initialization of the exception object but before activation of a handler for the exception, calls a function that exits via an exception ([except.throw], paragraph 7) - See - - ERR60-CPP. Exception objects must be nothrow copy constructible - - for more information. -
    2. -
    3. - When a - - throw-expression - - with no operand attempts to rethrow an exception and no exception is being handled ([except.throw], paragraph 9) -
    4. -
    5. - When the exception handling mechanism cannot find a handler for a thrown exception ([except.handle], paragraph 9) - See - - ERR51-CPP. Handle all exceptions - - for more information. -
    6. -
    7. - When the search for a handler encounters the outermost block of a function with a - - noexcept-specification - - that does not allow the exception ([except.spec], paragraph 9) - See - - ERR55-CPP. Honor exception specifications - - for more information. -
    8. -
    9. - When the destruction of an object during stack unwinding terminates by throwing an exception ([except.ctor], paragraph 3) - See - - DCL57-CPP. Do not let exceptions escape from destructors or deallocation functions - - for more information. -
    10. -
    11. - When initialization of a nonlocal variable with static or thread storage duration exits via an exception ([basic.start.init], paragraph 6) - See - - ERR58-CPP. Handle all exceptions thrown before main() begins executing - - for more information. -
    12. -
    13. - When destruction of an object with static or thread storage duration exits via an exception ([basic.start.term], paragraph 1) - See - - DCL57-CPP. Do not let exceptions escape from destructors or deallocation functions - - for more information. -
    14. -
    15. - When execution of a function registered with - - std::atexit() - - or - - std::at_quick_exit() - - exits via an exception ([support.start.term], paragraphs 8 and 12) -
    16. -
    17. - When the implementation’s default unexpected exception handler is called ([except.unexpected], paragraph 2) - Note that - - std::unexpected() - - is currently deprecated. -
    18. -
    19. - When - - std::unexpected() - - throws an exception that is not allowed by the previously violated - - dynamic-exception-specification - - , and - - std::bad_exception() - - is not included in that - - dynamic-exception-specification - - ([except.unexpected], paragraph 3) -
    20. -
    21. - When the function - - std::nested_exception::rethrow_nested() - - is called for an object that has captured no exception ([except.nested], paragraph 4) -
    22. -
    23. - When execution of the initial function of a thread exits via an exception ([thread.thread.constr], paragraph 5) - See - - ERR51-CPP. Handle all exceptions - - for more information. -
    24. -
    25. - When the destructor is invoked on an object of type - - std::thread - - that refers to a joinable thread ([thread.thread.destr], paragraph 1) -
    26. -
    27. - When the copy assignment operator is invoked on an object of type - - std::thread - - that refers to a joinable thread ([thread.thread.assign], paragraph 1) -
    28. -
    29. - When calling - - condition_variable::wait() - - , - - condition_variable::wait_until() - - , or - - condition_variable::wait_for() - - results in a failure to meet the postcondition: - - lock.owns_lock() == true - - or - - lock.mutex() - - is not locked by the calling thread ([thread.condition.condvar], paragraphs 11, 16, 21, 28, 33, and 40) -
    30. -
    31. - When calling - - condition_variable_any::wait() - - , - - condition_variable_any::wait_until() - - , or - - condition_variable_any::wait_for() - - results in a failure to meet the postcondition: - - lock - - is not locked by the calling thread ([thread.condition.condvarany], paragraphs 11, 16, and 22) -
    32. +
    33. When the exception handling mechanism, after completing the initialization of the exception object but before activation of a handler for the exception, calls a function that exits via an exception ([except.throw], paragraph 7)See ERR60-CPP. Exception objects must be nothrow copy constructible for more information.
    34. +
    35. When a throw-expression with no operand attempts to rethrow an exception and no exception is being handled ([except.throw], paragraph 9)
    36. +
    37. When the exception handling mechanism cannot find a handler for a thrown exception ([except.handle], paragraph 9)See ERR51-CPP. Handle all exceptions for more information.
    38. +
    39. When the search for a handler encounters the outermost block of a function with a noexcept-specification that does not allow the exception ([except.spec], paragraph 9)See ERR55-CPP. Honor exception specifications for more information.
    40. +
    41. When the destruction of an object during stack unwinding terminates by throwing an exception ([except.ctor], paragraph 3)See DCL57-CPP. Do not let exceptions escape from destructors or deallocation functions for more information.
    42. +
    43. When initialization of a nonlocal variable with static or thread storage duration exits via an exception ([basic.start.init], paragraph 6)See ERR58-CPP. Handle all exceptions thrown before main() begins executing for more information.
    44. +
    45. When destruction of an object with static or thread storage duration exits via an exception ([basic.start.term], paragraph 1)See DCL57-CPP. Do not let exceptions escape from destructors or deallocation functions for more information.
    46. +
    47. When execution of a function registered with std::atexit()or std::at_quick_exit() exits via an exception ([support.start.term], paragraphs 8 and 12)
    48. +
    49. When the implementation’s default unexpected exception handler is called ([except.unexpected], paragraph 2) Note that std::unexpected() is currently deprecated.
    50. +
    51. When std::unexpected() throws an exception that is not allowed by the previously violated dynamic-exception-specification, and std::bad_exception() is not included in that dynamic-exception-specification ([except.unexpected], paragraph 3)
    52. +
    53. When the function std::nested_exception::rethrow_nested() is called for an object that has captured no exception ([except.nested], paragraph 4)
    54. +
    55. When execution of the initial function of a thread exits via an exception ([thread.thread.constr], paragraph 5)See ERR51-CPP. Handle all exceptions for more information.
    56. +
    57. When the destructor is invoked on an object of type std::thread that refers to a joinable thread ([thread.thread.destr], paragraph 1)
    58. +
    59. When the copy assignment operator is invoked on an object of type std::thread that refers to a joinable thread ([thread.thread.assign], paragraph 1)
    60. +
    61. When calling condition_variable::wait(), condition_variable::wait_until(), or condition_variable::wait_for() results in a failure to meet the postcondition: lock.owns_lock() == true or lock.mutex() is not locked by the calling thread ([thread.condition.condvar], paragraphs 11, 16, 21, 28, 33, and 40)
    62. +
    63. When calling condition_variable_any::wait(), condition_variable_any::wait_until(), or condition_variable_any::wait_for() results in a failure to meet the postcondition: lock is not locked by the calling thread ([thread.condition.condvarany], paragraphs 11, 16, and 22)
    -

    - In many circumstances, the call stack will not be unwound in response to an implicit call to - - std::terminate() - - , and in a few cases, it is implementation-defined whether or not stack unwinding will occur. The C++ Standard, [except.terminate], paragraph 2 [ - - ISO/IEC 14882-2014 - - ], in part, states the following: -

    +

    In many circumstances, the call stack will not be unwound in response to an implicit call to std::terminate(), and in a few cases, it is implementation-defined whether or not stack unwinding will occur. The C++ Standard, [except.terminate], paragraph 2 [ISO/IEC 14882-2014], in part, states the following:

    -

    - In the situation where no matching handler is found, it is implementation-defined whether or not the stack is unwound before - - std::terminate() - - is called. In the situation where the search for a handler encounters the outermost block of a function with a - - noexcept-specification - - that does not allow the exception, it is implementation-defined whether the stack is unwound, unwound partially, or not unwound at all before - - std::terminate() - - is called. In all other situations, the stack shall not be unwound before - - std::terminate() - - is called. -

    +

    In the situation where no matching handler is found, it is implementation-defined whether or not the stack is unwound before std::terminate() is called. In the situation where the search for a handler encounters the outermost block of a function with a noexcept-specification that does not allow the exception, it is implementation-defined whether the stack is unwound, unwound partially, or not unwound at all before std::terminate() is called. In all other situations, the stack shall not be unwound before std::terminate() is called.

    -

    - Do not explicitly or implicitly call - - std::quick_exit() - - , - - std::abort() - - , or - - std::_Exit() - - . When the default - - terminate_handler - - is installed or the current - - terminate_handler - - responds by calling - - std::abort() - - or - - std::_Exit() - - , do not explicitly or implicitly call - - std::terminate() - - . - - Abnormal process termination - - is the typical vector for - - denial-of-service attacks - - . -

    -

    - The - - std::exit() - - function is more complex. The C++ Standard, - [basic.start.main], paragraph 4, states: -

    +

    Do not explicitly or implicitly call std::quick_exit(), std::abort(), or std::_Exit(). When the default terminate_handler is installed or the current terminate_handler responds by calling std::abort() or std::_Exit(), do not explicitly or implicitly call std::terminate(). Abnormal process termination is the typical vector for denial-of-service attacks.

    +

    The std::exit() function is more complex. The C++ Standard, [basic.start.main], paragraph 4, states:

    -

    - Terminating the program without leaving the current block (e.g., by calling the function std::exit(int) (17.5)) does not destroy any objects with automatic storage duration (11.4.6). If std::exit is called to end a program during the destruction of an object with static or thread storage duration, the program has undefined behavior. -

    +

    Terminating the program without leaving the current block (e.g., by calling the function std::exit(int) (17.5)) does not destroy any objects with automatic storage duration (11.4.6). If std::exit is called to end a program during the destruction of an object with static or thread storage duration, the program has undefined behavior.

    -

    - You may call - - std::exit() - - only in a program that has not yet initialized any objects with automatic storage duration. -

    -

    - Noncompliant Code Example -

    -

    - In this noncompliant code example, the call to - - f() - - , which was registered as an exit handler with - - std::at_exit() - - , may result in a call to - - std::terminate() - - because - - throwing_func() - - may throw an exception. -

    - - #include <cstdlib> -  +

    You may call std::exit() only in a program that has not yet initialized any objects with automatic storage duration.

    +

    Noncompliant Code Example

    +

    In this noncompliant code example, the call to f(), which was registered as an exit handler with std::at_exit(), may result in a call to std::terminate() because throwing_func() may throw an exception.

    + #include <cstdlib> + void throwing_func() noexcept(false); -  + void f() { // Not invoked by the program except as an exit handler. throwing_func(); } -  + int main() { if (0 != std::atexit(f)) { // Handle error } // ... -} - +}
    -

    - In this compliant solution, - - f() - - handles all exceptions thrown by - - throwing_func() - - and does not rethrow. -

    - - #include <cstdlib> +

    In this compliant solution, f() handles all exceptions thrown by throwing_func() and does not rethrow.

    + #include <cstdlib> void throwing_func() noexcept(false); @@ -392,78 +68,34 @@ int main() { // Handle error } // ... -} - +}
    -

    - - ERR50-CPP-EX1: - - It is acceptable, after indicating the nature of the problem to the operator, to explicitly call - - std::abort() - - , - - std::_Exit() - - , or - - std::terminate() - - in response to a critical program error for which no recovery is possible, as in this example. -

    - - #include <exception> +

    ERR50-CPP-EX1: It is acceptable, after indicating the nature of the problem to the operator, to explicitly call std::abort(), std::_Exit(), or std::terminate() in response to a critical program error for which no recovery is possible, as in this example.

    + #include <exception> void report(const char *msg) noexcept; [[noreturn]] void fast_fail(const char *msg) { // Report error message to operator report(msg); -  + // Terminate std::terminate(); } -  + void critical_function_that_fails() noexcept(false); -  + void f() { try { critical_function_that_fails(); } catch (...) { fast_fail("Critical function failure"); } -} - -

    - The - - assert() - - macro is permissible under this exception because failed assertions will notify the operator on the standard error stream in an - - implementation-defined - - manner before calling - - std::abort() - - . -

    +}
    +

    The assert() macro is permissible under this exception because failed assertions will notify the operator on the standard error stream in an implementation-defined manner before calling std::abort().

    -

    - Allowing the application to - - abnormally terminate - - can lead to resources not being freed, closed, and so on. It is frequently a vector for - - denial-of-service attacks - - . -

    +

    Allowing the application to abnormally terminate can lead to resources not being freed, closed, and so on. It is frequently a vector for denial-of-service attacks.

    Subclause 7.20.4.1, "The - - abort - + abort Function" Subclause 7.20.4.4, "The - - _Exit - + _Exit Function"
    Subclause 15.5.1, "The - - std::terminate() - + std::terminate() Function" Subclause 18.5, "Start and Termination"
    @@ -500,14 +132,10 @@ void f() { Medium @@ -540,9 +168,7 @@ void f() { 20.10 @@ -595,12 +216,8 @@ void f() { 2021.4 @@ -614,9 +231,7 @@ void f() { @@ -732,18 +318,10 @@ void f() { @@ -758,9 +336,7 @@ void f() { 20.10 @@ -789,17 +361,7 @@ void f() {
    - - P4 - + P4 - - L3 - + L3
    - - stdlib-use - + stdlib-use Partially checked @@ -555,13 +181,10 @@ void f() { - 6.1p0 + 6.2p0 - - BADFUNC.ABORT - BADFUNC.EXIT - + BADFUNC.ABORTBADFUNC.EXIT Use of abort @@ -578,9 +201,7 @@ void f() { 2021.2 - - C++5014 - + C++5014 - - MISRA.TERMINATE - - - CERT.ERR.ABRUPT_TERM - + MISRA.TERMINATE + CERT.ERR.ABRUPT_TERM - - 122 S - + 122 S Enhanced Enforcement @@ -632,46 +247,19 @@ void f() { 2021.2 - - CERT_CPP-ERR50-a - - - CERT_CPP-ERR50-b - - - CERT_CPP-ERR50-c - - - CERT_CPP-ERR50-d - - - CERT_CPP-ERR50-e - - - CERT_CPP-ERR50-f - - - CERT_CPP-ERR50-g - - - CERT_CPP-ERR50-h - - - CERT_CPP-ERR50-i - - - CERT_CPP-ERR50-j - - - CERT_CPP-ERR50-k - - - CERT_CPP-ERR50-l - - - CERT_CPP-ERR50-m - CERT_CPP-ERR50-n - + CERT_CPP-ERR50-a + CERT_CPP-ERR50-b + CERT_CPP-ERR50-c + CERT_CPP-ERR50-d + CERT_CPP-ERR50-e + CERT_CPP-ERR50-f + CERT_CPP-ERR50-g + CERT_CPP-ERR50-h + CERT_CPP-ERR50-i + CERT_CPP-ERR50-j + CERT_CPP-ERR50-k + CERT_CPP-ERR50-l + CERT_CPP-ERR50-mCERT_CPP-ERR50-n The execution of a function registered with 'std::atexit()' or 'std::at_quick_exit()' should not exit via an exception @@ -718,9 +306,7 @@ void f() { 4.4 - - 5014 - + 5014 - 7.16 + 7.17 - - - V667 - - , - - V2014 - - + V667, V2014 - - stdlib-use - + stdlib-use Partially checked @@ -776,11 +352,7 @@ void f() { 4.10 - - - S990 - - + S990
    -

    - Search for other - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for other vulnerabilities resulting from the violation of this rule on the CERT website.

    @@ -851,14 +413,10 @@ void f() { @@ -872,9 +430,7 @@ void f() { diff --git a/cpp/cert/src/rules/ERR50-CPP/JoinableThreadCopiedOrDestroyedCert-standard.qhelp b/cpp/cert/src/rules/ERR50-CPP/JoinableThreadCopiedOrDestroyedCert-standard.qhelp index ddb56f87a3..cdcf65adda 100644 --- a/cpp/cert/src/rules/ERR50-CPP/JoinableThreadCopiedOrDestroyedCert-standard.qhelp +++ b/cpp/cert/src/rules/ERR50-CPP/JoinableThreadCopiedOrDestroyedCert-standard.qhelp @@ -1,381 +1,57 @@
    -

    - The - - std::abort() - - , - - std::quick_exit() - - , and - - std::_Exit() - - functions are used to terminate the program in an immediate fashion. They do so without calling exit handlers registered with - - std::atexit() - - and without executing destructors for objects with automatic, thread, or static storage duration. How a system manages open streams when a program ends is - - implementation-defined - - [ - - ISO/IEC 9899:1999 - - ]. Open streams with unwritten buffered data may or may not be flushed, open streams may or may not be closed, and temporary files may or may not be removed. Because these functions can leave external resources, such as files and network communications, in an indeterminate state, they should be called explicitly only in direct response to a critical error in the application. (See ERR50-CPP-EX1 for more information.) -

    -

    - The - - std::terminate() - - function calls the current - - terminate_handler - - function, which defaults to calling - - std::abort() - - . -

    -

    - The C++ Standard defines several ways in which - - std::terminate() - - may be called implicitly by an - - implementation - - [ - - ISO/IEC 14882-2014 - - ]: -

    +

    The std::abort(), std::quick_exit(), and std::_Exit() functions are used to terminate the program in an immediate fashion. They do so without calling exit handlers registered with std::atexit() and without executing destructors for objects with automatic, thread, or static storage duration. How a system manages open streams when a program ends is implementation-defined [ISO/IEC 9899:1999]. Open streams with unwritten buffered data may or may not be flushed, open streams may or may not be closed, and temporary files may or may not be removed. Because these functions can leave external resources, such as files and network communications, in an indeterminate state, they should be called explicitly only in direct response to a critical error in the application. (See ERR50-CPP-EX1 for more information.)

    +

    The std::terminate() function calls the current terminate_handler function, which defaults to calling std::abort().

    +

    The C++ Standard defines several ways in which std::terminate() may be called implicitly by an implementation [ISO/IEC 14882-2014]:

      -
    1. - When the exception handling mechanism, after completing the initialization of the exception object but before activation of a handler for the exception, calls a function that exits via an exception ([except.throw], paragraph 7) - See - - ERR60-CPP. Exception objects must be nothrow copy constructible - - for more information. -
    2. -
    3. - When a - - throw-expression - - with no operand attempts to rethrow an exception and no exception is being handled ([except.throw], paragraph 9) -
    4. -
    5. - When the exception handling mechanism cannot find a handler for a thrown exception ([except.handle], paragraph 9) - See - - ERR51-CPP. Handle all exceptions - - for more information. -
    6. -
    7. - When the search for a handler encounters the outermost block of a function with a - - noexcept-specification - - that does not allow the exception ([except.spec], paragraph 9) - See - - ERR55-CPP. Honor exception specifications - - for more information. -
    8. -
    9. - When the destruction of an object during stack unwinding terminates by throwing an exception ([except.ctor], paragraph 3) - See - - DCL57-CPP. Do not let exceptions escape from destructors or deallocation functions - - for more information. -
    10. -
    11. - When initialization of a nonlocal variable with static or thread storage duration exits via an exception ([basic.start.init], paragraph 6) - See - - ERR58-CPP. Handle all exceptions thrown before main() begins executing - - for more information. -
    12. -
    13. - When destruction of an object with static or thread storage duration exits via an exception ([basic.start.term], paragraph 1) - See - - DCL57-CPP. Do not let exceptions escape from destructors or deallocation functions - - for more information. -
    14. -
    15. - When execution of a function registered with - - std::atexit() - - or - - std::at_quick_exit() - - exits via an exception ([support.start.term], paragraphs 8 and 12) -
    16. -
    17. - When the implementation’s default unexpected exception handler is called ([except.unexpected], paragraph 2) - Note that - - std::unexpected() - - is currently deprecated. -
    18. -
    19. - When - - std::unexpected() - - throws an exception that is not allowed by the previously violated - - dynamic-exception-specification - - , and - - std::bad_exception() - - is not included in that - - dynamic-exception-specification - - ([except.unexpected], paragraph 3) -
    20. -
    21. - When the function - - std::nested_exception::rethrow_nested() - - is called for an object that has captured no exception ([except.nested], paragraph 4) -
    22. -
    23. - When execution of the initial function of a thread exits via an exception ([thread.thread.constr], paragraph 5) - See - - ERR51-CPP. Handle all exceptions - - for more information. -
    24. -
    25. - When the destructor is invoked on an object of type - - std::thread - - that refers to a joinable thread ([thread.thread.destr], paragraph 1) -
    26. -
    27. - When the copy assignment operator is invoked on an object of type - - std::thread - - that refers to a joinable thread ([thread.thread.assign], paragraph 1) -
    28. -
    29. - When calling - - condition_variable::wait() - - , - - condition_variable::wait_until() - - , or - - condition_variable::wait_for() - - results in a failure to meet the postcondition: - - lock.owns_lock() == true - - or - - lock.mutex() - - is not locked by the calling thread ([thread.condition.condvar], paragraphs 11, 16, 21, 28, 33, and 40) -
    30. -
    31. - When calling - - condition_variable_any::wait() - - , - - condition_variable_any::wait_until() - - , or - - condition_variable_any::wait_for() - - results in a failure to meet the postcondition: - - lock - - is not locked by the calling thread ([thread.condition.condvarany], paragraphs 11, 16, and 22) -
    32. +
    33. When the exception handling mechanism, after completing the initialization of the exception object but before activation of a handler for the exception, calls a function that exits via an exception ([except.throw], paragraph 7)See ERR60-CPP. Exception objects must be nothrow copy constructible for more information.
    34. +
    35. When a throw-expression with no operand attempts to rethrow an exception and no exception is being handled ([except.throw], paragraph 9)
    36. +
    37. When the exception handling mechanism cannot find a handler for a thrown exception ([except.handle], paragraph 9)See ERR51-CPP. Handle all exceptions for more information.
    38. +
    39. When the search for a handler encounters the outermost block of a function with a noexcept-specification that does not allow the exception ([except.spec], paragraph 9)See ERR55-CPP. Honor exception specifications for more information.
    40. +
    41. When the destruction of an object during stack unwinding terminates by throwing an exception ([except.ctor], paragraph 3)See DCL57-CPP. Do not let exceptions escape from destructors or deallocation functions for more information.
    42. +
    43. When initialization of a nonlocal variable with static or thread storage duration exits via an exception ([basic.start.init], paragraph 6)See ERR58-CPP. Handle all exceptions thrown before main() begins executing for more information.
    44. +
    45. When destruction of an object with static or thread storage duration exits via an exception ([basic.start.term], paragraph 1)See DCL57-CPP. Do not let exceptions escape from destructors or deallocation functions for more information.
    46. +
    47. When execution of a function registered with std::atexit()or std::at_quick_exit() exits via an exception ([support.start.term], paragraphs 8 and 12)
    48. +
    49. When the implementation’s default unexpected exception handler is called ([except.unexpected], paragraph 2) Note that std::unexpected() is currently deprecated.
    50. +
    51. When std::unexpected() throws an exception that is not allowed by the previously violated dynamic-exception-specification, and std::bad_exception() is not included in that dynamic-exception-specification ([except.unexpected], paragraph 3)
    52. +
    53. When the function std::nested_exception::rethrow_nested() is called for an object that has captured no exception ([except.nested], paragraph 4)
    54. +
    55. When execution of the initial function of a thread exits via an exception ([thread.thread.constr], paragraph 5)See ERR51-CPP. Handle all exceptions for more information.
    56. +
    57. When the destructor is invoked on an object of type std::thread that refers to a joinable thread ([thread.thread.destr], paragraph 1)
    58. +
    59. When the copy assignment operator is invoked on an object of type std::thread that refers to a joinable thread ([thread.thread.assign], paragraph 1)
    60. +
    61. When calling condition_variable::wait(), condition_variable::wait_until(), or condition_variable::wait_for() results in a failure to meet the postcondition: lock.owns_lock() == true or lock.mutex() is not locked by the calling thread ([thread.condition.condvar], paragraphs 11, 16, 21, 28, 33, and 40)
    62. +
    63. When calling condition_variable_any::wait(), condition_variable_any::wait_until(), or condition_variable_any::wait_for() results in a failure to meet the postcondition: lock is not locked by the calling thread ([thread.condition.condvarany], paragraphs 11, 16, and 22)
    -

    - In many circumstances, the call stack will not be unwound in response to an implicit call to - - std::terminate() - - , and in a few cases, it is implementation-defined whether or not stack unwinding will occur. The C++ Standard, [except.terminate], paragraph 2 [ - - ISO/IEC 14882-2014 - - ], in part, states the following: -

    +

    In many circumstances, the call stack will not be unwound in response to an implicit call to std::terminate(), and in a few cases, it is implementation-defined whether or not stack unwinding will occur. The C++ Standard, [except.terminate], paragraph 2 [ISO/IEC 14882-2014], in part, states the following:

    -

    - In the situation where no matching handler is found, it is implementation-defined whether or not the stack is unwound before - - std::terminate() - - is called. In the situation where the search for a handler encounters the outermost block of a function with a - - noexcept-specification - - that does not allow the exception, it is implementation-defined whether the stack is unwound, unwound partially, or not unwound at all before - - std::terminate() - - is called. In all other situations, the stack shall not be unwound before - - std::terminate() - - is called. -

    +

    In the situation where no matching handler is found, it is implementation-defined whether or not the stack is unwound before std::terminate() is called. In the situation where the search for a handler encounters the outermost block of a function with a noexcept-specification that does not allow the exception, it is implementation-defined whether the stack is unwound, unwound partially, or not unwound at all before std::terminate() is called. In all other situations, the stack shall not be unwound before std::terminate() is called.

    -

    - Do not explicitly or implicitly call - - std::quick_exit() - - , - - std::abort() - - , or - - std::_Exit() - - . When the default - - terminate_handler - - is installed or the current - - terminate_handler - - responds by calling - - std::abort() - - or - - std::_Exit() - - , do not explicitly or implicitly call - - std::terminate() - - . - - Abnormal process termination - - is the typical vector for - - denial-of-service attacks - - . -

    -

    - The - - std::exit() - - function is more complex. The C++ Standard, - [basic.start.main], paragraph 4, states: -

    +

    Do not explicitly or implicitly call std::quick_exit(), std::abort(), or std::_Exit(). When the default terminate_handler is installed or the current terminate_handler responds by calling std::abort() or std::_Exit(), do not explicitly or implicitly call std::terminate(). Abnormal process termination is the typical vector for denial-of-service attacks.

    +

    The std::exit() function is more complex. The C++ Standard, [basic.start.main], paragraph 4, states:

    -

    - Terminating the program without leaving the current block (e.g., by calling the function std::exit(int) (17.5)) does not destroy any objects with automatic storage duration (11.4.6). If std::exit is called to end a program during the destruction of an object with static or thread storage duration, the program has undefined behavior. -

    +

    Terminating the program without leaving the current block (e.g., by calling the function std::exit(int) (17.5)) does not destroy any objects with automatic storage duration (11.4.6). If std::exit is called to end a program during the destruction of an object with static or thread storage duration, the program has undefined behavior.

    -

    - You may call - - std::exit() - - only in a program that has not yet initialized any objects with automatic storage duration. -

    -

    - Noncompliant Code Example -

    -

    - In this noncompliant code example, the call to - - f() - - , which was registered as an exit handler with - - std::at_exit() - - , may result in a call to - - std::terminate() - - because - - throwing_func() - - may throw an exception. -

    - - #include <cstdlib> -  +

    You may call std::exit() only in a program that has not yet initialized any objects with automatic storage duration.

    +

    Noncompliant Code Example

    +

    In this noncompliant code example, the call to f(), which was registered as an exit handler with std::at_exit(), may result in a call to std::terminate() because throwing_func() may throw an exception.

    + #include <cstdlib> + void throwing_func() noexcept(false); -  + void f() { // Not invoked by the program except as an exit handler. throwing_func(); } -  + int main() { if (0 != std::atexit(f)) { // Handle error } // ... -} - +}
    -

    - In this compliant solution, - - f() - - handles all exceptions thrown by - - throwing_func() - - and does not rethrow. -

    - - #include <cstdlib> +

    In this compliant solution, f() handles all exceptions thrown by throwing_func() and does not rethrow.

    + #include <cstdlib> void throwing_func() noexcept(false); @@ -392,78 +68,34 @@ int main() { // Handle error } // ... -} - +}
    -

    - - ERR50-CPP-EX1: - - It is acceptable, after indicating the nature of the problem to the operator, to explicitly call - - std::abort() - - , - - std::_Exit() - - , or - - std::terminate() - - in response to a critical program error for which no recovery is possible, as in this example. -

    - - #include <exception> +

    ERR50-CPP-EX1: It is acceptable, after indicating the nature of the problem to the operator, to explicitly call std::abort(), std::_Exit(), or std::terminate() in response to a critical program error for which no recovery is possible, as in this example.

    + #include <exception> void report(const char *msg) noexcept; [[noreturn]] void fast_fail(const char *msg) { // Report error message to operator report(msg); -  + // Terminate std::terminate(); } -  + void critical_function_that_fails() noexcept(false); -  + void f() { try { critical_function_that_fails(); } catch (...) { fast_fail("Critical function failure"); } -} - -

    - The - - assert() - - macro is permissible under this exception because failed assertions will notify the operator on the standard error stream in an - - implementation-defined - - manner before calling - - std::abort() - - . -

    +}
    +

    The assert() macro is permissible under this exception because failed assertions will notify the operator on the standard error stream in an implementation-defined manner before calling std::abort().

    -

    - Allowing the application to - - abnormally terminate - - can lead to resources not being freed, closed, and so on. It is frequently a vector for - - denial-of-service attacks - - . -

    +

    Allowing the application to abnormally terminate can lead to resources not being freed, closed, and so on. It is frequently a vector for denial-of-service attacks.

    Subclause 7.20.4.1, "The - - abort - + abort Function" Subclause 7.20.4.4, "The - - _Exit - + _Exit Function"
    Subclause 15.5.1, "The - - std::terminate() - + std::terminate() Function" Subclause 18.5, "Start and Termination"
    @@ -500,14 +132,10 @@ void f() { Medium @@ -540,9 +168,7 @@ void f() { 20.10 @@ -595,12 +216,8 @@ void f() { 2021.4 @@ -614,9 +231,7 @@ void f() { @@ -732,18 +318,10 @@ void f() { @@ -758,9 +336,7 @@ void f() { 20.10 @@ -789,17 +361,7 @@ void f() {
    - - P4 - + P4 - - L3 - + L3
    - - stdlib-use - + stdlib-use Partially checked @@ -555,13 +181,10 @@ void f() { - 6.1p0 + 6.2p0 - - BADFUNC.ABORT - BADFUNC.EXIT - + BADFUNC.ABORTBADFUNC.EXIT Use of abort @@ -578,9 +201,7 @@ void f() { 2021.2 - - C++5014 - + C++5014 - - MISRA.TERMINATE - - - CERT.ERR.ABRUPT_TERM - + MISRA.TERMINATE + CERT.ERR.ABRUPT_TERM - - 122 S - + 122 S Enhanced Enforcement @@ -632,46 +247,19 @@ void f() { 2021.2 - - CERT_CPP-ERR50-a - - - CERT_CPP-ERR50-b - - - CERT_CPP-ERR50-c - - - CERT_CPP-ERR50-d - - - CERT_CPP-ERR50-e - - - CERT_CPP-ERR50-f - - - CERT_CPP-ERR50-g - - - CERT_CPP-ERR50-h - - - CERT_CPP-ERR50-i - - - CERT_CPP-ERR50-j - - - CERT_CPP-ERR50-k - - - CERT_CPP-ERR50-l - - - CERT_CPP-ERR50-m - CERT_CPP-ERR50-n - + CERT_CPP-ERR50-a + CERT_CPP-ERR50-b + CERT_CPP-ERR50-c + CERT_CPP-ERR50-d + CERT_CPP-ERR50-e + CERT_CPP-ERR50-f + CERT_CPP-ERR50-g + CERT_CPP-ERR50-h + CERT_CPP-ERR50-i + CERT_CPP-ERR50-j + CERT_CPP-ERR50-k + CERT_CPP-ERR50-l + CERT_CPP-ERR50-mCERT_CPP-ERR50-n The execution of a function registered with 'std::atexit()' or 'std::at_quick_exit()' should not exit via an exception @@ -718,9 +306,7 @@ void f() { 4.4 - - 5014 - + 5014 - 7.16 + 7.17 - - - V667 - - , - - V2014 - - + V667, V2014 - - stdlib-use - + stdlib-use Partially checked @@ -776,11 +352,7 @@ void f() { 4.10 - - - S990 - - + S990
    -

    - Search for other - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for other vulnerabilities resulting from the violation of this rule on the CERT website.

    @@ -851,14 +413,10 @@ void f() { @@ -872,9 +430,7 @@ void f() { diff --git a/cpp/cert/src/rules/ERR50-CPP/RethrowNestedWithoutCaptureCert-standard.qhelp b/cpp/cert/src/rules/ERR50-CPP/RethrowNestedWithoutCaptureCert-standard.qhelp index ddb56f87a3..cdcf65adda 100644 --- a/cpp/cert/src/rules/ERR50-CPP/RethrowNestedWithoutCaptureCert-standard.qhelp +++ b/cpp/cert/src/rules/ERR50-CPP/RethrowNestedWithoutCaptureCert-standard.qhelp @@ -1,381 +1,57 @@
    -

    - The - - std::abort() - - , - - std::quick_exit() - - , and - - std::_Exit() - - functions are used to terminate the program in an immediate fashion. They do so without calling exit handlers registered with - - std::atexit() - - and without executing destructors for objects with automatic, thread, or static storage duration. How a system manages open streams when a program ends is - - implementation-defined - - [ - - ISO/IEC 9899:1999 - - ]. Open streams with unwritten buffered data may or may not be flushed, open streams may or may not be closed, and temporary files may or may not be removed. Because these functions can leave external resources, such as files and network communications, in an indeterminate state, they should be called explicitly only in direct response to a critical error in the application. (See ERR50-CPP-EX1 for more information.) -

    -

    - The - - std::terminate() - - function calls the current - - terminate_handler - - function, which defaults to calling - - std::abort() - - . -

    -

    - The C++ Standard defines several ways in which - - std::terminate() - - may be called implicitly by an - - implementation - - [ - - ISO/IEC 14882-2014 - - ]: -

    +

    The std::abort(), std::quick_exit(), and std::_Exit() functions are used to terminate the program in an immediate fashion. They do so without calling exit handlers registered with std::atexit() and without executing destructors for objects with automatic, thread, or static storage duration. How a system manages open streams when a program ends is implementation-defined [ISO/IEC 9899:1999]. Open streams with unwritten buffered data may or may not be flushed, open streams may or may not be closed, and temporary files may or may not be removed. Because these functions can leave external resources, such as files and network communications, in an indeterminate state, they should be called explicitly only in direct response to a critical error in the application. (See ERR50-CPP-EX1 for more information.)

    +

    The std::terminate() function calls the current terminate_handler function, which defaults to calling std::abort().

    +

    The C++ Standard defines several ways in which std::terminate() may be called implicitly by an implementation [ISO/IEC 14882-2014]:

      -
    1. - When the exception handling mechanism, after completing the initialization of the exception object but before activation of a handler for the exception, calls a function that exits via an exception ([except.throw], paragraph 7) - See - - ERR60-CPP. Exception objects must be nothrow copy constructible - - for more information. -
    2. -
    3. - When a - - throw-expression - - with no operand attempts to rethrow an exception and no exception is being handled ([except.throw], paragraph 9) -
    4. -
    5. - When the exception handling mechanism cannot find a handler for a thrown exception ([except.handle], paragraph 9) - See - - ERR51-CPP. Handle all exceptions - - for more information. -
    6. -
    7. - When the search for a handler encounters the outermost block of a function with a - - noexcept-specification - - that does not allow the exception ([except.spec], paragraph 9) - See - - ERR55-CPP. Honor exception specifications - - for more information. -
    8. -
    9. - When the destruction of an object during stack unwinding terminates by throwing an exception ([except.ctor], paragraph 3) - See - - DCL57-CPP. Do not let exceptions escape from destructors or deallocation functions - - for more information. -
    10. -
    11. - When initialization of a nonlocal variable with static or thread storage duration exits via an exception ([basic.start.init], paragraph 6) - See - - ERR58-CPP. Handle all exceptions thrown before main() begins executing - - for more information. -
    12. -
    13. - When destruction of an object with static or thread storage duration exits via an exception ([basic.start.term], paragraph 1) - See - - DCL57-CPP. Do not let exceptions escape from destructors or deallocation functions - - for more information. -
    14. -
    15. - When execution of a function registered with - - std::atexit() - - or - - std::at_quick_exit() - - exits via an exception ([support.start.term], paragraphs 8 and 12) -
    16. -
    17. - When the implementation’s default unexpected exception handler is called ([except.unexpected], paragraph 2) - Note that - - std::unexpected() - - is currently deprecated. -
    18. -
    19. - When - - std::unexpected() - - throws an exception that is not allowed by the previously violated - - dynamic-exception-specification - - , and - - std::bad_exception() - - is not included in that - - dynamic-exception-specification - - ([except.unexpected], paragraph 3) -
    20. -
    21. - When the function - - std::nested_exception::rethrow_nested() - - is called for an object that has captured no exception ([except.nested], paragraph 4) -
    22. -
    23. - When execution of the initial function of a thread exits via an exception ([thread.thread.constr], paragraph 5) - See - - ERR51-CPP. Handle all exceptions - - for more information. -
    24. -
    25. - When the destructor is invoked on an object of type - - std::thread - - that refers to a joinable thread ([thread.thread.destr], paragraph 1) -
    26. -
    27. - When the copy assignment operator is invoked on an object of type - - std::thread - - that refers to a joinable thread ([thread.thread.assign], paragraph 1) -
    28. -
    29. - When calling - - condition_variable::wait() - - , - - condition_variable::wait_until() - - , or - - condition_variable::wait_for() - - results in a failure to meet the postcondition: - - lock.owns_lock() == true - - or - - lock.mutex() - - is not locked by the calling thread ([thread.condition.condvar], paragraphs 11, 16, 21, 28, 33, and 40) -
    30. -
    31. - When calling - - condition_variable_any::wait() - - , - - condition_variable_any::wait_until() - - , or - - condition_variable_any::wait_for() - - results in a failure to meet the postcondition: - - lock - - is not locked by the calling thread ([thread.condition.condvarany], paragraphs 11, 16, and 22) -
    32. +
    33. When the exception handling mechanism, after completing the initialization of the exception object but before activation of a handler for the exception, calls a function that exits via an exception ([except.throw], paragraph 7)See ERR60-CPP. Exception objects must be nothrow copy constructible for more information.
    34. +
    35. When a throw-expression with no operand attempts to rethrow an exception and no exception is being handled ([except.throw], paragraph 9)
    36. +
    37. When the exception handling mechanism cannot find a handler for a thrown exception ([except.handle], paragraph 9)See ERR51-CPP. Handle all exceptions for more information.
    38. +
    39. When the search for a handler encounters the outermost block of a function with a noexcept-specification that does not allow the exception ([except.spec], paragraph 9)See ERR55-CPP. Honor exception specifications for more information.
    40. +
    41. When the destruction of an object during stack unwinding terminates by throwing an exception ([except.ctor], paragraph 3)See DCL57-CPP. Do not let exceptions escape from destructors or deallocation functions for more information.
    42. +
    43. When initialization of a nonlocal variable with static or thread storage duration exits via an exception ([basic.start.init], paragraph 6)See ERR58-CPP. Handle all exceptions thrown before main() begins executing for more information.
    44. +
    45. When destruction of an object with static or thread storage duration exits via an exception ([basic.start.term], paragraph 1)See DCL57-CPP. Do not let exceptions escape from destructors or deallocation functions for more information.
    46. +
    47. When execution of a function registered with std::atexit()or std::at_quick_exit() exits via an exception ([support.start.term], paragraphs 8 and 12)
    48. +
    49. When the implementation’s default unexpected exception handler is called ([except.unexpected], paragraph 2) Note that std::unexpected() is currently deprecated.
    50. +
    51. When std::unexpected() throws an exception that is not allowed by the previously violated dynamic-exception-specification, and std::bad_exception() is not included in that dynamic-exception-specification ([except.unexpected], paragraph 3)
    52. +
    53. When the function std::nested_exception::rethrow_nested() is called for an object that has captured no exception ([except.nested], paragraph 4)
    54. +
    55. When execution of the initial function of a thread exits via an exception ([thread.thread.constr], paragraph 5)See ERR51-CPP. Handle all exceptions for more information.
    56. +
    57. When the destructor is invoked on an object of type std::thread that refers to a joinable thread ([thread.thread.destr], paragraph 1)
    58. +
    59. When the copy assignment operator is invoked on an object of type std::thread that refers to a joinable thread ([thread.thread.assign], paragraph 1)
    60. +
    61. When calling condition_variable::wait(), condition_variable::wait_until(), or condition_variable::wait_for() results in a failure to meet the postcondition: lock.owns_lock() == true or lock.mutex() is not locked by the calling thread ([thread.condition.condvar], paragraphs 11, 16, 21, 28, 33, and 40)
    62. +
    63. When calling condition_variable_any::wait(), condition_variable_any::wait_until(), or condition_variable_any::wait_for() results in a failure to meet the postcondition: lock is not locked by the calling thread ([thread.condition.condvarany], paragraphs 11, 16, and 22)
    -

    - In many circumstances, the call stack will not be unwound in response to an implicit call to - - std::terminate() - - , and in a few cases, it is implementation-defined whether or not stack unwinding will occur. The C++ Standard, [except.terminate], paragraph 2 [ - - ISO/IEC 14882-2014 - - ], in part, states the following: -

    +

    In many circumstances, the call stack will not be unwound in response to an implicit call to std::terminate(), and in a few cases, it is implementation-defined whether or not stack unwinding will occur. The C++ Standard, [except.terminate], paragraph 2 [ISO/IEC 14882-2014], in part, states the following:

    -

    - In the situation where no matching handler is found, it is implementation-defined whether or not the stack is unwound before - - std::terminate() - - is called. In the situation where the search for a handler encounters the outermost block of a function with a - - noexcept-specification - - that does not allow the exception, it is implementation-defined whether the stack is unwound, unwound partially, or not unwound at all before - - std::terminate() - - is called. In all other situations, the stack shall not be unwound before - - std::terminate() - - is called. -

    +

    In the situation where no matching handler is found, it is implementation-defined whether or not the stack is unwound before std::terminate() is called. In the situation where the search for a handler encounters the outermost block of a function with a noexcept-specification that does not allow the exception, it is implementation-defined whether the stack is unwound, unwound partially, or not unwound at all before std::terminate() is called. In all other situations, the stack shall not be unwound before std::terminate() is called.

    -

    - Do not explicitly or implicitly call - - std::quick_exit() - - , - - std::abort() - - , or - - std::_Exit() - - . When the default - - terminate_handler - - is installed or the current - - terminate_handler - - responds by calling - - std::abort() - - or - - std::_Exit() - - , do not explicitly or implicitly call - - std::terminate() - - . - - Abnormal process termination - - is the typical vector for - - denial-of-service attacks - - . -

    -

    - The - - std::exit() - - function is more complex. The C++ Standard, - [basic.start.main], paragraph 4, states: -

    +

    Do not explicitly or implicitly call std::quick_exit(), std::abort(), or std::_Exit(). When the default terminate_handler is installed or the current terminate_handler responds by calling std::abort() or std::_Exit(), do not explicitly or implicitly call std::terminate(). Abnormal process termination is the typical vector for denial-of-service attacks.

    +

    The std::exit() function is more complex. The C++ Standard, [basic.start.main], paragraph 4, states:

    -

    - Terminating the program without leaving the current block (e.g., by calling the function std::exit(int) (17.5)) does not destroy any objects with automatic storage duration (11.4.6). If std::exit is called to end a program during the destruction of an object with static or thread storage duration, the program has undefined behavior. -

    +

    Terminating the program without leaving the current block (e.g., by calling the function std::exit(int) (17.5)) does not destroy any objects with automatic storage duration (11.4.6). If std::exit is called to end a program during the destruction of an object with static or thread storage duration, the program has undefined behavior.

    -

    - You may call - - std::exit() - - only in a program that has not yet initialized any objects with automatic storage duration. -

    -

    - Noncompliant Code Example -

    -

    - In this noncompliant code example, the call to - - f() - - , which was registered as an exit handler with - - std::at_exit() - - , may result in a call to - - std::terminate() - - because - - throwing_func() - - may throw an exception. -

    - - #include <cstdlib> -  +

    You may call std::exit() only in a program that has not yet initialized any objects with automatic storage duration.

    +

    Noncompliant Code Example

    +

    In this noncompliant code example, the call to f(), which was registered as an exit handler with std::at_exit(), may result in a call to std::terminate() because throwing_func() may throw an exception.

    + #include <cstdlib> + void throwing_func() noexcept(false); -  + void f() { // Not invoked by the program except as an exit handler. throwing_func(); } -  + int main() { if (0 != std::atexit(f)) { // Handle error } // ... -} - +}
    -

    - In this compliant solution, - - f() - - handles all exceptions thrown by - - throwing_func() - - and does not rethrow. -

    - - #include <cstdlib> +

    In this compliant solution, f() handles all exceptions thrown by throwing_func() and does not rethrow.

    + #include <cstdlib> void throwing_func() noexcept(false); @@ -392,78 +68,34 @@ int main() { // Handle error } // ... -} - +}
    -

    - - ERR50-CPP-EX1: - - It is acceptable, after indicating the nature of the problem to the operator, to explicitly call - - std::abort() - - , - - std::_Exit() - - , or - - std::terminate() - - in response to a critical program error for which no recovery is possible, as in this example. -

    - - #include <exception> +

    ERR50-CPP-EX1: It is acceptable, after indicating the nature of the problem to the operator, to explicitly call std::abort(), std::_Exit(), or std::terminate() in response to a critical program error for which no recovery is possible, as in this example.

    + #include <exception> void report(const char *msg) noexcept; [[noreturn]] void fast_fail(const char *msg) { // Report error message to operator report(msg); -  + // Terminate std::terminate(); } -  + void critical_function_that_fails() noexcept(false); -  + void f() { try { critical_function_that_fails(); } catch (...) { fast_fail("Critical function failure"); } -} - -

    - The - - assert() - - macro is permissible under this exception because failed assertions will notify the operator on the standard error stream in an - - implementation-defined - - manner before calling - - std::abort() - - . -

    +}
    +

    The assert() macro is permissible under this exception because failed assertions will notify the operator on the standard error stream in an implementation-defined manner before calling std::abort().

    -

    - Allowing the application to - - abnormally terminate - - can lead to resources not being freed, closed, and so on. It is frequently a vector for - - denial-of-service attacks - - . -

    +

    Allowing the application to abnormally terminate can lead to resources not being freed, closed, and so on. It is frequently a vector for denial-of-service attacks.

    Subclause 7.20.4.1, "The - - abort - + abort Function" Subclause 7.20.4.4, "The - - _Exit - + _Exit Function"
    Subclause 15.5.1, "The - - std::terminate() - + std::terminate() Function" Subclause 18.5, "Start and Termination"
    @@ -500,14 +132,10 @@ void f() { Medium @@ -540,9 +168,7 @@ void f() { 20.10 @@ -595,12 +216,8 @@ void f() { 2021.4 @@ -614,9 +231,7 @@ void f() { @@ -732,18 +318,10 @@ void f() { @@ -758,9 +336,7 @@ void f() { 20.10 @@ -789,17 +361,7 @@ void f() {
    - - P4 - + P4 - - L3 - + L3
    - - stdlib-use - + stdlib-use Partially checked @@ -555,13 +181,10 @@ void f() { - 6.1p0 + 6.2p0 - - BADFUNC.ABORT - BADFUNC.EXIT - + BADFUNC.ABORTBADFUNC.EXIT Use of abort @@ -578,9 +201,7 @@ void f() { 2021.2 - - C++5014 - + C++5014 - - MISRA.TERMINATE - - - CERT.ERR.ABRUPT_TERM - + MISRA.TERMINATE + CERT.ERR.ABRUPT_TERM - - 122 S - + 122 S Enhanced Enforcement @@ -632,46 +247,19 @@ void f() { 2021.2 - - CERT_CPP-ERR50-a - - - CERT_CPP-ERR50-b - - - CERT_CPP-ERR50-c - - - CERT_CPP-ERR50-d - - - CERT_CPP-ERR50-e - - - CERT_CPP-ERR50-f - - - CERT_CPP-ERR50-g - - - CERT_CPP-ERR50-h - - - CERT_CPP-ERR50-i - - - CERT_CPP-ERR50-j - - - CERT_CPP-ERR50-k - - - CERT_CPP-ERR50-l - - - CERT_CPP-ERR50-m - CERT_CPP-ERR50-n - + CERT_CPP-ERR50-a + CERT_CPP-ERR50-b + CERT_CPP-ERR50-c + CERT_CPP-ERR50-d + CERT_CPP-ERR50-e + CERT_CPP-ERR50-f + CERT_CPP-ERR50-g + CERT_CPP-ERR50-h + CERT_CPP-ERR50-i + CERT_CPP-ERR50-j + CERT_CPP-ERR50-k + CERT_CPP-ERR50-l + CERT_CPP-ERR50-mCERT_CPP-ERR50-n The execution of a function registered with 'std::atexit()' or 'std::at_quick_exit()' should not exit via an exception @@ -718,9 +306,7 @@ void f() { 4.4 - - 5014 - + 5014 - 7.16 + 7.17 - - - V667 - - , - - V2014 - - + V667, V2014 - - stdlib-use - + stdlib-use Partially checked @@ -776,11 +352,7 @@ void f() { 4.10 - - - S990 - - + S990
    -

    - Search for other - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for other vulnerabilities resulting from the violation of this rule on the CERT website.

    @@ -851,14 +413,10 @@ void f() { @@ -872,9 +430,7 @@ void f() { diff --git a/cpp/cert/src/rules/ERR51-CPP/HandleAllExceptions-standard.qhelp b/cpp/cert/src/rules/ERR51-CPP/HandleAllExceptions-standard.qhelp index 2c70cd0110..c875e96022 100644 --- a/cpp/cert/src/rules/ERR51-CPP/HandleAllExceptions-standard.qhelp +++ b/cpp/cert/src/rules/ERR51-CPP/HandleAllExceptions-standard.qhelp @@ -1,122 +1,29 @@
    -

    - When an exception is thrown, control is transferred to the nearest handler with a type that matches the type of the exception thrown. If no matching handler is directly found within the handlers for a try block in which the exception is thrown, the search for a matching handler continues to dynamically search for handlers in the surrounding try blocks of the same thread. The C++ Standard, [except.handle], paragraph 9 [ - - ISO/IEC 14882-2014 - - ], states the following: -

    +

    When an exception is thrown, control is transferred to the nearest handler with a type that matches the type of the exception thrown. If no matching handler is directly found within the handlers for a try block in which the exception is thrown, the search for a matching handler continues to dynamically search for handlers in the surrounding try blocks of the same thread. The C++ Standard, [except.handle], paragraph 9 [ISO/IEC 14882-2014], states the following:

    -

    - If no matching handler is found, the function - - std::terminate() - - is called; whether or not the stack is unwound before this call to - - std::terminate() - - is implementation-defined. -

    +

    If no matching handler is found, the function std::terminate() is called; whether or not the stack is unwound before this call to std::terminate() is implementation-defined.

    -

    - The default terminate handler called by - - std::terminate() - - calls - - std::abort() - - , which - - abnormally terminates - - the process. When - - std::abort() - - is called, or if the - - implementation - - does not unwind the stack prior to calling - - std::terminate() - - , destructors for objects may not be called and external resources can be left in an indeterminate state. Abnormal process termination is the typical vector for - - denial-of-service - - attacks. For more information on implicitly calling - - std::terminate() - - , see - - ERR50-CPP. Do not abruptly terminate the program - - . -

    -

    - All exceptions thrown by an application must be caught by a matching exception handler. Even if the exception cannot be gracefully recovered from, using the matching exception handler ensures that the stack will be properly unwound and provides an opportunity to gracefully manage external resources before terminating the process. -

    -

    - As per - - ERR50-CPP-EX1 - - , a program that encounters an unrecoverable exception may explicitly catch the exception and terminate, but it may not allow the exception to remain uncaught. One possible solution to comply with this rule, as well as with ERR50-CPP, is for the - - main() - - function to catch all exceptions. While this does not generally allow the application to recover from the exception gracefully, it does allow the application to terminate in a controlled fashion. -

    +

    The default terminate handler called by std::terminate() calls std::abort(), which abnormally terminates the process. When std::abort() is called, or if the implementation does not unwind the stack prior to calling std::terminate(), destructors for objects may not be called and external resources can be left in an indeterminate state. Abnormal process termination is the typical vector for denial-of-service attacks. For more information on implicitly calling std::terminate(), see ERR50-CPP. Do not abruptly terminate the program.

    +

    All exceptions thrown by an application must be caught by a matching exception handler. Even if the exception cannot be gracefully recovered from, using the matching exception handler ensures that the stack will be properly unwound and provides an opportunity to gracefully manage external resources before terminating the process.

    +

    As per ERR50-CPP-EX1, a program that encounters an unrecoverable exception may explicitly catch the exception and terminate, but it may not allow the exception to remain uncaught. One possible solution to comply with this rule, as well as with ERR50-CPP, is for the main() function to catch all exceptions. While this does not generally allow the application to recover from the exception gracefully, it does allow the application to terminate in a controlled fashion.

    -

    - In this noncompliant code example, neither - - f() - - nor - - main() - - catch exceptions thrown by - - throwing_func() - - . Because no matching handler can be found for the exception thrown, - - std::terminate() - - is called. -

    - - void throwing_func() noexcept(false); -  +

    In this noncompliant code example, neither f() nor main() catch exceptions thrown by throwing_func(). Because no matching handler can be found for the exception thrown, std::terminate() is called.

    + void throwing_func() noexcept(false); + void f() { throwing_func(); } -  + int main() { f(); -} - +}
    -

    - In this compliant solution, the main entry point handles all exceptions, which ensures that the stack is unwound up to the - - main() - - function and allows for graceful management of external resources. -

    - - void throwing_func() noexcept(false); +

    In this compliant solution, the main entry point handles all exceptions, which ensures that the stack is unwound up to the main() function and allows for graceful management of external resources.

    + void throwing_func() noexcept(false); void f() { throwing_func(); @@ -128,51 +35,26 @@ int main() { } catch (...) { // Handle error } -} - +}
    -

    - In this noncompliant code example, the thread entry point function - - thread_start() - - does not catch exceptions thrown by - - throwing_func() - - . If the initial thread function exits because an exception is thrown, - - std::terminate() - - is called. -

    - - #include <thread> +

    In this noncompliant code example, the thread entry point function thread_start() does not catch exceptions thrown by throwing_func(). If the initial thread function exits because an exception is thrown, std::terminate() is called.

    + #include <thread> void throwing_func() noexcept(false); -  + void thread_start() { throwing_func(); } -  + void f() { std::thread t(thread_start); t.join(); -} - +}
    -

    - In this compliant solution, the - - thread_start() - - handles all exceptions and does not rethrow, allowing the thread to - terminate normally. -

    - - #include <thread> +

    In this compliant solution, the thread_start() handles all exceptions and does not rethrow, allowing the thread to terminate normally.

    + #include <thread> void throwing_func() noexcept(false); @@ -187,21 +69,10 @@ void thread_start(void) { void f() { std::thread t(thread_start); t.join(); -} - +}
    -

    - Allowing the application to - - abnormally terminate - - can lead to resources not being freed, closed, and so on. It is frequently a vector for - - denial-of-service attacks - - . -

    +

    Allowing the application to abnormally terminate can lead to resources not being freed, closed, and so on. It is frequently a vector for denial-of-service attacks.

    Subclause 7.20.4.1, "The - - abort - + abort Function" Subclause 7.20.4.4, "The - - _Exit - + _Exit Function"
    Subclause 15.5.1, "The - - std::terminate() - + std::terminate() Function" Subclause 18.5, "Start and Termination"
    @@ -238,14 +109,10 @@ void f() { Medium @@ -278,10 +145,7 @@ void f() { 20.10 @@ -314,9 +176,7 @@ void f() { 2021.2 @@ -331,9 +191,7 @@ void f() { 2021.4 @@ -347,9 +205,7 @@ void f() { @@ -422,12 +272,7 @@ void f() { 20.10
    - - P4 - + P4 - - L3 - + L3
    - - main-function-catch-all - early-catch-all - + main-function-catch-allearly-catch-all Partially checked @@ -297,9 +161,7 @@ void f() { 7.2.0 - - CertC++-ERR51 - + CertC++-ERR51 - - C++4035, C++4036, C++4037 - + C++4035, C++4036, C++4037 - - MISRA.CATCH.ALL - + MISRA.CATCH.ALL - - 527 S - + 527 S Partially implemented @@ -365,12 +221,8 @@ void f() { 2021.2 - - CERT_CPP-ERR51-a - - - CERT_CPP-ERR51-b - + CERT_CPP-ERR51-a + CERT_CPP-ERR51-b Always catch exceptions @@ -405,9 +257,7 @@ void f() { 4.4 - - 4035, 4036, 4037 - + 4035, 4036, 4037 - - - main-function-catch-all - early-catch-all - - + main-function-catch-allearly-catch-all Partially checked @@ -437,30 +282,10 @@ void f() {
    -

    - Search for other - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for other vulnerabilities resulting from the violation of this rule on the CERT website.

    -

    - - This rule is a subset of - - - - ERR50-CPP. Do not abruptly terminate the program - - - . -

    +

    This rule is a subset of ERR50-CPP. Do not abruptly terminate the program.

    @@ -494,9 +319,7 @@ void f() { Subclause 15.1, "Throwing an Exception" Subclause 15.3, "Handling an Exception" Subclause 15.5.1, "The - - std::terminate() - + std::terminate() Function" diff --git a/cpp/cert/src/rules/ERR52-CPP/DoNotUseSetjmpOrLongjmp-standard.qhelp b/cpp/cert/src/rules/ERR52-CPP/DoNotUseSetjmpOrLongjmp-standard.qhelp index a60c531bb1..516d16fcd9 100644 --- a/cpp/cert/src/rules/ERR52-CPP/DoNotUseSetjmpOrLongjmp-standard.qhelp +++ b/cpp/cert/src/rules/ERR52-CPP/DoNotUseSetjmpOrLongjmp-standard.qhelp @@ -1,113 +1,16 @@
    -

    - The C standard library facilities - - setjmp() - - and - - longjmp() - - can be used to simulate throwing and catching exceptions. However, these facilities bypass automatic resource management and can result in - - undefined behavior - - , commonly including resource leaks and - - denial-of-service attacks - - . -

    -

    - The C++ Standard, [support.runtime], paragraph 4 - [ - - ISO/IEC 14882-2014 - - ], states the following - : -

    +

    The C standard library facilities setjmp() and longjmp() can be used to simulate throwing and catching exceptions. However, these facilities bypass automatic resource management and can result in undefined behavior, commonly including resource leaks and denial-of-service attacks.

    +

    The C++ Standard, [support.runtime], paragraph 4 [ISO/IEC 14882-2014], states the following:

    -

    - The function signature - - longjmp(jmp_buf jbuf, int val) - - has more restricted behavior in this International Standard. A - - setjmp - - / - - longjmp - - call pair has undefined behavior if replacing the - - setjmp - - and - - longjmp - - by - - catch - - and - - throw - - would invoke any non-trivial destructors for any automatic objects. -

    +

    The function signature longjmp(jmp_buf jbuf, int val) has more restricted behavior in this International Standard. A setjmp/longjmp call pair has undefined behavior if replacing the setjmp and longjmp by catch and throw would invoke any non-trivial destructors for any automatic objects.

    -

    - Do not call - - setjmp() - - or - - longjmp() - - ; their usage can be replaced by more standard idioms such as - - throw - - expressions and - - catch - - statements. -

    +

    Do not call setjmp() or longjmp(); their usage can be replaced by more standard idioms such as throw expressions and catch statements.

    -

    - If a - - throw - - expression would cause a nontrivial destructor to be invoked, then calling - - longjmp() - - in the same context will result in - - undefined behavior - - . In the following noncompliant code example, the call to - - longjmp() - - occurs in a context with a local - - Counter - - object. Since this object’s destructor is nontrivial, undefined behavior results. -

    - - #include <csetjmp> +

    If a throw expression would cause a nontrivial destructor to be invoked, then calling longjmp() in the same context will result in undefined behavior. In the following noncompliant code example, the call to longjmp() occurs in a context with a local Counter object. Since this object’s destructor is nontrivial, undefined behavior results.

    + #include <csetjmp> #include <iostream> static jmp_buf env; @@ -135,56 +38,17 @@ int main() { } std::cout << "After longjmp(): Instances: " << Counter::instances << std::endl; } - -

    - - Implementation Details - -

    -

    - The above code produces the following results when compiled with - - Clang - - 3.8 for Linux, demonstrating that the program, on this platform, fails to destroy the local - - Counter - - instance when the execution of - - f() - - is terminated. This is permissible as the behavior is undefined. -

    - - Before setjmp(): Instances: 0 + +

    Implementation Details

    +

    The above code produces the following results when compiled with Clang 3.8 for Linux, demonstrating that the program, on this platform, fails to destroy the local Counter instance when the execution of f() is terminated. This is permissible as the behavior is undefined.

    + Before setjmp(): Instances: 0 f(): Instances: 1 From longjmp(): Instances: 1 -After longjmp(): Instances: 1 - +After longjmp(): Instances: 1
    -

    - This compliant solution replaces the calls to - - setjmp() - - and - - longjmp() - - with a - - throw - - expression and a - - catch - - statement. -

    - - #include <iostream> +

    This compliant solution replaces the calls to setjmp() and longjmp() with a throw expression and a catch statement.

    + #include <iostream> struct Counter { static int instances; @@ -209,33 +73,16 @@ int main() { } std::cout << "After catch: Instances: " << Counter::instances << std::endl; } - -

    - This solution produces the following output. -

    - - Before throw: Instances: 0 + +

    This solution produces the following output.

    + Before throw: Instances: 0 f(): Instances: 1 From catch: Instances: 0 After catch: Instances: 0 - +
    -

    - Using - - setjmp() - - and - - longjmp() - - could lead to a - - denial-of-service attack - - due to resources not being properly destroyed. -

    +

    Using setjmp() and longjmp() could lead to a denial-of-service attack due to resources not being properly destroyed.

    @@ -272,14 +119,10 @@ After catch: Instances: 0 Medium @@ -312,9 +155,7 @@ After catch: Instances: 0 20.10 @@ -347,15 +186,11 @@ After catch: Instances: 0 3.9 @@ -366,13 +201,10 @@ After catch: Instances: 0 @@ -406,11 +236,7 @@ After catch: Instances: 0 2021.4 @@ -424,9 +250,7 @@ After catch: Instances: 0 @@ -499,9 +317,7 @@ After catch: Instances: 0 20.10 @@ -530,17 +342,7 @@ After catch: Instances: 0
    - - P4 - + P4 - - L3 - + L3
    - - include-setjmp - + include-setjmp Fully checked @@ -330,9 +171,7 @@ After catch: Instances: 0 7.2.0 - - CertC++-ERR52 - + CertC++-ERR52 - - cert-err52-cpp - + cert-err52-cpp Checked by - - clang-tidy - + clang-tidy .
    - 6.1p0 + 6.2p0 - - BADFUNC.LONGJMP - BADFUNC.SETJMP - + BADFUNC.LONGJMPBADFUNC.SETJMP Use of longjmp @@ -389,9 +221,7 @@ After catch: Instances: 0 2021.2 - - C++5015 - + C++5015 - - - MISRA.STDLIB.LONGJMP - - + MISRA.STDLIB.LONGJMP - - 43 S - + 43 S Fully implemented @@ -442,12 +266,8 @@ After catch: Instances: 0 2021.2 - - CERT_CPP-ERR52-a - - - CERT_CPP-ERR52-b - + CERT_CPP-ERR52-a + CERT_CPP-ERR52-b The setjmp macro and the longjmp function shall not be used @@ -482,9 +302,7 @@ After catch: Instances: 0 4.4 - - 5015 - + 5015 - - include-setjmp - + include-setjmp Fully checked @@ -517,11 +333,7 @@ After catch: Instances: 0 4.10 - - - S982 - - + S982
    -

    - Search for other - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for other vulnerabilities resulting from the violation of this rule on the CERT website.

    @@ -555,13 +357,9 @@ After catch: Instances: 0 diff --git a/cpp/cert/src/rules/ERR53-CPP/DestroyedValueReferencedInConstructorDestructorCatchBlock-standard.qhelp b/cpp/cert/src/rules/ERR53-CPP/DestroyedValueReferencedInConstructorDestructorCatchBlock-standard.qhelp index fba43e59a7..4a21b9a762 100644 --- a/cpp/cert/src/rules/ERR53-CPP/DestroyedValueReferencedInConstructorDestructorCatchBlock-standard.qhelp +++ b/cpp/cert/src/rules/ERR53-CPP/DestroyedValueReferencedInConstructorDestructorCatchBlock-standard.qhelp @@ -1,70 +1,19 @@
    -

    - When an exception is caught by a - - - function-try-block - - - handler in a constructor, any fully constructed base classes and class members of the object are destroyed prior to entering the handler [ - - ISO/IEC 14882-2014 - - ]. Similarly, when an exception is caught by a - - function-try-block - - handler in a destructor, all base classes and nonvariant class members of the objects are destroyed prior to entering the handler. Because of this behavior, the C++ Standard, [except.handle], paragraph 10, states the following: -

    +

    When an exception is caught by a function-try-block handler in a constructor, any fully constructed base classes and class members of the object are destroyed prior to entering the handler [ISO/IEC 14882-2014]. Similarly, when an exception is caught by a function-try-block handler in a destructor, all base classes and nonvariant class members of the objects are destroyed prior to entering the handler. Because of this behavior, the C++ Standard, [except.handle], paragraph 10, states the following:

    -

    - Referring to any non-static member or base class of an object in the handler for a - - function-try-block - - of a constructor or destructor for that object results in undefined behavior. -

    +

    Referring to any non-static member or base class of an object in the handler for a function-try-block of a constructor or destructor for that object results in undefined behavior.

    -

    - Do not reference base classes or class data members in a constructor or destructor - - function-try-block - - handler. Doing so results in - - undefined behavior - - . -

    +

    Do not reference base classes or class data members in a constructor or destructor function-try-block handler. Doing so results in undefined behavior.

    -

    - In this noncompliant code example, the constructor for class - - C - - handles exceptions with a - - function-try-block - - . However, it generates - - undefined behavior - - by inspecting its member field - - str - - . -

    - - #include <string> -  +

    In this noncompliant code example, the constructor for class C handles exceptions with a function-try-block. However, it generates undefined behavior by inspecting its member field str.

    + #include <string> + class C { std::string str; -  + public: C(const std::string &s) try : str(s) { // ... @@ -74,18 +23,11 @@ public: } } }; - +
    -

    - In this compliant solution, the handler inspects the constructor parameter rather than the class data member, thereby avoiding - - undefined behavior - - . -

    - - #include <string> +

    In this compliant solution, the handler inspects the constructor parameter rather than the class data member, thereby avoiding undefined behavior.

    + #include <string> class C { std::string str; @@ -98,17 +40,10 @@ public: // ... } } -}; - +};
    -

    - Accessing nonstatic data in a constructor's exception handler or a destructor's exception handler leads to - - undefined behavior - - . -

    +

    Accessing nonstatic data in a constructor's exception handler or a destructor's exception handler leads to undefined behavior.

    Rule 13.3, Do not use - - setjmp() - + setjmp() and - - longjmp() - + longjmp()
    @@ -145,14 +80,10 @@ public: Medium @@ -185,9 +116,7 @@ public: 20.10 @@ -220,9 +147,7 @@ public: 3.9 @@ -237,9 +162,7 @@ public: 2021.2 @@ -254,11 +177,7 @@ public: 2021.4 @@ -272,9 +191,7 @@ public: @@ -345,9 +257,7 @@ public: 20.10
    - - P2 - + P2 - - L3 - + L3
    - - exception-handler-member-access - + exception-handler-member-access Fully checked @@ -203,9 +132,7 @@ public: 7.2.0 - - CertC++-ERR53 - + CertC++-ERR53 - - -Wexceptions - + -Wexceptions - - C++3510 - + C++3510 - - - MISRA.CTOR.TRY.NON_STATIC - - + MISRA.CTOR.TRY.NON_STATIC - - 549 S - + 549 S Partially implemented @@ -290,9 +207,7 @@ public: 2021.2 - - CERT_CPP-ERR53-a - + CERT_CPP-ERR53-a Handlers of a function-try-block implementation of a class constructor or destructor shall not reference nonstatic members from this class or its bases @@ -326,11 +241,8 @@ public: 4.4 - - 3510 - - - + 3510 + - - exception-handler-member-access - + exception-handler-member-access Fully checked @@ -357,17 +267,7 @@ public:
    -

    - Search for other - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for other vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/ERR54-CPP/CatchBlockShadowingCert-standard.qhelp b/cpp/cert/src/rules/ERR54-CPP/CatchBlockShadowingCert-standard.qhelp index 28703c0aa3..e6e684ac81 100644 --- a/cpp/cert/src/rules/ERR54-CPP/CatchBlockShadowingCert-standard.qhelp +++ b/cpp/cert/src/rules/ERR54-CPP/CatchBlockShadowingCert-standard.qhelp @@ -1,44 +1,15 @@
    -

    - The C++ Standard, [except.handle], paragraph 4 [ - - ISO/IEC 14882-2014 - - ], states the following: -

    +

    The C++ Standard, [except.handle], paragraph 4 [ISO/IEC 14882-2014], states the following:

    -

    - The handlers for a try block are tried in order of appearance. That makes it possible to write handlers that can never be executed, for example by placing a handler for a derived class after a handler for a corresponding base class. -

    +

    The handlers for a try block are tried in order of appearance. That makes it possible to write handlers that can never be executed, for example by placing a handler for a derived class after a handler for a corresponding base class.

    -

    - Consequently, if two handlers catch exceptions that are derived from the same base class (such as - - std::exception - - ), the most derived exception must come first. -

    +

    Consequently, if two handlers catch exceptions that are derived from the same base class (such as std::exception), the most derived exception must come first.

    -

    - In this noncompliant code example, the first handler catches all exceptions of class - - B - - , as well as exceptions of class - - D - - , since they are also of class - - B - - . Consequently, the second handler does not catch any exceptions. -

    - - // Classes used for exception handling +

    In this noncompliant code example, the first handler catches all exceptions of class B, as well as exceptions of class D, since they are also of class B. Consequently, the second handler does not catch any exceptions.

    + // Classes used for exception handling class B {}; class D : public B {}; @@ -50,23 +21,11 @@ void f() { } catch (D &d) { // ... } -} - +}
    -

    - In this compliant solution, the first handler catches all exceptions of class - - D - - , and the second handler catches all the other exceptions of class - - B - - . -

    - - // Classes used for exception handling +

    In this compliant solution, the first handler catches all exceptions of class D, and the second handler catches all the other exceptions of class B.

    + // Classes used for exception handling class B {}; class D : public B {}; @@ -78,13 +37,10 @@ void f() { } catch (B &b) { // ... } -} - +}
    -

    - Exception handlers with inverted priorities cause unexpected control flow when an exception of the derived type occurs. -

    +

    Exception handlers with inverted priorities cause unexpected control flow when an exception of the derived type occurs.

    @@ -121,14 +77,10 @@ void f() { Low @@ -161,9 +113,7 @@ void f() { 20.10 @@ -196,13 +144,27 @@ void f() { 3.9 + + + + + + @@ -248,18 +206,9 @@ void f() { 2021.4 @@ -273,9 +222,7 @@ void f() { @@ -329,9 +274,7 @@ void f() { 4.4 @@ -343,14 +286,10 @@ void f() { @@ -365,9 +304,7 @@ void f() { 20.10 @@ -396,17 +329,7 @@ void f() {
    - - P18 - + P18 - - L1 - + L1
    - - exception-caught-by-earlier-handler - + exception-caught-by-earlier-handler Fully checked @@ -179,9 +129,7 @@ void f() { 7.2.0 - - CertC++-ERR54 - + CertC++-ERR54 - - -Wexceptions - + -Wexceptions
    + + CodeSonar + + + 6.2p0 + + LANG.STRUCT.UCTCH + + Unreachable Catch +
    @@ -213,9 +175,7 @@ void f() { 1.2 - - CP1.ERR36 - + CP1.ERR36 Fully implemented @@ -231,9 +191,7 @@ void f() { 2021.2 - - C++4030, C++4639 - + C++4030, C++4639 - - - MISRA.CATCH.NOALL - - - - - MISRA.CATCH.WRONGORD - - - - + MISRA.CATCH.NOALL + MISRA.CATCH.WRONGORD + - - 541 S, 556 S - + 541 S, 556 S Fully implemented @@ -291,9 +238,7 @@ void f() { 2021.2 - - CERT_CPP-ERR54-a - + CERT_CPP-ERR54-a Where multiple handlers are provided in a single try-catch statement or function-try-block for a derived class and some or all of its bases, the handlers shall be ordered most-derived to base class @@ -315,7 +260,7 @@ void f() { Checks for: - Exception handlers not ordered from most-derived to base class, incorrect order of ellipsis handler. + Exception handlers not ordered from most-derived to base classxception handlers not ordered from most-derived to base class, incorrect order of ellipsis handlerncorrect order of ellipsis handler. Rule fully covered.
    - - 4030, 4639 - + 4030, 4639 - 7.16 + 7.17 - - - V759 - - + V759 - - exception-caught-by-earlier-handler - + exception-caught-by-earlier-handler Fully checked @@ -383,11 +320,7 @@ void f() { 4.10 - - - S1045 - - + S1045
    -

    - Search for other - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for other vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/ERR55-CPP/HonorExceptionSpecifications-standard.qhelp b/cpp/cert/src/rules/ERR55-CPP/HonorExceptionSpecifications-standard.qhelp index c3d9339993..0fe94fd62a 100644 --- a/cpp/cert/src/rules/ERR55-CPP/HonorExceptionSpecifications-standard.qhelp +++ b/cpp/cert/src/rules/ERR55-CPP/HonorExceptionSpecifications-standard.qhelp @@ -1,183 +1,38 @@
    -

    - The C++ Standard, [except.spec], paragraph 8 - [ - - ISO/IEC 14882-2014 - - ], states the following - : -

    +

    The C++ Standard, [except.spec], paragraph 8 [ISO/IEC 14882-2014], states the following:

    -

    - A function is said to - - allow - - an exception of type - - E - - if the - - constant-expression - - in its - - noexcept-specification - - evaluates to - - false - - or its - - dynamic-exception-specification - - contains a type - - T - - for which a handler of type - - T - - would be a match (15.3) for an exception of type - - E - - . -

    +

    A function is said to allow an exception of type E if the constant-expression in its noexcept-specification evaluates to false or its dynamic-exception-specification contains a type T for which a handler of type T would be a match (15.3) for an exception of type E.

    -

    - If a function throws an exception other than one allowed by its - - exception-specification - - , it can lead to an - - implementation-defined - - termination of the program ([except.spec], paragraph 9). -

    -

    - If a function declared with a - - dynamic-exception-specification - - throws an exception of a type that would not match the - - exception-specification - - , the function - - std::unexpected() - - is called. The behavior of this function can be overridden but, by default, causes an exception of - - std::bad_exception - - to be thrown. Unless - - std::bad_exception - - is listed in the - - exception-specification - - , the function - - std::terminate() - - will be called. -

    -

    - Similarly, if a function declared with a - - noexcept-specification - - throws an exception of a type that would cause the - - noexcept-specification - - to evaluate to - - false - - , the function - - std::terminate() - - will be called. -

    -

    - Calling - - std::terminate() - - leads to implementation-defined termination of the program. To prevent - - abnormal termination - - of the program, any function that declares an - - exception-specification - - should restrict itself, as well as any functions it calls, to throwing only allowed exceptions. -

    +

    If a function throws an exception other than one allowed by its exception-specification, it can lead to an implementation-defined termination of the program ([except.spec], paragraph 9).

    +

    If a function declared with a dynamic-exception-specification throws an exception of a type that would not match the exception-specification, the function std::unexpected() is called. The behavior of this function can be overridden but, by default, causes an exception of std::bad_exception to be thrown. Unless std::bad_exception is listed in the exception-specification, the function std::terminate() will be called.

    +

    Similarly, if a function declared with a noexcept-specification throws an exception of a type that would cause the noexcept-specification to evaluate to false, the function std::terminate() will be called.

    +

    Calling std::terminate() leads to implementation-defined termination of the program. To prevent abnormal termination of the program, any function that declares an exception-specification should restrict itself, as well as any functions it calls, to throwing only allowed exceptions.

    -

    - In this noncompliant code example, a function is declared as nonthrowing, but it is possible for - - std::vector::resize() - - to throw an exception when the requested memory cannot be allocated. -

    - - #include <cstddef> +

    In this noncompliant code example, a function is declared as nonthrowing, but it is possible for std::vector::resize() to throw an exception when the requested memory cannot be allocated.

    + #include <cstddef> #include <vector> -  + void f(std::vector<int> &v, size_t s) noexcept(true) { v.resize(s); // May throw } - +
    -

    - In this compliant solution, the function's - - noexcept-specification - - is removed, signifying that the function allows all exceptions. -

    - - #include <cstddef> +

    In this compliant solution, the function's noexcept-specification is removed, signifying that the function allows all exceptions.

    + #include <cstddef> #include <vector> void f(std::vector<int> &v, size_t s) { v.resize(s); // May throw, but that is okay -} - +}
    -

    - In this noncompliant code example, the second function claims to throw only - - Exception1 - - , but it may also throw - - - Exception2. - - -

    - - #include <exception> -  +

    In this noncompliant code example, the second function claims to throw only Exception1, but it may also throw Exception2.

    + #include <exception> + class Exception1 : public std::exception {}; class Exception2 : public std::exception {}; @@ -188,17 +43,11 @@ void foo() { void bar() throw (Exception1) { foo(); // Bad because foo() can throw Exception2 } - +
    -

    - This compliant solution catches the exceptions thrown by - - foo(). - -

    - - #include <exception> +

    This compliant solution catches the exceptions thrown by foo().

    + #include <exception> class Exception1 : public std::exception {}; class Exception2 : public std::exception {}; @@ -214,22 +63,11 @@ void bar() throw (Exception1) { // Handle error without rethrowing it } } - +
    -

    - This compliant solution declares a dynamic - - exception-specification - - for - - bar() - - , which covers all of the exceptions that can be thrown from it. -

    - - #include <exception> +

    This compliant solution declares a dynamic exception-specification for bar(), which covers all of the exceptions that can be thrown from it.

    + #include <exception> class Exception1 : public std::exception {}; class Exception2 : public std::exception {}; @@ -240,42 +78,13 @@ void foo() { void bar() throw (Exception1, Exception2) { foo(); -} - +}
    -

    - Some vendors provide language extensions for specifying whether or not a function throws. For instance, - - Microsoft Visual Studio - - provides - - __declspec(nothrow)) - - , and - - Clang - - supports - - __attribute__((nothrow)) - - . Currently, the vendors do not document the behavior of specifying a nonthrowing function using these extensions. Throwing from a function declared with one of these language extensions is presumed to be - - undefined behavior - - . -

    +

    Some vendors provide language extensions for specifying whether or not a function throws. For instance, Microsoft Visual Studio provides __declspec(nothrow)), and Clang supports __attribute__((nothrow)). Currently, the vendors do not document the behavior of specifying a nonthrowing function using these extensions. Throwing from a function declared with one of these language extensions is presumed to be undefined behavior.

    -

    - Throwing unexpected exceptions disrupts control flow and can cause premature termination and - - denial of service - - . -

    +

    Throwing unexpected exceptions disrupts control flow and can cause premature termination and denial of service.

    @@ -312,14 +121,10 @@ void bar() throw (Exception1, Exception2) { Low @@ -352,9 +157,7 @@ void bar() throw (Exception1, Exception2) { 20.10 @@ -387,9 +188,7 @@ void bar() throw (Exception1, Exception2) { 2021.2 @@ -403,9 +202,7 @@ void bar() throw (Exception1, Exception2) { @@ -457,9 +252,7 @@ void bar() throw (Exception1, Exception2) { 4.4 @@ -474,9 +267,7 @@ void bar() throw (Exception1, Exception2) { 20.10
    - - P9 - + P9 - - L2 - + L2
    - - unhandled-throw-noexcept - + unhandled-throw-noexcept Partially checked @@ -370,9 +173,7 @@ void bar() throw (Exception1, Exception2) { 7.2.0 - - CertC++-ERR55 - + CertC++-ERR55 - - C++4035, C++4036, C++4632 - + C++4035, C++4036, C++4632 - - 56 D - + 56 D Partially implemented @@ -421,9 +218,7 @@ void bar() throw (Exception1, Exception2) { 2021.2 - - CERT_CPP-ERR55-a - + CERT_CPP-ERR55-a Where a function's declaration includes an exception-specification, the function shall only be capable of throwing exceptions of the indicated type(s) @@ -444,7 +239,7 @@ void bar() throw (Exception1, Exception2) { - Checks for noexcept functions exiting with exception (rule fully covered) + Checks for noexcept functions exiting with exception (rule fully covered)
    - - 4035, 4036, 4632 - + 4035, 4036, 4632 - - unhandled-throw-noexcept - + unhandled-throw-noexcept Partially checked @@ -486,17 +277,7 @@ void bar() throw (Exception1, Exception2) {
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    @@ -553,9 +334,7 @@ void bar() throw (Exception1, Exception2) { diff --git a/cpp/cert/src/rules/ERR56-CPP/GuaranteeExceptionSafety-standard.qhelp b/cpp/cert/src/rules/ERR56-CPP/GuaranteeExceptionSafety-standard.qhelp index 3aae16836e..0ab2c3f32b 100644 --- a/cpp/cert/src/rules/ERR56-CPP/GuaranteeExceptionSafety-standard.qhelp +++ b/cpp/cert/src/rules/ERR56-CPP/GuaranteeExceptionSafety-standard.qhelp @@ -1,35 +1,9 @@
    -

    - Proper handling of errors and exceptional situations is essential for the continued correct operation of software. The preferred mechanism for reporting errors in a C++ program is exceptions rather than error codes. A number of core language facilities, including - - dynamic_cast - - , - - operator new() - - , and - - typeid - - , report failures by throwing exceptions. In addition, the C++ standard library makes heavy use of exceptions to report several different kinds of failures. Few C++ programs manage to avoid using some of these facilities. Consequently, the vast majority of C++ programs must be prepared for exceptions to occur and must handle each appropriately. (See - - ERR51-CPP. Handle all exceptions - - .) -

    -

    - Because exceptions introduce code paths into a program, it is important to consider the effects of code taking such paths and to avoid any undesirable effects that might arise otherwise. Some such effects include failure to release an acquired resource, thereby introducing a leak, and failure to reestablish a class invariant after a partial update to an object or even a partial object update while maintaining all invariants. Code that avoids any such undesirable effects is said to be - - exception safe - - . -

    -

    - Based on the preceding effects, the following table distinguishes three kinds of exception safety guarantees from most to least desired. -

    +

    Proper handling of errors and exceptional situations is essential for the continued correct operation of software. The preferred mechanism for reporting errors in a C++ program is exceptions rather than error codes. A number of core language facilities, including dynamic_cast, operator new(), and typeid, report failures by throwing exceptions. In addition, the C++ standard library makes heavy use of exceptions to report several different kinds of failures. Few C++ programs manage to avoid using some of these facilities. Consequently, the vast majority of C++ programs must be prepared for exceptions to occur and must handle each appropriately. (See ERR51-CPP. Handle all exceptions.)

    +

    Because exceptions introduce code paths into a program, it is important to consider the effects of code taking such paths and to avoid any undesirable effects that might arise otherwise. Some such effects include failure to release an acquired resource, thereby introducing a leak, and failure to reestablish a class invariant after a partial update to an object or even a partial object update while maintaining all invariants. Code that avoids any such undesirable effects is said to be exception safe.

    +

    Based on the preceding effects, the following table distinguishes three kinds of exception safety guarantees from most to least desired.

    " - - nothrow - + nothrow (C++)"
    @@ -45,28 +19,20 @@
    - - - Strong - - + Strong The strong exception safety guarantee is a property of an operation such that, in addition to satisfying the basic exception safety guarantee, if the operation terminates by raising an exception, it has no observable effects on program state. - + Strong Exception Safety
    - - - Basic - - + Basic The basic exception safety guarantee is a property of an operation such that, if the operation terminates by raising an exception, it preserves program state invariants and prevents resource leaks. @@ -77,69 +43,26 @@
    - - - None - - + None Code that provides neither the strong nor basic exception safety guarantee is not exception safe. - + No Exception Safety
    -

    - Code that guarantees strong exception safety also guarantees basic exception safety. -

    -

    - Because all exceptions thrown in an application must be handled, in compliance with - - ERR50-CPP. Do not abruptly terminate the program - - , it is critical that thrown exceptions do not leave the program in an indeterminate state where invariants are violated. That is, the program must provide basic exception safety for all invariants and may choose to provide strong exception safety for some invariants. Whether exception handling is used to control the termination of the program or to recover from an exceptional situation, a violated invariant leaves the program in a state where graceful continued execution is likely to introduce security vulnerabilities. Thus, code that provides no exception safety guarantee is unsafe and must be considered defective. -

    +

    Code that guarantees strong exception safety also guarantees basic exception safety.

    +

    Because all exceptions thrown in an application must be handled, in compliance with ERR50-CPP. Do not abruptly terminate the program, it is critical that thrown exceptions do not leave the program in an indeterminate state where invariants are violated. That is, the program must provide basic exception safety for all invariants and may choose to provide strong exception safety for some invariants. Whether exception handling is used to control the termination of the program or to recover from an exceptional situation, a violated invariant leaves the program in a state where graceful continued execution is likely to introduce security vulnerabilities. Thus, code that provides no exception safety guarantee is unsafe and must be considered defective.

    -

    - The following noncompliant code example shows a flawed copy assignment operator. The implicit invariants of the class are that the - - array - - member is a valid (possibly null) pointer and that the - - nElems - - member stores the number of elements in the array pointed to by - - array - - . The function deallocates - - array - - and assigns the element counter, - - nElems - - , before allocating a new block of memory for the copy. As a result, if the - - new - - expression throws an exception, the function will have modified the state of both member variables in a way that violates the implicit invariants of the class. Consequently, such an object is in an indeterminate state and any operation on it, including its destruction, results in - - undefined behavior - - . -

    - - #include <cstring> -  +

    The following noncompliant code example shows a flawed copy assignment operator. The implicit invariants of the class are that the array member is a valid (possibly null) pointer and that the nElems member stores the number of elements in the array pointed to by array. The function deallocates array and assigns the element counter, nElems, before allocating a new block of memory for the copy. As a result, if the new expression throws an exception, the function will have modified the state of both member variables in a way that violates the implicit invariants of the class. Consequently, such an object is in an indeterminate state and any operation on it, including its destruction, results in undefined behavior.

    + #include <cstring> + class IntArray { int *array; std::size_t nElems; @@ -150,7 +73,7 @@ public: delete[] array; } -  + IntArray(const IntArray& that); // nontrivial copy constructor IntArray& operator=(const IntArray &rhs) { if (this != &rhs) { @@ -167,23 +90,12 @@ public: // ... }; - +
    -

    - In this compliant solution, the copy assignment operator provides the - - strong exception safety - - guarantee. The function allocates new storage for the copy before changing the state of the object. Only after the allocation succeeds does the function proceed to change the state of the object. In addition, by copying the array to the newly allocated storage before deallocating the existing array, the function avoids the test for self-assignment, which improves the performance of the code in the common case [ - - Sutter 2004 - - ]. -

    - - #include <cstring> -  +

    In this compliant solution, the copy assignment operator provides the strong exception safety guarantee. The function allocates new storage for the copy before changing the state of the object. Only after the allocation succeeds does the function proceed to change the state of the object. In addition, by copying the array to the newly allocated storage before deallocating the existing array, the function avoids the test for self-assignment, which improves the performance of the code in the common case [Sutter 2004].

    + #include <cstring> + class IntArray { int *array; std::size_t nElems; @@ -210,12 +122,10 @@ public: // ... }; - +
    -

    - Code that is not exception safe typically leads to resource leaks, causes the program to be left in an inconsistent or unexpected state, and ultimately results in undefined behavior at some point after the first exception is thrown. -

    +

    Code that is not exception safe typically leads to resource leaks, causes the program to be left in an inconsistent or unexpected state, and ultimately results in undefined behavior at some point after the first exception is thrown.

    @@ -252,14 +162,10 @@ public: High @@ -282,6 +188,22 @@ public: Description + + + + + + @@ -308,9 +228,7 @@ public: @@ -362,22 +274,10 @@ public: @@ -386,13 +286,7 @@ public:
    - - P9 - + P9 - - L2 - + L2
    + + CodeSonar + + + 6.2p0 + + ALLOC.LEAK + + Leak +
    @@ -292,9 +214,7 @@ public: 2021.2 - - C++4075, C++4076 - + C++4075, C++4076 - - 527 S, 56 D, 71 D - + 527 S, 56 D, 71 D Partially implemented @@ -326,10 +244,7 @@ public: 2021.2 - - CERT_CPP-ERR56-a - CERT_CPP-ERR56-b - + CERT_CPP-ERR56-aCERT_CPP-ERR56-b Always catch exceptions @@ -346,11 +261,8 @@ public: 4.4 - - 4075, 4076 - - - + 4075, 4076 + - 7.16 + 7.17 - - - V565 - - , - - V1023 - - , - - V5002 - - + V565, V1023, V5002
    -

    - Search for vulnerabilities resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/ERR57-CPP/DoNotLeakResourcesWhenHandlingExceptions-standard.qhelp b/cpp/cert/src/rules/ERR57-CPP/DoNotLeakResourcesWhenHandlingExceptions-standard.qhelp index db75741272..2eaa2150a8 100644 --- a/cpp/cert/src/rules/ERR57-CPP/DoNotLeakResourcesWhenHandlingExceptions-standard.qhelp +++ b/cpp/cert/src/rules/ERR57-CPP/DoNotLeakResourcesWhenHandlingExceptions-standard.qhelp @@ -1,81 +1,32 @@
    -

    - Reclaiming resources when exceptions are thrown is important. An exception being thrown may result in cleanup code being bypassed or an object being left in a partially initialized state. Such a partially initialized object would violate basic exception safety, as described in - - ERR56-CPP. Guarantee exception safety - - . It is preferable that resources be reclaimed automatically, using the - - RAII - - design pattern [ - - Stroustrup 2001 - - ], when objects go out of scope. This technique avoids the need to write complex cleanup code when allocating resources. -

    -

    - However, constructors do not offer the same protection. Because a constructor is involved in allocating resources, it does not automatically free any resources it allocates if it terminates prematurely. The C++ Standard, [except.ctor], paragraph 2 [ - - ISO/IEC 14882-2014 - - ], states the following: -

    +

    Reclaiming resources when exceptions are thrown is important. An exception being thrown may result in cleanup code being bypassed or an object being left in a partially initialized state. Such a partially initialized object would violate basic exception safety, as described in ERR56-CPP. Guarantee exception safety. It is preferable that resources be reclaimed automatically, using the RAII design pattern [Stroustrup 2001], when objects go out of scope. This technique avoids the need to write complex cleanup code when allocating resources.

    +

    However, constructors do not offer the same protection. Because a constructor is involved in allocating resources, it does not automatically free any resources it allocates if it terminates prematurely. The C++ Standard, [except.ctor], paragraph 2 [ISO/IEC 14882-2014], states the following:

    -

    - An object of any storage duration whose initialization or destruction is terminated by an exception will have destructors executed for all of its fully constructed subobjects (excluding the variant members of a union-like class), that is, for subobjects for which the principal constructor (12.6.2) has completed execution and the destructor has not yet begun execution. Similarly, if the non-delegating constructor for an object has completed execution and a delegating constructor for that object exits with an exception, the object’s destructor will be invoked. If the object was allocated in a new-expression, the matching deallocation function (3.7.4.2, 5.3.4, 12.5), if any, is called to free the storage occupied by the object. -

    +

    An object of any storage duration whose initialization or destruction is terminated by an exception will have destructors executed for all of its fully constructed subobjects (excluding the variant members of a union-like class), that is, for subobjects for which the principal constructor (12.6.2) has completed execution and the destructor has not yet begun execution. Similarly, if the non-delegating constructor for an object has completed execution and a delegating constructor for that object exits with an exception, the object’s destructor will be invoked. If the object was allocated in a new-expression, the matching deallocation function (3.7.4.2, 5.3.4, 12.5), if any, is called to free the storage occupied by the object.

    -

    - It is generally recommended that constructors that cannot complete their job should throw exceptions rather than exit normally and leave their object in an incomplete state [ - - Cline 2009 - - ]. -

    -

    - Resources must not be leaked as a result of throwing an exception, including during the construction of an object. -

    -

    - - This rule is a subset of - - MEM51-CPP. Properly deallocate dynamically allocated resources - - , as all failures to deallocate resources violate that rule. - -

    +

    It is generally recommended that constructors that cannot complete their job should throw exceptions rather than exit normally and leave their object in an incomplete state [Cline 2009].

    +

    Resources must not be leaked as a result of throwing an exception, including during the construction of an object.

    +

    This rule is a subset of MEM51-CPP. Properly deallocate dynamically allocated resources, as all failures to deallocate resources violate that rule.

    -

    - In this noncompliant code example, - - pst - - is not properly released when - - process_item - - throws an exception, causing a resource leak. -

    - - #include <new> -  +

    In this noncompliant code example, pst is not properly released when process_item throws an exception, causing a resource leak.

    + #include <new> + struct SomeType { SomeType() noexcept; // Performs nontrivial initialization. ~SomeType(); // Performs nontrivial finalization. void process_item() noexcept(false); }; -  + void f() { SomeType *pst = new (std::nothrow) SomeType(); if (!pst) { // Handle error return; } -  + try { pst->process_item(); } catch (...) { @@ -84,21 +35,11 @@ void f() { } delete pst; } - +
    -

    - In this compliant solution, the exception handler frees - - pst - - by calling - - delete. - -

    - - #include <new> +

    In this compliant solution, the exception handler frees pst by calling delete.

    + #include <new> struct SomeType { SomeType() noexcept; // Performs nontrivial initialization. @@ -121,42 +62,16 @@ void f() { throw; } delete pst; -} - -

    - While this compliant solution properly releases its resources using - - catch - - clauses, this approach can have some disadvantages: -

    +}
    +

    While this compliant solution properly releases its resources using catch clauses, this approach can have some disadvantages:

      -
    • - Each distinct cleanup requires its own - - try - - and - - catch - - blocks. -
    • -
    • - The cleanup operation must not throw any exceptions. -
    • +
    • Each distinct cleanup requires its own try and catch blocks.
    • +
    • The cleanup operation must not throw any exceptions.
    -

    - A better approach is to employ RAII. This pattern forces every object to clean up after itself in the face of abnormal behavior, preventing the programmer from having to do so. Another benefit of this approach is that it does not require statements to handle resource allocation errors, in conformance with - - MEM52-CPP. Detect and handle memory allocation errors - - . -

    - - struct SomeType { +

    A better approach is to employ RAII. This pattern forces every object to clean up after itself in the face of abnormal behavior, preventing the programmer from having to do so. Another benefit of this approach is that it does not require statements to handle resource allocation errors, in conformance with MEM52-CPP. Detect and handle memory allocation errors.

    + struct SomeType { SomeType() noexcept; // Performs nontrivial initialization. ~SomeType(); // Performs nontrivial finalization. @@ -172,50 +87,11 @@ void f() { throw; } // After re-throwing the exception, the destructor is run for st. } // If f() exits without throwing an exception, the destructor is run for st. - +
    -

    - In this noncompliant code example, the - - C::C() - - constructor might fail to allocate memory for - - a - - , might fail to allocate memory for - - b - - , or might throw an exception in the - - init() - - method. If - - init() - - throws an exception, neither - - a - - nor - - b - - will be released. Likewise, if the allocation for - - b - - fails, - - a - - will not be released. -

    - - struct A {/* ... */}; +

    In this noncompliant code example, the C::C() constructor might fail to allocate memory for a, might fail to allocate memory for b, or might throw an exception in the init() method. If init() throws an exception, neither a nor b will be released. Likewise, if the allocation for b fails, a will not be released.

    + struct A {/* ... */}; struct B {/* ... */}; class C { @@ -228,28 +104,13 @@ public: init(); } }; - +
    -

    - This compliant solution mitigates the potential failures by releasing - - a - - and - - b - - if an exception is thrown during their allocation or during - - init() - - . -

    - - struct A {/* ... */}; +

    This compliant solution mitigates the potential failures by releasing a and b if an exception is thrown during their allocation or during init().

    + struct A {/* ... */}; struct B {/* ... */}; -  + class C { A *a; B *b; @@ -268,27 +129,12 @@ public: } } }; - +
    -

    - This compliant solution uses - - std::unique_ptr - - to create objects that clean up after themselves should anything go wrong in the - - C::C() - - constructor. The - - std::unique_ptr - - applies the principles of RAII to pointers. -

    - - #include <memory> -  +

    This compliant solution uses std::unique_ptr to create objects that clean up after themselves should anything go wrong in the C::C() constructor. The std::unique_ptr applies the principles of RAII to pointers.

    + #include <memory> + struct A {/* ... */}; struct B {/* ... */}; @@ -301,17 +147,10 @@ public: C() : a(new A()), b(new B()) { init(); } -}; - +};
    -

    - Memory and other resource leaks will eventually cause a program to crash. If an attacker can provoke repeated resource leaks by forcing an exception to be thrown through the submission of suitably crafted data, then the attacker can mount a - - denial-of-service attack - - . -

    +

    Memory and other resource leaks will eventually cause a program to crash. If an attacker can provoke repeated resource leaks by forcing an exception to be thrown through the submission of suitably crafted data, then the attacker can mount a denial-of-service attack.

    @@ -348,14 +187,10 @@ public: High @@ -385,12 +220,10 @@ public: @@ -423,24 +254,12 @@ public: 2021.4 @@ -454,9 +273,7 @@ public:
    - - P2 - + P2 - - L3 - + L3
    - 6.1p0 + 6.2p0 - - ALLOC.LEAK - + ALLOC.LEAK Leak @@ -406,9 +239,7 @@ public: 2021.2 - - C++4756, C++4757, C++4758 - + C++4756, C++4757, C++4758 - - CL.MLK - - - MLK.MIGHT - - - MLK.MUST - - - MLK.RET.MIGHT - - - MLK.RET.MUST - - - RH.LEAK - + CL.MLK + MLK.MIGHT + MLK.MUST + MLK.RET.MIGHT + MLK.RET.MUST + RH.LEAK - - 50 D - + 50 D Partially implemented @@ -472,9 +289,7 @@ public: 2021.2 - - CERT_CPP-ERR57-a - + CERT_CPP-ERR57-a Ensure resources are freed @@ -496,24 +311,14 @@ public: Checks for: - Resource leak caused by exception, object left in partially initialized state, bad allocation in constructor. + Resource leak caused by exceptionesource leak caused by exception, object left in partially initialized statebject left in partially initialized state, bad allocation in constructorad allocation in constructor.
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/ERR58-CPP/HandleAllExceptionsThrownBeforeMainBeginsExecuting-standard.qhelp b/cpp/cert/src/rules/ERR58-CPP/HandleAllExceptionsThrownBeforeMainBeginsExecuting-standard.qhelp index df7d10c74d..3a5bc8e0ae 100644 --- a/cpp/cert/src/rules/ERR58-CPP/HandleAllExceptionsThrownBeforeMainBeginsExecuting-standard.qhelp +++ b/cpp/cert/src/rules/ERR58-CPP/HandleAllExceptionsThrownBeforeMainBeginsExecuting-standard.qhelp @@ -1,108 +1,27 @@
    -

    - Not all exceptions can be caught, even with careful use of - - function-try-blocks - - . The C++ Standard, [except.handle], paragraph 13 [ - - ISO/IEC 14882-2014 - - ], states the following: -

    +

    Not all exceptions can be caught, even with careful use of function-try-blocks. The C++ Standard, [except.handle], paragraph 13 [ISO/IEC 14882-2014], states the following:

    -

    - Exceptions thrown in destructors of objects with static storage duration or in constructors of namespace scope objects with static storage duration are not caught by a - - function-try-block - - on - - main() - - . Exceptions thrown in destructors of objects with thread storage duration or in constructors of namespace-scope objects with thread storage duration are not caught by a function-try-block on the initial function of the thread. -

    +

    Exceptions thrown in destructors of objects with static storage duration or in constructors of namespace scope objects with static storage duration are not caught by a function-try-block on main() . Exceptions thrown in destructors of objects with thread storage duration or in constructors of namespace-scope objects with thread storage duration are not caught by a function-try-block on the initial function of the thread.

    -

    - When declaring an object with static or thread storage duration, and that object is not declared within a function block scope, the type's constructor must be declared - - noexcept - - and must comply with - - ERR55-CPP. Honor exception specifications - - . Additionally, the initializer for such a declaration, if any, must not throw an uncaught exception (including from any implicitly constructed objects that are created as a part of the initialization). If an uncaught exception is thrown before - - main() - - is executed, or if an uncaught exception is thrown after - - main() - - has finished executing, there are no further opportunities to handle the exception and it results in implementation-defined behavior. (See - - ERR50-CPP. Do not abruptly terminate the program - - for further details.) -

    -

    - For more information on exception specifications of destructors, see - - DCL57-CPP. Do not let exceptions escape from destructors or deallocation functions - - . -

    +

    When declaring an object with static or thread storage duration, and that object is not declared within a function block scope, the type's constructor must be declared noexcept and must comply with ERR55-CPP. Honor exception specifications. Additionally, the initializer for such a declaration, if any, must not throw an uncaught exception (including from any implicitly constructed objects that are created as a part of the initialization). If an uncaught exception is thrown before main() is executed, or if an uncaught exception is thrown after main() has finished executing, there are no further opportunities to handle the exception and it results in implementation-defined behavior. (See ERR50-CPP. Do not abruptly terminate the program for further details.)

    +

    For more information on exception specifications of destructors, see DCL57-CPP. Do not let exceptions escape from destructors or deallocation functions.

    -

    - In this noncompliant example, the constructor for - S - may throw an exception that is not caught when - - globalS - - is constructed during program startup. -

    - - struct S { +

    In this noncompliant example, the constructor for S may throw an exception that is not caught when globalS is constructed during program startup.

    + struct S { S() noexcept(false); }; -  -static S globalS; - + +static S globalS;
    -

    - This compliant solution makes - - globalS - - into a local variable with static storage duration, allowing any exceptions thrown during object construction to be caught because the constructor for - - S - - will be executed the first time the function - - globalS() - - is called rather than at program startup. This solution does require the programmer to modify source code so that previous uses of - - globalS - - are replaced by a function call to - - globalS() - - . -

    - - struct S { +

    This compliant solution makes globalS into a local variable with static storage duration, allowing any exceptions thrown during object construction to be caught because the constructor for S will be executed the first time the function globalS() is called rather than at program startup. This solution does require the programmer to modify source code so that previous uses of globalS are replaced by a function call to globalS().

    + struct S { S() noexcept(false); }; -  + S &globalS() { try { static S s; @@ -111,47 +30,11 @@ S &globalS() { // Handle error, perhaps by logging it and gracefully terminating the application. } // Unreachable. -} - +}
    -

    - In this noncompliant example, the constructor of - - global - - may throw an exception during program startup. (The - - std::string - - constructor, which accepts a - - const char * - - and a default allocator object, is not marked - - noexcept - - and consequently allows all exceptions.) This exception is not caught by the - - function-try-block - - on - - main() - - , resulting in a call to - - std::terminate() - - and - - abnormal program termination - - . -

    - - #include <string> +

    In this noncompliant example, the constructor of global may throw an exception during program startup. (The std::string constructor, which accepts a const char * and a default allocator object, is not marked noexcept and consequently allows all exceptions.) This exception is not caught by the function-try-block on main(), resulting in a call to std::terminate() and abnormal program termination.

    + #include <string> static const std::string global("..."); @@ -161,54 +44,20 @@ try { } catch(...) { // IMPORTANT: Will not catch exceptions thrown // from the constructor of global -} - +}
    -

    - Compliant code must prevent exceptions from escaping during program startup and termination. This compliant solution avoids defining a - - std::string - - at global namespace scope and instead uses a - - static const char * - - . -

    - - static const char *global = "..."; +

    Compliant code must prevent exceptions from escaping during program startup and termination. This compliant solution avoids defining a std::string at global namespace scope and instead uses a static const char *.

    + static const char *global = "..."; int main() { // ... -} - +}
    -

    - This compliant solution introduces a class derived from - - std::string - - with a constructor that catches all exceptions with a function try block and terminates the application in accordance with - - ERR50-CPP-EX1 - - in - - ERR50-CPP. Do not abruptly terminate the program - - in the event any exceptions are thrown. Because no exceptions can escape the constructor, it is marked - - noexcept - - and the class type is permissible to use in the declaration or initialization of a static global variable. -

    -

    - For brevity, the full interface for such a type is not described. -

    - - #include <exception> +

    This compliant solution introduces a class derived from std::string with a constructor that catches all exceptions with a function try block and terminates the application in accordance with ERR50-CPP-EX1 in ERR50-CPP. Do not abruptly terminate the program in the event any exceptions are thrown. Because no exceptions can escape the constructor, it is marked noexcept and the class type is permissible to use in the declaration or initialization of a static global variable.

    +

    For brevity, the full interface for such a type is not described.

    + #include <exception> #include <string> namespace my { @@ -223,50 +72,26 @@ struct string : std::string { // ... }; } -  + static const my::string global("..."); int main() { // ... -} - +}
    -

    - In this noncompliant example, an exception may be thrown by the initializer for the static global variable - - i - - . -

    - - extern int f() noexcept(false); +

    In this noncompliant example, an exception may be thrown by the initializer for the static global variable i.

    + extern int f() noexcept(false); int i = f(); -  + int main() { // ... -} - +}
    -

    - This compliant solution wraps the call to - - f() - - with a helper function that catches all exceptions and terminates the program in conformance with - - ERR50-CPP-EX1 - - of - - ERR50-CPP. Do not abruptly terminate the program - - . -

    - - #include <exception> -  +

    This compliant solution wraps the call to f() with a helper function that catches all exceptions and terminates the program in conformance with ERR50-CPP-EX1 of ERR50-CPP. Do not abruptly terminate the program.

    + #include <exception> + int f_helper() noexcept { try { extern int f() noexcept(false); @@ -278,26 +103,15 @@ int f_helper() noexcept { } // Unreachable. } -  + int i = f_helper(); int main() { // ... -} - +}
    -

    - Throwing an exception that cannot be caught results in - - abnormal program termination - - and can lead to - - denial-of-service attacks - - . -

    +

    Throwing an exception that cannot be caught results in abnormal program termination and can lead to denial-of-service attacks.

    @@ -334,14 +148,10 @@ int main() { Low @@ -374,9 +184,7 @@ int main() { 20.10 @@ -409,15 +215,11 @@ int main() { 3.9 @@ -430,9 +232,7 @@ int main() { 2021.2 @@ -447,9 +247,7 @@ int main() { 2021.2 @@ -500,9 +296,7 @@ int main() { 20.10
    - - P9 - + P9 - - L2 - + L2
    - - potentially-throwing-static-initialization - + potentially-throwing-static-initialization Partially checked @@ -392,9 +200,7 @@ int main() { 7.2.0 - - CertC++-ERR58 - + CertC++-ERR58 - - cert-err58-cpp - + cert-err58-cpp Checked by - - clang-tidy - + clang-tidy
    - - C++4634, C++4636, C++4637, C++4639 - + C++4634, C++4636, C++4637, C++4639 - - CERT_CPP-ERR58-a - + CERT_CPP-ERR58-a Exceptions shall be raised only after start-up and before termination of the program @@ -483,9 +281,7 @@ int main() { 4.4 - - 4634, 4636, 4637, 4639 - + 4634, 4636, 4637, 4639 - - potentially-throwing-static-initialization - + potentially-throwing-static-initialization Partially checked @@ -512,29 +306,10 @@ int main() {
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    -

    - - This rule is a subset of - - - - ERR50-CPP. Do not abruptly terminate the program - - -

    +

    This rule is a subset of ERR50-CPP. Do not abruptly terminate the program

    diff --git a/cpp/cert/src/rules/ERR59-CPP/DoNotThrowAnExceptionAcrossExecutionBoundaries-standard.qhelp b/cpp/cert/src/rules/ERR59-CPP/DoNotThrowAnExceptionAcrossExecutionBoundaries-standard.qhelp index ce5d76f641..586abf3621 100644 --- a/cpp/cert/src/rules/ERR59-CPP/DoNotThrowAnExceptionAcrossExecutionBoundaries-standard.qhelp +++ b/cpp/cert/src/rules/ERR59-CPP/DoNotThrowAnExceptionAcrossExecutionBoundaries-standard.qhelp @@ -1,44 +1,15 @@
    -

    - Throwing an exception requires collaboration between the execution of the - - throw - - expression and the passing of control to the appropriate - - catch - - statement, if one applies. This collaboration takes the form of runtime logic used to calculate the correct handler for the exception and is an implementation detail specific to the platform. For code compiled by a single C++ compiler, the details of how to throw and catch exceptions can be safely ignored. However, when throwing an exception across execution boundaries, care must be taken to ensure the runtime logic used is compatible between differing sides of the execution boundary. -

    -

    - An - - execution boundary - - is the delimitation between code compiled by differing compilers, including different versions of a compiler produced by the same vendor. For instance, a function may be declared in a header file but defined in a library that is loaded at runtime. The execution boundary is between the call site in the executable and the function implementation in the library. Such boundaries are also called - - ABI - - (application binary interface) boundaries because they relate to the interoperability of application binaries. -

    -

    - Throw an exception across an execution boundary only when both sides of the execution boundary use the same ABI for exception handling. -

    +

    Throwing an exception requires collaboration between the execution of the throw expression and the passing of control to the appropriate catch statement, if one applies. This collaboration takes the form of runtime logic used to calculate the correct handler for the exception and is an implementation detail specific to the platform. For code compiled by a single C++ compiler, the details of how to throw and catch exceptions can be safely ignored. However, when throwing an exception across execution boundaries, care must be taken to ensure the runtime logic used is compatible between differing sides of the execution boundary.

    +

    An execution boundary is the delimitation between code compiled by differing compilers, including different versions of a compiler produced by the same vendor. For instance, a function may be declared in a header file but defined in a library that is loaded at runtime. The execution boundary is between the call site in the executable and the function implementation in the library. Such boundaries are also called ABI (application binary interface) boundaries because they relate to the interoperability of application binaries.

    +

    Throw an exception across an execution boundary only when both sides of the execution boundary use the same ABI for exception handling.

    -

    - In this noncompliant code example, an exception is thrown from a library function to signal an error. Despite the exception being a scalar type (and thus implicitly conforming to - - EXP60-CPP. Do not pass a nonstandard-layout type object across execution boundaries - - ), this code can still result in abnormal program execution if the library and application adhere to different ABIs. -

    - - // library.h +

    In this noncompliant code example, an exception is thrown from a library function to signal an error. Despite the exception being a scalar type (and thus implicitly conforming to EXP60-CPP. Do not pass a nonstandard-layout type object across execution boundaries), this code can still result in abnormal program execution if the library and application adhere to different ABIs.

    + // library.h void func() noexcept(false); // Implemented by the library -  + // library.cpp void func() noexcept(false) { // ... @@ -46,7 +17,7 @@ void func() noexcept(false) { throw 42; } } -  + // application.cpp #include "library.h" @@ -56,43 +27,13 @@ void f() { } catch(int &e) { // Handle error } -} - -

    - - Implementation Details - -

    -

    - If the library code is compiled (with modification to account for mangling differences) with - - GCC - - 4.9 on a default installation of MinGW-w64 without special compiler flags, the exception throw will rely on the zero-cost, table-based exception model that is based on - - DWARF - - and uses the Itanium ABI. If the application code is compiled with - - Microsoft Visual Studio - - 2013, the catch handler will be based on - - Structured Exception Handling - - and the Microsoft ABI. These two exception-handling formats are incompatible, as are the ABIs, resulting in abnormal program behavior. Specifically, the exception thrown by the library is not caught by the application, and - - std::terminate() - - is eventually called. -

    +}
    +

    Implementation Details

    +

    If the library code is compiled (with modification to account for mangling differences) with GCC 4.9 on a default installation of MinGW-w64 without special compiler flags, the exception throw will rely on the zero-cost, table-based exception model that is based on DWARF and uses the Itanium ABI. If the application code is compiled with Microsoft Visual Studio 2013, the catch handler will be based on Structured Exception Handling and the Microsoft ABI. These two exception-handling formats are incompatible, as are the ABIs, resulting in abnormal program behavior. Specifically, the exception thrown by the library is not caught by the application, and std::terminate() is eventually called.

    -

    - In this compliant solution, the error from the library function is indicated by a return value instead of an exception. Using Microsoft Visual Studio (or GCC) to compile both the library and the application would also be a compliant solution because the same exception-handling machinery and ABI would be used on both sides of the execution boundary. -

    - - // library.h +

    In this compliant solution, the error from the library function is indicated by a return value instead of an exception. Using Microsoft Visual Studio (or GCC) to compile both the library and the application would also be a compliant solution because the same exception-handling machinery and ABI would be used on both sides of the execution boundary.

    + // library.h int func() noexcept(true); // Implemented by the library // library.cpp @@ -112,21 +53,10 @@ void f() { if (int err = func()) { // Handle error } -} - +}
    -

    - The effects of throwing an exception across execution boundaries depends on the - - implementation details - - of the exception-handling mechanics. They can range from correct or benign behavior to - - undefined behavior - - . -

    +

    The effects of throwing an exception across execution boundaries depends on the implementation details of the exception-handling mechanics. They can range from correct or benign behavior to undefined behavior.

    @@ -163,14 +93,10 @@ void f() { Medium @@ -203,9 +129,7 @@ void f() { 2021.2 @@ -220,9 +144,7 @@ void f() { 2021.2
    - - P12 - + P12 - - L1 - + L1
    - - C++3809, C++3810 - + C++3809, C++3810 - - CERT_CPP-ERR59-a - + CERT_CPP-ERR59-a Do not throw an exception across execution boundaries @@ -232,17 +154,7 @@ void f() {
    -

    - Search for other - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for other vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/ERR60-CPP/ExceptionObjectsMustBeNothrowCopyConstructible-standard.qhelp b/cpp/cert/src/rules/ERR60-CPP/ExceptionObjectsMustBeNothrowCopyConstructible-standard.qhelp index c52805595a..0e56232676 100644 --- a/cpp/cert/src/rules/ERR60-CPP/ExceptionObjectsMustBeNothrowCopyConstructible-standard.qhelp +++ b/cpp/cert/src/rules/ERR60-CPP/ExceptionObjectsMustBeNothrowCopyConstructible-standard.qhelp @@ -1,122 +1,17 @@
    -

    - When an exception is thrown, the exception object operand of the - - throw - - expression is copied into a temporary object that is used to initialize the handler. The C++ Standard, [except.throw], paragraph 3 [ - - ISO/IEC 14882-2014 - - ], in part, states the following: -

    +

    When an exception is thrown, the exception object operand of the throw expression is copied into a temporary object that is used to initialize the handler. The C++ Standard, [except.throw], paragraph 3 [ISO/IEC 14882-2014], in part, states the following:

    -

    - Throwing an exception copy-initializes a temporary object, called the - - exception object - - . The temporary is an lvalue and is used to initialize the variable declared in the matching - - handler - - . -

    +

    Throwing an exception copy-initializes a temporary object, called the exception object. The temporary is an lvalue and is used to initialize the variable declared in the matching handler.

    -

    - If the copy constructor for the exception object type throws during the copy initialization, - - std::terminate() - - is called, which can result in possibly unexpected - - implementation-defined behavior - - . For more information on implicitly calling - - std::terminate() - - , see - - ERR50-CPP. Do not abruptly terminate the program - - . -

    -

    - The copy constructor for an object thrown as an exception must be declared - - noexcept - - , including any implicitly-defined copy constructors. Any function declared - - noexcept - - that terminates by throwing an exception violates - - ERR55-CPP. Honor exception specifications - - . -

    -

    - The C++ Standard allows the copy constructor to be elided when initializing the exception object to perform the initialization if a temporary is thrown. Many modern compiler implementations make use of both optimization techniques. However, the copy constructor for an exception object still must not throw an exception because compilers are not required to elide the copy constructor call in all situations, and common implementations of - - std::exception_ptr - - will call a copy constructor even if it can be elided from a - - throw - - expression. -

    +

    If the copy constructor for the exception object type throws during the copy initialization, std::terminate() is called, which can result in possibly unexpected implementation-defined behavior. For more information on implicitly calling std::terminate(), see ERR50-CPP. Do not abruptly terminate the program.

    +

    The copy constructor for an object thrown as an exception must be declared noexcept, including any implicitly-defined copy constructors. Any function declared noexcept that terminates by throwing an exception violates ERR55-CPP. Honor exception specifications.

    +

    The C++ Standard allows the copy constructor to be elided when initializing the exception object to perform the initialization if a temporary is thrown. Many modern compiler implementations make use of both optimization techniques. However, the copy constructor for an exception object still must not throw an exception because compilers are not required to elide the copy constructor call in all situations, and common implementations of std::exception_ptr will call a copy constructor even if it can be elided from a throw expression.

    -

    - In this noncompliant code example, an exception of type - - S - - is thrown in - - f() - - . However, because - - S - - has a - - std::string - - data member, and the copy constructor for - - std::string - - is not declared - - noexcept - - , the implicitly-defined copy constructor for - - S - - is also not declared to be - - noexcept - - . In low-memory situations, the copy constructor for - - std::string - - may be unable to allocate sufficient memory to complete the copy operation, resulting in a - - std::bad_alloc - - exception being thrown. -

    - - #include <exception> +

    In this noncompliant code example, an exception of type S is thrown in f(). However, because S has a std::string data member, and the copy constructor for std::string is not declared noexcept, the implicitly-defined copy constructor for S is also not declared to be noexcept. In low-memory situations, the copy constructor for std::string may be unable to allocate sufficient memory to complete the copy operation, resulting in a std::bad_alloc exception being thrown.

    + #include <exception> #include <string> class S : public std::exception { @@ -128,7 +23,7 @@ public: return m.c_str(); } }; -  + void g() { // If some condition doesn't hold... throw S("Condition did not hold"); @@ -140,38 +35,17 @@ void f() { } catch (S &s) { // Handle error } -} - +}
    -

    - This compliant solution assumes that the type of the exception object can inherit from - - std::runtime_error - - , or that type can be used directly. Unlike - - std::string - - , a - - std::runtime_error - - object is required to correctly handle an arbitrary-length error message that is exception safe and guarantees the copy constructor will not throw - [ - - ISO/IEC 14882-2014 - - ]. -

    - - #include <stdexcept> +

    This compliant solution assumes that the type of the exception object can inherit from std::runtime_error, or that type can be used directly. Unlike std::string, a std::runtime_error object is required to correctly handle an arbitrary-length error message that is exception safe and guarantees the copy constructor will not throw [ ISO/IEC 14882-2014 ].

    + #include <stdexcept> #include <type_traits> struct S : std::runtime_error { S(const char *msg) : std::runtime_error(msg) {} }; -  + static_assert(std::is_nothrow_copy_constructible<S>::value, "S must be nothrow copy constructible"); @@ -186,19 +60,11 @@ void f() { } catch (S &s) { // Handle error } -} - +}
    -

    - If the exception type cannot be modified to inherit from - - std::runtime_error - - , a data member of that type is a legitimate implementation strategy, as shown in this compliant solution. -

    - - #include <stdexcept> +

    If the exception type cannot be modified to inherit from std::runtime_error, a data member of that type is a legitimate implementation strategy, as shown in this compliant solution.

    + #include <stdexcept> #include <type_traits> class S : public std::exception { @@ -210,7 +76,7 @@ public: return m.what(); } }; -  + static_assert(std::is_nothrow_copy_constructible<S>::value, "S must be nothrow copy constructible"); @@ -225,21 +91,10 @@ void f() { } catch (S &s) { // Handle error } -} - +}
    -

    - Allowing the application to - - abnormally terminate - - can lead to resources not being freed, closed, and so on. It is frequently a vector for - - denial-of-service attacks - - . -

    +

    Allowing the application to abnormally terminate can lead to resources not being freed, closed, and so on. It is frequently a vector for denial-of-service attacks.

    @@ -276,14 +131,10 @@ void f() { Medium @@ -316,15 +167,11 @@ void f() { 3.9 @@ -337,9 +184,7 @@ void f() { 2021.2 @@ -354,12 +199,8 @@ void f() { 2021.2 @@ -387,17 +226,7 @@ void f() {
    - - P4 - + P4 - - L3 - + L3
    - - cert-err60-cpp - + cert-err60-cpp Checked by - - clang-tidy - + clang-tidy
    - - C++3508 - + C++3508 - - CERT_CPP-ERR60-a - - - CERT_CPP-ERR60-b - + CERT_CPP-ERR60-a + CERT_CPP-ERR60-b Exception objects must be nothrow copy constructible @@ -376,9 +217,7 @@ void f() { 4.4 - - 3508 - + 3508
    -

    - Search for other - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for other vulnerabilities resulting from the violation of this rule on the CERT website.

    @@ -445,9 +274,7 @@ void f() { diff --git a/cpp/cert/src/rules/ERR61-CPP/CatchExceptionsByLvalueReference-standard.qhelp b/cpp/cert/src/rules/ERR61-CPP/CatchExceptionsByLvalueReference-standard.qhelp index d4acedd8f9..86d608c149 100644 --- a/cpp/cert/src/rules/ERR61-CPP/CatchExceptionsByLvalueReference-standard.qhelp +++ b/cpp/cert/src/rules/ERR61-CPP/CatchExceptionsByLvalueReference-standard.qhelp @@ -1,233 +1,60 @@
    -

    - When an exception is thrown, the value of the object in the throw expression is used to initialize an anonymous temporary object called the - - exception object - - . The type of this exception object is used to transfer control to the nearest catch handler, which contains an exception declaration with a matching type. The C++ Standard, [except.handle], paragraph 16 [ - - ISO/IEC 14882-2014 - - ], in part, states the following: -

    +

    When an exception is thrown, the value of the object in the throw expression is used to initialize an anonymous temporary object called the exception object. The type of this exception object is used to transfer control to the nearest catch handler, which contains an exception declaration with a matching type. The C++ Standard, [except.handle], paragraph 16 [ISO/IEC 14882-2014], in part, states the following:

    -

    - The variable declared by the - - exception-declaration - - , of type - - cv - - - T - - or - - cv - - - T& - - , is initialized from the exception object, of type - - E - - , as follows: - — if - - T - - is a base class of - - E - - , the variable is copy-initialized from the corresponding base class subobject of the exception object; - — otherwise, the variable is copy-initialized from the exception object. -

    +

    The variable declared by the exception-declaration, of type cv T or cv T&, is initialized from the exception object, of type E, as follows: — if T is a base class of E, the variable is copy-initialized from the corresponding base class subobject of the exception object; — otherwise, the variable is copy-initialized from the exception object.

    -

    - Because the variable declared by the - - exception-declaration - - is copy-initialized, it is possible to - - slice - - - - the exception object as part of the copy operation, losing valuable exception information and leading to incorrect error recovery. - For more information about object slicing, see - - OOP51-CPP. Do not slice derived objects - - . Further, if the copy constructor of the exception object throws an exception, the copy initialization of the - - exception-declaration - - object results in undefined behavior. (See - - ERR60-CPP. Exception objects must be nothrow copy constructible - - for more information.) -

    -

    - Always catch exceptions by - - lvalue - - reference unless the type is a trivial type. For reference, the C++ Standard, [basic.types], paragraph 9 [ - - ISO/IEC 14882-2014 - - ], defines trivial types as the following: -

    +

    Because the variable declared by the exception-declaration is copy-initialized, it is possible to slice the exception object as part of the copy operation, losing valuable exception information and leading to incorrect error recovery. For more information about object slicing, see OOP51-CPP. Do not slice derived objects. Further, if the copy constructor of the exception object throws an exception, the copy initialization of the exception-declaration object results in undefined behavior. (See ERR60-CPP. Exception objects must be nothrow copy constructible for more information.)

    +

    Always catch exceptions by lvalue reference unless the type is a trivial type. For reference, the C++ Standard, [basic.types], paragraph 9 [ISO/IEC 14882-2014], defines trivial types as the following:

    -

    - Arithmetic types, enumeration types, pointer types, pointer to member types, - - std::nullptr_t - - , and cv-qualified versions of these types are collectively called - - scalar types - - .... Scalar types, trivial class types, arrays of such types and cv-qualified versions of these types are collectively called - - trivial types - - . -

    +

    Arithmetic types, enumeration types, pointer types, pointer to member types, std::nullptr_t, and cv-qualified versions of these types are collectively called scalar types.... Scalar types, trivial class types, arrays of such types and cv-qualified versions of these types are collectively called trivial types.

    -

    - The C++ Standard, [class], paragraph 6, defines trivial class types as the following: -

    +

    The C++ Standard, [class], paragraph 6, defines trivial class types as the following:

    -

    - A - - trivially copyable class - - is a class that: - — has no non-trivial copy constructors, - — has no non-trivial move constructors, - — has no non-trivial copy assignment operators, - — has no non-trivial move assignment operators, and - — has a trivial destructor. - A - - trivial class - - is a class that has a default constructor, has no non-trivial default constructors, and is trivially copyable. [ - - Note - - : In particular, a trivially copyable or trivial class does not have virtual functions or virtual base classes. — - - end note - - ] -

    +

    A trivially copyable class is a class that: — has no non-trivial copy constructors, — has no non-trivial move constructors, — has no non-trivial copy assignment operators, — has no non-trivial move assignment operators, and — has a trivial destructor.A trivial class is a class that has a default constructor, has no non-trivial default constructors, and is trivially copyable. [Note: In particular, a trivially copyable or trivial class does not have virtual functions or virtual base classes. — end note]

    -

    - In this noncompliant code example, an object of type - - S - - is used to initialize the exception object that is later caught by an - - exception-declaration - - of type - - std::exception - - . The - - exception-declaration - - matches the exception object type, so the variable - - E - - is copy-initialized from the exception object, resulting in the exception object being sliced. Consequently, the output of this noncompliant code example is the implementation-defined value returned from calling - - std::exception::what() - - instead of - - "My custom exception" - - . -

    - - #include <exception> +

    In this noncompliant code example, an object of type S is used to initialize the exception object that is later caught by an exception-declaration of type std::exception. The exception-declaration matches the exception object type, so the variable E is copy-initialized from the exception object, resulting in the exception object being sliced. Consequently, the output of this noncompliant code example is the implementation-defined value returned from calling std::exception::what() instead of "My custom exception".

    + #include <exception> #include <iostream> -  + struct S : std::exception { const char *what() const noexcept override { return "My custom exception"; } }; -  + void f() { try { throw S(); } catch (std::exception e) { std::cout << e.what() << std::endl; } -} - +}
    -

    - In this compliant solution, the variable declared by the - - exception-declaration - - is an lvalue reference. The call to - - what() - - results in executing - - S::what() - - instead of - - std::exception::what() - - . -

    - - #include <exception> +

    In this compliant solution, the variable declared by the exception-declaration is an lvalue reference. The call to what() results in executing S::what() instead of std::exception::what().

    + #include <exception> #include <iostream> -  + struct S : std::exception { const char *what() const noexcept override { return "My custom exception"; } }; -  + void f() { try { throw S(); } catch (std::exception &e) { std::cout << e.what() << std::endl; } -} - +}
    -

    - Object slicing can result in abnormal program execution. This generally is not a problem for exceptions, but it can lead to unexpected behavior depending on the assumptions made by the exception handler. -

    +

    Object slicing can result in abnormal program execution. This generally is not a problem for exceptions, but it can lead to unexpected behavior depending on the assumptions made by the exception handler.

    Subclause 15.1, "Throwing an Exception" Subclause 18.8.1, "Class - - exception - + exception " Subclause 18.8.5, "Exception Propagation"
    @@ -264,14 +91,10 @@ void f() { Low @@ -304,9 +127,7 @@ void f() { 20.10 @@ -339,15 +158,11 @@ void f() { 3.9 @@ -382,9 +195,7 @@ void f() { 2021.4 @@ -398,9 +209,7 @@ void f() { @@ -470,18 +273,10 @@ void f() { @@ -496,9 +291,7 @@ void f() { 20.10 @@ -527,27 +316,10 @@ void f() {
    - - P3 - + P3 - - L3 - + L3
    - - catch-class-by-value - + catch-class-by-value Fully checked @@ -322,9 +143,7 @@ void f() { 7.2.0 - - CertC++-ERR61 - + CertC++-ERR61 - - cert-err61-cpp - + cert-err61-cpp Checked by - - clang-tidy - + clang-tidy ; also checks for VOID ERR09-CPP. Throw anonymous temporaries @@ -365,9 +180,7 @@ void f() { 2021.2 - - C++4031 - + C++4031 - - MISRA.CATCH.BY_VALUE - + MISRA.CATCH.BY_VALUE - - 455 S - + 455 S Fully implemented @@ -416,12 +225,8 @@ void f() { 2021.2 - - CERT_CPP-ERR61-a - - - CERT_CPP-ERR61-b - + CERT_CPP-ERR61-a + CERT_CPP-ERR61-b A class type exception shall always be caught by reference @@ -456,9 +261,7 @@ void f() { 4.4 - - 4031 - + 4031 - 7.16 + 7.17 - - - V746 - - , - - V816 - - + V746, V816 - - catch-class-by-value - + catch-class-by-value Fully checked @@ -514,11 +307,7 @@ void f() { 4.10 - - - S1044 - - + S1044
    -

    - Search for other - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for other vulnerabilities resulting from the violation of this rule on the CERT website.

    -

    - - This rule is a subset of - - OOP51-CPP. Do not slice derived objects. - - -

    +

    This rule is a subset of OOP51-CPP. Do not slice derived objects.

    diff --git a/cpp/cert/src/rules/ERR62-CPP/DetectErrorsWhenConvertingAStringToANumber-standard.qhelp b/cpp/cert/src/rules/ERR62-CPP/DetectErrorsWhenConvertingAStringToANumber-standard.qhelp index 3e12cc8f18..e9628787bf 100644 --- a/cpp/cert/src/rules/ERR62-CPP/DetectErrorsWhenConvertingAStringToANumber-standard.qhelp +++ b/cpp/cert/src/rules/ERR62-CPP/DetectErrorsWhenConvertingAStringToANumber-standard.qhelp @@ -1,159 +1,28 @@
    -

    - The process of parsing an integer or floating-point number from a string can produce many errors. The string might not contain a number. It might contain a number of the correct type that is out of range (such as an integer that is larger than - - INT_MAX - - ). The string may also contain extra information after the number, which may or may not be useful after the conversion. These error conditions must be detected and addressed when a string-to-number conversion is performed using a formatted input stream such as - - std::istream - - or the locale facet - - num_get<> - - . -

    -

    - When calling a formatted input stream function like - - istream::operator>>() - - , information about conversion errors is queried through the - - basic_ios::good() - - , - - basic_ios::bad() - - , and - - basic_ios::fail() - - inherited member functions or through exception handling if it is enabled on the stream object. -

    -

    - When calling - - num_get<>::get() - - , information about conversion errors is returned to the caller through the - - ios_base::iostate& - - argument. The C++ Standard, section [facet.num.get.virtuals], paragraph 3 [ - - ISO/IEC 14882-2014 - - ], in part, states the following: -

    +

    The process of parsing an integer or floating-point number from a string can produce many errors. The string might not contain a number. It might contain a number of the correct type that is out of range (such as an integer that is larger than INT_MAX). The string may also contain extra information after the number, which may or may not be useful after the conversion. These error conditions must be detected and addressed when a string-to-number conversion is performed using a formatted input stream such as std::istream or the locale facet num_get<>.

    +

    When calling a formatted input stream function like istream::operator>>(), information about conversion errors is queried through the basic_ios::good(), basic_ios::bad(), and basic_ios::fail() inherited member functions or through exception handling if it is enabled on the stream object.

    +

    When calling num_get<>::get(), information about conversion errors is returned to the caller through the ios_base::iostate& argument. The C++ Standard, section [facet.num.get.virtuals], paragraph 3 [ISO/IEC 14882-2014], in part, states the following:

    -

    - If the conversion function fails to convert the entire field, or if the field represents a value outside the range of representable values, - - ios_base::failbit - - is assigned to - - err - - . -

    +

    If the conversion function fails to convert the entire field, or if the field represents a value outside the range of representable values, ios_base::failbit is assigned to err.

    -

    - Always explicitly check the error state of a conversion from string to a numeric value (or handle the related exception, if applicable) instead of assuming the conversion results in a valid value. This rule is in addition to - - ERR34-C. Detect errors when converting a string to a number - - , which bans the use of conversion functions that do not perform conversion validation such as - - std::atoi() - - and - - std::scanf() - - from the C Standard Library. -

    +

    Always explicitly check the error state of a conversion from string to a numeric value (or handle the related exception, if applicable) instead of assuming the conversion results in a valid value. This rule is in addition to ERR34-C. Detect errors when converting a string to a number, which bans the use of conversion functions that do not perform conversion validation such as std::atoi() and std::scanf() from the C Standard Library.

    -

    - In this noncompliant code example, multiple numeric values are converted from the standard input stream. However, if the text received from the standard input stream cannot be converted into a numeric value that can be represented by an - - int - - , the resulting value stored into the variables - - i - - and - - j - - may be unexpected. -

    - - #include <iostream> +

    In this noncompliant code example, multiple numeric values are converted from the standard input stream. However, if the text received from the standard input stream cannot be converted into a numeric value that can be represented by an int, the resulting value stored into the variables i and j may be unexpected.

    + #include <iostream> void f() { int i, j; std::cin >> i >> j; // ... -} - -

    - For instance, if the text - - 12345678901234567890 - - is the first converted value read from the standard input stream, then - - i - - will have the value - - std::numeric_limits<int>::max() - - (per [facet.num.get.virtuals] paragraph 3), and - - j - - will be uninitialized (per [istream.formatted.arithmetic] paragraph 3). If the text - - abcdefg - - is the first converted value read from the standard input stream, then - - i - - will have the value - - 0 - - and - - j - - will remain uninitialized. -

    +}
    +

    For instance, if the text 12345678901234567890 is the first converted value read from the standard input stream, then i will have the value std::numeric_limits<int>::max() (per [facet.num.get.virtuals] paragraph 3), and j will be uninitialized (per [istream.formatted.arithmetic] paragraph 3). If the text abcdefg is the first converted value read from the standard input stream, then i will have the value 0 and j will remain uninitialized.

    -

    - In this compliant solution, exceptions are enabled so that any conversion failure results in an exception being thrown. However, this approach cannot distinguish between which values are valid and which values are invalid and must assume that all values are invalid. Both the - - badbit - - and - - failbit - - flags are set to ensure that conversion errors as well as loss of integrity with the stream are treated as exceptions. -

    - - #include <iostream> +

    In this compliant solution, exceptions are enabled so that any conversion failure results in an exception being thrown. However, this approach cannot distinguish between which values are valid and which values are invalid and must assume that all values are invalid. Both the badbit and failbit flags are set to ensure that conversion errors as well as loss of integrity with the stream are treated as exceptions.

    + #include <iostream> void f() { int i, j; @@ -165,23 +34,11 @@ void f() { } catch (std::istream::failure &E) { // Handle error } -} - +}
    -

    - In this compliant solution, each converted value read from the standard input stream is tested for validity before reading the next value in the sequence, allowing error recovery on a per-value basis. It checks - - std::istream::fail() - - to see if the failure bit was set due to a conversion failure or whether the bad bit was set due to a loss of integrity with the stream object. If a failure condition is encountered, it is cleared on the input stream and then characters are read and discarded until a - - ' ' - - (space) character occurs. The error handling in this case only works if a space character is what delimits the two numeric values to be converted. -

    - - #include <iostream> +

    In this compliant solution, each converted value read from the standard input stream is tested for validity before reading the next value in the sequence, allowing error recovery on a per-value basis. It checks std::istream::fail() to see if the failure bit was set due to a conversion failure or whether the bad bit was set due to a loss of integrity with the stream object. If a failure condition is encountered, it is cleared on the input stream and then characters are read and discarded until a ' ' (space) character occurs. The error handling in this case only works if a space character is what delimits the two numeric values to be converted.

    + #include <iostream> #include <limits> void f() { @@ -199,19 +56,12 @@ void f() { std::cin.clear(); std::cin.ignore(std::numeric_limits<std::streamsize>::max(), ' '); } -  + // ... -} - +}
    -

    - It is rare for a violation of this rule to result in a security - - vulnerability - - unless it occurs in security-sensitive code. However, violations of this rule can easily result in lost or misinterpreted data. -

    +

    It is rare for a violation of this rule to result in a security vulnerability unless it occurs in security-sensitive code. However, violations of this rule can easily result in lost or misinterpreted data.

    @@ -248,14 +98,10 @@ void f() { Medium @@ -288,9 +134,7 @@ void f() { 7.2.0 @@ -305,15 +149,11 @@ void f() { 3.9 @@ -324,21 +164,10 @@ void f() { @@ -374,11 +201,7 @@ void f() { 2021.4 @@ -393,9 +216,7 @@ void f() { 2021.2
    - - P4 - + P4 - - L3 - + L3
    - - CertC++-ERR62 - + CertC++-ERR62 - - cert-err34-c - + cert-err34-c Checked by - - clang-tidy - + clang-tidy ; only identifies use of unsafe C Standard Library functions corresponding to ERR34-C
    - 6.1p0 + 6.2p0 - - BADFUNC.ATOF - - BADFUNC.ATOI - - - BADFUNC.ATOF - - - BADFUNC.ATOF - - + BADFUNC.ATOFBADFUNC.ATOIBADFUNC.ATOFBADFUNC.ATOF Use of atof @@ -357,9 +186,7 @@ void f() { 2021.2 - - C++3161 - + C++3161 - - - CERT.ERR.CONV.STR_TO_NUM - - + CERT.ERR.CONV.STR_TO_NUM - - CERT_CPP-ERR62-a - + CERT_CPP-ERR62-a The library functions atof, atoi and atol from library stdlib.h shall not be used @@ -405,17 +226,7 @@ void f() {
    -

    - Search for other - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for other vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments-standard.qhelp b/cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments-standard.qhelp index f9997e79a2..cb9f3b81df 100644 --- a/cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments-standard.qhelp +++ b/cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments-standard.qhelp @@ -1,401 +1,115 @@
    -

    - In C++, modifying an object, calling a library I/O function, accessing a - - volatile - - -qualified value, or calling a function that performs one of these actions are ways to modify the state of the execution environment. These actions are called - - side effects - - . All relationships between value computations and side effects can be described in terms of sequencing of their evaluations. The C++ Standard, [intro.execution], paragraph 13 [ - - ISO/IEC 14882-2014 - - ], establishes three sequencing terms: -

    +

    In C++, modifying an object, calling a library I/O function, accessing a volatile-qualified value, or calling a function that performs one of these actions are ways to modify the state of the execution environment. These actions are called side effects. All relationships between value computations and side effects can be described in terms of sequencing of their evaluations. The C++ Standard, [intro.execution], paragraph 13 [ISO/IEC 14882-2014], establishes three sequencing terms:

    -

    - - Sequenced before - - is an asymmetric, transitive, pair-wise relation between evaluations executed by a single thread, which induces a partial order among those evaluations. Given any two evaluations - - A - - and - - B - - , if - - A - - is sequenced before - - B - - , then the execution of - - A - - shall precede the execution of - - B - - . If - - A - - is not sequenced before - - B - - and - - B - - is not sequenced before - - A - - , then - - A - - and - - B - - are - - unsequenced - - . [Note: The execution of unsequenced evaluations can overlap. — end note] Evaluations - - A - - and - - B - - are - - indeterminately sequenced - - when either - - A - - is sequenced before - - B - - or - - B - - is sequenced before - - A - - , but it is unspecified which. [Note: Indeterminately sequenced evaluations cannot overlap, but either could be executed first. — end note] -

    +

    Sequenced before is an asymmetric, transitive, pair-wise relation between evaluations executed by a single thread, which induces a partial order among those evaluations. Given any two evaluations A and B, if A is sequenced before B, then the execution of A shall precede the execution of B. If A is not sequenced before B and B is not sequenced before A, then A and B are unsequenced. [Note: The execution of unsequenced evaluations can overlap. — end note] Evaluations A and B are indeterminately sequenced when either A is sequenced before B or B is sequenced before A, but it is unspecified which. [Note: Indeterminately sequenced evaluations cannot overlap, but either could be executed first. — end note]

    -

    - Paragraph 15 further states (nonnormative text removed for brevity) the following: -

    +

    Paragraph 15 further states (nonnormative text removed for brevity) the following:

    -

    - Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced. ... The value computations of the operands of an operator are sequenced before the value computation of the result of the operator. If a side effect on a scalar object is unsequenced relative to either another side effect on the same scalar object or a value computation using the value of the same scalar object, and they are not potentially concurrent, the behavior is undefined. ... When calling a function (whether or not the function is inline), every value computation and side effect associated with any argument expression, or with the postfix expression designating the called function, is sequenced before execution of every expression or statement in the body of the called function. ... Every evaluation in the calling function (including other function calls) that is not otherwise specifically sequenced before or after the execution of the body of the called function is indeterminately sequenced with respect to the execution of the called function. Several contexts in C++ cause evaluation of a function call, even though no corresponding function call syntax appears in the translation unit. ... The sequencing constraints on the execution of the called function (as described above) are features of the function calls as evaluated, whatever the syntax of the expression that calls the function might be. -

    +

    Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced. ... The value computations of the operands of an operator are sequenced before the value computation of the result of the operator. If a side effect on a scalar object is unsequenced relative to either another side effect on the same scalar object or a value computation using the value of the same scalar object, and they are not potentially concurrent, the behavior is undefined. ... When calling a function (whether or not the function is inline), every value computation and side effect associated with any argument expression, or with the postfix expression designating the called function, is sequenced before execution of every expression or statement in the body of the called function. ... Every evaluation in the calling function (including other function calls) that is not otherwise specifically sequenced before or after the execution of the body of the called function is indeterminately sequenced with respect to the execution of the called function. Several contexts in C++ cause evaluation of a function call, even though no corresponding function call syntax appears in the translation unit. ... The sequencing constraints on the execution of the called function (as described above) are features of the function calls as evaluated, whatever the syntax of the expression that calls the function might be.

    -

    - Do not allow the same scalar object to appear in side effects or value computations in both halves of an unsequenced or indeterminately sequenced operation. -

    -

    - The following expressions have sequencing restrictions that deviate from the usual unsequenced ordering [ - - ISO/IEC 14882-2014 - - ]: -

    +

    Do not allow the same scalar object to appear in side effects or value computations in both halves of an unsequenced or indeterminately sequenced operation.

    +

    The following expressions have sequencing restrictions that deviate from the usual unsequenced ordering [ISO/IEC 14882-2014]:

      -
    • - In postfix - - ++ - - and - - -- - - expressions, the value computation is sequenced before the modification of the operand. ([expr.post.incr], paragraph 1) -
    • -
    • - In logical - - && - - expressions, if the second expression is evaluated, every value computation and side effect associated with the first expression is sequenced before every value computation and side effect associated with the second expression. ([expr.log.and], paragraph 2) -
    • -
    • - In logical - - || - - expressions, if the second expression is evaluated, every value computation and side effect associated with the first expression is sequenced before every value computation and side effect associated with the second expression. ([expr.log.or], paragraph 2) -
    • -
    • - In conditional - - ?: - - expressions, every value computation and side effect associated with the first expression is sequenced before every value computation and side effect associated with the second or third expression (whichever is evaluated). ([expr.cond], paragraph 1) -
    • -
    • - In assignment expressions (including compound assignments), the assignment is sequenced after the value computations of left and right operands and before the value computation of the assignment expression. ([expr.ass], paragraph 1) -
    • -
    • - In comma - - , - - expressions, every value computation and side effect associated with the left expression is sequenced before every value computation and side effect associated with the right expression. ([expr.comma], paragraph 1) -
    • -
    • - When evaluating initializer lists, the value computation and side effect associated with each - - initializer-clause - - is sequenced before every value computation and side effect associated with a subsequent - - initializer-clause - - . ([dcl.init.list], paragraph 4) -
    • -
    • - When a signal handler is executed as a result of a call to - - std::raise() - - , the execution of the handler is sequenced after the invocation of - - std::raise() - - and before its return. ([intro.execution], paragraph 6) -
    • -
    • - The completions of the destructors for all initialized objects with thread storage duration within a thread are sequenced before the initiation of the destructors of any object with static storage duration. ([basic.start.term], paragraph 1) -
    • -
    • - In a - - new-expression - - , initialization of an allocated object is sequenced before the value computation of the - - new-expression - - . ([expr.new], paragraph 18) -
    • -
    • - When a default constructor is called to initialize an element of an array and the constructor has at least one default argument, the destruction of every temporary created in a default argument is sequenced before the construction of the next array element, if any. ([class.temporary], paragraph 4) -
    • -
    • - The destruction of a temporary whose lifetime is not extended by being bound to a reference is sequenced before the destruction of every temporary that is constructed earlier in the same full-expression. ([class.temporary], paragraph 5) -
    • -
    • - Atomic memory ordering functions can explicitly determine the sequencing order for expressions. ([atomics.order] and [atomics.fences]) -
    • +
    • In postfix ++ and -- expressions, the value computation is sequenced before the modification of the operand. ([expr.post.incr], paragraph 1)
    • +
    • In logical && expressions, if the second expression is evaluated, every value computation and side effect associated with the first expression is sequenced before every value computation and side effect associated with the second expression. ([expr.log.and], paragraph 2)
    • +
    • In logical || expressions, if the second expression is evaluated, every value computation and side effect associated with the first expression is sequenced before every value computation and side effect associated with the second expression. ([expr.log.or], paragraph 2)
    • +
    • In conditional ?: expressions, every value computation and side effect associated with the first expression is sequenced before every value computation and side effect associated with the second or third expression (whichever is evaluated). ([expr.cond], paragraph 1)
    • +
    • In assignment expressions (including compound assignments), the assignment is sequenced after the value computations of left and right operands and before the value computation of the assignment expression. ([expr.ass], paragraph 1)
    • +
    • In comma , expressions, every value computation and side effect associated with the left expression is sequenced before every value computation and side effect associated with the right expression. ([expr.comma], paragraph 1)
    • +
    • When evaluating initializer lists, the value computation and side effect associated with each initializer-clause is sequenced before every value computation and side effect associated with a subsequent initializer-clause. ([dcl.init.list], paragraph 4)
    • +
    • When a signal handler is executed as a result of a call to std::raise(), the execution of the handler is sequenced after the invocation of std::raise() and before its return. ([intro.execution], paragraph 6)
    • +
    • The completions of the destructors for all initialized objects with thread storage duration within a thread are sequenced before the initiation of the destructors of any object with static storage duration. ([basic.start.term], paragraph 1)
    • +
    • In a new-expression, initialization of an allocated object is sequenced before the value computation of the new-expression. ([expr.new], paragraph 18)
    • +
    • When a default constructor is called to initialize an element of an array and the constructor has at least one default argument, the destruction of every temporary created in a default argument is sequenced before the construction of the next array element, if any. ([class.temporary], paragraph 4)
    • +
    • The destruction of a temporary whose lifetime is not extended by being bound to a reference is sequenced before the destruction of every temporary that is constructed earlier in the same full-expression. ([class.temporary], paragraph 5)
    • +
    • Atomic memory ordering functions can explicitly determine the sequencing order for expressions. ([atomics.order] and [atomics.fences])
    -

    - This rule means that statements such as -

    - - i = i + 1; +

    This rule means that statements such as

    + i = i + 1; a[i] = i; - -

    - have defined behavior, and statements such as the following do not. -

    - - // i is modified twice in the same full expression + +

    have defined behavior, and statements such as the following do not.

    + // i is modified twice in the same full expression i = ++i + 1; // i is read other than to determine the value to be stored -a[i++] = i; - -

    - Not all instances of a comma in C++ code denote use of the comma operator. For example, the comma between arguments in a function call is - - not - - the comma operator. Additionally, overloaded operators behave the same as a function call, with the operands to the operator acting as arguments to a function call. -

    +a[i++] = i; +
    +

    Not all instances of a comma in C++ code denote use of the comma operator. For example, the comma between arguments in a function call is not the comma operator. Additionally, overloaded operators behave the same as a function call, with the operands to the operator acting as arguments to a function call.

    -

    - In this noncompliant code example, - - i - - is evaluated more than once in an unsequenced manner, so the behavior of the expression is - - undefined - - . -

    - - void f(int i, const int *b) { +

    In this noncompliant code example, i is evaluated more than once in an unsequenced manner, so the behavior of the expression is undefined.

    + void f(int i, const int *b) { int a = i + b[++i]; // ... } - +
    -

    - These examples are independent of the order of evaluation of the operands and can each be interpreted in only one way. -

    - - void f(int i, const int *b) { +

    These examples are independent of the order of evaluation of the operands and can each be interpreted in only one way.

    + void f(int i, const int *b) { ++i; int a = i + b[i]; // ... } - - - void f(int i, const int *b) { + + void f(int i, const int *b) { int a = i + b[i + 1]; ++i; // ... } - +
    -

    - The call to - - func() - - in this noncompliant code example has - - undefined behavior - - because the argument expressions are unsequenced. -

    - - extern void func(int i, int j); +

    The call to func() in this noncompliant code example has undefined behavior because the argument expressions are unsequenced.

    + extern void func(int i, int j); void f(int i) { func(i++, i); } - -

    - The first (left) argument expression reads the value of - - i - - (to determine the value to be stored) and then modifies - - i - - . The second (right) argument expression reads the value of - - i - - , but not to determine the value to be stored in - - i - - . This additional attempt to read the value of - - i - - has - - undefined behavior - - . -

    +
    +

    The first (left) argument expression reads the value of i (to determine the value to be stored) and then modifies i. The second (right) argument expression reads the value of i, but not to determine the value to be stored in i. This additional attempt to read the value of i has undefined behavior.

    -

    - This compliant solution is appropriate when the programmer intends for both arguments to - - func() - - to be equivalent. -

    - - extern void func(int i, int j); +

    This compliant solution is appropriate when the programmer intends for both arguments to func() to be equivalent.

    + extern void func(int i, int j); void f(int i) { i++; func(i, i); } - -

    - This compliant solution is appropriate when the programmer intends for the second argument to be 1 greater than the first. -

    - - extern void func(int i, int j); + +

    This compliant solution is appropriate when the programmer intends for the second argument to be 1 greater than the first.

    + extern void func(int i, int j); void f(int i) { int j = i++; func(j, i); } - +
    -

    - This noncompliant code example is similar to the previous noncompliant code example. However, instead of calling a function directly, this code calls an overloaded - - operator<<() - - . Overloaded operators are equivalent to a function call and have the same restrictions regarding the sequencing of the function call arguments. This means that the operands are not evaluated left-to-right, but are unsequenced with respect to one another. Consequently, this noncompliant code example has undefined behavior. -

    - - #include <iostream> +

    This noncompliant code example is similar to the previous noncompliant code example. However, instead of calling a function directly, this code calls an overloaded operator<<(). Overloaded operators are equivalent to a function call and have the same restrictions regarding the sequencing of the function call arguments. This means that the operands are not evaluated left-to-right, but are unsequenced with respect to one another. Consequently, this noncompliant code example has undefined behavior.

    + #include <iostream> void f(int i) { std::cout << i++ << i << std::endl; -} - +}
    -

    - In this compliant solution, two calls are made to - - operator<<() - - , ensuring that the arguments are printed in a well-defined order. -

    - - #include <iostream> -  +

    In this compliant solution, two calls are made to operator<<(), ensuring that the arguments are printed in a well-defined order.

    + #include <iostream> + void f(int i) { std::cout << i++; std::cout << i << std::endl; -} - +}
    -

    - The order of evaluation for function arguments is unspecified. This noncompliant code example exhibits - - unspecified behavior - - but not - - undefined behavior - - . -

    - - extern void c(int i, int j); +

    The order of evaluation for function arguments is unspecified. This noncompliant code example exhibits unspecified behavior but not undefined behavior.

    + extern void c(int i, int j); int glob; int a() { @@ -410,61 +124,12 @@ int b() { void f() { c(a(), b()); } - -

    - The order in which - - a() - - and - - b() - - are called is unspecified; the only guarantee is that both - - a() - - and - - b() - - will be called before - - c() - - is called. If - - a() - - or - - b() - - rely on shared state when calculating their return value, as they do in this example, the resulting arguments passed to - - c() - - may differ between compilers or architectures. -

    +
    +

    The order in which a() and b() are called is unspecified; the only guarantee is that both a() and b() will be called before c() is called. If a() or b() rely on shared state when calculating their return value, as they do in this example, the resulting arguments passed to c() may differ between compilers or architectures.

    -

    - In this compliant solution, the order of evaluation for - - a() - - and - - b() - - is fixed, and so no - - unspecified behavior - - occurs. -

    - - extern void c(int i, int j); +

    In this compliant solution, the order of evaluation for a() and b() is fixed, and so no unspecified behavior occurs.

    + extern void c(int i, int j); int glob; int a() { @@ -484,14 +149,10 @@ void f() { c(a_val, b_val); } - +
    -

    - Attempting to modify an object in an unsequenced or indeterminately sequenced evaluation may cause that object to take on an unexpected value, which can lead to - unexpected program behavior - . -

    +

    Attempting to modify an object in an unsequenced or indeterminately sequenced evaluation may cause that object to take on an unexpected value, which can lead to unexpected program behavior.

    @@ -528,14 +189,10 @@ void f() { Medium @@ -568,9 +225,7 @@ void f() { 7.2.0 @@ -585,9 +240,7 @@ void f() { 3.9 @@ -617,9 +270,7 @@ void f() { v7.5.0 @@ -671,9 +318,7 @@ void f() { 2021.2 @@ -688,31 +333,11 @@ void f() { 2021.4 @@ -726,18 +351,10 @@ void f() { @@ -823,20 +426,12 @@ void f() { @@ -851,11 +446,7 @@ void f() { 4.10
    - - P8 - + P8 - - L2 - + L2
    - - CertC++-EXP50 - + CertC++-EXP50 - - -Wunsequenced - + -Wunsequenced Can detect simple violations of this rule where path-sensitive analysis is not required @@ -604,7 +257,7 @@ void f() { - Can detect simple violations of this rule. It needs to examine each expression and make sure that no variable is modified twice in the expression. It also must check that no variable is modified once, then read elsewhere, with the single exception that a variable may appear on both the left and right of an assignment operator + Can detect simple violations of this rule. It needs to examine each expression and make sure that no variable is modified twice in the expression. It also must check that no variable is modified once, then read elsewhere, with the single exception that a variable may appear on both the left and right of an assignment operator
    - - EVALUATION_ORDER - + EVALUATION_ORDER Can detect the specific instance where a statement contains multiple side effects on the same value with an undefined evaluation order because, with different compiler flags or different compilers or platforms, the statement may behave differently @@ -635,9 +286,7 @@ void f() { 1.2 - - CC2.EXP30 - + CC2.EXP30 Fully implemented @@ -655,9 +304,7 @@ void f() { Can detect violations of this rule when the - - -Wsequence-point - + -Wsequence-point flag is used
    - - C++3220, C++3221, C++3222, C++3223, C++3228 - + C++3220, C++3221, C++3222, C++3223, C++3228 - - - PORTING.VAR.EFFECTS - - - - - MISRA.EXPR.PARENS - - - - - MISRA.EXPR.PARENS.INSUFFICIENT - - - - - MISRA.EXPR.PARENS.REDUNDANT - - - - - MISRA.INCR_DECR.OTHER - - + PORTING.VAR.EFFECTS + MISRA.EXPR.PARENS + MISRA.EXPR.PARENS.INSUFFICIENT + MISRA.EXPR.PARENS.REDUNDANT + MISRA.INCR_DECR.OTHER - - 35 D - - - , 1 Q - - - , 9 S - - - , 134 S, 67 D, 72 D - + 35 D + , 1 Q + , 9 S + , 134 S, 67 D, 72 D Partially implemented @@ -753,24 +370,12 @@ void f() { 2021.2 - - CERT_CPP-EXP50-a - - - CERT_CPP-EXP50-b - - - CERT_CPP-EXP50-c - - - CERT_CPP-EXP50-d - - - CERT_CPP-EXP50-e - - - CERT_CPP-EXP50-f - + CERT_CPP-EXP50-a + CERT_CPP-EXP50-b + CERT_CPP-EXP50-c + CERT_CPP-EXP50-d + CERT_CPP-EXP50-e + CERT_CPP-EXP50-f The value of an expression shall be the same under any order of evaluation that the standard permits @@ -809,9 +414,7 @@ void f() { 4.4 - - 3220, 3221, 3222, 3223, 3228 - + 3220, 3221, 3222, 3223, 3228 - 7.16 + 7.17 - - V521 - - - + V521 , - - - V708 - - + V708 - - - IncAndDecMixedWithOtherOperators - - + IncAndDecMixedWithOtherOperators Partially implemented @@ -878,17 +469,7 @@ void f() {
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfScalarObjectEvaluationForSideEffects-standard.qhelp b/cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfScalarObjectEvaluationForSideEffects-standard.qhelp index f9997e79a2..cb9f3b81df 100644 --- a/cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfScalarObjectEvaluationForSideEffects-standard.qhelp +++ b/cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfScalarObjectEvaluationForSideEffects-standard.qhelp @@ -1,401 +1,115 @@
    -

    - In C++, modifying an object, calling a library I/O function, accessing a - - volatile - - -qualified value, or calling a function that performs one of these actions are ways to modify the state of the execution environment. These actions are called - - side effects - - . All relationships between value computations and side effects can be described in terms of sequencing of their evaluations. The C++ Standard, [intro.execution], paragraph 13 [ - - ISO/IEC 14882-2014 - - ], establishes three sequencing terms: -

    +

    In C++, modifying an object, calling a library I/O function, accessing a volatile-qualified value, or calling a function that performs one of these actions are ways to modify the state of the execution environment. These actions are called side effects. All relationships between value computations and side effects can be described in terms of sequencing of their evaluations. The C++ Standard, [intro.execution], paragraph 13 [ISO/IEC 14882-2014], establishes three sequencing terms:

    -

    - - Sequenced before - - is an asymmetric, transitive, pair-wise relation between evaluations executed by a single thread, which induces a partial order among those evaluations. Given any two evaluations - - A - - and - - B - - , if - - A - - is sequenced before - - B - - , then the execution of - - A - - shall precede the execution of - - B - - . If - - A - - is not sequenced before - - B - - and - - B - - is not sequenced before - - A - - , then - - A - - and - - B - - are - - unsequenced - - . [Note: The execution of unsequenced evaluations can overlap. — end note] Evaluations - - A - - and - - B - - are - - indeterminately sequenced - - when either - - A - - is sequenced before - - B - - or - - B - - is sequenced before - - A - - , but it is unspecified which. [Note: Indeterminately sequenced evaluations cannot overlap, but either could be executed first. — end note] -

    +

    Sequenced before is an asymmetric, transitive, pair-wise relation between evaluations executed by a single thread, which induces a partial order among those evaluations. Given any two evaluations A and B, if A is sequenced before B, then the execution of A shall precede the execution of B. If A is not sequenced before B and B is not sequenced before A, then A and B are unsequenced. [Note: The execution of unsequenced evaluations can overlap. — end note] Evaluations A and B are indeterminately sequenced when either A is sequenced before B or B is sequenced before A, but it is unspecified which. [Note: Indeterminately sequenced evaluations cannot overlap, but either could be executed first. — end note]

    -

    - Paragraph 15 further states (nonnormative text removed for brevity) the following: -

    +

    Paragraph 15 further states (nonnormative text removed for brevity) the following:

    -

    - Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced. ... The value computations of the operands of an operator are sequenced before the value computation of the result of the operator. If a side effect on a scalar object is unsequenced relative to either another side effect on the same scalar object or a value computation using the value of the same scalar object, and they are not potentially concurrent, the behavior is undefined. ... When calling a function (whether or not the function is inline), every value computation and side effect associated with any argument expression, or with the postfix expression designating the called function, is sequenced before execution of every expression or statement in the body of the called function. ... Every evaluation in the calling function (including other function calls) that is not otherwise specifically sequenced before or after the execution of the body of the called function is indeterminately sequenced with respect to the execution of the called function. Several contexts in C++ cause evaluation of a function call, even though no corresponding function call syntax appears in the translation unit. ... The sequencing constraints on the execution of the called function (as described above) are features of the function calls as evaluated, whatever the syntax of the expression that calls the function might be. -

    +

    Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced. ... The value computations of the operands of an operator are sequenced before the value computation of the result of the operator. If a side effect on a scalar object is unsequenced relative to either another side effect on the same scalar object or a value computation using the value of the same scalar object, and they are not potentially concurrent, the behavior is undefined. ... When calling a function (whether or not the function is inline), every value computation and side effect associated with any argument expression, or with the postfix expression designating the called function, is sequenced before execution of every expression or statement in the body of the called function. ... Every evaluation in the calling function (including other function calls) that is not otherwise specifically sequenced before or after the execution of the body of the called function is indeterminately sequenced with respect to the execution of the called function. Several contexts in C++ cause evaluation of a function call, even though no corresponding function call syntax appears in the translation unit. ... The sequencing constraints on the execution of the called function (as described above) are features of the function calls as evaluated, whatever the syntax of the expression that calls the function might be.

    -

    - Do not allow the same scalar object to appear in side effects or value computations in both halves of an unsequenced or indeterminately sequenced operation. -

    -

    - The following expressions have sequencing restrictions that deviate from the usual unsequenced ordering [ - - ISO/IEC 14882-2014 - - ]: -

    +

    Do not allow the same scalar object to appear in side effects or value computations in both halves of an unsequenced or indeterminately sequenced operation.

    +

    The following expressions have sequencing restrictions that deviate from the usual unsequenced ordering [ISO/IEC 14882-2014]:

      -
    • - In postfix - - ++ - - and - - -- - - expressions, the value computation is sequenced before the modification of the operand. ([expr.post.incr], paragraph 1) -
    • -
    • - In logical - - && - - expressions, if the second expression is evaluated, every value computation and side effect associated with the first expression is sequenced before every value computation and side effect associated with the second expression. ([expr.log.and], paragraph 2) -
    • -
    • - In logical - - || - - expressions, if the second expression is evaluated, every value computation and side effect associated with the first expression is sequenced before every value computation and side effect associated with the second expression. ([expr.log.or], paragraph 2) -
    • -
    • - In conditional - - ?: - - expressions, every value computation and side effect associated with the first expression is sequenced before every value computation and side effect associated with the second or third expression (whichever is evaluated). ([expr.cond], paragraph 1) -
    • -
    • - In assignment expressions (including compound assignments), the assignment is sequenced after the value computations of left and right operands and before the value computation of the assignment expression. ([expr.ass], paragraph 1) -
    • -
    • - In comma - - , - - expressions, every value computation and side effect associated with the left expression is sequenced before every value computation and side effect associated with the right expression. ([expr.comma], paragraph 1) -
    • -
    • - When evaluating initializer lists, the value computation and side effect associated with each - - initializer-clause - - is sequenced before every value computation and side effect associated with a subsequent - - initializer-clause - - . ([dcl.init.list], paragraph 4) -
    • -
    • - When a signal handler is executed as a result of a call to - - std::raise() - - , the execution of the handler is sequenced after the invocation of - - std::raise() - - and before its return. ([intro.execution], paragraph 6) -
    • -
    • - The completions of the destructors for all initialized objects with thread storage duration within a thread are sequenced before the initiation of the destructors of any object with static storage duration. ([basic.start.term], paragraph 1) -
    • -
    • - In a - - new-expression - - , initialization of an allocated object is sequenced before the value computation of the - - new-expression - - . ([expr.new], paragraph 18) -
    • -
    • - When a default constructor is called to initialize an element of an array and the constructor has at least one default argument, the destruction of every temporary created in a default argument is sequenced before the construction of the next array element, if any. ([class.temporary], paragraph 4) -
    • -
    • - The destruction of a temporary whose lifetime is not extended by being bound to a reference is sequenced before the destruction of every temporary that is constructed earlier in the same full-expression. ([class.temporary], paragraph 5) -
    • -
    • - Atomic memory ordering functions can explicitly determine the sequencing order for expressions. ([atomics.order] and [atomics.fences]) -
    • +
    • In postfix ++ and -- expressions, the value computation is sequenced before the modification of the operand. ([expr.post.incr], paragraph 1)
    • +
    • In logical && expressions, if the second expression is evaluated, every value computation and side effect associated with the first expression is sequenced before every value computation and side effect associated with the second expression. ([expr.log.and], paragraph 2)
    • +
    • In logical || expressions, if the second expression is evaluated, every value computation and side effect associated with the first expression is sequenced before every value computation and side effect associated with the second expression. ([expr.log.or], paragraph 2)
    • +
    • In conditional ?: expressions, every value computation and side effect associated with the first expression is sequenced before every value computation and side effect associated with the second or third expression (whichever is evaluated). ([expr.cond], paragraph 1)
    • +
    • In assignment expressions (including compound assignments), the assignment is sequenced after the value computations of left and right operands and before the value computation of the assignment expression. ([expr.ass], paragraph 1)
    • +
    • In comma , expressions, every value computation and side effect associated with the left expression is sequenced before every value computation and side effect associated with the right expression. ([expr.comma], paragraph 1)
    • +
    • When evaluating initializer lists, the value computation and side effect associated with each initializer-clause is sequenced before every value computation and side effect associated with a subsequent initializer-clause. ([dcl.init.list], paragraph 4)
    • +
    • When a signal handler is executed as a result of a call to std::raise(), the execution of the handler is sequenced after the invocation of std::raise() and before its return. ([intro.execution], paragraph 6)
    • +
    • The completions of the destructors for all initialized objects with thread storage duration within a thread are sequenced before the initiation of the destructors of any object with static storage duration. ([basic.start.term], paragraph 1)
    • +
    • In a new-expression, initialization of an allocated object is sequenced before the value computation of the new-expression. ([expr.new], paragraph 18)
    • +
    • When a default constructor is called to initialize an element of an array and the constructor has at least one default argument, the destruction of every temporary created in a default argument is sequenced before the construction of the next array element, if any. ([class.temporary], paragraph 4)
    • +
    • The destruction of a temporary whose lifetime is not extended by being bound to a reference is sequenced before the destruction of every temporary that is constructed earlier in the same full-expression. ([class.temporary], paragraph 5)
    • +
    • Atomic memory ordering functions can explicitly determine the sequencing order for expressions. ([atomics.order] and [atomics.fences])
    -

    - This rule means that statements such as -

    - - i = i + 1; +

    This rule means that statements such as

    + i = i + 1; a[i] = i; - -

    - have defined behavior, and statements such as the following do not. -

    - - // i is modified twice in the same full expression + +

    have defined behavior, and statements such as the following do not.

    + // i is modified twice in the same full expression i = ++i + 1; // i is read other than to determine the value to be stored -a[i++] = i; - -

    - Not all instances of a comma in C++ code denote use of the comma operator. For example, the comma between arguments in a function call is - - not - - the comma operator. Additionally, overloaded operators behave the same as a function call, with the operands to the operator acting as arguments to a function call. -

    +a[i++] = i; +
    +

    Not all instances of a comma in C++ code denote use of the comma operator. For example, the comma between arguments in a function call is not the comma operator. Additionally, overloaded operators behave the same as a function call, with the operands to the operator acting as arguments to a function call.

    -

    - In this noncompliant code example, - - i - - is evaluated more than once in an unsequenced manner, so the behavior of the expression is - - undefined - - . -

    - - void f(int i, const int *b) { +

    In this noncompliant code example, i is evaluated more than once in an unsequenced manner, so the behavior of the expression is undefined.

    + void f(int i, const int *b) { int a = i + b[++i]; // ... } - +
    -

    - These examples are independent of the order of evaluation of the operands and can each be interpreted in only one way. -

    - - void f(int i, const int *b) { +

    These examples are independent of the order of evaluation of the operands and can each be interpreted in only one way.

    + void f(int i, const int *b) { ++i; int a = i + b[i]; // ... } - - - void f(int i, const int *b) { + + void f(int i, const int *b) { int a = i + b[i + 1]; ++i; // ... } - +
    -

    - The call to - - func() - - in this noncompliant code example has - - undefined behavior - - because the argument expressions are unsequenced. -

    - - extern void func(int i, int j); +

    The call to func() in this noncompliant code example has undefined behavior because the argument expressions are unsequenced.

    + extern void func(int i, int j); void f(int i) { func(i++, i); } - -

    - The first (left) argument expression reads the value of - - i - - (to determine the value to be stored) and then modifies - - i - - . The second (right) argument expression reads the value of - - i - - , but not to determine the value to be stored in - - i - - . This additional attempt to read the value of - - i - - has - - undefined behavior - - . -

    +
    +

    The first (left) argument expression reads the value of i (to determine the value to be stored) and then modifies i. The second (right) argument expression reads the value of i, but not to determine the value to be stored in i. This additional attempt to read the value of i has undefined behavior.

    -

    - This compliant solution is appropriate when the programmer intends for both arguments to - - func() - - to be equivalent. -

    - - extern void func(int i, int j); +

    This compliant solution is appropriate when the programmer intends for both arguments to func() to be equivalent.

    + extern void func(int i, int j); void f(int i) { i++; func(i, i); } - -

    - This compliant solution is appropriate when the programmer intends for the second argument to be 1 greater than the first. -

    - - extern void func(int i, int j); + +

    This compliant solution is appropriate when the programmer intends for the second argument to be 1 greater than the first.

    + extern void func(int i, int j); void f(int i) { int j = i++; func(j, i); } - +
    -

    - This noncompliant code example is similar to the previous noncompliant code example. However, instead of calling a function directly, this code calls an overloaded - - operator<<() - - . Overloaded operators are equivalent to a function call and have the same restrictions regarding the sequencing of the function call arguments. This means that the operands are not evaluated left-to-right, but are unsequenced with respect to one another. Consequently, this noncompliant code example has undefined behavior. -

    - - #include <iostream> +

    This noncompliant code example is similar to the previous noncompliant code example. However, instead of calling a function directly, this code calls an overloaded operator<<(). Overloaded operators are equivalent to a function call and have the same restrictions regarding the sequencing of the function call arguments. This means that the operands are not evaluated left-to-right, but are unsequenced with respect to one another. Consequently, this noncompliant code example has undefined behavior.

    + #include <iostream> void f(int i) { std::cout << i++ << i << std::endl; -} - +}
    -

    - In this compliant solution, two calls are made to - - operator<<() - - , ensuring that the arguments are printed in a well-defined order. -

    - - #include <iostream> -  +

    In this compliant solution, two calls are made to operator<<(), ensuring that the arguments are printed in a well-defined order.

    + #include <iostream> + void f(int i) { std::cout << i++; std::cout << i << std::endl; -} - +}
    -

    - The order of evaluation for function arguments is unspecified. This noncompliant code example exhibits - - unspecified behavior - - but not - - undefined behavior - - . -

    - - extern void c(int i, int j); +

    The order of evaluation for function arguments is unspecified. This noncompliant code example exhibits unspecified behavior but not undefined behavior.

    + extern void c(int i, int j); int glob; int a() { @@ -410,61 +124,12 @@ int b() { void f() { c(a(), b()); } - -

    - The order in which - - a() - - and - - b() - - are called is unspecified; the only guarantee is that both - - a() - - and - - b() - - will be called before - - c() - - is called. If - - a() - - or - - b() - - rely on shared state when calculating their return value, as they do in this example, the resulting arguments passed to - - c() - - may differ between compilers or architectures. -

    +
    +

    The order in which a() and b() are called is unspecified; the only guarantee is that both a() and b() will be called before c() is called. If a() or b() rely on shared state when calculating their return value, as they do in this example, the resulting arguments passed to c() may differ between compilers or architectures.

    -

    - In this compliant solution, the order of evaluation for - - a() - - and - - b() - - is fixed, and so no - - unspecified behavior - - occurs. -

    - - extern void c(int i, int j); +

    In this compliant solution, the order of evaluation for a() and b() is fixed, and so no unspecified behavior occurs.

    + extern void c(int i, int j); int glob; int a() { @@ -484,14 +149,10 @@ void f() { c(a_val, b_val); } - +
    -

    - Attempting to modify an object in an unsequenced or indeterminately sequenced evaluation may cause that object to take on an unexpected value, which can lead to - unexpected program behavior - . -

    +

    Attempting to modify an object in an unsequenced or indeterminately sequenced evaluation may cause that object to take on an unexpected value, which can lead to unexpected program behavior.

    @@ -528,14 +189,10 @@ void f() { Medium @@ -568,9 +225,7 @@ void f() { 7.2.0 @@ -585,9 +240,7 @@ void f() { 3.9 @@ -617,9 +270,7 @@ void f() { v7.5.0 @@ -671,9 +318,7 @@ void f() { 2021.2 @@ -688,31 +333,11 @@ void f() { 2021.4 @@ -726,18 +351,10 @@ void f() { @@ -823,20 +426,12 @@ void f() { @@ -851,11 +446,7 @@ void f() { 4.10
    - - P8 - + P8 - - L2 - + L2
    - - CertC++-EXP50 - + CertC++-EXP50 - - -Wunsequenced - + -Wunsequenced Can detect simple violations of this rule where path-sensitive analysis is not required @@ -604,7 +257,7 @@ void f() { - Can detect simple violations of this rule. It needs to examine each expression and make sure that no variable is modified twice in the expression. It also must check that no variable is modified once, then read elsewhere, with the single exception that a variable may appear on both the left and right of an assignment operator + Can detect simple violations of this rule. It needs to examine each expression and make sure that no variable is modified twice in the expression. It also must check that no variable is modified once, then read elsewhere, with the single exception that a variable may appear on both the left and right of an assignment operator
    - - EVALUATION_ORDER - + EVALUATION_ORDER Can detect the specific instance where a statement contains multiple side effects on the same value with an undefined evaluation order because, with different compiler flags or different compilers or platforms, the statement may behave differently @@ -635,9 +286,7 @@ void f() { 1.2 - - CC2.EXP30 - + CC2.EXP30 Fully implemented @@ -655,9 +304,7 @@ void f() { Can detect violations of this rule when the - - -Wsequence-point - + -Wsequence-point flag is used
    - - C++3220, C++3221, C++3222, C++3223, C++3228 - + C++3220, C++3221, C++3222, C++3223, C++3228 - - - PORTING.VAR.EFFECTS - - - - - MISRA.EXPR.PARENS - - - - - MISRA.EXPR.PARENS.INSUFFICIENT - - - - - MISRA.EXPR.PARENS.REDUNDANT - - - - - MISRA.INCR_DECR.OTHER - - + PORTING.VAR.EFFECTS + MISRA.EXPR.PARENS + MISRA.EXPR.PARENS.INSUFFICIENT + MISRA.EXPR.PARENS.REDUNDANT + MISRA.INCR_DECR.OTHER - - 35 D - - - , 1 Q - - - , 9 S - - - , 134 S, 67 D, 72 D - + 35 D + , 1 Q + , 9 S + , 134 S, 67 D, 72 D Partially implemented @@ -753,24 +370,12 @@ void f() { 2021.2 - - CERT_CPP-EXP50-a - - - CERT_CPP-EXP50-b - - - CERT_CPP-EXP50-c - - - CERT_CPP-EXP50-d - - - CERT_CPP-EXP50-e - - - CERT_CPP-EXP50-f - + CERT_CPP-EXP50-a + CERT_CPP-EXP50-b + CERT_CPP-EXP50-c + CERT_CPP-EXP50-d + CERT_CPP-EXP50-e + CERT_CPP-EXP50-f The value of an expression shall be the same under any order of evaluation that the standard permits @@ -809,9 +414,7 @@ void f() { 4.4 - - 3220, 3221, 3222, 3223, 3228 - + 3220, 3221, 3222, 3223, 3228 - 7.16 + 7.17 - - V521 - - - + V521 , - - - V708 - - + V708 - - - IncAndDecMixedWithOtherOperators - - + IncAndDecMixedWithOtherOperators Partially implemented @@ -878,17 +469,7 @@ void f() {
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfScalarObjectEvaluationForSideEffects.ql b/cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfScalarObjectEvaluationForSideEffects.ql index 65fc502937..1ddb315506 100644 --- a/cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfScalarObjectEvaluationForSideEffects.ql +++ b/cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfScalarObjectEvaluationForSideEffects.ql @@ -16,6 +16,8 @@ import codingstandards.cpp.cert import codingstandards.cpp.SideEffect import codingstandards.cpp.Ordering import codingstandards.cpp.orderofevaluation.VariableAccessOrdering +import codingstandards.cpp.Expr +import codingstandards.cpp.Variable from VariableAccessInFullExpressionOrdering config, FullExpr e, ScalarVariable v, VariableEffect ve, diff --git a/cpp/cert/src/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType-standard.qhelp b/cpp/cert/src/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType-standard.qhelp index 17a474ce5d..dc793383a4 100644 --- a/cpp/cert/src/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType-standard.qhelp +++ b/cpp/cert/src/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType-standard.qhelp @@ -1,64 +1,15 @@
    -

    - The C++ Standard, [expr.delete], paragraph 3 [ - - ISO/IEC 14882-2014 - - ], states the following: -

    +

    The C++ Standard, [expr.delete], paragraph 3 [ISO/IEC 14882-2014], states the following:

    -

    - In the first alternative ( - - delete object - - ), if the static type of the object to be deleted is different from its dynamic type, the static type shall be a base class of the dynamic type of the object to be deleted and the static type shall have a virtual destructor or the behavior is undefined. In the second alternative ( - - delete array - - ) if the dynamic type of the object to be deleted differs from its static type, the behavior is undefined. -

    +

    In the first alternative (delete object), if the static type of the object to be deleted is different from its dynamic type, the static type shall be a base class of the dynamic type of the object to be deleted and the static type shall have a virtual destructor or the behavior is undefined. In the second alternative (delete array) if the dynamic type of the object to be deleted differs from its static type, the behavior is undefined.

    -

    - Do not delete an array object through a static pointer type that differs from the dynamic pointer type of the object. Deleting an array through a pointer to the incorrect type results in - - undefined behavior - - . -

    +

    Do not delete an array object through a static pointer type that differs from the dynamic pointer type of the object. Deleting an array through a pointer to the incorrect type results in undefined behavior.

    -

    - In this noncompliant code example, an array of - - Derived - - objects is created and the pointer is stored in a - - Base * - - . Despite - - Base::~Base - - () being declared virtual, it still results in - - undefined behavior - - . Further, attempting to perform pointer arithmetic on the static type - - Base * - - violates - - CTR56-CPP. Do not use pointer arithmetic on polymorphic objects - - . -

    - - struct Base { +

    In this noncompliant code example, an array of Derived objects is created and the pointer is stored in a Base *. Despite Base::~Base() being declared virtual, it still results in undefined behavior. Further, attempting to perform pointer arithmetic on the static type Base * violates CTR56-CPP. Do not use pointer arithmetic on polymorphic objects.

    + struct Base { virtual ~Base() = default; }; @@ -68,27 +19,11 @@ void f() { Base *b = new Derived[10]; // ... delete [] b; -} - +}
    -

    - In this compliant solution, the static type of - - b - - is - - Derived * - - , which removes the - - undefined behavior - - when indexing into the array as well as when deleting the pointer. -

    - - struct Base { +

    In this compliant solution, the static type of b is Derived *, which removes the undefined behavior when indexing into the array as well as when deleting the pointer.

    + struct Base { virtual ~Base() = default; }; @@ -98,13 +33,10 @@ void f() { Derived *b = new Derived[10]; // ... delete [] b; -} - +}
    -

    - Attempting to destroy an array of polymorphic objects through the incorrect static type is undefined behavior. In practice, potential consequences include abnormal program execution and memory leaks. -

    +

    Attempting to destroy an array of polymorphic objects through the incorrect static type is undefined behavior. In practice, potential consequences include abnormal program execution and memory leaks.

    @@ -141,14 +73,10 @@ void f() { Medium @@ -181,19 +109,13 @@ void f() { 3.9 @@ -206,9 +128,7 @@ void f() { 2021.2 @@ -223,11 +143,7 @@ void f() { 2021.4 @@ -242,9 +158,7 @@ void f() { 2021.2
    - - P2 - + P2 - - L3 - + L3
    - - -analyzer-checker=cplusplus - + -analyzer-checker=cplusplus Checked with - - clang -cc1 - + clang -cc1 or (preferably) - - scan-build - + scan-build
    - - C++3166 - + C++3166 - - - CERT.EXPR.DELETE_ARR.BASE_PTR - - + CERT.EXPR.DELETE_ARR.BASE_PTR - - CERT_CPP-EXP51-a - + CERT_CPP-EXP51-a Do not treat arrays polymorphically @@ -268,17 +182,7 @@ void f() {
    -

    - Search for other - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for other vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclTypeOperand-standard.qhelp b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclTypeOperand-standard.qhelp index 258c817654..efc279dec8 100644 --- a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclTypeOperand-standard.qhelp +++ b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclTypeOperand-standard.qhelp @@ -1,194 +1,64 @@
    -

    - Some expressions involve operands that are - - unevaluated - - . The C++ Standard, [expr], paragraph 8 - [ - - ISO/IEC 14882-2014 - - ] states the following - : -

    +

    Some expressions involve operands that are unevaluated. The C++ Standard, [expr], paragraph 8 [ISO/IEC 14882-2014] states the following:

    -

    - In some contexts, - - unevaluated operands - - appear. An unevaluated operand is not evaluated. An unevaluated operand is considered a full-expression. [Note: In an unevaluated operand, a non-static class member may be named (5.1) and naming of objects or functions does not, by itself, require that a definition be provided. — end note] -

    +

    In some contexts, unevaluated operands appear. An unevaluated operand is not evaluated. An unevaluated operand is considered a full-expression. [Note: In an unevaluated operand, a non-static class member may be named (5.1) and naming of objects or functions does not, by itself, require that a definition be provided. — end note]

    -

    - The following expressions do not evaluate their operands: - - sizeof() - - , - - typeid() - - , - - noexcept() - - , - - decltype() - - , and - - declval() - - . -

    -

    - Because an unevaluated operand in an expression is not evaluated, no side effects from that operand are triggered. Reliance on those side effects will result in unexpected behavior. Do not rely on side effects in unevaluated operands. -

    -

    - Unevaluated expression operands are used when the declaration of an object is required but the definition of the object is not. For instance, in the following example, the function - - f() - - is overloaded, relying on the unevaluated expression operand to select the desired overload, which is then used to determine the result of the - - sizeof() - - expression. -

    - - int f(int); +

    The following expressions do not evaluate their operands: sizeof(), typeid(), noexcept(), decltype(), and declval().

    +

    Because an unevaluated operand in an expression is not evaluated, no side effects from that operand are triggered. Reliance on those side effects will result in unexpected behavior. Do not rely on side effects in unevaluated operands.

    +

    Unevaluated expression operands are used when the declaration of an object is required but the definition of the object is not. For instance, in the following example, the function f() is overloaded, relying on the unevaluated expression operand to select the desired overload, which is then used to determine the result of the sizeof() expression.

    + int f(int); double f(double); -size_t size = sizeof(f(0)); - -

    - Such a use does not rely on the side effects of - - f() - - and consequently conforms to this guideline. -

    +size_t size = sizeof(f(0));
    +

    Such a use does not rely on the side effects of f() and consequently conforms to this guideline.

    -

    - In this noncompliant code example, the expression - - a++ - - is not evaluated. -

    - - #include <iostream> +

    In this noncompliant code example, the expression a++ is not evaluated.

    + #include <iostream> void f() { int a = 14; int b = sizeof(a++); std::cout << a << ", " << b << std::endl; -} - -

    - Consequently, the value of - - a - - after - - b - - has been initialized is 14. -

    +}
    +

    Consequently, the value of a after b has been initialized is 14.

    -

    - In this compliant solution, the variable - - a - - is incremented outside of the - - sizeof - - operator. -

    - - #include <iostream> +

    In this compliant solution, the variable a is incremented outside of the sizeof operator.

    + #include <iostream> void f() { int a = 14; int b = sizeof(a); ++a; std::cout << a << ", " << b << std::endl; -} - +}
    -

    - In this noncompliant code example, the expression - - i++ - - is not evaluated within the - - decltype - - specifier. -

    - - #include <iostream> +

    In this noncompliant code example, the expression i++ is not evaluated within the decltype specifier.

    + #include <iostream> void f() { int i = 0; decltype(i++) h = 12; std::cout << i; -} - -

    - Consequently, the value of - i - remains 0. -

    +}
    +

    Consequently, the value of i remains 0.

    -

    - In this compliant solution, - - i - - is incremented outside of the - - decltype - - specifier so that it is evaluated as desired. -

    - - #include <iostream> +

    In this compliant solution, i is incremented outside of the decltype specifier so that it is evaluated as desired.

    + #include <iostream> void f() { int i = 0; decltype(i) h = 12; ++i; std::cout << i; -} - +}
    -

    - - EXP52-CPP-EX1: - - It is permissible for an expression with side effects to be used as an unevaluated operand in a macro definition or - - SFINAE - - context. Although these situations rely on the side effects to produce valid code, they typically do not rely on values produced as a result of the side effects. -

    -

    - The following code is an example of compliant code using an unevaluated operand in a macro definition. -

    - - void small(int x); +

    EXP52-CPP-EX1: It is permissible for an expression with side effects to be used as an unevaluated operand in a macro definition or SFINAE context. Although these situations rely on the side effects to produce valid code, they typically do not rely on values produced as a result of the side effects.

    +

    The following code is an example of compliant code using an unevaluated operand in a macro definition.

    + void small(int x); void large(long long x); #define m(x) \ @@ -203,36 +73,10 @@ void large(long long x); void f() { int i = 0; m(++i); -} - -

    - The expansion of the macro - - m - - will result in the expression - - ++i - - being used as an unevaluated operand to - - sizeof() - - . However, the expectation of the programmer at the expansion loci is that - - i - - is preincremented only once. Consequently, this is a safe macro and complies with - - PRE31-C. Avoid side effects in arguments to unsafe macros - - . Compliance with that rule is especially important for code that follows this exception. -

    -

    - The following code is an example of compliant code using an unevaluated operand in a SFINAE context to determine whether a type can be postfix incremented. -

    - - #include <iostream> +} +

    The expansion of the macro m will result in the expression ++i being used as an unevaluated operand to sizeof(). However, the expectation of the programmer at the expansion loci is that i is preincremented only once. Consequently, this is a safe macro and complies with PRE31-C. Avoid side effects in arguments to unsafe macros. Compliance with that rule is especially important for code that follows this exception.

    +

    The following code is an example of compliant code using an unevaluated operand in a SFINAE context to determine whether a type can be postfix incremented.

    + #include <iostream> #include <type_traits> #include <utility> @@ -249,20 +93,11 @@ public: void f() { std::cout << std::boolalpha << is_incrementable<int>::value; -} - -

    - In an instantiation of - - is_incrementable - - , the use of the postfix increment operator generates side effects that are used to determine whether the type is postfix incrementable. However, the value result of these side effects is discarded, so the side effects are used only for SFINAE. -

    +}
    +

    In an instantiation of is_incrementable, the use of the postfix increment operator generates side effects that are used to determine whether the type is postfix incrementable. However, the value result of these side effects is discarded, so the side effects are used only for SFINAE.

    -

    - If expressions that appear to produce side effects are an unevaluated operand, the results may be different than expected. Depending on how this result is used, it can lead to unintended program behavior. -

    +

    If expressions that appear to produce side effects are an unevaluated operand, the results may be different than expected. Depending on how this result is used, it can lead to unintended program behavior.

    @@ -299,14 +134,10 @@ void f() { Low @@ -339,9 +170,7 @@ void f() { 20.10 @@ -374,9 +201,7 @@ void f() { 3.9 @@ -391,9 +216,7 @@ void f() { 2021.2 @@ -408,11 +231,7 @@ void f() { 2021.4 @@ -426,9 +245,7 @@ void f() { @@ -509,9 +316,7 @@ void f() { 20.10
    - - P3 - + P3 - - L3 - + L3
    - - sizeof - + sizeof Partially checked @@ -357,9 +186,7 @@ void f() { 7.2.0 - - CertC++-EXP52 - + CertC++-EXP52 - - -Wunevaluated-expression - + -Wunevaluated-expression - - C++3240, C++3241 - + C++3240, C++3241 - - - MISRA.SIZEOF.SIDE_EFFECT - - + MISRA.SIZEOF.SIDE_EFFECT - - 54 S, 133 S - + 54 S, 133 S Partially implemented @@ -444,17 +261,9 @@ void f() { 2021.2 - - CERT_CPP-EXP52-a - - - CERT_CPP-EXP52-b - - - CERT_CPP-EXP52-c - CERT_CPP-EXP52-d - CERT_CPP-EXP52-e - + CERT_CPP-EXP52-a + CERT_CPP-EXP52-b + CERT_CPP-EXP52-cCERT_CPP-EXP52-dCERT_CPP-EXP52-e The operand of the sizeof operator shall not contain any expression which has side effects @@ -492,9 +301,7 @@ void f() { 4.4 - - 3240, 3241 - + 3240, 3241 - - sizeof - + sizeof Partially checked @@ -521,17 +326,7 @@ void f() {
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    @@ -565,9 +360,7 @@ void f() { diff --git a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclTypeOperand.ql b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclTypeOperand.ql index f42aa0a0a0..217be3db6a 100644 --- a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclTypeOperand.ql +++ b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclTypeOperand.ql @@ -15,6 +15,7 @@ import cpp import codingstandards.cpp.cert import codingstandards.cpp.Sfinae import codingstandards.cpp.SideEffect +import codingstandards.cpp.sideeffect.DefaultEffects from Decltype t, SideEffect e where diff --git a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclValExpression-standard.qhelp b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclValExpression-standard.qhelp index 258c817654..efc279dec8 100644 --- a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclValExpression-standard.qhelp +++ b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclValExpression-standard.qhelp @@ -1,194 +1,64 @@
    -

    - Some expressions involve operands that are - - unevaluated - - . The C++ Standard, [expr], paragraph 8 - [ - - ISO/IEC 14882-2014 - - ] states the following - : -

    +

    Some expressions involve operands that are unevaluated. The C++ Standard, [expr], paragraph 8 [ISO/IEC 14882-2014] states the following:

    -

    - In some contexts, - - unevaluated operands - - appear. An unevaluated operand is not evaluated. An unevaluated operand is considered a full-expression. [Note: In an unevaluated operand, a non-static class member may be named (5.1) and naming of objects or functions does not, by itself, require that a definition be provided. — end note] -

    +

    In some contexts, unevaluated operands appear. An unevaluated operand is not evaluated. An unevaluated operand is considered a full-expression. [Note: In an unevaluated operand, a non-static class member may be named (5.1) and naming of objects or functions does not, by itself, require that a definition be provided. — end note]

    -

    - The following expressions do not evaluate their operands: - - sizeof() - - , - - typeid() - - , - - noexcept() - - , - - decltype() - - , and - - declval() - - . -

    -

    - Because an unevaluated operand in an expression is not evaluated, no side effects from that operand are triggered. Reliance on those side effects will result in unexpected behavior. Do not rely on side effects in unevaluated operands. -

    -

    - Unevaluated expression operands are used when the declaration of an object is required but the definition of the object is not. For instance, in the following example, the function - - f() - - is overloaded, relying on the unevaluated expression operand to select the desired overload, which is then used to determine the result of the - - sizeof() - - expression. -

    - - int f(int); +

    The following expressions do not evaluate their operands: sizeof(), typeid(), noexcept(), decltype(), and declval().

    +

    Because an unevaluated operand in an expression is not evaluated, no side effects from that operand are triggered. Reliance on those side effects will result in unexpected behavior. Do not rely on side effects in unevaluated operands.

    +

    Unevaluated expression operands are used when the declaration of an object is required but the definition of the object is not. For instance, in the following example, the function f() is overloaded, relying on the unevaluated expression operand to select the desired overload, which is then used to determine the result of the sizeof() expression.

    + int f(int); double f(double); -size_t size = sizeof(f(0)); - -

    - Such a use does not rely on the side effects of - - f() - - and consequently conforms to this guideline. -

    +size_t size = sizeof(f(0));
    +

    Such a use does not rely on the side effects of f() and consequently conforms to this guideline.

    -

    - In this noncompliant code example, the expression - - a++ - - is not evaluated. -

    - - #include <iostream> +

    In this noncompliant code example, the expression a++ is not evaluated.

    + #include <iostream> void f() { int a = 14; int b = sizeof(a++); std::cout << a << ", " << b << std::endl; -} - -

    - Consequently, the value of - - a - - after - - b - - has been initialized is 14. -

    +}
    +

    Consequently, the value of a after b has been initialized is 14.

    -

    - In this compliant solution, the variable - - a - - is incremented outside of the - - sizeof - - operator. -

    - - #include <iostream> +

    In this compliant solution, the variable a is incremented outside of the sizeof operator.

    + #include <iostream> void f() { int a = 14; int b = sizeof(a); ++a; std::cout << a << ", " << b << std::endl; -} - +}
    -

    - In this noncompliant code example, the expression - - i++ - - is not evaluated within the - - decltype - - specifier. -

    - - #include <iostream> +

    In this noncompliant code example, the expression i++ is not evaluated within the decltype specifier.

    + #include <iostream> void f() { int i = 0; decltype(i++) h = 12; std::cout << i; -} - -

    - Consequently, the value of - i - remains 0. -

    +}
    +

    Consequently, the value of i remains 0.

    -

    - In this compliant solution, - - i - - is incremented outside of the - - decltype - - specifier so that it is evaluated as desired. -

    - - #include <iostream> +

    In this compliant solution, i is incremented outside of the decltype specifier so that it is evaluated as desired.

    + #include <iostream> void f() { int i = 0; decltype(i) h = 12; ++i; std::cout << i; -} - +}
    -

    - - EXP52-CPP-EX1: - - It is permissible for an expression with side effects to be used as an unevaluated operand in a macro definition or - - SFINAE - - context. Although these situations rely on the side effects to produce valid code, they typically do not rely on values produced as a result of the side effects. -

    -

    - The following code is an example of compliant code using an unevaluated operand in a macro definition. -

    - - void small(int x); +

    EXP52-CPP-EX1: It is permissible for an expression with side effects to be used as an unevaluated operand in a macro definition or SFINAE context. Although these situations rely on the side effects to produce valid code, they typically do not rely on values produced as a result of the side effects.

    +

    The following code is an example of compliant code using an unevaluated operand in a macro definition.

    + void small(int x); void large(long long x); #define m(x) \ @@ -203,36 +73,10 @@ void large(long long x); void f() { int i = 0; m(++i); -} - -

    - The expansion of the macro - - m - - will result in the expression - - ++i - - being used as an unevaluated operand to - - sizeof() - - . However, the expectation of the programmer at the expansion loci is that - - i - - is preincremented only once. Consequently, this is a safe macro and complies with - - PRE31-C. Avoid side effects in arguments to unsafe macros - - . Compliance with that rule is especially important for code that follows this exception. -

    -

    - The following code is an example of compliant code using an unevaluated operand in a SFINAE context to determine whether a type can be postfix incremented. -

    - - #include <iostream> +} +

    The expansion of the macro m will result in the expression ++i being used as an unevaluated operand to sizeof(). However, the expectation of the programmer at the expansion loci is that i is preincremented only once. Consequently, this is a safe macro and complies with PRE31-C. Avoid side effects in arguments to unsafe macros. Compliance with that rule is especially important for code that follows this exception.

    +

    The following code is an example of compliant code using an unevaluated operand in a SFINAE context to determine whether a type can be postfix incremented.

    + #include <iostream> #include <type_traits> #include <utility> @@ -249,20 +93,11 @@ public: void f() { std::cout << std::boolalpha << is_incrementable<int>::value; -} - -

    - In an instantiation of - - is_incrementable - - , the use of the postfix increment operator generates side effects that are used to determine whether the type is postfix incrementable. However, the value result of these side effects is discarded, so the side effects are used only for SFINAE. -

    +}
    +

    In an instantiation of is_incrementable, the use of the postfix increment operator generates side effects that are used to determine whether the type is postfix incrementable. However, the value result of these side effects is discarded, so the side effects are used only for SFINAE.

    -

    - If expressions that appear to produce side effects are an unevaluated operand, the results may be different than expected. Depending on how this result is used, it can lead to unintended program behavior. -

    +

    If expressions that appear to produce side effects are an unevaluated operand, the results may be different than expected. Depending on how this result is used, it can lead to unintended program behavior.

    Clause 5, "Expressions" Subclause 20.2.5, "Function Template - - declval - + declval "
    @@ -299,14 +134,10 @@ void f() { Low @@ -339,9 +170,7 @@ void f() { 20.10 @@ -374,9 +201,7 @@ void f() { 3.9 @@ -391,9 +216,7 @@ void f() { 2021.2 @@ -408,11 +231,7 @@ void f() { 2021.4 @@ -426,9 +245,7 @@ void f() { @@ -509,9 +316,7 @@ void f() { 20.10
    - - P3 - + P3 - - L3 - + L3
    - - sizeof - + sizeof Partially checked @@ -357,9 +186,7 @@ void f() { 7.2.0 - - CertC++-EXP52 - + CertC++-EXP52 - - -Wunevaluated-expression - + -Wunevaluated-expression - - C++3240, C++3241 - + C++3240, C++3241 - - - MISRA.SIZEOF.SIDE_EFFECT - - + MISRA.SIZEOF.SIDE_EFFECT - - 54 S, 133 S - + 54 S, 133 S Partially implemented @@ -444,17 +261,9 @@ void f() { 2021.2 - - CERT_CPP-EXP52-a - - - CERT_CPP-EXP52-b - - - CERT_CPP-EXP52-c - CERT_CPP-EXP52-d - CERT_CPP-EXP52-e - + CERT_CPP-EXP52-a + CERT_CPP-EXP52-b + CERT_CPP-EXP52-cCERT_CPP-EXP52-dCERT_CPP-EXP52-e The operand of the sizeof operator shall not contain any expression which has side effects @@ -492,9 +301,7 @@ void f() { 4.4 - - 3240, 3241 - + 3240, 3241 - - sizeof - + sizeof Partially checked @@ -521,17 +326,7 @@ void f() {
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    @@ -565,9 +360,7 @@ void f() { diff --git a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclValExpression.ql b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclValExpression.ql index 4f339d7ae3..93bb653c11 100644 --- a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclValExpression.ql +++ b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclValExpression.ql @@ -15,6 +15,7 @@ import cpp import codingstandards.cpp.cert import codingstandards.cpp.Sfinae import codingstandards.cpp.SideEffect +import codingstandards.cpp.sideeffect.DefaultEffects class DeclValCall extends FunctionCall { DeclValCall() { this.getTarget().hasQualifiedName("std", "declval") } diff --git a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInNoExceptOperand-standard.qhelp b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInNoExceptOperand-standard.qhelp index 258c817654..efc279dec8 100644 --- a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInNoExceptOperand-standard.qhelp +++ b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInNoExceptOperand-standard.qhelp @@ -1,194 +1,64 @@
    -

    - Some expressions involve operands that are - - unevaluated - - . The C++ Standard, [expr], paragraph 8 - [ - - ISO/IEC 14882-2014 - - ] states the following - : -

    +

    Some expressions involve operands that are unevaluated. The C++ Standard, [expr], paragraph 8 [ISO/IEC 14882-2014] states the following:

    -

    - In some contexts, - - unevaluated operands - - appear. An unevaluated operand is not evaluated. An unevaluated operand is considered a full-expression. [Note: In an unevaluated operand, a non-static class member may be named (5.1) and naming of objects or functions does not, by itself, require that a definition be provided. — end note] -

    +

    In some contexts, unevaluated operands appear. An unevaluated operand is not evaluated. An unevaluated operand is considered a full-expression. [Note: In an unevaluated operand, a non-static class member may be named (5.1) and naming of objects or functions does not, by itself, require that a definition be provided. — end note]

    -

    - The following expressions do not evaluate their operands: - - sizeof() - - , - - typeid() - - , - - noexcept() - - , - - decltype() - - , and - - declval() - - . -

    -

    - Because an unevaluated operand in an expression is not evaluated, no side effects from that operand are triggered. Reliance on those side effects will result in unexpected behavior. Do not rely on side effects in unevaluated operands. -

    -

    - Unevaluated expression operands are used when the declaration of an object is required but the definition of the object is not. For instance, in the following example, the function - - f() - - is overloaded, relying on the unevaluated expression operand to select the desired overload, which is then used to determine the result of the - - sizeof() - - expression. -

    - - int f(int); +

    The following expressions do not evaluate their operands: sizeof(), typeid(), noexcept(), decltype(), and declval().

    +

    Because an unevaluated operand in an expression is not evaluated, no side effects from that operand are triggered. Reliance on those side effects will result in unexpected behavior. Do not rely on side effects in unevaluated operands.

    +

    Unevaluated expression operands are used when the declaration of an object is required but the definition of the object is not. For instance, in the following example, the function f() is overloaded, relying on the unevaluated expression operand to select the desired overload, which is then used to determine the result of the sizeof() expression.

    + int f(int); double f(double); -size_t size = sizeof(f(0)); - -

    - Such a use does not rely on the side effects of - - f() - - and consequently conforms to this guideline. -

    +size_t size = sizeof(f(0));
    +

    Such a use does not rely on the side effects of f() and consequently conforms to this guideline.

    -

    - In this noncompliant code example, the expression - - a++ - - is not evaluated. -

    - - #include <iostream> +

    In this noncompliant code example, the expression a++ is not evaluated.

    + #include <iostream> void f() { int a = 14; int b = sizeof(a++); std::cout << a << ", " << b << std::endl; -} - -

    - Consequently, the value of - - a - - after - - b - - has been initialized is 14. -

    +}
    +

    Consequently, the value of a after b has been initialized is 14.

    -

    - In this compliant solution, the variable - - a - - is incremented outside of the - - sizeof - - operator. -

    - - #include <iostream> +

    In this compliant solution, the variable a is incremented outside of the sizeof operator.

    + #include <iostream> void f() { int a = 14; int b = sizeof(a); ++a; std::cout << a << ", " << b << std::endl; -} - +}
    -

    - In this noncompliant code example, the expression - - i++ - - is not evaluated within the - - decltype - - specifier. -

    - - #include <iostream> +

    In this noncompliant code example, the expression i++ is not evaluated within the decltype specifier.

    + #include <iostream> void f() { int i = 0; decltype(i++) h = 12; std::cout << i; -} - -

    - Consequently, the value of - i - remains 0. -

    +}
    +

    Consequently, the value of i remains 0.

    -

    - In this compliant solution, - - i - - is incremented outside of the - - decltype - - specifier so that it is evaluated as desired. -

    - - #include <iostream> +

    In this compliant solution, i is incremented outside of the decltype specifier so that it is evaluated as desired.

    + #include <iostream> void f() { int i = 0; decltype(i) h = 12; ++i; std::cout << i; -} - +}
    -

    - - EXP52-CPP-EX1: - - It is permissible for an expression with side effects to be used as an unevaluated operand in a macro definition or - - SFINAE - - context. Although these situations rely on the side effects to produce valid code, they typically do not rely on values produced as a result of the side effects. -

    -

    - The following code is an example of compliant code using an unevaluated operand in a macro definition. -

    - - void small(int x); +

    EXP52-CPP-EX1: It is permissible for an expression with side effects to be used as an unevaluated operand in a macro definition or SFINAE context. Although these situations rely on the side effects to produce valid code, they typically do not rely on values produced as a result of the side effects.

    +

    The following code is an example of compliant code using an unevaluated operand in a macro definition.

    + void small(int x); void large(long long x); #define m(x) \ @@ -203,36 +73,10 @@ void large(long long x); void f() { int i = 0; m(++i); -} - -

    - The expansion of the macro - - m - - will result in the expression - - ++i - - being used as an unevaluated operand to - - sizeof() - - . However, the expectation of the programmer at the expansion loci is that - - i - - is preincremented only once. Consequently, this is a safe macro and complies with - - PRE31-C. Avoid side effects in arguments to unsafe macros - - . Compliance with that rule is especially important for code that follows this exception. -

    -

    - The following code is an example of compliant code using an unevaluated operand in a SFINAE context to determine whether a type can be postfix incremented. -

    - - #include <iostream> +} +

    The expansion of the macro m will result in the expression ++i being used as an unevaluated operand to sizeof(). However, the expectation of the programmer at the expansion loci is that i is preincremented only once. Consequently, this is a safe macro and complies with PRE31-C. Avoid side effects in arguments to unsafe macros. Compliance with that rule is especially important for code that follows this exception.

    +

    The following code is an example of compliant code using an unevaluated operand in a SFINAE context to determine whether a type can be postfix incremented.

    + #include <iostream> #include <type_traits> #include <utility> @@ -249,20 +93,11 @@ public: void f() { std::cout << std::boolalpha << is_incrementable<int>::value; -} - -

    - In an instantiation of - - is_incrementable - - , the use of the postfix increment operator generates side effects that are used to determine whether the type is postfix incrementable. However, the value result of these side effects is discarded, so the side effects are used only for SFINAE. -

    +}
    +

    In an instantiation of is_incrementable, the use of the postfix increment operator generates side effects that are used to determine whether the type is postfix incrementable. However, the value result of these side effects is discarded, so the side effects are used only for SFINAE.

    -

    - If expressions that appear to produce side effects are an unevaluated operand, the results may be different than expected. Depending on how this result is used, it can lead to unintended program behavior. -

    +

    If expressions that appear to produce side effects are an unevaluated operand, the results may be different than expected. Depending on how this result is used, it can lead to unintended program behavior.

    Clause 5, "Expressions" Subclause 20.2.5, "Function Template - - declval - + declval "
    @@ -299,14 +134,10 @@ void f() { Low @@ -339,9 +170,7 @@ void f() { 20.10 @@ -374,9 +201,7 @@ void f() { 3.9 @@ -391,9 +216,7 @@ void f() { 2021.2 @@ -408,11 +231,7 @@ void f() { 2021.4 @@ -426,9 +245,7 @@ void f() { @@ -509,9 +316,7 @@ void f() { 20.10
    - - P3 - + P3 - - L3 - + L3
    - - sizeof - + sizeof Partially checked @@ -357,9 +186,7 @@ void f() { 7.2.0 - - CertC++-EXP52 - + CertC++-EXP52 - - -Wunevaluated-expression - + -Wunevaluated-expression - - C++3240, C++3241 - + C++3240, C++3241 - - - MISRA.SIZEOF.SIDE_EFFECT - - + MISRA.SIZEOF.SIDE_EFFECT - - 54 S, 133 S - + 54 S, 133 S Partially implemented @@ -444,17 +261,9 @@ void f() { 2021.2 - - CERT_CPP-EXP52-a - - - CERT_CPP-EXP52-b - - - CERT_CPP-EXP52-c - CERT_CPP-EXP52-d - CERT_CPP-EXP52-e - + CERT_CPP-EXP52-a + CERT_CPP-EXP52-b + CERT_CPP-EXP52-cCERT_CPP-EXP52-dCERT_CPP-EXP52-e The operand of the sizeof operator shall not contain any expression which has side effects @@ -492,9 +301,7 @@ void f() { 4.4 - - 3240, 3241 - + 3240, 3241 - - sizeof - + sizeof Partially checked @@ -521,17 +326,7 @@ void f() {
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    @@ -565,9 +360,7 @@ void f() { diff --git a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInNoExceptOperand.ql b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInNoExceptOperand.ql index c297de22e2..a32aa1eb14 100644 --- a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInNoExceptOperand.ql +++ b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInNoExceptOperand.ql @@ -14,6 +14,7 @@ import cpp import codingstandards.cpp.cert import codingstandards.cpp.SideEffect +import codingstandards.cpp.sideeffect.DefaultEffects from NoExceptExpr e where diff --git a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInSizeOfOperand-standard.qhelp b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInSizeOfOperand-standard.qhelp index 258c817654..efc279dec8 100644 --- a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInSizeOfOperand-standard.qhelp +++ b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInSizeOfOperand-standard.qhelp @@ -1,194 +1,64 @@
    -

    - Some expressions involve operands that are - - unevaluated - - . The C++ Standard, [expr], paragraph 8 - [ - - ISO/IEC 14882-2014 - - ] states the following - : -

    +

    Some expressions involve operands that are unevaluated. The C++ Standard, [expr], paragraph 8 [ISO/IEC 14882-2014] states the following:

    -

    - In some contexts, - - unevaluated operands - - appear. An unevaluated operand is not evaluated. An unevaluated operand is considered a full-expression. [Note: In an unevaluated operand, a non-static class member may be named (5.1) and naming of objects or functions does not, by itself, require that a definition be provided. — end note] -

    +

    In some contexts, unevaluated operands appear. An unevaluated operand is not evaluated. An unevaluated operand is considered a full-expression. [Note: In an unevaluated operand, a non-static class member may be named (5.1) and naming of objects or functions does not, by itself, require that a definition be provided. — end note]

    -

    - The following expressions do not evaluate their operands: - - sizeof() - - , - - typeid() - - , - - noexcept() - - , - - decltype() - - , and - - declval() - - . -

    -

    - Because an unevaluated operand in an expression is not evaluated, no side effects from that operand are triggered. Reliance on those side effects will result in unexpected behavior. Do not rely on side effects in unevaluated operands. -

    -

    - Unevaluated expression operands are used when the declaration of an object is required but the definition of the object is not. For instance, in the following example, the function - - f() - - is overloaded, relying on the unevaluated expression operand to select the desired overload, which is then used to determine the result of the - - sizeof() - - expression. -

    - - int f(int); +

    The following expressions do not evaluate their operands: sizeof(), typeid(), noexcept(), decltype(), and declval().

    +

    Because an unevaluated operand in an expression is not evaluated, no side effects from that operand are triggered. Reliance on those side effects will result in unexpected behavior. Do not rely on side effects in unevaluated operands.

    +

    Unevaluated expression operands are used when the declaration of an object is required but the definition of the object is not. For instance, in the following example, the function f() is overloaded, relying on the unevaluated expression operand to select the desired overload, which is then used to determine the result of the sizeof() expression.

    + int f(int); double f(double); -size_t size = sizeof(f(0)); - -

    - Such a use does not rely on the side effects of - - f() - - and consequently conforms to this guideline. -

    +size_t size = sizeof(f(0));
    +

    Such a use does not rely on the side effects of f() and consequently conforms to this guideline.

    -

    - In this noncompliant code example, the expression - - a++ - - is not evaluated. -

    - - #include <iostream> +

    In this noncompliant code example, the expression a++ is not evaluated.

    + #include <iostream> void f() { int a = 14; int b = sizeof(a++); std::cout << a << ", " << b << std::endl; -} - -

    - Consequently, the value of - - a - - after - - b - - has been initialized is 14. -

    +}
    +

    Consequently, the value of a after b has been initialized is 14.

    -

    - In this compliant solution, the variable - - a - - is incremented outside of the - - sizeof - - operator. -

    - - #include <iostream> +

    In this compliant solution, the variable a is incremented outside of the sizeof operator.

    + #include <iostream> void f() { int a = 14; int b = sizeof(a); ++a; std::cout << a << ", " << b << std::endl; -} - +}
    -

    - In this noncompliant code example, the expression - - i++ - - is not evaluated within the - - decltype - - specifier. -

    - - #include <iostream> +

    In this noncompliant code example, the expression i++ is not evaluated within the decltype specifier.

    + #include <iostream> void f() { int i = 0; decltype(i++) h = 12; std::cout << i; -} - -

    - Consequently, the value of - i - remains 0. -

    +}
    +

    Consequently, the value of i remains 0.

    -

    - In this compliant solution, - - i - - is incremented outside of the - - decltype - - specifier so that it is evaluated as desired. -

    - - #include <iostream> +

    In this compliant solution, i is incremented outside of the decltype specifier so that it is evaluated as desired.

    + #include <iostream> void f() { int i = 0; decltype(i) h = 12; ++i; std::cout << i; -} - +}
    -

    - - EXP52-CPP-EX1: - - It is permissible for an expression with side effects to be used as an unevaluated operand in a macro definition or - - SFINAE - - context. Although these situations rely on the side effects to produce valid code, they typically do not rely on values produced as a result of the side effects. -

    -

    - The following code is an example of compliant code using an unevaluated operand in a macro definition. -

    - - void small(int x); +

    EXP52-CPP-EX1: It is permissible for an expression with side effects to be used as an unevaluated operand in a macro definition or SFINAE context. Although these situations rely on the side effects to produce valid code, they typically do not rely on values produced as a result of the side effects.

    +

    The following code is an example of compliant code using an unevaluated operand in a macro definition.

    + void small(int x); void large(long long x); #define m(x) \ @@ -203,36 +73,10 @@ void large(long long x); void f() { int i = 0; m(++i); -} - -

    - The expansion of the macro - - m - - will result in the expression - - ++i - - being used as an unevaluated operand to - - sizeof() - - . However, the expectation of the programmer at the expansion loci is that - - i - - is preincremented only once. Consequently, this is a safe macro and complies with - - PRE31-C. Avoid side effects in arguments to unsafe macros - - . Compliance with that rule is especially important for code that follows this exception. -

    -

    - The following code is an example of compliant code using an unevaluated operand in a SFINAE context to determine whether a type can be postfix incremented. -

    - - #include <iostream> +} +

    The expansion of the macro m will result in the expression ++i being used as an unevaluated operand to sizeof(). However, the expectation of the programmer at the expansion loci is that i is preincremented only once. Consequently, this is a safe macro and complies with PRE31-C. Avoid side effects in arguments to unsafe macros. Compliance with that rule is especially important for code that follows this exception.

    +

    The following code is an example of compliant code using an unevaluated operand in a SFINAE context to determine whether a type can be postfix incremented.

    + #include <iostream> #include <type_traits> #include <utility> @@ -249,20 +93,11 @@ public: void f() { std::cout << std::boolalpha << is_incrementable<int>::value; -} - -

    - In an instantiation of - - is_incrementable - - , the use of the postfix increment operator generates side effects that are used to determine whether the type is postfix incrementable. However, the value result of these side effects is discarded, so the side effects are used only for SFINAE. -

    +}
    +

    In an instantiation of is_incrementable, the use of the postfix increment operator generates side effects that are used to determine whether the type is postfix incrementable. However, the value result of these side effects is discarded, so the side effects are used only for SFINAE.

    -

    - If expressions that appear to produce side effects are an unevaluated operand, the results may be different than expected. Depending on how this result is used, it can lead to unintended program behavior. -

    +

    If expressions that appear to produce side effects are an unevaluated operand, the results may be different than expected. Depending on how this result is used, it can lead to unintended program behavior.

    Clause 5, "Expressions" Subclause 20.2.5, "Function Template - - declval - + declval "
    @@ -299,14 +134,10 @@ void f() { Low @@ -339,9 +170,7 @@ void f() { 20.10 @@ -374,9 +201,7 @@ void f() { 3.9 @@ -391,9 +216,7 @@ void f() { 2021.2 @@ -408,11 +231,7 @@ void f() { 2021.4 @@ -426,9 +245,7 @@ void f() { @@ -509,9 +316,7 @@ void f() { 20.10
    - - P3 - + P3 - - L3 - + L3
    - - sizeof - + sizeof Partially checked @@ -357,9 +186,7 @@ void f() { 7.2.0 - - CertC++-EXP52 - + CertC++-EXP52 - - -Wunevaluated-expression - + -Wunevaluated-expression - - C++3240, C++3241 - + C++3240, C++3241 - - - MISRA.SIZEOF.SIDE_EFFECT - - + MISRA.SIZEOF.SIDE_EFFECT - - 54 S, 133 S - + 54 S, 133 S Partially implemented @@ -444,17 +261,9 @@ void f() { 2021.2 - - CERT_CPP-EXP52-a - - - CERT_CPP-EXP52-b - - - CERT_CPP-EXP52-c - CERT_CPP-EXP52-d - CERT_CPP-EXP52-e - + CERT_CPP-EXP52-a + CERT_CPP-EXP52-b + CERT_CPP-EXP52-cCERT_CPP-EXP52-dCERT_CPP-EXP52-e The operand of the sizeof operator shall not contain any expression which has side effects @@ -492,9 +301,7 @@ void f() { 4.4 - - 3240, 3241 - + 3240, 3241 - - sizeof - + sizeof Partially checked @@ -521,17 +326,7 @@ void f() {
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    @@ -565,9 +360,7 @@ void f() { diff --git a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInSizeOfOperand.ql b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInSizeOfOperand.ql index ca91a22a56..4cc602362e 100644 --- a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInSizeOfOperand.ql +++ b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInSizeOfOperand.ql @@ -14,6 +14,7 @@ import cpp import codingstandards.cpp.cert import codingstandards.cpp.SideEffect +import codingstandards.cpp.sideeffect.DefaultEffects from SizeofExprOperator op where diff --git a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInTypeIdOperand-standard.qhelp b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInTypeIdOperand-standard.qhelp index 258c817654..efc279dec8 100644 --- a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInTypeIdOperand-standard.qhelp +++ b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInTypeIdOperand-standard.qhelp @@ -1,194 +1,64 @@
    -

    - Some expressions involve operands that are - - unevaluated - - . The C++ Standard, [expr], paragraph 8 - [ - - ISO/IEC 14882-2014 - - ] states the following - : -

    +

    Some expressions involve operands that are unevaluated. The C++ Standard, [expr], paragraph 8 [ISO/IEC 14882-2014] states the following:

    -

    - In some contexts, - - unevaluated operands - - appear. An unevaluated operand is not evaluated. An unevaluated operand is considered a full-expression. [Note: In an unevaluated operand, a non-static class member may be named (5.1) and naming of objects or functions does not, by itself, require that a definition be provided. — end note] -

    +

    In some contexts, unevaluated operands appear. An unevaluated operand is not evaluated. An unevaluated operand is considered a full-expression. [Note: In an unevaluated operand, a non-static class member may be named (5.1) and naming of objects or functions does not, by itself, require that a definition be provided. — end note]

    -

    - The following expressions do not evaluate their operands: - - sizeof() - - , - - typeid() - - , - - noexcept() - - , - - decltype() - - , and - - declval() - - . -

    -

    - Because an unevaluated operand in an expression is not evaluated, no side effects from that operand are triggered. Reliance on those side effects will result in unexpected behavior. Do not rely on side effects in unevaluated operands. -

    -

    - Unevaluated expression operands are used when the declaration of an object is required but the definition of the object is not. For instance, in the following example, the function - - f() - - is overloaded, relying on the unevaluated expression operand to select the desired overload, which is then used to determine the result of the - - sizeof() - - expression. -

    - - int f(int); +

    The following expressions do not evaluate their operands: sizeof(), typeid(), noexcept(), decltype(), and declval().

    +

    Because an unevaluated operand in an expression is not evaluated, no side effects from that operand are triggered. Reliance on those side effects will result in unexpected behavior. Do not rely on side effects in unevaluated operands.

    +

    Unevaluated expression operands are used when the declaration of an object is required but the definition of the object is not. For instance, in the following example, the function f() is overloaded, relying on the unevaluated expression operand to select the desired overload, which is then used to determine the result of the sizeof() expression.

    + int f(int); double f(double); -size_t size = sizeof(f(0)); - -

    - Such a use does not rely on the side effects of - - f() - - and consequently conforms to this guideline. -

    +size_t size = sizeof(f(0));
    +

    Such a use does not rely on the side effects of f() and consequently conforms to this guideline.

    -

    - In this noncompliant code example, the expression - - a++ - - is not evaluated. -

    - - #include <iostream> +

    In this noncompliant code example, the expression a++ is not evaluated.

    + #include <iostream> void f() { int a = 14; int b = sizeof(a++); std::cout << a << ", " << b << std::endl; -} - -

    - Consequently, the value of - - a - - after - - b - - has been initialized is 14. -

    +}
    +

    Consequently, the value of a after b has been initialized is 14.

    -

    - In this compliant solution, the variable - - a - - is incremented outside of the - - sizeof - - operator. -

    - - #include <iostream> +

    In this compliant solution, the variable a is incremented outside of the sizeof operator.

    + #include <iostream> void f() { int a = 14; int b = sizeof(a); ++a; std::cout << a << ", " << b << std::endl; -} - +}
    -

    - In this noncompliant code example, the expression - - i++ - - is not evaluated within the - - decltype - - specifier. -

    - - #include <iostream> +

    In this noncompliant code example, the expression i++ is not evaluated within the decltype specifier.

    + #include <iostream> void f() { int i = 0; decltype(i++) h = 12; std::cout << i; -} - -

    - Consequently, the value of - i - remains 0. -

    +}
    +

    Consequently, the value of i remains 0.

    -

    - In this compliant solution, - - i - - is incremented outside of the - - decltype - - specifier so that it is evaluated as desired. -

    - - #include <iostream> +

    In this compliant solution, i is incremented outside of the decltype specifier so that it is evaluated as desired.

    + #include <iostream> void f() { int i = 0; decltype(i) h = 12; ++i; std::cout << i; -} - +}
    -

    - - EXP52-CPP-EX1: - - It is permissible for an expression with side effects to be used as an unevaluated operand in a macro definition or - - SFINAE - - context. Although these situations rely on the side effects to produce valid code, they typically do not rely on values produced as a result of the side effects. -

    -

    - The following code is an example of compliant code using an unevaluated operand in a macro definition. -

    - - void small(int x); +

    EXP52-CPP-EX1: It is permissible for an expression with side effects to be used as an unevaluated operand in a macro definition or SFINAE context. Although these situations rely on the side effects to produce valid code, they typically do not rely on values produced as a result of the side effects.

    +

    The following code is an example of compliant code using an unevaluated operand in a macro definition.

    + void small(int x); void large(long long x); #define m(x) \ @@ -203,36 +73,10 @@ void large(long long x); void f() { int i = 0; m(++i); -} - -

    - The expansion of the macro - - m - - will result in the expression - - ++i - - being used as an unevaluated operand to - - sizeof() - - . However, the expectation of the programmer at the expansion loci is that - - i - - is preincremented only once. Consequently, this is a safe macro and complies with - - PRE31-C. Avoid side effects in arguments to unsafe macros - - . Compliance with that rule is especially important for code that follows this exception. -

    -

    - The following code is an example of compliant code using an unevaluated operand in a SFINAE context to determine whether a type can be postfix incremented. -

    - - #include <iostream> +} +

    The expansion of the macro m will result in the expression ++i being used as an unevaluated operand to sizeof(). However, the expectation of the programmer at the expansion loci is that i is preincremented only once. Consequently, this is a safe macro and complies with PRE31-C. Avoid side effects in arguments to unsafe macros. Compliance with that rule is especially important for code that follows this exception.

    +

    The following code is an example of compliant code using an unevaluated operand in a SFINAE context to determine whether a type can be postfix incremented.

    + #include <iostream> #include <type_traits> #include <utility> @@ -249,20 +93,11 @@ public: void f() { std::cout << std::boolalpha << is_incrementable<int>::value; -} - -

    - In an instantiation of - - is_incrementable - - , the use of the postfix increment operator generates side effects that are used to determine whether the type is postfix incrementable. However, the value result of these side effects is discarded, so the side effects are used only for SFINAE. -

    +}
    +

    In an instantiation of is_incrementable, the use of the postfix increment operator generates side effects that are used to determine whether the type is postfix incrementable. However, the value result of these side effects is discarded, so the side effects are used only for SFINAE.

    -

    - If expressions that appear to produce side effects are an unevaluated operand, the results may be different than expected. Depending on how this result is used, it can lead to unintended program behavior. -

    +

    If expressions that appear to produce side effects are an unevaluated operand, the results may be different than expected. Depending on how this result is used, it can lead to unintended program behavior.

    Clause 5, "Expressions" Subclause 20.2.5, "Function Template - - declval - + declval "
    @@ -299,14 +134,10 @@ void f() { Low @@ -339,9 +170,7 @@ void f() { 20.10 @@ -374,9 +201,7 @@ void f() { 3.9 @@ -391,9 +216,7 @@ void f() { 2021.2 @@ -408,11 +231,7 @@ void f() { 2021.4 @@ -426,9 +245,7 @@ void f() { @@ -509,9 +316,7 @@ void f() { 20.10
    - - P3 - + P3 - - L3 - + L3
    - - sizeof - + sizeof Partially checked @@ -357,9 +186,7 @@ void f() { 7.2.0 - - CertC++-EXP52 - + CertC++-EXP52 - - -Wunevaluated-expression - + -Wunevaluated-expression - - C++3240, C++3241 - + C++3240, C++3241 - - - MISRA.SIZEOF.SIDE_EFFECT - - + MISRA.SIZEOF.SIDE_EFFECT - - 54 S, 133 S - + 54 S, 133 S Partially implemented @@ -444,17 +261,9 @@ void f() { 2021.2 - - CERT_CPP-EXP52-a - - - CERT_CPP-EXP52-b - - - CERT_CPP-EXP52-c - CERT_CPP-EXP52-d - CERT_CPP-EXP52-e - + CERT_CPP-EXP52-a + CERT_CPP-EXP52-b + CERT_CPP-EXP52-cCERT_CPP-EXP52-dCERT_CPP-EXP52-e The operand of the sizeof operator shall not contain any expression which has side effects @@ -492,9 +301,7 @@ void f() { 4.4 - - 3240, 3241 - + 3240, 3241 - - sizeof - + sizeof Partially checked @@ -521,17 +326,7 @@ void f() {
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    @@ -565,9 +360,7 @@ void f() { diff --git a/cpp/cert/src/rules/EXP53-CPP/DoNotReadUninitializedMemory-standard.qhelp b/cpp/cert/src/rules/EXP53-CPP/DoNotReadUninitializedMemory-standard.qhelp index cd071cc8bd..517fad3973 100644 --- a/cpp/cert/src/rules/EXP53-CPP/DoNotReadUninitializedMemory-standard.qhelp +++ b/cpp/cert/src/rules/EXP53-CPP/DoNotReadUninitializedMemory-standard.qhelp @@ -1,292 +1,78 @@
    -

    - Local, automatic variables assume unexpected values if they are read before they are initialized. The C++ Standard, [dcl.init], paragraph 12 [ - - ISO/IEC 14882-2014 - - ], states the following: -

    +

    Local, automatic variables assume unexpected values if they are read before they are initialized. The C++ Standard, [dcl.init], paragraph 12 [ISO/IEC 14882-2014], states the following:

    -

    - If no initializer is specified for an object, the object is default-initialized. When storage for an object with automatic or dynamic storage duration is obtained, the object has an - - indeterminate value - - , and if no initialization is performed for the object, that object retains an indeterminate value until that value is replaced. If an indeterminate value is produced by an evaluation, the behavior is undefined except in the following cases: -

    -

    - — If an indeterminate value of unsigned narrow character type is produced by the evaluation of: - — the second or third operand of a conditional expression, - — the right operand of a comma expression, - — the operand of a cast or conversion to an unsigned narrow character type, or - — a discarded-value expression, - then the result of the operation is an indeterminate value. - — If an indeterminate value of unsigned narrow character type is produced by the evaluation of the right operand of a simple assignment operator whose first operand is an lvalue of unsigned narrow character type, an indeterminate value replaces the value of the object referred to by the left operand. - — If an indeterminate value of unsigned narrow character type is produced by the evaluation of the initialization expression when initializing an object of unsigned narrow character type, that object is initialized to an indeterminate value. -

    +

    If no initializer is specified for an object, the object is default-initialized. When storage for an object with automatic or dynamic storage duration is obtained, the object has an indeterminate value, and if no initialization is performed for the object, that object retains an indeterminate value until that value is replaced. If an indeterminate value is produced by an evaluation, the behavior is undefined except in the following cases:

    +

    — If an indeterminate value of unsigned narrow character type is produced by the evaluation of: — the second or third operand of a conditional expression, — the right operand of a comma expression, — the operand of a cast or conversion to an unsigned narrow character type, or — a discarded-value expression,then the result of the operation is an indeterminate value.— If an indeterminate value of unsigned narrow character type is produced by the evaluation of the right operand of a simple assignment operator whose first operand is an lvalue of unsigned narrow character type, an indeterminate value replaces the value of the object referred to by the left operand.— If an indeterminate value of unsigned narrow character type is produced by the evaluation of the initialization expression when initializing an object of unsigned narrow character type, that object is initialized to an indeterminate value.

    -

    - The default initialization of an object is described by paragraph 7 of the same subclause: -

    +

    The default initialization of an object is described by paragraph 7 of the same subclause:

    -

    - To - - default-initialize - - an object of type - - T - - means: - — if - - T - - is a (possibly cv-qualified) class type, the default constructor for - - T - - is called (and the initialization is ill-formed if - - T - - has no default constructor or overload resolution results in an ambiguity or in a function that is deleted or inaccessible from the context of the initialization); - — if - - T - - is an array type, each element is default-initialized; - — otherwise, no initialization is performed. - If a program calls for the default initialization of an object of a const-qualified type - - T - - , - - T - - shall be a class type with a user-provided default constructor. -

    +

    To default-initialize an object of type T means:— if T is a (possibly cv-qualified) class type, the default constructor for T is called (and the initialization is ill-formed if T has no default constructor or overload resolution results in an ambiguity or in a function that is deleted or inaccessible from the context of the initialization);— if T is an array type, each element is default-initialized;— otherwise, no initialization is performed.If a program calls for the default initialization of an object of a const-qualified type T, T shall be a class type with a user-provided default constructor.

    -

    - As a result, objects of type - - T - - with automatic or dynamic storage duration must be explicitly initialized before having their value read as part of an expression unless - - T - - is a class type or an array thereof or is an unsigned narrow character type. If - - T - - is an unsigned narrow character type, it may be used to initialize an object of unsigned narrow character type, which results in both objects having an - - indeterminate value - - . This technique can be used to implement copy operations such as - - std::memcpy() - - without triggering - - undefined behavior - - . -

    -

    - Additionally, memory - dynamically allocated with a - - new - - expression is default-initialized when the - - new-initialized - - is omitted. Memory allocated by the standard library function - - std::calloc() - - is zero-initialized. Memory allocated by the standard library function - - std::realloc() - - assumes the values of the original pointer but may not initialize the full range of memory. Memory allocated by any other means ( - - std::malloc() - - , allocator objects, - - operator new() - - , and so on) is assumed to be default-initialized. -

    -

    - Objects of static or thread storage duration are zero-initialized before any other initialization takes place [ - - ISO/IEC 14882-2014 - - ] and need not be explicitly initialized before having their value read. -

    -

    - Reading uninitialized variables for creating entropy is problematic because these memory accesses can be removed by compiler optimization. - VU925211 - is an example of a - - vulnerability - - caused by this coding error [ - - VU#925211 - - ]. -

    +

    As a result, objects of type T with automatic or dynamic storage duration must be explicitly initialized before having their value read as part of an expression unless T is a class type or an array thereof or is an unsigned narrow character type. If T is an unsigned narrow character type, it may be used to initialize an object of unsigned narrow character type, which results in both objects having an indeterminate value. This technique can be used to implement copy operations such as std::memcpy() without triggering undefined behavior.

    +

    Additionally, memory dynamically allocated with a new expression is default-initialized when the new-initialized is omitted. Memory allocated by the standard library function std::calloc() is zero-initialized. Memory allocated by the standard library function std::realloc() assumes the values of the original pointer but may not initialize the full range of memory. Memory allocated by any other means ( std::malloc(), allocator objects, operator new(), and so on) is assumed to be default-initialized.

    +

    Objects of static or thread storage duration are zero-initialized before any other initialization takes place [ISO/IEC 14882-2014] and need not be explicitly initialized before having their value read.

    +

    Reading uninitialized variables for creating entropy is problematic because these memory accesses can be removed by compiler optimization. VU925211 is an example of a vulnerability caused by this coding error [VU#925211].

    -

    - In this noncompliant code example, an uninitialized local variable is evaluated as part of an expression to print its value, resulting in - - undefined behavior - - . -

    - - #include <iostream> -  +

    In this noncompliant code example, an uninitialized local variable is evaluated as part of an expression to print its value, resulting in undefined behavior.

    + #include <iostream> + void f() { int i; std::cout << i; -} - +}
    -

    - In this compliant solution, the object is initialized prior to printing its value. -

    - - #include <iostream> -  +

    In this compliant solution, the object is initialized prior to printing its value.

    + #include <iostream> + void f() { int i = 0; std::cout << i; -} - +}
    -

    - In this noncompliant code example, an - - int * - - object is allocated by a - - new-expression - - , but the memory it points to is not initialized. The object's pointer value and the value it points to are printed to the standard output stream. Printing the pointer value is well-defined, but attempting to print the value pointed to yields an - - indeterminate value - - , resulting in - - undefined behavior - - . -

    - - #include <iostream> -  +

    In this noncompliant code example, an int * object is allocated by a new-expression, but the memory it points to is not initialized. The object's pointer value and the value it points to are printed to the standard output stream. Printing the pointer value is well-defined, but attempting to print the value pointed to yields an indeterminate value, resulting in undefined behavior.

    + #include <iostream> + void f() { int *i = new int; std::cout << i << ", " << *i; -} - +}
    -

    - In this compliant solution, the memory is direct-initialized to the value - - 12 - - prior to printing its value. -

    - - #include <iostream> +

    In this compliant solution, the memory is direct-initialized to the value 12 prior to printing its value.

    + #include <iostream> void f() { int *i = new int(12); std::cout << i << ", " << *i; -} - -

    - Initialization of an object produced by a - - new-expression - - is performed by placing (possibly empty) parenthesis or curly braces after the type being allocated. This causes direct initialization of the pointed-to object to occur, which will zero-initialize the object if the initialization omits a value, as illustrated by the following code. -

    - - int *i = new int(); // zero-initializes *i +} +

    Initialization of an object produced by a new-expression is performed by placing (possibly empty) parenthesis or curly braces after the type being allocated. This causes direct initialization of the pointed-to object to occur, which will zero-initialize the object if the initialization omits a value, as illustrated by the following code.

    + int *i = new int(); // zero-initializes *i int *j = new int{}; // zero-initializes *j int *k = new int(12); // initializes *k to 12 -int *l = new int{12}; // initializes *l to 12 - +int *l = new int{12}; // initializes *l to 12
    -

    - In this noncompliant code example, the class member variable - - c - - is not explicitly initialized by a - - ctor-initializer - - in the default constructor. Despite the local variable - - s - - being default-initialized, the use of - - c - - within the call to - - S::f() - - results in the evaluation of an object with indeterminate value, resulting in undefined behavior. -

    - - class S { +

    In this noncompliant code example, the class member variable c is not explicitly initialized by a ctor-initializer in the default constructor. Despite the local variable s being default-initialized, the use of c within the call to S::f() results in the evaluation of an object with indeterminate value, resulting in undefined behavior.

    + class S { int c; -  + public: int f(int i) const { return i + c; } }; -  + void f() { S s; int i = s.f(10); -} - +}
    -

    - In this compliant solution, - - S - - is given a default constructor that initializes the class member variable - - c. - -

    - - class S { +

    In this compliant solution, S is given a default constructor that initializes the class member variable c.

    + class S { int c; public: @@ -297,17 +83,10 @@ public: void f() { S s; int i = s.f(10); -} - +}
    -

    - Reading uninitialized variables is undefined behavior and can result in unexpected program behavior. In some cases, these - - security flaws - - may allow the execution of arbitrary code. -

    +

    Reading uninitialized variables is undefined behavior and can result in unexpected program behavior. In some cases, these security flaws may allow the execution of arbitrary code.

    Clause 5, "Expressions" Subclause 20.2.5, "Function Template - - declval - + declval "
    @@ -344,14 +123,10 @@ void f() { Medium @@ -384,9 +159,7 @@ void f() { 20.10 @@ -460,51 +224,15 @@ void f() { 2021.4 @@ -518,9 +246,7 @@ void f() { @@ -588,9 +312,7 @@ void f() { 4.4 @@ -602,62 +324,26 @@ void f() { @@ -672,9 +358,7 @@ void f() { 20.10
    - - P12 - + P12 - - L1 - + L1
    - - uninitialized-read - + uninitialized-read Partially checked @@ -402,12 +175,8 @@ void f() { 3.9 - - -Wuninitialized - - - clang-analyzer-core.UndefinedBinaryOperatorResult - + -Wuninitialized + clang-analyzer-core.UndefinedBinaryOperatorResult Does not catch all instances of this rule, such as uninitialized values read from heap-allocated memory. @@ -420,13 +189,10 @@ void f() { - 6.1p0 + 6.2p0 - - LANG.STRUCT.RPL - LANG.MEM.UVAR - + LANG.STRUCT.RPLLANG.MEM.UVAR Return pointer to local @@ -443,9 +209,7 @@ void f() { 2021.2 - - C++2726, C++2727, C++2728, C++2961, C++2962, C++2963, C++2966, C++2967, C++2968, C++2971, C++2972, C++2973, C++2976, C++2977, C++2978 - + C++2726, C++2727, C++2728, C++2961, C++2962, C++2963, C++2966, C++2967, C++2968, C++2971, C++2972, C++2973, C++2976, C++2977, C++2978 - - - UNINIT.CTOR.MIGHT - - - - - UNINIT.CTOR.MUST - - - - - UNINIT.HEAP.MIGHT - - - - - UNINIT.HEAP.MUST - - - - - UNINIT.STACK.ARRAY.MIGHT - - - - - UNINIT.STACK.ARRAY.MUST - - - - - UNINIT.STACK.ARRAY.PARTIAL.MUST - - - - - UNINIT.STACK.MIGHT - - - - - UNINIT.STACK.MUST - - + UNINIT.CTOR.MIGHT + UNINIT.CTOR.MUST + UNINIT.HEAP.MIGHT + UNINIT.HEAP.MUST + UNINIT.STACK.ARRAY.MIGHT + UNINIT.STACK.ARRAY.MUST + UNINIT.STACK.ARRAY.PARTIAL.MUST + UNINIT.STACK.MIGHT + UNINIT.STACK.MUST - - 53 D, 69 D, 631 S, 652 S - + 53 D, 69 D, 631 S, 652 S Partially implemented @@ -536,9 +262,7 @@ void f() { 2021.2 - - CERT_CPP-EXP53-a - + CERT_CPP-EXP53-a Avoid use before initialization @@ -574,7 +298,7 @@ void f() { Checks for: - Non-initialized variable, non-initialized pointer. + Non-initialized variableon-initialized variable, non-initialized pointeron-initialized pointer. Rule partially covered.
    - - 2726, 2727, 2728, 2961, 2962, 2963, 2966, 2967, 2968, 2971, 2972, 2973, 2976, 2977, 2978 - + 2726, 2727, 2728, 2961, 2962, 2963, 2966, 2967, 2968, 2971, 2972, 2973, 2976, 2977, 2978 - 7.16 + 7.17 - - V546 - - - + V546 , - - V573 - - - + V573 , - - - V614 - - + V614 , - - - V670 - - + V670 , - - - V679 - - + V679 , - - - V730 - - + V730 , - - V788 - - - + V788 , - - - V1007 - - + V1007 , - - - V1050 - - + V1050 - - uninitialized-read - + uninitialized-read Partially checked @@ -684,17 +368,7 @@ void f() {
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/EXP54-CPP/ObjectAccessedAfterLifetimeCert-standard.qhelp b/cpp/cert/src/rules/EXP54-CPP/ObjectAccessedAfterLifetimeCert-standard.qhelp index 47781085bd..1e9a428728 100644 --- a/cpp/cert/src/rules/EXP54-CPP/ObjectAccessedAfterLifetimeCert-standard.qhelp +++ b/cpp/cert/src/rules/EXP54-CPP/ObjectAccessedAfterLifetimeCert-standard.qhelp @@ -1,128 +1,31 @@
    -

    - Every object has a lifetime in which it can be used in a well-defined manner. The lifetime of an object begins when sufficient, properly aligned storage has been obtained for it and its initialization is complete. The lifetime of an object ends when a nontrivial destructor, if any, is called for the object and the storage for the object has been reused or released. Use of an object, or a pointer to an object, outside of its lifetime frequently results in - - undefined behavior - - . -

    -

    - The C++ Standard, [basic.life], paragraph 5 [ - - ISO/IEC 14882-2014 - - ], describes the lifetime rules for pointers: -

    +

    Every object has a lifetime in which it can be used in a well-defined manner. The lifetime of an object begins when sufficient, properly aligned storage has been obtained for it and its initialization is complete. The lifetime of an object ends when a nontrivial destructor, if any, is called for the object and the storage for the object has been reused or released. Use of an object, or a pointer to an object, outside of its lifetime frequently results in undefined behavior.

    +

    The C++ Standard, [basic.life], paragraph 5 [ISO/IEC 14882-2014], describes the lifetime rules for pointers:

    -

    - Before the lifetime of an object has started but after the storage which the object will occupy has been allocated or, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, any pointer that refers to the storage location where the object will be or was located may be used but only in limited ways. For an object under construction or destruction, see 12.7. Otherwise, such a pointer refers to allocated storage, and using the pointer as if the pointer were of type - - void* - - , is well-defined. Indirection through such a pointer is permitted but the resulting lvalue may only be used in limited ways, as described below. The program has undefined behavior if: - — the object will be or was of a class type with a non-trivial destructor and the pointer is used as the operand of a - - delete-expression - - , - — the pointer is used to access a non-static data member or call a non-static member function of the object, or - — the pointer is implicitly converted to a pointer to a virtual base class, or - — the pointer is used as the operand of a - - static_cast - - , except when the conversion is to pointer to - - cv - - - void - - , or to pointer to - - cv - - - void - - and subsequently to pointer to either - - cv - - - char - - or - - cv - - - unsigned char - - , or - — the pointer is used as the operand of a - - dynamic_cast - - . -

    +

    Before the lifetime of an object has started but after the storage which the object will occupy has been allocated or, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, any pointer that refers to the storage location where the object will be or was located may be used but only in limited ways. For an object under construction or destruction, see 12.7. Otherwise, such a pointer refers to allocated storage, and using the pointer as if the pointer were of type void*, is well-defined. Indirection through such a pointer is permitted but the resulting lvalue may only be used in limited ways, as described below. The program has undefined behavior if: — the object will be or was of a class type with a non-trivial destructor and the pointer is used as the operand of a delete-expression, — the pointer is used to access a non-static data member or call a non-static member function of the object, or — the pointer is implicitly converted to a pointer to a virtual base class, or — the pointer is used as the operand of a static_cast, except when the conversion is to pointer to cv void, or to pointer to cv void and subsequently to pointer to either cv char or cv unsigned char, or — the pointer is used as the operand of a dynamic_cast.

    -

    - Paragraph 6 describes the lifetime rules for non-pointers: -

    +

    Paragraph 6 describes the lifetime rules for non-pointers:

    -

    - Similarly, before the lifetime of an object has started but after the storage which the object will occupy has been allocated or, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, any glvalue that refers to the original object may be used but only in limited ways. For an object under construction or destruction, see 12.7. Otherwise, such a glvalue refers to allocated storage, and using the properties of the glvalue that do not depend on its value is well-defined. The program has undefined behavior if: - — an lvalue-to-rvalue conversion is applied to such a glvalue, - — the glvalue is used to access a non-static data member or call a non-static member function of the object, or - — the glvalue is bound to a reference to a virtual base class, or - — the glvalue is used as the operand of a - - dynamic_cast - - or as the operand of - - typeid - - . -

    +

    Similarly, before the lifetime of an object has started but after the storage which the object will occupy has been allocated or, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, any glvalue that refers to the original object may be used but only in limited ways. For an object under construction or destruction, see 12.7. Otherwise, such a glvalue refers to allocated storage, and using the properties of the glvalue that do not depend on its value is well-defined. The program has undefined behavior if: — an lvalue-to-rvalue conversion is applied to such a glvalue, — the glvalue is used to access a non-static data member or call a non-static member function of the object, or — the glvalue is bound to a reference to a virtual base class, or — the glvalue is used as the operand of a dynamic_cast or as the operand of typeid.

    -

    - Do not use an object outside of its lifetime, except in the ways described above as being well-defined. -

    +

    Do not use an object outside of its lifetime, except in the ways described above as being well-defined.

    -

    - In this noncompliant code example, a pointer to an object is used to call a non-static member function of the object - prior to the beginning of the pointer's lifetime, - resulting in - - undefined behavior - - . -

    - - struct S { +

    In this noncompliant code example, a pointer to an object is used to call a non-static member function of the object prior to the beginning of the pointer's lifetime, resulting in undefined behavior.

    + struct S { void mem_fn(); }; -  + void f() { S *s; s->mem_fn(); -} - +}
    -

    - In this compliant solution, storage is obtained for the pointer prior to calling - - S::mem_fn(). - -

    - - struct S { +

    In this compliant solution, storage is obtained for the pointer prior to calling S::mem_fn().

    + struct S { void mem_fn(); }; @@ -130,67 +33,32 @@ void f() { S *s = new S; s->mem_fn(); delete s; -} - -

    - An improved compliant solution would not dynamically allocate memory directly but would instead use an automatic local variable to obtain the storage and perform initialization. If a pointer were required, use of a smart pointer, such as - - std::unique_ptr - - , would be a marked improvement. However, these suggested compliant solutions would distract from the lifetime demonstration of this compliant solution and consequently are not shown. -

    +}
    +

    An improved compliant solution would not dynamically allocate memory directly but would instead use an automatic local variable to obtain the storage and perform initialization. If a pointer were required, use of a smart pointer, such as std::unique_ptr, would be a marked improvement. However, these suggested compliant solutions would distract from the lifetime demonstration of this compliant solution and consequently are not shown.

    -

    - In this noncompliant code example, a pointer to an object is implicitly converted to a virtual base class after the object's lifetime has ended, resulting in - - undefined behavior - - . -

    - - struct B {}; -  +

    In this noncompliant code example, a pointer to an object is implicitly converted to a virtual base class after the object's lifetime has ended, resulting in undefined behavior.

    + struct B {}; + struct D1 : virtual B {}; struct D2 : virtual B {}; -  + struct S : D1, D2 {}; -  + void f(const B *b) {} -  + void g() { S *s = new S; // Use s delete s; -  + f(s); -} - -

    - Despite the fact that - - f() - - never makes use of the object, its being passed as an argument to - - f() - - is sufficient to trigger undefined behavior. -

    +}
    +

    Despite the fact that f() never makes use of the object, its being passed as an argument to f() is sufficient to trigger undefined behavior.

    -

    - In this compliant solution, the lifetime of - - s - - is extended to cover the call to - - f(). - -

    - - struct B {}; +

    In this compliant solution, the lifetime of s is extended to cover the call to f().

    + struct B {}; struct D1 : virtual B {}; struct D2 : virtual B {}; @@ -203,61 +71,28 @@ void g() { S *s = new S; // Use s f(s); -  + delete s; -} - +}
    -

    - In this noncompliant code example, the address of a local variable is returned from - - f() - - . When the resulting pointer is passed to - - h() - - , the lvalue-to-rvalue conversion applied to - - i - - results in - - undefined behavior - - . -

    - - int *g() { +

    In this noncompliant code example, the address of a local variable is returned from f(). When the resulting pointer is passed to h(), the lvalue-to-rvalue conversion applied to i results in undefined behavior.

    + int *g() { int i = 12; return &i; } -  + void h(int *i); -  + void f() { int *i = g(); h(i); -} - -

    - Some compilers generate a diagnostic message when a pointer to an object with automatic storage duration is returned from a function, as in this example. -

    +}
    +

    Some compilers generate a diagnostic message when a pointer to an object with automatic storage duration is returned from a function, as in this example.

    -

    - In this compliant solution, the local variable returned from - - g() - - has static storage duration instead of automatic storage duration, extending its lifetime sufficiently for use within - - f(). - -

    - - int *g() { +

    In this compliant solution, the local variable returned from g() has static storage duration instead of automatic storage duration, extending its lifetime sufficiently for use within f().

    + int *g() { static int i = 12; return &i; } @@ -268,49 +103,12 @@ void f() { int *i = g(); h(i); } - +
    -

    - A - - std::initializer_list<> - - object is constructed from an initializer list as though the implementation allocated a temporary array and passed it to the - - std::initializer_list<> - - constructor. This temporary array has the same lifetime as other temporary objects except that initializing a - - std::initializer_list<> - - object from the array extends the lifetime of the array exactly like binding a reference to a temporary [ - - ISO/IEC 14882-2014 - - ]. -

    -

    - In this noncompliant code example, a member variable of type - - std::initializer_list<int> - - is list-initialized within the constructor's - - ctor-initializer - - . Under these circumstances, the conceptual temporary array's lifetime ends once the constructor exits, so accessing any elements of the - - std::initializer_list<int> - - member variable results in - - undefined behavior - - . -

    - - #include <initializer_list> +

    A std::initializer_list<> object is constructed from an initializer list as though the implementation allocated a temporary array and passed it to the std::initializer_list<> constructor. This temporary array has the same lifetime as other temporary objects except that initializing a std::initializer_list<> object from the array extends the lifetime of the array exactly like binding a reference to a temporary [ISO/IEC 14882-2014].

    +

    In this noncompliant code example, a member variable of type std::initializer_list<int> is list-initialized within the constructor's ctor-initializer. Under these circumstances, the conceptual temporary array's lifetime ends once the constructor exits, so accessing any elements of the std::initializer_list<int> member variable results in undefined behavior.

    + #include <initializer_list> #include <iostream> class C { @@ -325,23 +123,11 @@ public: void f() { C c; std::cout << c.first(); -} - +}
    -

    - In this compliant solution, the - - std::initializer_list<int> - - member variable is replaced with a - - std::vector<int> - - , which copies the elements of the initializer list to the container instead of relying on a dangling reference to the temporary array. -

    - - #include <iostream> +

    In this compliant solution, the std::initializer_list<int> member variable is replaced with a std::vector<int>, which copies the elements of the initializer list to the container instead of relying on a dangling reference to the temporary array.

    + #include <iostream> #include <vector> class C { @@ -356,59 +142,23 @@ public: void f() { C c; std::cout << c.first(); -} - +}
    -

    - In this noncompliant code example, a lambda object is stored in a function object, which is later called (executing the lambda) to obtain a constant reference to a value. The lambda object returns an - - int - - value, which is then stored in a temporary - - int - - object that becomes bound to the - - const int & - - return type specified by the function object. However, the temporary object's lifetime is not extended past the return from the function object's invocation, which causes undefined behavior when the resulting value is accessed. -

    - - #include <functional> -  +

    In this noncompliant code example, a lambda object is stored in a function object, which is later called (executing the lambda) to obtain a constant reference to a value. The lambda object returns an int value, which is then stored in a temporary int object that becomes bound to the const int & return type specified by the function object. However, the temporary object's lifetime is not extended past the return from the function object's invocation, which causes undefined behavior when the resulting value is accessed.

    + #include <functional> + void f() { auto l = [](const int &j) { return j; }; std::function<const int&(const int &)> fn(l); -  + int i = 42; int j = fn(i); -} - +}
    -

    - In this compliant solution, the - - std::function - - object returns an - - int - - instead of a - - const int & - - , ensuring that the value is copied instead of bound to a temporary reference. An alternative solution would be to call the lambda directly instead of through the - - std::function<> - - object. -

    - - #include <functional> +

    In this compliant solution, the std::function object returns an int instead of a const int &, ensuring that the value is copied instead of bound to a temporary reference. An alternative solution would be to call the lambda directly instead of through the std::function<> object.

    + #include <functional> void f() { auto l = [](const int &j) { return j; }; @@ -416,122 +166,64 @@ void f() { int i = 42; int j = fn(i); -} - +}
    -

    - In this noncompliant code example, the constructor for the automatic variable - - s - - is not called because execution does not flow through the declaration of the local variable due to the - - goto - - statement. Because the constructor is not called, the lifetime for - - s - - has not begun. Therefore, calling - - S::f() - - uses the object outside of its lifetime and results in undefined behavior. -

    - - class S { +

    In this noncompliant code example, the constructor for the automatic variable s is not called because execution does not flow through the declaration of the local variable due to the goto statement. Because the constructor is not called, the lifetime for s has not begun. Therefore, calling S::f() uses the object outside of its lifetime and results in undefined behavior.

    + class S { int v; -  + public: S() : v(12) {} // Non-trivial constructor -  + void f(); -};   -  +}; + void f() { -  - // ...   -  - goto bad_idea;   -  + + // ... + + goto bad_idea; + // ... -  - S s; // Control passes over the declaration, so initialization does not take place.   -  + + S s; // Control passes over the declaration, so initialization does not take place. + bad_idea: s.f(); -} - +}
    -

    - This compliant solution ensures that - - s - - is properly initialized prior to performing the local jump. -

    - - class S { +

    This compliant solution ensures that s is properly initialized prior to performing the local jump.

    + class S { int v; -  + public: S() : v(12) {} // Non-trivial constructor void f(); -};   -  +}; + void f() { S s; -  + // ... -  + goto bad_idea; -  + // ... -  + bad_idea: s.f(); -} - +}
    -

    - In this noncompliant code example, - - - f() - - - is called with an iterable range of objects of type - - S - - . These objects are copied into a temporary buffer using - - std::copy() - - , and when processing of those objects is complete, the temporary buffer is deallocated. However, the buffer returned by - - std::get_temporary_buffer() - - does not contain initialized objects of type - - S - - , so when - - std::copy() - - dereferences the destination iterator, it results in undefined behavior because the object referenced by the destination iterator has yet to start its lifetime. This is because while space for the object has been allocated, no constructors or initializers have been invoked. -

    - - #include <algorithm> +

    In this noncompliant code example, f() is called with an iterable range of objects of type S. These objects are copied into a temporary buffer using std::copy(), and when processing of those objects is complete, the temporary buffer is deallocated. However, the buffer returned by std::get_temporary_buffer() does not contain initialized objects of type S, so when std::copy() dereferences the destination iterator, it results in undefined behavior because the object referenced by the destination iterator has yet to start its lifetime. This is because while space for the object has been allocated, no constructors or initializers have been invoked.

    + #include <algorithm> #include <cstddef> #include <memory> #include <type_traits> -  + class S { int i; @@ -566,95 +258,34 @@ void f(Iter i, Iter e) { // Return the temporary memory. std::return_temporary_buffer(vals); -} - -

    - - Implementation Details - -

    -

    - A reasonable implementation of - - std::get_temporary_buffer() - - and - - std::copy() - - can result in code that behaves like the following example (with error-checking elided). -

    - - unsigned char *buffer = new (std::nothrow) unsigned char[sizeof(S) * object_count]; +} +

    Implementation Details

    +

    A reasonable implementation of std::get_temporary_buffer() and std::copy() can result in code that behaves like the following example (with error-checking elided).

    + unsigned char *buffer = new (std::nothrow) unsigned char[sizeof(S) * object_count]; S *result = reinterpret_cast<S *>(buffer); while (i != e) { *result = *i; // Undefined behavior ++result; ++i; -} - -

    - The act of dereferencing - - result - - is undefined behavior because the memory pointed to is not an object of type - - S - - within its lifetime. -

    +}
    +

    The act of dereferencing result is undefined behavior because the memory pointed to is not an object of type S within its lifetime.

    -

    - In this compliant solution, - - std::uninitialized_copy() - - is used to perform the copy, instead of - - std::copy() - - , ensuring that the objects are initialized using placement - - new - - instead of dereferencing uninitialized memory. Identical code from the noncompliant code example has been elided for brevity. -

    - - //... +

    In this compliant solution, std::uninitialized_copy() is used to perform the copy, instead of std::copy(), ensuring that the objects are initialized using placement new instead of dereferencing uninitialized memory. Identical code from the noncompliant code example has been elided for brevity.

    + //... // Copy the values into the memory. std::uninitialized_copy(i, e, vals); -// ... - +// ...
    -

    - This compliant solution uses - - std::copy() - - with a - - std::raw_storage_iterator - - as the destination iterator with the same well-defined results as using - - std::uninitialized_copy() - - . As with the previous compliant solution, identical code from the noncompliant code example has been elided for brevity. -

    - - //... +

    This compliant solution uses std::copy() with a std::raw_storage_iterator as the destination iterator with the same well-defined results as using std::uninitialized_copy(). As with the previous compliant solution, identical code from the noncompliant code example has been elided for brevity.

    + //... // Copy the values into the memory. std::copy(i, e, std::raw_storage_iterator<S*, S>(vals)); -// ... - +// ...
    -

    - Referencing an object outside of its lifetime can result in an attacker being able to run arbitrary code. -

    +

    Referencing an object outside of its lifetime can result in an attacker being able to run arbitrary code.

    @@ -691,14 +322,10 @@ while (i != e) { High @@ -731,10 +358,7 @@ while (i != e) { 20.10 @@ -768,13 +388,10 @@ while (i != e) { @@ -808,106 +423,26 @@ while (i != e) { 2021.4 @@ -921,9 +456,7 @@ while (i != e) { @@ -999,12 +526,8 @@ while (i != e) { 4.4 @@ -1016,18 +539,10 @@ while (i != e) { @@ -1042,9 +557,7 @@ while (i != e) { 20.10
    - - P6 - + P6 - - L2 - + L2
    - - return-reference-local - dangling_pointer_use - + return-reference-localdangling_pointer_use Partially checked @@ -750,15 +374,11 @@ while (i != e) { 3.9 - - -Wdangling-initializer-list - + -Wdangling-initializer-list Catches some lifetime issues related to incorrect use of - - std::initializer_list<> - + std::initializer_list<>
    - 6.1p0 + 6.2p0 - - IO.UAC - ALLOC.UAF - + IO.UACALLOC.UAF Use after close @@ -791,9 +408,7 @@ while (i != e) { 2021.2 - - C++2812, C++2813, C++2814, C++2930, C++2931, C++2932, C++2933, C++2934, C++4003, C++4026 - + C++2812, C++2813, C++2814, C++2930, C++2931, C++2932, C++2933, C++2934, C++4003, C++4026 - - - CL.FFM.ASSIGN - - - - - CL.FFM.COPY - - - - - LOCRET.ARG - - - - - LOCRET.GLOB - - - - - LOCRET.RET - - - - - UFM.DEREF.MIGHT - - - - - UFM.DEREF.MUST - - - - - UFM.FFM.MIGHT - - - - - UFM.FFM.MUST - - - - - UFM.RETURN.MIGHT - - - - - UFM.RETURN.MUST - - - - - UFM.USE.MIGHT - - - - - UFM.USE.MUST - - - - - UNINIT.HEAP.MIGHT - - - - - UNINIT.HEAP.MUST - - - - - UNINIT.STACK.ARRAY.MIGHT - - - - - UNINIT.STACK.ARRAY.MUST - - - - - UNINIT.STACK.ARRAY.PARTIAL.MUST - - - - - UNINIT.STACK.MIGHT - - - - - UNINIT.STACK.MUST - - + CL.FFM.ASSIGN + CL.FFM.COPY + LOCRET.ARG + LOCRET.GLOB + LOCRET.RET + UFM.DEREF.MIGHT + UFM.DEREF.MUST + UFM.FFM.MIGHT + UFM.FFM.MUST + UFM.RETURN.MIGHT + UFM.RETURN.MUST + UFM.USE.MIGHT + UFM.USE.MUST + UNINIT.HEAP.MIGHT + UNINIT.HEAP.MUST + UNINIT.STACK.ARRAY.MIGHT + UNINIT.STACK.ARRAY.MUST + UNINIT.STACK.ARRAY.PARTIAL.MUST + UNINIT.STACK.MIGHT + UNINIT.STACK.MUST - - 42 D, 53 D, 77 D, 1 J, 71 S, 565 S - + 42 D, 53 D, 77 D, 1 J, 71 S, 565 S Partially implemented @@ -939,15 +472,9 @@ while (i != e) { 2021.2 - - CERT_CPP-EXP54-a - - - CERT_CPP-EXP54-b - - - CERT_CPP-EXP54-c - + CERT_CPP-EXP54-a + CERT_CPP-EXP54-b + CERT_CPP-EXP54-c Do not use resources that have been freed @@ -985,7 +512,7 @@ while (i != e) { Checks for: - Non-initialized variable or pointer, use of previously freed pointer, pointer or reference to stack variable leaving scope, accessing object with temporary lifetime. + Non-initialized variable or pointeron-initialized variable or pointer, use of previously freed pointerse of previously freed pointer, pointer or reference to stack variable leaving scopeointer or reference to stack variable leaving scope, accessing object with temporary lifetimeccessing object with temporary lifetime. Rule partially covered.
    - - 2812, 2813, 2814, 2930, 2931, - - - 2932, 2933, 2934, 4003, 4026 - + 2812, 2813, 2814, 2930, 2931, + 2932, 2933, 2934, 4003, 4026 - 7.16 + 7.17 - - - V758 - - , - - V1041 - - + V758, V1041 - - return-reference-local - + return-reference-local Partially checked @@ -1054,17 +567,7 @@ while (i != e) {
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/EXP54-CPP/ObjectAccessedBeforeLifetimeCert-standard.qhelp b/cpp/cert/src/rules/EXP54-CPP/ObjectAccessedBeforeLifetimeCert-standard.qhelp index 47781085bd..1e9a428728 100644 --- a/cpp/cert/src/rules/EXP54-CPP/ObjectAccessedBeforeLifetimeCert-standard.qhelp +++ b/cpp/cert/src/rules/EXP54-CPP/ObjectAccessedBeforeLifetimeCert-standard.qhelp @@ -1,128 +1,31 @@
    -

    - Every object has a lifetime in which it can be used in a well-defined manner. The lifetime of an object begins when sufficient, properly aligned storage has been obtained for it and its initialization is complete. The lifetime of an object ends when a nontrivial destructor, if any, is called for the object and the storage for the object has been reused or released. Use of an object, or a pointer to an object, outside of its lifetime frequently results in - - undefined behavior - - . -

    -

    - The C++ Standard, [basic.life], paragraph 5 [ - - ISO/IEC 14882-2014 - - ], describes the lifetime rules for pointers: -

    +

    Every object has a lifetime in which it can be used in a well-defined manner. The lifetime of an object begins when sufficient, properly aligned storage has been obtained for it and its initialization is complete. The lifetime of an object ends when a nontrivial destructor, if any, is called for the object and the storage for the object has been reused or released. Use of an object, or a pointer to an object, outside of its lifetime frequently results in undefined behavior.

    +

    The C++ Standard, [basic.life], paragraph 5 [ISO/IEC 14882-2014], describes the lifetime rules for pointers:

    -

    - Before the lifetime of an object has started but after the storage which the object will occupy has been allocated or, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, any pointer that refers to the storage location where the object will be or was located may be used but only in limited ways. For an object under construction or destruction, see 12.7. Otherwise, such a pointer refers to allocated storage, and using the pointer as if the pointer were of type - - void* - - , is well-defined. Indirection through such a pointer is permitted but the resulting lvalue may only be used in limited ways, as described below. The program has undefined behavior if: - — the object will be or was of a class type with a non-trivial destructor and the pointer is used as the operand of a - - delete-expression - - , - — the pointer is used to access a non-static data member or call a non-static member function of the object, or - — the pointer is implicitly converted to a pointer to a virtual base class, or - — the pointer is used as the operand of a - - static_cast - - , except when the conversion is to pointer to - - cv - - - void - - , or to pointer to - - cv - - - void - - and subsequently to pointer to either - - cv - - - char - - or - - cv - - - unsigned char - - , or - — the pointer is used as the operand of a - - dynamic_cast - - . -

    +

    Before the lifetime of an object has started but after the storage which the object will occupy has been allocated or, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, any pointer that refers to the storage location where the object will be or was located may be used but only in limited ways. For an object under construction or destruction, see 12.7. Otherwise, such a pointer refers to allocated storage, and using the pointer as if the pointer were of type void*, is well-defined. Indirection through such a pointer is permitted but the resulting lvalue may only be used in limited ways, as described below. The program has undefined behavior if: — the object will be or was of a class type with a non-trivial destructor and the pointer is used as the operand of a delete-expression, — the pointer is used to access a non-static data member or call a non-static member function of the object, or — the pointer is implicitly converted to a pointer to a virtual base class, or — the pointer is used as the operand of a static_cast, except when the conversion is to pointer to cv void, or to pointer to cv void and subsequently to pointer to either cv char or cv unsigned char, or — the pointer is used as the operand of a dynamic_cast.

    -

    - Paragraph 6 describes the lifetime rules for non-pointers: -

    +

    Paragraph 6 describes the lifetime rules for non-pointers:

    -

    - Similarly, before the lifetime of an object has started but after the storage which the object will occupy has been allocated or, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, any glvalue that refers to the original object may be used but only in limited ways. For an object under construction or destruction, see 12.7. Otherwise, such a glvalue refers to allocated storage, and using the properties of the glvalue that do not depend on its value is well-defined. The program has undefined behavior if: - — an lvalue-to-rvalue conversion is applied to such a glvalue, - — the glvalue is used to access a non-static data member or call a non-static member function of the object, or - — the glvalue is bound to a reference to a virtual base class, or - — the glvalue is used as the operand of a - - dynamic_cast - - or as the operand of - - typeid - - . -

    +

    Similarly, before the lifetime of an object has started but after the storage which the object will occupy has been allocated or, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, any glvalue that refers to the original object may be used but only in limited ways. For an object under construction or destruction, see 12.7. Otherwise, such a glvalue refers to allocated storage, and using the properties of the glvalue that do not depend on its value is well-defined. The program has undefined behavior if: — an lvalue-to-rvalue conversion is applied to such a glvalue, — the glvalue is used to access a non-static data member or call a non-static member function of the object, or — the glvalue is bound to a reference to a virtual base class, or — the glvalue is used as the operand of a dynamic_cast or as the operand of typeid.

    -

    - Do not use an object outside of its lifetime, except in the ways described above as being well-defined. -

    +

    Do not use an object outside of its lifetime, except in the ways described above as being well-defined.

    -

    - In this noncompliant code example, a pointer to an object is used to call a non-static member function of the object - prior to the beginning of the pointer's lifetime, - resulting in - - undefined behavior - - . -

    - - struct S { +

    In this noncompliant code example, a pointer to an object is used to call a non-static member function of the object prior to the beginning of the pointer's lifetime, resulting in undefined behavior.

    + struct S { void mem_fn(); }; -  + void f() { S *s; s->mem_fn(); -} - +}
    -

    - In this compliant solution, storage is obtained for the pointer prior to calling - - S::mem_fn(). - -

    - - struct S { +

    In this compliant solution, storage is obtained for the pointer prior to calling S::mem_fn().

    + struct S { void mem_fn(); }; @@ -130,67 +33,32 @@ void f() { S *s = new S; s->mem_fn(); delete s; -} - -

    - An improved compliant solution would not dynamically allocate memory directly but would instead use an automatic local variable to obtain the storage and perform initialization. If a pointer were required, use of a smart pointer, such as - - std::unique_ptr - - , would be a marked improvement. However, these suggested compliant solutions would distract from the lifetime demonstration of this compliant solution and consequently are not shown. -

    +}
    +

    An improved compliant solution would not dynamically allocate memory directly but would instead use an automatic local variable to obtain the storage and perform initialization. If a pointer were required, use of a smart pointer, such as std::unique_ptr, would be a marked improvement. However, these suggested compliant solutions would distract from the lifetime demonstration of this compliant solution and consequently are not shown.

    -

    - In this noncompliant code example, a pointer to an object is implicitly converted to a virtual base class after the object's lifetime has ended, resulting in - - undefined behavior - - . -

    - - struct B {}; -  +

    In this noncompliant code example, a pointer to an object is implicitly converted to a virtual base class after the object's lifetime has ended, resulting in undefined behavior.

    + struct B {}; + struct D1 : virtual B {}; struct D2 : virtual B {}; -  + struct S : D1, D2 {}; -  + void f(const B *b) {} -  + void g() { S *s = new S; // Use s delete s; -  + f(s); -} - -

    - Despite the fact that - - f() - - never makes use of the object, its being passed as an argument to - - f() - - is sufficient to trigger undefined behavior. -

    +}
    +

    Despite the fact that f() never makes use of the object, its being passed as an argument to f() is sufficient to trigger undefined behavior.

    -

    - In this compliant solution, the lifetime of - - s - - is extended to cover the call to - - f(). - -

    - - struct B {}; +

    In this compliant solution, the lifetime of s is extended to cover the call to f().

    + struct B {}; struct D1 : virtual B {}; struct D2 : virtual B {}; @@ -203,61 +71,28 @@ void g() { S *s = new S; // Use s f(s); -  + delete s; -} - +}
    -

    - In this noncompliant code example, the address of a local variable is returned from - - f() - - . When the resulting pointer is passed to - - h() - - , the lvalue-to-rvalue conversion applied to - - i - - results in - - undefined behavior - - . -

    - - int *g() { +

    In this noncompliant code example, the address of a local variable is returned from f(). When the resulting pointer is passed to h(), the lvalue-to-rvalue conversion applied to i results in undefined behavior.

    + int *g() { int i = 12; return &i; } -  + void h(int *i); -  + void f() { int *i = g(); h(i); -} - -

    - Some compilers generate a diagnostic message when a pointer to an object with automatic storage duration is returned from a function, as in this example. -

    +}
    +

    Some compilers generate a diagnostic message when a pointer to an object with automatic storage duration is returned from a function, as in this example.

    -

    - In this compliant solution, the local variable returned from - - g() - - has static storage duration instead of automatic storage duration, extending its lifetime sufficiently for use within - - f(). - -

    - - int *g() { +

    In this compliant solution, the local variable returned from g() has static storage duration instead of automatic storage duration, extending its lifetime sufficiently for use within f().

    + int *g() { static int i = 12; return &i; } @@ -268,49 +103,12 @@ void f() { int *i = g(); h(i); } - +
    -

    - A - - std::initializer_list<> - - object is constructed from an initializer list as though the implementation allocated a temporary array and passed it to the - - std::initializer_list<> - - constructor. This temporary array has the same lifetime as other temporary objects except that initializing a - - std::initializer_list<> - - object from the array extends the lifetime of the array exactly like binding a reference to a temporary [ - - ISO/IEC 14882-2014 - - ]. -

    -

    - In this noncompliant code example, a member variable of type - - std::initializer_list<int> - - is list-initialized within the constructor's - - ctor-initializer - - . Under these circumstances, the conceptual temporary array's lifetime ends once the constructor exits, so accessing any elements of the - - std::initializer_list<int> - - member variable results in - - undefined behavior - - . -

    - - #include <initializer_list> +

    A std::initializer_list<> object is constructed from an initializer list as though the implementation allocated a temporary array and passed it to the std::initializer_list<> constructor. This temporary array has the same lifetime as other temporary objects except that initializing a std::initializer_list<> object from the array extends the lifetime of the array exactly like binding a reference to a temporary [ISO/IEC 14882-2014].

    +

    In this noncompliant code example, a member variable of type std::initializer_list<int> is list-initialized within the constructor's ctor-initializer. Under these circumstances, the conceptual temporary array's lifetime ends once the constructor exits, so accessing any elements of the std::initializer_list<int> member variable results in undefined behavior.

    + #include <initializer_list> #include <iostream> class C { @@ -325,23 +123,11 @@ public: void f() { C c; std::cout << c.first(); -} - +}
    -

    - In this compliant solution, the - - std::initializer_list<int> - - member variable is replaced with a - - std::vector<int> - - , which copies the elements of the initializer list to the container instead of relying on a dangling reference to the temporary array. -

    - - #include <iostream> +

    In this compliant solution, the std::initializer_list<int> member variable is replaced with a std::vector<int>, which copies the elements of the initializer list to the container instead of relying on a dangling reference to the temporary array.

    + #include <iostream> #include <vector> class C { @@ -356,59 +142,23 @@ public: void f() { C c; std::cout << c.first(); -} - +}
    -

    - In this noncompliant code example, a lambda object is stored in a function object, which is later called (executing the lambda) to obtain a constant reference to a value. The lambda object returns an - - int - - value, which is then stored in a temporary - - int - - object that becomes bound to the - - const int & - - return type specified by the function object. However, the temporary object's lifetime is not extended past the return from the function object's invocation, which causes undefined behavior when the resulting value is accessed. -

    - - #include <functional> -  +

    In this noncompliant code example, a lambda object is stored in a function object, which is later called (executing the lambda) to obtain a constant reference to a value. The lambda object returns an int value, which is then stored in a temporary int object that becomes bound to the const int & return type specified by the function object. However, the temporary object's lifetime is not extended past the return from the function object's invocation, which causes undefined behavior when the resulting value is accessed.

    + #include <functional> + void f() { auto l = [](const int &j) { return j; }; std::function<const int&(const int &)> fn(l); -  + int i = 42; int j = fn(i); -} - +}
    -

    - In this compliant solution, the - - std::function - - object returns an - - int - - instead of a - - const int & - - , ensuring that the value is copied instead of bound to a temporary reference. An alternative solution would be to call the lambda directly instead of through the - - std::function<> - - object. -

    - - #include <functional> +

    In this compliant solution, the std::function object returns an int instead of a const int &, ensuring that the value is copied instead of bound to a temporary reference. An alternative solution would be to call the lambda directly instead of through the std::function<> object.

    + #include <functional> void f() { auto l = [](const int &j) { return j; }; @@ -416,122 +166,64 @@ void f() { int i = 42; int j = fn(i); -} - +}
    -

    - In this noncompliant code example, the constructor for the automatic variable - - s - - is not called because execution does not flow through the declaration of the local variable due to the - - goto - - statement. Because the constructor is not called, the lifetime for - - s - - has not begun. Therefore, calling - - S::f() - - uses the object outside of its lifetime and results in undefined behavior. -

    - - class S { +

    In this noncompliant code example, the constructor for the automatic variable s is not called because execution does not flow through the declaration of the local variable due to the goto statement. Because the constructor is not called, the lifetime for s has not begun. Therefore, calling S::f() uses the object outside of its lifetime and results in undefined behavior.

    + class S { int v; -  + public: S() : v(12) {} // Non-trivial constructor -  + void f(); -};   -  +}; + void f() { -  - // ...   -  - goto bad_idea;   -  + + // ... + + goto bad_idea; + // ... -  - S s; // Control passes over the declaration, so initialization does not take place.   -  + + S s; // Control passes over the declaration, so initialization does not take place. + bad_idea: s.f(); -} - +}
    -

    - This compliant solution ensures that - - s - - is properly initialized prior to performing the local jump. -

    - - class S { +

    This compliant solution ensures that s is properly initialized prior to performing the local jump.

    + class S { int v; -  + public: S() : v(12) {} // Non-trivial constructor void f(); -};   -  +}; + void f() { S s; -  + // ... -  + goto bad_idea; -  + // ... -  + bad_idea: s.f(); -} - +}
    -

    - In this noncompliant code example, - - - f() - - - is called with an iterable range of objects of type - - S - - . These objects are copied into a temporary buffer using - - std::copy() - - , and when processing of those objects is complete, the temporary buffer is deallocated. However, the buffer returned by - - std::get_temporary_buffer() - - does not contain initialized objects of type - - S - - , so when - - std::copy() - - dereferences the destination iterator, it results in undefined behavior because the object referenced by the destination iterator has yet to start its lifetime. This is because while space for the object has been allocated, no constructors or initializers have been invoked. -

    - - #include <algorithm> +

    In this noncompliant code example, f() is called with an iterable range of objects of type S. These objects are copied into a temporary buffer using std::copy(), and when processing of those objects is complete, the temporary buffer is deallocated. However, the buffer returned by std::get_temporary_buffer() does not contain initialized objects of type S, so when std::copy() dereferences the destination iterator, it results in undefined behavior because the object referenced by the destination iterator has yet to start its lifetime. This is because while space for the object has been allocated, no constructors or initializers have been invoked.

    + #include <algorithm> #include <cstddef> #include <memory> #include <type_traits> -  + class S { int i; @@ -566,95 +258,34 @@ void f(Iter i, Iter e) { // Return the temporary memory. std::return_temporary_buffer(vals); -} - -

    - - Implementation Details - -

    -

    - A reasonable implementation of - - std::get_temporary_buffer() - - and - - std::copy() - - can result in code that behaves like the following example (with error-checking elided). -

    - - unsigned char *buffer = new (std::nothrow) unsigned char[sizeof(S) * object_count]; +} +

    Implementation Details

    +

    A reasonable implementation of std::get_temporary_buffer() and std::copy() can result in code that behaves like the following example (with error-checking elided).

    + unsigned char *buffer = new (std::nothrow) unsigned char[sizeof(S) * object_count]; S *result = reinterpret_cast<S *>(buffer); while (i != e) { *result = *i; // Undefined behavior ++result; ++i; -} - -

    - The act of dereferencing - - result - - is undefined behavior because the memory pointed to is not an object of type - - S - - within its lifetime. -

    +}
    +

    The act of dereferencing result is undefined behavior because the memory pointed to is not an object of type S within its lifetime.

    -

    - In this compliant solution, - - std::uninitialized_copy() - - is used to perform the copy, instead of - - std::copy() - - , ensuring that the objects are initialized using placement - - new - - instead of dereferencing uninitialized memory. Identical code from the noncompliant code example has been elided for brevity. -

    - - //... +

    In this compliant solution, std::uninitialized_copy() is used to perform the copy, instead of std::copy(), ensuring that the objects are initialized using placement new instead of dereferencing uninitialized memory. Identical code from the noncompliant code example has been elided for brevity.

    + //... // Copy the values into the memory. std::uninitialized_copy(i, e, vals); -// ... - +// ...
    -

    - This compliant solution uses - - std::copy() - - with a - - std::raw_storage_iterator - - as the destination iterator with the same well-defined results as using - - std::uninitialized_copy() - - . As with the previous compliant solution, identical code from the noncompliant code example has been elided for brevity. -

    - - //... +

    This compliant solution uses std::copy() with a std::raw_storage_iterator as the destination iterator with the same well-defined results as using std::uninitialized_copy(). As with the previous compliant solution, identical code from the noncompliant code example has been elided for brevity.

    + //... // Copy the values into the memory. std::copy(i, e, std::raw_storage_iterator<S*, S>(vals)); -// ... - +// ...
    -

    - Referencing an object outside of its lifetime can result in an attacker being able to run arbitrary code. -

    +

    Referencing an object outside of its lifetime can result in an attacker being able to run arbitrary code.

    @@ -691,14 +322,10 @@ while (i != e) { High @@ -731,10 +358,7 @@ while (i != e) { 20.10 @@ -768,13 +388,10 @@ while (i != e) { @@ -808,106 +423,26 @@ while (i != e) { 2021.4 @@ -921,9 +456,7 @@ while (i != e) { @@ -999,12 +526,8 @@ while (i != e) { 4.4 @@ -1016,18 +539,10 @@ while (i != e) { @@ -1042,9 +557,7 @@ while (i != e) { 20.10
    - - P6 - + P6 - - L2 - + L2
    - - return-reference-local - dangling_pointer_use - + return-reference-localdangling_pointer_use Partially checked @@ -750,15 +374,11 @@ while (i != e) { 3.9 - - -Wdangling-initializer-list - + -Wdangling-initializer-list Catches some lifetime issues related to incorrect use of - - std::initializer_list<> - + std::initializer_list<>
    - 6.1p0 + 6.2p0 - - IO.UAC - ALLOC.UAF - + IO.UACALLOC.UAF Use after close @@ -791,9 +408,7 @@ while (i != e) { 2021.2 - - C++2812, C++2813, C++2814, C++2930, C++2931, C++2932, C++2933, C++2934, C++4003, C++4026 - + C++2812, C++2813, C++2814, C++2930, C++2931, C++2932, C++2933, C++2934, C++4003, C++4026 - - - CL.FFM.ASSIGN - - - - - CL.FFM.COPY - - - - - LOCRET.ARG - - - - - LOCRET.GLOB - - - - - LOCRET.RET - - - - - UFM.DEREF.MIGHT - - - - - UFM.DEREF.MUST - - - - - UFM.FFM.MIGHT - - - - - UFM.FFM.MUST - - - - - UFM.RETURN.MIGHT - - - - - UFM.RETURN.MUST - - - - - UFM.USE.MIGHT - - - - - UFM.USE.MUST - - - - - UNINIT.HEAP.MIGHT - - - - - UNINIT.HEAP.MUST - - - - - UNINIT.STACK.ARRAY.MIGHT - - - - - UNINIT.STACK.ARRAY.MUST - - - - - UNINIT.STACK.ARRAY.PARTIAL.MUST - - - - - UNINIT.STACK.MIGHT - - - - - UNINIT.STACK.MUST - - + CL.FFM.ASSIGN + CL.FFM.COPY + LOCRET.ARG + LOCRET.GLOB + LOCRET.RET + UFM.DEREF.MIGHT + UFM.DEREF.MUST + UFM.FFM.MIGHT + UFM.FFM.MUST + UFM.RETURN.MIGHT + UFM.RETURN.MUST + UFM.USE.MIGHT + UFM.USE.MUST + UNINIT.HEAP.MIGHT + UNINIT.HEAP.MUST + UNINIT.STACK.ARRAY.MIGHT + UNINIT.STACK.ARRAY.MUST + UNINIT.STACK.ARRAY.PARTIAL.MUST + UNINIT.STACK.MIGHT + UNINIT.STACK.MUST - - 42 D, 53 D, 77 D, 1 J, 71 S, 565 S - + 42 D, 53 D, 77 D, 1 J, 71 S, 565 S Partially implemented @@ -939,15 +472,9 @@ while (i != e) { 2021.2 - - CERT_CPP-EXP54-a - - - CERT_CPP-EXP54-b - - - CERT_CPP-EXP54-c - + CERT_CPP-EXP54-a + CERT_CPP-EXP54-b + CERT_CPP-EXP54-c Do not use resources that have been freed @@ -985,7 +512,7 @@ while (i != e) { Checks for: - Non-initialized variable or pointer, use of previously freed pointer, pointer or reference to stack variable leaving scope, accessing object with temporary lifetime. + Non-initialized variable or pointeron-initialized variable or pointer, use of previously freed pointerse of previously freed pointer, pointer or reference to stack variable leaving scopeointer or reference to stack variable leaving scope, accessing object with temporary lifetimeccessing object with temporary lifetime. Rule partially covered.
    - - 2812, 2813, 2814, 2930, 2931, - - - 2932, 2933, 2934, 4003, 4026 - + 2812, 2813, 2814, 2930, 2931, + 2932, 2933, 2934, 4003, 4026 - 7.16 + 7.17 - - - V758 - - , - - V1041 - - + V758, V1041 - - return-reference-local - + return-reference-local Partially checked @@ -1054,17 +567,7 @@ while (i != e) {
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/EXP55-CPP/RemoveConstOrVolatileQualificationCert-standard.qhelp b/cpp/cert/src/rules/EXP55-CPP/RemoveConstOrVolatileQualificationCert-standard.qhelp index ea3ee4b8c0..9639961b58 100644 --- a/cpp/cert/src/rules/EXP55-CPP/RemoveConstOrVolatileQualificationCert-standard.qhelp +++ b/cpp/cert/src/rules/EXP55-CPP/RemoveConstOrVolatileQualificationCert-standard.qhelp @@ -1,72 +1,19 @@
    -

    - The C++ Standard, [dcl.type.cv], paragraph 4 [ - - ISO/IEC 14882-2014 - - ], states the following: -

    +

    The C++ Standard, [dcl.type.cv], paragraph 4 [ISO/IEC 14882-2014], states the following:

    -

    - Except that any class member declared - - mutable - - can be modified, any attempt to modify a - - const - - object during its lifetime results in undefined behavior. -

    +

    Except that any class member declared mutable can be modified, any attempt to modify a const object during its lifetime results in undefined behavior.

    -

    - Similarly, paragraph 6 states the following: -

    +

    Similarly, paragraph 6 states the following:

    -

    - What constitutes an access to an object that has volatile-qualified type is implementation-defined. If an attempt is made to refer to an object defined with a volatile-qualified type through the use of a glvalue with a non-volatile-qualified type, the program behavior is undefined. -

    +

    What constitutes an access to an object that has volatile-qualified type is implementation-defined. If an attempt is made to refer to an object defined with a volatile-qualified type through the use of a glvalue with a non-volatile-qualified type, the program behavior is undefined.

    -

    - Do not cast away a - - const - - qualification to attempt to modify the resulting object. The - - const - - qualifier implies that the API designer does not intend for that object to be modified despite the possibility it may be modifiable. Do not cast away a - - volatile - - qualification; the - - volatile - - qualifier implies that the API designer intends the object to be accessed in ways unknown to the compiler, and any access of the volatile object results in - - undefined behavior - - . -

    +

    Do not cast away a const qualification to attempt to modify the resulting object. The const qualifier implies that the API designer does not intend for that object to be modified despite the possibility it may be modifiable. Do not cast away a volatile qualification; the volatile qualifier implies that the API designer intends the object to be accessed in ways unknown to the compiler, and any access of the volatile object results in undefined behavior.

    -

    - In this noncompliant code example, the function - - g - - () is passed a const int &, which is then cast to an int & and modified. Because the referenced value was previously declared as const, the assignment operation results in - - undefined behavior - - . -

    - - void g(const int &ci) { +

    In this noncompliant code example, the function g() is passed a const int &, which is then cast to an int & and modified. Because the referenced value was previously declared as const, the assignment operation results in undefined behavior.

    + void g(const int &ci) { int &ir = const_cast<int &>(ci); ir = 42; } @@ -74,27 +21,11 @@ void f() { const int i = 4; g(i); -} - +}
    -

    - In this compliant solution, the function - - g() - - is passed an - - int & - - , and the caller is required to pass an - - int - - that can be modified. -

    - - void g(int &i) { +

    In this compliant solution, the function g() is passed an int &, and the caller is required to pass an int that can be modified.

    + void g(int &i) { i = 42; } @@ -102,43 +33,12 @@ void f() { int i = 4; g(i); } - +
    -

    - In this noncompliant code example, a - - const - - -qualified method is called that attempts to cache results by casting away the - - const - - -qualifier of - - this - - . Because - - s - - was declared - - const - - , the mutation of - - cachedValue - - results in - - undefined behavior - - . -

    - - #include <iostream> -  +

    In this noncompliant code example, a const-qualified method is called that attempts to cache results by casting away the const-qualifier of this. Because s was declared const, the mutation of cachedValue results in undefined behavior.

    + #include <iostream> + class S { int cachedValue; @@ -158,37 +58,11 @@ public: void f() { const S s; std::cout << s.get_value() << std::endl; -} - +}
    -

    - This compliant solution uses the - - - mutable - - - keyword when declaring - - cachedValue - - , which allows - - cachedValue - - to be mutated within a - - const - - context without triggering - - undefined behavior - - . -

    - - #include <iostream> +

    This compliant solution uses the mutable keyword when declaring cachedValue, which allows cachedValue to be mutated within a const context without triggering undefined behavior.

    + #include <iostream> class S { mutable int cachedValue; @@ -209,31 +83,11 @@ public: void f() { const S s; std::cout << s.get_value() << std::endl; -} - +}
    -

    - In this noncompliant code example, the volatile value - - s - - has the - - volatile - - qualifier cast away, and an attempt is made to read the value within - - g() - - , resulting in - - undefined behavior - - . -

    - - #include <iostream> +

    In this noncompliant code example, the volatile value s has the volatile qualifier cast away, and an attempt is made to read the value within g(), resulting in undefined behavior.

    + #include <iostream> struct S { int i; @@ -248,26 +102,11 @@ void g(S &s) { void f() { volatile S s(12); g(const_cast<S &>(s)); -} - +}
    -

    - This compliant solution assumes that the volatility of - - s - - is required, so - - g() - - is modified to accept a - - volatile S &. - -

    - - #include <iostream> +

    This compliant solution assumes that the volatility of s is required, so g() is modified to accept a volatile S &.

    + #include <iostream> struct S { int i; @@ -282,63 +121,21 @@ void g(volatile S &s) { void f() { volatile S s(12); g(s); -} - +}
    -

    - - EXP55-CPP-EX1: - - An exception to this rule is allowed when it is necessary to cast away - - const - - when invoking a legacy API that does not accept a - - const - - argument, provided the function does not attempt to modify the referenced variable. However, it is always preferable to modify the API to be - - const - - -correct when possible. For example, the following code casts away the - - const - - qualification of - - INVFNAME - - in the call to the - - audit_log() - - function. -

    - - // Legacy function defined elsewhere - cannot be modified; does not attempt to +

    EXP55-CPP-EX1: An exception to this rule is allowed when it is necessary to cast away const when invoking a legacy API that does not accept a const argument, provided the function does not attempt to modify the referenced variable. However, it is always preferable to modify the API to be const-correct when possible. For example, the following code casts away the const qualification of INVFNAME in the call to the audit_log() function.

    + // Legacy function defined elsewhere - cannot be modified; does not attempt to // modify the contents of the passed parameter. void audit_log(char *errstr); void f() { const char INVFNAME[] = "Invalid file name."; audit_log(const_cast<char *>(INVFNAME)); -} - +}
    -

    - If the object is declared as being constant, it may reside in write-protected memory at runtime. Attempting to modify such an object may lead to - - abnormal program termination - - or a - - denial-of-service attack - - . If an object is declared as being volatile, the compiler can make no assumptions regarding access of that object. Casting away the volatility of an object can result in reads or writes to the object being reordered or elided entirely, resulting in abnormal program execution. -

    +

    If the object is declared as being constant, it may reside in write-protected memory at runtime. Attempting to modify such an object may lead to abnormal program termination or a denial-of-service attack. If an object is declared as being volatile, the compiler can make no assumptions regarding access of that object. Casting away the volatility of an object can result in reads or writes to the object being reordered or elided entirely, resulting in abnormal program execution.

    @@ -375,14 +172,10 @@ void f() { Medium @@ -415,10 +208,7 @@ void f() { 20.10 @@ -451,9 +239,7 @@ void f() { 2021.2 @@ -468,11 +254,7 @@ void f() { 2021.4 @@ -486,9 +268,7 @@ void f() { @@ -557,10 +333,7 @@ void f() { 20.10 @@ -589,17 +358,7 @@ void f() {
    - - P8 - + P8 - - L2 - + L2
    - - pointer-qualifier-cast-const - pointer-qualifier-cast-volatile - + pointer-qualifier-cast-constpointer-qualifier-cast-volatile Partially checked @@ -434,9 +224,7 @@ void f() { 7.2.0 - - CertC++-EXP55 - + CertC++-EXP55 - - C++3066, C++4671 - + C++3066, C++4671 - - - MISRA.CAST.CONST - - + MISRA.CAST.CONST - - 203 S, 242 S, 344 S - + 203 S, 242 S, 344 S Fully implemented @@ -504,9 +284,7 @@ void f() { 2021.2 - - CERT_CPP-EXP55-a - + CERT_CPP-EXP55-a A cast shall not remove any 'const' or 'volatile' qualification from the type of a pointer or reference @@ -540,9 +318,7 @@ void f() { 4.4 - - 3066, 4671 - + 3066, 4671 - - pointer-qualifier-cast-const - pointer-qualifier-cast-volatile - + pointer-qualifier-cast-constpointer-qualifier-cast-volatile Partially checked @@ -576,11 +349,7 @@ void f() { 4.10 - - - S859 - - + S859
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    @@ -651,9 +410,7 @@ void f() { diff --git a/cpp/cert/src/rules/EXP56-CPP/FunctionWithMismatchedLanguageLinkage-standard.qhelp b/cpp/cert/src/rules/EXP56-CPP/FunctionWithMismatchedLanguageLinkage-standard.qhelp index 58b771b147..52c977d290 100644 --- a/cpp/cert/src/rules/EXP56-CPP/FunctionWithMismatchedLanguageLinkage-standard.qhelp +++ b/cpp/cert/src/rules/EXP56-CPP/FunctionWithMismatchedLanguageLinkage-standard.qhelp @@ -1,108 +1,22 @@
    -

    - C++ allows a degree of interoperability with other languages through the use of language linkage specifications. These specifications affect the way in which functions are called or data is accessed. By default, all function types, as well as function and variable names, with external linkage have C++ language linkage, though a different language linkage may be specified. Implementations are required to support - - "C" and - - "C++" - - - as a language linkage, but other language linkages exist with implementation-defined semantics, such as - - "java" - - , - - "Ada" - - , and - - "FORTRAN" - - . -

    -

    - Language linkage is specified to be part of the function type, according to the C++ Standard, [dcl.link], paragraph 1 [ - - ISO/IEC 14882-2014 - - ], which, in part, states the following: -

    +

    C++ allows a degree of interoperability with other languages through the use of language linkage specifications. These specifications affect the way in which functions are called or data is accessed. By default, all function types, as well as function and variable names, with external linkage have C++ language linkage, though a different language linkage may be specified. Implementations are required to support "C" and "C++" as a language linkage, but other language linkages exist with implementation-defined semantics, such as "java", "Ada", and "FORTRAN".

    +

    Language linkage is specified to be part of the function type, according to the C++ Standard, [dcl.link], paragraph 1 [ISO/IEC 14882-2014], which, in part, states the following:

    -

    - Two function types with different language linkages are distinct types even if they are otherwise identical. -

    +

    Two function types with different language linkages are distinct types even if they are otherwise identical.

    -

    - When calling a function, it is - - undefined behavior - - if the language linkage of the function type used in the call does not match the language linkage of the function definition. For instance, a mismatch in language linkage specification may corrupt the call stack due to calling conventions or other ABI mismatches. -

    -

    - Do not call a function through a type whose language linkage does not match the language linkage of the called function's definition. This restriction applies both to functions called within a C++ program as well as function pointers used to make a function call from outside of the C++ program. -

    -

    - However, many compilers fail to integrate language linkage into the function's type, despite the normative requirement to do so in the C++ Standard. For instance, - - GCC - - 6.1.0, - - Clang - - 3.9, and - - Microsoft Visual Studio - - 2015 all consider the following code snippet to be - - ill-formed - - due to a redefinition of - - f() - - rather than a - - well-formed - - overload of - - f() - - . -

    - - typedef void (*cpp_func)(void); +

    When calling a function, it is undefined behavior if the language linkage of the function type used in the call does not match the language linkage of the function definition. For instance, a mismatch in language linkage specification may corrupt the call stack due to calling conventions or other ABI mismatches.

    +

    Do not call a function through a type whose language linkage does not match the language linkage of the called function's definition. This restriction applies both to functions called within a C++ program as well as function pointers used to make a function call from outside of the C++ program.

    +

    However, many compilers fail to integrate language linkage into the function's type, despite the normative requirement to do so in the C++ Standard. For instance, GCC 6.1.0, Clang 3.9, and Microsoft Visual Studio 2015 all consider the following code snippet to be ill-formed due to a redefinition of f() rather than a well-formed overload of f().

    + typedef void (*cpp_func)(void); extern "C" typedef void (*c_func)(void); void f(cpp_func fp) {} -void f(c_func fp) {} - -

    - Some compilers conform to the C++ Standard, but only in their strictest conformance mode, such as EDG 4.11. This implementation divergence from the C++ Standard is a matter of practical design trade-offs. Compilers are required to support only the - - "C" - - and - - "C++" - - language linkages, and interoperability between these two languages often does not require significant code generation differences beyond the mangling of function types for most common architectures such as x86, x86-64, and ARM. There are extant Standard Template Library implementations for which language linkage specifications being correctly implemented as part of the function type would break existing code on common platforms where the language linkage has no effect on the runtime implementation of a function call. -

    -

    - It is acceptable to call a function with a mismatched language linkage when the combination of language linkage specifications, runtime platform, and compiler implementation result in no effect on runtime behavior of the function call. For instance, the following code is permissible when compiled with Microsoft Visual Studio 2015 for x86, despite the lambda function call operator implicitly converting to a function pointer type with C++ language linkage, while - - qsort() - - expects a function pointer with C language linkage. -

    - - #include <cstdlib> +void f(c_func fp) {} +

    Some compilers conform to the C++ Standard, but only in their strictest conformance mode, such as EDG 4.11. This implementation divergence from the C++ Standard is a matter of practical design trade-offs. Compilers are required to support only the "C" and "C++" language linkages, and interoperability between these two languages often does not require significant code generation differences beyond the mangling of function types for most common architectures such as x86, x86-64, and ARM. There are extant Standard Template Library implementations for which language linkage specifications being correctly implemented as part of the function type would break existing code on common platforms where the language linkage has no effect on the runtime implementation of a function call.

    +

    It is acceptable to call a function with a mismatched language linkage when the combination of language linkage specifications, runtime platform, and compiler implementation result in no effect on runtime behavior of the function call. For instance, the following code is permissible when compiled with Microsoft Visual Studio 2015 for x86, despite the lambda function call operator implicitly converting to a function pointer type with C++ language linkage, while qsort() expects a function pointer with C language linkage.

    + #include <cstdlib> void f(int *int_list, size_t count) { std::qsort(int_list, count, sizeof(int), @@ -111,74 +25,32 @@ void f(int *int_list, size_t count) { reinterpret_cast<const int *>(rhs); }); } - +
    -

    - In this noncompliant code example, the - - call_java_fn_ptr() - - function expects to receive a function pointer with - - "java" - - language linkage because that function pointer will be used by a Java interpreter to call back into the C++ code. However, the function is given a pointer with - - "C++" - - language linkage instead, resulting in undefined behavior when the interpreter attempts to call the function pointer. This code should be ill-formed because the type of - - callback_func() - - is different than the type - - java_callback. However, - - due to common implementation divergence from the C++ Standard, some compilers may incorrectly accept this code without issuing a diagnostic. -

    - - extern "java" typedef void (*java_callback)(int); -  +

    In this noncompliant code example, the call_java_fn_ptr() function expects to receive a function pointer with "java" language linkage because that function pointer will be used by a Java interpreter to call back into the C++ code. However, the function is given a pointer with "C++" language linkage instead, resulting in undefined behavior when the interpreter attempts to call the function pointer. This code should be ill-formed because the type of callback_func() is different than the type java_callback. However, due to common implementation divergence from the C++ Standard, some compilers may incorrectly accept this code without issuing a diagnostic.

    + extern "java" typedef void (*java_callback)(int); + extern void call_java_fn_ptr(java_callback callback); void callback_func(int); -  + void f() { call_java_fn_ptr(callback_func); -} - +}
    -

    - In this compliant solution, the - - callback_func() - - function is given - - "java" - - language linkage to match the language linkage for - - java_callback - - . -

    - - extern "java" typedef void (*java_callback)(int); +

    In this compliant solution, the callback_func() function is given "java" language linkage to match the language linkage for java_callback.

    + extern "java" typedef void (*java_callback)(int); extern void call_java_fn_ptr(java_callback callback); extern "java" void callback_func(int); void f() { call_java_fn_ptr(callback_func); -} - +}
    -

    - Mismatched language linkage specifications generally do not create exploitable security vulnerabilities between the C and C++ language linkages. However, other language linkages exist where the undefined behavior is more likely to result in abnormal program execution, including exploitable vulnerabilities. -

    +

    Mismatched language linkage specifications generally do not create exploitable security vulnerabilities between the C and C++ language linkages. However, other language linkages exist where the undefined behavior is more likely to result in abnormal program execution, including exploitable vulnerabilities.

    Item 94, "Avoid Casting Away - - const - + const "
    @@ -215,14 +87,10 @@ void f() { Medium @@ -255,9 +123,7 @@ void f() { 2021.2 @@ -272,36 +138,12 @@ void f() { 2021.4 @@ -316,9 +158,7 @@ void f() { 2021.2 @@ -345,17 +183,7 @@ void f() {
    - - P2 - + P2 - - L3 - + L3
    - - C++3033, C++3038 - + C++3033, C++3038 - - - PORTING.CAST.PTR - - - - - PORTING.CAST.PTR.FLTPNT - - - - - PORTING.CAST.PTR.SIZE - - - - - PORTING.CAST.SIZE - - - - - MISRA.CAST.PTR.UNRELATED - - - - - MISRA.CAST.PTR_TO_INT - - + PORTING.CAST.PTR + PORTING.CAST.PTR.FLTPNT + PORTING.CAST.PTR.SIZE + PORTING.CAST.SIZE + MISRA.CAST.PTR.UNRELATED + MISRA.CAST.PTR_TO_INT - - CERT_CPP-EXP56-a - + CERT_CPP-EXP56-a Do not call a function with a mismatched language linkage @@ -334,9 +174,7 @@ void f() { 4.4 - - 3033. 3038 - + 3033. 3038
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/EXP57-CPP/CastOfPointerToIncompleteClass-standard.qhelp b/cpp/cert/src/rules/EXP57-CPP/CastOfPointerToIncompleteClass-standard.qhelp index 4d0b452eb5..a8510f29ba 100644 --- a/cpp/cert/src/rules/EXP57-CPP/CastOfPointerToIncompleteClass-standard.qhelp +++ b/cpp/cert/src/rules/EXP57-CPP/CastOfPointerToIncompleteClass-standard.qhelp @@ -1,117 +1,28 @@
    -

    - Referring to objects of incomplete class type, also known as - - forward declarations - - , is a common practice. One such common usage is with the "pimpl idiom" [ - - Sutter 00 - - ] whereby an opaque pointer is used to hide implementation details from a public-facing API. However, attempting to delete a pointer to an object of incomplete class type can lead to - - undefined behavior - - . The C++ Standard, [expr.delete], paragraph 5 [ - - ISO/IEC 14882-2014 - - ], states the following: -

    +

    Referring to objects of incomplete class type, also known as forward declarations, is a common practice. One such common usage is with the "pimpl idiom" [Sutter 00] whereby an opaque pointer is used to hide implementation details from a public-facing API. However, attempting to delete a pointer to an object of incomplete class type can lead to undefined behavior. The C++ Standard, [expr.delete], paragraph 5 [ISO/IEC 14882-2014], states the following:

    -

    - If the object being deleted has incomplete class type at the point of deletion and the complete class has a non-trivial destructor or a deallocation function, the behavior is undefined. -

    +

    If the object being deleted has incomplete class type at the point of deletion and the complete class has a non-trivial destructor or a deallocation function, the behavior is undefined.

    -

    - Do not attempt to delete a pointer to an object of - - incomplete type - - . Although it is well-formed if the class has no nontrivial destructor and no associated deallocation function, it would become undefined behavior were a nontrivial destructor or deallocation function added later. It would be possible to check for a nontrivial destructor at compile time using a - - static_assert - - and the - - std::is_trivially_destructible - - type trait, but no such type trait exists to test for the presence of a deallocation function. -

    -

    - Pointer downcasting to a pointer of incomplete class type has similar caveats. Pointer upcasting (casting from a more derived type to a less derived type) is a standard implicit conversion operation. C++ allows - - static_cast - - to perform the inverse operation, pointer downcasting, via [expr.static.cast], paragraph 7. However, when the pointed-to type is incomplete, the compiler is unable to make any class offset adjustments that may be required in the presence of multiple inheritance, resulting in a pointer that cannot be validly dereferenced. -

    -

    - - reinterpret_cast - - of a pointer type is defined by [expr.reinterpret.cast], paragraph 7, as being - - static_cast<cv T *>(static_cast<cv void *>(PtrValue)) - - , meaning that - - reinterpret_cast - - is simply a sequence of - - static_cast - - operations. C-style casts of a pointer to an incomplete object type are defined as using either - - static_cast - - or - - reinterpret_cast - - (it is unspecified which is picked) in [expr.cast], paragraph 5. -

    -

    - Do not attempt to cast through a pointer to an object of incomplete type. The cast operation itself is well-formed, but dereferencing the resulting pointer may result in undefined behavior if the downcast is unable to adjust for multiple inheritance. -

    +

    Do not attempt to delete a pointer to an object of incomplete type. Although it is well-formed if the class has no nontrivial destructor and no associated deallocation function, it would become undefined behavior were a nontrivial destructor or deallocation function added later. It would be possible to check for a nontrivial destructor at compile time using a static_assert and the std::is_trivially_destructible type trait, but no such type trait exists to test for the presence of a deallocation function.

    +

    Pointer downcasting to a pointer of incomplete class type has similar caveats. Pointer upcasting (casting from a more derived type to a less derived type) is a standard implicit conversion operation. C++ allows static_cast to perform the inverse operation, pointer downcasting, via [expr.static.cast], paragraph 7. However, when the pointed-to type is incomplete, the compiler is unable to make any class offset adjustments that may be required in the presence of multiple inheritance, resulting in a pointer that cannot be validly dereferenced.

    +

    reinterpret_cast of a pointer type is defined by [expr.reinterpret.cast], paragraph 7, as being static_cast<cv T *>(static_cast<cv void *>(PtrValue)), meaning that reinterpret_cast is simply a sequence of static_cast operations. C-style casts of a pointer to an incomplete object type are defined as using either static_cast or reinterpret_cast (it is unspecified which is picked) in [expr.cast], paragraph 5.

    +

    Do not attempt to cast through a pointer to an object of incomplete type. The cast operation itself is well-formed, but dereferencing the resulting pointer may result in undefined behavior if the downcast is unable to adjust for multiple inheritance.

    -

    - In this noncompliant code example, a class attempts to implement the pimpl idiom but deletes a pointer to an incomplete class type, resulting in - - undefined behavior - - if - - Body - - has a nontrivial destructor. -

    - - class Handle { +

    In this noncompliant code example, a class attempts to implement the pimpl idiom but deletes a pointer to an incomplete class type, resulting in undefined behavior if Body has a nontrivial destructor.

    + class Handle { class Body *impl; // Declaration of a pointer to an incomplete class public: ~Handle() { delete impl; } // Deletion of pointer to an incomplete class // ... }; - +
    -

    - In this compliant solution, the deletion of - - impl - - is moved to a part of the code where - - Body - - is defined. -

    - - class Handle { +

    In this compliant solution, the deletion of impl is moved to a part of the code where Body is defined.

    + class Handle { class Body *impl; // Declaration of a pointer to an incomplete class public: ~Handle(); @@ -120,85 +31,33 @@ public: // Elsewhere class Body { /* ... */ }; -  + Handle::~Handle() { delete impl; -} - +}
    -

    - In this compliant solution, a - - std::shared_ptr - - is used to own the memory to - - impl - - . A - - std::shared_ptr - - is capable of referring to an incomplete type, but a - - std::unique_ptr - - is not. -

    - - #include <memory> -  +

    In this compliant solution, a std::shared_ptr is used to own the memory to impl. A std::shared_ptr is capable of referring to an incomplete type, but a std::unique_ptr is not.

    + #include <memory> + class Handle { std::shared_ptr<class Body> impl; public: Handle(); ~Handle() {} // ... -}; - +};
    -

    - Pointer downcasting (casting a pointer to a base class into a pointer to a derived class) may require adjusting the address of the pointer by a fixed amount that can be determined only when the layout of the class inheritance structure is known. In this noncompliant code example, - - f() - - retrieves a polymorphic pointer of complete type - - B - - from - - get_d() - - . That pointer is then cast to a pointer of incomplete type - - D - - before being passed to - - g() - - . Casting to a pointer to the derived class may fail to properly adjust the resulting pointer, causing - - undefined behavior - - when the pointer is dereferenced by calling - - d->do_something() - - . -

    - - // File1.h +

    Pointer downcasting (casting a pointer to a base class into a pointer to a derived class) may require adjusting the address of the pointer by a fixed amount that can be determined only when the layout of the class inheritance structure is known. In this noncompliant code example, f() retrieves a polymorphic pointer of complete type B from get_d(). That pointer is then cast to a pointer of incomplete type D before being passed to g(). Casting to a pointer to the derived class may fail to properly adjust the resulting pointer, causing undefined behavior when the pointer is dereferenced by calling d->do_something().

    + // File1.h class B { protected: double d; public: B() : d(1.0) {} }; -  + // File2.h void g(class D *); class B *get_d(); // Returns a pointer to a D object @@ -211,7 +70,7 @@ void f() { B *v = get_d(); g(reinterpret_cast<class D *>(v)); } -  + // File2.cpp #include "File2.h" #include "File1.h" @@ -238,59 +97,15 @@ void g(D *d) { B *get_d() { return new D; } - -

    - - Implementation Details - -

    -

    - When compiled with - - Clang - - - BB. Definitions#clang - - 3.8 and the function - - f() - - is executed, the noncompliant code example prints the following. -

    - - f: 1.89367e-40, d: 5.27183e-315, s: 0 - -

    - Similarly, unexpected values are printed when the example is run in - - Microsoft Visual Studio - - 2015 and - - GCC - - 6.1.0. -

    +
    +

    Implementation Details

    +

    When compiled with ClangBB. Definitions#clang3.8 and the function f() is executed, the noncompliant code example prints the following.

    + f: 1.89367e-40, d: 5.27183e-315, s: 0 +

    Similarly, unexpected values are printed when the example is run in Microsoft Visual Studio 2015 and GCC 6.1.0.

    -

    - This compliant solution assumes that the intent is to hide implementation details by using incomplete class types. Instead of requiring a - - D * - - to be passed to - - g() - - , it expects a - - B * - - type. -

    - - // File1.h -- contents identical. +

    This compliant solution assumes that the intent is to hide implementation details by using incomplete class types. Instead of requiring a D * to be passed to g(), it expects a B * type.

    + // File1.h -- contents identical. // File2.h void g(class B *); // Accepts a B object, expects a D object class B *get_d(); // Returns a pointer to a D object @@ -317,13 +132,10 @@ void g(B *d) { B *get_d() { return new D; -} - +}
    -

    - Casting pointers or references to incomplete classes can result in bad addresses. Deleting a pointer to an incomplete class results in undefined behavior if the class has a nontrivial destructor. Doing so can cause program termination, a runtime signal, or resource leaks. -

    +

    Casting pointers or references to incomplete classes can result in bad addresses. Deleting a pointer to an incomplete class results in undefined behavior if the class has a nontrivial destructor. Doing so can cause program termination, a runtime signal, or resource leaks.

    @@ -360,14 +172,10 @@ B *get_d() { Medium @@ -400,9 +208,7 @@ B *get_d() { 20.10 @@ -417,9 +223,7 @@ B *get_d() { 6.5 @@ -449,12 +251,10 @@ B *get_d() { @@ -487,11 +285,7 @@ B *get_d() { 2021.4 @@ -505,11 +299,8 @@ B *get_d() { @@ -590,17 +375,7 @@ B *get_d() {
    - - P4 - + P4 - - L3 - + L3
    - - delete-with-incomplete-type - + delete-with-incomplete-type - - DELETE_VOID - + DELETE_VOID Fully implemented @@ -435,9 +239,7 @@ B *get_d() { 3.9 - - -Wdelete-incomplete - + -Wdelete-incomplete - 6.1p0 + 6.2p0 - - LANG.CAST.PC.INC - + LANG.CAST.PC.INC Conversion: pointer to incomplete @@ -470,9 +270,7 @@ B *get_d() { 2021.2 - - C++3112 - + C++3112 - - - CERT.EXPR.DELETE_PTR.INCOMPLETE_TYPE - - + CERT.EXPR.DELETE_PTR.INCOMPLETE_TYPE - - 169 S, 554 S - - - + 169 S, 554 S + Enhanced Enforcement @@ -525,12 +316,8 @@ B *get_d() { 2021.2 - - CERT_CPP-EXP57-a - - - CERT_CPP-EXP57-b - + CERT_CPP-EXP57-a + CERT_CPP-EXP57-b Do not delete objects with incomplete class at the point of deletion @@ -579,9 +366,7 @@ B *get_d() { 20.10 - - delete-with-incomplete-type - + delete-with-incomplete-type
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/EXP57-CPP/DeletingPointerToIncompleteClass-standard.qhelp b/cpp/cert/src/rules/EXP57-CPP/DeletingPointerToIncompleteClass-standard.qhelp index 4d0b452eb5..a8510f29ba 100644 --- a/cpp/cert/src/rules/EXP57-CPP/DeletingPointerToIncompleteClass-standard.qhelp +++ b/cpp/cert/src/rules/EXP57-CPP/DeletingPointerToIncompleteClass-standard.qhelp @@ -1,117 +1,28 @@
    -

    - Referring to objects of incomplete class type, also known as - - forward declarations - - , is a common practice. One such common usage is with the "pimpl idiom" [ - - Sutter 00 - - ] whereby an opaque pointer is used to hide implementation details from a public-facing API. However, attempting to delete a pointer to an object of incomplete class type can lead to - - undefined behavior - - . The C++ Standard, [expr.delete], paragraph 5 [ - - ISO/IEC 14882-2014 - - ], states the following: -

    +

    Referring to objects of incomplete class type, also known as forward declarations, is a common practice. One such common usage is with the "pimpl idiom" [Sutter 00] whereby an opaque pointer is used to hide implementation details from a public-facing API. However, attempting to delete a pointer to an object of incomplete class type can lead to undefined behavior. The C++ Standard, [expr.delete], paragraph 5 [ISO/IEC 14882-2014], states the following:

    -

    - If the object being deleted has incomplete class type at the point of deletion and the complete class has a non-trivial destructor or a deallocation function, the behavior is undefined. -

    +

    If the object being deleted has incomplete class type at the point of deletion and the complete class has a non-trivial destructor or a deallocation function, the behavior is undefined.

    -

    - Do not attempt to delete a pointer to an object of - - incomplete type - - . Although it is well-formed if the class has no nontrivial destructor and no associated deallocation function, it would become undefined behavior were a nontrivial destructor or deallocation function added later. It would be possible to check for a nontrivial destructor at compile time using a - - static_assert - - and the - - std::is_trivially_destructible - - type trait, but no such type trait exists to test for the presence of a deallocation function. -

    -

    - Pointer downcasting to a pointer of incomplete class type has similar caveats. Pointer upcasting (casting from a more derived type to a less derived type) is a standard implicit conversion operation. C++ allows - - static_cast - - to perform the inverse operation, pointer downcasting, via [expr.static.cast], paragraph 7. However, when the pointed-to type is incomplete, the compiler is unable to make any class offset adjustments that may be required in the presence of multiple inheritance, resulting in a pointer that cannot be validly dereferenced. -

    -

    - - reinterpret_cast - - of a pointer type is defined by [expr.reinterpret.cast], paragraph 7, as being - - static_cast<cv T *>(static_cast<cv void *>(PtrValue)) - - , meaning that - - reinterpret_cast - - is simply a sequence of - - static_cast - - operations. C-style casts of a pointer to an incomplete object type are defined as using either - - static_cast - - or - - reinterpret_cast - - (it is unspecified which is picked) in [expr.cast], paragraph 5. -

    -

    - Do not attempt to cast through a pointer to an object of incomplete type. The cast operation itself is well-formed, but dereferencing the resulting pointer may result in undefined behavior if the downcast is unable to adjust for multiple inheritance. -

    +

    Do not attempt to delete a pointer to an object of incomplete type. Although it is well-formed if the class has no nontrivial destructor and no associated deallocation function, it would become undefined behavior were a nontrivial destructor or deallocation function added later. It would be possible to check for a nontrivial destructor at compile time using a static_assert and the std::is_trivially_destructible type trait, but no such type trait exists to test for the presence of a deallocation function.

    +

    Pointer downcasting to a pointer of incomplete class type has similar caveats. Pointer upcasting (casting from a more derived type to a less derived type) is a standard implicit conversion operation. C++ allows static_cast to perform the inverse operation, pointer downcasting, via [expr.static.cast], paragraph 7. However, when the pointed-to type is incomplete, the compiler is unable to make any class offset adjustments that may be required in the presence of multiple inheritance, resulting in a pointer that cannot be validly dereferenced.

    +

    reinterpret_cast of a pointer type is defined by [expr.reinterpret.cast], paragraph 7, as being static_cast<cv T *>(static_cast<cv void *>(PtrValue)), meaning that reinterpret_cast is simply a sequence of static_cast operations. C-style casts of a pointer to an incomplete object type are defined as using either static_cast or reinterpret_cast (it is unspecified which is picked) in [expr.cast], paragraph 5.

    +

    Do not attempt to cast through a pointer to an object of incomplete type. The cast operation itself is well-formed, but dereferencing the resulting pointer may result in undefined behavior if the downcast is unable to adjust for multiple inheritance.

    -

    - In this noncompliant code example, a class attempts to implement the pimpl idiom but deletes a pointer to an incomplete class type, resulting in - - undefined behavior - - if - - Body - - has a nontrivial destructor. -

    - - class Handle { +

    In this noncompliant code example, a class attempts to implement the pimpl idiom but deletes a pointer to an incomplete class type, resulting in undefined behavior if Body has a nontrivial destructor.

    + class Handle { class Body *impl; // Declaration of a pointer to an incomplete class public: ~Handle() { delete impl; } // Deletion of pointer to an incomplete class // ... }; - +
    -

    - In this compliant solution, the deletion of - - impl - - is moved to a part of the code where - - Body - - is defined. -

    - - class Handle { +

    In this compliant solution, the deletion of impl is moved to a part of the code where Body is defined.

    + class Handle { class Body *impl; // Declaration of a pointer to an incomplete class public: ~Handle(); @@ -120,85 +31,33 @@ public: // Elsewhere class Body { /* ... */ }; -  + Handle::~Handle() { delete impl; -} - +}
    -

    - In this compliant solution, a - - std::shared_ptr - - is used to own the memory to - - impl - - . A - - std::shared_ptr - - is capable of referring to an incomplete type, but a - - std::unique_ptr - - is not. -

    - - #include <memory> -  +

    In this compliant solution, a std::shared_ptr is used to own the memory to impl. A std::shared_ptr is capable of referring to an incomplete type, but a std::unique_ptr is not.

    + #include <memory> + class Handle { std::shared_ptr<class Body> impl; public: Handle(); ~Handle() {} // ... -}; - +};
    -

    - Pointer downcasting (casting a pointer to a base class into a pointer to a derived class) may require adjusting the address of the pointer by a fixed amount that can be determined only when the layout of the class inheritance structure is known. In this noncompliant code example, - - f() - - retrieves a polymorphic pointer of complete type - - B - - from - - get_d() - - . That pointer is then cast to a pointer of incomplete type - - D - - before being passed to - - g() - - . Casting to a pointer to the derived class may fail to properly adjust the resulting pointer, causing - - undefined behavior - - when the pointer is dereferenced by calling - - d->do_something() - - . -

    - - // File1.h +

    Pointer downcasting (casting a pointer to a base class into a pointer to a derived class) may require adjusting the address of the pointer by a fixed amount that can be determined only when the layout of the class inheritance structure is known. In this noncompliant code example, f() retrieves a polymorphic pointer of complete type B from get_d(). That pointer is then cast to a pointer of incomplete type D before being passed to g(). Casting to a pointer to the derived class may fail to properly adjust the resulting pointer, causing undefined behavior when the pointer is dereferenced by calling d->do_something().

    + // File1.h class B { protected: double d; public: B() : d(1.0) {} }; -  + // File2.h void g(class D *); class B *get_d(); // Returns a pointer to a D object @@ -211,7 +70,7 @@ void f() { B *v = get_d(); g(reinterpret_cast<class D *>(v)); } -  + // File2.cpp #include "File2.h" #include "File1.h" @@ -238,59 +97,15 @@ void g(D *d) { B *get_d() { return new D; } - -

    - - Implementation Details - -

    -

    - When compiled with - - Clang - - - BB. Definitions#clang - - 3.8 and the function - - f() - - is executed, the noncompliant code example prints the following. -

    - - f: 1.89367e-40, d: 5.27183e-315, s: 0 - -

    - Similarly, unexpected values are printed when the example is run in - - Microsoft Visual Studio - - 2015 and - - GCC - - 6.1.0. -

    +
    +

    Implementation Details

    +

    When compiled with ClangBB. Definitions#clang3.8 and the function f() is executed, the noncompliant code example prints the following.

    + f: 1.89367e-40, d: 5.27183e-315, s: 0 +

    Similarly, unexpected values are printed when the example is run in Microsoft Visual Studio 2015 and GCC 6.1.0.

    -

    - This compliant solution assumes that the intent is to hide implementation details by using incomplete class types. Instead of requiring a - - D * - - to be passed to - - g() - - , it expects a - - B * - - type. -

    - - // File1.h -- contents identical. +

    This compliant solution assumes that the intent is to hide implementation details by using incomplete class types. Instead of requiring a D * to be passed to g(), it expects a B * type.

    + // File1.h -- contents identical. // File2.h void g(class B *); // Accepts a B object, expects a D object class B *get_d(); // Returns a pointer to a D object @@ -317,13 +132,10 @@ void g(B *d) { B *get_d() { return new D; -} - +}
    -

    - Casting pointers or references to incomplete classes can result in bad addresses. Deleting a pointer to an incomplete class results in undefined behavior if the class has a nontrivial destructor. Doing so can cause program termination, a runtime signal, or resource leaks. -

    +

    Casting pointers or references to incomplete classes can result in bad addresses. Deleting a pointer to an incomplete class results in undefined behavior if the class has a nontrivial destructor. Doing so can cause program termination, a runtime signal, or resource leaks.

    @@ -360,14 +172,10 @@ B *get_d() { Medium @@ -400,9 +208,7 @@ B *get_d() { 20.10 @@ -417,9 +223,7 @@ B *get_d() { 6.5 @@ -449,12 +251,10 @@ B *get_d() { @@ -487,11 +285,7 @@ B *get_d() { 2021.4 @@ -505,11 +299,8 @@ B *get_d() { @@ -590,17 +375,7 @@ B *get_d() {
    - - P4 - + P4 - - L3 - + L3
    - - delete-with-incomplete-type - + delete-with-incomplete-type - - DELETE_VOID - + DELETE_VOID Fully implemented @@ -435,9 +239,7 @@ B *get_d() { 3.9 - - -Wdelete-incomplete - + -Wdelete-incomplete - 6.1p0 + 6.2p0 - - LANG.CAST.PC.INC - + LANG.CAST.PC.INC Conversion: pointer to incomplete @@ -470,9 +270,7 @@ B *get_d() { 2021.2 - - C++3112 - + C++3112 - - - CERT.EXPR.DELETE_PTR.INCOMPLETE_TYPE - - + CERT.EXPR.DELETE_PTR.INCOMPLETE_TYPE - - 169 S, 554 S - - - + 169 S, 554 S + Enhanced Enforcement @@ -525,12 +316,8 @@ B *get_d() { 2021.2 - - CERT_CPP-EXP57-a - - - CERT_CPP-EXP57-b - + CERT_CPP-EXP57-a + CERT_CPP-EXP57-b Do not delete objects with incomplete class at the point of deletion @@ -579,9 +366,7 @@ B *get_d() { 20.10 - - delete-with-incomplete-type - + delete-with-incomplete-type
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/EXP58-CPP/PassNonTrivialObjectToVaStart-standard.qhelp b/cpp/cert/src/rules/EXP58-CPP/PassNonTrivialObjectToVaStart-standard.qhelp index 19bc5a0141..3d374d8649 100644 --- a/cpp/cert/src/rules/EXP58-CPP/PassNonTrivialObjectToVaStart-standard.qhelp +++ b/cpp/cert/src/rules/EXP58-CPP/PassNonTrivialObjectToVaStart-standard.qhelp @@ -1,151 +1,35 @@
    -

    - While rule - - DCL50-CPP. Do not define a C-style variadic function - - forbids creation of such functions, they may still be defined when that function has external, C language linkage. Under these circumstances, care must be taken when invoking the - - va_start() - - macro. The C-standard library macro - - va_start() - - imposes several semantic restrictions on the type of the value of its second parameter. The C Standard, subclause 7.16.1.4, paragraph 4 [ - - ISO/IEC 9899:2011 - - ], states the following: -

    +

    While rule DCL50-CPP. Do not define a C-style variadic function forbids creation of such functions, they may still be defined when that function has external, C language linkage. Under these circumstances, care must be taken when invoking the va_start() macro. The C-standard library macro va_start() imposes several semantic restrictions on the type of the value of its second parameter. The C Standard, subclause 7.16.1.4, paragraph 4 [ISO/IEC 9899:2011], states the following:

    -

    - The parameter - - parmN - - is the identifier of the rightmost parameter in the variable parameter list in the function definition (the one just before the - - ... - - ). If the parameter - - parmN - - is declared with the - - register - - storage class, with a function or array type, or with a type that is not compatible with the type that results after application of the default argument promotions, the behavior is undefined. -

    +

    The parameter parmN is the identifier of the rightmost parameter in the variable parameter list in the function definition (the one just before the ...). If the parameter parmN is declared with the register storage class, with a function or array type, or with a type that is not compatible with the type that results after application of the default argument promotions, the behavior is undefined.

    -

    - These restrictions are superseded by the C++ Standard, [support.runtime], paragraph 3 - [ - - ISO/IEC 14882-2014 - - ] - , which states the following: -

    +

    These restrictions are superseded by the C++ Standard, [support.runtime], paragraph 3 [ISO/IEC 14882-2014], which states the following:

    -

    - The restrictions that ISO C places on the second parameter to the - - va_start() - - macro in header - - <stdarg.h> - - are different in this International Standard. The parameter - - parmN - - is the identifier of the rightmost parameter in the variable parameter list of the function definition (the one just before the - - ... - - ). If the parameter - - parmN - - is of a reference type, or of a type that is not compatible with the type that results when passing an argument for which there is no parameter, the behavior is undefined. -

    +

    The restrictions that ISO C places on the second parameter to the va_start() macro in header <stdarg.h> are different in this International Standard. The parameter parmN is the identifier of the rightmost parameter in the variable parameter list of the function definition (the one just before the ...). If the parameter parmN is of a reference type, or of a type that is not compatible with the type that results when passing an argument for which there is no parameter, the behavior is undefined.

    -

    - The primary differences between the semantic requirements are as follows: -

    +

    The primary differences between the semantic requirements are as follows:

      -
    • - You must not pass a reference as the second argument to - - va_start() - - . -
    • -
    • - Passing an object of a class type that has a nontrivial copy constructor, nontrivial move constructor, or nontrivial destructor as the second argument to - - va_start - - is conditionally supported with implementation-defined semantics ([expr.call] paragraph 7). -
    • -
    • - You may pass a parameter declared with the - - register - - keyword ([dcl.stc] paragraph 3) or a parameter with a function type. -
    • +
    • You must not pass a reference as the second argument to va_start().
    • +
    • Passing an object of a class type that has a nontrivial copy constructor, nontrivial move constructor, or nontrivial destructor as the second argument to va_start is conditionally supported with implementation-defined semantics ([expr.call] paragraph 7).
    • +
    • You may pass a parameter declared with the register keyword ([dcl.stc] paragraph 3) or a parameter with a function type.
    -

    - Passing an object of array type still produces - - undefined behavior - - in C++ because an array type as a function parameter requires the use of a reference, which is prohibited. Additionally, passing an object of a type that undergoes default argument promotions still produces undefined behavior in C++. -

    -

    - Noncompliant Code Example -

    -

    - In this noncompliant code example, the object passed to - - va_start() - - will undergo a default argument promotion, which results in undefined behavior. -

    - - #include <cstdarg> +

    Passing an object of array type still produces undefined behavior in C++ because an array type as a function parameter requires the use of a reference, which is prohibited. Additionally, passing an object of a type that undergoes default argument promotions still produces undefined behavior in C++.

    +

    Noncompliant Code Example

    +

    In this noncompliant code example, the object passed to va_start() will undergo a default argument promotion, which results in undefined behavior.

    + #include <cstdarg> extern "C" void f(float a, ...) { va_list list; va_start(list, a); // ... va_end(list); -} - +}
    -

    - In this compliant solution, - - f() - - accepts a - - double - - instead of a - - float. - -

    - - #include <cstdarg> +

    In this compliant solution, f() accepts a double instead of a float.

    + #include <cstdarg> extern "C" void f(double a, ...) { va_list list; @@ -153,17 +37,11 @@ extern "C" void f(double a, ...) { // ... va_end(list); } - +
    -

    - In this noncompliant code example, a reference type is passed as the second argument to - - va_start(). - -

    - - #include <cstdarg> +

    In this noncompliant code example, a reference type is passed as the second argument to va_start().

    + #include <cstdarg> #include <iostream> extern "C" void f(int &a, ...) { @@ -174,19 +52,11 @@ extern "C" void f(int &a, ...) { a = 100; // Assign something to a for the caller } va_end(list); -} - +}
    -

    - Instead of passing a reference type to - - f() - - , this compliant solution passes a pointer type. -

    - - #include <cstdarg> +

    Instead of passing a reference type to f(), this compliant solution passes a pointer type.

    + #include <cstdarg> #include <iostream> extern "C" void f(int *a, ...) { @@ -198,26 +68,11 @@ extern "C" void f(int *a, ...) { } va_end(list); } - +
    -

    - In this noncompliant code example, a class with a nontrivial copy constructor ( - - std::string - - ) is passed as the second argument to - - va_start() - - , which is conditionally supported depending on the - - implementation - - . -

    - - #include <cstdarg> +

    In this noncompliant code example, a class with a nontrivial copy constructor (std::string) is passed as the second argument to va_start(), which is conditionally supported depending on the implementation.

    + #include <cstdarg> #include <iostream> #include <string> @@ -226,23 +81,11 @@ extern "C" void f(std::string s, ...) { va_start(list, s); std::cout << s << ", " << va_arg(list, int); va_end(list); -} - +}
    -

    - This compliant solution passes a - - const char * - - instead of a - - std::string - - , which has well-defined behavior on all implementations. -

    - - #include <cstdarg> +

    This compliant solution passes a const char * instead of a std::string, which has well-defined behavior on all implementations.

    + #include <cstdarg> #include <iostream> extern "C" void f(const char *s, ...) { @@ -250,25 +93,10 @@ extern "C" void f(const char *s, ...) { va_start(list, s); std::cout << (s ? s : "") << ", " << va_arg(list, int); va_end(list); -} - +}
    -

    - Passing an object of an unsupported type as the second argument to - - va_start() - - can result in - - undefined behavior - - that might be - - exploited - - to cause data integrity violations. -

    +

    Passing an object of an unsupported type as the second argument to va_start() can result in undefined behavior that might be exploited to cause data integrity violations.

    @@ -305,14 +133,10 @@ extern "C" void f(const char *s, ...) { Medium @@ -345,9 +169,7 @@ extern "C" void f(const char *s, ...) { 3.9 @@ -384,9 +204,7 @@ extern "C" void f(const char *s, ...) { 2021.2
    - - P4 - + P4 - - L3 - + L3
    - - -Wvarargs - + -Wvarargs Does not catch the violation in the third noncompliant code example (it is conditionally supported by @@ -367,9 +189,7 @@ extern "C" void f(const char *s, ...) { 2021.2 - - C++3852, C++3853 - + C++3852, C++3853 - - CERT_CPP-EXP58-a - + CERT_CPP-EXP58-a Use macros for variable arguments correctly @@ -414,17 +232,7 @@ extern "C" void f(const char *s, ...) {
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    @@ -457,9 +265,7 @@ extern "C" void f(const char *s, ...) { diff --git a/cpp/cert/src/rules/EXP58-CPP/PassPromotablePrimitiveTypeToVaStart-standard.qhelp b/cpp/cert/src/rules/EXP58-CPP/PassPromotablePrimitiveTypeToVaStart-standard.qhelp index 19bc5a0141..3d374d8649 100644 --- a/cpp/cert/src/rules/EXP58-CPP/PassPromotablePrimitiveTypeToVaStart-standard.qhelp +++ b/cpp/cert/src/rules/EXP58-CPP/PassPromotablePrimitiveTypeToVaStart-standard.qhelp @@ -1,151 +1,35 @@
    -

    - While rule - - DCL50-CPP. Do not define a C-style variadic function - - forbids creation of such functions, they may still be defined when that function has external, C language linkage. Under these circumstances, care must be taken when invoking the - - va_start() - - macro. The C-standard library macro - - va_start() - - imposes several semantic restrictions on the type of the value of its second parameter. The C Standard, subclause 7.16.1.4, paragraph 4 [ - - ISO/IEC 9899:2011 - - ], states the following: -

    +

    While rule DCL50-CPP. Do not define a C-style variadic function forbids creation of such functions, they may still be defined when that function has external, C language linkage. Under these circumstances, care must be taken when invoking the va_start() macro. The C-standard library macro va_start() imposes several semantic restrictions on the type of the value of its second parameter. The C Standard, subclause 7.16.1.4, paragraph 4 [ISO/IEC 9899:2011], states the following:

    -

    - The parameter - - parmN - - is the identifier of the rightmost parameter in the variable parameter list in the function definition (the one just before the - - ... - - ). If the parameter - - parmN - - is declared with the - - register - - storage class, with a function or array type, or with a type that is not compatible with the type that results after application of the default argument promotions, the behavior is undefined. -

    +

    The parameter parmN is the identifier of the rightmost parameter in the variable parameter list in the function definition (the one just before the ...). If the parameter parmN is declared with the register storage class, with a function or array type, or with a type that is not compatible with the type that results after application of the default argument promotions, the behavior is undefined.

    -

    - These restrictions are superseded by the C++ Standard, [support.runtime], paragraph 3 - [ - - ISO/IEC 14882-2014 - - ] - , which states the following: -

    +

    These restrictions are superseded by the C++ Standard, [support.runtime], paragraph 3 [ISO/IEC 14882-2014], which states the following:

    -

    - The restrictions that ISO C places on the second parameter to the - - va_start() - - macro in header - - <stdarg.h> - - are different in this International Standard. The parameter - - parmN - - is the identifier of the rightmost parameter in the variable parameter list of the function definition (the one just before the - - ... - - ). If the parameter - - parmN - - is of a reference type, or of a type that is not compatible with the type that results when passing an argument for which there is no parameter, the behavior is undefined. -

    +

    The restrictions that ISO C places on the second parameter to the va_start() macro in header <stdarg.h> are different in this International Standard. The parameter parmN is the identifier of the rightmost parameter in the variable parameter list of the function definition (the one just before the ...). If the parameter parmN is of a reference type, or of a type that is not compatible with the type that results when passing an argument for which there is no parameter, the behavior is undefined.

    -

    - The primary differences between the semantic requirements are as follows: -

    +

    The primary differences between the semantic requirements are as follows:

      -
    • - You must not pass a reference as the second argument to - - va_start() - - . -
    • -
    • - Passing an object of a class type that has a nontrivial copy constructor, nontrivial move constructor, or nontrivial destructor as the second argument to - - va_start - - is conditionally supported with implementation-defined semantics ([expr.call] paragraph 7). -
    • -
    • - You may pass a parameter declared with the - - register - - keyword ([dcl.stc] paragraph 3) or a parameter with a function type. -
    • +
    • You must not pass a reference as the second argument to va_start().
    • +
    • Passing an object of a class type that has a nontrivial copy constructor, nontrivial move constructor, or nontrivial destructor as the second argument to va_start is conditionally supported with implementation-defined semantics ([expr.call] paragraph 7).
    • +
    • You may pass a parameter declared with the register keyword ([dcl.stc] paragraph 3) or a parameter with a function type.
    -

    - Passing an object of array type still produces - - undefined behavior - - in C++ because an array type as a function parameter requires the use of a reference, which is prohibited. Additionally, passing an object of a type that undergoes default argument promotions still produces undefined behavior in C++. -

    -

    - Noncompliant Code Example -

    -

    - In this noncompliant code example, the object passed to - - va_start() - - will undergo a default argument promotion, which results in undefined behavior. -

    - - #include <cstdarg> +

    Passing an object of array type still produces undefined behavior in C++ because an array type as a function parameter requires the use of a reference, which is prohibited. Additionally, passing an object of a type that undergoes default argument promotions still produces undefined behavior in C++.

    +

    Noncompliant Code Example

    +

    In this noncompliant code example, the object passed to va_start() will undergo a default argument promotion, which results in undefined behavior.

    + #include <cstdarg> extern "C" void f(float a, ...) { va_list list; va_start(list, a); // ... va_end(list); -} - +}
    -

    - In this compliant solution, - - f() - - accepts a - - double - - instead of a - - float. - -

    - - #include <cstdarg> +

    In this compliant solution, f() accepts a double instead of a float.

    + #include <cstdarg> extern "C" void f(double a, ...) { va_list list; @@ -153,17 +37,11 @@ extern "C" void f(double a, ...) { // ... va_end(list); } - +
    -

    - In this noncompliant code example, a reference type is passed as the second argument to - - va_start(). - -

    - - #include <cstdarg> +

    In this noncompliant code example, a reference type is passed as the second argument to va_start().

    + #include <cstdarg> #include <iostream> extern "C" void f(int &a, ...) { @@ -174,19 +52,11 @@ extern "C" void f(int &a, ...) { a = 100; // Assign something to a for the caller } va_end(list); -} - +}
    -

    - Instead of passing a reference type to - - f() - - , this compliant solution passes a pointer type. -

    - - #include <cstdarg> +

    Instead of passing a reference type to f(), this compliant solution passes a pointer type.

    + #include <cstdarg> #include <iostream> extern "C" void f(int *a, ...) { @@ -198,26 +68,11 @@ extern "C" void f(int *a, ...) { } va_end(list); } - +
    -

    - In this noncompliant code example, a class with a nontrivial copy constructor ( - - std::string - - ) is passed as the second argument to - - va_start() - - , which is conditionally supported depending on the - - implementation - - . -

    - - #include <cstdarg> +

    In this noncompliant code example, a class with a nontrivial copy constructor (std::string) is passed as the second argument to va_start(), which is conditionally supported depending on the implementation.

    + #include <cstdarg> #include <iostream> #include <string> @@ -226,23 +81,11 @@ extern "C" void f(std::string s, ...) { va_start(list, s); std::cout << s << ", " << va_arg(list, int); va_end(list); -} - +}
    -

    - This compliant solution passes a - - const char * - - instead of a - - std::string - - , which has well-defined behavior on all implementations. -

    - - #include <cstdarg> +

    This compliant solution passes a const char * instead of a std::string, which has well-defined behavior on all implementations.

    + #include <cstdarg> #include <iostream> extern "C" void f(const char *s, ...) { @@ -250,25 +93,10 @@ extern "C" void f(const char *s, ...) { va_start(list, s); std::cout << (s ? s : "") << ", " << va_arg(list, int); va_end(list); -} - +}
    -

    - Passing an object of an unsupported type as the second argument to - - va_start() - - can result in - - undefined behavior - - that might be - - exploited - - to cause data integrity violations. -

    +

    Passing an object of an unsupported type as the second argument to va_start() can result in undefined behavior that might be exploited to cause data integrity violations.

    Subclause 7.16.1.4, "The - - va_start - + va_start Macro"
    @@ -305,14 +133,10 @@ extern "C" void f(const char *s, ...) { Medium @@ -345,9 +169,7 @@ extern "C" void f(const char *s, ...) { 3.9 @@ -384,9 +204,7 @@ extern "C" void f(const char *s, ...) { 2021.2
    - - P4 - + P4 - - L3 - + L3
    - - -Wvarargs - + -Wvarargs Does not catch the violation in the third noncompliant code example (it is conditionally supported by @@ -367,9 +189,7 @@ extern "C" void f(const char *s, ...) { 2021.2 - - C++3852, C++3853 - + C++3852, C++3853 - - CERT_CPP-EXP58-a - + CERT_CPP-EXP58-a Use macros for variable arguments correctly @@ -414,17 +232,7 @@ extern "C" void f(const char *s, ...) {
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    @@ -457,9 +265,7 @@ extern "C" void f(const char *s, ...) { diff --git a/cpp/cert/src/rules/EXP58-CPP/PassReferenceTypeToVaStart-standard.qhelp b/cpp/cert/src/rules/EXP58-CPP/PassReferenceTypeToVaStart-standard.qhelp index 19bc5a0141..3d374d8649 100644 --- a/cpp/cert/src/rules/EXP58-CPP/PassReferenceTypeToVaStart-standard.qhelp +++ b/cpp/cert/src/rules/EXP58-CPP/PassReferenceTypeToVaStart-standard.qhelp @@ -1,151 +1,35 @@
    -

    - While rule - - DCL50-CPP. Do not define a C-style variadic function - - forbids creation of such functions, they may still be defined when that function has external, C language linkage. Under these circumstances, care must be taken when invoking the - - va_start() - - macro. The C-standard library macro - - va_start() - - imposes several semantic restrictions on the type of the value of its second parameter. The C Standard, subclause 7.16.1.4, paragraph 4 [ - - ISO/IEC 9899:2011 - - ], states the following: -

    +

    While rule DCL50-CPP. Do not define a C-style variadic function forbids creation of such functions, they may still be defined when that function has external, C language linkage. Under these circumstances, care must be taken when invoking the va_start() macro. The C-standard library macro va_start() imposes several semantic restrictions on the type of the value of its second parameter. The C Standard, subclause 7.16.1.4, paragraph 4 [ISO/IEC 9899:2011], states the following:

    -

    - The parameter - - parmN - - is the identifier of the rightmost parameter in the variable parameter list in the function definition (the one just before the - - ... - - ). If the parameter - - parmN - - is declared with the - - register - - storage class, with a function or array type, or with a type that is not compatible with the type that results after application of the default argument promotions, the behavior is undefined. -

    +

    The parameter parmN is the identifier of the rightmost parameter in the variable parameter list in the function definition (the one just before the ...). If the parameter parmN is declared with the register storage class, with a function or array type, or with a type that is not compatible with the type that results after application of the default argument promotions, the behavior is undefined.

    -

    - These restrictions are superseded by the C++ Standard, [support.runtime], paragraph 3 - [ - - ISO/IEC 14882-2014 - - ] - , which states the following: -

    +

    These restrictions are superseded by the C++ Standard, [support.runtime], paragraph 3 [ISO/IEC 14882-2014], which states the following:

    -

    - The restrictions that ISO C places on the second parameter to the - - va_start() - - macro in header - - <stdarg.h> - - are different in this International Standard. The parameter - - parmN - - is the identifier of the rightmost parameter in the variable parameter list of the function definition (the one just before the - - ... - - ). If the parameter - - parmN - - is of a reference type, or of a type that is not compatible with the type that results when passing an argument for which there is no parameter, the behavior is undefined. -

    +

    The restrictions that ISO C places on the second parameter to the va_start() macro in header <stdarg.h> are different in this International Standard. The parameter parmN is the identifier of the rightmost parameter in the variable parameter list of the function definition (the one just before the ...). If the parameter parmN is of a reference type, or of a type that is not compatible with the type that results when passing an argument for which there is no parameter, the behavior is undefined.

    -

    - The primary differences between the semantic requirements are as follows: -

    +

    The primary differences between the semantic requirements are as follows:

      -
    • - You must not pass a reference as the second argument to - - va_start() - - . -
    • -
    • - Passing an object of a class type that has a nontrivial copy constructor, nontrivial move constructor, or nontrivial destructor as the second argument to - - va_start - - is conditionally supported with implementation-defined semantics ([expr.call] paragraph 7). -
    • -
    • - You may pass a parameter declared with the - - register - - keyword ([dcl.stc] paragraph 3) or a parameter with a function type. -
    • +
    • You must not pass a reference as the second argument to va_start().
    • +
    • Passing an object of a class type that has a nontrivial copy constructor, nontrivial move constructor, or nontrivial destructor as the second argument to va_start is conditionally supported with implementation-defined semantics ([expr.call] paragraph 7).
    • +
    • You may pass a parameter declared with the register keyword ([dcl.stc] paragraph 3) or a parameter with a function type.
    -

    - Passing an object of array type still produces - - undefined behavior - - in C++ because an array type as a function parameter requires the use of a reference, which is prohibited. Additionally, passing an object of a type that undergoes default argument promotions still produces undefined behavior in C++. -

    -

    - Noncompliant Code Example -

    -

    - In this noncompliant code example, the object passed to - - va_start() - - will undergo a default argument promotion, which results in undefined behavior. -

    - - #include <cstdarg> +

    Passing an object of array type still produces undefined behavior in C++ because an array type as a function parameter requires the use of a reference, which is prohibited. Additionally, passing an object of a type that undergoes default argument promotions still produces undefined behavior in C++.

    +

    Noncompliant Code Example

    +

    In this noncompliant code example, the object passed to va_start() will undergo a default argument promotion, which results in undefined behavior.

    + #include <cstdarg> extern "C" void f(float a, ...) { va_list list; va_start(list, a); // ... va_end(list); -} - +}
    -

    - In this compliant solution, - - f() - - accepts a - - double - - instead of a - - float. - -

    - - #include <cstdarg> +

    In this compliant solution, f() accepts a double instead of a float.

    + #include <cstdarg> extern "C" void f(double a, ...) { va_list list; @@ -153,17 +37,11 @@ extern "C" void f(double a, ...) { // ... va_end(list); } - +
    -

    - In this noncompliant code example, a reference type is passed as the second argument to - - va_start(). - -

    - - #include <cstdarg> +

    In this noncompliant code example, a reference type is passed as the second argument to va_start().

    + #include <cstdarg> #include <iostream> extern "C" void f(int &a, ...) { @@ -174,19 +52,11 @@ extern "C" void f(int &a, ...) { a = 100; // Assign something to a for the caller } va_end(list); -} - +}
    -

    - Instead of passing a reference type to - - f() - - , this compliant solution passes a pointer type. -

    - - #include <cstdarg> +

    Instead of passing a reference type to f(), this compliant solution passes a pointer type.

    + #include <cstdarg> #include <iostream> extern "C" void f(int *a, ...) { @@ -198,26 +68,11 @@ extern "C" void f(int *a, ...) { } va_end(list); } - +
    -

    - In this noncompliant code example, a class with a nontrivial copy constructor ( - - std::string - - ) is passed as the second argument to - - va_start() - - , which is conditionally supported depending on the - - implementation - - . -

    - - #include <cstdarg> +

    In this noncompliant code example, a class with a nontrivial copy constructor (std::string) is passed as the second argument to va_start(), which is conditionally supported depending on the implementation.

    + #include <cstdarg> #include <iostream> #include <string> @@ -226,23 +81,11 @@ extern "C" void f(std::string s, ...) { va_start(list, s); std::cout << s << ", " << va_arg(list, int); va_end(list); -} - +}
    -

    - This compliant solution passes a - - const char * - - instead of a - - std::string - - , which has well-defined behavior on all implementations. -

    - - #include <cstdarg> +

    This compliant solution passes a const char * instead of a std::string, which has well-defined behavior on all implementations.

    + #include <cstdarg> #include <iostream> extern "C" void f(const char *s, ...) { @@ -250,25 +93,10 @@ extern "C" void f(const char *s, ...) { va_start(list, s); std::cout << (s ? s : "") << ", " << va_arg(list, int); va_end(list); -} - +}
    -

    - Passing an object of an unsupported type as the second argument to - - va_start() - - can result in - - undefined behavior - - that might be - - exploited - - to cause data integrity violations. -

    +

    Passing an object of an unsupported type as the second argument to va_start() can result in undefined behavior that might be exploited to cause data integrity violations.

    Subclause 7.16.1.4, "The - - va_start - + va_start Macro"
    @@ -305,14 +133,10 @@ extern "C" void f(const char *s, ...) { Medium @@ -345,9 +169,7 @@ extern "C" void f(const char *s, ...) { 3.9 @@ -384,9 +204,7 @@ extern "C" void f(const char *s, ...) { 2021.2
    - - P4 - + P4 - - L3 - + L3
    - - -Wvarargs - + -Wvarargs Does not catch the violation in the third noncompliant code example (it is conditionally supported by @@ -367,9 +189,7 @@ extern "C" void f(const char *s, ...) { 2021.2 - - C++3852, C++3853 - + C++3852, C++3853 - - CERT_CPP-EXP58-a - + CERT_CPP-EXP58-a Use macros for variable arguments correctly @@ -414,17 +232,7 @@ extern "C" void f(const char *s, ...) {
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    @@ -457,9 +265,7 @@ extern "C" void f(const char *s, ...) { diff --git a/cpp/cert/src/rules/EXP59-CPP/OffsetUsedOnInvalidTypeOrMember-standard.qhelp b/cpp/cert/src/rules/EXP59-CPP/OffsetUsedOnInvalidTypeOrMember-standard.qhelp index ef6f2c5a40..b343ea0fd9 100644 --- a/cpp/cert/src/rules/EXP59-CPP/OffsetUsedOnInvalidTypeOrMember-standard.qhelp +++ b/cpp/cert/src/rules/EXP59-CPP/OffsetUsedOnInvalidTypeOrMember-standard.qhelp @@ -1,193 +1,35 @@
    -

    - The - - offsetof() - - macro is defined by the C Standard as a portable way to determine the offset, expressed in bytes, from the start of the object to a given member of that object. The C Standard, subclause 7.17, paragraph 3 [ - - ISO/IEC 9899:1999 - - ], in part, specifies the following: -

    +

    The offsetof() macro is defined by the C Standard as a portable way to determine the offset, expressed in bytes, from the start of the object to a given member of that object. The C Standard, subclause 7.17, paragraph 3 [ISO/IEC 9899:1999], in part, specifies the following:

    -

    - - offsetof(type, member-designator) - - which expands to an integer constant expression that has type - - size_t - - , the value of which is the offset in bytes, to the structure member (designated by - - member-designator - - ), from the beginning of its structure (designated by - - type - - ). The type and member designator shall be such that given - - static type t; - - then the expression - - &(t.member-designator) - - evaluates to an address constant. (If the specified member is a bit-field, the behavior is undefined.) -

    +

    offsetof(type, member-designator) which expands to an integer constant expression that has type size_t, the value of which is the offset in bytes, to the structure member (designated by member-designator), from the beginning of its structure (designated by type). The type and member designator shall be such that given static type t; then the expression &(t.member-designator) evaluates to an address constant. (If the specified member is a bit-field, the behavior is undefined.)

    -

    - The C++ Standard, [support.types], paragraph 4 [ - - ISO/IEC 14882-2014 - - ], places additional restrictions beyond those set by the C Standard: -

    +

    The C++ Standard, [support.types], paragraph 4 [ISO/IEC 14882-2014], places additional restrictions beyond those set by the C Standard:

    -

    - The macro - - offsetof(type, member-designator) - - accepts a restricted set of - - type - - arguments in this International Standard. If - - type - - is not a - - standard-layout class - - , the results are undefined. The expression - - offsetof(type, member-designator) - - is never type-dependent and it is value-dependent if and only if - - type - - is dependent. The result of applying the - - offsetof - - macro to a field that is a static data member or a function member is undefined. No operation invoked by the - - offsetof - - macro shall throw an exception and - - noexcept(offsetof(type, member-designator)) - - shall be true. -

    +

    The macro offsetof(type, member-designator) accepts a restricted set of type arguments in this International Standard. If type is not a standard-layout class, the results are undefined. The expression offsetof(type, member-designator) is never type-dependent and it is value-dependent if and only if type is dependent. The result of applying the offsetof macro to a field that is a static data member or a function member is undefined. No operation invoked by the offsetof macro shall throw an exception and noexcept(offsetof(type, member-designator)) shall be true.

    -

    - When specifying the type argument for the - - offsetof() - - macro, pass only a standard-layout class. The full description of a standard-layout class can be found in paragraph 7 of the [class] clause of the C++ Standard, or the type can be checked with the - - std::is_standard_layout<> - - type trait. When specifying the member designator argument for the - - offsetof() - - macro, do not pass a bit-field, static data member, or function member. Passing an invalid type or member to the - - offsetof() - - macro is - - undefined behavior - - . -

    +

    When specifying the type argument for the offsetof() macro, pass only a standard-layout class. The full description of a standard-layout class can be found in paragraph 7 of the [class] clause of the C++ Standard, or the type can be checked with the std::is_standard_layout<> type trait. When specifying the member designator argument for the offsetof() macro, do not pass a bit-field, static data member, or function member. Passing an invalid type or member to the offsetof() macro is undefined behavior.

    -

    - In this noncompliant code example, a type that is not a standard-layout class is passed to the - - offsetof() - - macro, resulting in - - undefined behavior - - . -

    - - #include <cstddef> -  +

    In this noncompliant code example, a type that is not a standard-layout class is passed to the offsetof() macro, resulting in undefined behavior.

    + #include <cstddef> + struct D { virtual void f() {} int i; }; -  + void f() { size_t off = offsetof(D, i); // ... -} - -

    - - Implementation Details - -

    -

    - The noncompliant code example does not emit a diagnostic when compiled with the - - /Wall - - switch in - - Microsoft Visual Studio - - 2015 on x86, resulting in - - off - - being - - 4 - - , due to the presence of a vtable for type - - D - - . -

    +}
    +

    Implementation Details

    +

    The noncompliant code example does not emit a diagnostic when compiled with the /Wall switch in Microsoft Visual Studio 2015 on x86, resulting in off being 4, due to the presence of a vtable for type D.

    -

    - It is not possible to determine the offset to - - i - - within - - D - - because - - D - - is not a standard-layout class. However, it is possible to make a standard-layout class within - - D - - if this functionality is critical to the application, as demonstrated by this compliant solution. -

    - - #include <cstddef> +

    It is not possible to determine the offset to i within D because D is not a standard-layout class. However, it is possible to make a standard-layout class within D if this functionality is critical to the application, as demonstrated by this compliant solution.

    + #include <cstddef> struct D { virtual void f() {} @@ -199,85 +41,31 @@ struct D { void f() { size_t off = offsetof(D::InnerStandardLayout, i); // ... -} - +}
    -

    - In this noncompliant code example, the offset to - - i - - is calculated so that a value can be stored at that offset within - - buffer - - . However, because - - i - - is a static data member of the class, this example results in - - undefined behavior - - . According to the C++ Standard, [class.static.data], paragraph 1 [ - - ISO/IEC 14882-2014 - - ], static data members are not part of the subobjects of a class. -

    - - #include <cstddef> -  +

    In this noncompliant code example, the offset to i is calculated so that a value can be stored at that offset within buffer. However, because i is a static data member of the class, this example results in undefined behavior. According to the C++ Standard, [class.static.data], paragraph 1 [ISO/IEC 14882-2014], static data members are not part of the subobjects of a class.

    + #include <cstddef> + struct S { static int i; // ... }; int S::i = 0; -  + extern void store_in_some_buffer(void *buffer, size_t offset, int val); extern void *buffer; -  + void f() { size_t off = offsetof(S, i); store_in_some_buffer(buffer, off, 42); -} - -

    - - Implementation Details - -

    -

    - The noncompliant code example does not emit a diagnostic when compiled with the - - /Wall - - switch in Microsoft Visual Studio 2015 on x86, resulting in - - off - - being a large value representing the offset between the null pointer address - - 0 - - and the address of the static variable - - S::i - - . -

    +}
    +

    Implementation Details

    +

    The noncompliant code example does not emit a diagnostic when compiled with the /Wall switch in Microsoft Visual Studio 2015 on x86, resulting in off being a large value representing the offset between the null pointer address 0 and the address of the static variable S::i.

    -

    - Because static data members are not a part of the class layout, but are instead an entity of their own, this compliant solution passes the address of the static member variable as the buffer to store the data in and passes - - 0 - - as the offset. -

    - - #include <cstddef> +

    Because static data members are not a part of the class layout, but are instead an entity of their own, this compliant solution passes the address of the static member variable as the buffer to store the data in and passes 0 as the offset.

    + #include <cstddef> struct S { static int i; @@ -289,25 +77,10 @@ extern void store_in_some_buffer(void *buffer, size_t offset, int val); void f() { store_in_some_buffer(&S::i, 0, 42); -} - +}
    -

    - Passing an invalid type or member to - - offsetof() - - can result in - - undefined behavior - - that might be - - exploited - - to cause data integrity violations or result in incorrect values from the macro expansion. -

    +

    Passing an invalid type or member to offsetof() can result in undefined behavior that might be exploited to cause data integrity violations or result in incorrect values from the macro expansion.

    Subclause 7.16.1.4, "The - - va_start - + va_start Macro"
    @@ -344,20 +117,15 @@ void f() { Medium
    - - P4 - + P4 - - L3 - + L3
    -
    -
    +

    Automated Detection

    @@ -384,9 +152,7 @@ void f() { 7.2.0 @@ -401,9 +167,7 @@ void f() { 3.9 @@ -453,9 +213,7 @@ void f() { 2021.2
    - - CertC++-EXP59 - + CertC++-EXP59 - - -Winvalid-offsetof - + -Winvalid-offsetof Emits an error diagnostic on invalid member designators, and emits a warning diagnostic on invalid types. @@ -418,9 +182,7 @@ void f() { - - -Winvalid-offsetof - + -Winvalid-offsetof Emits an error diagnostic on invalid member designators, and emits a warning diagnostic on invalid types. @@ -436,9 +198,7 @@ void f() { 2021.2 - - C++3915, C++3916 - + C++3915, C++3916 - - CERT_CPP-EXP59-a - + CERT_CPP-EXP59-a Use offsetof() on valid types and members @@ -483,17 +241,7 @@ void f() {
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    @@ -508,9 +256,7 @@ void f() { diff --git a/cpp/cert/src/rules/EXP60-CPP/DoNotPassANonstandardObjectAcrossBoundaries-standard.qhelp b/cpp/cert/src/rules/EXP60-CPP/DoNotPassANonstandardObjectAcrossBoundaries-standard.qhelp index fcadfc2de6..75d55c85f8 100644 --- a/cpp/cert/src/rules/EXP60-CPP/DoNotPassANonstandardObjectAcrossBoundaries-standard.qhelp +++ b/cpp/cert/src/rules/EXP60-CPP/DoNotPassANonstandardObjectAcrossBoundaries-standard.qhelp @@ -1,125 +1,40 @@
    -

    - Standard-layout types can be used to communicate with code written in other programming languages, as the layout of the type is strictly specified. The C++ Standard, [class], paragraph 7 [ - - ISO/IEC 14882-2014 - - ], defines a standard-layout class as a class that -

    +

    Standard-layout types can be used to communicate with code written in other programming languages, as the layout of the type is strictly specified. The C++ Standard, [class], paragraph 7 [ISO/IEC 14882-2014], defines a standard-layout class as a class that

      -
    • - does not have virtual functions, -
    • -
    • - has the same access control for all nonstatic data members, -
    • -
    • - has no base classes of the same type as the first nonstatic data member, -
    • -
    • - has nonstatic data members declared in only one class within the class hierarchy, and -
    • -
    • - recursively, does not have nonstatic data members of nonstandard-layout type. -
    • +
    • does not have virtual functions,
    • +
    • has the same access control for all nonstatic data members,
    • +
    • has no base classes of the same type as the first nonstatic data member,
    • +
    • has nonstatic data members declared in only one class within the class hierarchy, and
    • +
    • recursively, does not have nonstatic data members of nonstandard-layout type.
    -

    - An - - execution boundary - - is the delimitation between code compiled by differing compilers, including different versions of a compiler produced by the same vendor. For instance, a function may be declared in a header file but defined in a library that is loaded at runtime. The execution boundary exists between the call site in the executable and the function implementation in the library. Such boundaries are also called - - ABI - - (application binary interface) boundaries because they relate to the interoperability of application binaries. -

    -

    - Do not make any assumptions about the specific layout of objects with nonstandard-layout types. For objects compiled by one compiler that are referenced by code compiled by a different compiler, such assumptions cause correctness and portability concerns. The layout of the object generated by the first compiler is not guaranteed to be identical to the layout generated by the second compiler, even if both compilers are - - conforming - - C++ - - implementations - - . However, some implementations may document binary compatibility guarantees that can be relied on for passing nonstandard-layout objects between execution boundaries. -

    -

    - A special instance of this guidance involves non-C++ code compiled by a different compiler, such as C standard library implementations that are exposed via the C++ standard library. C standard library functions are exposed with C++ signatures, and the type system frequently assists in ensuring that types match appropriately. This process disallows passing a pointer to a C++ object to a function expecting a - - char * - - without additional work to suppress the type mismatch. However, some C standard library functions accept a - - void * - - for which any C++ pointer type will suffice. Passing a pointer to a nonstandard-layout type in this situation results in indeterminate behavior because it depends on the behavior of the other language as well as on the layout of the given object. For more information, see rule - - EXP56-CPP. Do not call a function with a mismatched language linkage - - . -

    -

    - Pass a nonstandard-layout type object across execution boundaries only when both sides of the execution boundary adhere to the same ABI. This is permissible if the same version of a compiler is used to compile both sides of the execution boundary, if the compiler used to compile both sides of the execution boundary is ABI-compatible across multiple versions, or if the differing compilers document that they adhere to the same ABI. -

    +

    An execution boundary is the delimitation between code compiled by differing compilers, including different versions of a compiler produced by the same vendor. For instance, a function may be declared in a header file but defined in a library that is loaded at runtime. The execution boundary exists between the call site in the executable and the function implementation in the library. Such boundaries are also called ABI (application binary interface) boundaries because they relate to the interoperability of application binaries.

    +

    Do not make any assumptions about the specific layout of objects with nonstandard-layout types. For objects compiled by one compiler that are referenced by code compiled by a different compiler, such assumptions cause correctness and portability concerns. The layout of the object generated by the first compiler is not guaranteed to be identical to the layout generated by the second compiler, even if both compilers are conforming C++ implementations. However, some implementations may document binary compatibility guarantees that can be relied on for passing nonstandard-layout objects between execution boundaries.

    +

    A special instance of this guidance involves non-C++ code compiled by a different compiler, such as C standard library implementations that are exposed via the C++ standard library. C standard library functions are exposed with C++ signatures, and the type system frequently assists in ensuring that types match appropriately. This process disallows passing a pointer to a C++ object to a function expecting a char * without additional work to suppress the type mismatch. However, some C standard library functions accept a void * for which any C++ pointer type will suffice. Passing a pointer to a nonstandard-layout type in this situation results in indeterminate behavior because it depends on the behavior of the other language as well as on the layout of the given object. For more information, see rule EXP56-CPP. Do not call a function with a mismatched language linkage.

    +

    Pass a nonstandard-layout type object across execution boundaries only when both sides of the execution boundary adhere to the same ABI. This is permissible if the same version of a compiler is used to compile both sides of the execution boundary, if the compiler used to compile both sides of the execution boundary is ABI-compatible across multiple versions, or if the differing compilers document that they adhere to the same ABI.

    -

    - This noncompliant code example assumes that there is a library whose header is - - library.h - - , an application (represented by - - application.cpp - - ), and that the library and application are not ABI-compatible. Therefore, the contents of - - library.h - - constitute an execution boundary. A nonstandard-layout type object - - S - - is passed across this execution boundary. The application creates an instance of an object of this type, then passes a reference to the object to a function defined by the library, crossing the execution boundary. Because the layout is not guaranteed to be compatible across the boundary, this results in unexpected behavior. -

    - - // library.h +

    This noncompliant code example assumes that there is a library whose header is library.h, an application (represented by application.cpp), and that the library and application are not ABI-compatible. Therefore, the contents of library.h constitute an execution boundary. A nonstandard-layout type object S is passed across this execution boundary. The application creates an instance of an object of this type, then passes a reference to the object to a function defined by the library, crossing the execution boundary. Because the layout is not guaranteed to be compatible across the boundary, this results in unexpected behavior.

    + // library.h struct S { virtual void f() { /* ... */ } }; -  + void func(S &s); // Implemented by the library, calls S::f() -  + // application.cpp #include "library.h" -  + void g() { S s; func(s); -} - -

    - This example would be compliant if the library and the application conformed to the same ABI, either explicitly through vendor documentation or implicitly by virtue of using the same compiler version to compile both. -

    +}
    +

    This example would be compliant if the library and the application conformed to the same ABI, either explicitly through vendor documentation or implicitly by virtue of using the same compiler version to compile both.

    -
    -

    - Because the library and application do not conform to the same ABI, this compliant solution modifies the library and application to work with a standard-layout type. Furthermore, it also adds a - - static_assert() - - to help guard against future code changes that accidentally modify - - S - - to no longer be a standard-layout type. -

    - - // library.h +
    +

    Because the library and application do not conform to the same ABI, this compliant solution modifies the library and application to work with a standard-layout type. Furthermore, it also adds a static_assert() to help guard against future code changes that accidentally modify S to no longer be a standard-layout type.

    + // library.h #include <type_traits> struct S { @@ -135,63 +50,27 @@ void func(S &s); // Implemented by the library, calls S::f() void g() { S s; func(s); -} - +}
    -

    - In this noncompliant code example, a pointer to an object of nonstandard-layout type is passed to a function that has a - - "Fortran" - - language linkage. Language linkages other than - - "C" - - and - - "C++" - - are conditionally supported with implementation-defined semantics [ - - ISO/IEC 14882-2014 - - ]. If the - - implementation - - does not support this language linkage, the code is - - ill-formed - - . Assuming that the language linkage is supported, any operations performed on the object passed may result in indeterminate behavior, which could have security implications. -

    - - struct B { +

    In this noncompliant code example, a pointer to an object of nonstandard-layout type is passed to a function that has a "Fortran" language linkage. Language linkages other than "C" and "C++" are conditionally supported with implementation-defined semantics [ISO/IEC 14882-2014]. If the implementation does not support this language linkage, the code is ill-formed. Assuming that the language linkage is supported, any operations performed on the object passed may result in indeterminate behavior, which could have security implications.

    + struct B { int i, j; }; -  + struct D : B { float f; }; -  + extern "Fortran" void func(void *); -  + void foo(D *d) { func(d); -} - +}
    -

    - In this compliant solution, the nonstandard-layout type object is serialized into a local standard-layout type object, which is then passed to the - - Fortran - - function. -

    - - struct B { +

    In this compliant solution, the nonstandard-layout type object is serialized into a local standard-layout type object, which is then passed to the Fortran function.

    + struct B { int i, j; }; @@ -206,23 +85,16 @@ void foo(D *d) { int i, j; float f; } temp; -  + temp.i = d->i; temp.j = d->j; temp.f = d->f; func(&temp); -} - +}
    -

    - The effects of passing objects of nonstandard-layout type across execution boundaries depends on what operations are performed on the object within the callee as well as what subsequent operations are performed on the object from the caller. The effects can range from correct or benign behavior to - - undefined behavior - - . -

    +

    The effects of passing objects of nonstandard-layout type across execution boundaries depends on what operations are performed on the object within the callee as well as what subsequent operations are performed on the object from the caller. The effects can range from correct or benign behavior to undefined behavior.

    Subclause 7.17, "Common Definitions - - <stddef.h> - + <stddef.h> "
    @@ -259,14 +131,10 @@ void foo(D *d) { Medium @@ -299,9 +167,7 @@ void foo(D *d) { 3.9 @@ -334,9 +198,7 @@ void foo(D *d) { 2021.2
    - - P12 - + P12 - - L1 - + L1
    - - -Wdynamic-class-memaccess - + -Wdynamic-class-memaccess Catches instances where the vtable pointer will be overwritten @@ -317,9 +183,7 @@ void foo(D *d) { 2021.2 - - C++4741, C++4742, C++4743 - + C++4741, C++4742, C++4743 - - CERT_CPP-EXP60-a - + CERT_CPP-EXP60-a Do not pass a nonstandard-layout type object across execution boundaries @@ -346,17 +208,7 @@ void foo(D *d) {
    -

    - Search for other - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for other vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/EXP61-CPP/EscapingLambdaObjectWithCaptureByReference-standard.qhelp b/cpp/cert/src/rules/EXP61-CPP/EscapingLambdaObjectWithCaptureByReference-standard.qhelp index 1e7399289c..7bd69d24d9 100644 --- a/cpp/cert/src/rules/EXP61-CPP/EscapingLambdaObjectWithCaptureByReference-standard.qhelp +++ b/cpp/cert/src/rules/EXP61-CPP/EscapingLambdaObjectWithCaptureByReference-standard.qhelp @@ -1,67 +1,12 @@
    -

    - Lambda expressions may capture objects with automatic storage duration from the set of enclosing scopes (called the - - reaching scope - - ) for use in the lambda's function body. These captures may be either explicit, by specifying the object to capture in the lambda's - - capture-list - - , or implicit, by using a - - capture-default - - and referring to the object within the lambda's function body. When capturing an object explicitly or implicitly, the capture-default indicates that the object is either captured by copy (using - - =) - - or captured by reference (using - - & - - ). When an object is captured by copy, the lambda object will contain an unnamed nonstatic data member that is initialized to the value of the object being captured. This nonstatic data member's lifetime is that of the lambda object's lifetime. However, when an object is captured by reference, the lifetime of the referent is not tied to the lifetime of the lambda object. -

    -

    - Because entities captured are objects with automatic storage duration (or - - this - - ), a general guideline is that functions returning a lambda object (including returning via a reference parameter), or storing a lambda object in a member variable or global, should not capture an entity by reference because the lambda object often outlives the captured reference object. -

    -

    - When a lambda object outlives one of its reference-captured objects, execution of the lambda object's function call operator results in - - undefined behavior - - once that reference-captured object is accessed. Therefore, a lambda object must not outlive any of its reference-captured objects. This is a specific instance of - - EXP54-CPP. Do not access an object outside of its lifetime - - . -

    -

    - Noncompliant Code Example -

    -

    - In this noncompliant code example, the function - - g() - - returns a lambda, which implicitly captures the automatic local variable - - i - - by reference. When that lambda is returned from the call, the reference it captured will refer to a variable whose lifetime has ended. As a result, when the lambda is executed in - - f() - - , the use of the dangling reference in the lambda results in undefined behavior. -

    - - auto g() { +

    Lambda expressions may capture objects with automatic storage duration from the set of enclosing scopes (called the reaching scope) for use in the lambda's function body. These captures may be either explicit, by specifying the object to capture in the lambda's capture-list, or implicit, by using a capture-default and referring to the object within the lambda's function body. When capturing an object explicitly or implicitly, the capture-default indicates that the object is either captured by copy (using =) or captured by reference (using &). When an object is captured by copy, the lambda object will contain an unnamed nonstatic data member that is initialized to the value of the object being captured. This nonstatic data member's lifetime is that of the lambda object's lifetime. However, when an object is captured by reference, the lifetime of the referent is not tied to the lifetime of the lambda object.

    +

    Because entities captured are objects with automatic storage duration (or this), a general guideline is that functions returning a lambda object (including returning via a reference parameter), or storing a lambda object in a member variable or global, should not capture an entity by reference because the lambda object often outlives the captured reference object.

    +

    When a lambda object outlives one of its reference-captured objects, execution of the lambda object's function call operator results in undefined behavior once that reference-captured object is accessed. Therefore, a lambda object must not outlive any of its reference-captured objects. This is a specific instance of EXP54-CPP. Do not access an object outside of its lifetime.

    +

    Noncompliant Code Example

    +

    In this noncompliant code example, the function g() returns a lambda, which implicitly captures the automatic local variable i by reference. When that lambda is returned from the call, the reference it captured will refer to a variable whose lifetime has ended. As a result, when the lambda is executed in f(), the use of the dangling reference in the lambda results in undefined behavior.

    + auto g() { int i = 12; return [&] { i = 100; @@ -71,19 +16,11 @@ void f() { int j = g()(); -} - +}
    -

    - In this compliant solution, the lambda does not capture - - i - - by reference but instead captures it by copy. Consequently, the lambda contains an implicit nonstatic data member whose lifetime is that of the lambda. -

    - - auto g() { +

    In this compliant solution, the lambda does not capture i by reference but instead captures it by copy. Consequently, the lambda contains an implicit nonstatic data member whose lifetime is that of the lambda.

    + auto g() { int i = 12; return [=] () mutable { i = 100; @@ -93,19 +30,11 @@ void f() { void f() { int j = g()(); -} - +}
    -

    - In this noncompliant code example, a lambda reference captures a local variable from an outer lambda. However, this inner lambda outlives the lifetime of the outer lambda and any automatic local variables it defines, resulting in undefined behavior when an inner lambda object is executed within - - f() - - . -

    - - auto g(int val) { +

    In this noncompliant code example, a lambda reference captures a local variable from an outer lambda. However, this inner lambda outlives the lifetime of the outer lambda and any automatic local variables it defines, resulting in undefined behavior when an inner lambda object is executed within f().

    + auto g(int val) { auto outer = [val] { int i = val; auto inner = [&] { @@ -120,19 +49,11 @@ void f() { void f() { auto fn = g(12); int j = fn(); -} - +}
    -

    - In this compliant solution, the inner lambda captures - - i - - by copy instead of by reference. -

    - - auto g(int val) { +

    In this compliant solution, the inner lambda captures i by copy instead of by reference.

    + auto g(int val) { auto outer = [val] { int i = val; auto inner = [i] { @@ -146,13 +67,10 @@ void f() { void f() { auto fn = g(12); int j = fn(); -} - +}
    -

    - Referencing an object outside of its lifetime can result in an attacker being able to run arbitrary code. -

    +

    Referencing an object outside of its lifetime can result in an attacker being able to run arbitrary code.

    @@ -189,14 +107,10 @@ void f() { High @@ -229,9 +143,7 @@ void f() { 20.10 @@ -246,9 +158,7 @@ void f() { 2021.2 @@ -263,15 +173,9 @@ void f() { 2021.2 @@ -320,17 +220,7 @@ void f() {
    - - P6 - + P6 - - L2 - + L2
    - - invalid_pointer_dereference - + invalid_pointer_dereference - - C++4706, C++4707, C++4708 - + C++4706, C++4707, C++4708 - - CERT_CPP-EXP61-a - - - CERT_CPP-EXP61-b - - - CERT_CPP-EXP61-c - + CERT_CPP-EXP61-a + CERT_CPP-EXP61-b + CERT_CPP-EXP61-c Never return lambdas that capture local objects by reference @@ -304,14 +208,10 @@ void f() { - 7.16 + 7.17 - - - V1047 - - + V1047
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/EXP61-CPP/ReturningLambdaObjectWithCaptureByReference-standard.qhelp b/cpp/cert/src/rules/EXP61-CPP/ReturningLambdaObjectWithCaptureByReference-standard.qhelp index 1e7399289c..7bd69d24d9 100644 --- a/cpp/cert/src/rules/EXP61-CPP/ReturningLambdaObjectWithCaptureByReference-standard.qhelp +++ b/cpp/cert/src/rules/EXP61-CPP/ReturningLambdaObjectWithCaptureByReference-standard.qhelp @@ -1,67 +1,12 @@
    -

    - Lambda expressions may capture objects with automatic storage duration from the set of enclosing scopes (called the - - reaching scope - - ) for use in the lambda's function body. These captures may be either explicit, by specifying the object to capture in the lambda's - - capture-list - - , or implicit, by using a - - capture-default - - and referring to the object within the lambda's function body. When capturing an object explicitly or implicitly, the capture-default indicates that the object is either captured by copy (using - - =) - - or captured by reference (using - - & - - ). When an object is captured by copy, the lambda object will contain an unnamed nonstatic data member that is initialized to the value of the object being captured. This nonstatic data member's lifetime is that of the lambda object's lifetime. However, when an object is captured by reference, the lifetime of the referent is not tied to the lifetime of the lambda object. -

    -

    - Because entities captured are objects with automatic storage duration (or - - this - - ), a general guideline is that functions returning a lambda object (including returning via a reference parameter), or storing a lambda object in a member variable or global, should not capture an entity by reference because the lambda object often outlives the captured reference object. -

    -

    - When a lambda object outlives one of its reference-captured objects, execution of the lambda object's function call operator results in - - undefined behavior - - once that reference-captured object is accessed. Therefore, a lambda object must not outlive any of its reference-captured objects. This is a specific instance of - - EXP54-CPP. Do not access an object outside of its lifetime - - . -

    -

    - Noncompliant Code Example -

    -

    - In this noncompliant code example, the function - - g() - - returns a lambda, which implicitly captures the automatic local variable - - i - - by reference. When that lambda is returned from the call, the reference it captured will refer to a variable whose lifetime has ended. As a result, when the lambda is executed in - - f() - - , the use of the dangling reference in the lambda results in undefined behavior. -

    - - auto g() { +

    Lambda expressions may capture objects with automatic storage duration from the set of enclosing scopes (called the reaching scope) for use in the lambda's function body. These captures may be either explicit, by specifying the object to capture in the lambda's capture-list, or implicit, by using a capture-default and referring to the object within the lambda's function body. When capturing an object explicitly or implicitly, the capture-default indicates that the object is either captured by copy (using =) or captured by reference (using &). When an object is captured by copy, the lambda object will contain an unnamed nonstatic data member that is initialized to the value of the object being captured. This nonstatic data member's lifetime is that of the lambda object's lifetime. However, when an object is captured by reference, the lifetime of the referent is not tied to the lifetime of the lambda object.

    +

    Because entities captured are objects with automatic storage duration (or this), a general guideline is that functions returning a lambda object (including returning via a reference parameter), or storing a lambda object in a member variable or global, should not capture an entity by reference because the lambda object often outlives the captured reference object.

    +

    When a lambda object outlives one of its reference-captured objects, execution of the lambda object's function call operator results in undefined behavior once that reference-captured object is accessed. Therefore, a lambda object must not outlive any of its reference-captured objects. This is a specific instance of EXP54-CPP. Do not access an object outside of its lifetime.

    +

    Noncompliant Code Example

    +

    In this noncompliant code example, the function g() returns a lambda, which implicitly captures the automatic local variable i by reference. When that lambda is returned from the call, the reference it captured will refer to a variable whose lifetime has ended. As a result, when the lambda is executed in f(), the use of the dangling reference in the lambda results in undefined behavior.

    + auto g() { int i = 12; return [&] { i = 100; @@ -71,19 +16,11 @@ void f() { int j = g()(); -} - +}
    -

    - In this compliant solution, the lambda does not capture - - i - - by reference but instead captures it by copy. Consequently, the lambda contains an implicit nonstatic data member whose lifetime is that of the lambda. -

    - - auto g() { +

    In this compliant solution, the lambda does not capture i by reference but instead captures it by copy. Consequently, the lambda contains an implicit nonstatic data member whose lifetime is that of the lambda.

    + auto g() { int i = 12; return [=] () mutable { i = 100; @@ -93,19 +30,11 @@ void f() { void f() { int j = g()(); -} - +}
    -

    - In this noncompliant code example, a lambda reference captures a local variable from an outer lambda. However, this inner lambda outlives the lifetime of the outer lambda and any automatic local variables it defines, resulting in undefined behavior when an inner lambda object is executed within - - f() - - . -

    - - auto g(int val) { +

    In this noncompliant code example, a lambda reference captures a local variable from an outer lambda. However, this inner lambda outlives the lifetime of the outer lambda and any automatic local variables it defines, resulting in undefined behavior when an inner lambda object is executed within f().

    + auto g(int val) { auto outer = [val] { int i = val; auto inner = [&] { @@ -120,19 +49,11 @@ void f() { void f() { auto fn = g(12); int j = fn(); -} - +}
    -

    - In this compliant solution, the inner lambda captures - - i - - by copy instead of by reference. -

    - - auto g(int val) { +

    In this compliant solution, the inner lambda captures i by copy instead of by reference.

    + auto g(int val) { auto outer = [val] { int i = val; auto inner = [i] { @@ -146,13 +67,10 @@ void f() { void f() { auto fn = g(12); int j = fn(); -} - +}
    -

    - Referencing an object outside of its lifetime can result in an attacker being able to run arbitrary code. -

    +

    Referencing an object outside of its lifetime can result in an attacker being able to run arbitrary code.

    @@ -189,14 +107,10 @@ void f() { High @@ -229,9 +143,7 @@ void f() { 20.10 @@ -246,9 +158,7 @@ void f() { 2021.2 @@ -263,15 +173,9 @@ void f() { 2021.2 @@ -320,17 +220,7 @@ void f() {
    - - P6 - + P6 - - L2 - + L2
    - - invalid_pointer_dereference - + invalid_pointer_dereference - - C++4706, C++4707, C++4708 - + C++4706, C++4707, C++4708 - - CERT_CPP-EXP61-a - - - CERT_CPP-EXP61-b - - - CERT_CPP-EXP61-c - + CERT_CPP-EXP61-a + CERT_CPP-EXP61-b + CERT_CPP-EXP61-c Never return lambdas that capture local objects by reference @@ -304,14 +208,10 @@ void f() { - 7.16 + 7.17 - - - V1047 - - + V1047
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/EXP62-CPP/MemcmpUsedToAccessObjectRepresentation-standard.qhelp b/cpp/cert/src/rules/EXP62-CPP/MemcmpUsedToAccessObjectRepresentation-standard.qhelp index aa5d3059c4..5937232e00 100644 --- a/cpp/cert/src/rules/EXP62-CPP/MemcmpUsedToAccessObjectRepresentation-standard.qhelp +++ b/cpp/cert/src/rules/EXP62-CPP/MemcmpUsedToAccessObjectRepresentation-standard.qhelp @@ -1,114 +1,18 @@
    -

    - The C++ Standard, [basic.types], paragraph 9 [ - - ISO/IEC 14882-2014 - - ], states the following: -

    +

    The C++ Standard, [basic.types], paragraph 9 [ISO/IEC 14882-2014], states the following:

    -

    - The - - object representation - - of an object of type - - T - - is the sequence of - - N - - - unsigned char - - objects taken up by the object of type - - T - - , where - - N - - equals - - sizeof(T) - - . The - - value representation - - of an object is the set of bits that hold the value of type - - T - - . -

    +

    The object representation of an object of type T is the sequence of N unsigned char objects taken up by the object of type T, where N equals sizeof(T). The value representation of an object is the set of bits that hold the value of type T.

    -

    - The narrow character types ( - - char - - , - - signed char - - , and - - unsigned char - - )—as well as some other integral types on specific platforms—have an object representation that consists solely of the bits from the object's value representation. For such types, accessing any of the bits of the value representation is well-defined behavior. This form of object representation allows a programmer to access and modify an object solely based on its bit representation, such as by calling - - std::memcmp() - - on its object representation. -

    -

    - Other types, such as classes, may not have an object representation composed solely of the bits from the object's value representation. For instance, classes may have bit-field data members, padding inserted between data members, a - - vtable - - to support virtual method dispatch, or data members declared with different access privileges. For such types, accessing bits of the object representation that are not part of the object's value representation may result in - - undefined behavior - - depending on how those bits are accessed. -

    -

    - Do not access the bits of an object representation that are not part of the object's value representation. Even if the bits are accessed in a well-defined manner, such as through an array of - - unsigned char - - objects, the values represented by those bits are unspecified or implementation-defined, and reliance on any particular value can lead to abnormal program execution. -

    +

    The narrow character types (char, signed char, and unsigned char)—as well as some other integral types on specific platforms—have an object representation that consists solely of the bits from the object's value representation. For such types, accessing any of the bits of the value representation is well-defined behavior. This form of object representation allows a programmer to access and modify an object solely based on its bit representation, such as by calling std::memcmp() on its object representation.

    +

    Other types, such as classes, may not have an object representation composed solely of the bits from the object's value representation. For instance, classes may have bit-field data members, padding inserted between data members, a vtable to support virtual method dispatch, or data members declared with different access privileges. For such types, accessing bits of the object representation that are not part of the object's value representation may result in undefined behavior depending on how those bits are accessed.

    +

    Do not access the bits of an object representation that are not part of the object's value representation. Even if the bits are accessed in a well-defined manner, such as through an array of unsigned char objects, the values represented by those bits are unspecified or implementation-defined, and reliance on any particular value can lead to abnormal program execution.

    -

    - In this noncompliant code example, the complete object representation is accessed when comparing two objects of type - - S - - . Per the C++ Standard, [class], paragraph 13 [ - - ISO/IEC 14882-2014 - - ], classes may be padded with data to ensure that they are properly aligned in memory. The contents of the padding and the amount of padding added is - - implementation-defined - - . This can lead to incorrect results when comparing the object representation of classes instead of the value representation, as the padding may assume different - - unspecified values - - for each object instance. -

    - - #include <cstring> -  +

    In this noncompliant code example, the complete object representation is accessed when comparing two objects of type S. Per the C++ Standard, [class], paragraph 13 [ISO/IEC 14882-2014], classes may be padded with data to ensure that they are properly aligned in memory. The contents of the padding and the amount of padding added is implementation-defined. This can lead to incorrect results when comparing the object representation of classes instead of the value representation, as the padding may assume different unspecified values for each object instance.

    + #include <cstring> + struct S { unsigned char buffType; int size; @@ -118,65 +22,33 @@ void f(const S &s1, const S &s2) { if (!std::memcmp(&s1, &s2, sizeof(S))) { // ... } -} - +}
    -

    - In this compliant solution, - - S - - overloads - - operator==() - - to perform a comparison of the value representation of the object. -

    - - struct S { +

    In this compliant solution, S overloads operator==() to perform a comparison of the value representation of the object.

    + struct S { unsigned char buffType; int size; -  + friend bool operator==(const S &lhs, const S &rhs) { return lhs.buffType == rhs.buffType && lhs.size == rhs.size; } }; -  + void f(const S &s1, const S &s2) { if (s1 == s2) { // ... } -} - +}
    -

    - In this noncompliant code example, - - std::memset() - - is used to clear the internal state of an object. An - - implementation - - may store a vtable within the object instance due to the presence of a virtual function, and that vtable is subsequently overwritten by the call to - - std::memset() - - , leading to - - undefined behavior - - when virtual method dispatch is required. -

    - - #include <cstring> +

    In this noncompliant code example, std::memset() is used to clear the internal state of an object. An implementation may store a vtable within the object instance due to the presence of a virtual function, and that vtable is subsequently overwritten by the call to std::memset(), leading to undefined behavior when virtual method dispatch is required.

    + #include <cstring> struct S { int i, j, k; -  + // ... virtual void f(); @@ -188,22 +60,11 @@ void f() { std::memset(s, 0, sizeof(S)); // ... s->f(); // undefined behavior -} - +}
    -

    - In this compliant solution, the data members of - - S - - are cleared explicitly instead of calling - - std::memset(). - -

    - - struct S { +

    In this compliant solution, the data members of S are cleared explicitly instead of calling std::memset().

    + struct S { int i, j, k; // ... @@ -218,56 +79,26 @@ void f() { s->clear(); // ... s->f(); // ok -} - +}
    -

    - - EXP62-CPP-EX1: - - It is permissible to access the bits of an object representation when that access is otherwise unobservable in well-defined code. Specifically, reading bits that are not part of the value representation is permissible when there is no reliance or assumptions placed on their values, and writing bits that are not part of the value representation is only permissible when those bits are padding bits. This exception does not permit writing to bits that are part of the object representation aside from padding bits, such as overwriting a vtable pointer. -

    -

    - For instance, it is acceptable to call - - std::memcpy() - - on an object containing a bit-field, as in the following example, because the read and write of the padding bits cannot be observed. -

    - - #include <cstring> -  +

    EXP62-CPP-EX1: It is permissible to access the bits of an object representation when that access is otherwise unobservable in well-defined code. Specifically, reading bits that are not part of the value representation is permissible when there is no reliance or assumptions placed on their values, and writing bits that are not part of the value representation is only permissible when those bits are padding bits. This exception does not permit writing to bits that are part of the object representation aside from padding bits, such as overwriting a vtable pointer.

    +

    For instance, it is acceptable to call std::memcpy() on an object containing a bit-field, as in the following example, because the read and write of the padding bits cannot be observed.

    + #include <cstring> + struct S { int i : 10; int j; }; -  + void f(const S &s1) { S s2; std::memcpy(&s2, &s1, sizeof(S)); -} - -

    - Code that complies with this exception must still comply with - - OOP57-CPP. Prefer special member functions and overloaded operators to C Standard Library functions - - . -

    +}
    +

    Code that complies with this exception must still comply with OOP57-CPP. Prefer special member functions and overloaded operators to C Standard Library functions.

    -
    -

    - The effects of accessing bits of an object representation that are not part of the object's value representation can range from - - implementation-defined behavior - - (such as assuming the layout of fields with differing access controls) to code execution - - vulnerabilities - - (such as overwriting the vtable pointer). -

    +
    +

    The effects of accessing bits of an object representation that are not part of the object's value representation can range from implementation-defined behavior (such as assuming the layout of fields with differing access controls) to code execution vulnerabilities (such as overwriting the vtable pointer).

    @@ -304,14 +135,10 @@ void f(const S &s1) { High @@ -344,12 +171,27 @@ void f(const S &s1) { 20.10 + + + + + + @@ -362,9 +204,7 @@ void f(const S &s1) { 2021.2 @@ -378,9 +218,7 @@ void f(const S &s1) { @@ -433,17 +261,7 @@ void f(const S &s1) {
    - - P6 - + P6 - - L2 - + L2
    - - invalid_pointer_dereference - uninitialized_variable_use - + invalid_pointer_dereferenceuninitialized_variable_use + +
    + + CodeSonar + + + 6.2p0 + + BADFUNC.MEMCMP + BADFUNC.MEMSET + Use of memcmp + Use of memset
    - - C++4726, C++4727, C++4728, C++4729, C++4731, C++4732, C++4733, C++4734 - + C++4726, C++4727, C++4728, C++4729, C++4731, C++4732, C++4733, C++4734 - - 618 S - + 618 S Partially implemented @@ -396,9 +234,7 @@ void f(const S &s1) { 2021.2 - - CERT_CPP-EXP62-a - + CERT_CPP-EXP62-a Do not compare objects of a class that may contain padding bits with C standard library functions @@ -411,20 +247,12 @@ void f(const S &s1) { - 7.16 + 7.17 - - V598 - - - + V598 , - - - V780 - - + V780
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/EXP62-CPP/MemcpyUsedToAccessObjectRepresentation-standard.qhelp b/cpp/cert/src/rules/EXP62-CPP/MemcpyUsedToAccessObjectRepresentation-standard.qhelp index aa5d3059c4..5937232e00 100644 --- a/cpp/cert/src/rules/EXP62-CPP/MemcpyUsedToAccessObjectRepresentation-standard.qhelp +++ b/cpp/cert/src/rules/EXP62-CPP/MemcpyUsedToAccessObjectRepresentation-standard.qhelp @@ -1,114 +1,18 @@
    -

    - The C++ Standard, [basic.types], paragraph 9 [ - - ISO/IEC 14882-2014 - - ], states the following: -

    +

    The C++ Standard, [basic.types], paragraph 9 [ISO/IEC 14882-2014], states the following:

    -

    - The - - object representation - - of an object of type - - T - - is the sequence of - - N - - - unsigned char - - objects taken up by the object of type - - T - - , where - - N - - equals - - sizeof(T) - - . The - - value representation - - of an object is the set of bits that hold the value of type - - T - - . -

    +

    The object representation of an object of type T is the sequence of N unsigned char objects taken up by the object of type T, where N equals sizeof(T). The value representation of an object is the set of bits that hold the value of type T.

    -

    - The narrow character types ( - - char - - , - - signed char - - , and - - unsigned char - - )—as well as some other integral types on specific platforms—have an object representation that consists solely of the bits from the object's value representation. For such types, accessing any of the bits of the value representation is well-defined behavior. This form of object representation allows a programmer to access and modify an object solely based on its bit representation, such as by calling - - std::memcmp() - - on its object representation. -

    -

    - Other types, such as classes, may not have an object representation composed solely of the bits from the object's value representation. For instance, classes may have bit-field data members, padding inserted between data members, a - - vtable - - to support virtual method dispatch, or data members declared with different access privileges. For such types, accessing bits of the object representation that are not part of the object's value representation may result in - - undefined behavior - - depending on how those bits are accessed. -

    -

    - Do not access the bits of an object representation that are not part of the object's value representation. Even if the bits are accessed in a well-defined manner, such as through an array of - - unsigned char - - objects, the values represented by those bits are unspecified or implementation-defined, and reliance on any particular value can lead to abnormal program execution. -

    +

    The narrow character types (char, signed char, and unsigned char)—as well as some other integral types on specific platforms—have an object representation that consists solely of the bits from the object's value representation. For such types, accessing any of the bits of the value representation is well-defined behavior. This form of object representation allows a programmer to access and modify an object solely based on its bit representation, such as by calling std::memcmp() on its object representation.

    +

    Other types, such as classes, may not have an object representation composed solely of the bits from the object's value representation. For instance, classes may have bit-field data members, padding inserted between data members, a vtable to support virtual method dispatch, or data members declared with different access privileges. For such types, accessing bits of the object representation that are not part of the object's value representation may result in undefined behavior depending on how those bits are accessed.

    +

    Do not access the bits of an object representation that are not part of the object's value representation. Even if the bits are accessed in a well-defined manner, such as through an array of unsigned char objects, the values represented by those bits are unspecified or implementation-defined, and reliance on any particular value can lead to abnormal program execution.

    -

    - In this noncompliant code example, the complete object representation is accessed when comparing two objects of type - - S - - . Per the C++ Standard, [class], paragraph 13 [ - - ISO/IEC 14882-2014 - - ], classes may be padded with data to ensure that they are properly aligned in memory. The contents of the padding and the amount of padding added is - - implementation-defined - - . This can lead to incorrect results when comparing the object representation of classes instead of the value representation, as the padding may assume different - - unspecified values - - for each object instance. -

    - - #include <cstring> -  +

    In this noncompliant code example, the complete object representation is accessed when comparing two objects of type S. Per the C++ Standard, [class], paragraph 13 [ISO/IEC 14882-2014], classes may be padded with data to ensure that they are properly aligned in memory. The contents of the padding and the amount of padding added is implementation-defined. This can lead to incorrect results when comparing the object representation of classes instead of the value representation, as the padding may assume different unspecified values for each object instance.

    + #include <cstring> + struct S { unsigned char buffType; int size; @@ -118,65 +22,33 @@ void f(const S &s1, const S &s2) { if (!std::memcmp(&s1, &s2, sizeof(S))) { // ... } -} - +}
    -

    - In this compliant solution, - - S - - overloads - - operator==() - - to perform a comparison of the value representation of the object. -

    - - struct S { +

    In this compliant solution, S overloads operator==() to perform a comparison of the value representation of the object.

    + struct S { unsigned char buffType; int size; -  + friend bool operator==(const S &lhs, const S &rhs) { return lhs.buffType == rhs.buffType && lhs.size == rhs.size; } }; -  + void f(const S &s1, const S &s2) { if (s1 == s2) { // ... } -} - +}
    -

    - In this noncompliant code example, - - std::memset() - - is used to clear the internal state of an object. An - - implementation - - may store a vtable within the object instance due to the presence of a virtual function, and that vtable is subsequently overwritten by the call to - - std::memset() - - , leading to - - undefined behavior - - when virtual method dispatch is required. -

    - - #include <cstring> +

    In this noncompliant code example, std::memset() is used to clear the internal state of an object. An implementation may store a vtable within the object instance due to the presence of a virtual function, and that vtable is subsequently overwritten by the call to std::memset(), leading to undefined behavior when virtual method dispatch is required.

    + #include <cstring> struct S { int i, j, k; -  + // ... virtual void f(); @@ -188,22 +60,11 @@ void f() { std::memset(s, 0, sizeof(S)); // ... s->f(); // undefined behavior -} - +}
    -

    - In this compliant solution, the data members of - - S - - are cleared explicitly instead of calling - - std::memset(). - -

    - - struct S { +

    In this compliant solution, the data members of S are cleared explicitly instead of calling std::memset().

    + struct S { int i, j, k; // ... @@ -218,56 +79,26 @@ void f() { s->clear(); // ... s->f(); // ok -} - +}
    -

    - - EXP62-CPP-EX1: - - It is permissible to access the bits of an object representation when that access is otherwise unobservable in well-defined code. Specifically, reading bits that are not part of the value representation is permissible when there is no reliance or assumptions placed on their values, and writing bits that are not part of the value representation is only permissible when those bits are padding bits. This exception does not permit writing to bits that are part of the object representation aside from padding bits, such as overwriting a vtable pointer. -

    -

    - For instance, it is acceptable to call - - std::memcpy() - - on an object containing a bit-field, as in the following example, because the read and write of the padding bits cannot be observed. -

    - - #include <cstring> -  +

    EXP62-CPP-EX1: It is permissible to access the bits of an object representation when that access is otherwise unobservable in well-defined code. Specifically, reading bits that are not part of the value representation is permissible when there is no reliance or assumptions placed on their values, and writing bits that are not part of the value representation is only permissible when those bits are padding bits. This exception does not permit writing to bits that are part of the object representation aside from padding bits, such as overwriting a vtable pointer.

    +

    For instance, it is acceptable to call std::memcpy() on an object containing a bit-field, as in the following example, because the read and write of the padding bits cannot be observed.

    + #include <cstring> + struct S { int i : 10; int j; }; -  + void f(const S &s1) { S s2; std::memcpy(&s2, &s1, sizeof(S)); -} - -

    - Code that complies with this exception must still comply with - - OOP57-CPP. Prefer special member functions and overloaded operators to C Standard Library functions - - . -

    +}
    +

    Code that complies with this exception must still comply with OOP57-CPP. Prefer special member functions and overloaded operators to C Standard Library functions.

    -
    -

    - The effects of accessing bits of an object representation that are not part of the object's value representation can range from - - implementation-defined behavior - - (such as assuming the layout of fields with differing access controls) to code execution - - vulnerabilities - - (such as overwriting the vtable pointer). -

    +
    +

    The effects of accessing bits of an object representation that are not part of the object's value representation can range from implementation-defined behavior (such as assuming the layout of fields with differing access controls) to code execution vulnerabilities (such as overwriting the vtable pointer).

    @@ -304,14 +135,10 @@ void f(const S &s1) { High @@ -344,12 +171,27 @@ void f(const S &s1) { 20.10 + + + + + + @@ -362,9 +204,7 @@ void f(const S &s1) { 2021.2 @@ -378,9 +218,7 @@ void f(const S &s1) { @@ -433,17 +261,7 @@ void f(const S &s1) {
    - - P6 - + P6 - - L2 - + L2
    - - invalid_pointer_dereference - uninitialized_variable_use - + invalid_pointer_dereferenceuninitialized_variable_use + +
    + + CodeSonar + + + 6.2p0 + + BADFUNC.MEMCMP + BADFUNC.MEMSET + Use of memcmp + Use of memset
    - - C++4726, C++4727, C++4728, C++4729, C++4731, C++4732, C++4733, C++4734 - + C++4726, C++4727, C++4728, C++4729, C++4731, C++4732, C++4733, C++4734 - - 618 S - + 618 S Partially implemented @@ -396,9 +234,7 @@ void f(const S &s1) { 2021.2 - - CERT_CPP-EXP62-a - + CERT_CPP-EXP62-a Do not compare objects of a class that may contain padding bits with C standard library functions @@ -411,20 +247,12 @@ void f(const S &s1) { - 7.16 + 7.17 - - V598 - - - + V598 , - - - V780 - - + V780
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/EXP62-CPP/MemsetUsedToAccessObjectRepresentation-standard.qhelp b/cpp/cert/src/rules/EXP62-CPP/MemsetUsedToAccessObjectRepresentation-standard.qhelp index aa5d3059c4..5937232e00 100644 --- a/cpp/cert/src/rules/EXP62-CPP/MemsetUsedToAccessObjectRepresentation-standard.qhelp +++ b/cpp/cert/src/rules/EXP62-CPP/MemsetUsedToAccessObjectRepresentation-standard.qhelp @@ -1,114 +1,18 @@
    -

    - The C++ Standard, [basic.types], paragraph 9 [ - - ISO/IEC 14882-2014 - - ], states the following: -

    +

    The C++ Standard, [basic.types], paragraph 9 [ISO/IEC 14882-2014], states the following:

    -

    - The - - object representation - - of an object of type - - T - - is the sequence of - - N - - - unsigned char - - objects taken up by the object of type - - T - - , where - - N - - equals - - sizeof(T) - - . The - - value representation - - of an object is the set of bits that hold the value of type - - T - - . -

    +

    The object representation of an object of type T is the sequence of N unsigned char objects taken up by the object of type T, where N equals sizeof(T). The value representation of an object is the set of bits that hold the value of type T.

    -

    - The narrow character types ( - - char - - , - - signed char - - , and - - unsigned char - - )—as well as some other integral types on specific platforms—have an object representation that consists solely of the bits from the object's value representation. For such types, accessing any of the bits of the value representation is well-defined behavior. This form of object representation allows a programmer to access and modify an object solely based on its bit representation, such as by calling - - std::memcmp() - - on its object representation. -

    -

    - Other types, such as classes, may not have an object representation composed solely of the bits from the object's value representation. For instance, classes may have bit-field data members, padding inserted between data members, a - - vtable - - to support virtual method dispatch, or data members declared with different access privileges. For such types, accessing bits of the object representation that are not part of the object's value representation may result in - - undefined behavior - - depending on how those bits are accessed. -

    -

    - Do not access the bits of an object representation that are not part of the object's value representation. Even if the bits are accessed in a well-defined manner, such as through an array of - - unsigned char - - objects, the values represented by those bits are unspecified or implementation-defined, and reliance on any particular value can lead to abnormal program execution. -

    +

    The narrow character types (char, signed char, and unsigned char)—as well as some other integral types on specific platforms—have an object representation that consists solely of the bits from the object's value representation. For such types, accessing any of the bits of the value representation is well-defined behavior. This form of object representation allows a programmer to access and modify an object solely based on its bit representation, such as by calling std::memcmp() on its object representation.

    +

    Other types, such as classes, may not have an object representation composed solely of the bits from the object's value representation. For instance, classes may have bit-field data members, padding inserted between data members, a vtable to support virtual method dispatch, or data members declared with different access privileges. For such types, accessing bits of the object representation that are not part of the object's value representation may result in undefined behavior depending on how those bits are accessed.

    +

    Do not access the bits of an object representation that are not part of the object's value representation. Even if the bits are accessed in a well-defined manner, such as through an array of unsigned char objects, the values represented by those bits are unspecified or implementation-defined, and reliance on any particular value can lead to abnormal program execution.

    -

    - In this noncompliant code example, the complete object representation is accessed when comparing two objects of type - - S - - . Per the C++ Standard, [class], paragraph 13 [ - - ISO/IEC 14882-2014 - - ], classes may be padded with data to ensure that they are properly aligned in memory. The contents of the padding and the amount of padding added is - - implementation-defined - - . This can lead to incorrect results when comparing the object representation of classes instead of the value representation, as the padding may assume different - - unspecified values - - for each object instance. -

    - - #include <cstring> -  +

    In this noncompliant code example, the complete object representation is accessed when comparing two objects of type S. Per the C++ Standard, [class], paragraph 13 [ISO/IEC 14882-2014], classes may be padded with data to ensure that they are properly aligned in memory. The contents of the padding and the amount of padding added is implementation-defined. This can lead to incorrect results when comparing the object representation of classes instead of the value representation, as the padding may assume different unspecified values for each object instance.

    + #include <cstring> + struct S { unsigned char buffType; int size; @@ -118,65 +22,33 @@ void f(const S &s1, const S &s2) { if (!std::memcmp(&s1, &s2, sizeof(S))) { // ... } -} - +}
    -

    - In this compliant solution, - - S - - overloads - - operator==() - - to perform a comparison of the value representation of the object. -

    - - struct S { +

    In this compliant solution, S overloads operator==() to perform a comparison of the value representation of the object.

    + struct S { unsigned char buffType; int size; -  + friend bool operator==(const S &lhs, const S &rhs) { return lhs.buffType == rhs.buffType && lhs.size == rhs.size; } }; -  + void f(const S &s1, const S &s2) { if (s1 == s2) { // ... } -} - +}
    -

    - In this noncompliant code example, - - std::memset() - - is used to clear the internal state of an object. An - - implementation - - may store a vtable within the object instance due to the presence of a virtual function, and that vtable is subsequently overwritten by the call to - - std::memset() - - , leading to - - undefined behavior - - when virtual method dispatch is required. -

    - - #include <cstring> +

    In this noncompliant code example, std::memset() is used to clear the internal state of an object. An implementation may store a vtable within the object instance due to the presence of a virtual function, and that vtable is subsequently overwritten by the call to std::memset(), leading to undefined behavior when virtual method dispatch is required.

    + #include <cstring> struct S { int i, j, k; -  + // ... virtual void f(); @@ -188,22 +60,11 @@ void f() { std::memset(s, 0, sizeof(S)); // ... s->f(); // undefined behavior -} - +}
    -

    - In this compliant solution, the data members of - - S - - are cleared explicitly instead of calling - - std::memset(). - -

    - - struct S { +

    In this compliant solution, the data members of S are cleared explicitly instead of calling std::memset().

    + struct S { int i, j, k; // ... @@ -218,56 +79,26 @@ void f() { s->clear(); // ... s->f(); // ok -} - +}
    -

    - - EXP62-CPP-EX1: - - It is permissible to access the bits of an object representation when that access is otherwise unobservable in well-defined code. Specifically, reading bits that are not part of the value representation is permissible when there is no reliance or assumptions placed on their values, and writing bits that are not part of the value representation is only permissible when those bits are padding bits. This exception does not permit writing to bits that are part of the object representation aside from padding bits, such as overwriting a vtable pointer. -

    -

    - For instance, it is acceptable to call - - std::memcpy() - - on an object containing a bit-field, as in the following example, because the read and write of the padding bits cannot be observed. -

    - - #include <cstring> -  +

    EXP62-CPP-EX1: It is permissible to access the bits of an object representation when that access is otherwise unobservable in well-defined code. Specifically, reading bits that are not part of the value representation is permissible when there is no reliance or assumptions placed on their values, and writing bits that are not part of the value representation is only permissible when those bits are padding bits. This exception does not permit writing to bits that are part of the object representation aside from padding bits, such as overwriting a vtable pointer.

    +

    For instance, it is acceptable to call std::memcpy() on an object containing a bit-field, as in the following example, because the read and write of the padding bits cannot be observed.

    + #include <cstring> + struct S { int i : 10; int j; }; -  + void f(const S &s1) { S s2; std::memcpy(&s2, &s1, sizeof(S)); -} - -

    - Code that complies with this exception must still comply with - - OOP57-CPP. Prefer special member functions and overloaded operators to C Standard Library functions - - . -

    +}
    +

    Code that complies with this exception must still comply with OOP57-CPP. Prefer special member functions and overloaded operators to C Standard Library functions.

    -
    -

    - The effects of accessing bits of an object representation that are not part of the object's value representation can range from - - implementation-defined behavior - - (such as assuming the layout of fields with differing access controls) to code execution - - vulnerabilities - - (such as overwriting the vtable pointer). -

    +
    +

    The effects of accessing bits of an object representation that are not part of the object's value representation can range from implementation-defined behavior (such as assuming the layout of fields with differing access controls) to code execution vulnerabilities (such as overwriting the vtable pointer).

    @@ -304,14 +135,10 @@ void f(const S &s1) { High @@ -344,12 +171,27 @@ void f(const S &s1) { 20.10 + + + + + + @@ -362,9 +204,7 @@ void f(const S &s1) { 2021.2 @@ -378,9 +218,7 @@ void f(const S &s1) { @@ -433,17 +261,7 @@ void f(const S &s1) {
    - - P6 - + P6 - - L2 - + L2
    - - invalid_pointer_dereference - uninitialized_variable_use - + invalid_pointer_dereferenceuninitialized_variable_use + +
    + + CodeSonar + + + 6.2p0 + + BADFUNC.MEMCMP + BADFUNC.MEMSET + Use of memcmp + Use of memset
    - - C++4726, C++4727, C++4728, C++4729, C++4731, C++4732, C++4733, C++4734 - + C++4726, C++4727, C++4728, C++4729, C++4731, C++4732, C++4733, C++4734 - - 618 S - + 618 S Partially implemented @@ -396,9 +234,7 @@ void f(const S &s1) { 2021.2 - - CERT_CPP-EXP62-a - + CERT_CPP-EXP62-a Do not compare objects of a class that may contain padding bits with C standard library functions @@ -411,20 +247,12 @@ void f(const S &s1) { - 7.16 + 7.17 - - V598 - - - + V598 , - - - V780 - - + V780
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/EXP63-CPP/DoNotRelyOnTheValueOfAMovedFromObject-standard.qhelp b/cpp/cert/src/rules/EXP63-CPP/DoNotRelyOnTheValueOfAMovedFromObject-standard.qhelp index d88d79aa5f..9e98b68835 100644 --- a/cpp/cert/src/rules/EXP63-CPP/DoNotRelyOnTheValueOfAMovedFromObject-standard.qhelp +++ b/cpp/cert/src/rules/EXP63-CPP/DoNotRelyOnTheValueOfAMovedFromObject-standard.qhelp @@ -1,38 +1,10 @@
    -

    - Many types, including user-defined types and types provided by the Standard Template Library, support move semantics. Except in rare circumstances, an object of a type that supports move operations (move initialization or move assignment) will be left in a valid, but unspecified state after the object's value has been moved. -

    -

    - Passing an object as a function argument that binds to an - - rvalue - - reference parameter, including via implicit function call syntax such as move assignment or move construction, - - moves - - the object's state into another object. Upon return from such a function call, the object that was bound as an rvalue reference parameter is considered to be in the - - moved-from - - state. Once an object is in the moved-from state, the only operations that may be safely performed on that object instance are ones for which the operation has no preconditions, because it is unknown whether the unspecified state of the object will satisfy those preconditions. While some types have explicitly-defined preconditions, such as types defined by the Standard Template Library, it should be assumed that the only operations that may be safely performed on a moved-from object instance are reinitialization through assignment into the object or terminating the lifetime of the object by invoking its destructor. -

    -

    - Do not rely on the value of a moved-from object unless the type of the object is documented to be in a well-specified state. While the object is guaranteed to be in a valid state, relying on - - unspecified values - - leads to - - unspecified behavior - - . Since the behavior need not be documented, this can in turn result in abnormal program behavior and portability concerns. -

    -

    - The following Standard Template Library functions are guaranteed to leave the moved-from object in a well-specified state. -

    +

    Many types, including user-defined types and types provided by the Standard Template Library, support move semantics. Except in rare circumstances, an object of a type that supports move operations (move initialization or move assignment) will be left in a valid, but unspecified state after the object's value has been moved.

    +

    Passing an object as a function argument that binds to an rvalue reference parameter, including via implicit function call syntax such as move assignment or move construction, moves the object's state into another object. Upon return from such a function call, the object that was bound as an rvalue reference parameter is considered to be in the moved-from state. Once an object is in the moved-from state, the only operations that may be safely performed on that object instance are ones for which the operation has no preconditions, because it is unknown whether the unspecified state of the object will satisfy those preconditions. While some types have explicitly-defined preconditions, such as types defined by the Standard Template Library, it should be assumed that the only operations that may be safely performed on a moved-from object instance are reinitialization through assignment into the object or terminating the lifetime of the object by invoking its destructor.

    +

    Do not rely on the value of a moved-from object unless the type of the object is documented to be in a well-specified state. While the object is guaranteed to be in a valid state, relying on unspecified values leads to unspecified behavior. Since the behavior need not be documented, this can in turn result in abnormal program behavior and portability concerns.

    +

    The following Standard Template Library functions are guaranteed to leave the moved-from object in a well-specified state.

    @@ -48,17 +20,13 @@
    - - std::unique_ptr - + std::unique_ptr Move construction, Move assignment, "Converting" move construction, "Converting" move assignment (likewise for - - std::unique_ptr - + std::unique_ptr for array objects with a runtime length) @@ -71,9 +39,7 @@
    - - std::shared_ptr - + std::shared_ptr Move construction, Move assignment, @@ -85,15 +51,11 @@
    - - std::shared_ptr - + std::shared_ptr Move construction, Move assignment from a - - std::unique_ptr - + std::unique_ptr The moved-from object is guaranteed to refer to a null pointer value, per [util.smartptr.shared.const], paragraph 29 and [util.smartptr.shared.assign], paragraph 6. @@ -101,9 +63,7 @@
    - - std::weak_ptr - + std::weak_ptr Move construction, Move assignment, @@ -115,36 +75,24 @@
    - - std::basic_ios - + std::basic_ios - - move() - + move() The moved-from object is still left in an unspecified state, except that - - rdbuf() - + rdbuf() shall return the same value as it returned before the move, and - - tie() - + tie() shall return - - 0 - + 0 , per [basic.ios.members], paragraph 20.
    - - std::basic_filebuf - + std::basic_filebuf Move constructor, Move assignment @@ -155,26 +103,20 @@
    - - std::thread - + std::thread Move constructor, Move assignment The result from calling - - get_id() - + get_id() on the moved-from object is guaranteed to remain unchanged; otherwise the object is in an unspecified state, per [thread.thread.constr], paragraph 11 and [thread.thread.assign], paragraph 2.
    - - std::unique_lock - + std::unique_lock Move constructor, Move assignment @@ -185,9 +127,7 @@
    - - std::shared_lock - + std::shared_lock Move constructor, Move assignment @@ -198,9 +138,7 @@
    - - std::promise - + std::promise Move constructor, Move assignment @@ -211,30 +149,22 @@
    - - std::future - + std::future Move constructor, Move assignment Calling - - valid() - + valid() on the moved-from object is guaranteed to return - - false - + false , per [futures.unique_future], paragraphs 8 and 11.
    - - std::shared_future - + std::shared_future Move constructor, Move assignment, @@ -242,21 +172,15 @@ Calling - - valid() - + valid() on the moved-from object is guaranteed to return - - false - + false , per [futures.shared_future], paragraphs 8 and 11.
    - - std::packaged_task - + std::packaged_task Move constructor, Move assignment @@ -267,58 +191,11 @@
    -

    - Several generic standard template library (STL) algorithms, such as - - std::remove() - - and - - std::unique() - - , remove instances of elements from a container without shrinking the size of the container. Instead, these algorithms return a - - ForwardIterator - - to indicate the partition within the container after which elements are no longer valid. The elements in the container that precede the returned iterator are valid elements with specified values; whereas the elements that - succeed - the returned iterator are valid but have unspecified values. Accessing - - unspecified values - - of elements iterated over results in - - unspecified behavior - - . Frequently, the - - erase-remove idiom - - is used to shrink the size of the container when using these algorithms. -

    +

    Several generic standard template library (STL) algorithms, such as std::remove() and std::unique(), remove instances of elements from a container without shrinking the size of the container. Instead, these algorithms return a ForwardIterator to indicate the partition within the container after which elements are no longer valid. The elements in the container that precede the returned iterator are valid elements with specified values; whereas the elements that succeed the returned iterator are valid but have unspecified values. Accessing unspecified values of elements iterated over results in unspecified behavior. Frequently, the erase-remove idiom is used to shrink the size of the container when using these algorithms.

    -
    -

    - In this noncompliant code example, the integer values - - 0 - - through - - 9 - - are expected to be printed to the standard output stream from a - - std::string - - rvalue reference. However, because the object is moved and then reused under the assumption its internal state has been cleared, unexpected output may occur despite not triggering - - undefined behavior - - . -

    - - #include <iostream> +
    +

    In this noncompliant code example, the integer values 0 through 9 are expected to be printed to the standard output stream from a std::string rvalue reference. However, because the object is moved and then reused under the assumption its internal state has been cleared, unexpected output may occur despite not triggering undefined behavior.

    + #include <iostream> #include <string> void g(std::string v) { @@ -331,38 +208,10 @@ void f() { s.append(1, static_cast<char>('0' + i)); g(std::move(s)); } -} - -

    - - Implementation Details - -

    -

    - Some standard library implementations may implement the - - short string optimization (SSO) - - when implementing - - std::string - - . In such implementations, strings under a certain length are stored in a character buffer internal to the - - std::string - - object (avoiding an expensive heap allocation operation). However, such an implementation might not alter the original buffer value when performing a move operation. When the noncompliant code example is compiled with - - Clang - - 3.7 using - - libc++ - - , the following output is produced. -

    - - 0 +} +

    Implementation Details

    +

    Some standard library implementations may implement the short string optimization (SSO) when implementing std::string. In such implementations, strings under a certain length are stored in a character buffer internal to the std::string object (avoiding an expensive heap allocation operation). However, such an implementation might not alter the original buffer value when performing a move operation. When the noncompliant code example is compiled with Clang 3.7 using libc++, the following output is produced.

    + 0 01 012 0123 @@ -371,23 +220,11 @@ void f() { 0123456 01234567 012345678 -0123456789 - +0123456789
    -

    - In this compliant solution, the - - std::string - - object is initialized to the expected value on each iteration of the loop. This practice ensures that the object is in a valid, specified state prior to attempting to access it in - - g() - - , resulting in the expected output. -

    - - #include <iostream> +

    In this compliant solution, the std::string object is initialized to the expected value on each iteration of the loop. This practice ensures that the object is in a valid, specified state prior to attempting to access it in g(), resulting in the expected output.

    + #include <iostream> #include <string> void g(std::string v) { @@ -399,44 +236,24 @@ void f() { std::string s(1, static_cast<char>('0' + i)); g(std::move(s)); } -} - +}
    -
    -

    - In this noncompliant code example, elements matching - - 42 - - are removed from the given container. The contents of the container are then printed to the standard output stream. However, if any elements were removed from the container, the range-based - - for - - loop iterates over an invalid iterator range, resulting in - - unspecified behavior - - . -

    - - #include <algorithm> +
    +

    In this noncompliant code example, elements matching 42 are removed from the given container. The contents of the container are then printed to the standard output stream. However, if any elements were removed from the container, the range-based for loop iterates over an invalid iterator range, resulting in unspecified behavior.

    + #include <algorithm> #include <iostream> #include <vector> -  + void f(std::vector<int> &c) { std::remove(c.begin(), c.end(), 42); for (auto v : c) { std::cout << "Container element: " << v << std::endl; } -} - +}
    -

    - In this compliant solution, elements removed by the standard algorithm are skipped during iteration. -

    - - #include <algorithm> +

    In this compliant solution, elements removed by the standard algorithm are skipped during iteration.

    + #include <algorithm> #include <iostream> #include <vector> @@ -447,19 +264,11 @@ void f(std::vector<int> &c) { std::cout << *i << std::endl; } } -} - +}
    -

    - In this compliant solution, elements removed by the standard algorithm are subsequently erased from the given container. This technique ensures that a valid iterator range is used by the range-based - - for - - loop. -

    - - #include <algorithm> +

    In this compliant solution, elements removed by the standard algorithm are subsequently erased from the given container. This technique ensures that a valid iterator range is used by the range-based for loop.

    + #include <algorithm> #include <iostream> #include <vector> @@ -468,13 +277,10 @@ void f(std::vector<int> &c) { for (auto v : c) { std::cout << "Container element: " << v << std::endl; } -} - +}
    -

    - The state of a moved-from object is generally valid, but unspecified. Relying on unspecified values can lead to abnormal program termination as well as data integrity violations. -

    +

    The state of a moved-from object is generally valid, but unspecified. Relying on unspecified values can lead to abnormal program termination as well as data integrity violations.

    @@ -511,14 +317,10 @@ void f(std::vector<int> &c) { Medium @@ -541,6 +343,22 @@ void f(std::vector<int> &c) { Description + + + + + + @@ -568,9 +384,7 @@ void f(std::vector<int> &c) { 2021.2 @@ -617,17 +427,7 @@ void f(std::vector<int> &c) {
    - - P8 - + P8 - - L2 - + L2
    + + CodeSonar + + + 6.2p0 + + LANG.MEM.NPD + + Null Pointer Dereference +
    @@ -551,9 +369,7 @@ void f(std::vector<int> &c) { 2021.2 - - C++4701, C++4702, C++4703 - + C++4701, C++4702, C++4703 - - CERT_CPP-EXP63-a - + CERT_CPP-EXP63-a Do not rely on the value of a moved-from object @@ -601,14 +415,10 @@ void f(std::vector<int> &c) { - 7.16 + 7.17 - - - V1030 - - + V1030
    -

    - Search for other - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for other vulnerabilities resulting from the violation of this rule on the CERT website.

    @@ -653,23 +453,17 @@ void f(std::vector<int> &c) { ]
    - Subclause 17.6.5.15, "Moved-from State of Library Types" + Subclause 17.6.5.15, "Moved-from State of Library Types" Subclause 20.8.1, "Class Template - - unique_ptr - + unique_ptr " Subclause 20.8.2, "Shared-Ownership Pointers" Subclause 27.5.5, "Class Template - - basic_ios - + basic_ios " Subclause 27.9.1, "File Streams" Subclause 30.3.1, "Class - - thread - + thread " Subclause 30.4.2, "Locks" Subclause 30.6, "Futures" diff --git a/cpp/cert/src/rules/FIO50-CPP/InterleavedInputOutputWithoutPosition-standard.qhelp b/cpp/cert/src/rules/FIO50-CPP/InterleavedInputOutputWithoutPosition-standard.qhelp index 9943e7d2b1..e8c3ca4ff4 100644 --- a/cpp/cert/src/rules/FIO50-CPP/InterleavedInputOutputWithoutPosition-standard.qhelp +++ b/cpp/cert/src/rules/FIO50-CPP/InterleavedInputOutputWithoutPosition-standard.qhelp @@ -1,138 +1,25 @@
    -

    - The C++ Standard, [filebuf], paragraph 2 [ - - ISO/IEC 14882-2014 - - ], states the following: -

    +

    The C++ Standard, [filebuf], paragraph 2 [ISO/IEC 14882-2014], states the following:

    -

    - The restrictions on reading and writing a sequence controlled by an object of class - - basic_filebuf<charT, traits> - - are the same as for reading and writing with the Standard C library - - FILE - - s. -

    +

    The restrictions on reading and writing a sequence controlled by an object of class basic_filebuf<charT, traits> are the same as for reading and writing with the Standard C library FILEs.

    -

    - The C Standard, subclause 7.19.5.3, paragraph 6 [ - - ISO/IEC 9899:1999 - - ], places the following restrictions on - - FILE - - objects opened for both reading and writing: -

    +

    The C Standard, subclause 7.19.5.3, paragraph 6 [ISO/IEC 9899:1999], places the following restrictions on FILE objects opened for both reading and writing:

    -

    - When a file is opened with update mode . . ., both input and output may be performed on the associated stream. However, output shall not be directly followed by input without an intervening call to the - - fflush - - function or to a file positioning function ( - - fseek - - , - - fsetpos - - , or - - rewind - - ), and input shall not be directly followed by output without an intervening call to a file positioning function, unless the input operation encounters end-of-file. -

    +

    When a file is opened with update mode . . ., both input and output may be performed on the associated stream. However, output shall not be directly followed by input without an intervening call to the fflush function or to a file positioning function (fseek, fsetpos, or rewind), and input shall not be directly followed by output without an intervening call to a file positioning function, unless the input operation encounters end-of-file.

    -

    - Consequently, the following scenarios can result in - - undefined behavior - - : -

    +

    Consequently, the following scenarios can result in undefined behavior:

      -
    • - Receiving input from a stream directly following an output to that stream without an intervening call to - - std::basic_filebuf<T>::seekoff() - - if the file is not at end-of-file -
    • -
    • - Outputting to a stream after receiving input from that stream without a call to - - std::basic_filebuf<T>::seekoff() - - if the file is not at end-of-file -
    • +
    • Receiving input from a stream directly following an output to that stream without an intervening call to std::basic_filebuf<T>::seekoff() if the file is not at end-of-file
    • +
    • Outputting to a stream after receiving input from that stream without a call to std::basic_filebuf<T>::seekoff() if the file is not at end-of-file
    -

    - No other - - std::basic_filebuf<T> - - function guarantees behavior as if a call were made to a standard C library file-positioning function, or - - std::fflush() - - . -

    -

    - Calling - - std::basic_ostream<T>::seekp() - - or - - std::basic_istream<T>::seekg() - - eventually results in a call to - - std::basic_filebuf<T>::seekoff() - - for file stream positioning. Given that - - std::basic_iostream<T> - - inherits from both - - std::basic_ostream<T> - - and - - std::basic_istream<T> - - , and - - std::fstream - - inherits from - - std::basic_iostream - - , either function is acceptable to call to ensure the file buffer is in a valid state before the subsequent I/O operation. -

    +

    No other std::basic_filebuf<T> function guarantees behavior as if a call were made to a standard C library file-positioning function, or std::fflush().

    +

    Calling std::basic_ostream<T>::seekp() or std::basic_istream<T>::seekg() eventually results in a call to std::basic_filebuf<T>::seekoff() for file stream positioning. Given that std::basic_iostream<T> inherits from both std::basic_ostream<T> and std::basic_istream<T>, and std::fstream inherits from std::basic_iostream, either function is acceptable to call to ensure the file buffer is in a valid state before the subsequent I/O operation.

    -

    - This noncompliant code example appends data to the end of a file and then reads from the same file. However, because there is no intervening positioning call between the formatted output and input calls, the behavior is - - undefined - - . -

    - - #include <fstream> +

    This noncompliant code example appends data to the end of a file and then reads from the same file. However, because there is no intervening positioning call between the formatted output and input calls, the behavior is undefined.

    + #include <fstream> #include <string> void f(const std::string &fileName) { @@ -146,22 +33,11 @@ void f(const std::string &fileName) { std::string str; file >> str; } - +
    -

    - In this compliant solution, the - - std::basic_istream<T>::seekg() - - function is called between the output and input, eliminating the - - undefined behavior - - . -

    - - #include <fstream> +

    In this compliant solution, the std::basic_istream<T>::seekg() function is called between the output and input, eliminating the undefined behavior.

    + #include <fstream> #include <string> void f(const std::string &fileName) { @@ -172,21 +48,15 @@ void f(const std::string &fileName) { } file << "Output some data"; -  + std::string str; file.seekg(0, std::ios::beg); file >> str; } - +
    -

    - Alternately inputting and outputting from a stream without an intervening flush or positioning call is - - undefined behavior - - . -

    +

    Alternately inputting and outputting from a stream without an intervening flush or positioning call is undefined behavior.

    @@ -223,14 +93,10 @@ void f(const std::string &fileName) { Medium @@ -263,13 +129,29 @@ void f(const std::string &fileName) { 7.2.0 + + + + + + @@ -297,9 +177,7 @@ void f(const std::string &fileName) { 2021.2
    - - P6 - + P6 - - L2 - + L2
    - - CertC++-FIO50 - + CertC++-FIO50
    + + CodeSonar + + + 6.2p0 + + IO.IOWOP + IO.OIWOP + + Input After Output Without Positioning + Output After Input Without Positioning +
    @@ -280,9 +162,7 @@ void f(const std::string &fileName) { 2021.2 - - C++4711, C++4712, C++4713 - + C++4711, C++4712, C++4713 - - CERT_CPP-FIO50-a - + CERT_CPP-FIO50-a Do not alternately input and output from a stream without an intervening flush or positioning call @@ -327,30 +205,10 @@ void f(const std::string &fileName) {
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    -

    - - This rule supplements - - - - FIO39-C. Do not alternately input and output from a stream without an intervening flush or positioning call - - . - -

    +

    This rule supplements FIO39-C. Do not alternately input and output from a stream without an intervening flush or positioning call.

    @@ -375,9 +233,7 @@ void f(const std::string &fileName) { diff --git a/cpp/cert/src/rules/FIO51-CPP/CloseFilesWhenTheyAreNoLongerNeeded-standard.qhelp b/cpp/cert/src/rules/FIO51-CPP/CloseFilesWhenTheyAreNoLongerNeeded-standard.qhelp index f77907f31f..ad1167f071 100644 --- a/cpp/cert/src/rules/FIO51-CPP/CloseFilesWhenTheyAreNoLongerNeeded-standard.qhelp +++ b/cpp/cert/src/rules/FIO51-CPP/CloseFilesWhenTheyAreNoLongerNeeded-standard.qhelp @@ -1,87 +1,12 @@
    -

    - A call to the - - std::basic_filebuf<T>::open() - - function must be matched with a call to - - std::basic_filebuf<T>::close() - - before the lifetime of the last pointer that stores the return value of the call has ended or before normal program termination, whichever occurs first. -

    -

    - Note that - - std::basic_ifstream<T> - - , - - std::basic_ofstream<T> - - , and - - std::basic_fstream<T> - - all maintain an internal reference to a - - std::basic_filebuf<T> - - object on which - - open() - - and - - close() - - are called as needed. Properly managing an object of one of these types (by not leaking the object) is sufficient to ensure compliance with this rule. Often, the best solution is to use the stream object by value semantics instead of via dynamic memory allocation, ensuring compliance with - - MEM51-CPP. Properly deallocate dynamically allocated resources - - . However, that is still insufficient for situations in which destructors are not automatically called. -

    +

    A call to the std::basic_filebuf<T>::open() function must be matched with a call to std::basic_filebuf<T>::close() before the lifetime of the last pointer that stores the return value of the call has ended or before normal program termination, whichever occurs first.

    +

    Note that std::basic_ifstream<T>, std::basic_ofstream<T>, and std::basic_fstream<T> all maintain an internal reference to a std::basic_filebuf<T> object on which open() and close() are called as needed. Properly managing an object of one of these types (by not leaking the object) is sufficient to ensure compliance with this rule. Often, the best solution is to use the stream object by value semantics instead of via dynamic memory allocation, ensuring compliance with MEM51-CPP. Properly deallocate dynamically allocated resources. However, that is still insufficient for situations in which destructors are not automatically called.

    -

    - In this noncompliant code example, a - - std::fstream - - object - - file - - is constructed. The constructor for - - std::fstream - - calls - - std::basic_filebuf<T>::open() - - , and the default - - std::terminate_handler - - called by - - std::terminate() - - is - - std::abort() - - , which does not call destructors. Consequently, the underlying - - std::basic_filebuf<T> - - object maintained by the object is not properly closed. -

    - - #include <exception> +

    In this noncompliant code example, a std::fstream object file is constructed. The constructor for std::fstream calls std::basic_filebuf<T>::open(), and the default std::terminate_handler called by std::terminate() is std::abort(), which does not call destructors. Consequently, the underlying std::basic_filebuf<T> object maintained by the object is not properly closed.

    + #include <exception> #include <fstream> #include <string> @@ -93,34 +18,12 @@ void f(const std::string &fileName) { } // ... std::terminate(); -} - -

    - This noncompliant code example and the subsequent compliant solutions are assumed to eventually call - - std::terminate() - - in accordance with the ERR50-CPP-EX1 exception described in - - ERR50-CPP. Do not abruptly terminate the program - - . Indicating the nature of the problem to the operator is elided for brevity. -

    +}
    +

    This noncompliant code example and the subsequent compliant solutions are assumed to eventually call std::terminate() in accordance with the ERR50-CPP-EX1 exception described in ERR50-CPP. Do not abruptly terminate the program. Indicating the nature of the problem to the operator is elided for brevity.

    -

    - In this compliant solution, - - std::fstream::close() - - is called before - - std::terminate() - - is called, ensuring that the file resources are properly closed. -

    - - #include <exception> +

    In this compliant solution, std::fstream::close() is called before std::terminate() is called, ensuring that the file resources are properly closed.

    + #include <exception> #include <fstream> #include <string> @@ -137,22 +40,11 @@ void f(const std::string &fileName) { } std::terminate(); } - +
    -

    - In this compliant solution, the stream is implicitly closed through - - RAII - - before - - std::terminate() - - is called, ensuring that the file resources are properly closed. -

    - - #include <exception> +

    In this compliant solution, the stream is implicitly closed through RAII before std::terminate() is called, ensuring that the file resources are properly closed.

    + #include <exception> #include <fstream> #include <string> @@ -165,17 +57,10 @@ void f(const std::string &fileName) { } } // file is closed properly here when it is destroyed std::terminate(); -} - +}
    -

    - Failing to properly close files may allow an attacker to exhaust system resources and can increase the risk that data written into in-memory file buffers will not be flushed in the event of - - abnormal program termination - - . -

    +

    Failing to properly close files may allow an attacker to exhaust system resources and can increase the risk that data written into in-memory file buffers will not be flushed in the event of abnormal program termination.

    Subclause 7.19.5.3, "The - - fopen - + fopen Function"
    @@ -212,14 +97,10 @@ void f(const std::string &fileName) { Medium @@ -249,12 +130,10 @@ void f(const std::string &fileName) { @@ -287,11 +164,7 @@ void f(const std::string &fileName) { 2021.4 @@ -306,9 +179,7 @@ void f(const std::string &fileName) { 2021.2
    - - P4 - + P4 - - L3 - + L3
    - 6.1p0 + 6.2p0 - - ALLOC.LEAK - + ALLOC.LEAK Leak @@ -270,9 +149,7 @@ void f(const std::string &fileName) { 2021.2 - - C++4786, C++4787, C++4788 - + C++4786, C++4787, C++4788 - - - RH.LEAK - - + RH.LEAK - - CERT_CPP-FIO51-a - + CERT_CPP-FIO51-a Ensure resources are freed @@ -350,28 +221,10 @@ void f(const std::string &fileName) {
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    -

    - - This rule supplements - - FIO42-C. Close files when they are no longer needed - - . - -

    +

    This rule supplements FIO42-C. Close files when they are no longer needed.

    diff --git a/cpp/cert/src/rules/INT50-CPP/DoNotCastToAnOutOfRangeEnumerationValue-standard.qhelp b/cpp/cert/src/rules/INT50-CPP/DoNotCastToAnOutOfRangeEnumerationValue-standard.qhelp index 6d8f724edd..e849086aa5 100644 --- a/cpp/cert/src/rules/INT50-CPP/DoNotCastToAnOutOfRangeEnumerationValue-standard.qhelp +++ b/cpp/cert/src/rules/INT50-CPP/DoNotCastToAnOutOfRangeEnumerationValue-standard.qhelp @@ -1,78 +1,19 @@
    -

    - Enumerations in C++ come in two forms: - - scoped - - enumerations in which the underlying type is fixed and - - unscoped - - enumerations in which the underlying type may or may not be fixed. The range of values that can be represented by either form of enumeration may include enumerator values not specified by the enumeration itself. The range of valid enumeration values for an enumeration type is defined by the C++ Standard, [dcl.enum], in paragraph 8 [ - - ISO/IEC 14882-2020 - - ]: -

    +

    Enumerations in C++ come in two forms: scoped enumerations in which the underlying type is fixed and unscoped enumerations in which the underlying type may or may not be fixed. The range of values that can be represented by either form of enumeration may include enumerator values not specified by the enumeration itself. The range of valid enumeration values for an enumeration type is defined by the C++ Standard, [dcl.enum], in paragraph 8 [ISO/IEC 14882-2020]:

    -

    - For an enumeration whose underlying type is fixed, the values of the enumeration are the values of the underlying type. Otherwise, the values of the enumeration are the values representable by a hypothetical integer type with minimal width - M - such that all enumerators can be represented. The width of the smallest bit-field large enough to hold all the values of the enumeration type is - M - . It is possible to define an enumeration that has values not defined by any of its enumerators. If the - enumerator-list - is empty, the values of the enumeration are as if the enumeration had a single enumerator with value 0. -

    +

    For an enumeration whose underlying type is fixed, the values of the enumeration are the values of the underlying type. Otherwise, the values of the enumeration are the values representable by a hypothetical integer type with minimal width M such that all enumerators can be represented. The width of the smallest bit-field large enough to hold all the values of the enumeration type is M. It is possible to define an enumeration that has values not defined by any of its enumerators. If the enumerator-list is empty, the values of the enumeration are as if the enumeration had a single enumerator with value 0.

    -

    - The C++ Standard, [expr.static.cast], paragraph 10, states the following: -

    +

    The C++ Standard, [expr.static.cast], paragraph 10, states the following:

    -

    - A value of integral or enumeration type can be explicitly converted to a complete enumeration type. If the enumeration type has a fixed underlying type, the value is first converted to that type by integral conversion, if necessary, and then to the enumeration type. If the enumeration type does not have a fixed underlying type, the value is unchanged if the original value is within the range of the enumeration values ( - 9.7.1 - ), and otherwise, the behavior is undefined. A value of floating-point type can also be explicitly converted to an enumeration type. The resulting value is the same as converting the original value to the underlying type of the enumeration ( - 7.3.10 - ), and subsequently to the enumeration type. -

    +

    A value of integral or enumeration type can be explicitly converted to a complete enumeration type. If the enumeration type has a fixed underlying type, the value is first converted to that type by integral conversion, if necessary, and then to the enumeration type. If the enumeration type does not have a fixed underlying type, the value is unchanged if the original value is within the range of the enumeration values (9.7.1), and otherwise, the behavior is undefined. A value of floating-point type can also be explicitly converted to an enumeration type. The resulting value is the same as converting the original value to the underlying type of the enumeration (7.3.10), and subsequently to the enumeration type.

    -

    - To avoid operating on - - unspecified values - - , the arithmetic value being cast must be within the range of values the enumeration can represent. When dynamically checking for out-of-range values, checking must be performed before the cast expression. -

    +

    To avoid operating on unspecified values, the arithmetic value being cast must be within the range of values the enumeration can represent. When dynamically checking for out-of-range values, checking must be performed before the cast expression.

    -

    - This noncompliant code example attempts to check whether a given value is within the range of acceptable enumeration values. However, it is doing so after casting to the enumeration type, which may not be able to represent the given integer value. On a two's complement system, the valid range of values that can be represented by - - EnumType - - are [0..3], so if a value outside of that range were passed to - - f() - - , the cast to - - EnumType - - would result in an unspecified value, and using that value within the - - if - - statement results in - - unspecified behavior - - . -

    - - enum EnumType { +

    This noncompliant code example attempts to check whether a given value is within the range of acceptable enumeration values. However, it is doing so after casting to the enumeration type, which may not be able to represent the given integer value. On a two's complement system, the valid range of values that can be represented by EnumType are [0..3], so if a value outside of that range were passed to f(), the cast to EnumType would result in an unspecified value, and using that value within the if statement results in unspecified behavior.

    + enum EnumType { First, Second, Third @@ -84,15 +25,11 @@ void f(int intVar) { if (enumVar < First || enumVar > Third) { // Handle error } -} - +}
    -

    - This compliant solution checks that the value can be represented by the enumeration type before performing the conversion to guarantee the conversion does not result in an unspecified value. It does this by restricting the converted value to one for which there is a specific enumerator value. -

    - - enum EnumType { +

    This compliant solution checks that the value can be represented by the enumeration type before performing the conversion to guarantee the conversion does not result in an unspecified value. It does this by restricting the converted value to one for which there is a specific enumerator value.

    + enum EnumType { First, Second, Third @@ -104,18 +41,11 @@ void f(int intVar) { } EnumType enumVar = static_cast<EnumType>(intVar); } - +
    -

    - This compliant solution uses a scoped enumeration, which has a fixed underlying - - int - - type by default, allowing any value from the parameter to be converted into a valid enumeration value. It does not restrict the converted value to one for which there is a specific enumerator value, but it could do so as shown in the previous compliant solution. -

    - - enum class EnumType { +

    This compliant solution uses a scoped enumeration, which has a fixed underlying int type by default, allowing any value from the parameter to be converted into a valid enumeration value. It does not restrict the converted value to one for which there is a specific enumerator value, but it could do so as shown in the previous compliant solution.

    + enum class EnumType { First, Second, Third @@ -123,19 +53,11 @@ void f(int intVar) { void f(int intVar) { EnumType enumVar = static_cast<EnumType>(intVar); -} - +}
    -

    - Similar to the previous compliant solution, this compliant solution uses an unscoped enumeration but provides a fixed underlying - - int - - type allowing any value from the parameter to be converted to a valid enumeration value. -

    - - enum EnumType : int { +

    Similar to the previous compliant solution, this compliant solution uses an unscoped enumeration but provides a fixed underlying int type allowing any value from the parameter to be converted to a valid enumeration value.

    + enum EnumType : int { First, Second, Third @@ -143,28 +65,11 @@ void f(int intVar) { void f(int intVar) { EnumType enumVar = static_cast<EnumType>(intVar); -} - -

    - Although similar to the previous compliant solution, this compliant solution differs from the noncompliant code example in the way the enumerator values are expressed in code and which implicit conversions are allowed. The previous compliant solution requires a nested name specifier to identify the enumerator (for example, - - EnumType::First - - ) and will not implicitly convert the enumerator value to - - int - - . As with the noncompliant code example, this compliant solution does not allow a nested name specifier and will implicitly convert the enumerator value to - - int - - . -

    +}
    +

    Although similar to the previous compliant solution, this compliant solution differs from the noncompliant code example in the way the enumerator values are expressed in code and which implicit conversions are allowed. The previous compliant solution requires a nested name specifier to identify the enumerator (for example, EnumType::First) and will not implicitly convert the enumerator value to int. As with the noncompliant code example, this compliant solution does not allow a nested name specifier and will implicitly convert the enumerator value to int.

    -

    - It is possible for unspecified values to result in a buffer overflow, leading to the execution of arbitrary code by an attacker. However, because enumerators are rarely used for indexing into arrays or other forms of pointer arithmetic, it is more likely that this scenario will result in data integrity violations rather than arbitrary code execution. -

    +

    It is possible for unspecified values to result in a buffer overflow, leading to the execution of arbitrary code by an attacker. However, because enumerators are rarely used for indexing into arrays or other forms of pointer arithmetic, it is more likely that this scenario will result in data integrity violations rather than arbitrary code execution.

    @@ -201,14 +106,10 @@ void f(int intVar) { Medium @@ -241,11 +142,27 @@ void f(int intVar) { 7.2.0 + + + + + + @@ -258,10 +175,7 @@ void f(int intVar) { 2021.2 @@ -276,9 +190,7 @@ void f(int intVar) { 2021.2 @@ -308,14 +218,10 @@ void f(int intVar) { @@ -324,17 +230,7 @@ void f(int intVar) {
    - - P4 - + P4 - - L3 - + L3
    - - CertC++-INT50 - + CertC++-INT50 + +
    + + CodeSonar + + + 6.2p0 + + LANG.CAST.COERCE + LANG.CAST.VALUE + Coercion Alters Value + Cast Alters Value
    - - C++ - 3013 - + C++3013 - - CERT_CPP-INT50-a - + CERT_CPP-INT50-a An expression with enum underlying type shall only have values corresponding to the enumerators of the enumeration @@ -294,9 +206,7 @@ void f(int intVar) { 4.4 - - 3013 - + 3013 - 7.16 + 7.17 - - - V1016 - - + V1016
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/MEM50-CPP/UseAfterFree-standard.qhelp b/cpp/cert/src/rules/MEM50-CPP/UseAfterFree-standard.qhelp index 1a7feb63fe..ce87a52e92 100644 --- a/cpp/cert/src/rules/MEM50-CPP/UseAfterFree-standard.qhelp +++ b/cpp/cert/src/rules/MEM50-CPP/UseAfterFree-standard.qhelp @@ -1,48 +1,17 @@
    -

    - Evaluating a pointer—including dereferencing the pointer, using it as an operand of an arithmetic operation, type casting it, and using it as the right-hand side of an assignment—into memory that has been deallocated by a memory management function is - - undefined behavior - - . Pointers to memory that has been deallocated are called - - dangling pointers - - . Accessing a dangling pointer can result in exploitable - - vulnerabilities - - . -

    -

    - It is at the memory manager's discretion when to reallocate or recycle the freed memory. When memory is freed, all pointers into it become invalid, and its contents might either be returned to the operating system, making the freed space inaccessible, or remain intact and accessible. As a result, the data at the freed location can appear to be valid but change unexpectedly. Consequently, memory must not be written to or read from once it is freed. -

    +

    Evaluating a pointer—including dereferencing the pointer, using it as an operand of an arithmetic operation, type casting it, and using it as the right-hand side of an assignment—into memory that has been deallocated by a memory management function is undefined behavior. Pointers to memory that has been deallocated are called dangling pointers. Accessing a dangling pointer can result in exploitable vulnerabilities.

    +

    It is at the memory manager's discretion when to reallocate or recycle the freed memory. When memory is freed, all pointers into it become invalid, and its contents might either be returned to the operating system, making the freed space inaccessible, or remain intact and accessible. As a result, the data at the freed location can appear to be valid but change unexpectedly. Consequently, memory must not be written to or read from once it is freed.

    -
    -

    - In this noncompliant code example, - - s - - is dereferenced after it has been deallocated. If this access results in a write-after-free, the - - vulnerability - - can be - - exploited - - to run arbitrary code with the permissions of the vulnerable process. Typically, dynamic memory allocations and deallocations are far removed, making it difficult to recognize and diagnose such problems. -

    - - #include <new> -  +
    +

    In this noncompliant code example, s is dereferenced after it has been deallocated. If this access results in a write-after-free, the vulnerability can be exploited to run arbitrary code with the permissions of the vulnerable process. Typically, dynamic memory allocations and deallocations are far removed, making it difficult to recognize and diagnose such problems.

    + #include <new> + struct S { void f(); }; -  + void g() noexcept(false) { S *s = new S; // ... @@ -50,29 +19,12 @@ void g() noexcept(false) { // ... s->f(); } - -

    - The function - - g() - - is marked - - noexcept(false) - - to comply with - - MEM52-CPP. Detect and handle memory allocation errors - - . -

    + +

    The function g() is marked noexcept(false) to comply with MEM52-CPP. Detect and handle memory allocation errors.

    -
    -

    - In this compliant solution, the dynamically allocated memory is not deallocated until it is no longer required. -

    - - #include <new> +
    +

    In this compliant solution, the dynamically allocated memory is not deallocated until it is no longer required.

    + #include <new> struct S { void f(); @@ -83,30 +35,11 @@ void g() noexcept(false) { // ... s->f(); delete s; -} - +}
    -

    - When possible, use automatic storage duration instead of dynamic storage duration. Since - - s - - is not required to live beyond the scope of - - g() - - , this compliant solution uses automatic storage duration to limit the lifetime of - - s - - to the scope of - - g(). - -

    - - struct S { +

    When possible, use automatic storage duration instead of dynamic storage duration. Since s is not required to live beyond the scope of g(), this compliant solution uses automatic storage duration to limit the lifetime of s to the scope of g().

    + struct S { void f(); }; @@ -114,22 +47,14 @@ void g() { S s; // ... s.f(); -} - +}
    -

    - In the following noncompliant code example, the dynamically allocated memory managed by the - - buff - - object is accessed after it has been implicitly deallocated by the object's destructor. -

    - - #include <iostream> +

    In the following noncompliant code example, the dynamically allocated memory managed by the buff object is accessed after it has been implicitly deallocated by the object's destructor.

    + #include <iostream> #include <memory> #include <cstring> -  + int main(int argc, const char *argv[]) { const char *s = ""; if (argc > 1) { @@ -146,32 +71,15 @@ int main(int argc, const char *argv[]) { std::cout << s << std::endl; } - -

    - This code always creates a null-terminated byte string, despite its use of - - strncpy() - - , because it leaves the final - - char - - in the buffer set to 0. -

    +
    +

    This code always creates a null-terminated byte string, despite its use of strncpy(), because it leaves the final char in the buffer set to 0.

    -

    - In this compliant solution, the lifetime of the - - buff - - object extends past the point at which the memory managed by the object is accessed. -

    - - #include <iostream> +

    In this compliant solution, the lifetime of the buff object extends past the point at which the memory managed by the object is accessed.

    + #include <iostream> #include <memory> #include <cstring> -  + int main(int argc, const char *argv[]) { std::unique_ptr<char[]> buff; const char *s = ""; @@ -190,24 +98,13 @@ int main(int argc, const char *argv[]) { std::cout << s << std::endl; } - +
    -

    - In this compliant solution, a variable with automatic storage duration of type - - std::string - - is used in place of the - - std::unique_ptr<char[]> - - , which reduces the complexity and improves the security of the solution. -

    - - #include <iostream> +

    In this compliant solution, a variable with automatic storage duration of type std::string is used in place of the std::unique_ptr<char[]>, which reduces the complexity and improves the security of the solution.

    + #include <iostream> #include <string> -  + int main(int argc, const char *argv[]) { std::string str; @@ -216,60 +113,24 @@ int main(int argc, const char *argv[]) { } std::cout << str << std::endl; -} - +}
    -

    - In this noncompliant code example, - - std::string::c_str() - - is being called on a temporary - - std::string - - object. The resulting pointer will point to released memory once the - - std::string - - object is destroyed at the end of the assignment expression, resulting in - - undefined behavior - - when accessing elements of that pointer. -

    - - #include <string> -  +

    In this noncompliant code example, std::string::c_str() is being called on a temporary std::string object. The resulting pointer will point to released memory once the std::string object is destroyed at the end of the assignment expression, resulting in undefined behavior when accessing elements of that pointer.

    + #include <string> + std::string str_func(); void display_string(const char *); -  + void f() { const char *str = str_func().c_str(); display_string(str); /* Undefined behavior */ -} - +}
    -

    - In this compliant solution, a local copy of the string returned by - - str_func() - - is made to ensure that string - - str - - will be valid when the call to - - display_string() - - is made. -

    - - #include <string> -  +

    In this compliant solution, a local copy of the string returned by str_func() is made to ensure that string str will be valid when the call to display_string() is made.

    + #include <string> + std::string str_func(); void display_string(const char *s); @@ -277,106 +138,40 @@ void f() { std::string str = str_func(); const char *cstr = str.c_str(); display_string(cstr); /* ok */ -} - +}
    -

    - In this noncompliant code example, an attempt is made to allocate zero bytes of memory through a call to - - operator new() - - . If this request succeeds, - - operator new() - - is required to return a non-null pointer value. However, according to the C++ Standard, [basic.stc.dynamic.allocation], paragraph 2 [ - - ISO/IEC 14882-2014 - - ], attempting to dereference memory through such a pointer results in - - undefined behavior - - . -

    - - #include <new> +

    In this noncompliant code example, an attempt is made to allocate zero bytes of memory through a call to operator new(). If this request succeeds, operator new() is required to return a non-null pointer value. However, according to the C++ Standard, [basic.stc.dynamic.allocation], paragraph 2 [ISO/IEC 14882-2014], attempting to dereference memory through such a pointer results in undefined behavior.

    + #include <new> void f() noexcept(false) { unsigned char *ptr = static_cast<unsigned char *>(::operator new(0)); *ptr = 0; // ... ::operator delete(ptr); -} - +}
    -

    - The compliant solution depends on programmer intent. If the programmer intends to allocate a single - - unsigned char - - object, the compliant solution is to use - - new - - instead of a direct call to - - operator new() - - , as this compliant solution demonstrates. -

    - - void f() noexcept(false) { +

    The compliant solution depends on programmer intent. If the programmer intends to allocate a single unsigned char object, the compliant solution is to use new instead of a direct call to operator new(), as this compliant solution demonstrates.

    + void f() noexcept(false) { unsigned char *ptr = new unsigned char; *ptr = 0; // ... delete ptr; -} - +}
    -

    - If the programmer intends to allocate zero bytes of memory (perhaps to obtain a unique pointer value that cannot be reused by any other pointer in the program until it is properly released), then instead of attempting to dereference the resulting pointer, the recommended solution is to declare - - ptr - - as a - - void * - - , which cannot be dereferenced by a - - conforming - - - implementation - - . -

    - - #include <new> +

    If the programmer intends to allocate zero bytes of memory (perhaps to obtain a unique pointer value that cannot be reused by any other pointer in the program until it is properly released), then instead of attempting to dereference the resulting pointer, the recommended solution is to declare ptr as a void *, which cannot be dereferenced by a conforming implementation.

    + #include <new> void f() noexcept(false) { void *ptr = ::operator new(0); // ... ::operator delete(ptr); -} - +}
    -

    - Reading previously dynamically allocated memory after it has been deallocated can lead to - - abnormal program termination - - and - - denial-of-service attacks - - . Writing memory that has been deallocated can lead to the execution of arbitrary code with the permissions of the vulnerable process. -

    +

    Reading previously dynamically allocated memory after it has been deallocated can lead to abnormal program termination and denial-of-service attacks. Writing memory that has been deallocated can lead to the execution of arbitrary code with the permissions of the vulnerable process.

    @@ -413,14 +208,10 @@ void f() noexcept(false) { Medium @@ -453,9 +244,7 @@ void f() noexcept(false) { 20.10 @@ -470,9 +259,7 @@ void f() noexcept(false) { 7.2.0 @@ -487,16 +274,11 @@ void f() noexcept(false) { 3.9 @@ -507,12 +289,10 @@ void f() noexcept(false) { @@ -559,9 +337,7 @@ void f() noexcept(false) { 2021.2 @@ -576,46 +352,14 @@ void f() noexcept(false) { 2021.4 @@ -629,9 +373,7 @@ void f() noexcept(false) { @@ -699,9 +439,7 @@ void f() noexcept(false) { 4.4 @@ -713,20 +451,12 @@ void f() noexcept(false) { @@ -748,28 +478,8 @@ void f() noexcept(false) {
    - - P18 - + P18 - - L1 - + L1
    - - dangling_pointer_use - + dangling_pointer_use - - CertC++-MEM50 - + CertC++-MEM50 - - clang-analyzer-cplusplus.NewDelete - clang-analyzer-alpha.security.ArrayBoundV2 - + clang-analyzer-cplusplus.NewDeleteclang-analyzer-alpha.security.ArrayBoundV2 Checked by - - clang-tidy - + clang-tidy , but does not catch all violations of this rule.
    - 6.1p0 + 6.2p0 - - ALLOC.UAF - + ALLOC.UAF Use after free @@ -541,12 +321,10 @@ void f() noexcept(false) { v7.5.0 - - USE_AFTER_FREE - + USE_AFTER_FREE - Can detect the specific instances where memory is deallocated more than once or read/written to the target of a freed pointer + Can detect the specific instances where memory is deallocated more than once or read/written to the target of a freed pointer
    - - C++4303, C++4304 - + C++4303, C++4304 - - - UFM.DEREF.MIGHT - - - - - UFM.DEREF.MUST - - - - - UFM.FFM.MIGHT - - - - - UFM.FFM.MUST - - - - - UFM.RETURN.MIGHT - - - - - UFM.RETURN.MUST - - - - - UFM.USE.MIGHT - - - - - UFM.USE.MUST - - + UFM.DEREF.MIGHT + UFM.DEREF.MUST + UFM.FFM.MIGHT + UFM.FFM.MUST + UFM.RETURN.MIGHT + UFM.RETURN.MUST + UFM.USE.MIGHT + UFM.USE.MUST - - 483 S, 484 S - + 483 S, 484 S Partially implemented @@ -647,9 +389,7 @@ void f() noexcept(false) { 2021.2 - - CERT_CPP-MEM50-a - + CERT_CPP-MEM50-a Do not use resources that have been freed @@ -685,7 +425,7 @@ void f() noexcept(false) { Checks for: - Pointer access out of bounds, deallocation of previously deallocated pointer, use of previously freed pointer. + Pointer access out of boundsointer access out of bounds, deallocation of previously deallocated pointereallocation of previously deallocated pointer, use of previously freed pointerse of previously freed pointer. Rule partially covered.
    - - 4303, 4304 - + 4303, 4304 - 7.16 + 7.17 - - V586 - - - + V586 , - - - V774 - - + V774
    -

    - VU#623332 describes a double-free vulnerability in the MIT Kerberos 5 function - - krb5_recvauth() - - [ - - VU# 623332 - - ]. -

    -

    - Search for other - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    VU#623332 describes a double-free vulnerability in the MIT Kerberos 5 function krb5_recvauth() [VU# 623332].

    +

    Search for other vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/MEM51-CPP/ProperlyDeallocateDynamicallyAllocatedResources-standard.qhelp b/cpp/cert/src/rules/MEM51-CPP/ProperlyDeallocateDynamicallyAllocatedResources-standard.qhelp index 00b52e5ae2..ed4541aee0 100644 --- a/cpp/cert/src/rules/MEM51-CPP/ProperlyDeallocateDynamicallyAllocatedResources-standard.qhelp +++ b/cpp/cert/src/rules/MEM51-CPP/ProperlyDeallocateDynamicallyAllocatedResources-standard.qhelp @@ -1,67 +1,9 @@
    -

    - The C programming language provides several ways to allocate memory, such as - - std::malloc() - - , - - std::calloc() - - , and - - std::realloc() - - , which can be used by a C++ program. However, the C programming language defines only a single way to free the allocated memory: - - std::free() - - . See - - MEM31-C. Free dynamically allocated memory when no longer needed - - and - - MEM34-C. Only free memory allocated dynamically - - for rules specifically regarding C allocation and deallocation requirements. -

    -

    - The C++ programming language adds additional ways to allocate memory, such as the operators - - new - - , - - new[] - - , and placement - - new - - , and - - allocator objects - - . Unlike C, C++ provides multiple ways to free dynamically allocated memory, such as the operators - - delete - - , - - delete[]() - - , and deallocation functions on allocator objects. -

    -

    - Do not call a deallocation function on anything other than - - nullptr - - , or a pointer returned by the corresponding allocation function described by the following. -

    +

    The C programming language provides several ways to allocate memory, such as std::malloc(), std::calloc(), and std::realloc(), which can be used by a C++ program. However, the C programming language defines only a single way to free the allocated memory: std::free(). See MEM31-C. Free dynamically allocated memory when no longer needed and MEM34-C. Only free memory allocated dynamically for rules specifically regarding C allocation and deallocation requirements.

    +

    The C++ programming language adds additional ways to allocate memory, such as the operators new, new[], and placement new, and allocator objects. Unlike C, C++ provides multiple ways to free dynamically allocated memory, such as the operators delete, delete[](), and deallocation functions on allocator objects.

    +

    Do not call a deallocation function on anything other than nullptr , or a pointer returned by the corresponding allocation function described by the following.

    @@ -75,73 +17,51 @@
    global - - operator new()/new - + operator new()/new global - - operator delete - + operator delete () - - /delete - + /delete
    global - - operator new[]()/new[] - + operator new[]()/new[] global - - operator delete[]()/delete[] - + operator delete[]()/delete[]
    class-specific - - operator new()/new - + operator new()/new - class-specific - operator delete - +class-specific operator delete () - - /delete - + /delete
    - class-specific - operator new[]()/new[] - +class-specific operator new[]()/new[] - class-specific - operator delete[]()/delete[] - +class-specific operator delete[]()/delete[]
    placement - - operator new - + operator new () @@ -150,169 +70,49 @@
    - - allocator<T>::allocate() - + allocator<T>::allocate() - - allocator<T>::deallocate() - + allocator<T>::deallocate()
    - - std::malloc() - + std::malloc() , - - std::calloc() - + std::calloc() , - std:: - realloc() - +std::realloc() - std:: - free() - +std::free()
    - - std::get_temporary_buffer() - + std::get_temporary_buffer() - - std::return_temporary_buffer() - + std::return_temporary_buffer()
    -

    - Passing a pointer value to an inappropriate deallocation function can result in - - undefined behavior - - . -

    -

    - The C++ Standard, [expr.delete], paragraph 2 [ - - ISO/IEC 14882-2014 - - ], in part, states the following: -

    +

    Passing a pointer value to an inappropriate deallocation function can result in undefined behavior.

    +

    The C++ Standard, [expr.delete], paragraph 2 [ISO/IEC 14882-2014], in part, states the following:

    -

    - In the first alternative ( - - delete object - - ), the value of the operand of - - delete - - may be a null pointer value, a pointer to a non-array object created by a previous - - new-expression - - , or a pointer to a subobject (1.8) representing a base class of such an object (Clause 10). If not, the behavior is undefined. In the second alternative ( - - delete array - - ), the value of the operand of - - delete - - may be a null pointer value or a pointer value that resulted from a previous array - - new-expression - - . If not, the behavior is undefined. -

    +

    In the first alternative (delete object), the value of the operand of delete may be a null pointer value, a pointer to a non-array object created by a previous new-expression, or a pointer to a subobject (1.8) representing a base class of such an object (Clause 10). If not, the behavior is undefined. In the second alternative (delete array), the value of the operand of delete may be a null pointer value or a pointer value that resulted from a previous array new-expression. If not, the behavior is undefined.

    -

    - Deallocating a pointer that is not allocated dynamically (including non-dynamic pointers returned from calls to placement - - new() - - ) is undefined behavior because the pointer value was not obtained by an allocation function. Deallocating a pointer that has already - been passed to a deallocation function is undefined behavior because the pointer value no longer points to memory that has been dynamically allocated. -

    -

    - When an operator such as - - new - - is called, it results in a call to an overloadable operator of the same name, such as - - operator new() - - . These overloadable functions can be called directly but carry the same restrictions as their operator counterparts. That is, calling - - operator delete() - - and passing a pointer parameter has the same constraints as calling the - - delete - - operator on that pointer. Further, the overloads are subject to scope resolution, so it is possible (but not permissible) to call a class-specific operator to allocate an object but a global operator to deallocate the object. -

    -

    - See - - MEM53-CPP. Explicitly construct and destruct objects when manually managing object lifetime - - for information on lifetime management of objects when using memory management functions other than the - - new - - and - - delete - - operators. -

    +

    Deallocating a pointer that is not allocated dynamically (including non-dynamic pointers returned from calls to placement new()) is undefined behavior because the pointer value was not obtained by an allocation function. Deallocating a pointer that has already been passed to a deallocation function is undefined behavior because the pointer value no longer points to memory that has been dynamically allocated.

    +

    When an operator such as new is called, it results in a call to an overloadable operator of the same name, such as operator new(). These overloadable functions can be called directly but carry the same restrictions as their operator counterparts. That is, calling operator delete() and passing a pointer parameter has the same constraints as calling the delete operator on that pointer. Further, the overloads are subject to scope resolution, so it is possible (but not permissible) to call a class-specific operator to allocate an object but a global operator to deallocate the object.

    +

    See MEM53-CPP. Explicitly construct and destruct objects when manually managing object lifetime for information on lifetime management of objects when using memory management functions other than the new and delete operators.

    -
    -

    - In this noncompliant code example, the local variable - - space - - is passed as the expression to the placement - - new - - operator. The resulting pointer of that call is then passed to - - ::operator delete() - - , resulting in - - undefined behavior - - due to - - ::operator delete() - - attempting to free memory that was not returned by - - ::operator new() - - . -

    - - #include <iostream> -  +
    +

    In this noncompliant code example, the local variable space is passed as the expression to the placement new operator. The resulting pointer of that call is then passed to ::operator delete(), resulting in undefined behavior due to ::operator delete() attempting to free memory that was not returned by ::operator new().

    + #include <iostream> + struct S { S() { std::cout << "S::S()" << std::endl; } ~S() { std::cout << "S::~S()" << std::endl; } @@ -325,23 +125,11 @@ void f() { // ... delete s1; -} - +}
    -
    -

    - This compliant solution removes the call to - - ::operator delete() - - , instead explicitly calling - - s1 - - 's destructor. This is one of the few times when explicitly invoking a destructor is warranted. -

    - - #include <iostream> +
    +

    This compliant solution removes the call to ::operator delete(), instead explicitly calling s1's destructor. This is one of the few times when explicitly invoking a destructor is warranted.

    + #include <iostream> struct S { S() { std::cout << "S::S()" << std::endl; } @@ -355,44 +143,12 @@ void f() { // ... s1->~S(); -} - +}
    -
    -

    - In this noncompliant code example, two allocations are attempted within the same - - try - - block, and if either fails, the - - catch - - handler attempts to free resources that have been allocated. However, because the pointer variables have not been initialized to a known value, a failure to allocate memory for - - i1 - - may result in passing - - ::operator delete() - - a value (in - - i2 - - ) that was not previously returned by a call to - - ::operator new() - - , resulting in - - undefined behavior - - . -

    - - #include <new> -  +
    +

    In this noncompliant code example, two allocations are attempted within the same try block, and if either fails, the catch handler attempts to free resources that have been allocated. However, because the pointer variables have not been initialized to a known value, a failure to allocate memory for i1 may result in passing ::operator delete() a value (in i2) that was not previously returned by a call to ::operator new(), resulting in undefined behavior.

    + #include <new> + void f() { int *i1, *i2; try { @@ -402,23 +158,12 @@ void f() { delete i1; delete i2; } -} - +}
    -
    -

    - This compliant solution initializes both pointer values to - - nullptr - - , which is a valid value to pass to - - ::operator delete(). - -

    - - #include <new> -  +
    +

    This compliant solution initializes both pointer values to nullptr, which is a valid value to pass to ::operator delete().

    + #include <new> + void f() { int *i1 = nullptr, *i2 = nullptr; try { @@ -428,66 +173,16 @@ void f() { delete i1; delete i2; } -} - +}
    -

    - Once a pointer is passed to the proper deallocation function, that pointer value is invalidated. Passing the pointer to a deallocation function a second time when the pointer value has not been returned by a subsequent call to an allocation function results in an attempt to free memory that has not been allocated dynamically. The underlying data structures that manage the heap can become corrupted in a way that can introduce security - - vulnerabilities - - into a program. These types of issues are called - - double-free vulnerabilities - - . In practice, double-free vulnerabilities can be - - exploited - - to execute arbitrary code. -

    -

    - In this noncompliant code example, the class - - C - - is given ownership of a - - P * - - , which is subsequently deleted by the class destructor. The C++ Standard, [class.copy], paragraph 7 [ - - ISO/IEC 14882-2014 - - ], states the following: -

    +

    Once a pointer is passed to the proper deallocation function, that pointer value is invalidated. Passing the pointer to a deallocation function a second time when the pointer value has not been returned by a subsequent call to an allocation function results in an attempt to free memory that has not been allocated dynamically. The underlying data structures that manage the heap can become corrupted in a way that can introduce security vulnerabilities into a program. These types of issues are called double-free vulnerabilities. In practice, double-free vulnerabilities can be exploited to execute arbitrary code.

    +

    In this noncompliant code example, the class C is given ownership of a P *, which is subsequently deleted by the class destructor. The C++ Standard, [class.copy], paragraph 7 [ISO/IEC 14882-2014], states the following:

    -

    - If the class definition does not explicitly declare a copy constructor, one is declared implicitly. If the class definition declares a move constructor or move assignment operator, the implicitly declared copy constructor is defined as deleted; otherwise, it is defined as defaulted (8.4). The latter case is deprecated if the class has a user-declared copy assignment operator or a user-declared destructor. -

    +

    If the class definition does not explicitly declare a copy constructor, one is declared implicitly. If the class definition declares a move constructor or move assignment operator, the implicitly declared copy constructor is defined as deleted; otherwise, it is defined as defaulted (8.4). The latter case is deprecated if the class has a user-declared copy assignment operator or a user-declared destructor.

    -

    - Despite the presence of a user-declared destructor, - - C - - will have an implicitly defaulted copy constructor defined for it, and this defaulted copy constructor will copy the pointer value stored in - - p - - , resulting in a double-free: the first free happens when - - g() - - exits and the second free happens when - - h() - - exits. -

    - - struct P {}; +

    Despite the presence of a user-declared destructor, C will have an implicitly defaulted copy constructor defined for it, and this defaulted copy constructor will copy the pointer value stored in p, resulting in a double-free: the first free happens when g() exits and the second free happens when h() exits.

    + struct P {}; class C { P *p; @@ -507,31 +202,11 @@ void h() { P *p = new P; C c(p); g(c); -} - +}
    -

    - In this compliant solution, the copy constructor and copy assignment operator for - - C - - are explicitly deleted. This deletion would result in an - - ill-formed - - program with the definition of - - g() - - from the preceding noncompliant code example due to use of the deleted copy constructor. Consequently, - - g() - - was modified to accept its parameter by reference, removing the double-free. -

    - - struct P {}; +

    In this compliant solution, the copy constructor and copy assignment operator for C are explicitly deleted. This deletion would result in an ill-formed program with the definition of g() from the preceding noncompliant code example due to use of the deleted copy constructor. Consequently, g() was modified to accept its parameter by reference, removing the double-free.

    + struct P {}; class C { P *p; @@ -540,7 +215,7 @@ public: C(P *p) : p(p) {} C(const C&) = delete; ~C() { delete p; } -  + void operator=(const C&) = delete; void f() {} @@ -554,148 +229,54 @@ void h() { P *p = new P; C c(p); g(c); -} - +}
    -
    -

    - In the following noncompliant code example, an array is allocated with array - - new[] - - but is deallocated with a scalar - - delete - - call instead of an array - - delete[] - - call, resulting in - - undefined behavior - - . -

    - - void f() { +
    +

    In the following noncompliant code example, an array is allocated with array new[] but is deallocated with a scalar delete call instead of an array delete[] call, resulting in undefined behavior.

    + void f() { int *array = new int[10]; // ... delete array; -} - +}
    -
    +
    -
    - - void f() { +
    + void f() { int *array = new int[10]; // ... delete[] array; } - +
    -

    - In this noncompliant code example, the call to - - malloc() - - is mixed with a call to - - delete - - . -

    - - #include <cstdlib> +

    In this noncompliant code example, the call to malloc() is mixed with a call to delete.

    + #include <cstdlib> void f() { int *i = static_cast<int *>(std::malloc(sizeof(int))); // ... delete i; } - -

    - This code does not violate - - MEM53-CPP. Explicitly construct and destruct objects when manually managing object lifetime - - because it complies with the MEM53-CPP-EX1 exception. -

    +
    +

    This code does not violate MEM53-CPP. Explicitly construct and destruct objects when manually managing object lifetime because it complies with the MEM53-CPP-EX1 exception.

    -

    - Some implementations of - - ::operator new() - - result in calling - - std::malloc() - - . On such implementations, the - - ::operator delete() - - function is required to call - - std::free() - - to deallocate the pointer, and the noncompliant code example would behave in a well-defined manner. However, this is an - - implementation - - detail and should not be relied on—implementations are under no obligation to use underlying C memory management functions to implement C++ memory management operators. -

    +

    Some implementations of ::operator new() result in calling std::malloc(). On such implementations, the ::operator delete() function is required to call std::free() to deallocate the pointer, and the noncompliant code example would behave in a well-defined manner. However, this is an implementation detail and should not be relied on—implementations are under no obligation to use underlying C memory management functions to implement C++ memory management operators.

    -

    - In this compliant solution, the pointer allocated by - - std::malloc() - - is deallocated by a call to - - std::free() - - instead of - - delete. - -

    - - #include <cstdlib> +

    In this compliant solution, the pointer allocated by std::malloc() is deallocated by a call to std::free() instead of delete.

    + #include <cstdlib> void f() { int *i = static_cast<int *>(std::malloc(sizeof(int))); // ... std::free(i); -} - +}
    -

    - In this noncompliant code example, - - std::free() - - is called to deallocate memory that was allocated by - - new - - . A common side effect of the - - undefined behavior - - caused by using the incorrect deallocation function is that destructors will not be called for the object being deallocated by - - std::free(). - -

    - - #include <cstdlib> -  +

    In this noncompliant code example, std::free() is called to deallocate memory that was allocated by new. A common side effect of the undefined behavior caused by using the incorrect deallocation function is that destructors will not be called for the object being deallocated by std::free().

    + #include <cstdlib> + struct S { ~S(); }; @@ -704,33 +285,12 @@ void f() { S *s = new S(); // ... std::free(s); -} - -

    - Additionally, this code violates - - MEM53-CPP. Explicitly construct and destruct objects when manually managing object lifetime - - . -

    +}
    +

    Additionally, this code violates MEM53-CPP. Explicitly construct and destruct objects when manually managing object lifetime.

    -

    - In this compliant solution, the pointer allocated by - - new - - is deallocated by calling - - delete - - instead of - - std::free(). - -

    - - struct S { +

    In this compliant solution, the pointer allocated by new is deallocated by calling delete instead of std::free().

    + struct S { ~S(); }; @@ -738,49 +298,13 @@ void f() { S *s = new S(); // ... delete s; -} - +}
    -
    -

    - In this noncompliant code example, the global - - new - - operator is overridden by a class-specific implementation of - - operator new() - - . When - - new - - is called, the class-specific override is selected, so - - S::operator new() - - is called. However, because the object is destroyed with a scoped - - ::delete - - operator, the global - - operator delete() - - function is called instead of the class-specific implementation - - S::operator delete() - - , resulting in - - undefined behavior - - . -

    - - #include <cstdlib> +
    +

    In this noncompliant code example, the global new operator is overridden by a class-specific implementation of operator new(). When new is called, the class-specific override is selected, so S::operator new() is called. However, because the object is destroyed with a scoped ::delete operator, the global operator delete() function is called instead of the class-specific implementation S::operator delete(), resulting in undefined behavior.

    + #include <cstdlib> #include <new> -  + struct S { static void *operator new(std::size_t size) noexcept(true) { return std::malloc(size); @@ -794,27 +318,11 @@ struct S { void f() { S *s = new S; ::delete s; -} - +}
    -
    -

    - In this compliant solution, the scoped - - ::delete - - call is replaced by a nonscoped - - delete - - call, resulting in - - S::operator delete() - - being called. -

    - - #include <cstdlib> +
    +

    In this compliant solution, the scoped ::delete call is replaced by a nonscoped delete call, resulting in S::operator delete() being called.

    + #include <cstdlib> #include <new> struct S { @@ -830,148 +338,51 @@ struct S { void f() { S *s = new S; delete s; -} - +}
    -

    - In this noncompliant code example, a - - std::unique_ptr - - is declared to hold a pointer to an object, but is direct-initialized with an array of objects. When the - - std::unique_ptr - - is destroyed, its default deleter calls - - delete - - instead of - - delete[] - - , resulting in undefined behavior. -

    - - #include <memory> +

    In this noncompliant code example, a std::unique_ptr is declared to hold a pointer to an object, but is direct-initialized with an array of objects. When the std::unique_ptr is destroyed, its default deleter calls delete instead of delete[], resulting in undefined behavior.

    + #include <memory> struct S {}; void f() { std::unique_ptr<S> s{new S[10]}; -} - +}
    -

    - In this compliant solution, the - - std::unique_ptr - - is declared to hold an array of objects instead of a pointer to an object. Additionally, - - std::make_unique() - - is used to initialize the smart pointer. -

    - - #include <memory> +

    In this compliant solution, the std::unique_ptr is declared to hold an array of objects instead of a pointer to an object. Additionally, std::make_unique() is used to initialize the smart pointer.

    + #include <memory> struct S {}; void f() { std::unique_ptr<S[]> s = std::make_unique<S[]>(10); -} - -

    - Use of - - std::make_unique() - - instead of direct initialization will emit a diagnostic if the resulting - - std::unique_ptr - - is not of the correct type. Had it been used in the noncompliant code example, the result would have been an ill-formed program instead of undefined behavior. It is best to use - - std::make_unique() - - instead of manual initialization by other means. -

    +}
    +

    Use of std::make_unique() instead of direct initialization will emit a diagnostic if the resulting std::unique_ptr is not of the correct type. Had it been used in the noncompliant code example, the result would have been an ill-formed program instead of undefined behavior. It is best to use std::make_unique() instead of manual initialization by other means.

    -

    - In this noncompliant code example, a - - std::shared_ptr - - is declared to hold a pointer to an object, but is direct-initialized with an array of objects. As with - - std::unique_ptr - - , when the - - std::shared_ptr - - is destroyed, its default deleter calls - - delete - - instead of - - delete[] - - , resulting in undefined behavior. -

    - - #include <memory> +

    In this noncompliant code example, a std::shared_ptr is declared to hold a pointer to an object, but is direct-initialized with an array of objects. As with std::unique_ptr, when the std::shared_ptr is destroyed, its default deleter calls delete instead of delete[], resulting in undefined behavior.

    + #include <memory> struct S {}; void f() { std::shared_ptr<S> s{new S[10]}; -} - +}
    -

    - Unlike the compliant solution for - - std::unique_ptr - - , where - - std::make_unique() - - is called to create a unique pointer to an array, it is ill-formed to call - - std::make_shared() - - with an array type. Instead, this compliant solution manually specifies a custom deleter for the shared pointer type, ensuring that the underlying array is properly deleted. -

    - - #include <memory> +

    Unlike the compliant solution for std::unique_ptr, where std::make_unique() is called to create a unique pointer to an array, it is ill-formed to call std::make_shared() with an array type. Instead, this compliant solution manually specifies a custom deleter for the shared pointer type, ensuring that the underlying array is properly deleted.

    + #include <memory> struct S {}; void f() { std::shared_ptr<S> s{new S[10], [](const S *ptr) { delete [] ptr; }}; -} - +}
    -

    - Passing a pointer value to a deallocation function that was not previously obtained by the matching allocation function results in - - undefined behavior - - , which can lead to exploitable - - vulnerabilities - - . -

    +

    Passing a pointer value to a deallocation function that was not previously obtained by the matching allocation function results in undefined behavior, which can lead to exploitable vulnerabilities.

    @@ -1008,14 +419,10 @@ void f() { Medium @@ -1048,10 +455,7 @@ void f() { 20.10 @@ -1066,9 +470,7 @@ void f() { 7.2.0 @@ -1083,19 +485,12 @@ void f() { 3.9 @@ -1106,14 +501,10 @@ void f() { @@ -1148,43 +537,17 @@ void f() { 2021.4 @@ -1198,11 +561,8 @@ void f() { @@ -1282,18 +634,8 @@ void f() { 4.4 @@ -1305,50 +647,22 @@ void f() { @@ -1363,11 +677,7 @@ void f() { 4.10 @@ -1376,17 +686,7 @@ void f() {
    - - P18 - + P18 - - L1 - + L1
    - - invalid_dynamic_memory_allocation - dangling_pointer_use - + invalid_dynamic_memory_allocationdangling_pointer_use - - CertC++-MEM51 - + CertC++-MEM51 - - clang-analyzer-cplusplus.NewDeleteLeaks - - - -Wmismatched-new-delete - clang-analyzer-unix.MismatchedDeallocator - + clang-analyzer-cplusplus.NewDeleteLeaks + -Wmismatched-new-deleteclang-analyzer-unix.MismatchedDeallocator Checked by - - clang-tidy - + clang-tidy , but does not catch all violations of this rule
    - 6.1p0 + 6.2p0 - - ALLOC.FNH - ALLOC.DF - ALLOC.TM - + ALLOC.FNHALLOC.DFALLOC.TM Free non-heap variable @@ -1131,9 +522,7 @@ void f() { 2021.2 - - C++2110, C++2111, C++2112, C++2113, C++2118, C++3337, C++3339, C++4262, C++4263, C++4264 - + C++2110, C++2111, C++2112, C++2113, C++2118, C++3337, C++3339, C++4262, C++4263, C++4264 - - CL.FFM.ASSIGN - - - CL.FFM.COPY - - - CL.FMM - - - CL.SHALLOW.ASSIGN - CL.SHALLOW.COPY - - - FMM.MIGHT - - - FMM.MUST - - - FNH.MIGHT - - - FNH.MUST - - - FUM.GEN.MIGHT - - - FUM.GEN.MUST - - - UNINIT.CTOR.MIGHT - UNINIT.CTOR.MUST - UNINIT.HEAP.MIGHT - UNINIT.HEAP.MUST - + CL.FFM.ASSIGN + CL.FFM.COPY + CL.FMM + CL.SHALLOW.ASSIGNCL.SHALLOW.COPY + FMM.MIGHT + FMM.MUST + FNH.MIGHT + FNH.MUST + FUM.GEN.MIGHT + FUM.GEN.MUST + UNINIT.CTOR.MIGHTUNINIT.CTOR.MUSTUNINIT.HEAP.MIGHTUNINIT.HEAP.MUST - - 232 S, 236 S, 239 S, 407 S, 469 S, 470 S, 483 S, 484 S, 485 S, 64 D, 112 D - - - + 232 S, 236 S, 239 S, 407 S, 469 S, 470 S, 483 S, 484 S, 485 S, 64 D, 112 D + Partially implemented @@ -1218,18 +578,10 @@ void f() { 2021.2 - - CERT_CPP-MEM51-a - - - CERT_CPP-MEM51-b - - - CERT_CPP-MEM51-c - - - CERT_CPP-MEM51-d - + CERT_CPP-MEM51-a + CERT_CPP-MEM51-b + CERT_CPP-MEM51-c + CERT_CPP-MEM51-d Use the same form in corresponding calls to new/malloc and delete/free @@ -1268,7 +620,7 @@ void f() { Checks for: - Invalid deletion of pointer, invalid free of pointer, deallocation of previously deallocated pointer. + Invalid deletion of pointernvalid deletion of pointer, invalid free of pointernvalid free of pointer, deallocation of previously deallocated pointereallocation of previously deallocated pointer. Rule partially covered.
    - - 2110, 2111, 2112, 2113, 2118 - - , - - - - - 3337, 3339 - - , 4262, 4263, 4264 - + 2110, 2111, 2112, 2113, 2118, + 3337, 3339, 4262, 4263, 4264 - 7.16 + 7.17 - - V515 - - - + V515 , - - V554 - - - + V554 , - - V611 - - - + V611 , - - V701 - - - + V701 , - - V748 - - - + V748 , - - V773 - - - + V773 , - - - V1066 - - + V1066 - - - S1232 - - + S1232
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    @@ -1459,13 +759,9 @@ void f() { @@ -1479,21 +775,13 @@ void f() { @@ -1521,13 +809,9 @@ void f() { diff --git a/cpp/cert/src/rules/MEM52-CPP/DetectAndHandleMemoryAllocationErrors-standard.qhelp b/cpp/cert/src/rules/MEM52-CPP/DetectAndHandleMemoryAllocationErrors-standard.qhelp index 19f76d9fab..45090007a1 100644 --- a/cpp/cert/src/rules/MEM52-CPP/DetectAndHandleMemoryAllocationErrors-standard.qhelp +++ b/cpp/cert/src/rules/MEM52-CPP/DetectAndHandleMemoryAllocationErrors-standard.qhelp @@ -1,141 +1,30 @@
    -

    - The default memory allocation operator, - - ::operator new(std::size_t) - - , throws a - - std::bad_alloc - - exception if the allocation fails. Therefore, you need not check whether calling - - ::operator new(std::size_t) - - results in - nullptr - . The nonthrowing form, - - ::operator new(std::size_t, const std::nothrow_t &) - - , does not throw an exception if the allocation fails but instead returns - - nullptr - - . The same behaviors apply for the - - operator new[] - - versions of both allocation functions. Additionally, the default allocator object ( - - std::allocator - - ) uses - - ::operator new(std::size_t) - - to perform allocations and should be treated similarly. -

    - - T *p1 = new T; // Throws std::bad_alloc if allocation fails +

    The default memory allocation operator, ::operator new(std::size_t), throws a std::bad_alloc exception if the allocation fails. Therefore, you need not check whether calling ::operator new(std::size_t) results in nullptr. The nonthrowing form, ::operator new(std::size_t, const std::nothrow_t &), does not throw an exception if the allocation fails but instead returns nullptr. The same behaviors apply for the operator new[] versions of both allocation functions. Additionally, the default allocator object (std::allocator) uses ::operator new(std::size_t) to perform allocations and should be treated similarly.

    + T *p1 = new T; // Throws std::bad_alloc if allocation fails T *p2 = new (std::nothrow) T; // Returns nullptr if allocation fails T *p3 = new T[1]; // Throws std::bad_alloc if the allocation fails -T *p4 = new (std::nothrow) T[1]; // Returns nullptr if the allocation fails - -

    - Furthermore, - - operator new[] - - can throw an error of type - - std::bad_array_new_length - - , a subclass of - - std::bad_alloc - - , if the - - size - - argument passed to - - new - - is negative or excessively large. -

    -

    - When using the nonthrowing form, it is imperative to check that the return value is not - - nullptr - - before accessing the resulting pointer. When using either form, be sure to comply with - - ERR50-CPP. Do not abruptly terminate the program - - . -

    +T *p4 = new (std::nothrow) T[1]; // Returns nullptr if the allocation fails
    +

    Furthermore, operator new[] can throw an error of type std::bad_array_new_length, a subclass of std::bad_alloc, if the size argument passed to new is negative or excessively large.

    +

    When using the nonthrowing form, it is imperative to check that the return value is not nullptr before accessing the resulting pointer. When using either form, be sure to comply with ERR50-CPP. Do not abruptly terminate the program.

    -

    - In this noncompliant code example, an array of - - int - - is created using - - ::operator new[](std::size_t) - - and the results of the allocation are not checked. The function is marked as - - noexcept - - , so the caller assumes this function does not throw any exceptions. Because - - ::operator new[](std::size_t) - - can throw an exception if the allocation fails, it could lead to - - abnormal termination - - of the program. -

    - - #include <cstring> -  +

    In this noncompliant code example, an array of int is created using ::operator new[](std::size_t) and the results of the allocation are not checked. The function is marked as noexcept, so the caller assumes this function does not throw any exceptions. Because ::operator new[](std::size_t) can throw an exception if the allocation fails, it could lead to abnormal termination of the program.

    + #include <cstring> + void f(const int *array, std::size_t size) noexcept { int *copy = new int[size]; std::memcpy(copy, array, size * sizeof(*copy)); // ... delete [] copy; } - +
    -

    - When using - - std::nothrow - - , the - - new - - operator returns either a null pointer or a pointer to the allocated space. Always test the returned pointer to ensure it is not - - nullptr - - before referencing the pointer. This compliant solution handles the error condition appropriately when the returned pointer is - - nullptr. - -

    - - #include <cstring> +

    When using std::nothrow, the new operator returns either a null pointer or a pointer to the allocated space. Always test the returned pointer to ensure it is not nullptr before referencing the pointer. This compliant solution handles the error condition appropriately when the returned pointer is nullptr.

    + #include <cstring> #include <new> void f(const int *array, std::size_t size) noexcept { @@ -147,27 +36,11 @@ void f(const int *array, std::size_t size) noexcept { std::memcpy(copy, array, size * sizeof(*copy)); // ... delete [] copy; -} - +}
    -

    - Alternatively, you can use - - ::operator new[] - - without - - std::nothrow - - and instead catch a - - std::bad_alloc - - exception if sufficient memory cannot be allocated. -

    - - #include <cstring> +

    Alternatively, you can use ::operator new[] without std::nothrow and instead catch a std::bad_alloc exception if sufficient memory cannot be allocated.

    + #include <cstring> #include <new> void f(const int *array, std::size_t size) noexcept { @@ -182,19 +55,11 @@ void f(const int *array, std::size_t size) noexcept { std::memcpy(copy, array, size * sizeof(*copy)); // ... delete [] copy; -} - +}
    -

    - If the design of the function is such that the caller is expected to handle exceptional situations, it is permissible to mark the function explicitly as one that may throw, as in this compliant solution. Marking the function is not strictly required, as any function without a - - noexcept - - specifier is presumed to allow throwing. -

    - - #include <cstring> +

    If the design of the function is such that the caller is expected to handle exceptional situations, it is permissible to mark the function explicitly as one that may throw, as in this compliant solution. Marking the function is not strictly required, as any function without a noexcept specifier is presumed to allow throwing.

    + #include <cstring> void f(const int *array, std::size_t size) noexcept(false) { int *copy = new int[size]; @@ -203,100 +68,23 @@ void f(const int *array, std::size_t size) noexcept(false) { std::memcpy(copy, array, size * sizeof(*copy)); // ... delete [] copy; -} - +}
    -

    - In this noncompliant code example, two memory allocations are performed within the same expression. Because the memory allocations are passed as arguments to a function call, an exception thrown as a result of one of the calls to - - new - - could result in a memory leak. -

    - - struct A { /* ... */ }; -struct B { /* ... */ };  -  +

    In this noncompliant code example, two memory allocations are performed within the same expression. Because the memory allocations are passed as arguments to a function call, an exception thrown as a result of one of the calls to new could result in a memory leak.

    + struct A { /* ... */ }; +struct B { /* ... */ }; + void g(A *, B *); void f() { g(new A, new B); -} - -

    - Consider the situation in which - - A - - is allocated and constructed first, and then - - B - - is allocated and throws an exception. Wrapping the call to - - g() - - in a - - try - - / - - catch - - block is insufficient because it would be impossible to free the memory allocated for - - A - - . -

    -

    - This noncompliant code example also violates - - EXP50-CPP. Do not depend on the order of evaluation for side effects - - , b - ecause the order in which the arguments to - - g() - - are evaluated is unspecified. -

    +}
    +

    Consider the situation in which A is allocated and constructed first, and then B is allocated and throws an exception. Wrapping the call to g() in a try/catch block is insufficient because it would be impossible to free the memory allocated for A.

    +

    This noncompliant code example also violates EXP50-CPP. Do not depend on the order of evaluation for side effects, because the order in which the arguments to g() are evaluated is unspecified.

    -

    - In this compliant solution, a - - std::unique_ptr - - is used to manage the resources for the - - A - - and - - B - - objects with - - RAII - - . In the situation described by the noncompliant code example, - - B - - throwing an exception would still result in the destruction and deallocation of the - - A - - object when then - - std::unique_ptr<A> - - was destroyed. -

    - - #include <memory> +

    In this compliant solution, a std::unique_ptr is used to manage the resources for the A and B objects with RAII. In the situation described by the noncompliant code example, B throwing an exception would still result in the destruction and deallocation of the A object when then std::unique_ptr<A> was destroyed.

    + #include <memory> struct A { /* ... */ }; struct B { /* ... */ }; @@ -304,15 +92,11 @@ struct B { /* ... */ }; void g(std::unique_ptr<A> a, std::unique_ptr<B> b); void f() { g(std::make_unique<A>(), std::make_unique<B>()); -} - +}
    -

    - When possible, the more resilient compliant solution is to remove the memory allocation entirely and pass the objects by reference instead. -

    - - struct A { /* ... */ }; +

    When possible, the more resilient compliant solution is to remove the memory allocation entirely and pass the objects by reference instead.

    + struct A { /* ... */ }; struct B { /* ... */ }; void g(A &a, B &b); @@ -320,32 +104,11 @@ void f() { A a; B b; g(a, b); -} - +}
    -

    - Failing to detect allocation failures can lead to - - abnormal program termination - - and - - denial-of-service attacks - - . -

    -

    - If the vulnerable program references memory offset from the return value, an attacker can exploit the program to read or write arbitrary memory. This - - vulnerability - - has been used to execute arbitrary code [ - - VU#159523 - - ]. -

    +

    Failing to detect allocation failures can lead to abnormal program termination and denial-of-service attacks.

    +

    If the vulnerable program references memory offset from the return value, an attacker can exploit the program to read or write arbitrary memory. This vulnerability has been used to execute arbitrary code [VU#159523].

    "Attacking - - delete - + delete and - - delete [] - + delete [] in C++"
    Rule 8.1, " - - delete - + delete should only be used with - - new" - + new" Rule 8.2, " - - delete [] - + delete [] should only be used with - - new []" - + new []"
    Item 16, "Use the Same Form in Corresponding Uses of - - new - + new and - - delete - + delete "
    @@ -382,14 +145,10 @@ void f() { Medium @@ -435,9 +194,7 @@ void f() { 7.5 @@ -470,81 +225,18 @@ void f() { 2021.4 @@ -558,9 +250,7 @@ void f() { @@ -647,18 +328,10 @@ void f() { @@ -667,48 +340,8 @@ void f() {
    - - P18 - + P18 - - L1 - + L1
    - - CHECKED_RETURN - + CHECKED_RETURN Finds inconsistencies in how function call return values are handled @@ -453,9 +210,7 @@ void f() { 2021.2 - - C++3225, C++3226, C++3227, C++3228, C++3229, C++4632 - + C++3225, C++3226, C++3227, C++3228, C++3229, C++4632 - - - NPD.CHECK.CALL.MIGHT - - - - - NPD.CHECK.CALL.MUST - - - - - NPD.CHECK.MIGHT - - - - - NPD.CHECK.MUST - - - - - NPD.CONST.CALL - - - - - NPD.CONST.DEREF - - - - - NPD.FUNC.CALL.MIGHT - - - - - NPD.FUNC.CALL.MUST - - - - - NPD.FUNC.MIGHT - - - - - NPD.FUNC.MUST - - - - - NPD.GEN.CALL.MIGHT - - - NPD.GEN.CALL.MUST - - - NPD.GEN.MIGHT - - - NPD.GEN. - - - MUST - - - - - RNPD.CALL - - - RNPD.DEREF - - + NPD.CHECK.CALL.MIGHT + NPD.CHECK.CALL.MUST + NPD.CHECK.MIGHT + NPD.CHECK.MUST + NPD.CONST.CALL + NPD.CONST.DEREF + NPD.FUNC.CALL.MIGHT + NPD.FUNC.CALL.MUST + NPD.FUNC.MIGHT + NPD.FUNC.MUST + NPD.GEN.CALL.MIGHTNPD.GEN.CALL.MUSTNPD.GEN.MIGHTNPD.GEN.MUST + RNPD.CALLRNPD.DEREF - - 45 D - + 45 D Partially implemented @@ -576,12 +266,8 @@ void f() { 2021.2 - - CERT_CPP-MEM52-a - - - CERT_CPP-MEM52-b - + CERT_CPP-MEM52-a + CERT_CPP-MEM52-b Check the return value of new @@ -630,12 +316,7 @@ void f() { 4.4 - - 3225, 3226, 3227, 3228, 3229, - - 4632 - - + 3225, 3226, 3227, 3228, 3229, 4632 - 7.16 + 7.17 - - - V522 - - , - - V668 - - + V522, V668
    -

    - The - - vulnerability - - in Adobe Flash [ - - VU#159523 - - ] arises because Flash neglects to check the return value from - - calloc() - - . Even though - - calloc() - - returns - - NULL - - , Flash does not attempt to read or write to the return value. Instead, it attempts to write to an offset from the return value. Dereferencing - - NULL - - usually results in a program crash, but dereferencing an offset from - - NULL - - allows an - - exploit - - to succeed without crashing the program. -

    -

    - Search for vulnerabilities resulting from the violation of this rule on the - - CERT website - - . -

    +

    The vulnerability in Adobe Flash [VU#159523] arises because Flash neglects to check the return value from calloc(). Even though calloc() returns NULL, Flash does not attempt to read or write to the return value. Instead, it attempts to write to an offset from the return value. Dereferencing NULL usually results in a program crash, but dereferencing an offset from NULL allows an exploit to succeed without crashing the program.

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/MEM53-CPP/MissingConstructorCallForManuallyManagedObject-standard.qhelp b/cpp/cert/src/rules/MEM53-CPP/MissingConstructorCallForManuallyManagedObject-standard.qhelp index 826a3e374c..6acb82a64e 100644 --- a/cpp/cert/src/rules/MEM53-CPP/MissingConstructorCallForManuallyManagedObject-standard.qhelp +++ b/cpp/cert/src/rules/MEM53-CPP/MissingConstructorCallForManuallyManagedObject-standard.qhelp @@ -1,176 +1,21 @@
    -

    - The creation of dynamically allocated objects in C++ happens in two stages. The first stage is responsible for allocating sufficient memory to store the object, and the second stage is responsible for initializing the newly allocated chunk of memory, depending on the type of the object being created. -

    -

    - Similarly, the destruction of dynamically allocated objects in C++ happens in two stages. The first stage is responsible for finalizing the object, depending on the type, and the second stage is responsible for deallocating the memory used by the object. The C++ Standard, [basic.life], paragraph 1 [ - - ISO/IEC 14882-2014 - - ], states the following: -

    +

    The creation of dynamically allocated objects in C++ happens in two stages. The first stage is responsible for allocating sufficient memory to store the object, and the second stage is responsible for initializing the newly allocated chunk of memory, depending on the type of the object being created.

    +

    Similarly, the destruction of dynamically allocated objects in C++ happens in two stages. The first stage is responsible for finalizing the object, depending on the type, and the second stage is responsible for deallocating the memory used by the object. The C++ Standard, [basic.life], paragraph 1 [ISO/IEC 14882-2014], states the following:

    -

    - The - - lifetime - - of an object is a runtime property of the object. An object is said to have non-trivial initialization if it is of a class or aggregate type and it or one of its members is initialized by a constructor other than a trivial default constructor. [ - - Note: - - initialization by a trivial copy/move constructor is non-trivial initialization. — - - end note - - ] The lifetime of an object of type - - T - - begins when: -

    -

    - — storage with the proper alignment and size for type - - T - - is obtained, and - — if the object has non-trivial initialization, its initialization is complete. -

    -

    - The lifetime of an object of type - - T - - ends when: -

    -

    - — if - - T - - is a class type with a non-trivial destructor, the destructor call starts, or - — the storage which the object occupies is reused or released. -

    +

    The lifetime of an object is a runtime property of the object. An object is said to have non-trivial initialization if it is of a class or aggregate type and it or one of its members is initialized by a constructor other than a trivial default constructor. [Note: initialization by a trivial copy/move constructor is non-trivial initialization. — end note] The lifetime of an object of type T begins when:

    +

    — storage with the proper alignment and size for type T is obtained, and— if the object has non-trivial initialization, its initialization is complete.

    +

    The lifetime of an object of type T ends when:

    +

    — if T is a class type with a non-trivial destructor, the destructor call starts, or— the storage which the object occupies is reused or released.

    -

    - For a dynamically allocated object, these two stages are typically handled automatically by using the - - new - - and - - delete - - operators. The expression - - new T - - for a type - - T - - results in a call to - - operator new() - - to allocate sufficient memory for - - T - - . If memory is successfully allocated, the default constructor for - - T - - is called. The result of the expression is a pointer - - P - - to the object of type - - T - - . When that pointer is passed in the expression - - delete P - - , it results in a call to the destructor for - - T - - . After the destructor completes, a call is made to - - operator delete() - - to deallocate the memory. -

    -

    - When a program creates a dynamically allocated object by means other than the - - new - - operator, it is said to be - - manually managing - - the lifetime of that object. This situation arises when using other allocation schemes to obtain storage for the dynamically allocated object, such as using an - - allocator object - - or - - malloc() - - . For example, a custom container class may allocate a slab of memory in a - - reserve() - - function in which subsequent objects will be stored. See - - MEM51-CPP. Properly deallocate dynamically allocated resources - - for further information on dynamic memory management. -

    -

    - When manually managing the lifetime of an object, the constructor must be called to initiate the lifetime of the object. Similarly, the destructor must be called to terminate the lifetime of the object. Use of an object outside of its lifetime is - - undefined behavior - - . An object can be constructed either by calling the constructor explicitly using the placement - - new - - operator or by calling the - - construct() - - function of an allocator object. An object can be destroyed either by calling the destructor explicitly or by calling the - - destroy() - - function of an allocator object. -

    +

    For a dynamically allocated object, these two stages are typically handled automatically by using the new and delete operators. The expression new T for a type T results in a call to operator new() to allocate sufficient memory for T. If memory is successfully allocated, the default constructor for T is called. The result of the expression is a pointer P to the object of type T. When that pointer is passed in the expression delete P, it results in a call to the destructor for T. After the destructor completes, a call is made to operator delete() to deallocate the memory.

    +

    When a program creates a dynamically allocated object by means other than the new operator, it is said to be manually managing the lifetime of that object. This situation arises when using other allocation schemes to obtain storage for the dynamically allocated object, such as using an allocator object or malloc(). For example, a custom container class may allocate a slab of memory in a reserve() function in which subsequent objects will be stored. See MEM51-CPP. Properly deallocate dynamically allocated resources for further information on dynamic memory management.

    +

    When manually managing the lifetime of an object, the constructor must be called to initiate the lifetime of the object. Similarly, the destructor must be called to terminate the lifetime of the object. Use of an object outside of its lifetime is undefined behavior. An object can be constructed either by calling the constructor explicitly using the placement new operator or by calling the construct() function of an allocator object. An object can be destroyed either by calling the destructor explicitly or by calling the destroy() function of an allocator object.

    -

    - In this noncompliant code example, a class with nontrivial initialization (due to the presence of a user-provided constructor) is created with a call to - - std::malloc() - - . However, the constructor for the object is never called, resulting in - - undefined behavior - - when the class is later accessed by calling - - s->f() - - . -

    - - #include <cstdlib> +

    In this noncompliant code example, a class with nontrivial initialization (due to the presence of a user-provided constructor) is created with a call to std::malloc(). However, the constructor for the object is never called, resulting in undefined behavior when the class is later accessed by calling s->f().

    + #include <cstdlib> struct S { S(); @@ -180,19 +25,15 @@ struct S { void g() { S *s = static_cast<S *>(std::malloc(sizeof(S))); -  + s->f(); -  + std::free(s); -} - +}
    -

    - In this compliant solution, the constructor and destructor are both explicitly called. Further, to reduce the possibility of the object being used outside of its lifetime, the underlying storage is a separate variable from the live object. -

    - - #include <cstdlib> +

    In this compliant solution, the constructor and destructor are both explicitly called. Further, to reduce the possibility of the object being used outside of its lifetime, the underlying storage is a separate variable from the live object.

    + #include <cstdlib> #include <new> struct S { @@ -206,34 +47,14 @@ void g() { S *s = new (ptr) S; s->f(); -  + s->~S(); std::free(ptr); -} - +}
    -

    - In this noncompliant code example, a custom container class uses an allocator object to obtain storage for arbitrary element types. While the - - copy_elements() - - function is presumed to call copy constructors for elements being moved into the newly allocated storage, this example fails to explicitly call the default constructor for any additional elements being reserved. If such an element is accessed through the - - operator[]() - - function, it results in - - undefined behavior - - , depending on the type - - T - - . -

    - - #include <memory> +

    In this noncompliant code example, a custom container class uses an allocator object to obtain storage for arbitrary element types. While the copy_elements() function is presumed to call copy constructors for elements being moved into the newly allocated storage, this example fails to explicitly call the default constructor for any additional elements being reserved. If such an element is accessed through the operator[]() function, it results in undefined behavior, depending on the type T.

    + #include <memory> template <typename T, typename Alloc = std::allocator<T>> class Container { @@ -260,18 +81,11 @@ public: T &operator[](size_t idx) { return underlyingStorage[idx]; } const T &operator[](size_t idx) const { return underlyingStorage[idx]; } -}; - +};
    -

    - In this compliant solution, all elements are properly initialized by explicitly calling copy or default constructors for - - T. - -

    - - #include <memory> +

    In this compliant solution, all elements are properly initialized by explicitly calling copy or default constructors for T.

    + #include <memory> template <typename T, typename Alloc = std::allocator<T>> class Container { @@ -301,45 +115,13 @@ public: T &operator[](size_t idx) { return underlyingStorage[idx]; } const T &operator[](size_t idx) const { return underlyingStorage[idx]; } -}; - +};
    -

    - - MEM53-CPP-EX1: - - If the object is trivially constructable, it need not have its constructor explicitly called to initiate the object's lifetime. If the object is trivially destructible, it need not have its destructor explicitly called to terminate the object's lifetime. These properties can be tested by calling - - std::is_trivially_constructible() - - and - - std::is_trivially_destructible() - - from - - <type_traits> - - . For instance, integral types such as - - int - - and - - long long - - do not require an explicit constructor or destructor call. -

    +

    MEM53-CPP-EX1: If the object is trivially constructable, it need not have its constructor explicitly called to initiate the object's lifetime. If the object is trivially destructible, it need not have its destructor explicitly called to terminate the object's lifetime. These properties can be tested by calling std::is_trivially_constructible() and std::is_trivially_destructible() from <type_traits>. For instance, integral types such as int and long long do not require an explicit constructor or destructor call.

    -

    - Failing to properly construct or destroy an object leaves its internal state inconsistent, which can result in - - undefined behavior - - and accidental information exposure. -

    +

    Failing to properly construct or destroy an object leaves its internal state inconsistent, which can result in undefined behavior and accidental information exposure.

    @@ -376,14 +158,10 @@ public: Medium @@ -416,9 +194,7 @@ public: 2021.2 @@ -433,9 +209,7 @@ public: 2021.2 @@ -468,17 +234,7 @@ public:
    - - P18 - + P18 - - L1 - + L1
    - - C++4761, C++4762, C++4766, C++4767 - + C++4761, C++4762, C++4766, C++4767 - - CERT_CPP-MEM53-a - + CERT_CPP-MEM53-a Do not invoke malloc/realloc for objects having constructors @@ -448,18 +222,10 @@ public: - 7.16 + 7.17 - - - V630 - - , - - V749 - - + V630, V749
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/MEM53-CPP/MissingDestructorCallForManuallyManagedObject-standard.qhelp b/cpp/cert/src/rules/MEM53-CPP/MissingDestructorCallForManuallyManagedObject-standard.qhelp index 826a3e374c..6acb82a64e 100644 --- a/cpp/cert/src/rules/MEM53-CPP/MissingDestructorCallForManuallyManagedObject-standard.qhelp +++ b/cpp/cert/src/rules/MEM53-CPP/MissingDestructorCallForManuallyManagedObject-standard.qhelp @@ -1,176 +1,21 @@
    -

    - The creation of dynamically allocated objects in C++ happens in two stages. The first stage is responsible for allocating sufficient memory to store the object, and the second stage is responsible for initializing the newly allocated chunk of memory, depending on the type of the object being created. -

    -

    - Similarly, the destruction of dynamically allocated objects in C++ happens in two stages. The first stage is responsible for finalizing the object, depending on the type, and the second stage is responsible for deallocating the memory used by the object. The C++ Standard, [basic.life], paragraph 1 [ - - ISO/IEC 14882-2014 - - ], states the following: -

    +

    The creation of dynamically allocated objects in C++ happens in two stages. The first stage is responsible for allocating sufficient memory to store the object, and the second stage is responsible for initializing the newly allocated chunk of memory, depending on the type of the object being created.

    +

    Similarly, the destruction of dynamically allocated objects in C++ happens in two stages. The first stage is responsible for finalizing the object, depending on the type, and the second stage is responsible for deallocating the memory used by the object. The C++ Standard, [basic.life], paragraph 1 [ISO/IEC 14882-2014], states the following:

    -

    - The - - lifetime - - of an object is a runtime property of the object. An object is said to have non-trivial initialization if it is of a class or aggregate type and it or one of its members is initialized by a constructor other than a trivial default constructor. [ - - Note: - - initialization by a trivial copy/move constructor is non-trivial initialization. — - - end note - - ] The lifetime of an object of type - - T - - begins when: -

    -

    - — storage with the proper alignment and size for type - - T - - is obtained, and - — if the object has non-trivial initialization, its initialization is complete. -

    -

    - The lifetime of an object of type - - T - - ends when: -

    -

    - — if - - T - - is a class type with a non-trivial destructor, the destructor call starts, or - — the storage which the object occupies is reused or released. -

    +

    The lifetime of an object is a runtime property of the object. An object is said to have non-trivial initialization if it is of a class or aggregate type and it or one of its members is initialized by a constructor other than a trivial default constructor. [Note: initialization by a trivial copy/move constructor is non-trivial initialization. — end note] The lifetime of an object of type T begins when:

    +

    — storage with the proper alignment and size for type T is obtained, and— if the object has non-trivial initialization, its initialization is complete.

    +

    The lifetime of an object of type T ends when:

    +

    — if T is a class type with a non-trivial destructor, the destructor call starts, or— the storage which the object occupies is reused or released.

    -

    - For a dynamically allocated object, these two stages are typically handled automatically by using the - - new - - and - - delete - - operators. The expression - - new T - - for a type - - T - - results in a call to - - operator new() - - to allocate sufficient memory for - - T - - . If memory is successfully allocated, the default constructor for - - T - - is called. The result of the expression is a pointer - - P - - to the object of type - - T - - . When that pointer is passed in the expression - - delete P - - , it results in a call to the destructor for - - T - - . After the destructor completes, a call is made to - - operator delete() - - to deallocate the memory. -

    -

    - When a program creates a dynamically allocated object by means other than the - - new - - operator, it is said to be - - manually managing - - the lifetime of that object. This situation arises when using other allocation schemes to obtain storage for the dynamically allocated object, such as using an - - allocator object - - or - - malloc() - - . For example, a custom container class may allocate a slab of memory in a - - reserve() - - function in which subsequent objects will be stored. See - - MEM51-CPP. Properly deallocate dynamically allocated resources - - for further information on dynamic memory management. -

    -

    - When manually managing the lifetime of an object, the constructor must be called to initiate the lifetime of the object. Similarly, the destructor must be called to terminate the lifetime of the object. Use of an object outside of its lifetime is - - undefined behavior - - . An object can be constructed either by calling the constructor explicitly using the placement - - new - - operator or by calling the - - construct() - - function of an allocator object. An object can be destroyed either by calling the destructor explicitly or by calling the - - destroy() - - function of an allocator object. -

    +

    For a dynamically allocated object, these two stages are typically handled automatically by using the new and delete operators. The expression new T for a type T results in a call to operator new() to allocate sufficient memory for T. If memory is successfully allocated, the default constructor for T is called. The result of the expression is a pointer P to the object of type T. When that pointer is passed in the expression delete P, it results in a call to the destructor for T. After the destructor completes, a call is made to operator delete() to deallocate the memory.

    +

    When a program creates a dynamically allocated object by means other than the new operator, it is said to be manually managing the lifetime of that object. This situation arises when using other allocation schemes to obtain storage for the dynamically allocated object, such as using an allocator object or malloc(). For example, a custom container class may allocate a slab of memory in a reserve() function in which subsequent objects will be stored. See MEM51-CPP. Properly deallocate dynamically allocated resources for further information on dynamic memory management.

    +

    When manually managing the lifetime of an object, the constructor must be called to initiate the lifetime of the object. Similarly, the destructor must be called to terminate the lifetime of the object. Use of an object outside of its lifetime is undefined behavior. An object can be constructed either by calling the constructor explicitly using the placement new operator or by calling the construct() function of an allocator object. An object can be destroyed either by calling the destructor explicitly or by calling the destroy() function of an allocator object.

    -

    - In this noncompliant code example, a class with nontrivial initialization (due to the presence of a user-provided constructor) is created with a call to - - std::malloc() - - . However, the constructor for the object is never called, resulting in - - undefined behavior - - when the class is later accessed by calling - - s->f() - - . -

    - - #include <cstdlib> +

    In this noncompliant code example, a class with nontrivial initialization (due to the presence of a user-provided constructor) is created with a call to std::malloc(). However, the constructor for the object is never called, resulting in undefined behavior when the class is later accessed by calling s->f().

    + #include <cstdlib> struct S { S(); @@ -180,19 +25,15 @@ struct S { void g() { S *s = static_cast<S *>(std::malloc(sizeof(S))); -  + s->f(); -  + std::free(s); -} - +}
    -

    - In this compliant solution, the constructor and destructor are both explicitly called. Further, to reduce the possibility of the object being used outside of its lifetime, the underlying storage is a separate variable from the live object. -

    - - #include <cstdlib> +

    In this compliant solution, the constructor and destructor are both explicitly called. Further, to reduce the possibility of the object being used outside of its lifetime, the underlying storage is a separate variable from the live object.

    + #include <cstdlib> #include <new> struct S { @@ -206,34 +47,14 @@ void g() { S *s = new (ptr) S; s->f(); -  + s->~S(); std::free(ptr); -} - +}
    -

    - In this noncompliant code example, a custom container class uses an allocator object to obtain storage for arbitrary element types. While the - - copy_elements() - - function is presumed to call copy constructors for elements being moved into the newly allocated storage, this example fails to explicitly call the default constructor for any additional elements being reserved. If such an element is accessed through the - - operator[]() - - function, it results in - - undefined behavior - - , depending on the type - - T - - . -

    - - #include <memory> +

    In this noncompliant code example, a custom container class uses an allocator object to obtain storage for arbitrary element types. While the copy_elements() function is presumed to call copy constructors for elements being moved into the newly allocated storage, this example fails to explicitly call the default constructor for any additional elements being reserved. If such an element is accessed through the operator[]() function, it results in undefined behavior, depending on the type T.

    + #include <memory> template <typename T, typename Alloc = std::allocator<T>> class Container { @@ -260,18 +81,11 @@ public: T &operator[](size_t idx) { return underlyingStorage[idx]; } const T &operator[](size_t idx) const { return underlyingStorage[idx]; } -}; - +};
    -

    - In this compliant solution, all elements are properly initialized by explicitly calling copy or default constructors for - - T. - -

    - - #include <memory> +

    In this compliant solution, all elements are properly initialized by explicitly calling copy or default constructors for T.

    + #include <memory> template <typename T, typename Alloc = std::allocator<T>> class Container { @@ -301,45 +115,13 @@ public: T &operator[](size_t idx) { return underlyingStorage[idx]; } const T &operator[](size_t idx) const { return underlyingStorage[idx]; } -}; - +};
    -

    - - MEM53-CPP-EX1: - - If the object is trivially constructable, it need not have its constructor explicitly called to initiate the object's lifetime. If the object is trivially destructible, it need not have its destructor explicitly called to terminate the object's lifetime. These properties can be tested by calling - - std::is_trivially_constructible() - - and - - std::is_trivially_destructible() - - from - - <type_traits> - - . For instance, integral types such as - - int - - and - - long long - - do not require an explicit constructor or destructor call. -

    +

    MEM53-CPP-EX1: If the object is trivially constructable, it need not have its constructor explicitly called to initiate the object's lifetime. If the object is trivially destructible, it need not have its destructor explicitly called to terminate the object's lifetime. These properties can be tested by calling std::is_trivially_constructible() and std::is_trivially_destructible() from <type_traits>. For instance, integral types such as int and long long do not require an explicit constructor or destructor call.

    -

    - Failing to properly construct or destroy an object leaves its internal state inconsistent, which can result in - - undefined behavior - - and accidental information exposure. -

    +

    Failing to properly construct or destroy an object leaves its internal state inconsistent, which can result in undefined behavior and accidental information exposure.

    @@ -376,14 +158,10 @@ public: Medium @@ -416,9 +194,7 @@ public: 2021.2 @@ -433,9 +209,7 @@ public: 2021.2 @@ -468,17 +234,7 @@ public:
    - - P18 - + P18 - - L1 - + L1
    - - C++4761, C++4762, C++4766, C++4767 - + C++4761, C++4762, C++4766, C++4767 - - CERT_CPP-MEM53-a - + CERT_CPP-MEM53-a Do not invoke malloc/realloc for objects having constructors @@ -448,18 +222,10 @@ public: - 7.16 + 7.17 - - - V630 - - , - - V749 - - + V630, V749
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/MEM54-CPP/PlacementNewInsufficientStorageCert-standard.qhelp b/cpp/cert/src/rules/MEM54-CPP/PlacementNewInsufficientStorageCert-standard.qhelp index 9b78a32e1d..68b77fb174 100644 --- a/cpp/cert/src/rules/MEM54-CPP/PlacementNewInsufficientStorageCert-standard.qhelp +++ b/cpp/cert/src/rules/MEM54-CPP/PlacementNewInsufficientStorageCert-standard.qhelp @@ -1,160 +1,31 @@
    -

    - When invoked by a - - new - - expression for a given type, the default global non-placement forms of - - operator new - - attempt to allocate sufficient storage for an object of the type and, if successful, return a pointer with alignment suitable for any object with a fundamental alignment requirement. However, the default placement - - new - - operator simply returns the given pointer back to the caller without guaranteeing that there is sufficient space in which to construct the object or ensuring that the pointer meets the proper alignment requirements. The C++ Standard, [expr.new], paragraph 16 [ - - ISO/IEC 14882-2014 - - ], nonnormatively states the following: -

    +

    When invoked by a new expression for a given type, the default global non-placement forms of operator new attempt to allocate sufficient storage for an object of the type and, if successful, return a pointer with alignment suitable for any object with a fundamental alignment requirement. However, the default placement new operator simply returns the given pointer back to the caller without guaranteeing that there is sufficient space in which to construct the object or ensuring that the pointer meets the proper alignment requirements. The C++ Standard, [expr.new], paragraph 16 [ISO/IEC 14882-2014], nonnormatively states the following:

    -

    - [Note: when the allocation function returns a value other than null, it must be a pointer to a block of storage in which space for the object has been reserved. The block of storage is assumed to be appropriately aligned and of the requested size. The address of the created object will not necessarily be the same as that of the block if the object is an array. —end note] -

    +

    [Note: when the allocation function returns a value other than null, it must be a pointer to a block of storage in which space for the object has been reserved. The block of storage is assumed to be appropriately aligned and of the requested size. The address of the created object will not necessarily be the same as that of the block if the object is an array. —end note]

    -

    - (This note is a reminder of the general requirements specified by the C++ Standard, [basic.stc.dynamic.allocation], paragraph 1, which apply to placement - - new - - operators by virtue of [basic.stc.dynamic], paragraph 3.) -

    -

    - In addition, the standard provides the following example later in the same section: -

    +

    (This note is a reminder of the general requirements specified by the C++ Standard, [basic.stc.dynamic.allocation], paragraph 1, which apply to placement new operators by virtue of [basic.stc.dynamic], paragraph 3.)

    +

    In addition, the standard provides the following example later in the same section:

    -

    - - new(2, f) T[5] - - results in a call - - of operator new[](sizeof(T) * 5 + y, 2, f). - -

    -

    - Here, - - ... - - and - - y - - are non-negative unspecified values representing array allocation overhead; the result of the new-expression will be offset by this amount from the value returned by - - operator new[] - - . This overhead may be applied in all array - - new-expressions - - , including those referencing the library function - - operator new[](std::size_t, void*) - - and other placement allocation functions. The amount of overhead may vary from one invocation of new to another. -

    +

    new(2, f) T[5] results in a call of operator new[](sizeof(T) * 5 + y, 2, f).

    +

    Here, ... and y are non-negative unspecified values representing array allocation overhead; the result of the new-expression will be offset by this amount from the value returned by operator new[]. This overhead may be applied in all array new-expressions, including those referencing the library function operator new[](std::size_t, void*) and other placement allocation functions. The amount of overhead may vary from one invocation of new to another.

    -

    - Do not pass a pointer that is not suitably aligned for the object being constructed to placement - - new - - . Doing so results in an object being constructed at a misaligned location, which results in - - undefined behavior - - . Do not pass a pointer that has insufficient storage capacity for the object being constructed, including the overhead required for arrays. Doing so may result in initialization of memory outside of the bounds of the object being constructed, which results in undefined behavior. -

    -

    - Finally, do not use placement - - new[] - - on any platform that does not specify a limit for the overhead it requires. -

    +

    Do not pass a pointer that is not suitably aligned for the object being constructed to placement new. Doing so results in an object being constructed at a misaligned location, which results in undefined behavior. Do not pass a pointer that has insufficient storage capacity for the object being constructed, including the overhead required for arrays. Doing so may result in initialization of memory outside of the bounds of the object being constructed, which results in undefined behavior.

    +

    Finally, do not use placement new[] on any platform that does not specify a limit for the overhead it requires.

    -

    - In this noncompliant code example, a pointer to a - - short - - is passed to placement - - new - - , which is attempting to initialize a - - long - - . On architectures where - - sizeof(short) < sizeof(long) - - , this results in - - undefined behavior - - . This example, and subsequent ones, all assume the pointer returned by placement - - new - - will not be used after the lifetime of its underlying storage has ended. For instance, the pointer will not be stored in a - - static - - global variable and dereferenced after the call to - - f() - - has ended. This assumption is in conformance with - - MEM50-CPP. Do not access freed memory - - . -

    - - #include <new> -  +

    In this noncompliant code example, a pointer to a short is passed to placement new, which is attempting to initialize a long. On architectures where sizeof(short) < sizeof(long), this results in undefined behavior. This example, and subsequent ones, all assume the pointer returned by placement new will not be used after the lifetime of its underlying storage has ended. For instance, the pointer will not be stored in a static global variable and dereferenced after the call to f() has ended. This assumption is in conformance with MEM50-CPP. Do not access freed memory.

    + #include <new> + void f() { short s; long *lp = ::new (&s) long; -} - +}
    -

    - This noncompliant code example ensures that the - - long - - is constructed into a buffer of sufficient size. However, it does not ensure that the alignment requirements are met for the pointer passed into placement - - new - - . To make this example clearer, an additional local variable - - c - - has also been declared. -

    - - #include <new> +

    This noncompliant code example ensures that the long is constructed into a buffer of sufficient size. However, it does not ensure that the alignment requirements are met for the pointer passed into placement new. To make this example clearer, an additional local variable c has also been declared.

    + #include <new> void f() { char c; // Used elsewhere in the function @@ -162,62 +33,35 @@ void f() { long *lp = ::new (buffer) long; // ... -} - +}
    -

    - In this compliant solution, the - - alignas - - declaration specifier is used to ensure the buffer is appropriately aligned for a - - long. - -

    - - #include <new> -  +

    In this compliant solution, the alignas declaration specifier is used to ensure the buffer is appropriately aligned for a long.

    + #include <new> + void f() { char c; // Used elsewhere in the function alignas(long) unsigned char buffer[sizeof(long)]; long *lp = ::new (buffer) long; -  + // ... -} - +}
    -

    - This compliant solution ensures that the - - long - - is constructed into a buffer of sufficient size and with suitable alignment. -

    - - #include <new> -  +

    This compliant solution ensures that the long is constructed into a buffer of sufficient size and with suitable alignment.

    + #include <new> + void f() { char c; // Used elsewhere in the function std::aligned_storage<sizeof(long), alignof(long)>::type buffer; long *lp = ::new (&buffer) long; -  + // ... -} - +}
    -

    - This noncompliant code example attempts to allocate sufficient storage of the appropriate alignment for the array of objects of - - S - - .  However, it fails to account for the overhead an implementation may add to the amount of storage for array objects.  The overhead (commonly referred to as a cookie) is necessary to store the number of elements in the array so that the array delete expression or the exception unwinding mechanism can invoke the type's destructor on each successfully constructed element of the array.  While some implementations are able to avoid allocating space for the cookie in some situations, assuming they do in all cases is unsafe. -

    - - #include <new> +

    This noncompliant code example attempts to allocate sufficient storage of the appropriate alignment for the array of objects of S. However, it fails to account for the overhead an implementation may add to the amount of storage for array objects. The overhead (commonly referred to as a cookie) is necessary to store the number of elements in the array so that the array delete expression or the exception unwinding mechanism can invoke the type's destructor on each successfully constructed element of the array. While some implementations are able to avoid allocating space for the cookie in some situations, assuming they do in all cases is unsafe.

    + #include <new> struct S { S (); @@ -234,31 +78,11 @@ void f() { for (size_t i = 0; i != n; ++i) { sp[i].~S(); } -} - +}
    -

    - The amount of overhead required by array new expressions is unspecified but ideally would be documented by quality implementations. The following compliant solution is specifically for the - - Clang - - and GNU - - GCC - - compilers, which guarantee that the overhead for dynamic array allocations is a single value of type - - size_t - - . (Note that this value is often treated as a "-1th" element in the array, so the actual space used may be larger.) To verify that the assumption is, in fact, safe, the compliant solution also overloads the placement - - new[] - - operator to accept the buffer size as a third argument and verifies that it is not smaller than the total amount of storage required. -

    - - #include <cstddef> +

    The amount of overhead required by array new expressions is unspecified but ideally would be documented by quality implementations. The following compliant solution is specifically for the Clang and GNU GCC compilers, which guarantee that the overhead for dynamic array allocations is a single value of type size_t. (Note that this value is often treated as a "-1th" element in the array, so the actual space used may be larger.) To verify that the assumption is, in fact, safe, the compliant solution also overloads the placement new[] operator to accept the buffer size as a third argument and verifies that it is not smaller than the total amount of storage required.

    + #include <cstddef> #include <new> #if defined(__clang__) || defined(__GNUG__) @@ -290,28 +114,11 @@ void f() { for (size_t i = 0; i != n; ++i) { sp[i].~S(); } -} - -

    - Porting this compliant solution to other implementations requires adding similar conditional definitions of the overhead constant, depending on the constraints of the platform. -

    +}
    +

    Porting this compliant solution to other implementations requires adding similar conditional definitions of the overhead constant, depending on the constraints of the platform.

    -

    - Passing improperly aligned pointers or pointers to insufficient storage to placement - - new - - expressions can result in - - undefined behavior - - , including buffer overflow and - - abnormal termination - - . -

    +

    Passing improperly aligned pointers or pointers to insufficient storage to placement new expressions can result in undefined behavior, including buffer overflow and abnormal termination.

    @@ -348,14 +155,10 @@ void f() { Medium @@ -388,9 +191,7 @@ void f() { 7.2.0 @@ -405,9 +206,7 @@ void f() { 2021.2 @@ -421,9 +220,7 @@ void f() { @@ -492,17 +281,7 @@ void f() {
    - - P18 - + P18 - - L1 - + L1
    - - CertC++-MEM54 - + CertC++-MEM54 - - C++3119, C++3128 - + C++3119, C++3128 - - 597 S - + 597 S Enhanced Enforcement @@ -439,12 +236,8 @@ void f() { 2021.2 - - CERT_CPP-MEM54-a - - - CERT_CPP-MEM54-b - + CERT_CPP-MEM54-a + CERT_CPP-MEM54-b Do not pass a pointer that has insufficient storage capacity or that is not suitably aligned for the object being constructed to placement 'new' @@ -476,14 +269,10 @@ void f() { - 7.16 + 7.17 - - - V752 - - + V752
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/MEM54-CPP/PlacementNewNotProperlyAlignedCert-standard.qhelp b/cpp/cert/src/rules/MEM54-CPP/PlacementNewNotProperlyAlignedCert-standard.qhelp index 9b78a32e1d..68b77fb174 100644 --- a/cpp/cert/src/rules/MEM54-CPP/PlacementNewNotProperlyAlignedCert-standard.qhelp +++ b/cpp/cert/src/rules/MEM54-CPP/PlacementNewNotProperlyAlignedCert-standard.qhelp @@ -1,160 +1,31 @@
    -

    - When invoked by a - - new - - expression for a given type, the default global non-placement forms of - - operator new - - attempt to allocate sufficient storage for an object of the type and, if successful, return a pointer with alignment suitable for any object with a fundamental alignment requirement. However, the default placement - - new - - operator simply returns the given pointer back to the caller without guaranteeing that there is sufficient space in which to construct the object or ensuring that the pointer meets the proper alignment requirements. The C++ Standard, [expr.new], paragraph 16 [ - - ISO/IEC 14882-2014 - - ], nonnormatively states the following: -

    +

    When invoked by a new expression for a given type, the default global non-placement forms of operator new attempt to allocate sufficient storage for an object of the type and, if successful, return a pointer with alignment suitable for any object with a fundamental alignment requirement. However, the default placement new operator simply returns the given pointer back to the caller without guaranteeing that there is sufficient space in which to construct the object or ensuring that the pointer meets the proper alignment requirements. The C++ Standard, [expr.new], paragraph 16 [ISO/IEC 14882-2014], nonnormatively states the following:

    -

    - [Note: when the allocation function returns a value other than null, it must be a pointer to a block of storage in which space for the object has been reserved. The block of storage is assumed to be appropriately aligned and of the requested size. The address of the created object will not necessarily be the same as that of the block if the object is an array. —end note] -

    +

    [Note: when the allocation function returns a value other than null, it must be a pointer to a block of storage in which space for the object has been reserved. The block of storage is assumed to be appropriately aligned and of the requested size. The address of the created object will not necessarily be the same as that of the block if the object is an array. —end note]

    -

    - (This note is a reminder of the general requirements specified by the C++ Standard, [basic.stc.dynamic.allocation], paragraph 1, which apply to placement - - new - - operators by virtue of [basic.stc.dynamic], paragraph 3.) -

    -

    - In addition, the standard provides the following example later in the same section: -

    +

    (This note is a reminder of the general requirements specified by the C++ Standard, [basic.stc.dynamic.allocation], paragraph 1, which apply to placement new operators by virtue of [basic.stc.dynamic], paragraph 3.)

    +

    In addition, the standard provides the following example later in the same section:

    -

    - - new(2, f) T[5] - - results in a call - - of operator new[](sizeof(T) * 5 + y, 2, f). - -

    -

    - Here, - - ... - - and - - y - - are non-negative unspecified values representing array allocation overhead; the result of the new-expression will be offset by this amount from the value returned by - - operator new[] - - . This overhead may be applied in all array - - new-expressions - - , including those referencing the library function - - operator new[](std::size_t, void*) - - and other placement allocation functions. The amount of overhead may vary from one invocation of new to another. -

    +

    new(2, f) T[5] results in a call of operator new[](sizeof(T) * 5 + y, 2, f).

    +

    Here, ... and y are non-negative unspecified values representing array allocation overhead; the result of the new-expression will be offset by this amount from the value returned by operator new[]. This overhead may be applied in all array new-expressions, including those referencing the library function operator new[](std::size_t, void*) and other placement allocation functions. The amount of overhead may vary from one invocation of new to another.

    -

    - Do not pass a pointer that is not suitably aligned for the object being constructed to placement - - new - - . Doing so results in an object being constructed at a misaligned location, which results in - - undefined behavior - - . Do not pass a pointer that has insufficient storage capacity for the object being constructed, including the overhead required for arrays. Doing so may result in initialization of memory outside of the bounds of the object being constructed, which results in undefined behavior. -

    -

    - Finally, do not use placement - - new[] - - on any platform that does not specify a limit for the overhead it requires. -

    +

    Do not pass a pointer that is not suitably aligned for the object being constructed to placement new. Doing so results in an object being constructed at a misaligned location, which results in undefined behavior. Do not pass a pointer that has insufficient storage capacity for the object being constructed, including the overhead required for arrays. Doing so may result in initialization of memory outside of the bounds of the object being constructed, which results in undefined behavior.

    +

    Finally, do not use placement new[] on any platform that does not specify a limit for the overhead it requires.

    -

    - In this noncompliant code example, a pointer to a - - short - - is passed to placement - - new - - , which is attempting to initialize a - - long - - . On architectures where - - sizeof(short) < sizeof(long) - - , this results in - - undefined behavior - - . This example, and subsequent ones, all assume the pointer returned by placement - - new - - will not be used after the lifetime of its underlying storage has ended. For instance, the pointer will not be stored in a - - static - - global variable and dereferenced after the call to - - f() - - has ended. This assumption is in conformance with - - MEM50-CPP. Do not access freed memory - - . -

    - - #include <new> -  +

    In this noncompliant code example, a pointer to a short is passed to placement new, which is attempting to initialize a long. On architectures where sizeof(short) < sizeof(long), this results in undefined behavior. This example, and subsequent ones, all assume the pointer returned by placement new will not be used after the lifetime of its underlying storage has ended. For instance, the pointer will not be stored in a static global variable and dereferenced after the call to f() has ended. This assumption is in conformance with MEM50-CPP. Do not access freed memory.

    + #include <new> + void f() { short s; long *lp = ::new (&s) long; -} - +}
    -

    - This noncompliant code example ensures that the - - long - - is constructed into a buffer of sufficient size. However, it does not ensure that the alignment requirements are met for the pointer passed into placement - - new - - . To make this example clearer, an additional local variable - - c - - has also been declared. -

    - - #include <new> +

    This noncompliant code example ensures that the long is constructed into a buffer of sufficient size. However, it does not ensure that the alignment requirements are met for the pointer passed into placement new. To make this example clearer, an additional local variable c has also been declared.

    + #include <new> void f() { char c; // Used elsewhere in the function @@ -162,62 +33,35 @@ void f() { long *lp = ::new (buffer) long; // ... -} - +}
    -

    - In this compliant solution, the - - alignas - - declaration specifier is used to ensure the buffer is appropriately aligned for a - - long. - -

    - - #include <new> -  +

    In this compliant solution, the alignas declaration specifier is used to ensure the buffer is appropriately aligned for a long.

    + #include <new> + void f() { char c; // Used elsewhere in the function alignas(long) unsigned char buffer[sizeof(long)]; long *lp = ::new (buffer) long; -  + // ... -} - +}
    -

    - This compliant solution ensures that the - - long - - is constructed into a buffer of sufficient size and with suitable alignment. -

    - - #include <new> -  +

    This compliant solution ensures that the long is constructed into a buffer of sufficient size and with suitable alignment.

    + #include <new> + void f() { char c; // Used elsewhere in the function std::aligned_storage<sizeof(long), alignof(long)>::type buffer; long *lp = ::new (&buffer) long; -  + // ... -} - +}
    -

    - This noncompliant code example attempts to allocate sufficient storage of the appropriate alignment for the array of objects of - - S - - .  However, it fails to account for the overhead an implementation may add to the amount of storage for array objects.  The overhead (commonly referred to as a cookie) is necessary to store the number of elements in the array so that the array delete expression or the exception unwinding mechanism can invoke the type's destructor on each successfully constructed element of the array.  While some implementations are able to avoid allocating space for the cookie in some situations, assuming they do in all cases is unsafe. -

    - - #include <new> +

    This noncompliant code example attempts to allocate sufficient storage of the appropriate alignment for the array of objects of S. However, it fails to account for the overhead an implementation may add to the amount of storage for array objects. The overhead (commonly referred to as a cookie) is necessary to store the number of elements in the array so that the array delete expression or the exception unwinding mechanism can invoke the type's destructor on each successfully constructed element of the array. While some implementations are able to avoid allocating space for the cookie in some situations, assuming they do in all cases is unsafe.

    + #include <new> struct S { S (); @@ -234,31 +78,11 @@ void f() { for (size_t i = 0; i != n; ++i) { sp[i].~S(); } -} - +}
    -

    - The amount of overhead required by array new expressions is unspecified but ideally would be documented by quality implementations. The following compliant solution is specifically for the - - Clang - - and GNU - - GCC - - compilers, which guarantee that the overhead for dynamic array allocations is a single value of type - - size_t - - . (Note that this value is often treated as a "-1th" element in the array, so the actual space used may be larger.) To verify that the assumption is, in fact, safe, the compliant solution also overloads the placement - - new[] - - operator to accept the buffer size as a third argument and verifies that it is not smaller than the total amount of storage required. -

    - - #include <cstddef> +

    The amount of overhead required by array new expressions is unspecified but ideally would be documented by quality implementations. The following compliant solution is specifically for the Clang and GNU GCC compilers, which guarantee that the overhead for dynamic array allocations is a single value of type size_t. (Note that this value is often treated as a "-1th" element in the array, so the actual space used may be larger.) To verify that the assumption is, in fact, safe, the compliant solution also overloads the placement new[] operator to accept the buffer size as a third argument and verifies that it is not smaller than the total amount of storage required.

    + #include <cstddef> #include <new> #if defined(__clang__) || defined(__GNUG__) @@ -290,28 +114,11 @@ void f() { for (size_t i = 0; i != n; ++i) { sp[i].~S(); } -} - -

    - Porting this compliant solution to other implementations requires adding similar conditional definitions of the overhead constant, depending on the constraints of the platform. -

    +}
    +

    Porting this compliant solution to other implementations requires adding similar conditional definitions of the overhead constant, depending on the constraints of the platform.

    -

    - Passing improperly aligned pointers or pointers to insufficient storage to placement - - new - - expressions can result in - - undefined behavior - - , including buffer overflow and - - abnormal termination - - . -

    +

    Passing improperly aligned pointers or pointers to insufficient storage to placement new expressions can result in undefined behavior, including buffer overflow and abnormal termination.

    @@ -348,14 +155,10 @@ void f() { Medium @@ -388,9 +191,7 @@ void f() { 7.2.0 @@ -405,9 +206,7 @@ void f() { 2021.2 @@ -421,9 +220,7 @@ void f() { @@ -492,17 +281,7 @@ void f() {
    - - P18 - + P18 - - L1 - + L1
    - - CertC++-MEM54 - + CertC++-MEM54 - - C++3119, C++3128 - + C++3119, C++3128 - - 597 S - + 597 S Enhanced Enforcement @@ -439,12 +236,8 @@ void f() { 2021.2 - - CERT_CPP-MEM54-a - - - CERT_CPP-MEM54-b - + CERT_CPP-MEM54-a + CERT_CPP-MEM54-b Do not pass a pointer that has insufficient storage capacity or that is not suitably aligned for the object being constructed to placement 'new' @@ -476,14 +269,10 @@ void f() { - 7.16 + 7.17 - - - V752 - - + V752
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/MEM55-CPP/OperatorDeleteMissingPartnerCert-standard.qhelp b/cpp/cert/src/rules/MEM55-CPP/OperatorDeleteMissingPartnerCert-standard.qhelp index e89f641058..005f1bb236 100644 --- a/cpp/cert/src/rules/MEM55-CPP/OperatorDeleteMissingPartnerCert-standard.qhelp +++ b/cpp/cert/src/rules/MEM55-CPP/OperatorDeleteMissingPartnerCert-standard.qhelp @@ -1,92 +1,32 @@
    -

    - Dynamic memory allocation and deallocation functions can be globally replaced by custom implementations, as specified by [replacement.functions], paragraph 2, of the C++ Standard [ - - ISO/IEC 14882-2014 - - ]. For instance, a user may profile the dynamic memory usage of an application and decide that the default allocator is not optimal for their usage pattern, and a different allocation strategy may be a marked improvement. However, the C++ Standard, [res.on.functions], paragraph 1, states the following: -

    +

    Dynamic memory allocation and deallocation functions can be globally replaced by custom implementations, as specified by [replacement.functions], paragraph 2, of the C++ Standard [ISO/IEC 14882-2014]. For instance, a user may profile the dynamic memory usage of an application and decide that the default allocator is not optimal for their usage pattern, and a different allocation strategy may be a marked improvement. However, the C++ Standard, [res.on.functions], paragraph 1, states the following:

    -

    - In certain cases (replacement functions, handler functions, operations on types used to instantiate standard library template components), the C++ standard library depends on components supplied by a C++ program. If these components do not meet their requirements, the Standard places no requirements on the implementation. -

    +

    In certain cases (replacement functions, handler functions, operations on types used to instantiate standard library template components), the C++ standard library depends on components supplied by a C++ program. If these components do not meet their requirements, the Standard places no requirements on the implementation.

    -

    - Paragraph 2 further, in part, states the following: -

    +

    Paragraph 2 further, in part, states the following:

    -

    - In particular, the effects are undefined in the following cases: - — for replacement functions, if the installed replacement function does not implement the semantics of the applicable - - Required behavior: - - paragraph. -

    +

    In particular, the effects are undefined in the following cases:— for replacement functions, if the installed replacement function does not implement the semantics of the applicable Required behavior: paragraph.

    -

    - A replacement for any of the dynamic memory allocation or deallocation functions must meet the semantic requirements specified by the appropriate - - Required behavior: - - clause of the replaced function. -

    +

    A replacement for any of the dynamic memory allocation or deallocation functions must meet the semantic requirements specified by the appropriate Required behavior: clause of the replaced function.

    -

    - In this noncompliant code example, the global - - operator new(std::size_t) - - function is replaced by a custom implementation. However, the custom implementation fails to honor the behavior required by the function it replaces, as per the C++ Standard, [new.delete.single], paragraph 3. Specifically, if the custom allocator fails to allocate the requested amount of memory, the replacement function returns a null pointer instead of throwing an exception of type - - std::bad_alloc - - . By returning a null pointer instead of throwing, functions relying on the required behavior of - - operator new(std::size_t) - - to throw on memory allocations may instead attempt to dereference a null pointer. See - - EXP34-C. Do not dereference null pointers - - for more information. -

    - - #include <new> +

    In this noncompliant code example, the global operator new(std::size_t) function is replaced by a custom implementation. However, the custom implementation fails to honor the behavior required by the function it replaces, as per the C++ Standard, [new.delete.single], paragraph 3. Specifically, if the custom allocator fails to allocate the requested amount of memory, the replacement function returns a null pointer instead of throwing an exception of type std::bad_alloc. By returning a null pointer instead of throwing, functions relying on the required behavior of operator new(std::size_t) to throw on memory allocations may instead attempt to dereference a null pointer. See EXP34-C. Do not dereference null pointers for more information.

    + #include <new> void *operator new(std::size_t size) { extern void *alloc_mem(std::size_t); // Implemented elsewhere; may return nullptr return alloc_mem(size); } -  + void operator delete(void *ptr) noexcept; // Defined elsewhere -void operator delete(void *ptr, std::size_t) noexcept; // Defined elsewhere - -

    - The declarations of the replacement - - operator delete() - - functions indicate that this noncompliant code example still complies with - - DCL54-CPP. Overload allocation and deallocation functions as a pair in the same scope - - . -

    +void operator delete(void *ptr, std::size_t) noexcept; // Defined elsewhere
    +

    The declarations of the replacement operator delete() functions indicate that this noncompliant code example still complies with DCL54-CPP. Overload allocation and deallocation functions as a pair in the same scope.

    -

    - This compliant solution implements the required behavior for the replaced global allocator function by properly throwing a - - std::bad_alloc - - exception when the allocation fails. -

    - - #include <new> +

    This compliant solution implements the required behavior for the replaced global allocator function by properly throwing a std::bad_alloc exception when the allocation fails.

    + #include <new> void *operator new(std::size_t size) { extern void *alloc_mem(std::size_t); // Implemented elsewhere; may return nullptr @@ -95,27 +35,12 @@ void *operator new(std::size_t size) { } throw std::bad_alloc(); } -  + void operator delete(void *ptr) noexcept; // Defined elsewhere -void operator delete(void *ptr, std::size_t) noexcept; // Defined elsewhere - +void operator delete(void *ptr, std::size_t) noexcept; // Defined elsewhere
    -

    - Failing to meet the stated requirements for a replaceable dynamic storage function leads to - - undefined behavior - - . The severity of risk depends heavily on the caller of the allocation functions, but in some situations, dereferencing a null pointer can lead to the execution of arbitrary code [ - - Jack 2007 - - , - - van Sprundel 2006 - - ]. The indicated severity is for this more severe case. -

    +

    Failing to meet the stated requirements for a replaceable dynamic storage function leads to undefined behavior. The severity of risk depends heavily on the caller of the allocation functions, but in some situations, dereferencing a null pointer can lead to the execution of arbitrary code [Jack 2007, van Sprundel 2006]. The indicated severity is for this more severe case.

    @@ -152,14 +77,10 @@ void operator delete(void *ptr, std::size_t) noexcept; // Defined elsewhere Medium @@ -192,9 +113,7 @@ void operator delete(void *ptr, std::size_t) noexcept; // Defined elsewhere 2021.2 @@ -209,16 +128,8 @@ void operator delete(void *ptr, std::size_t) noexcept; // Defined elsewhere 2021.4 @@ -233,9 +144,7 @@ void operator delete(void *ptr, std::size_t) noexcept; // Defined elsewhere 2021.2
    - - P18 - + P18 - - L1 - + L1
    - - C++4736, C++4737, C++4738, C++4739 - + C++4736, C++4737, C++4738, C++4739 - - - CERT.MEM.OVERRIDE.DELETE - - - - - CERT.MEM.OVERRIDE.NEW - - + CERT.MEM.OVERRIDE.DELETE + CERT.MEM.OVERRIDE.NEW - - CERT_CPP-MEM55-a - + CERT_CPP-MEM55-a The user defined 'new' operator should throw the 'std::bad_alloc' exception when the allocation fails @@ -263,17 +172,7 @@ void operator delete(void *ptr, std::size_t) noexcept; // Defined elsewhere
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/MEM55-CPP/ThrowingNoThrowOperatorNewDeleteCert-standard.qhelp b/cpp/cert/src/rules/MEM55-CPP/ThrowingNoThrowOperatorNewDeleteCert-standard.qhelp index e89f641058..005f1bb236 100644 --- a/cpp/cert/src/rules/MEM55-CPP/ThrowingNoThrowOperatorNewDeleteCert-standard.qhelp +++ b/cpp/cert/src/rules/MEM55-CPP/ThrowingNoThrowOperatorNewDeleteCert-standard.qhelp @@ -1,92 +1,32 @@
    -

    - Dynamic memory allocation and deallocation functions can be globally replaced by custom implementations, as specified by [replacement.functions], paragraph 2, of the C++ Standard [ - - ISO/IEC 14882-2014 - - ]. For instance, a user may profile the dynamic memory usage of an application and decide that the default allocator is not optimal for their usage pattern, and a different allocation strategy may be a marked improvement. However, the C++ Standard, [res.on.functions], paragraph 1, states the following: -

    +

    Dynamic memory allocation and deallocation functions can be globally replaced by custom implementations, as specified by [replacement.functions], paragraph 2, of the C++ Standard [ISO/IEC 14882-2014]. For instance, a user may profile the dynamic memory usage of an application and decide that the default allocator is not optimal for their usage pattern, and a different allocation strategy may be a marked improvement. However, the C++ Standard, [res.on.functions], paragraph 1, states the following:

    -

    - In certain cases (replacement functions, handler functions, operations on types used to instantiate standard library template components), the C++ standard library depends on components supplied by a C++ program. If these components do not meet their requirements, the Standard places no requirements on the implementation. -

    +

    In certain cases (replacement functions, handler functions, operations on types used to instantiate standard library template components), the C++ standard library depends on components supplied by a C++ program. If these components do not meet their requirements, the Standard places no requirements on the implementation.

    -

    - Paragraph 2 further, in part, states the following: -

    +

    Paragraph 2 further, in part, states the following:

    -

    - In particular, the effects are undefined in the following cases: - — for replacement functions, if the installed replacement function does not implement the semantics of the applicable - - Required behavior: - - paragraph. -

    +

    In particular, the effects are undefined in the following cases:— for replacement functions, if the installed replacement function does not implement the semantics of the applicable Required behavior: paragraph.

    -

    - A replacement for any of the dynamic memory allocation or deallocation functions must meet the semantic requirements specified by the appropriate - - Required behavior: - - clause of the replaced function. -

    +

    A replacement for any of the dynamic memory allocation or deallocation functions must meet the semantic requirements specified by the appropriate Required behavior: clause of the replaced function.

    -

    - In this noncompliant code example, the global - - operator new(std::size_t) - - function is replaced by a custom implementation. However, the custom implementation fails to honor the behavior required by the function it replaces, as per the C++ Standard, [new.delete.single], paragraph 3. Specifically, if the custom allocator fails to allocate the requested amount of memory, the replacement function returns a null pointer instead of throwing an exception of type - - std::bad_alloc - - . By returning a null pointer instead of throwing, functions relying on the required behavior of - - operator new(std::size_t) - - to throw on memory allocations may instead attempt to dereference a null pointer. See - - EXP34-C. Do not dereference null pointers - - for more information. -

    - - #include <new> +

    In this noncompliant code example, the global operator new(std::size_t) function is replaced by a custom implementation. However, the custom implementation fails to honor the behavior required by the function it replaces, as per the C++ Standard, [new.delete.single], paragraph 3. Specifically, if the custom allocator fails to allocate the requested amount of memory, the replacement function returns a null pointer instead of throwing an exception of type std::bad_alloc. By returning a null pointer instead of throwing, functions relying on the required behavior of operator new(std::size_t) to throw on memory allocations may instead attempt to dereference a null pointer. See EXP34-C. Do not dereference null pointers for more information.

    + #include <new> void *operator new(std::size_t size) { extern void *alloc_mem(std::size_t); // Implemented elsewhere; may return nullptr return alloc_mem(size); } -  + void operator delete(void *ptr) noexcept; // Defined elsewhere -void operator delete(void *ptr, std::size_t) noexcept; // Defined elsewhere - -

    - The declarations of the replacement - - operator delete() - - functions indicate that this noncompliant code example still complies with - - DCL54-CPP. Overload allocation and deallocation functions as a pair in the same scope - - . -

    +void operator delete(void *ptr, std::size_t) noexcept; // Defined elsewhere
    +

    The declarations of the replacement operator delete() functions indicate that this noncompliant code example still complies with DCL54-CPP. Overload allocation and deallocation functions as a pair in the same scope.

    -

    - This compliant solution implements the required behavior for the replaced global allocator function by properly throwing a - - std::bad_alloc - - exception when the allocation fails. -

    - - #include <new> +

    This compliant solution implements the required behavior for the replaced global allocator function by properly throwing a std::bad_alloc exception when the allocation fails.

    + #include <new> void *operator new(std::size_t size) { extern void *alloc_mem(std::size_t); // Implemented elsewhere; may return nullptr @@ -95,27 +35,12 @@ void *operator new(std::size_t size) { } throw std::bad_alloc(); } -  + void operator delete(void *ptr) noexcept; // Defined elsewhere -void operator delete(void *ptr, std::size_t) noexcept; // Defined elsewhere - +void operator delete(void *ptr, std::size_t) noexcept; // Defined elsewhere
    -

    - Failing to meet the stated requirements for a replaceable dynamic storage function leads to - - undefined behavior - - . The severity of risk depends heavily on the caller of the allocation functions, but in some situations, dereferencing a null pointer can lead to the execution of arbitrary code [ - - Jack 2007 - - , - - van Sprundel 2006 - - ]. The indicated severity is for this more severe case. -

    +

    Failing to meet the stated requirements for a replaceable dynamic storage function leads to undefined behavior. The severity of risk depends heavily on the caller of the allocation functions, but in some situations, dereferencing a null pointer can lead to the execution of arbitrary code [Jack 2007, van Sprundel 2006]. The indicated severity is for this more severe case.

    @@ -152,14 +77,10 @@ void operator delete(void *ptr, std::size_t) noexcept; // Defined elsewhere Medium @@ -192,9 +113,7 @@ void operator delete(void *ptr, std::size_t) noexcept; // Defined elsewhere 2021.2 @@ -209,16 +128,8 @@ void operator delete(void *ptr, std::size_t) noexcept; // Defined elsewhere 2021.4 @@ -233,9 +144,7 @@ void operator delete(void *ptr, std::size_t) noexcept; // Defined elsewhere 2021.2
    - - P18 - + P18 - - L1 - + L1
    - - C++4736, C++4737, C++4738, C++4739 - + C++4736, C++4737, C++4738, C++4739 - - - CERT.MEM.OVERRIDE.DELETE - - - - - CERT.MEM.OVERRIDE.NEW - - + CERT.MEM.OVERRIDE.DELETE + CERT.MEM.OVERRIDE.NEW - - CERT_CPP-MEM55-a - + CERT_CPP-MEM55-a The user defined 'new' operator should throw the 'std::bad_alloc' exception when the allocation fails @@ -263,17 +172,7 @@ void operator delete(void *ptr, std::size_t) noexcept; // Defined elsewhere
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewReturnsNullCert-standard.qhelp b/cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewReturnsNullCert-standard.qhelp index e89f641058..005f1bb236 100644 --- a/cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewReturnsNullCert-standard.qhelp +++ b/cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewReturnsNullCert-standard.qhelp @@ -1,92 +1,32 @@
    -

    - Dynamic memory allocation and deallocation functions can be globally replaced by custom implementations, as specified by [replacement.functions], paragraph 2, of the C++ Standard [ - - ISO/IEC 14882-2014 - - ]. For instance, a user may profile the dynamic memory usage of an application and decide that the default allocator is not optimal for their usage pattern, and a different allocation strategy may be a marked improvement. However, the C++ Standard, [res.on.functions], paragraph 1, states the following: -

    +

    Dynamic memory allocation and deallocation functions can be globally replaced by custom implementations, as specified by [replacement.functions], paragraph 2, of the C++ Standard [ISO/IEC 14882-2014]. For instance, a user may profile the dynamic memory usage of an application and decide that the default allocator is not optimal for their usage pattern, and a different allocation strategy may be a marked improvement. However, the C++ Standard, [res.on.functions], paragraph 1, states the following:

    -

    - In certain cases (replacement functions, handler functions, operations on types used to instantiate standard library template components), the C++ standard library depends on components supplied by a C++ program. If these components do not meet their requirements, the Standard places no requirements on the implementation. -

    +

    In certain cases (replacement functions, handler functions, operations on types used to instantiate standard library template components), the C++ standard library depends on components supplied by a C++ program. If these components do not meet their requirements, the Standard places no requirements on the implementation.

    -

    - Paragraph 2 further, in part, states the following: -

    +

    Paragraph 2 further, in part, states the following:

    -

    - In particular, the effects are undefined in the following cases: - — for replacement functions, if the installed replacement function does not implement the semantics of the applicable - - Required behavior: - - paragraph. -

    +

    In particular, the effects are undefined in the following cases:— for replacement functions, if the installed replacement function does not implement the semantics of the applicable Required behavior: paragraph.

    -

    - A replacement for any of the dynamic memory allocation or deallocation functions must meet the semantic requirements specified by the appropriate - - Required behavior: - - clause of the replaced function. -

    +

    A replacement for any of the dynamic memory allocation or deallocation functions must meet the semantic requirements specified by the appropriate Required behavior: clause of the replaced function.

    -

    - In this noncompliant code example, the global - - operator new(std::size_t) - - function is replaced by a custom implementation. However, the custom implementation fails to honor the behavior required by the function it replaces, as per the C++ Standard, [new.delete.single], paragraph 3. Specifically, if the custom allocator fails to allocate the requested amount of memory, the replacement function returns a null pointer instead of throwing an exception of type - - std::bad_alloc - - . By returning a null pointer instead of throwing, functions relying on the required behavior of - - operator new(std::size_t) - - to throw on memory allocations may instead attempt to dereference a null pointer. See - - EXP34-C. Do not dereference null pointers - - for more information. -

    - - #include <new> +

    In this noncompliant code example, the global operator new(std::size_t) function is replaced by a custom implementation. However, the custom implementation fails to honor the behavior required by the function it replaces, as per the C++ Standard, [new.delete.single], paragraph 3. Specifically, if the custom allocator fails to allocate the requested amount of memory, the replacement function returns a null pointer instead of throwing an exception of type std::bad_alloc. By returning a null pointer instead of throwing, functions relying on the required behavior of operator new(std::size_t) to throw on memory allocations may instead attempt to dereference a null pointer. See EXP34-C. Do not dereference null pointers for more information.

    + #include <new> void *operator new(std::size_t size) { extern void *alloc_mem(std::size_t); // Implemented elsewhere; may return nullptr return alloc_mem(size); } -  + void operator delete(void *ptr) noexcept; // Defined elsewhere -void operator delete(void *ptr, std::size_t) noexcept; // Defined elsewhere - -

    - The declarations of the replacement - - operator delete() - - functions indicate that this noncompliant code example still complies with - - DCL54-CPP. Overload allocation and deallocation functions as a pair in the same scope - - . -

    +void operator delete(void *ptr, std::size_t) noexcept; // Defined elsewhere
    +

    The declarations of the replacement operator delete() functions indicate that this noncompliant code example still complies with DCL54-CPP. Overload allocation and deallocation functions as a pair in the same scope.

    -

    - This compliant solution implements the required behavior for the replaced global allocator function by properly throwing a - - std::bad_alloc - - exception when the allocation fails. -

    - - #include <new> +

    This compliant solution implements the required behavior for the replaced global allocator function by properly throwing a std::bad_alloc exception when the allocation fails.

    + #include <new> void *operator new(std::size_t size) { extern void *alloc_mem(std::size_t); // Implemented elsewhere; may return nullptr @@ -95,27 +35,12 @@ void *operator new(std::size_t size) { } throw std::bad_alloc(); } -  + void operator delete(void *ptr) noexcept; // Defined elsewhere -void operator delete(void *ptr, std::size_t) noexcept; // Defined elsewhere - +void operator delete(void *ptr, std::size_t) noexcept; // Defined elsewhere
    -

    - Failing to meet the stated requirements for a replaceable dynamic storage function leads to - - undefined behavior - - . The severity of risk depends heavily on the caller of the allocation functions, but in some situations, dereferencing a null pointer can lead to the execution of arbitrary code [ - - Jack 2007 - - , - - van Sprundel 2006 - - ]. The indicated severity is for this more severe case. -

    +

    Failing to meet the stated requirements for a replaceable dynamic storage function leads to undefined behavior. The severity of risk depends heavily on the caller of the allocation functions, but in some situations, dereferencing a null pointer can lead to the execution of arbitrary code [Jack 2007, van Sprundel 2006]. The indicated severity is for this more severe case.

    @@ -152,14 +77,10 @@ void operator delete(void *ptr, std::size_t) noexcept; // Defined elsewhere Medium @@ -192,9 +113,7 @@ void operator delete(void *ptr, std::size_t) noexcept; // Defined elsewhere 2021.2 @@ -209,16 +128,8 @@ void operator delete(void *ptr, std::size_t) noexcept; // Defined elsewhere 2021.4 @@ -233,9 +144,7 @@ void operator delete(void *ptr, std::size_t) noexcept; // Defined elsewhere 2021.2
    - - P18 - + P18 - - L1 - + L1
    - - C++4736, C++4737, C++4738, C++4739 - + C++4736, C++4737, C++4738, C++4739 - - - CERT.MEM.OVERRIDE.DELETE - - - - - CERT.MEM.OVERRIDE.NEW - - + CERT.MEM.OVERRIDE.DELETE + CERT.MEM.OVERRIDE.NEW - - CERT_CPP-MEM55-a - + CERT_CPP-MEM55-a The user defined 'new' operator should throw the 'std::bad_alloc' exception when the allocation fails @@ -263,17 +172,7 @@ void operator delete(void *ptr, std::size_t) noexcept; // Defined elsewhere
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewReturnsNullCert.md b/cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewReturnsNullCert.md deleted file mode 100644 index 535a49f06d..0000000000 --- a/cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewReturnsNullCert.md +++ /dev/null @@ -1,81 +0,0 @@ -# MEM55-CPP: Replacement operator new returns null instead of throwing std:bad_alloc -This query implements the CERT-C++ rule MEM55-CPP: - -> Honor replacement dynamic storage management requirements - - -## Description -Dynamic memory allocation and deallocation functions can be globally replaced by custom implementations, as specified by \[replacement.functions\], paragraph 2, of the C++ Standard \[ [ ISO/IEC 14882-2014 ](https://wiki.sei.cmu.edu//confluence/display/cplusplus/AA.+Bibliography#AA.Bibliography-ISO/IEC14882-2014) \]. For instance, a user may profile the dynamic memory usage of an application and decide that the default allocator is not optimal for their usage pattern, and a different allocation strategy may be a marked improvement. However, the C++ Standard, \[res.on.functions\], paragraph 1, states the following: - -> In certain cases (replacement functions, handler functions, operations on types used to instantiate standard library template components), the C++ standard library depends on components supplied by a C++ program. If these components do not meet their requirements, the Standard places no requirements on the implementation. - -Paragraph 2 further, in part, states the following: - -> In particular, the effects are undefined in the following cases: — for replacement functions, if the installed replacement function does not implement the semantics of the applicable Required behavior: paragraph. - -A replacement for any of the dynamic memory allocation or deallocation functions must meet the semantic requirements specified by the appropriate Required behavior: clause of the replaced function. - - -## Noncompliant Code Example -In this noncompliant code example, the global ` operator new(std::size_t) ` function is replaced by a custom implementation. However, the custom implementation fails to honor the behavior required by the function it replaces, as per the C++ Standard, \[new.delete.single\], paragraph 3. Specifically, if the custom allocator fails to allocate the requested amount of memory, the replacement function returns a null pointer instead of throwing an exception of type ` std::bad_alloc ` . By returning a null pointer instead of throwing, functions relying on the required behavior of ` operator new(std::size_t) ` to throw on memory allocations may instead attempt to dereference a null pointer. See [ EXP34-C. Do not dereference null pointers ](https://wiki.sei.cmu.edu//confluence/display/c/EXP34-C.+Do+not+dereference+null+pointers) for more information. - -```cpp - - #include - -void *operator new(std::size_t size) { - extern void *alloc_mem(std::size_t); // Implemented elsewhere; may return nullptr - return alloc_mem(size); -} -  -void operator delete(void *ptr) noexcept; // Defined elsewhere -void operator delete(void *ptr, std::size_t) noexcept; // Defined elsewhere - -``` -The declarations of the replacement ` operator delete() ` functions indicate that this noncompliant code example still complies with [ DCL54-CPP. Overload allocation and deallocation functions as a pair in the same scope ](https://wiki.sei.cmu.edu//confluence/display/cplusplus/DCL54-CPP.+Overload+allocation+and+deallocation+functions+as+a+pair+in+the+same+scope) . - - -## Compliant Solution -This compliant solution implements the required behavior for the replaced global allocator function by properly throwing a ` std::bad_alloc ` exception when the allocation fails. - -```cpp - - #include - -void *operator new(std::size_t size) { - extern void *alloc_mem(std::size_t); // Implemented elsewhere; may return nullptr - if (void *ret = alloc_mem(size)) { - return ret; - } - throw std::bad_alloc(); -} -  -void operator delete(void *ptr) noexcept; // Defined elsewhere -void operator delete(void *ptr, std::size_t) noexcept; // Defined elsewhere - -``` - -## Risk Assessment -Failing to meet the stated requirements for a replaceable dynamic storage function leads to [ undefined behavior ](https://wiki.sei.cmu.edu//confluence/display/cplusplus/BB.+Definitions#BB.Definitions-undefinedbehavior) . The severity of risk depends heavily on the caller of the allocation functions, but in some situations, dereferencing a null pointer can lead to the execution of arbitrary code \[ [ Jack 2007 ](https://wiki.sei.cmu.edu//confluence/display/cplusplus/AA.+Bibliography#AA.Bibliography-Jack07) , [ van Sprundel 2006 ](https://wiki.sei.cmu.edu//confluence/display/cplusplus/AA.+Bibliography#AA.Bibliography-vanSprundel06) \]. The indicated severity is for this more severe case. - -
    Rule Severity Likelihood Remediation Cost Priority Level
    MEM55-CPP High Likely Medium P18 L1
    - -## Automated Detection -
    Tool Version Checker Description
    Helix QAC 2021.2 C++4736, C++4737, C++4738, C++4739
    Klocwork 2021.4 CERT.MEM.OVERRIDE.DELETE CERT.MEM.OVERRIDE.NEW
    Parasoft C/C++test 2021.2 CERT_CPP-MEM55-a The user defined 'new' operator should throw the 'std::bad_alloc' exception when the allocation fails
    Polyspace Bug Finder R2021b CERT C++: MEM55-CPP Checks for replacement allocation/deallocation functions that do not meet requirements of the Standard (rule fully covered)
    - -## Related Vulnerabilities -Search for [ vulnerabilities ](https://wiki.sei.cmu.edu//confluence/display/cplusplus/BB.+Definitions#BB.Definitions-vulnerability) resulting from the violation of this rule on the [ CERT website ](https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+MEM55-CPP) . - - -## Related Guidelines - SEI CERT C++ Coding Standard DCL54-CPP. Overload allocation and deallocation functions as a pair in the same scope OOP56-CPP. Honor replacement handler requirements SEI CERT C Coding Standard EXP34-C. Do not dereference null pointers - -## Bibliography - \[ ISO/IEC 14882-2014 \] Subclause 17.6.4.8, "Other Functions" Subclause 18.6.1, "Storage Allocation and Deallocation" \[ Jack 2007 \] \[ van Sprundel 2006 \] - -## Implementation notes -None - - -## References -* CERT-C++: [MEM55-CPP: Honor replacement dynamic storage management requirements](https://wiki.sei.cmu.edu/confluence/pages/viewpage.action?pageId=88046682) . diff --git a/cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewThrowsInvalidExceptionCert-standard.qhelp b/cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewThrowsInvalidExceptionCert-standard.qhelp index e89f641058..005f1bb236 100644 --- a/cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewThrowsInvalidExceptionCert-standard.qhelp +++ b/cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewThrowsInvalidExceptionCert-standard.qhelp @@ -1,92 +1,32 @@
    -

    - Dynamic memory allocation and deallocation functions can be globally replaced by custom implementations, as specified by [replacement.functions], paragraph 2, of the C++ Standard [ - - ISO/IEC 14882-2014 - - ]. For instance, a user may profile the dynamic memory usage of an application and decide that the default allocator is not optimal for their usage pattern, and a different allocation strategy may be a marked improvement. However, the C++ Standard, [res.on.functions], paragraph 1, states the following: -

    +

    Dynamic memory allocation and deallocation functions can be globally replaced by custom implementations, as specified by [replacement.functions], paragraph 2, of the C++ Standard [ISO/IEC 14882-2014]. For instance, a user may profile the dynamic memory usage of an application and decide that the default allocator is not optimal for their usage pattern, and a different allocation strategy may be a marked improvement. However, the C++ Standard, [res.on.functions], paragraph 1, states the following:

    -

    - In certain cases (replacement functions, handler functions, operations on types used to instantiate standard library template components), the C++ standard library depends on components supplied by a C++ program. If these components do not meet their requirements, the Standard places no requirements on the implementation. -

    +

    In certain cases (replacement functions, handler functions, operations on types used to instantiate standard library template components), the C++ standard library depends on components supplied by a C++ program. If these components do not meet their requirements, the Standard places no requirements on the implementation.

    -

    - Paragraph 2 further, in part, states the following: -

    +

    Paragraph 2 further, in part, states the following:

    -

    - In particular, the effects are undefined in the following cases: - — for replacement functions, if the installed replacement function does not implement the semantics of the applicable - - Required behavior: - - paragraph. -

    +

    In particular, the effects are undefined in the following cases:— for replacement functions, if the installed replacement function does not implement the semantics of the applicable Required behavior: paragraph.

    -

    - A replacement for any of the dynamic memory allocation or deallocation functions must meet the semantic requirements specified by the appropriate - - Required behavior: - - clause of the replaced function. -

    +

    A replacement for any of the dynamic memory allocation or deallocation functions must meet the semantic requirements specified by the appropriate Required behavior: clause of the replaced function.

    -

    - In this noncompliant code example, the global - - operator new(std::size_t) - - function is replaced by a custom implementation. However, the custom implementation fails to honor the behavior required by the function it replaces, as per the C++ Standard, [new.delete.single], paragraph 3. Specifically, if the custom allocator fails to allocate the requested amount of memory, the replacement function returns a null pointer instead of throwing an exception of type - - std::bad_alloc - - . By returning a null pointer instead of throwing, functions relying on the required behavior of - - operator new(std::size_t) - - to throw on memory allocations may instead attempt to dereference a null pointer. See - - EXP34-C. Do not dereference null pointers - - for more information. -

    - - #include <new> +

    In this noncompliant code example, the global operator new(std::size_t) function is replaced by a custom implementation. However, the custom implementation fails to honor the behavior required by the function it replaces, as per the C++ Standard, [new.delete.single], paragraph 3. Specifically, if the custom allocator fails to allocate the requested amount of memory, the replacement function returns a null pointer instead of throwing an exception of type std::bad_alloc. By returning a null pointer instead of throwing, functions relying on the required behavior of operator new(std::size_t) to throw on memory allocations may instead attempt to dereference a null pointer. See EXP34-C. Do not dereference null pointers for more information.

    + #include <new> void *operator new(std::size_t size) { extern void *alloc_mem(std::size_t); // Implemented elsewhere; may return nullptr return alloc_mem(size); } -  + void operator delete(void *ptr) noexcept; // Defined elsewhere -void operator delete(void *ptr, std::size_t) noexcept; // Defined elsewhere - -

    - The declarations of the replacement - - operator delete() - - functions indicate that this noncompliant code example still complies with - - DCL54-CPP. Overload allocation and deallocation functions as a pair in the same scope - - . -

    +void operator delete(void *ptr, std::size_t) noexcept; // Defined elsewhere
    +

    The declarations of the replacement operator delete() functions indicate that this noncompliant code example still complies with DCL54-CPP. Overload allocation and deallocation functions as a pair in the same scope.

    -

    - This compliant solution implements the required behavior for the replaced global allocator function by properly throwing a - - std::bad_alloc - - exception when the allocation fails. -

    - - #include <new> +

    This compliant solution implements the required behavior for the replaced global allocator function by properly throwing a std::bad_alloc exception when the allocation fails.

    + #include <new> void *operator new(std::size_t size) { extern void *alloc_mem(std::size_t); // Implemented elsewhere; may return nullptr @@ -95,27 +35,12 @@ void *operator new(std::size_t size) { } throw std::bad_alloc(); } -  + void operator delete(void *ptr) noexcept; // Defined elsewhere -void operator delete(void *ptr, std::size_t) noexcept; // Defined elsewhere - +void operator delete(void *ptr, std::size_t) noexcept; // Defined elsewhere
    -

    - Failing to meet the stated requirements for a replaceable dynamic storage function leads to - - undefined behavior - - . The severity of risk depends heavily on the caller of the allocation functions, but in some situations, dereferencing a null pointer can lead to the execution of arbitrary code [ - - Jack 2007 - - , - - van Sprundel 2006 - - ]. The indicated severity is for this more severe case. -

    +

    Failing to meet the stated requirements for a replaceable dynamic storage function leads to undefined behavior. The severity of risk depends heavily on the caller of the allocation functions, but in some situations, dereferencing a null pointer can lead to the execution of arbitrary code [Jack 2007, van Sprundel 2006]. The indicated severity is for this more severe case.

    @@ -152,14 +77,10 @@ void operator delete(void *ptr, std::size_t) noexcept; // Defined elsewhere Medium @@ -192,9 +113,7 @@ void operator delete(void *ptr, std::size_t) noexcept; // Defined elsewhere 2021.2 @@ -209,16 +128,8 @@ void operator delete(void *ptr, std::size_t) noexcept; // Defined elsewhere 2021.4 @@ -233,9 +144,7 @@ void operator delete(void *ptr, std::size_t) noexcept; // Defined elsewhere 2021.2
    - - P18 - + P18 - - L1 - + L1
    - - C++4736, C++4737, C++4738, C++4739 - + C++4736, C++4737, C++4738, C++4739 - - - CERT.MEM.OVERRIDE.DELETE - - - - - CERT.MEM.OVERRIDE.NEW - - + CERT.MEM.OVERRIDE.DELETE + CERT.MEM.OVERRIDE.NEW - - CERT_CPP-MEM55-a - + CERT_CPP-MEM55-a The user defined 'new' operator should throw the 'std::bad_alloc' exception when the allocation fails @@ -263,17 +172,7 @@ void operator delete(void *ptr, std::size_t) noexcept; // Defined elsewhere
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/MEM56-CPP/OwnedPointerValueStoredInUnrelatedSmartPointerCert-standard.qhelp b/cpp/cert/src/rules/MEM56-CPP/OwnedPointerValueStoredInUnrelatedSmartPointerCert-standard.qhelp index 391ce4228f..fd39239138 100644 --- a/cpp/cert/src/rules/MEM56-CPP/OwnedPointerValueStoredInUnrelatedSmartPointerCert-standard.qhelp +++ b/cpp/cert/src/rules/MEM56-CPP/OwnedPointerValueStoredInUnrelatedSmartPointerCert-standard.qhelp @@ -1,200 +1,33 @@
    -

    - Smart pointers such as - - std::unique_ptr - - and - - std::shared_ptr - - encode pointer ownership semantics as part of the type system. They wrap a pointer value, provide pointer-like semantics through - - operator *() - - and - - operator->() - - member functions, and control the lifetime of the pointer they manage. When a smart pointer is constructed from a pointer value, that value is said to be - - owned - - by the smart pointer. -

    -

    - Calling - - std::unique_ptr::release() - - will relinquish ownership of the managed pointer value. Destruction of, move assignment of, or calling - - std::unique_ptr::reset() - - on a - - std::unique_ptr - - object will also relinquish ownership of the managed pointer value, but results in destruction of the managed pointer value. If a call to - - std::shared_ptr::unique() - - returns true, then destruction of or calling - - std::shared_ptr::reset() - - on that - - std::shared_ptr - - object will relinquish ownership of the managed pointer value but results in destruction of the managed pointer value. -

    -

    - Some smart pointers, such as - - std::shared_ptr - - , allow multiple smart pointer objects to manage the same underlying pointer value. In such cases, the initial smart pointer object owns the pointer value, and subsequent smart pointer objects are related to the original smart pointer. Two smart pointers are - - related - - when the initial smart pointer is used in the initialization of the subsequent smart pointer objects. For instance, copying a - - std::shared_ptr - - object to another - - std::shared_ptr - - object via copy assignment creates a relationship between the two smart pointers, whereas creating a - - std::shared_ptr - - object from the managed pointer value of another - - std::shared_ptr - - object does not. -

    -

    - Do not create an unrelated smart pointer object with a pointer value that is owned by another smart pointer object. This includes resetting a smart pointer's managed pointer to an already-owned pointer value, such as by calling - - reset() - - . -

    +

    Smart pointers such as std::unique_ptr and std::shared_ptr encode pointer ownership semantics as part of the type system. They wrap a pointer value, provide pointer-like semantics through operator *() and operator->() member functions, and control the lifetime of the pointer they manage. When a smart pointer is constructed from a pointer value, that value is said to be owned by the smart pointer.

    +

    Calling std::unique_ptr::release() will relinquish ownership of the managed pointer value. Destruction of, move assignment of, or calling std::unique_ptr::reset() on a std::unique_ptr object will also relinquish ownership of the managed pointer value, but results in destruction of the managed pointer value. If a call to std::shared_ptr::unique() returns true, then destruction of or calling std::shared_ptr::reset() on that std::shared_ptr object will relinquish ownership of the managed pointer value but results in destruction of the managed pointer value.

    +

    Some smart pointers, such as std::shared_ptr, allow multiple smart pointer objects to manage the same underlying pointer value. In such cases, the initial smart pointer object owns the pointer value, and subsequent smart pointer objects are related to the original smart pointer. Two smart pointers are related when the initial smart pointer is used in the initialization of the subsequent smart pointer objects. For instance, copying a std::shared_ptr object to another std::shared_ptr object via copy assignment creates a relationship between the two smart pointers, whereas creating a std::shared_ptr object from the managed pointer value of another std::shared_ptr object does not.

    +

    Do not create an unrelated smart pointer object with a pointer value that is owned by another smart pointer object. This includes resetting a smart pointer's managed pointer to an already-owned pointer value, such as by calling reset().

    -

    - In this noncompliant code example, two unrelated smart pointers are constructed from the same underlying pointer value. When the local, automatic variable - - p2 - - is destroyed, it deletes the pointer value it manages. Then, when the local, automatic variable - - p1 - - is destroyed, it deletes the same pointer value, resulting in a double-free - - vulnerability - - . -

    - - #include <memory> +

    In this noncompliant code example, two unrelated smart pointers are constructed from the same underlying pointer value. When the local, automatic variable p2 is destroyed, it deletes the pointer value it manages. Then, when the local, automatic variable p1 is destroyed, it deletes the same pointer value, resulting in a double-free vulnerability.

    + #include <memory> void f() { int *i = new int; std::shared_ptr<int> p1(i); std::shared_ptr<int> p2(i); -} - +}
    -

    - In this compliant solution, the - - std::shared_ptr - - objects are related to one another through copy construction. When the local, automatic variable - - p2 - - is destroyed, the use count for the shared pointer value is decremented but still nonzero. Then, when the local, automatic variable - - p1 - - is destroyed, the use count for the shared pointer value is decremented to zero, and the managed pointer is destroyed. This compliant solution also calls - - std::make_shared - - () instead of allocating a raw pointer and storing its value in a local variable. -

    - - #include <memory> +

    In this compliant solution, the std::shared_ptr objects are related to one another through copy construction. When the local, automatic variable p2 is destroyed, the use count for the shared pointer value is decremented but still nonzero. Then, when the local, automatic variable p1 is destroyed, the use count for the shared pointer value is decremented to zero, and the managed pointer is destroyed. This compliant solution also calls std::make_shared() instead of allocating a raw pointer and storing its value in a local variable.

    + #include <memory> void f() { std::shared_ptr<int> p1 = std::make_shared<int>(); std::shared_ptr<int> p2(p1); -} - +}
    -

    - In this noncompliant code example, the - - poly - - pointer value owned by a - - std::shared_ptr - - object is cast to the - - D * - - pointer type with - - dynamic_cast - - in an attempt to obtain a - - std::shared_ptr - - of the polymorphic derived type. However, this eventually results in - - undefined behavior - - as the same pointer is thereby stored in two different - - std::shared_ptr - - objects. When - - g() - - exits, the pointer stored in - - derived - - is freed by the default deleter. Any further use of - - poly - - results in accessing freed memory. When - - f() - - exits, the same pointer stored in - - poly - - is destroyed, resulting in a double-free vulnerability. -

    - - #include <memory> +

    In this noncompliant code example, the poly pointer value owned by a std::shared_ptr object is cast to the D * pointer type with dynamic_cast in an attempt to obtain a std::shared_ptr of the polymorphic derived type. However, this eventually results in undefined behavior as the same pointer is thereby stored in two different std::shared_ptr objects. When g() exits, the pointer stored in derived is freed by the default deleter. Any further use of poly results in accessing freed memory. When f() exits, the same pointer stored in poly is destroyed, resulting in a double-free vulnerability.

    + #include <memory> struct B { virtual ~B() = default; // Polymorphic object @@ -209,47 +42,11 @@ void f() { // ... g(std::shared_ptr<D>(dynamic_cast<D *>(poly.get()))); // Any use of poly will now result in accessing freed memory. -} - +}
    -

    - In this compliant solution, the - - dynamic_cast - - is replaced with a call to - - std::dynamic_pointer_cast() - - , which returns a - - std::shared_ptr - - of the polymorphic type with the valid shared pointer value. When - - g() - - exits, the reference count to the underlying pointer is decremented by the destruction of - - derived - - , but because of the reference held by - - poly - - (within - - f() - - ), the stored pointer value is still valid after - - g() - - returns. -

    - - #include <memory> +

    In this compliant solution, the dynamic_cast is replaced with a call to std::dynamic_pointer_cast(), which returns a std::shared_ptr of the polymorphic type with the valid shared pointer value. When g() exits, the reference count to the underlying pointer is decremented by the destruction of derived, but because of the reference held by poly (within f()), the stored pointer value is still valid after g() returns.

    + #include <memory> struct B { virtual ~B() = default; // Polymorphic object @@ -264,55 +61,11 @@ void f() { // ... g(std::dynamic_pointer_cast<D, B>(poly)); // poly is still referring to a valid pointer value. -} - +}
    -

    - In this noncompliant code example, a - - std::shared_ptr - - of type - - S - - is constructed and stored in - - s1 - - . Later, - - S::g() - - is called to get another shared pointer to the pointer value managed by - - s1 - - . However, the smart pointer returned by - - S::g() - - is not related to the smart pointer stored in - - s1 - - . When - - s2 - - is destroyed, it will free the pointer managed by - - s1 - - , causing a double-free vulnerability when - - s1 - - is destroyed. -

    - - #include <memory> +

    In this noncompliant code example, a std::shared_ptr of type S is constructed and stored in s1. Later, S::g() is called to get another shared pointer to the pointer value managed by s1. However, the smart pointer returned by S::g() is not related to the smart pointer stored in s1. When s2 is destroyed, it will free the pointer managed by s1, causing a double-free vulnerability when s1 is destroyed.

    + #include <memory> struct S { std::shared_ptr<S> g() { return std::shared_ptr<S>(this); } @@ -322,55 +75,11 @@ void f() { std::shared_ptr<S> s1 = std::make_shared<S>(); // ... std::shared_ptr<S> s2 = s1->g(); -} - +}
    -

    - The compliant solution is to use - - std::enable_shared_from_this::shared_from_this() - - to get a shared pointer from - - S - - that is related to an existing - - std::shared_ptr - - object. A common implementation strategy is for the - - std::shared_ptr - - constructors to detect the presence of a pointer that inherits from - - std::enable_shared_from_this - - , and automatically update the internal bookkeeping required for - - std::enable_shared_from_this::shared_from_this() - - to work. Note that - - std::enable_shared_from_this::shared_from_this() - - requires an existing - - std::shared_ptr - - instance that manages the pointer value pointed to by - - this - - . Failure to meet this requirement results in - - undefined behavior - - , as it would result in a smart pointer attempting to manage the lifetime of an object that itself does not have lifetime management semantics. -

    - - #include <memory> +

    The compliant solution is to use std::enable_shared_from_this::shared_from_this() to get a shared pointer from S that is related to an existing std::shared_ptr object. A common implementation strategy is for the std::shared_ptr constructors to detect the presence of a pointer that inherits from std::enable_shared_from_this, and automatically update the internal bookkeeping required for std::enable_shared_from_this::shared_from_this() to work. Note that std::enable_shared_from_this::shared_from_this() requires an existing std::shared_ptr instance that manages the pointer value pointed to by this. Failure to meet this requirement results in undefined behavior, as it would result in a smart pointer attempting to manage the lifetime of an object that itself does not have lifetime management semantics.

    + #include <memory> struct S : std::enable_shared_from_this<S> { std::shared_ptr<S> g() { return shared_from_this(); } @@ -379,21 +88,10 @@ struct S : std::enable_shared_from_this<S> { void f() { std::shared_ptr<S> s1 = std::make_shared<S>(); std::shared_ptr<S> s2 = s1->g(); -} - +}
    -

    - Passing a pointer value to a deallocation function that was not previously obtained by the matching allocation function results in - - undefined behavior - - , which can lead to exploitable - - vulnerabilities - - . -

    +

    Passing a pointer value to a deallocation function that was not previously obtained by the matching allocation function results in undefined behavior, which can lead to exploitable vulnerabilities.

    @@ -430,14 +128,10 @@ void f() { Medium @@ -470,9 +164,7 @@ void f() { 20.10 @@ -487,9 +179,7 @@ void f() { 7.2.0 @@ -504,9 +194,7 @@ void f() { 2021.2 @@ -521,9 +209,7 @@ void f() { 2021.2 @@ -570,17 +252,7 @@ void f() {
    - - P18 - + P18 - - L1 - + L1
    - - dangling_pointer_use - + dangling_pointer_use - - CertC++-MEM56 - + CertC++-MEM56 - - C++4721, C++4722, C++4723 - + C++4721, C++4722, C++4723 - - CERT_CPP-MEM56-a - + CERT_CPP-MEM56-a Do not store an already-owned pointer value in an unrelated smart pointer @@ -554,14 +240,10 @@ void f() { - 7.16 + 7.17 - - - V1006 - - + V1006
    -

    - Search for other - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for other vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/MEM57-CPP/UsingDefaultOperatorNewForOverAlignedTypes-standard.qhelp b/cpp/cert/src/rules/MEM57-CPP/UsingDefaultOperatorNewForOverAlignedTypes-standard.qhelp index e878a67751..a3af8293ff 100644 --- a/cpp/cert/src/rules/MEM57-CPP/UsingDefaultOperatorNewForOverAlignedTypes-standard.qhelp +++ b/cpp/cert/src/rules/MEM57-CPP/UsingDefaultOperatorNewForOverAlignedTypes-standard.qhelp @@ -1,121 +1,24 @@
    -

    - The non-placement - - new - - expression is specified to invoke an allocation function to allocate storage for an object of the specified type. When successful, the allocation function, in turn, is required to return a pointer to storage with alignment suitable for any object with a fundamental alignment requirement. Although the global - - operator new - - , the default allocation function invoked by the new expression, is specified by the C++ standard [ - - ISO/IEC 14882-2014 - - ] to allocate sufficient storage suitably aligned to represent any object of the specified size, since the expected alignment isn't part of the function's interface, the most a program can safely assume is that the storage allocated by the default - - operator new - - defined by the implementation is aligned for an object with a fundamental alignment. In particular, it is unsafe to use the storage for an object of a type with a stricter alignment requirement—an - - over-aligned type - - . -

    -

    - Furthermore, the array form of the non-placement - - new - - expression may increase the amount of storage it attempts to obtain by invoking the corresponding allocation function by an unspecified amount. This amount, referred to as overhead in the C++ standard, is commonly known as a - - cookie - - . The cookie is used to store the number of elements in the array so that the array delete expression or the exception unwinding mechanism can invoke the type's destructor on each successfully constructed element of the array. While the specific conditions under which the cookie is required by the array new expression aren't described in the C++ standard, they may be outlined in other specifications such as the - - application binary interface - - (ABI) document for the target environment. For example, the Itanium C++ ABI describes the rules for computing the size of a cookie, its location, and achieving the correct alignment of the array elements. When these rules require that a cookie be created, it is possible to obtain a suitably aligned array of elements of an overaligned type [ - - CodeSourcery 2016a - - ]. However, the rules are complex and the Itanium C++ ABI isn't universally applicable. -

    -

    - Avoid relying on the default - - operator new - - to obtain storage for objects of over-aligned types. Doing so may result in an object being constructed at a misaligned location, which has - - undefined behavior - - and can result in - - abnormal termination - - when the object is accessed, even on architectures otherwise known to tolerate misaligned accesses. -

    +

    The non-placement new expression is specified to invoke an allocation function to allocate storage for an object of the specified type. When successful, the allocation function, in turn, is required to return a pointer to storage with alignment suitable for any object with a fundamental alignment requirement. Although the global operator new, the default allocation function invoked by the new expression, is specified by the C++ standard [ISO/IEC 14882-2014] to allocate sufficient storage suitably aligned to represent any object of the specified size, since the expected alignment isn't part of the function's interface, the most a program can safely assume is that the storage allocated by the default operator new defined by the implementation is aligned for an object with a fundamental alignment. In particular, it is unsafe to use the storage for an object of a type with a stricter alignment requirement—an over-aligned type.

    +

    Furthermore, the array form of the non-placement new expression may increase the amount of storage it attempts to obtain by invoking the corresponding allocation function by an unspecified amount. This amount, referred to as overhead in the C++ standard, is commonly known as a cookie. The cookie is used to store the number of elements in the array so that the array delete expression or the exception unwinding mechanism can invoke the type's destructor on each successfully constructed element of the array. While the specific conditions under which the cookie is required by the array new expression aren't described in the C++ standard, they may be outlined in other specifications such as the application binary interface (ABI) document for the target environment. For example, the Itanium C++ ABI describes the rules for computing the size of a cookie, its location, and achieving the correct alignment of the array elements. When these rules require that a cookie be created, it is possible to obtain a suitably aligned array of elements of an overaligned type [CodeSourcery 2016a]. However, the rules are complex and the Itanium C++ ABI isn't universally applicable.

    +

    Avoid relying on the default operator new to obtain storage for objects of over-aligned types. Doing so may result in an object being constructed at a misaligned location, which has undefined behavior and can result in abnormal termination when the object is accessed, even on architectures otherwise known to tolerate misaligned accesses.

    -

    - In the following noncompliant code example, the new expression is used to invoke the default - - operator new - - to obtain storage in which to then construct an object of the user-defined type - - Vector - - with alignment that exceeds the fundamental alignment of most implementations (typically 16 bytes). Objects of such over-aligned types are typically required by SIMD (single instruction, multiple data) vectorization instructions, which can trap when passed unsuitably aligned arguments. -

    - - struct alignas(32) Vector { +

    In the following noncompliant code example, the new expression is used to invoke the default operator new to obtain storage in which to then construct an object of the user-defined type Vector with alignment that exceeds the fundamental alignment of most implementations (typically 16 bytes). Objects of such over-aligned types are typically required by SIMD (single instruction, multiple data) vectorization instructions, which can trap when passed unsuitably aligned arguments.

    + struct alignas(32) Vector { char elems[32]; }; Vector *f() { Vector *pv = new Vector; return pv; -} - +}
    -

    - In this compliant solution, an overloaded - - operator new - - function is defined to obtain appropriately aligned storage by calling the C11 function - - aligned_alloc() - - . Programs that make use of the array form of the new expression must define the corresponding member array - - operator new[] - - and - - operator delete[] - - . The - - aligned_alloc() - - function is not part of the C++ 98, C++ 11, or C++ 14 standards but may be provided by implementations of such standards as an extension. Programs targeting C++ implementations that do not provide the C11 - - aligned_alloc() - - function must define the member - - operator new - - to adjust the alignment of the storage obtained by the allocation function of their choice. -

    - - #include <cstdlib> +

    In this compliant solution, an overloaded operator new function is defined to obtain appropriately aligned storage by calling the C11 function aligned_alloc(). Programs that make use of the array form of the new expression must define the corresponding member array operator new[] and operator delete[]. The aligned_alloc() function is not part of the C++ 98, C++ 11, or C++ 14 standards but may be provided by implementations of such standards as an extension. Programs targeting C++ implementations that do not provide the C11 aligned_alloc() function must define the member operator new to adjust the alignment of the storage obtained by the allocation function of their choice.

    + #include <cstdlib> #include <new> struct alignas(32) Vector { @@ -134,21 +37,10 @@ struct alignas(32) Vector { Vector *f() { Vector *pv = new Vector; return pv; -} - +}
    -

    - Using improperly aligned pointers results in - - undefined behavior - - , typically leading to - - abnormal termination - - . -

    +

    Using improperly aligned pointers results in undefined behavior, typically leading to abnormal termination.

    @@ -185,14 +77,10 @@ Vector *f() { Low @@ -225,9 +113,7 @@ Vector *f() { 2021.2 @@ -242,9 +128,7 @@ Vector *f() { 2021.2
    - - P6 - + P6 - - L2 - + L2
    - - C++3129 - + C++3129 - - CERT_CPP-MEM57-a - + CERT_CPP-MEM57-a Avoid using the default operator 'new' for over-aligned types @@ -272,17 +156,7 @@ Vector *f() {
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/MSC50-CPP/DoNotUseRandForGeneratingPseudorandomNumbers-standard.qhelp b/cpp/cert/src/rules/MSC50-CPP/DoNotUseRandForGeneratingPseudorandomNumbers-standard.qhelp index c0ff5fbe4c..a6312aa07e 100644 --- a/cpp/cert/src/rules/MSC50-CPP/DoNotUseRandForGeneratingPseudorandomNumbers-standard.qhelp +++ b/cpp/cert/src/rules/MSC50-CPP/DoNotUseRandForGeneratingPseudorandomNumbers-standard.qhelp @@ -1,65 +1,26 @@
    -

    - Pseudorandom number generators use mathematical algorithms to produce a sequence of numbers with good statistical properties, but the numbers produced are not genuinely random. -

    -

    - The C Standard - - rand() - - function, exposed through the C++ standard library through - - <cstdlib> - - as - - std::rand() - - , makes no guarantees as to the quality of the random sequence produced. The numbers generated by some implementations of - - std::rand() - - have a comparatively short cycle, and the numbers can be predictable. Applications that have strong pseudorandom number requirements must use a generator that is known to be sufficient for their needs. -

    +

    Pseudorandom number generators use mathematical algorithms to produce a sequence of numbers with good statistical properties, but the numbers produced are not genuinely random.

    +

    The C Standard rand() function, exposed through the C++ standard library through <cstdlib> as std::rand(), makes no guarantees as to the quality of the random sequence produced. The numbers generated by some implementations of std::rand() have a comparatively short cycle, and the numbers can be predictable. Applications that have strong pseudorandom number requirements must use a generator that is known to be sufficient for their needs.

    -

    - The following noncompliant code generates an ID with a numeric part produced by calling the - - rand() - - function. The IDs produced are predictable and have limited randomness. Further, depending on the value of - - RAND_MAX - - , the resulting value can have modulo bias. -

    - - #include <cstdlib> +

    The following noncompliant code generates an ID with a numeric part produced by calling the rand() function. The IDs produced are predictable and have limited randomness. Further, depending on the value of RAND_MAX, the resulting value can have modulo bias.

    + #include <cstdlib> #include <string> -  + void f() { std::string id("ID"); // Holds the ID, starting with the characters "ID" followed // by a random integer in the range [0-10000]. id += std::to_string(std::rand() % 10000); // ... -} - +}
    -

    - The C++ standard library provides mechanisms for fine-grained control over pseudorandom number generation. It breaks random number generation into two parts: one is the algorithm responsible for providing random values (the engine), and the other is responsible for distribution of the random values via a density function (the distribution). The distribution object is not strictly required, but it works to ensure that values are properly distributed within a given range instead of improperly distributed due to bias issues. This compliant solution uses the - - Mersenne Twister - - algorithm as the engine for generating random values and a uniform distribution to negate the modulo bias from the noncompliant code example. -

    - - #include <random> +

    The C++ standard library provides mechanisms for fine-grained control over pseudorandom number generation. It breaks random number generation into two parts: one is the algorithm responsible for providing random values (the engine), and the other is responsible for distribution of the random values via a density function (the distribution). The distribution object is not strictly required, but it works to ensure that values are properly distributed within a given range instead of improperly distributed due to bias issues. This compliant solution uses the Mersenne Twister algorithm as the engine for generating random values and a uniform distribution to negate the modulo bias from the noncompliant code example.

    + #include <random> #include <string> -  + void f() { std::string id("ID"); // Holds the ID, starting with the characters "ID" followed // by a random integer in the range [0-10000]. @@ -69,23 +30,11 @@ void f() { id += std::to_string(distribution(engine)); // ... } - -

    - This compliant solution also seeds the random number engine, in conformance with - - MSC51-CPP. Ensure your random number generator is properly seeded - - . -

    +
    +

    This compliant solution also seeds the random number engine, in conformance with MSC51-CPP. Ensure your random number generator is properly seeded.

    -

    - Using the - - std::rand() - - function could lead to predictable random numbers. -

    +

    Using the std::rand() function could lead to predictable random numbers.

    @@ -122,14 +71,10 @@ void f() { Low @@ -162,9 +107,7 @@ void f() { 20.10 @@ -197,15 +138,11 @@ void f() { 4.0 (prerelease) @@ -215,18 +152,14 @@ void f() { @@ -252,9 +185,7 @@ void f() { 1.2 @@ -287,11 +216,7 @@ void f() { 2021.4 @@ -305,9 +230,7 @@ void f() {
    - - P6 - + P6 - - L2 - + L2
    - - bad-function (AUTOSAR.26.5.1A) - + bad-function (AUTOSAR.26.5.1A) Fully checked @@ -180,9 +123,7 @@ void f() { 7.2.0 - - CertC++-MSC50 - + CertC++-MSC50 - - cert-msc50-cpp - + cert-msc50-cpp Checked by - - clang-tidy - + clang-tidy
    - 6.1p0 + 6.2p0 - - BADFUNC.RANDOM.RAND - + BADFUNC.RANDOM.RAND Use of - - rand - + rand
    - - CC2.MSC30 - + CC2.MSC30 Fully implemented @@ -270,9 +201,7 @@ void f() { 2021.2 - - C++5028 - + C++5028 - - - CERT.MSC.STD_RAND_CALL - - + CERT.MSC.STD_RAND_CALL - - 44 S - + 44 S Enhanced Enforcement @@ -323,9 +246,7 @@ void f() { 2021.2 - - CERT_CPP-MSC50-a - + CERT_CPP-MSC50-a Do not use the rand() function for generating pseudorandom numbers @@ -359,9 +280,7 @@ void f() { 4.4 - - 5028 - + 5028 Fully implemented @@ -377,9 +296,7 @@ void f() { 20.10 - - bad-function (AUTOSAR.26.5.1A) - + bad-function (AUTOSAR.26.5.1A) Fully checked @@ -389,17 +306,7 @@ void f() {
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/MSC51-CPP/BadlySeededRandomNumberGenerator-standard.qhelp b/cpp/cert/src/rules/MSC51-CPP/BadlySeededRandomNumberGenerator-standard.qhelp index 72c3003df2..db310805fd 100644 --- a/cpp/cert/src/rules/MSC51-CPP/BadlySeededRandomNumberGenerator-standard.qhelp +++ b/cpp/cert/src/rules/MSC51-CPP/BadlySeededRandomNumberGenerator-standard.qhelp @@ -1,48 +1,15 @@
    -

    - A pseudorandom number generator (PRNG) is a deterministic algorithm capable of generating sequences of numbers that approximate the properties of random numbers. Each sequence is completely determined by the initial state of the PRNG and the algorithm for changing the state. Most PRNGs make it possible to set the initial state, also called the - - seed state - - . Setting the initial state is called - - seeding - - the PRNG. -

    -

    - Calling a PRNG in the same initial state, either without seeding it explicitly or by seeding it with a constant value, results in generating the same sequence of random numbers in different runs of the program. Consider a PRNG function that is seeded with some initial seed value and is consecutively called to produce a sequence of random numbers. If the PRNG is subsequently seeded with the same initial seed value, then it will generate the same sequence. -

    -

    - Consequently, after the first run of an improperly seeded PRNG, an attacker can predict the sequence of random numbers that will be generated in the future runs. Improperly seeding or failing to seed the PRNG can lead to - - vulnerabilities - - , especially in security protocols. -

    -

    - The solution is to ensure that a PRNG is always properly seeded with an initial seed value that will not be predictable or controllable by an attacker. A properly seeded PRNG will generate a different sequence of random numbers each time it is run. -

    -

    - Not all random number generators can be seeded. True random number generators that rely on hardware to produce completely unpredictable results do not need to be and cannot be seeded. Some high-quality PRNGs, such as the - - /dev/random - - device on some UNIX systems, also cannot be seeded. This rule applies only to algorithmic PRNGs that can be seeded. -

    +

    A pseudorandom number generator (PRNG) is a deterministic algorithm capable of generating sequences of numbers that approximate the properties of random numbers. Each sequence is completely determined by the initial state of the PRNG and the algorithm for changing the state. Most PRNGs make it possible to set the initial state, also called the seed state. Setting the initial state is called seeding the PRNG.

    +

    Calling a PRNG in the same initial state, either without seeding it explicitly or by seeding it with a constant value, results in generating the same sequence of random numbers in different runs of the program. Consider a PRNG function that is seeded with some initial seed value and is consecutively called to produce a sequence of random numbers. If the PRNG is subsequently seeded with the same initial seed value, then it will generate the same sequence.

    +

    Consequently, after the first run of an improperly seeded PRNG, an attacker can predict the sequence of random numbers that will be generated in the future runs. Improperly seeding or failing to seed the PRNG can lead to vulnerabilities, especially in security protocols.

    +

    The solution is to ensure that a PRNG is always properly seeded with an initial seed value that will not be predictable or controllable by an attacker. A properly seeded PRNG will generate a different sequence of random numbers each time it is run.

    +

    Not all random number generators can be seeded. True random number generators that rely on hardware to produce completely unpredictable results do not need to be and cannot be seeded. Some high-quality PRNGs, such as the /dev/random device on some UNIX systems, also cannot be seeded. This rule applies only to algorithmic PRNGs that can be seeded.

    -

    - This noncompliant code example generates a sequence of 10 pseudorandom numbers using the - - Mersenne Twister - - engine. No matter how many times this code is executed, it always produces the same sequence because the default seed is used for the engine. -

    - - #include <random> +

    This noncompliant code example generates a sequence of 10 pseudorandom numbers using the Mersenne Twister engine. No matter how many times this code is executed, it always produces the same sequence because the default seed is used for the engine.

    + #include <random> #include <iostream> void f() { @@ -51,28 +18,16 @@ void f() { for (int i = 0; i < 10; ++i) { std::cout << engine() << ", "; } -} - -

    - The output of this example follows. -

    - - 1st run: 3499211612, 581869302, 3890346734, 3586334585, 545404204, 4161255391, 3922919429, 949333985, 2715962298, 1323567403, +} +

    The output of this example follows.

    + 1st run: 3499211612, 581869302, 3890346734, 3586334585, 545404204, 4161255391, 3922919429, 949333985, 2715962298, 1323567403, 2nd run: 3499211612, 581869302, 3890346734, 3586334585, 545404204, 4161255391, 3922919429, 949333985, 2715962298, 1323567403, ... -nth run: 3499211612, 581869302, 3890346734, 3586334585, 545404204, 4161255391, 3922919429, 949333985, 2715962298, 1323567403, - +nth run: 3499211612, 581869302, 3890346734, 3586334585, 545404204, 4161255391, 3922919429, 949333985, 2715962298, 1323567403,
    -

    - This noncompliant code example improves the previous noncompliant code example by seeding the random number generation engine with the current time. However, this approach is still unsuitable when an attacker can control the time at which the seeding is executed. Predictable seed values can result in - - exploits - - when the subverted PRNG is used. -

    - - #include <ctime> +

    This noncompliant code example improves the previous noncompliant code example by seeding the random number generation engine with the current time. However, this approach is still unsuitable when an attacker can control the time at which the seeding is executed. Predictable seed values can result in exploits when the subverted PRNG is used.

    + #include <ctime> #include <random> #include <iostream> @@ -83,31 +38,11 @@ void f() { for (int i = 0; i < 10; ++i) { std::cout << engine() << ", "; } -} - +}
    -

    - This compliant solution uses - - std::random_device - - to generate a random value for seeding the Mersenne Twister engine object. The values generated by - - std::random_device - - are nondeterministic random numbers when possible, relying on random number generation devices, such as - - /dev/random - - . When such a device is not available, - - std::random_device - - may employ a random number engine; however, the initial value generated should have sufficient randomness to serve as a seed value. -

    - - #include <random> +

    This compliant solution uses std::random_device to generate a random value for seeding the Mersenne Twister engine object. The values generated by std::random_device are nondeterministic random numbers when possible, relying on random number generation devices, such as /dev/random. When such a device is not available, std::random_device may employ a random number engine; however, the initial value generated should have sufficient randomness to serve as a seed value.

    + #include <random> #include <iostream> void f() { @@ -117,17 +52,12 @@ void f() { for (int i = 0; i < 10; ++i) { std::cout << engine() << ", "; } -} - -

    - The output of this example follows. -

    - - 1st run: 3921124303, 1253168518, 1183339582, 197772533, 83186419, 2599073270, 3238222340, 101548389, 296330365, 3335314032, +} +

    The output of this example follows.

    + 1st run: 3921124303, 1253168518, 1183339582, 197772533, 83186419, 2599073270, 3238222340, 101548389, 296330365, 3335314032, 2nd run: 2392369099, 2509898672, 2135685437, 3733236524, 883966369, 2529945396, 764222328, 138530885, 4209173263, 1693483251, 3rd run: 914243768, 2191798381, 2961426773, 3791073717, 2222867426, 1092675429, 2202201605, 850375565, 3622398137, 422940882, -... - +...
    @@ -166,14 +96,10 @@ void f() { Low @@ -206,9 +132,7 @@ void f() { 20.10 @@ -241,9 +163,7 @@ void f() { 2021.2 @@ -264,7 +184,7 @@ void f() { @@ -278,9 +198,7 @@ void f() { 2021.2 @@ -315,9 +229,7 @@ void f() { 20.10
    - - P18 - + P18 - - L1 - + L1
    - - default-construction - + default-construction Partially checked @@ -224,9 +148,7 @@ void f() { 7.2.0 - - CertC++-MSC51 - + CertC++-MSC51 - - C++5041 - + C++5041 Checks for: - Deterministic random output from constant seed, predictable random output from predictable seed. + Deterministic random output from constant seedeterministic random output from constant seed, predictable random output from predictable seedredictable random output from predictable seed. Rule partially covered.
    - - CERT_CPP-MSC51-a - + CERT_CPP-MSC51-a Properly seed pseudorandom number generators @@ -293,14 +211,10 @@ void f() { - 7.16 + 7.17 - - - V1057 - - + V1057 - - default-construction - + default-construction Partially checked @@ -327,24 +239,8 @@ void f() {
    -

    - Using a predictable seed value, such as the current time, result in numerous - - vulnerabilities - - , such as the one described by - - CVE-2008-1637 - - . -

    -

    - Search for vulnerabilities resulting from the violation of this rule on the - - CERT website - - . -

    +

    Using a predictable seed value, such as the current time, result in numerous vulnerabilities, such as the one described by CVE-2008-1637.

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/MSC52-CPP/NonVoidFunctionDoesNotReturnCert-standard.qhelp b/cpp/cert/src/rules/MSC52-CPP/NonVoidFunctionDoesNotReturnCert-standard.qhelp index 4e98217391..954acafa2a 100644 --- a/cpp/cert/src/rules/MSC52-CPP/NonVoidFunctionDoesNotReturnCert-standard.qhelp +++ b/cpp/cert/src/rules/MSC52-CPP/NonVoidFunctionDoesNotReturnCert-standard.qhelp @@ -1,154 +1,58 @@
    -

    - The C++ Standard, [stmt.return], paragraph 2 [ - - ISO/IEC 14882-2014 - - ], states the following: -

    +

    The C++ Standard, [stmt.return], paragraph 2 [ISO/IEC 14882-2014], states the following:

    -

    - Flowing off the end of a function is equivalent to a - - return - - with no value; this results in undefined behavior in a value-returning function. -

    +

    Flowing off the end of a function is equivalent to a return with no value; this results in undefined behavior in a value-returning function.

    -

    - A value-returning function must return a value from all code paths; otherwise, it will result in - - undefined behavior - - . This includes returning through less-common code paths, such as from a - - - function-try-block - - - , as explained in the C++ Standard, [except.handle], paragraph 15: -

    +

    A value-returning function must return a value from all code paths; otherwise, it will result in undefined behavior. This includes returning through less-common code paths, such as from a function-try-block, as explained in the C++ Standard, [except.handle], paragraph 15:

    -

    - Flowing off the end of a - - function-try-block - - is equivalent to a - - return - - with no value; this results in undefined behavior in a value-returning function (6.6.3). -

    +

    Flowing off the end of a function-try-block is equivalent to a return with no value; this results in undefined behavior in a value-returning function (6.6.3).

    -

    - In this noncompliant code example, the programmer forgot to return the input value for positive input, so not all code paths return a value. -

    - - int absolute_value(int a) { +

    In this noncompliant code example, the programmer forgot to return the input value for positive input, so not all code paths return a value.

    + int absolute_value(int a) { if (a < 0) { return -a; } -} - +}
    -

    - In this compliant solution, all code paths now return a value. -

    - - int absolute_value(int a) { +

    In this compliant solution, all code paths now return a value.

    + int absolute_value(int a) { if (a < 0) { return -a; } return a; -} - +}
    -

    - In this noncompliant code example, the - - function-try-block - - handler does not return a value, resulting in - - undefined behavior - - when an exception is thrown. -

    - - #include <vector> +

    In this noncompliant code example, the function-try-block handler does not return a value, resulting in undefined behavior when an exception is thrown.

    + #include <vector> std::size_t f(std::vector<int> &v, std::size_t s) try { v.resize(s); return s; } catch (...) { } - +
    -

    - In this compliant solution, the exception handler of the - - function-try-block - - also returns a value. -

    - - #include <vector> +

    In this compliant solution, the exception handler of the function-try-block also returns a value.

    + #include <vector> std::size_t f(std::vector<int> &v, std::size_t s) try { v.resize(s); return s; } catch (...) { return 0; -} - +}
    -

    - - MSC54-CPP-EX1: - - Flowing off the end of the - - main() - - function is equivalent to a - - return 0; - - statement, according to the C++ Standard, [basic.start.main], paragraph 5 [ - - ISO/IEC 14882-2014 - - ].  Thus, flowing off the end of the - - main() - - function does not result in - - undefined behavior - - . -

    -

    - - MSC54-CPP-EX2: - - It is permissible for a control path to not return a value if that code path is never expected to be taken and a function marked - - [[noreturn]] - - is called as part of that code path or if an exception is thrown, as is illustrated in the following code example. -

    - - #include <cstdlib> +

    MSC54-CPP-EX1: Flowing off the end of the main() function is equivalent to a return 0; statement, according to the C++ Standard, [basic.start.main], paragraph 5 [ISO/IEC 14882-2014]. Thus, flowing off the end of the main() function does not result in undefined behavior.

    +

    MSC54-CPP-EX2: It is permissible for a control path to not return a value if that code path is never expected to be taken and a function marked [[noreturn]] is called as part of that code path or if an exception is thrown, as is illustrated in the following code example.

    + #include <cstdlib> #include <iostream> [[noreturn]] void unreachable(const char *msg) { std::cout << "Unreachable code reached: " << msg << std::endl; @@ -168,21 +72,10 @@ int f(E e) { case Three: return 3; } unreachable("Can never get here"); -} - +}
    -

    - Failing to return a value from a code path in a value-returning function results in - - undefined behavior - - that might be - - exploited - - to cause data integrity violations. -

    +

    Failing to return a value from a code path in a value-returning function results in undefined behavior that might be exploited to cause data integrity violations.

    @@ -219,14 +112,10 @@ int f(E e) { Medium @@ -259,9 +148,7 @@ int f(E e) { 20.10 @@ -294,9 +179,7 @@ int f(E e) { 3.9 @@ -350,12 +229,8 @@ int f(E e) { 2021.4 @@ -369,9 +244,7 @@ int f(E e) { @@ -442,9 +309,7 @@ int f(E e) { 4.4 @@ -456,14 +321,10 @@ int f(E e) { @@ -478,9 +339,7 @@ int f(E e) { 20.10
    - - P8 - + P8 - - L2 - + L2
    - - return-implicit - + return-implicit Fully checked @@ -277,9 +164,7 @@ int f(E e) { 7.2.0 - - CertC++-MSC52 - + CertC++-MSC52 - - -Wreturn-type - + -Wreturn-type Does not catch all instances of this rule, such as @@ -312,12 +195,10 @@ int f(E e) { - 6.1p0 + 6.2p0 - - LANG.STRUCT.MRS - + LANG.STRUCT.MRS Missing return statement @@ -333,9 +214,7 @@ int f(E e) { 2021.2 - - C++2888 - + C++2888 - - FUNCRET.GEN - - - FUNCRET.IMPLICIT - + FUNCRET.GEN + FUNCRET.IMPLICIT - - 2 D, 36 S - + 2 D, 36 S Fully implemented @@ -387,9 +260,7 @@ int f(E e) { 2021.2 - - CERT_CPP-MSC52-a - + CERT_CPP-MSC52-a All exit paths from a function with non-void return type shall have an explicit return statement with an expression @@ -423,11 +294,7 @@ int f(E e) { 4.10 - - - S935 - - + S935 - - 1510 - + 1510 - 7.16 + 7.17 - - - V591 - - + V591 - - return-implicit - + return-implicit Fully checked @@ -490,17 +349,7 @@ int f(E e) {
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    @@ -516,9 +365,7 @@ int f(E e) { diff --git a/cpp/cert/src/rules/MSC53-CPP/FunctionNoReturnAttributeConditionCert-standard.qhelp b/cpp/cert/src/rules/MSC53-CPP/FunctionNoReturnAttributeConditionCert-standard.qhelp index 812c817f12..bf7bfede31 100644 --- a/cpp/cert/src/rules/MSC53-CPP/FunctionNoReturnAttributeConditionCert-standard.qhelp +++ b/cpp/cert/src/rules/MSC53-CPP/FunctionNoReturnAttributeConditionCert-standard.qhelp @@ -1,104 +1,35 @@
    -

    - The - - [[noreturn]] - - attribute specifies that a function does not return. The C++ Standard, [dcl.attr.noreturn] paragraph 2 - [ - - ISO/IEC 14882-2014 - - ], states the following: -

    +

    The [[noreturn]] attribute specifies that a function does not return. The C++ Standard, [dcl.attr.noreturn] paragraph 2 [ISO/IEC 14882-2014], states the following:

    -

    - If a function - - f - - is called where - - f - - was previously declared with the - - noreturn - - attribute and - - f - - eventually returns, the behavior is undefined. -

    +

    If a function f is called where f was previously declared with the noreturn attribute and f eventually returns, the behavior is undefined.

    -

    - A function that specifies - - [[noreturn]] - - can prohibit returning by throwing an exception, entering an infinite loop, or calling another function designated with the - - [[noreturn]] - - attribute. -

    +

    A function that specifies [[noreturn]] can prohibit returning by throwing an exception, entering an infinite loop, or calling another function designated with the [[noreturn]] attribute.

    -

    - In this noncompliant code example, if the value - - 0 - - is passed, control will flow off the end of the function, resulting in an implicit return and - - undefined behavior - - . -

    - - #include <cstdlib> -  +

    In this noncompliant code example, if the value 0 is passed, control will flow off the end of the function, resulting in an implicit return and undefined behavior.

    + #include <cstdlib> + [[noreturn]] void f(int i) { if (i > 0) throw "Received positive input"; else if (i < 0) std::exit(0); -} - +}
    -

    - In this compliant solution, the function does not return on any code path. -

    - - #include <cstdlib> -  +

    In this compliant solution, the function does not return on any code path.

    + #include <cstdlib> + [[noreturn]] void f(int i) { if (i > 0) throw "Received positive input"; std::exit(0); -} - +}
    -

    - Returning from a function marked - - [[noreturn]] - - results in - - undefined behavior - - that might be - - exploited - - to cause data-integrity violations. -

    +

    Returning from a function marked [[noreturn]] results in undefined behavior that might be exploited to cause data-integrity violations.

    Subclause 3.6.1, "Main Function" Subclause 6.6.3, "The - - return - + return Statement" Subclause 15.3, "Handling an Exception"
    @@ -135,14 +66,10 @@ Low @@ -175,9 +102,7 @@ 20.10 @@ -210,13 +133,27 @@ 3.9 + + + + + + @@ -244,11 +179,7 @@ 2021.4 @@ -263,9 +194,7 @@ 2021.2 @@ -303,9 +230,7 @@ 20.10 @@ -334,17 +255,7 @@
    - - P2 - + P2 - - L3 - + L3
    - - invalid-noreturn - + invalid-noreturn Fully checked @@ -193,9 +118,7 @@ 7.2.0 - - CertC++-MSC53 - + CertC++-MSC53 - - -Winvalid-noreturn - + -Winvalid-noreturn
    + + CodeSonar + + + 6.2p0 + + LANG.STRUCT.RFNR + + Return from noreturn +
    @@ -227,9 +164,7 @@ 2021.2 - - C++2886 - + C++2886 - - - CERT.MSC.NORETURN_FUNC_RETURNS - - + CERT.MSC.NORETURN_FUNC_RETURNS - - CERT_CPP-MSC53-a - + CERT_CPP-MSC53-a Never return from functions that should not return @@ -287,9 +216,7 @@ Checks for - - [[noreturn]] - + [[noreturn]] functions returning to caller (rule fully covered)
    - - invalid-noreturn - + invalid-noreturn Fully checked @@ -321,11 +246,7 @@ 4.10 - - - S935 - - + S935
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    @@ -359,9 +270,7 @@ diff --git a/cpp/cert/src/rules/MSC54-CPP/SignalHandlerMustBeAPlainOldFunction-standard.qhelp b/cpp/cert/src/rules/MSC54-CPP/SignalHandlerMustBeAPlainOldFunction-standard.qhelp index 3505b13a02..b6682a3aba 100644 --- a/cpp/cert/src/rules/MSC54-CPP/SignalHandlerMustBeAPlainOldFunction-standard.qhelp +++ b/cpp/cert/src/rules/MSC54-CPP/SignalHandlerMustBeAPlainOldFunction-standard.qhelp @@ -1,107 +1,27 @@
    -

    - The C++14 Standard, [support.runtime], paragraph 10 - [ - - ISO/IEC 14882-2014 - - ] - , states the following: -

    +

    The C++14 Standard, [support.runtime], paragraph 10 [ISO/IEC 14882-2014], states the following:

    -

    - The common subset of the C and C++ languages consists of all declarations, definitions, and expressions that may appear in a well-formed C++ program and also in a conforming C program. A POF (“plain old function”) is a function that uses only features from this common subset, and that does not directly or indirectly use any function that is not a POF, except that it may use plain lock-free atomic operations. A plain lock-free atomic operation is an invocation of a function f from Clause 29, such that f is not a member function, and either f is the function atomic_is_lock_free, or for every atomic argument A passed to f, atomic_is_lock_free(A) yields true. All signal handlers shall have C linkage. The behavior of any function other than a POF used as a signal handler in a C++ program is implementation-defined.228 -

    +

    The common subset of the C and C++ languages consists of all declarations, definitions, and expressions that may appear in a well-formed C++ program and also in a conforming C program. A POF (“plain old function”) is a function that uses only features from this common subset, and that does not directly or indirectly use any function that is not a POF, except that it may use plain lock-free atomic operations. A plain lock-free atomic operation is an invocation of a function f from Clause 29, such that f is not a member function, and either f is the function atomic_is_lock_free, or for every atomic argument A passed to f, atomic_is_lock_free(A) yields true. All signal handlers shall have C linkage. The behavior of any function other than a POF used as a signal handler in a C++ program is implementation-defined.228

    -

    - Footnote 228 states the following: -

    +

    Footnote 228 states the following:

    -

    - In particular, a signal handler using exception handling is very likely to have problems. Also, invoking - - std::exit - - may cause destruction of objects, including those of the standard library implementation, which, in general, yields undefined behavior in a signal handler. -

    +

    In particular, a signal handler using exception handling is very likely to have problems. Also, invoking std::exit may cause destruction of objects, including those of the standard library implementation, which, in general, yields undefined behavior in a signal handler.

    -

    - If your signal handler is not a plain old function, then the behavior of a call to it in response to a signal is - - implementation-defined - - , at best, and is likely to result in - - undefined behavior - - . All signal handlers must meet the definition of a plain old function. In addition to the restrictions placed on signal handlers in a C program, this definition also prohibits the use of features that exist in C++ but not in C (such as non-POD [non–plain old data] objects and exceptions). This includes indirect use of such features through function calls. -

    -

    - In C++17, the wording has changed and relaxed some of the constraints on signal handlers. Section [support.signal], paragraph 3 says: -

    +

    If your signal handler is not a plain old function, then the behavior of a call to it in response to a signal is implementation-defined, at best, and is likely to result in undefined behavior. All signal handlers must meet the definition of a plain old function. In addition to the restrictions placed on signal handlers in a C program, this definition also prohibits the use of features that exist in C++ but not in C (such as non-POD [non–plain old data] objects and exceptions). This includes indirect use of such features through function calls.

    +

    In C++17, the wording has changed and relaxed some of the constraints on signal handlers. Section [support.signal], paragraph 3 says:

    -

    - An evaluation is - signal-safe - unless it includes one of the following: -

    -

    - — - a call to any standard library function, except for plain lock-free atomic operations and functions explicitly identified as signal-safe. [ - Note: - This implicitly excludes the use of - new - and - delete - expressions that rely on a library-provided memory allocator. - — end note - ] - — an access to an object with thread storage duration; - — a - dynamic_cast - expression; - — throwing of an exception; - — control entering a - try-block - or - function-try-block - ; - — initialization of a variable with static storage duration requiring dynamic initialization ( - 6.6.3 - , - 9.7 - ) - 220 - ; or - — waiting for the completion of the initialization of a variable with static storage duration ( - 9.7 - ). -

    -

    - A signal handler invocation has undefined behavior if it includes an evaluation that is not signal-safe. -

    +

    An evaluation is signal-safe unless it includes one of the following:

    +

    — a call to any standard library function, except for plain lock-free atomic operations and functions explicitly identified as signal-safe. [ Note: This implicitly excludes the use of new and delete expressions that rely on a library-provided memory allocator. — end note ]— an access to an object with thread storage duration;— a dynamic_cast expression;— throwing of an exception;— control entering a try-block or function-try-block;— initialization of a variable with static storage duration requiring dynamic initialization (6.6.3, 9.7)220; or— waiting for the completion of the initialization of a variable with static storage duration (9.7).

    +

    A signal handler invocation has undefined behavior if it includes an evaluation that is not signal-safe.

    -

    - Signal handlers in code that will be executed on C++17-compliant platforms must be signal-safe. -

    +

    Signal handlers in code that will be executed on C++17-compliant platforms must be signal-safe.

    -

    - In this noncompliant code example, the signal handler is declared as a - - static - - function. However, since all signal handler functions must have C language linkage, and C++ is the default language linkage for functions in C++, calling the signal handler results in - - undefined behavior - - . -

    - - #include <csignal> -  +

    In this noncompliant code example, the signal handler is declared as a static function. However, since all signal handler functions must have C language linkage, and C++ is the default language linkage for functions in C++, calling the signal handler results in undefined behavior.

    + #include <csignal> + static void sig_handler(int sig) { // Implementation details elided. } @@ -110,19 +30,11 @@ void install_signal_handler() { if (SIG_ERR == std::signal(SIGTERM, sig_handler)) { // Handle error } -} - +}
    -

    - This compliant solution defines - - sig_handler() - - as having C language linkage. As a consequence of declaring the signal handler with C language linkage, the signal handler will have external linkage rather than internal linkage. -

    - - #include <csignal> +

    This compliant solution defines sig_handler() as having C language linkage. As a consequence of declaring the signal handler with C language linkage, the signal handler will have external linkage rather than internal linkage.

    + #include <csignal> extern "C" void sig_handler(int sig) { // Implementation details elided. @@ -132,27 +44,11 @@ void install_signal_handler() { if (SIG_ERR == std::signal(SIGTERM, sig_handler)) { // Handle error } -} - +}
    -

    - In this noncompliant code example, a signal handler calls a function that allows exceptions, and it attempts to handle any exceptions thrown. Because exceptions are not part of the common subset of C and C++ features, this example results in - - implementation-defined behavior - - . However, it is unlikely that the implementation's behavior will be suitable. For instance, on a stack-based architecture where a signal is generated asynchronously (instead of as a result of a call to - - std:abort() - - or - - std::raise() - - ), it is possible that the stack frame is not properly initialized, causing stack tracing to be unreliable and preventing the exception from being caught properly. -

    - - #include <csignal> +

    In this noncompliant code example, a signal handler calls a function that allows exceptions, and it attempts to handle any exceptions thrown. Because exceptions are not part of the common subset of C and C++ features, this example results in implementation-defined behavior. However, it is unlikely that the implementation's behavior will be suitable. For instance, on a stack-based architecture where a signal is generated asynchronously (instead of as a result of a call to std:abort() or std::raise()), it is possible that the stack frame is not properly initialized, causing stack tracing to be unreliable and preventing the exception from being caught properly.

    + #include <csignal> static void g() noexcept(false); @@ -163,56 +59,16 @@ extern "C" void sig_handler(int sig) { // Handle error } } -  + void install_signal_handler() { if (SIG_ERR == std::signal(SIGTERM, sig_handler)) { // Handle error } -} - +}
    -

    - There is no compliant solution whereby - - g() - - can be called from the signal handler because it allows exceptions. Even if - - g() - - were implemented such that it handled all exceptions and was marked - - noexcept(true) - - , it would still be noncompliant to call - - g() - - from a signal handler because - - g() - - would still use a feature that is not a part of the common subset of C and C++ features allowed by a signal handler. Therefore, this compliant solution removes the call to - - g() - - from the signal handler and instead polls a variable of type - - volatile sig_atomic_t - - periodically; if the variable is set to - - 1 - - in the signal handler, then - - g() - - is called to respond to the signal. -

    - - #include <csignal> +

    There is no compliant solution whereby g() can be called from the signal handler because it allows exceptions. Even if g() were implemented such that it handled all exceptions and was marked noexcept(true), it would still be noncompliant to call g() from a signal handler because g() would still use a feature that is not a part of the common subset of C and C++ features allowed by a signal handler. Therefore, this compliant solution removes the call to g() from the signal handler and instead polls a variable of type volatile sig_atomic_t periodically; if the variable is set to 1 in the signal handler, then g() is called to respond to the signal.

    + #include <csignal> volatile sig_atomic_t signal_flag = 0; static void g() noexcept(false); @@ -226,7 +82,7 @@ void install_signal_handler() { // Handle error } } -  + // Called periodically to poll the signal flag. void poll_signal_flag() { if (signal_flag == 1) { @@ -237,25 +93,10 @@ void poll_signal_flag() { // Handle error } } -} - +}
    -

    - Failing to use a plain old function as a signal handler can result in - - implementation-defined behavior - - as well as - - undefined behavior - - . Given the number of features that exist in C++ that do not also exist in C, the consequences that arise from failure to comply with this rule can range from benign (harmless) behavior to - - abnormal program termination - - , or even arbitrary code execution. -

    +

    Failing to use a plain old function as a signal handler can result in implementation-defined behavior as well as undefined behavior. Given the number of features that exist in C++ that do not also exist in C, the consequences that arise from failure to comply with this rule can range from benign (harmless) behavior to abnormal program termination, or even arbitrary code execution.

    Subclause 7.6.3, " - - noreturn - + noreturn Attribute"
    @@ -292,14 +133,10 @@ void poll_signal_flag() { High @@ -332,9 +169,7 @@ void poll_signal_flag() { 2021.2 @@ -349,11 +184,7 @@ void poll_signal_flag() { 2021.4 @@ -368,9 +199,7 @@ void poll_signal_flag() { 2021.2 @@ -397,17 +224,7 @@ void poll_signal_flag() {
    - - P6 - + P6 - - L2 - + L2
    - - C++2888 - + C++2888 - - - CERT.MSC.SIG_HANDLER.POF - - + CERT.MSC.SIG_HANDLER.POF - - CERT_CPP-MSC54-a - + CERT_CPP-MSC54-a Properly define signal handlers @@ -386,9 +215,7 @@ void poll_signal_flag() { 4.4 - - 2888 - + 2888
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/OOP50-CPP/DoNotInvokeVirtualFunctionsFromConstructorsOrDestructors-standard.qhelp b/cpp/cert/src/rules/OOP50-CPP/DoNotInvokeVirtualFunctionsFromConstructorsOrDestructors-standard.qhelp index 316091ecec..cc8413bcbf 100644 --- a/cpp/cert/src/rules/OOP50-CPP/DoNotInvokeVirtualFunctionsFromConstructorsOrDestructors-standard.qhelp +++ b/cpp/cert/src/rules/OOP50-CPP/DoNotInvokeVirtualFunctionsFromConstructorsOrDestructors-standard.qhelp @@ -1,72 +1,19 @@
    -

    - Virtual functions allow for the choice of member function calls to be determined at run time based on the dynamic type of the object that the member function is being called on. This convention supports object-oriented programming practices commonly associated with object inheritance and function overriding. When calling a nonvirtual member function or when using a class member access expression to denote a call, the specified function is called. Otherwise, a virtual function call is made to the final overrider in the dynamic type of the object expression. -

    -

    - However, during the construction and destruction of an object, the rules for virtual method dispatch on that object are restricted. The C++ Standard, [class.cdtor], paragraph 4 - [ - - ISO/IEC 14882-2014 - - ] - , states the following: -

    +

    Virtual functions allow for the choice of member function calls to be determined at run time based on the dynamic type of the object that the member function is being called on. This convention supports object-oriented programming practices commonly associated with object inheritance and function overriding. When calling a nonvirtual member function or when using a class member access expression to denote a call, the specified function is called. Otherwise, a virtual function call is made to the final overrider in the dynamic type of the object expression.

    +

    However, during the construction and destruction of an object, the rules for virtual method dispatch on that object are restricted. The C++ Standard, [class.cdtor], paragraph 4 [ISO/IEC 14882-2014], states the following:

    -

    - Member functions, including virtual functions, can be called during construction or destruction. When a virtual function is called directly or indirectly from a constructor or from a destructor, including during the construction or destruction of the class’s non-static data members, and the object to which the call applies is the object (call it - - x - - ) under construction or destruction, the function called is the final overrider in the constructor’s or destructor’s class and not one overriding it in a more-derived class. If the virtual function call uses an explicit class member access and the object expression refers to the complete object of - - x - - or one of that object’s base class subobjects but not - - x - - or one of its base class subobjects, the behavior is undefined. -

    +

    Member functions, including virtual functions, can be called during construction or destruction. When a virtual function is called directly or indirectly from a constructor or from a destructor, including during the construction or destruction of the class’s non-static data members, and the object to which the call applies is the object (call it x) under construction or destruction, the function called is the final overrider in the constructor’s or destructor’s class and not one overriding it in a more-derived class. If the virtual function call uses an explicit class member access and the object expression refers to the complete object of x or one of that object’s base class subobjects but not x or one of its base class subobjects, the behavior is undefined.

    -

    - Do not directly or indirectly invoke a virtual function from a constructor or destructor that attempts to call into the object under construction or destruction. Because the order of construction starts with base classes and moves to more derived classes, attempting to call a derived class function from a base class under construction is dangerous. The derived class has not had the opportunity to initialize its resources, which is why calling a virtual function from a constructor does not result in a call to a function in a more derived class. Similarly, an object is destroyed in reverse order from construction, so attempting to call a function in a more derived class from a destructor may access resources that have already been released. -

    +

    Do not directly or indirectly invoke a virtual function from a constructor or destructor that attempts to call into the object under construction or destruction. Because the order of construction starts with base classes and moves to more derived classes, attempting to call a derived class function from a base class under construction is dangerous. The derived class has not had the opportunity to initialize its resources, which is why calling a virtual function from a constructor does not result in a call to a function in a more derived class. Similarly, an object is destroyed in reverse order from construction, so attempting to call a function in a more derived class from a destructor may access resources that have already been released.

    -

    - In this noncompliant code example, the base class attempts to seize and release an object's resources through calls to virtual functions from the constructor and destructor. However, the - - B::B() - - constructor calls - - B::seize() - - rather than - - D::seize() - - . Likewise, the - - B::~B() - - destructor calls - - B::release() - - rather than - - D::release() - - . -

    - - struct B { +

    In this noncompliant code example, the base class attempts to seize and release an object's resources through calls to virtual functions from the constructor and destructor. However, the B::B() constructor calls B::seize() rather than D::seize(). Likewise, the B::~B() destructor calls B::release() rather than D::release().

    + struct B { B() { seize(); } virtual ~B() { release(); } -  + protected: virtual void seize(); virtual void release(); @@ -74,73 +21,24 @@ protected: struct D : B { virtual ~D() = default; -  + protected: void seize() override { B::seize(); // Get derived resources... } -  + void release() override { // Release derived resources... B::release(); } }; - -

    - The result of running this code is that no derived class resources will be seized or released during the initialization and destruction of object of type - - D - - . At the time of the call to - - seize() - - from - - B::B() - - , the - - D - - constructor has not been entered, and the behavior of the under-construction object will be to invoke - - B::seize() - - rather than - - D::seize() - - . A similar situation occurs for the call to - - release() - - in the base class destructor. If the functions - - seize() - - and - - release() - - were declared to be pure virtual functions, the result would be - - undefined behavior - - . -

    +
    +

    The result of running this code is that no derived class resources will be seized or released during the initialization and destruction of object of type D. At the time of the call to seize() from B::B(), the D constructor has not been entered, and the behavior of the under-construction object will be to invoke B::seize() rather than D::seize(). A similar situation occurs for the call to release() in the base class destructor. If the functions seize() and release() were declared to be pure virtual functions, the result would be undefined behavior.

    -

    - In this compliant solution, the constructors and destructors call a nonvirtual, private member function (suffixed with - - mine - - ) instead of calling a virtual function. The result is that each class is responsible for seizing and releasing its own resources. -

    - - class B { +

    In this compliant solution, the constructors and destructors call a nonvirtual, private member function (suffixed with mine) instead of calling a virtual function. The result is that each class is responsible for seizing and releasing its own resources.

    + class B { void seize_mine(); void release_mine(); @@ -171,81 +69,43 @@ protected: release_mine(); B::release(); } -}; - +};
    -

    - - OOP50-CPP-EX1: - - Because valid use cases exist that involve calling (non-pure) virtual functions from the constructor of a class, it is permissible to call the virtual function with an explicitly qualified ID. The qualified ID signifies to code maintainers that the expected behavior is for the class under construction or destruction to be the final overrider for the function call. -

    - - struct A { +

    OOP50-CPP-EX1: Because valid use cases exist that involve calling (non-pure) virtual functions from the constructor of a class, it is permissible to call the virtual function with an explicitly qualified ID. The qualified ID signifies to code maintainers that the expected behavior is for the class under construction or destruction to be the final overrider for the function call.

    + struct A { A() { // f(); // WRONG! A::f(); // Okay } virtual void f(); }; - -

    - - OOP50-CPP-EX2: - - It is permissible to call a virtual function that has the - - final - - - virt-specifier - - from a constructor or destructor, as in this example. -

    - - struct A { + +

    OOP50-CPP-EX2: It is permissible to call a virtual function that has the final virt-specifier from a constructor or destructor, as in this example.

    + struct A { A(); virtual void f(); }; -  + struct B : A { B() : A() { f(); // Okay } void f() override final; -}; - -

    - Similarly, it is permissible to call a virtual function from a constructor or destructor of a class that has the - - final - - - class-virt-specifier - - , as in this example. -

    - - struct A { +}; +

    Similarly, it is permissible to call a virtual function from a constructor or destructor of a class that has the final class-virt-specifier, as in this example.

    + struct A { A(); virtual void f(); }; -  + struct B final : A { B() : A() { f(); // Okay } void f() override; -}; - -

    - In either case, - - f() - - must be the final overrider, guaranteeing consistent behavior of the function being called. -

    +};
    +

    In either case, f() must be the final overrider, guaranteeing consistent behavior of the function being called.

    @@ -284,14 +144,10 @@ struct B final : A { Medium @@ -324,10 +180,7 @@ struct B final : A { 20.10 @@ -360,15 +211,29 @@ struct B final : A { 3.9 + + + + + + @@ -381,9 +246,7 @@ struct B final : A { 2021.2 @@ -397,9 +260,7 @@ struct B final : A { @@ -463,11 +316,7 @@ struct B final : A { 4.4 @@ -479,14 +328,10 @@ struct B final : A { @@ -501,9 +346,7 @@ struct B final : A { 20.10 @@ -532,17 +371,7 @@ struct B final : A {
    - - P2 - + P2 - - L3 - + L3
    - - virtual-call-in-constructor - invalid_function_pointer - + virtual-call-in-constructorinvalid_function_pointer Fully checked @@ -343,9 +196,7 @@ struct B final : A { 7.2.0 - - CertC++-OOP50 - + CertC++-OOP50 - - clang-analyzer-alpha.cplusplus.VirtualCall - + clang-analyzer-alpha.cplusplus.VirtualCall Checked by - - clang-tidy - + clang-tidy +
    + + CodeSonar + + + 6.2p0 + + LANG.STRUCT.VCALL_IN_CTOR + LANG.STRUCT.VCALL_IN_DTOR + + Virtual Call in Constructor + Virtual Call in Destructor
    - - C++4260, C++4261, C++4273, C++4274, C++4275, C++4276, C++4277, C++4278, C++4279, C++4280, C++4281, C++4282 - + C++4260, C++4261, C++4273, C++4274, C++4275, C++4276, C++4277, C++4278, C++4279, C++4280, C++4281, C++4282 - - 467 S, 92 D - + 467 S, 92 D Fully implemented @@ -415,18 +276,10 @@ struct B final : A { 2021.2 - - CERT_CPP-OOP50-a - - - CERT_CPP-OOP50-b - - - CERT_CPP-OOP50-c - - - CERT_CPP-OOP50-d - + CERT_CPP-OOP50-a + CERT_CPP-OOP50-b + CERT_CPP-OOP50-c + CERT_CPP-OOP50-d Avoid calling virtual functions from constructors @@ -450,7 +303,7 @@ struct B final : A { - Checks for virtual function call from constructors and destructors (rule fully covered) + Checks for virtual function call from constructors and destructors (rule fully covered)
    - - 4260, 4261, 4273, 4274, - 4275, 4276, 4277, 4278, - 4279, 4280, 4281, 4282 - + 4260, 4261, 4273, 4274,4275, 4276, 4277, 4278,4279, 4280, 4281, 4282 - 7.16 + 7.17 - - - V1053 - - + V1053 - - virtual-call-in-constructor - + virtual-call-in-constructor Fully checked @@ -519,11 +362,7 @@ struct B final : A { 4.10 - - - S1699 - - + S1699
    -

    - Search for other - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for other vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/OOP51-CPP/DoNotSliceDerivedObjects-standard.qhelp b/cpp/cert/src/rules/OOP51-CPP/DoNotSliceDerivedObjects-standard.qhelp index 2b0fab854a..bcbb66c2f0 100644 --- a/cpp/cert/src/rules/OOP51-CPP/DoNotSliceDerivedObjects-standard.qhelp +++ b/cpp/cert/src/rules/OOP51-CPP/DoNotSliceDerivedObjects-standard.qhelp @@ -1,43 +1,12 @@
    -

    - An object deriving from a base class typically contains additional member variables that extend the base class. When by-value assigning or copying an object of the derived type to an object of the base type, those additional member variables are not copied because the base class contains insufficient space in which to store them. This action is commonly called - - slicing - - the object because the additional members are "sliced off" the resulting object. -

    -

    - Do not initialize an object of base class type with an object of derived class type, except through references, pointers, or pointer-like abstractions (such as - - std::unique_ptr, or std::shared_ptr - - ). -

    +

    An object deriving from a base class typically contains additional member variables that extend the base class. When by-value assigning or copying an object of the derived type to an object of the base type, those additional member variables are not copied because the base class contains insufficient space in which to store them. This action is commonly called slicing the object because the additional members are "sliced off" the resulting object.

    +

    Do not initialize an object of base class type with an object of derived class type, except through references, pointers, or pointer-like abstractions (such as std::unique_ptr, or std::shared_ptr).

    -

    - In this noncompliant code example, an object of the derived - - Manager - - type is passed by value to a function accepting a base - - Employee - - type. Consequently, the - - Manager - - objects are sliced, resulting in information loss and unexpected behavior when the - - print() - - function is called. -

    - - #include <iostream> +

    In this noncompliant code example, an object of the derived Manager type is passed by value to a function accepting a base Employee type. Consequently, the Manager objects are sliced, resulting in information loss and unexpected behavior when the print() function is called.

    + #include <iostream> #include <string> class Employee { @@ -84,49 +53,14 @@ int main() { f(typist); f(designer); } - -

    - When - - f() - - is called with the - - designer - - argument, the formal parameter in - - f() - - is sliced and information is lost. When the object - - e - - is printed, - - Employee::print() - - is called instead of - - Manager::print() - - , resulting in the following output: -

    - - Employee: Jane Doe - +
    +

    When f() is called with the designer argument, the formal parameter in f() is sliced and information is lost. When the object e is printed, Employee::print() is called instead of Manager::print(), resulting in the following output:

    + Employee: Jane Doe
    -

    - Using the same class definitions as the noncompliant code example, this compliant solution modifies the definition of - - f() - - to require raw pointers to the object, removing the slicing problem. -

    - - // Remainder of code unchanged... -  +

    Using the same class definitions as the noncompliant code example, this compliant solution modifies the definition of f() to require raw pointers to the object, removing the slicing problem.

    + // Remainder of code unchanged... + void f(const Employee *e) { if (e) { std::cout << *e; @@ -142,36 +76,17 @@ int main() { f(&typist); f(&designer); } - -

    - This compliant solution also complies with - - EXP34-C. Do not dereference null pointers - - in the implementation of - - f() - - . With this definition, the program correctly outputs the following. -

    - - Employee: Joe Smith + +

    This compliant solution also complies with EXP34-C. Do not dereference null pointers in the implementation of f(). With this definition, the program correctly outputs the following.

    + Employee: Joe Smith Employee: Bill Jones Manager: Jane Doe Assistant: - Employee: Bill Jones - + Employee: Bill Jones
    -

    - An improved compliant solution, which does not require guarding against null pointers within - - f() - - , uses references instead of pointers. -

    - - // ... Remainder of code unchanged ... +

    An improved compliant solution, which does not require guarding against null pointers within f(), uses references instead of pointers.

    + // ... Remainder of code unchanged ... void f(const Employee &e) { std::cout << e; @@ -185,43 +100,11 @@ int main() { f(coder); f(typist); f(designer); -} - +}
    -

    - Both previous compliant solutions depend on consumers of the - - Employee - - and - - Manager - - types to be declared in a compliant manner with the expected usage of the class hierarchy. This compliant solution ensures that consumers are unable to accidentally slice objects by removing the ability to copy-initialize an object that derives from - - Noncopyable - - . If copy-initialization is attempted, as in the original definition of - - f() - - , the program is - - ill-formed - - and a diagnostic will be emitted. However, such a solution also restricts the - - Manager - - object from attempting to copy-initialize its - - Employee - - object, which subtly changes the semantics of the class hierarchy. -

    - - #include <iostream> +

    Both previous compliant solutions depend on consumers of the Employee and Manager types to be declared in a compliant manner with the expected usage of the class hierarchy. This compliant solution ensures that consumers are unable to accidentally slice objects by removing the ability to copy-initialize an object that derives from Noncopyable. If copy-initialization is attempted, as in the original definition of f(), the program is ill-formed and a diagnostic will be emitted. However, such a solution also restricts the Manager object from attempting to copy-initialize its Employee object, which subtly changes the semantics of the class hierarchy.

    + #include <iostream> #include <string> class Noncopyable { @@ -264,7 +147,7 @@ public: Manager(const std::string &name, const Employee &assistant) : Employee(name), assistant(assistant) {} const Employee &get_assistant() const { return assistant; } }; -  + // If f() were declared as accepting an Employee, the program would be // ill-formed because Employee cannot be copy-initialized. void f(const Employee &e) { @@ -279,38 +162,14 @@ int main() { f(coder); f(typist); f(designer); -} - +}
    -

    - This noncompliant code example uses the same class definitions of - - Employee - - and - - Manager - - as in the previous noncompliant code example and attempts to store - - Employee - - objects in a - - std::vector - - . However, because - - std::vector - - requires a homogeneous list of elements, slicing occurs. -

    - - #include <iostream> +

    This noncompliant code example uses the same class definitions of Employee and Manager as in the previous noncompliant code example and attempts to store Employee objects in a std::vector. However, because std::vector requires a homogeneous list of elements, slicing occurs.

    + #include <iostream> #include <string> #include <vector> -  + void f(const std::vector<Employee> &v) { for (const auto &e : v) { std::cout << e; @@ -321,19 +180,11 @@ int main() { Employee typist("Joe Smith"); std::vector<Employee> v{typist, Employee("Bill Jones"), Manager("Jane Doe", typist)}; f(v); -} - +}
    -

    - This compliant solution uses a vector of - - std::unique_ptr - - objects, which eliminates the slicing problem. -

    - - #include <iostream> +

    This compliant solution uses a vector of std::unique_ptr objects, which eliminates the slicing problem.

    + #include <iostream> #include <memory> #include <string> #include <vector> @@ -352,17 +203,10 @@ int main() { v.emplace_back(new Manager("Jane Doe", *v.front())); f(v); -} - +}
    -

    - Slicing results in information loss, which could lead to abnormal program execution or - - denial-of-service attacks - - . -

    +

    Slicing results in information loss, which could lead to abnormal program execution or denial-of-service attacks.

    @@ -399,14 +243,10 @@ int main() { Medium @@ -429,6 +269,22 @@ int main() { Description + + + + + + @@ -456,9 +310,7 @@ int main() { 2021.2 @@ -506,14 +356,10 @@ int main() { @@ -522,17 +368,7 @@ int main() {
    - - P4 - + P4 - - L3 - + L3
    + + CodeSonar + + + 6.2p0 + + LANG.CAST.OBJSLICE + + Object Slicing +
    @@ -439,9 +295,7 @@ int main() { 2021.2 - - C++3072 - + C++3072 - - CERT_CPP-OOP51-a - + CERT_CPP-OOP51-a Avoid slicing function arguments / return value @@ -492,9 +344,7 @@ int main() { 4.4 - - 3072 - + 3072 - 7.16 + 7.17 - - - V1054 - - + V1054
    -

    - Search for other - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for other vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/OOP52-CPP/DoNotDeleteAPolymorphicObjectWithoutAVirtualDestructor-standard.qhelp b/cpp/cert/src/rules/OOP52-CPP/DoNotDeleteAPolymorphicObjectWithoutAVirtualDestructor-standard.qhelp index bad61be999..3c65030ab1 100644 --- a/cpp/cert/src/rules/OOP52-CPP/DoNotDeleteAPolymorphicObjectWithoutAVirtualDestructor-standard.qhelp +++ b/cpp/cert/src/rules/OOP52-CPP/DoNotDeleteAPolymorphicObjectWithoutAVirtualDestructor-standard.qhelp @@ -1,160 +1,48 @@
    -

    - The C++ Standard, [expr.delete], paragraph 3 - [ - - ISO/IEC 14882-2014 - - ], - states the following: -

    +

    The C++ Standard, [expr.delete], paragraph 3 [ISO/IEC 14882-2014], states the following:

    -

    - In the first alternative ( - - delete object - - ), if the static type of the object to be deleted is different from its dynamic type, the static type shall be a base class of the dynamic type of the object to be deleted and the static type shall have a virtual destructor or the behavior is undefined. In the second alternative ( - - delete array - - ) if the dynamic type of the object to be deleted differs from its static type, the behavior is undefined. -

    +

    In the first alternative (delete object), if the static type of the object to be deleted is different from its dynamic type, the static type shall be a base class of the dynamic type of the object to be deleted and the static type shall have a virtual destructor or the behavior is undefined. In the second alternative (delete array) if the dynamic type of the object to be deleted differs from its static type, the behavior is undefined.

    -

    - Do not delete an object of derived class type through a pointer to its base class type that has a non- - - virtual - - destructor. Instead, the base class should be defined with a - - virtual - - destructor. Deleting an object through a pointer to a type without a - - virtual - - destructor results in - - undefined behavior - - . -

    +

    Do not delete an object of derived class type through a pointer to its base class type that has a non-virtual destructor. Instead, the base class should be defined with a virtual destructor. Deleting an object through a pointer to a type without a virtual destructor results in undefined behavior.

    -

    - In this noncompliant example, - - b - - is a polymorphic pointer type whose static type is - - Base * - - and whose dynamic type is - - Derived * - - . When - - b - - is deleted, it results in - - undefined behavior - - because - - Base - - does not have a - - virtual - - destructor. The C++ Standard, [class.dtor], paragraph 4 - [ - - ISO/IEC 14882-2014 - - ], states the following - : -

    +

    In this noncompliant example, b is a polymorphic pointer type whose static type is Base * and whose dynamic type is Derived *. When b is deleted, it results in undefined behavior because Base does not have a virtual destructor. The C++ Standard, [class.dtor], paragraph 4 [ISO/IEC 14882-2014], states the following:

    -

    - If a class has no user-declared destructor, a destructor is implicitly declared as defaulted. An implicitly declared destructor is an - - inline public - - member of its class. -

    +

    If a class has no user-declared destructor, a destructor is implicitly declared as defaulted. An implicitly declared destructor is an inline public member of its class.

    -

    - The implicitly declared destructor is not declared as - - virtual - - even in the presence of other - - virtual - - functions. -

    - - struct Base { +

    The implicitly declared destructor is not declared as virtual even in the presence of other virtual functions.

    + struct Base { virtual void f(); }; -  + struct Derived : Base {}; -  + void f() { Base *b = new Derived(); // ... delete b; } - +
    -

    - In this noncompliant example, the explicit pointer operations have been replaced with a smart pointer object, demonstrating that smart pointers suffer from the same problem as other pointers. Because the default deleter for - - std::unique_ptr - - calls - - delete - - on the internal pointer value, the resulting behavior is identical to the previous noncompliant example. -

    - - #include <memory> -  +

    In this noncompliant example, the explicit pointer operations have been replaced with a smart pointer object, demonstrating that smart pointers suffer from the same problem as other pointers. Because the default deleter for std::unique_ptr calls delete on the internal pointer value, the resulting behavior is identical to the previous noncompliant example.

    + #include <memory> + struct Base { virtual void f(); }; -  + struct Derived : Base {}; -  + void f() { std::unique_ptr<Base> b = std::make_unique<Derived()>(); -} - +}
    -

    - In this compliant solution, the destructor for - - Base - - has an explicitly declared - - virtual - - destructor, ensuring that the polymorphic delete operation results in well-defined behavior. -

    - - struct Base { +

    In this compliant solution, the destructor for Base has an explicitly declared virtual destructor, ensuring that the polymorphic delete operation results in well-defined behavior.

    + struct Base { virtual ~Base() = default; virtual void f(); }; @@ -165,18 +53,11 @@ void f() { Base *b = new Derived(); // ... delete b; -} - +}
    -

    - - OOP52-CPP:EX0 - - : Deleting a polymorphic object without a virtual destructor is permitted if the object is referenced by a pointer to its class, rather than via a pointer to a class it inherits from. -

    - - class Base { +

    OOP52-CPP:EX0: Deleting a polymorphic object without a virtual destructor is permitted if the object is referenced by a pointer to its class, rather than via a pointer to a class it inherits from.

    + class Base { public: // ... virtual void AddRef() = 0; @@ -190,39 +71,10 @@ public: virtual void Destroy() { delete this; } private: ~Derived() {} -}; - -

    - Note that if - - Derived - - were not marked as - - final - - , then - - delete this - - could actually reference a subclass of - - Derived - - , violating this rule. -

    -

    - - OOP52-CPP:EX1 - - : Deleting a polymorphic object without a virtual destructor is permitted if its base class has a destroying - - operator delete - - that will figure out the correct derived class's destructor to call by other means. -

    - - #include <new> +}; +

    Note that if Derived were not marked as final, then delete this could actually reference a subclass of Derived, violating this rule.

    +

    OOP52-CPP:EX1: Deleting a polymorphic object without a virtual destructor is permitted if its base class has a destroying operator delete that will figure out the correct derived class's destructor to call by other means.

    + #include <new> class Base { const int whichDerived; @@ -261,25 +113,10 @@ void f() { Base *b = new Derived1(); // ... delete b; -} - +}
    -

    - Attempting to destruct a polymorphic object that does not have a - - virtual - - destructor declared results in - - undefined behavior - - . In practice, potential consequences include - - abnormal program termination - - and memory leaks. -

    +

    Attempting to destruct a polymorphic object that does not have a virtual destructor declared results in undefined behavior. In practice, potential consequences include abnormal program termination and memory leaks.

    @@ -316,14 +153,10 @@ void f() { Low @@ -356,9 +189,7 @@ void f() { 20.10 @@ -391,11 +220,25 @@ void f() { 3.9 + + + + + + @@ -408,9 +251,7 @@ void f() { 2021.2 @@ -425,16 +266,8 @@ void f() { 2021.4 @@ -448,9 +281,7 @@ void f() { @@ -516,20 +343,12 @@ void f() { @@ -544,9 +363,7 @@ void f() { 20.10 @@ -575,17 +388,7 @@ void f() {
    - - P9 - + P9 - - L2 - + L2
    - - non-virtual-public-destructor-in-non-final-class - + non-virtual-public-destructor-in-non-final-class Partially checked @@ -374,9 +205,7 @@ void f() { 7.2.0 - - CertC++-OOP52 - + CertC++-OOP52 - - -Wdelete-non-virtual-dtor - + -Wdelete-non-virtual-dtor + +
    + + CodeSonar + + + 6.2p0 + + LANG.STRUCT.DNVD + delete with Non-Virtual Destructor
    - - C++3402, C++3403, C++3404 - + C++3402, C++3403, C++3404 - - - CL.MLK.VIRTUAL - - - - - CWARN.DTOR.NONVIRT.DELETE - - + CL.MLK.VIRTUAL + CWARN.DTOR.NONVIRT.DELETE - - 303 S - + 303 S Partially implemented @@ -466,9 +297,7 @@ void f() { 2021.2 - - CERT_CPP-OOP52-a - + CERT_CPP-OOP52-a Define a virtual destructor in classes used as base classes which have virtual functions @@ -484,9 +313,7 @@ void f() { 4.4 - - 3402, 3403, 3404 - + 3402, 3403, 3404 - 7.16 + 7.17 - - V599 - - - + V599 , - - - V689 - - + V689 - - non-virtual-public-destructor-in-non-final-class - + non-virtual-public-destructor-in-non-final-class Partially checked @@ -562,11 +379,7 @@ void f() { 4.10 - - - S1235 - - + S1235
    -

    - Search for other - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for other vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/OOP53-CPP/UseCanonicalOrderForMemberInit-standard.qhelp b/cpp/cert/src/rules/OOP53-CPP/UseCanonicalOrderForMemberInit-standard.qhelp index 36643b6f59..3bb97d30f0 100644 --- a/cpp/cert/src/rules/OOP53-CPP/UseCanonicalOrderForMemberInit-standard.qhelp +++ b/cpp/cert/src/rules/OOP53-CPP/UseCanonicalOrderForMemberInit-standard.qhelp @@ -1,134 +1,47 @@
    -

    - The member initializer list for a class constructor allows members to be initialized to specified values and for base class constructors to be called with specific arguments. However, the order in which initialization occurs is fixed and does not depend on the order written in the member initializer list. The C++ Standard, [class.base.init], paragraph 11 [ - - ISO/IEC 14882-2014 - - ], states the following: -

    +

    The member initializer list for a class constructor allows members to be initialized to specified values and for base class constructors to be called with specific arguments. However, the order in which initialization occurs is fixed and does not depend on the order written in the member initializer list. The C++ Standard, [class.base.init], paragraph 11 [ISO/IEC 14882-2014], states the following:

    -

    - In a non-delegating constructor, initialization proceeds in the following order: - — First, and only for the constructor of the most derived class, virtual base classes are initialized in the order they appear on a depth-first left-to-right traversal of the directed acyclic graph of base classes, where “left-to-right” is the order of appearance of the base classes in the derived class base-specifier-list. - — Then, direct base classes are initialized in declaration order as they appear in the base-specifier-list (regardless of the order of the mem-initializers). - — Then, non-static data members are initialized in the order they were declared in the class definition (again regardless of the order of the mem-initializers). - — Finally, the compound-statement of the constructor body is executed. - [Note: The declaration order is mandated to ensure that base and member subobjects are destroyed in the reverse order of initialization. —end note] -

    +

    In a non-delegating constructor, initialization proceeds in the following order:— First, and only for the constructor of the most derived class, virtual base classes are initialized in the order they appear on a depth-first left-to-right traversal of the directed acyclic graph of base classes, where “left-to-right” is the order of appearance of the base classes in the derived class base-specifier-list.— Then, direct base classes are initialized in declaration order as they appear in the base-specifier-list (regardless of the order of the mem-initializers).— Then, non-static data members are initialized in the order they were declared in the class definition (again regardless of the order of the mem-initializers).— Finally, the compound-statement of the constructor body is executed.[Note: The declaration order is mandated to ensure that base and member subobjects are destroyed in the reverse order of initialization. —end note]

    -

    - Consequently, the order in which member initializers appear in the member initializer list is irrelevant. The order in which members are initialized, including base class initialization, is determined by the declaration order of the class member variables or the base class specifier list. Writing member initializers other than in canonical order can result in - - undefined behavior - - , such as reading uninitialized memory. -

    -

    - Always write member initializers in a constructor in the canonical order: first, direct base classes in the order in which they appear in the - - base-specifier-list - - for the class, then nonstatic data members in the order in which they are declared in the class definition. -

    +

    Consequently, the order in which member initializers appear in the member initializer list is irrelevant. The order in which members are initialized, including base class initialization, is determined by the declaration order of the class member variables or the base class specifier list. Writing member initializers other than in canonical order can result in undefined behavior, such as reading uninitialized memory.

    +

    Always write member initializers in a constructor in the canonical order: first, direct base classes in the order in which they appear in the base-specifier-list for the class, then nonstatic data members in the order in which they are declared in the class definition.

    -

    - In this noncompliant code example, the member initializer list for - - C::C() - - attempts to initialize - - someVal - - first and then to initialize - - dependsOnSomeVal - - to a value dependent on - - someVal - - . Because the declaration order of the member variables does not match the member initializer order, attempting to read the value of - - someVal - - results in an - - unspecified value - - being stored into - dependsOnSomeVal - . -

    - - class C { +

    In this noncompliant code example, the member initializer list for C::C() attempts to initialize someVal first and then to initialize dependsOnSomeVal to a value dependent on someVal. Because the declaration order of the member variables does not match the member initializer order, attempting to read the value of someVal results in an unspecified value being stored into dependsOnSomeVal.

    + class C { int dependsOnSomeVal; int someVal; -  + public: C(int val) : someVal(val), dependsOnSomeVal(someVal + 1) {} -}; - +};
    -

    - This compliant solution changes the declaration order of the class member variables so that the dependency can be ordered properly in the constructor's member initializer list. -

    - - class C { +

    This compliant solution changes the declaration order of the class member variables so that the dependency can be ordered properly in the constructor's member initializer list.

    + class C { int someVal; int dependsOnSomeVal; -  + public: C(int val) : someVal(val), dependsOnSomeVal(someVal + 1) {} }; - -

    - It is reasonable for initializers to depend on previously initialized values. -

    +
    +

    It is reasonable for initializers to depend on previously initialized values.

    -

    - In this noncompliant code example, the derived class, - - D - - , attempts to initialize the base class, - - B1 - - , with a value obtained from the base class, - - B2 - - . However, because - - B1 - - is initialized before - - B2 - - due to the declaration order in the base class specifier list, the resulting behavior is - - undefined - - . -

    - - class B1 { +

    In this noncompliant code example, the derived class, D, attempts to initialize the base class, B1, with a value obtained from the base class, B2. However, because B1 is initialized before B2 due to the declaration order in the base class specifier list, the resulting behavior is undefined.

    + class B1 { int val; -  + public: B1(int val) : val(val) {} }; class B2 { int otherVal; -  + public: B2(int otherVal) : otherVal(otherVal) {} int get_other_val() const { return otherVal; } @@ -137,15 +50,11 @@ public: class D : B1, B2 { public: D(int a) : B2(a), B1(get_other_val()) {} -}; - +};
    -

    - This compliant solution initializes both base classes using the same value from the constructor's parameter list instead of relying on the initialization order of the base classes. -

    - - class B1 { +

    This compliant solution initializes both base classes using the same value from the constructor's parameter list instead of relying on the initialization order of the base classes.

    + class B1 { int val; public: @@ -162,16 +71,10 @@ public: class D : B1, B2 { public: D(int a) : B1(a), B2(a) {} -}; - +};
    -

    - - OOP53-CPP-EX0: - - Constructors that do not use member initializers do not violate this rule. -

    +

    OOP53-CPP-EX0: Constructors that do not use member initializers do not violate this rule.

    @@ -210,14 +113,10 @@ public: Medium @@ -250,9 +149,7 @@ public: 20.10 @@ -285,11 +180,25 @@ public: 3.9 + + + + + + @@ -302,9 +211,7 @@ public: 2021.2 @@ -319,11 +226,7 @@ public: 2021.4 @@ -337,9 +240,7 @@ public: @@ -408,9 +305,7 @@ public: 20.10 @@ -439,17 +330,7 @@ public:
    - - P4 - + P4 - - L3 - + L3
    - - initializer-list-order - + initializer-list-order Fully checked @@ -268,9 +165,7 @@ public: 7.2.0 - - CertC++-OOP53 - + CertC++-OOP53 - - -Wreorder - + -Wreorder + +
    + + CodeSonar + + + 6.2p0 + + LANG.STRUCT.INIT.OOMI + Out of Order Member Initializers
    - - C++4053 - + C++4053 - - - CERT.OOP.CTOR.INIT_ORDER - - + CERT.OOP.CTOR.INIT_ORDER - - 206 S - + 206 S Fully implemented @@ -355,9 +256,7 @@ public: 2021.2 - - CERT_CPP-OOP53-a - + CERT_CPP-OOP53-a List members in an initialization list in the order in which they are declared @@ -391,9 +290,7 @@ public: 4.4 - - 4053 - + 4053 - - initializer-list-order - + initializer-list-order Fully checked @@ -426,11 +321,7 @@ public: 4.10 - - - S3229 - - + S3229
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/OOP54-CPP/GracefullyHandleSelfCopyAssignment-standard.qhelp b/cpp/cert/src/rules/OOP54-CPP/GracefullyHandleSelfCopyAssignment-standard.qhelp index 86f637e3b6..a704a0a3e5 100644 --- a/cpp/cert/src/rules/OOP54-CPP/GracefullyHandleSelfCopyAssignment-standard.qhelp +++ b/cpp/cert/src/rules/OOP54-CPP/GracefullyHandleSelfCopyAssignment-standard.qhelp @@ -1,129 +1,54 @@
    -

    - Self-copy assignment can occur in situations of varying complexity, but essentially, all self-copy assignments entail some variation of the following. -

    - - #include <utility> -  +

    Self-copy assignment can occur in situations of varying complexity, but essentially, all self-copy assignments entail some variation of the following.

    + #include <utility> + struct S { /* ... */ } -  + void f() { S s; s = s; // Self-copy assignment -} - -

    - User-provided copy operators must properly handle self-copy assignment. -

    -

    - The postconditions required for copy assignment are specified by the C++ Standard, [utility.arg.requirements], Table 23 [ - - ISO/IEC 14882-2014 - - ], which states that for - - x = y - - , the value of - - y - - is unchanged. When - - &x == &y - - , this postcondition translates into the values of both - - x - - and - - y - - remaining unchanged. A naive implementation of copy assignment could destroy object-local resources in the process of copying resources from the given parameter. If the given parameter is the same object as the local object, the act of destroying object-local resources will invalidate them. The subsequent copy of those resources will be left in an indeterminate state, which violates the postcondition. -

    -

    - A user-provided copy assignment operator must prevent self-copy assignment from leaving the object in an indeterminate state. This can be accomplished by self-assignment tests, copy-and-swap, or other idiomatic design patterns. -

    -

    - The C++ Standard, [copyassignable], specifies that types must ensure that self-copy assignment leave the object in a consistent state when passed to Standard Template Library (STL) functions. Since objects of STL types are used in contexts where - - CopyAssignable - - is required, STL types are required to gracefully handle self-copy assignment. -

    +}
    +

    User-provided copy operators must properly handle self-copy assignment.

    +

    The postconditions required for copy assignment are specified by the C++ Standard, [utility.arg.requirements], Table 23 [ISO/IEC 14882-2014], which states that for x = y, the value of y is unchanged. When &x == &y, this postcondition translates into the values of both x and y remaining unchanged. A naive implementation of copy assignment could destroy object-local resources in the process of copying resources from the given parameter. If the given parameter is the same object as the local object, the act of destroying object-local resources will invalidate them. The subsequent copy of those resources will be left in an indeterminate state, which violates the postcondition.

    +

    A user-provided copy assignment operator must prevent self-copy assignment from leaving the object in an indeterminate state. This can be accomplished by self-assignment tests, copy-and-swap, or other idiomatic design patterns.

    +

    The C++ Standard, [copyassignable], specifies that types must ensure that self-copy assignment leave the object in a consistent state when passed to Standard Template Library (STL) functions. Since objects of STL types are used in contexts where CopyAssignable is required, STL types are required to gracefully handle self-copy assignment.

    -

    - In this noncompliant code example, the copy assignment operator does not protect against self-copy assignment. If self-copy assignment occurs, - - this->s1 - - is deleted, which results in - - rhs.s1 - - also being deleted. The invalidated memory for - - rhs.s1 - - is then passed into the copy constructor for - - S - - , which can result in dereferencing an - - invalid pointer - - . -

    - - #include <new> -  +

    In this noncompliant code example, the copy assignment operator does not protect against self-copy assignment. If self-copy assignment occurs, this->s1 is deleted, which results in rhs.s1 also being deleted. The invalidated memory for rhs.s1 is then passed into the copy constructor for S, which can result in dereferencing an invalid pointer.

    + #include <new> + struct S { S(const S &) noexcept; /* ... */ }; -  + class T { int n; S *s1; -  + public: T(const T &rhs) : n(rhs.n), s1(rhs.s1 ? new S(*rhs.s1) : nullptr) {} ~T() { delete s1; } -  + // ... -  + T& operator=(const T &rhs) { n = rhs.n; delete s1; s1 = new S(*rhs.s1); return *this; } -}; - +};
    -

    - This compliant solution guards against self-copy assignment by testing whether the given parameter is the same as - - this - - . If self-copy assignment occurs, then - - operator= - - does nothing; otherwise, the copy proceeds as in the original example. -

    - - #include <new> +

    This compliant solution guards against self-copy assignment by testing whether the given parameter is the same as this. If self-copy assignment occurs, then operator= does nothing; otherwise, the copy proceeds as in the original example.

    + #include <new> struct S { S(const S &) noexcept; /* ... */ }; class T { int n; S *s1; -  + public: T(const T &rhs) : n(rhs.n), s1(rhs.s1 ? new S(*rhs.s1) : nullptr) {} ~T() { delete s1; } @@ -144,45 +69,12 @@ public: return *this; } }; - -

    - This solution does not provide a - - strong exception - - guarantee for the copy assignment. Specifically, if an exception is called when evaluating the - - new - - expression, - - this - - has already been modified. However, this solution does provide a basic exception guarantee because no resources are leaked and all data members contain valid values. Consequently, this code complies with - - ERR56-CPP. Guarantee exception safety - - . -

    +
    +

    This solution does not provide a strong exception guarantee for the copy assignment. Specifically, if an exception is called when evaluating the new expression, this has already been modified. However, this solution does provide a basic exception guarantee because no resources are leaked and all data members contain valid values. Consequently, this code complies with ERR56-CPP. Guarantee exception safety.

    -

    - This compliant solution avoids self-copy assignment by constructing a temporary object from - - rhs - - that is then swapped with - - *this - - . This compliant solution provides a strong exception guarantee because - - swap() - - will never be called if resource allocation results in an exception being thrown while creating the temporary object. -

    - - #include <new> +

    This compliant solution avoids self-copy assignment by constructing a temporary object from rhs that is then swapped with *this. This compliant solution provides a strong exception guarantee because swap() will never be called if resource allocation results in an exception being thrown while creating the temporary object.

    + #include <new> #include <utility> struct S { S(const S &) noexcept; /* ... */ }; @@ -196,7 +88,7 @@ public: ~T() { delete s1; } // ... -  + void swap(T &rhs) noexcept { using std::swap; swap(n, rhs.n); @@ -207,23 +99,11 @@ public: rhs.swap(*this); return *this; } -}; - +};
    -

    - This compliant solution uses the same classes - - S - - and - - T - - from the previous compliant solution, but adds the following public constructor and methods: -

    - - T(T &&rhs) { *this = std::move(rhs); } +

    This compliant solution uses the same classes S and T from the previous compliant solution, but adds the following public constructor and methods:

    + T(T &&rhs) { *this = std::move(rhs); } // ... everything except operator= .. @@ -232,34 +112,13 @@ public: swap(n, rhs.n); swap(s1, rhs.s1); return *this; - } - -

    - The copy assignment operator uses - - std::move() - - rather than - - swap() - - to achieve safe self-assignment and a strong exception guarantee. The move assignment operator uses a move (via the method parameter) and swap. -

    -

    - The move constructor is not strictly necessary, but defining a move constructor along with a move assignment operator is conventional for classes that support move operations. -

    -

    - Note that unlike copy assignment operators, the signature of a move assignment operator accepts a non-const reference to its object with the expectation that the moved-from object will be left in an unspecified, but valid state. Move constructors have the same difference from copy constructors. -

    + }
    +

    The copy assignment operator uses std::move() rather than swap() to achieve safe self-assignment and a strong exception guarantee. The move assignment operator uses a move (via the method parameter) and swap.

    +

    The move constructor is not strictly necessary, but defining a move constructor along with a move assignment operator is conventional for classes that support move operations.

    +

    Note that unlike copy assignment operators, the signature of a move assignment operator accepts a non-const reference to its object with the expectation that the moved-from object will be left in an unspecified, but valid state. Move constructors have the same difference from copy constructors.

    -

    - Allowing a copy assignment operator to corrupt an object could lead to - - undefined behavior - - . -

    +

    Allowing a copy assignment operator to corrupt an object could lead to undefined behavior.

    @@ -296,14 +155,10 @@ public: High @@ -336,9 +191,7 @@ public: 20.10 @@ -353,15 +206,11 @@ public: 9.0 (r361550) @@ -375,9 +224,7 @@ public: 2021.2 @@ -392,11 +239,7 @@ public: 2021.4 @@ -411,9 +254,7 @@ public: 2021.2 @@ -458,26 +297,10 @@ public:
    - - P2 - + P2 - - L3 - + L3
    - - dangling_pointer_use - + dangling_pointer_use - - cert-oop54-cpp - + cert-oop54-cpp Checked by - - clang-tidy - + clang-tidy .
    - - C++4072, C++4073, C++4075, C++4076 - + C++4072, C++4073, C++4075, C++4076 - - - CL.SELF-ASSIGN - - + CL.SELF-ASSIGN - - CERT_CPP-OOP54-a - + CERT_CPP-OOP54-a Check for assignment to self in operator= @@ -447,9 +288,7 @@ public: 4.4 - - 4072, 4073, 4075, 4076 - + 4072, 4073, 4075, 4076
    -

    - Search for other - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for other vulnerabilities resulting from the violation of this rule on the CERT website.

    -

    - This rule is a partial subset of - - OOP58-CPP. Copy operations must not mutate the source object - - when copy operations do not gracefully handle self-copy assignment, because the copy operation may mutate both the source and destination objects (due to them being the same object). -

    +

    This rule is a partial subset of OOP58-CPP. Copy operations must not mutate the source object when copy operations do not gracefully handle self-copy assignment, because the copy operation may mutate both the source and destination objects (due to them being the same object).

    @@ -517,9 +340,7 @@ public: diff --git a/cpp/cert/src/rules/OOP55-CPP/MemberAccessWithUninitializedStaticPointerToMember-standard.qhelp b/cpp/cert/src/rules/OOP55-CPP/MemberAccessWithUninitializedStaticPointerToMember-standard.qhelp index e7d9026a70..0f93c06587 100644 --- a/cpp/cert/src/rules/OOP55-CPP/MemberAccessWithUninitializedStaticPointerToMember-standard.qhelp +++ b/cpp/cert/src/rules/OOP55-CPP/MemberAccessWithUninitializedStaticPointerToMember-standard.qhelp @@ -1,27 +1,8 @@
    -

    - The pointer-to-member operators - - .* - - and - - ->* - - are used to obtain an object or a function as though it were a member of an underlying object. For instance, the following are functionally equivalent ways to call the member function - - f() - - on the object - - o - - . -

    - - struct S { +

    The pointer-to-member operators .* and ->* are used to obtain an object or a function as though it were a member of an underlying object. For instance, the following are functionally equivalent ways to call the member function f() on the object o.

    + struct S { void f() {} }; @@ -31,141 +12,22 @@ void func() { o.f(); (o.*pm)(); -} - -

    - The call of the form - - o.f() - - uses class member access at compile time to look up the address of the function - - S::f() - - on the object - - o - - . The call of the form - - (o.*pm)() - - uses the pointer-to-member operator - - .* - - to call the function at the address specified by - - pm - - . In both cases, the object - - o - - is the implicit - - this - - object within the member function - - S::f() - - . -

    -

    - The C++ Standard, [expr.mptr.oper], paragraph 4 - [ - - ISO/IEC 14882-2014 - - ] - , states - the following - : -

    +}
    +

    The call of the form o.f() uses class member access at compile time to look up the address of the function S::f() on the object o. The call of the form (o.*pm)() uses the pointer-to-member operator .* to call the function at the address specified by pm. In both cases, the object o is the implicit this object within the member function S::f().

    +

    The C++ Standard, [expr.mptr.oper], paragraph 4 [ISO/IEC 14882-2014], states the following:

    -

    - Abbreviating - - pm-expression.*cast-expression - - as - - E1.*E2 - - , - - E1 - - is called the - - object expression - - . If the dynamic type of - - E1 - - does not contain the member to which - - E2 - - refers, the behavior is undefined. -

    +

    Abbreviating pm-expression.*cast-expression as E1.*E2, E1 is called the object expression. If the dynamic type of E1 does not contain the member to which E2 refers, the behavior is undefined.

    -

    - A pointer-to-member expression of the form - - E1->*E2 - - is converted to its equivalent form, - - (*(E1)).*E2 - - , so use of pointer-to-member expressions of either form behave equivalently in terms of - - undefined behavior - - . -

    -

    - Further, the C++ Standard, - [expr.mptr.oper], paragraph 6, in part, states the following: -

    +

    A pointer-to-member expression of the form E1->*E2 is converted to its equivalent form, (*(E1)).*E2, so use of pointer-to-member expressions of either form behave equivalently in terms of undefined behavior.

    +

    Further, the C++ Standard, [expr.mptr.oper], paragraph 6, in part, states the following:

    -

    - If the second operand is the null pointer to member value, the behavior is undefined. -

    +

    If the second operand is the null pointer to member value, the behavior is undefined.

    -

    - Do not use a pointer-to-member expression where the dynamic type of the first operand does not contain the member to which the second operand refers, including the use of a null pointer-to-member value as the second operand. -

    +

    Do not use a pointer-to-member expression where the dynamic type of the first operand does not contain the member to which the second operand refers, including the use of a null pointer-to-member value as the second operand.

    -

    - In this noncompliant code example, a pointer-to-member object is obtained from - - D::g - - but is then upcast to be a - - B::* - - . When called on an object whose dynamic type is - - D - - , the pointer-to-member call is well defined. However, the dynamic type of the underlying object is - - B - - , which results in - - undefined behavior - - . -

    - - struct B { +

    In this noncompliant code example, a pointer-to-member object is obtained from D::g but is then upcast to be a B::*. When called on an object whose dynamic type is D, the pointer-to-member call is well defined. However, the dynamic type of the underlying object is B, which results in undefined behavior.

    + struct B { virtual ~B() = default; }; @@ -176,29 +38,18 @@ struct D : B { void f() { B *b = new B; -  + // ... -  + void (B::*gptr)() = static_cast<void(B::*)()>(&D::g); (b->*gptr)(); delete b; } - +
    -

    - In this compliant solution, the upcast is removed, rendering the initial code - - ill-formed - - and emphasizing the underlying problem that - - B::g() - - does not exist. This compliant solution assumes that the programmer's intention was to use the correct dynamic type for the underlying object. -

    - - struct B { +

    In this compliant solution, the upcast is removed, rendering the initial code ill-formed and emphasizing the underlying problem that B::g() does not exist. This compliant solution assumes that the programmer's intention was to use the correct dynamic type for the underlying object.

    + struct B { virtual ~B() = default; }; @@ -209,24 +60,17 @@ struct D : B { void f() { B *b = new D; // Corrected the dynamic object type. -  + // ... void (D::*gptr)() = &D::g; // Moved static_cast to the next line. (static_cast<D *>(b)->*gptr)(); delete b; } - +
    -

    - In this noncompliant code example, a null pointer-to-member value is passed as the second operand to a pointer-to-member expression, resulting in - - undefined behavior - - . -

    - - struct B { +

    In this noncompliant code example, a null pointer-to-member value is passed as the second operand to a pointer-to-member expression, resulting in undefined behavior.

    + struct B { virtual ~B() = default; }; @@ -234,52 +78,39 @@ struct D : B { virtual ~D() = default; virtual void g() { /* ... */ } }; -  + static void (D::*gptr)(); // Not explicitly initialized, defaults to nullptr. void call_memptr(D *ptr) { (ptr->*gptr)(); } -  + void f() { D *d = new D; call_memptr(d); delete d; -} - +}
    -

    - In this compliant solution, - - gptr - - is properly initialized to a valid pointer-to-member value instead of to the default value of - - nullptr - - . -

    - - struct B { +

    In this compliant solution, gptr is properly initialized to a valid pointer-to-member value instead of to the default value of nullptr.

    + struct B { virtual ~B() = default; }; -  + struct D : B { virtual ~D() = default; virtual void g() { /* ... */ } }; -  + static void (D::*gptr)() = &D::g; // Explicitly initialized. void call_memptr(D *ptr) { (ptr->*gptr)(); } -  + void f() { D *d = new D; call_memptr(d); delete d; -} - +}
    Item 11, "Handle Assignment to Self in - - operator= - + operator= "
    @@ -318,14 +149,10 @@ void f() { High @@ -358,10 +185,7 @@ void f() { 20.10 @@ -376,9 +200,7 @@ void f() { 7.2.0 @@ -393,9 +215,7 @@ void f() { 2021.2 @@ -410,11 +230,7 @@ void f() { 2021.4 @@ -429,9 +245,7 @@ void f() { 2021.2 @@ -472,28 +284,10 @@ void f() {
    - - P6 - + P6 - - L2 - + L2
    - - overflow_upon_dereference - invalid_function_pointer - + overflow_upon_dereferenceinvalid_function_pointer - - CertC++-OOP55 - + CertC++-OOP55 - - C++2810, C++2811, C++2812, C++2813, C++2814 - + C++2810, C++2811, C++2812, C++2813, C++2814 - - - CERT.OOP.PTR_MEMBER.NO_MEMBER - - + CERT.OOP.PTR_MEMBER.NO_MEMBER - - CERT_CPP-OOP55-a - + CERT_CPP-OOP55-a A cast shall not convert a pointer to a function to any other pointer type, including a pointer to function type @@ -461,9 +275,7 @@ void f() { 4.4 - - 2810, 2811, 2812, 2813, 2814 - + 2810, 2811, 2812, 2813, 2814
    -

    - Search for other - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for other vulnerabilities resulting from the violation of this rule on the CERT website.

    -

    - - This rule is a subset of - - EXP34-C. Do not dereference null pointers - - . - -

    +

    This rule is a subset of EXP34-C. Do not dereference null pointers.

    diff --git a/cpp/cert/src/rules/OOP55-CPP/UseOfPointerToMemberToAccessNonexistentMember-standard.qhelp b/cpp/cert/src/rules/OOP55-CPP/UseOfPointerToMemberToAccessNonexistentMember-standard.qhelp index e7d9026a70..0f93c06587 100644 --- a/cpp/cert/src/rules/OOP55-CPP/UseOfPointerToMemberToAccessNonexistentMember-standard.qhelp +++ b/cpp/cert/src/rules/OOP55-CPP/UseOfPointerToMemberToAccessNonexistentMember-standard.qhelp @@ -1,27 +1,8 @@
    -

    - The pointer-to-member operators - - .* - - and - - ->* - - are used to obtain an object or a function as though it were a member of an underlying object. For instance, the following are functionally equivalent ways to call the member function - - f() - - on the object - - o - - . -

    - - struct S { +

    The pointer-to-member operators .* and ->* are used to obtain an object or a function as though it were a member of an underlying object. For instance, the following are functionally equivalent ways to call the member function f() on the object o.

    + struct S { void f() {} }; @@ -31,141 +12,22 @@ void func() { o.f(); (o.*pm)(); -} - -

    - The call of the form - - o.f() - - uses class member access at compile time to look up the address of the function - - S::f() - - on the object - - o - - . The call of the form - - (o.*pm)() - - uses the pointer-to-member operator - - .* - - to call the function at the address specified by - - pm - - . In both cases, the object - - o - - is the implicit - - this - - object within the member function - - S::f() - - . -

    -

    - The C++ Standard, [expr.mptr.oper], paragraph 4 - [ - - ISO/IEC 14882-2014 - - ] - , states - the following - : -

    +}
    +

    The call of the form o.f() uses class member access at compile time to look up the address of the function S::f() on the object o. The call of the form (o.*pm)() uses the pointer-to-member operator .* to call the function at the address specified by pm. In both cases, the object o is the implicit this object within the member function S::f().

    +

    The C++ Standard, [expr.mptr.oper], paragraph 4 [ISO/IEC 14882-2014], states the following:

    -

    - Abbreviating - - pm-expression.*cast-expression - - as - - E1.*E2 - - , - - E1 - - is called the - - object expression - - . If the dynamic type of - - E1 - - does not contain the member to which - - E2 - - refers, the behavior is undefined. -

    +

    Abbreviating pm-expression.*cast-expression as E1.*E2, E1 is called the object expression. If the dynamic type of E1 does not contain the member to which E2 refers, the behavior is undefined.

    -

    - A pointer-to-member expression of the form - - E1->*E2 - - is converted to its equivalent form, - - (*(E1)).*E2 - - , so use of pointer-to-member expressions of either form behave equivalently in terms of - - undefined behavior - - . -

    -

    - Further, the C++ Standard, - [expr.mptr.oper], paragraph 6, in part, states the following: -

    +

    A pointer-to-member expression of the form E1->*E2 is converted to its equivalent form, (*(E1)).*E2, so use of pointer-to-member expressions of either form behave equivalently in terms of undefined behavior.

    +

    Further, the C++ Standard, [expr.mptr.oper], paragraph 6, in part, states the following:

    -

    - If the second operand is the null pointer to member value, the behavior is undefined. -

    +

    If the second operand is the null pointer to member value, the behavior is undefined.

    -

    - Do not use a pointer-to-member expression where the dynamic type of the first operand does not contain the member to which the second operand refers, including the use of a null pointer-to-member value as the second operand. -

    +

    Do not use a pointer-to-member expression where the dynamic type of the first operand does not contain the member to which the second operand refers, including the use of a null pointer-to-member value as the second operand.

    -

    - In this noncompliant code example, a pointer-to-member object is obtained from - - D::g - - but is then upcast to be a - - B::* - - . When called on an object whose dynamic type is - - D - - , the pointer-to-member call is well defined. However, the dynamic type of the underlying object is - - B - - , which results in - - undefined behavior - - . -

    - - struct B { +

    In this noncompliant code example, a pointer-to-member object is obtained from D::g but is then upcast to be a B::*. When called on an object whose dynamic type is D, the pointer-to-member call is well defined. However, the dynamic type of the underlying object is B, which results in undefined behavior.

    + struct B { virtual ~B() = default; }; @@ -176,29 +38,18 @@ struct D : B { void f() { B *b = new B; -  + // ... -  + void (B::*gptr)() = static_cast<void(B::*)()>(&D::g); (b->*gptr)(); delete b; } - +
    -

    - In this compliant solution, the upcast is removed, rendering the initial code - - ill-formed - - and emphasizing the underlying problem that - - B::g() - - does not exist. This compliant solution assumes that the programmer's intention was to use the correct dynamic type for the underlying object. -

    - - struct B { +

    In this compliant solution, the upcast is removed, rendering the initial code ill-formed and emphasizing the underlying problem that B::g() does not exist. This compliant solution assumes that the programmer's intention was to use the correct dynamic type for the underlying object.

    + struct B { virtual ~B() = default; }; @@ -209,24 +60,17 @@ struct D : B { void f() { B *b = new D; // Corrected the dynamic object type. -  + // ... void (D::*gptr)() = &D::g; // Moved static_cast to the next line. (static_cast<D *>(b)->*gptr)(); delete b; } - +
    -

    - In this noncompliant code example, a null pointer-to-member value is passed as the second operand to a pointer-to-member expression, resulting in - - undefined behavior - - . -

    - - struct B { +

    In this noncompliant code example, a null pointer-to-member value is passed as the second operand to a pointer-to-member expression, resulting in undefined behavior.

    + struct B { virtual ~B() = default; }; @@ -234,52 +78,39 @@ struct D : B { virtual ~D() = default; virtual void g() { /* ... */ } }; -  + static void (D::*gptr)(); // Not explicitly initialized, defaults to nullptr. void call_memptr(D *ptr) { (ptr->*gptr)(); } -  + void f() { D *d = new D; call_memptr(d); delete d; -} - +}
    -

    - In this compliant solution, - - gptr - - is properly initialized to a valid pointer-to-member value instead of to the default value of - - nullptr - - . -

    - - struct B { +

    In this compliant solution, gptr is properly initialized to a valid pointer-to-member value instead of to the default value of nullptr.

    + struct B { virtual ~B() = default; }; -  + struct D : B { virtual ~D() = default; virtual void g() { /* ... */ } }; -  + static void (D::*gptr)() = &D::g; // Explicitly initialized. void call_memptr(D *ptr) { (ptr->*gptr)(); } -  + void f() { D *d = new D; call_memptr(d); delete d; -} - +}
    @@ -318,14 +149,10 @@ void f() { High @@ -358,10 +185,7 @@ void f() { 20.10 @@ -376,9 +200,7 @@ void f() { 7.2.0 @@ -393,9 +215,7 @@ void f() { 2021.2 @@ -410,11 +230,7 @@ void f() { 2021.4 @@ -429,9 +245,7 @@ void f() { 2021.2 @@ -472,28 +284,10 @@ void f() {
    - - P6 - + P6 - - L2 - + L2
    - - overflow_upon_dereference - invalid_function_pointer - + overflow_upon_dereferenceinvalid_function_pointer - - CertC++-OOP55 - + CertC++-OOP55 - - C++2810, C++2811, C++2812, C++2813, C++2814 - + C++2810, C++2811, C++2812, C++2813, C++2814 - - - CERT.OOP.PTR_MEMBER.NO_MEMBER - - + CERT.OOP.PTR_MEMBER.NO_MEMBER - - CERT_CPP-OOP55-a - + CERT_CPP-OOP55-a A cast shall not convert a pointer to a function to any other pointer type, including a pointer to function type @@ -461,9 +275,7 @@ void f() { 4.4 - - 2810, 2811, 2812, 2813, 2814 - + 2810, 2811, 2812, 2813, 2814
    -

    - Search for other - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for other vulnerabilities resulting from the violation of this rule on the CERT website.

    -

    - - This rule is a subset of - - EXP34-C. Do not dereference null pointers - - . - -

    +

    This rule is a subset of EXP34-C. Do not dereference null pointers.

    diff --git a/cpp/cert/src/rules/OOP55-CPP/UseOfPointerToMemberToAccessUndefinedMember-standard.qhelp b/cpp/cert/src/rules/OOP55-CPP/UseOfPointerToMemberToAccessUndefinedMember-standard.qhelp index e7d9026a70..0f93c06587 100644 --- a/cpp/cert/src/rules/OOP55-CPP/UseOfPointerToMemberToAccessUndefinedMember-standard.qhelp +++ b/cpp/cert/src/rules/OOP55-CPP/UseOfPointerToMemberToAccessUndefinedMember-standard.qhelp @@ -1,27 +1,8 @@
    -

    - The pointer-to-member operators - - .* - - and - - ->* - - are used to obtain an object or a function as though it were a member of an underlying object. For instance, the following are functionally equivalent ways to call the member function - - f() - - on the object - - o - - . -

    - - struct S { +

    The pointer-to-member operators .* and ->* are used to obtain an object or a function as though it were a member of an underlying object. For instance, the following are functionally equivalent ways to call the member function f() on the object o.

    + struct S { void f() {} }; @@ -31,141 +12,22 @@ void func() { o.f(); (o.*pm)(); -} - -

    - The call of the form - - o.f() - - uses class member access at compile time to look up the address of the function - - S::f() - - on the object - - o - - . The call of the form - - (o.*pm)() - - uses the pointer-to-member operator - - .* - - to call the function at the address specified by - - pm - - . In both cases, the object - - o - - is the implicit - - this - - object within the member function - - S::f() - - . -

    -

    - The C++ Standard, [expr.mptr.oper], paragraph 4 - [ - - ISO/IEC 14882-2014 - - ] - , states - the following - : -

    +}
    +

    The call of the form o.f() uses class member access at compile time to look up the address of the function S::f() on the object o. The call of the form (o.*pm)() uses the pointer-to-member operator .* to call the function at the address specified by pm. In both cases, the object o is the implicit this object within the member function S::f().

    +

    The C++ Standard, [expr.mptr.oper], paragraph 4 [ISO/IEC 14882-2014], states the following:

    -

    - Abbreviating - - pm-expression.*cast-expression - - as - - E1.*E2 - - , - - E1 - - is called the - - object expression - - . If the dynamic type of - - E1 - - does not contain the member to which - - E2 - - refers, the behavior is undefined. -

    +

    Abbreviating pm-expression.*cast-expression as E1.*E2, E1 is called the object expression. If the dynamic type of E1 does not contain the member to which E2 refers, the behavior is undefined.

    -

    - A pointer-to-member expression of the form - - E1->*E2 - - is converted to its equivalent form, - - (*(E1)).*E2 - - , so use of pointer-to-member expressions of either form behave equivalently in terms of - - undefined behavior - - . -

    -

    - Further, the C++ Standard, - [expr.mptr.oper], paragraph 6, in part, states the following: -

    +

    A pointer-to-member expression of the form E1->*E2 is converted to its equivalent form, (*(E1)).*E2, so use of pointer-to-member expressions of either form behave equivalently in terms of undefined behavior.

    +

    Further, the C++ Standard, [expr.mptr.oper], paragraph 6, in part, states the following:

    -

    - If the second operand is the null pointer to member value, the behavior is undefined. -

    +

    If the second operand is the null pointer to member value, the behavior is undefined.

    -

    - Do not use a pointer-to-member expression where the dynamic type of the first operand does not contain the member to which the second operand refers, including the use of a null pointer-to-member value as the second operand. -

    +

    Do not use a pointer-to-member expression where the dynamic type of the first operand does not contain the member to which the second operand refers, including the use of a null pointer-to-member value as the second operand.

    -

    - In this noncompliant code example, a pointer-to-member object is obtained from - - D::g - - but is then upcast to be a - - B::* - - . When called on an object whose dynamic type is - - D - - , the pointer-to-member call is well defined. However, the dynamic type of the underlying object is - - B - - , which results in - - undefined behavior - - . -

    - - struct B { +

    In this noncompliant code example, a pointer-to-member object is obtained from D::g but is then upcast to be a B::*. When called on an object whose dynamic type is D, the pointer-to-member call is well defined. However, the dynamic type of the underlying object is B, which results in undefined behavior.

    + struct B { virtual ~B() = default; }; @@ -176,29 +38,18 @@ struct D : B { void f() { B *b = new B; -  + // ... -  + void (B::*gptr)() = static_cast<void(B::*)()>(&D::g); (b->*gptr)(); delete b; } - +
    -

    - In this compliant solution, the upcast is removed, rendering the initial code - - ill-formed - - and emphasizing the underlying problem that - - B::g() - - does not exist. This compliant solution assumes that the programmer's intention was to use the correct dynamic type for the underlying object. -

    - - struct B { +

    In this compliant solution, the upcast is removed, rendering the initial code ill-formed and emphasizing the underlying problem that B::g() does not exist. This compliant solution assumes that the programmer's intention was to use the correct dynamic type for the underlying object.

    + struct B { virtual ~B() = default; }; @@ -209,24 +60,17 @@ struct D : B { void f() { B *b = new D; // Corrected the dynamic object type. -  + // ... void (D::*gptr)() = &D::g; // Moved static_cast to the next line. (static_cast<D *>(b)->*gptr)(); delete b; } - +
    -

    - In this noncompliant code example, a null pointer-to-member value is passed as the second operand to a pointer-to-member expression, resulting in - - undefined behavior - - . -

    - - struct B { +

    In this noncompliant code example, a null pointer-to-member value is passed as the second operand to a pointer-to-member expression, resulting in undefined behavior.

    + struct B { virtual ~B() = default; }; @@ -234,52 +78,39 @@ struct D : B { virtual ~D() = default; virtual void g() { /* ... */ } }; -  + static void (D::*gptr)(); // Not explicitly initialized, defaults to nullptr. void call_memptr(D *ptr) { (ptr->*gptr)(); } -  + void f() { D *d = new D; call_memptr(d); delete d; -} - +}
    -

    - In this compliant solution, - - gptr - - is properly initialized to a valid pointer-to-member value instead of to the default value of - - nullptr - - . -

    - - struct B { +

    In this compliant solution, gptr is properly initialized to a valid pointer-to-member value instead of to the default value of nullptr.

    + struct B { virtual ~B() = default; }; -  + struct D : B { virtual ~D() = default; virtual void g() { /* ... */ } }; -  + static void (D::*gptr)() = &D::g; // Explicitly initialized. void call_memptr(D *ptr) { (ptr->*gptr)(); } -  + void f() { D *d = new D; call_memptr(d); delete d; -} - +}
    @@ -318,14 +149,10 @@ void f() { High @@ -358,10 +185,7 @@ void f() { 20.10 @@ -376,9 +200,7 @@ void f() { 7.2.0 @@ -393,9 +215,7 @@ void f() { 2021.2 @@ -410,11 +230,7 @@ void f() { 2021.4 @@ -429,9 +245,7 @@ void f() { 2021.2 @@ -472,28 +284,10 @@ void f() {
    - - P6 - + P6 - - L2 - + L2
    - - overflow_upon_dereference - invalid_function_pointer - + overflow_upon_dereferenceinvalid_function_pointer - - CertC++-OOP55 - + CertC++-OOP55 - - C++2810, C++2811, C++2812, C++2813, C++2814 - + C++2810, C++2811, C++2812, C++2813, C++2814 - - - CERT.OOP.PTR_MEMBER.NO_MEMBER - - + CERT.OOP.PTR_MEMBER.NO_MEMBER - - CERT_CPP-OOP55-a - + CERT_CPP-OOP55-a A cast shall not convert a pointer to a function to any other pointer type, including a pointer to function type @@ -461,9 +275,7 @@ void f() { 4.4 - - 2810, 2811, 2812, 2813, 2814 - + 2810, 2811, 2812, 2813, 2814
    -

    - Search for other - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for other vulnerabilities resulting from the violation of this rule on the CERT website.

    -

    - - This rule is a subset of - - EXP34-C. Do not dereference null pointers - - . - -

    +

    This rule is a subset of EXP34-C. Do not dereference null pointers.

    diff --git a/cpp/cert/src/rules/OOP56-CPP/HonorNewReplacementHandlerRequirements-standard.qhelp b/cpp/cert/src/rules/OOP56-CPP/HonorNewReplacementHandlerRequirements-standard.qhelp index a830c4012c..a93982cc9e 100644 --- a/cpp/cert/src/rules/OOP56-CPP/HonorNewReplacementHandlerRequirements-standard.qhelp +++ b/cpp/cert/src/rules/OOP56-CPP/HonorNewReplacementHandlerRequirements-standard.qhelp @@ -1,203 +1,51 @@
    -

    - The - - handler - - functions - - new_handler - - , - - terminate_handler - - , and - - unexpected_handler - - can be globally replaced by custom - - implementations - - , as specified by [handler.functions], paragraph 2, of the C++ Standard [ - - ISO/IEC 14882-2014 - - ]. For instance, an application could set a custom termination handler by calling - - std::set_terminate() - - , and the custom termination handler may log the termination for later auditing. However, the C++ Standard, [res.on.functions], paragraph 1, states the following: -

    +

    The handler functions new_handler, terminate_handler, and unexpected_handler can be globally replaced by custom implementations, as specified by [handler.functions], paragraph 2, of the C++ Standard [ISO/IEC 14882-2014]. For instance, an application could set a custom termination handler by calling std::set_terminate(), and the custom termination handler may log the termination for later auditing. However, the C++ Standard, [res.on.functions], paragraph 1, states the following:

    -

    - In certain cases (replacement functions, handler functions, operations on types used to instantiate standard library template components), the C++ standard library depends on components supplied by a C++ program. If these components do not meet their requirements, the Standard places no requirements on the implementation. -

    +

    In certain cases (replacement functions, handler functions, operations on types used to instantiate standard library template components), the C++ standard library depends on components supplied by a C++ program. If these components do not meet their requirements, the Standard places no requirements on the implementation.

    -

    - Paragraph 2, in part, further states the following: -

    +

    Paragraph 2, in part, further states the following:

    -

    - In particular, the effects are undefined in the following cases: - — for handler functions, if the installed handler function does not implement the semantics of the applicable - - Required behavior: - - paragraph -

    +

    In particular, the effects are undefined in the following cases:— for handler functions, if the installed handler function does not implement the semantics of the applicable Required behavior: paragraph

    -

    - A replacement for any of the handler functions must meet the semantic requirements specified by the appropriate - - Required behavior: - - clause of the replaced function. -

    -

    - - New Handler - -

    -

    - The requirements for a replacement - - new_handler - - are specified by [new.handler], paragraph 2: -

    +

    A replacement for any of the handler functions must meet the semantic requirements specified by the appropriate Required behavior: clause of the replaced function.

    +

    New Handler

    +

    The requirements for a replacement new_handler are specified by [new.handler], paragraph 2:

    -

    - Required behavior: A - - new_handler - - shall perform one of the following: - — make more storage available for allocation and then return; - — throw an exception of type - - bad_alloc - - or a class derived from - - bad_alloc - - ; - — terminate execution of the program without returning to the caller; -

    +

    Required behavior: A new_handler shall perform one of the following:— make more storage available for allocation and then return;— throw an exception of type bad_alloc or a class derived from bad_alloc;— terminate execution of the program without returning to the caller;

    -

    - - Terminate Handler - -

    -

    - The requirements for a replacement - - terminate_handler - - are specified by [terminate.handler], paragraph 2: -

    +

    Terminate Handler

    +

    The requirements for a replacement terminate_handler are specified by [terminate.handler], paragraph 2:

    -

    - Required behavior: - A - - terminate_handler - - shall terminate execution of the program without returning to the caller. -

    +

    Required behavior: A terminate_handler shall terminate execution of the program without returning to the caller.

    -

    - - Unexpected Handler - -

    -

    - The requirements for a replacement - - unexpected_handler - - are specified by [unexpected.handler], paragraph 2. -

    +

    Unexpected Handler

    +

    The requirements for a replacement unexpected_handler are specified by [unexpected.handler], paragraph 2.

    -

    - Required behavior: - An - - unexpected_handler - - shall not return. See also 15.5.2. -

    +

    Required behavior: An unexpected_handler shall not return. See also 15.5.2.

    -

    - - unexpected_handler - - is a deprecated feature of C++. -

    +

    unexpected_handler is a deprecated feature of C++.

    -

    - In this noncompliant code example, a replacement - - new_handler - - is written to attempt to release salvageable resources when the dynamic memory manager runs out of memory. However, this example does not take into account the situation in which all salvageable resources have been recovered and there is still insufficient memory to satisfy the allocation request. Instead of terminating the replacement handler with an exception of type - - std::bad_alloc - - or terminating the execution of the program without returning to the caller, the replacement handler returns as normal. Under low memory conditions, an infinite loop will occur with the default implementation of - - ::operator new() - - . Because such conditions are rare in practice, it is likely for this bug to go undiscovered under typical testing scenarios. -

    - - #include <new> -  +

    In this noncompliant code example, a replacement new_handler is written to attempt to release salvageable resources when the dynamic memory manager runs out of memory. However, this example does not take into account the situation in which all salvageable resources have been recovered and there is still insufficient memory to satisfy the allocation request. Instead of terminating the replacement handler with an exception of type std::bad_alloc or terminating the execution of the program without returning to the caller, the replacement handler returns as normal. Under low memory conditions, an infinite loop will occur with the default implementation of ::operator new(). Because such conditions are rare in practice, it is likely for this bug to go undiscovered under typical testing scenarios.

    + #include <new> + void custom_new_handler() { // Returns number of bytes freed. extern std::size_t reclaim_resources(); reclaim_resources(); } -  + int main() { std::set_new_handler(custom_new_handler); -  + // ... -} - +}
    -

    - In this compliant solution, - - custom_new_handler() - - uses the return value from - - reclaim_resources() - - . If it returns - - 0 - - , then there will be insufficient memory for - - operator new - - to succeed. Hence, an exception of type - - std::bad_alloc - - is thrown, meeting the requirements for the replacement handler. -

    - - #include <new> +

    In this compliant solution, custom_new_handler() uses the return value from reclaim_resources(). If it returns 0, then there will be insufficient memory for operator new to succeed. Hence, an exception of type std::bad_alloc is thrown, meeting the requirements for the replacement handler.

    + #include <new> void custom_new_handler() noexcept(false) { // Returns number of bytes freed. @@ -211,17 +59,10 @@ int main() { std::set_new_handler(custom_new_handler); // ... -} - +}
    -

    - Failing to meet the required behavior for a replacement handler results in - - undefined behavior - - . -

    +

    Failing to meet the required behavior for a replacement handler results in undefined behavior.

    @@ -258,14 +99,10 @@ int main() { High @@ -298,9 +135,7 @@ int main() { 2021.2 @@ -315,15 +150,9 @@ int main() { 2021.2
    - - P2 - + P2 - - L3 - + L3
    - - C++4776, C++4777, C++4778, C++4779 - + C++4776, C++4777, C++4778, C++4779 - - CERT_CPP-OOP56-a - - - CERT_CPP-OOP56-b - - - CERT_CPP-OOP56-c - + CERT_CPP-OOP56-a + CERT_CPP-OOP56-b + CERT_CPP-OOP56-c Properly define terminate handlers @@ -335,17 +164,7 @@ int main() {
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    @@ -379,19 +198,13 @@ int main() { diff --git a/cpp/cert/src/rules/OOP56-CPP/HonorTerminationReplacementHandlerRequirements-standard.qhelp b/cpp/cert/src/rules/OOP56-CPP/HonorTerminationReplacementHandlerRequirements-standard.qhelp index a830c4012c..a93982cc9e 100644 --- a/cpp/cert/src/rules/OOP56-CPP/HonorTerminationReplacementHandlerRequirements-standard.qhelp +++ b/cpp/cert/src/rules/OOP56-CPP/HonorTerminationReplacementHandlerRequirements-standard.qhelp @@ -1,203 +1,51 @@
    -

    - The - - handler - - functions - - new_handler - - , - - terminate_handler - - , and - - unexpected_handler - - can be globally replaced by custom - - implementations - - , as specified by [handler.functions], paragraph 2, of the C++ Standard [ - - ISO/IEC 14882-2014 - - ]. For instance, an application could set a custom termination handler by calling - - std::set_terminate() - - , and the custom termination handler may log the termination for later auditing. However, the C++ Standard, [res.on.functions], paragraph 1, states the following: -

    +

    The handler functions new_handler, terminate_handler, and unexpected_handler can be globally replaced by custom implementations, as specified by [handler.functions], paragraph 2, of the C++ Standard [ISO/IEC 14882-2014]. For instance, an application could set a custom termination handler by calling std::set_terminate(), and the custom termination handler may log the termination for later auditing. However, the C++ Standard, [res.on.functions], paragraph 1, states the following:

    -

    - In certain cases (replacement functions, handler functions, operations on types used to instantiate standard library template components), the C++ standard library depends on components supplied by a C++ program. If these components do not meet their requirements, the Standard places no requirements on the implementation. -

    +

    In certain cases (replacement functions, handler functions, operations on types used to instantiate standard library template components), the C++ standard library depends on components supplied by a C++ program. If these components do not meet their requirements, the Standard places no requirements on the implementation.

    -

    - Paragraph 2, in part, further states the following: -

    +

    Paragraph 2, in part, further states the following:

    -

    - In particular, the effects are undefined in the following cases: - — for handler functions, if the installed handler function does not implement the semantics of the applicable - - Required behavior: - - paragraph -

    +

    In particular, the effects are undefined in the following cases:— for handler functions, if the installed handler function does not implement the semantics of the applicable Required behavior: paragraph

    -

    - A replacement for any of the handler functions must meet the semantic requirements specified by the appropriate - - Required behavior: - - clause of the replaced function. -

    -

    - - New Handler - -

    -

    - The requirements for a replacement - - new_handler - - are specified by [new.handler], paragraph 2: -

    +

    A replacement for any of the handler functions must meet the semantic requirements specified by the appropriate Required behavior: clause of the replaced function.

    +

    New Handler

    +

    The requirements for a replacement new_handler are specified by [new.handler], paragraph 2:

    -

    - Required behavior: A - - new_handler - - shall perform one of the following: - — make more storage available for allocation and then return; - — throw an exception of type - - bad_alloc - - or a class derived from - - bad_alloc - - ; - — terminate execution of the program without returning to the caller; -

    +

    Required behavior: A new_handler shall perform one of the following:— make more storage available for allocation and then return;— throw an exception of type bad_alloc or a class derived from bad_alloc;— terminate execution of the program without returning to the caller;

    -

    - - Terminate Handler - -

    -

    - The requirements for a replacement - - terminate_handler - - are specified by [terminate.handler], paragraph 2: -

    +

    Terminate Handler

    +

    The requirements for a replacement terminate_handler are specified by [terminate.handler], paragraph 2:

    -

    - Required behavior: - A - - terminate_handler - - shall terminate execution of the program without returning to the caller. -

    +

    Required behavior: A terminate_handler shall terminate execution of the program without returning to the caller.

    -

    - - Unexpected Handler - -

    -

    - The requirements for a replacement - - unexpected_handler - - are specified by [unexpected.handler], paragraph 2. -

    +

    Unexpected Handler

    +

    The requirements for a replacement unexpected_handler are specified by [unexpected.handler], paragraph 2.

    -

    - Required behavior: - An - - unexpected_handler - - shall not return. See also 15.5.2. -

    +

    Required behavior: An unexpected_handler shall not return. See also 15.5.2.

    -

    - - unexpected_handler - - is a deprecated feature of C++. -

    +

    unexpected_handler is a deprecated feature of C++.

    -

    - In this noncompliant code example, a replacement - - new_handler - - is written to attempt to release salvageable resources when the dynamic memory manager runs out of memory. However, this example does not take into account the situation in which all salvageable resources have been recovered and there is still insufficient memory to satisfy the allocation request. Instead of terminating the replacement handler with an exception of type - - std::bad_alloc - - or terminating the execution of the program without returning to the caller, the replacement handler returns as normal. Under low memory conditions, an infinite loop will occur with the default implementation of - - ::operator new() - - . Because such conditions are rare in practice, it is likely for this bug to go undiscovered under typical testing scenarios. -

    - - #include <new> -  +

    In this noncompliant code example, a replacement new_handler is written to attempt to release salvageable resources when the dynamic memory manager runs out of memory. However, this example does not take into account the situation in which all salvageable resources have been recovered and there is still insufficient memory to satisfy the allocation request. Instead of terminating the replacement handler with an exception of type std::bad_alloc or terminating the execution of the program without returning to the caller, the replacement handler returns as normal. Under low memory conditions, an infinite loop will occur with the default implementation of ::operator new(). Because such conditions are rare in practice, it is likely for this bug to go undiscovered under typical testing scenarios.

    + #include <new> + void custom_new_handler() { // Returns number of bytes freed. extern std::size_t reclaim_resources(); reclaim_resources(); } -  + int main() { std::set_new_handler(custom_new_handler); -  + // ... -} - +}
    -

    - In this compliant solution, - - custom_new_handler() - - uses the return value from - - reclaim_resources() - - . If it returns - - 0 - - , then there will be insufficient memory for - - operator new - - to succeed. Hence, an exception of type - - std::bad_alloc - - is thrown, meeting the requirements for the replacement handler. -

    - - #include <new> +

    In this compliant solution, custom_new_handler() uses the return value from reclaim_resources(). If it returns 0, then there will be insufficient memory for operator new to succeed. Hence, an exception of type std::bad_alloc is thrown, meeting the requirements for the replacement handler.

    + #include <new> void custom_new_handler() noexcept(false) { // Returns number of bytes freed. @@ -211,17 +59,10 @@ int main() { std::set_new_handler(custom_new_handler); // ... -} - +}
    -

    - Failing to meet the required behavior for a replacement handler results in - - undefined behavior - - . -

    +

    Failing to meet the required behavior for a replacement handler results in undefined behavior.

    Subclause 17.6.4.8, "Other Functions" Subclause 18.6.2.3, "Type - - new_handler - + new_handler " Subclause 18.8.3.1, "Type - - terminate_handler - + terminate_handler " Subclause D.11.1, "Type - - unexpected_handler - + unexpected_handler "
    @@ -258,14 +99,10 @@ int main() { High @@ -298,9 +135,7 @@ int main() { 2021.2 @@ -315,15 +150,9 @@ int main() { 2021.2
    - - P2 - + P2 - - L3 - + L3
    - - C++4776, C++4777, C++4778, C++4779 - + C++4776, C++4777, C++4778, C++4779 - - CERT_CPP-OOP56-a - - - CERT_CPP-OOP56-b - - - CERT_CPP-OOP56-c - + CERT_CPP-OOP56-a + CERT_CPP-OOP56-b + CERT_CPP-OOP56-c Properly define terminate handlers @@ -335,17 +164,7 @@ int main() {
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    @@ -379,19 +198,13 @@ int main() { diff --git a/cpp/cert/src/rules/OOP57-CPP/PreferSpecialMemberFunctionsAndOverloadedOperatorsToCStandardLibraryFunctions-standard.qhelp b/cpp/cert/src/rules/OOP57-CPP/PreferSpecialMemberFunctionsAndOverloadedOperatorsToCStandardLibraryFunctions-standard.qhelp index 45f9596602..624f55f980 100644 --- a/cpp/cert/src/rules/OOP57-CPP/PreferSpecialMemberFunctionsAndOverloadedOperatorsToCStandardLibraryFunctions-standard.qhelp +++ b/cpp/cert/src/rules/OOP57-CPP/PreferSpecialMemberFunctionsAndOverloadedOperatorsToCStandardLibraryFunctions-standard.qhelp @@ -1,81 +1,16 @@
    -

    - Several C standard library functions perform bytewise operations on objects. For instance, - - std::memcmp() - - compares the bytes comprising the object representation of two objects, and - - std::memcpy() - - copies the bytes comprising an object representation into a destination buffer. However, for some object types, it results in undefined or abnormal program behavior. -

    -

    - The C++ Standard, [class], paragraph 6 [ - - ISO/IEC 14882-2014 - - ], states the following: -

    +

    Several C standard library functions perform bytewise operations on objects. For instance, std::memcmp() compares the bytes comprising the object representation of two objects, and std::memcpy() copies the bytes comprising an object representation into a destination buffer. However, for some object types, it results in undefined or abnormal program behavior.

    +

    The C++ Standard, [class], paragraph 6 [ISO/IEC 14882-2014], states the following:

    -

    - A - - trivially copyable class - - is a class that: - — has no non-trivial copy constructors, - — has no non-trivial move constructors, - — has no non-trivial copy assignment operators, - — has no non-trivial move assignment operators, and - — has a trivial destructor. - A - - trivial class - - is a class that has a default constructor, has no non-trivial default constructors, and is trivially copyable. - [ - Note: - In particular, a trivially copyable or trivial class does not have virtual functions or virtual base classes. - — end note - ] -

    +

    A trivially copyable class is a class that: — has no non-trivial copy constructors, — has no non-trivial move constructors, — has no non-trivial copy assignment operators, — has no non-trivial move assignment operators, and — has a trivial destructor.A trivial class is a class that has a default constructor, has no non-trivial default constructors, and is trivially copyable. [Note: In particular, a trivially copyable or trivial class does not have virtual functions or virtual base classes. — end note]

    -

    - Additionally, the C++ Standard, [class], paragraph 7, states the following: -

    +

    Additionally, the C++ Standard, [class], paragraph 7, states the following:

    -

    - A - - standard-layout class - - is a class that: - — has no non-static data members of type non-standard-layout class (or array of such types) or reference, - — has no virtual functions and no virtual base classes, - — has the same access control for all non-static data members, - — has no non-standard-layout base classes, - — either has no non-static data members in the most derived class and at most one base class with non-static data members, or has no base classes with non-static data members, and - — has no base classes of the same type as the first non-static data member. -

    +

    A standard-layout class is a class that: — has no non-static data members of type non-standard-layout class (or array of such types) or reference, — has no virtual functions and no virtual base classes, — has the same access control for all non-static data members, — has no non-standard-layout base classes, — either has no non-static data members in the most derived class and at most one base class with non-static data members, or has no base classes with non-static data members, and — has no base classes of the same type as the first non-static data member.

    -

    - Do not use - - std::memset() - - to initialize an object of nontrivial class type as it may not properly initialize the value representation of the object. Do not use - - std::memcpy() - - (or related bytewise copy functions) to initialize a copy of an object of nontrivial class type, as it may not properly initialize the value representation of the copy. Do not use - - std::memcmp() - - (or related bytewise comparison functions) to compare objects of nonstandard-layout class type, as it may not properly compare the value representations of the objects. In all cases, it is best to prefer the alternatives. -

    +

    Do not use std::memset() to initialize an object of nontrivial class type as it may not properly initialize the value representation of the object. Do not use std::memcpy() (or related bytewise copy functions) to initialize a copy of an object of nontrivial class type, as it may not properly initialize the value representation of the copy. Do not use std::memcmp() (or related bytewise comparison functions) to compare objects of nonstandard-layout class type, as it may not properly compare the value representations of the objects. In all cases, it is best to prefer the alternatives.

    Subclause 17.6.4.8, "Other Functions" Subclause 18.6.2.3, "Type - - new_handler - + new_handler " Subclause 18.8.3.1, "Type - - terminate_handler - + terminate_handler " Subclause D.11.1, "Type - - unexpected_handler - + unexpected_handler "
    @@ -88,9 +23,7 @@
    - - std::memset() - + std::memset() Class constructor @@ -98,69 +31,42 @@
    - - std::memcpy() - - - std::memmove() - - - std::strcpy() - + std::memcpy() + std::memmove() + std::strcpy() Class copy constructor or - - operator=() - + operator=()
    - - std::memcmp() - - - std::strcmp() - + std::memcmp() + std::strcmp() - - operator<() - + operator<() , - - operator>() - + operator>() , - - operator==() - + operator==() , or - - operator!=() - + operator!=()
    -

    - In this noncompliant code example, a nontrivial class object is initialized by calling its default constructor but is later reinitialized to its default state using - - std::memset() - - , which does not properly reinitialize the object. Improper reinitialization leads to class invariants not holding in later uses of the object. -

    - - #include <cstring> +

    In this noncompliant code example, a nontrivial class object is initialized by calling its default constructor but is later reinitialized to its default state using std::memset(), which does not properly reinitialize the object. Improper reinitialization leads to class invariants not holding in later uses of the object.

    + #include <cstring> #include <iostream> -  + class C { int scalingFactor; int otherData; -  + public: C() : scalingFactor(1) {} @@ -170,7 +76,7 @@ public: } // ... }; -  + void f() { C c; @@ -180,40 +86,18 @@ void f() { std::memset(&c, 0, sizeof(C)); std::cout << c.f(100) << std::endl; -} - -

    - The above noncompliant code example is compliant with - - EXP62-CPP. Do not access the bits of an object representation that are not part of the object's value representation - - because all of the bits in the value representation are also used in the object representation of - - C - - . -

    +}
    +

    The above noncompliant code example is compliant with EXP62-CPP. Do not access the bits of an object representation that are not part of the object's value representation because all of the bits in the value representation are also used in the object representation of C.

    -

    - In this compliant solution, the call to - - std::memset() - - is replaced with a default-initialized copy-and-swap operation called - - clear() - - . This operation ensures that the object is initialized to its default state properly, and it behaves properly for object types that have optimized assignment operators that fail to clear all data members of the object being assigned into. -

    - - #include <iostream> +

    In this compliant solution, the call to std::memset() is replaced with a default-initialized copy-and-swap operation called clear(). This operation ensures that the object is initialized to its default state properly, and it behaves properly for object types that have optimized assignment operators that fail to clear all data members of the object being assigned into.

    + #include <iostream> #include <utility> -  + class C { int scalingFactor; int otherData; -  + public: C() : scalingFactor(1) {} @@ -223,7 +107,7 @@ public: } // ... }; -  + template <typename T> T& clear(T &o) { using std::swap; @@ -241,75 +125,35 @@ void f() { clear(c); std::cout << c.f(100) << std::endl; -} - +}
    -

    - In this noncompliant code example, - - std::memcpy() - - is used to create a copy of an object of nontrivial type - - C - - . However, because each object instance attempts to delete the - - int * - - in - - C::~C() - - , double-free - - vulnerabilities - - may occur because the same pointer value will be copied into - - c2 - - . -

    - - #include <cstring> -  +

    In this noncompliant code example, std::memcpy() is used to create a copy of an object of nontrivial type C. However, because each object instance attempts to delete the int * in C::~C(), double-free vulnerabilities may occur because the same pointer value will be copied into c2.

    + #include <cstring> + class C { int *i; -  + public: C() : i(nullptr) {} ~C() { delete i; } -  + void set(int val) { if (i) { delete i; } i = new int{val}; } -  + // ... }; -  + void f(C &c1) { C c2; std::memcpy(&c2, &c1, sizeof(C)); -} - +}
    -

    - In this compliant solution, - - C - - defines an assignment operator that is used instead of calling - - std::memcpy() - - . -

    - - class C { +

    In this compliant solution, C defines an assignment operator that is used instead of calling std::memcpy().

    + class C { int *i; public: @@ -340,36 +184,12 @@ public: void f(C &c1) { C c2 = c1; -} - +}
    -

    - In this noncompliant code example, - - std::memcmp() - - is used to compared two objects of nonstandard-layout type. Because - - std::memcmp() - - performs a bytewise comparison of the object representations, if the implementation uses a vtable pointer as part of the object representation, it will compare vtable pointers. If the dynamic type of either - - c1 - - or - - c2 - - is a derived class of type - - C - - , the comparison may fail despite the value representation of either object. -

    - - #include <cstring> -  +

    In this noncompliant code example, std::memcmp() is used to compared two objects of nonstandard-layout type. Because std::memcmp() performs a bytewise comparison of the object representations, if the implementation uses a vtable pointer as part of the object representation, it will compare vtable pointers. If the dynamic type of either c1 or c2 is a derived class of type C, the comparison may fail despite the value representation of either object.

    + #include <cstring> + class C { int i; @@ -383,39 +203,17 @@ void f(C &c1, C &c2) { if (!std::memcmp(&c1, &c2, sizeof(C))) { // ... } -} - -

    - Because a vtable is not part of an object's value representation, comparing it with - - std::memcmp() - - also violates - - EXP62-CPP. Do not access the bits of an object representation that are not part of the object's value representation - - . -

    +}
    +

    Because a vtable is not part of an object's value representation, comparing it with std::memcmp() also violates EXP62-CPP. Do not access the bits of an object representation that are not part of the object's value representation.

    -

    - In this compliant solution, - - C - - defines an equality operator that is used instead of calling - - std::memcmp() - - . This solution ensures that only the value representation of the objects is considered when performing the comparison. -

    - - class C { +

    In this compliant solution, C defines an equality operator that is used instead of calling std::memcmp(). This solution ensures that only the value representation of the objects is considered when performing the comparison.

    + class C { int i; public: virtual void f(); -   + bool operator==(const C &rhs) const { return rhs.i == i; } @@ -427,21 +225,10 @@ void f(C &c1, C &c2) { if (c1 == c2) { // ... } -} - +}
    -

    - Most violations of this rule will result in abnormal program behavior. However, overwriting - - implementation - - details of the object representation can lead to code execution - - vulnerabilities - - . -

    +

    Most violations of this rule will result in abnormal program behavior. However, overwriting implementation details of the object representation can lead to code execution vulnerabilities.

    @@ -478,14 +265,10 @@ void f(C &c1, C &c2) { High @@ -518,19 +301,30 @@ void f(C &c1, C &c2) { 20.10 + + + + + + @@ -558,11 +350,7 @@ void f(C &c1, C &c2) { 2021.4 @@ -576,9 +364,7 @@ void f(C &c1, C &c2) { @@ -648,20 +428,12 @@ void f(C &c1, C &c2) { @@ -676,16 +448,7 @@ void f(C &c1, C &c2) { 20.10
    - - P6 - + P6 - - L2 - + L2
    - - stdlib-use-ato - stdlib-use - stdlib-use-getenv - stdlib-use-system - include-time - stdlib-use-string-unbounded - + stdlib-use-atostdlib-usestdlib-use-getenvstdlib-use-systeminclude-timestdlib-use-string-unbounded Partially checked
    + + CodeSonar + + + 6.2p0 + + BADFUNC.MEMCMP + BADFUNC.MEMSET + + Use of memcmp + Use of memset +
    @@ -541,9 +335,7 @@ void f(C &c1, C &c2) { 2021.2 - - C++5017, C++5038 - + C++5017, C++5038 - - - CERT.OOP.CSTD_FUNC_USE - - + CERT.OOP.CSTD_FUNC_USE - - 44 S - + 44 S Enhanced Enforcement @@ -594,12 +380,8 @@ void f(C &c1, C &c2) { 2021.2 - - CERT_CPP-OOP57-a - - - CERT_CPP-OOP57-b - + CERT_CPP-OOP57-a + CERT_CPP-OOP57-b Do not initialize objects with a non-trivial class type using C standard library functions @@ -634,9 +416,7 @@ void f(C &c1, C &c2) { 4.4 - - 5017, 5038 - + 5017, 5038 - 7.16 + 7.17 - - V598 - - - + V598 , - - - V780 - - + V780 - - - stdlib-use-ato - stdlib-use - stdlib-use-getenv - stdlib-use-system - include-time - stdlib-use-string-unbounded - - + stdlib-use-atostdlib-usestdlib-use-getenvstdlib-use-systeminclude-timestdlib-use-string-unbounded Partially checked @@ -695,17 +458,7 @@ void f(C &c1, C &c2) {
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/OOP58-CPP/CopyOperationsMustNotMutateTheSourceObject-standard.qhelp b/cpp/cert/src/rules/OOP58-CPP/CopyOperationsMustNotMutateTheSourceObject-standard.qhelp index 4d6ca63083..befff420e6 100644 --- a/cpp/cert/src/rules/OOP58-CPP/CopyOperationsMustNotMutateTheSourceObject-standard.qhelp +++ b/cpp/cert/src/rules/OOP58-CPP/CopyOperationsMustNotMutateTheSourceObject-standard.qhelp @@ -1,60 +1,12 @@
    -

    - Copy operations (copy constructors and copy assignment operators) are expected to copy the salient properties of a source object into the destination object, with the resulting object being a "copy" of the original. What is considered to be a salient property of the type is type-dependent, but for types that expose comparison or equality operators, includes any properties used for those comparison operations. This expectation leads to assumptions in code that a copy operation results in a destination object with a value representation that is equivalent to the source object value representation. Violation of this basic assumption can lead to unexpected behavior. -

    -

    - Ideally, the copy operator should have an idiomatic signature. For copy constructors, that is - - T(const T&); - - and for copy assignment operators, that is - - T& operator=(const T&); - - . Copy constructors and copy assignment operators that do not use an idiomatic signature do not meet the requirements of the - - CopyConstructible - - or - - CopyAssignable - - concept, respectively. This precludes the type from being used with common standard library functionality [ - - ISO/IEC 14882-2014 - - ]. -

    -

    - When implementing a copy operator, do not mutate any externally observable members of the source object operand or globally accessible information. Externally observable members include, but are not limited to, members that participate in comparison or equality operations, members whose values are exposed via public APIs, and global variables. -

    -

    - Before C++11, a copy operation that mutated the source operand was the only way to provide move-like semantics. However, the language did not provide a way to enforce that this operation only occurred when the source operand was at the end of its lifetime, which led to fragile APIs like - - std::auto_ptr - - . In C++11 and later, such a situation is a good candidate for a move operation instead of a copy operation. -

    -

    - - auto_ptr - -

    -

    - For example, in C++03, - - std::auto_ptr - - had the following copy operation signatures - [ - - ISO/IEC 14882-2003 - - ] - : -

    +

    Copy operations (copy constructors and copy assignment operators) are expected to copy the salient properties of a source object into the destination object, with the resulting object being a "copy" of the original. What is considered to be a salient property of the type is type-dependent, but for types that expose comparison or equality operators, includes any properties used for those comparison operations. This expectation leads to assumptions in code that a copy operation results in a destination object with a value representation that is equivalent to the source object value representation. Violation of this basic assumption can lead to unexpected behavior.

    +

    Ideally, the copy operator should have an idiomatic signature. For copy constructors, that is T(const T&); and for copy assignment operators, that is T& operator=(const T&);. Copy constructors and copy assignment operators that do not use an idiomatic signature do not meet the requirements of the CopyConstructible or CopyAssignable concept, respectively. This precludes the type from being used with common standard library functionality [ISO/IEC 14882-2014].

    +

    When implementing a copy operator, do not mutate any externally observable members of the source object operand or globally accessible information. Externally observable members include, but are not limited to, members that participate in comparison or equality operations, members whose values are exposed via public APIs, and global variables.

    +

    Before C++11, a copy operation that mutated the source operand was the only way to provide move-like semantics. However, the language did not provide a way to enforce that this operation only occurred when the source operand was at the end of its lifetime, which led to fragile APIs like std::auto_ptr. In C++11 and later, such a situation is a good candidate for a move operation instead of a copy operation.

    +

    auto_ptr

    +

    For example, in C++03, std::auto_ptr had the following copy operation signatures [ISO/IEC 14882-2003]:

    @@ -62,9 +14,7 @@ Copy constructor @@ -72,129 +22,20 @@ Copy assignment
    - - auto_ptr(auto_ptr &A); - + auto_ptr(auto_ptr &A);
    - - auto_ptr& operator=(auto_ptr &A); - + auto_ptr& operator=(auto_ptr &A);
    -

    - Both copy construction and copy assignment would mutate the source argument, - - A - - , by effectively calling - - this->reset(A.release()) - - . However, this invalidated assumptions made by standard library algorithms such as - - std::sort() - - , which may need to make a copy of an object for later comparisons - [ - - Hinnant 05 - - ] - . Consider the following implementation of - - std::sort() - - that implements the - - quick sort - - algorithm. -

    - - // ... +

    Both copy construction and copy assignment would mutate the source argument, A, by effectively calling this->reset(A.release()). However, this invalidated assumptions made by standard library algorithms such as std::sort(), which may need to make a copy of an object for later comparisons [Hinnant 05]. Consider the following implementation of std::sort() that implements the quick sort algorithm.

    + // ... value_type pivot_element = *mid_point; -// ... - -

    - At this point, the sorting algorithm assumes that - - pivot_element - - and - - *mid_point - - have equivalent value representations and will compare equal. However, for - - std::auto_ptr - - , this is not the case because - - *mid_point - - has been mutated and results in unexpected behavior. -

    -

    - In C++11, the - - std::unique_ptr - - smart pointer class was introduced as a replacement for - - std::auto_ptr - - to better specify the ownership semantics of pointer objects. Rather than mutate the source argument in a copy operation, - - std::unique_ptr - - explicitly deletes the copy constructor and copy assignment operator, and instead uses a move constructor and move assignment operator. Subsequently, - - std::auto_ptr - - was deprecated in C++11. -

    -

    - Noncompliant Code Example -

    -

    - In this noncompliant code example, the copy operations for - - A - - mutate the source operand by resetting its member variable - - m - - to - - 0 - - . When - - std::fill() - - is called, the first element copied will have the original value of - - obj.m - - , - - 12 - - , at which point - - obj.m - - is set to - - 0 - - . The subsequent nine copies will all retain the value - - 0 - - . -

    - - #include <algorithm> +// ... +

    At this point, the sorting algorithm assumes that pivot_element and *mid_point have equivalent value representations and will compare equal. However, for std::auto_ptr, this is not the case because *mid_point has been mutated and results in unexpected behavior.

    +

    In C++11, the std::unique_ptr smart pointer class was introduced as a replacement for std::auto_ptr to better specify the ownership semantics of pointer objects. Rather than mutate the source argument in a copy operation, std::unique_ptr explicitly deletes the copy constructor and copy assignment operator, and instead uses a move constructor and move assignment operator. Subsequently, std::auto_ptr was deprecated in C++11.

    +

    Noncompliant Code Example

    +

    In this noncompliant code example, the copy operations for A mutate the source operand by resetting its member variable m to 0. When std::fill() is called, the first element copied will have the original value of obj.m, 12, at which point obj.m is set to 0. The subsequent nine copies will all retain the value 0.

    + #include <algorithm> #include <vector> class A { @@ -215,7 +56,7 @@ public: } return *this; } -   + int get_m() const { return m; } }; @@ -223,27 +64,11 @@ void f() { std::vector<A> v{10}; A obj(12); std::fill(v.begin(), v.end(), obj); -} - +}
    -

    - In this compliant solution, the copy operations for - - A - - no longer mutate the source operand, ensuring that the vector contains equivalent copies of - - obj - - . Instead, - - A - - has been given move operations that perform the mutation when it is safe to do so. -

    - - #include <algorithm> +

    In this compliant solution, the copy operations for A no longer mutate the source operand, ensuring that the vector contains equivalent copies of obj. Instead, A has been given move operations that perform the mutation when it is safe to do so.

    + #include <algorithm> #include <vector> class A { @@ -262,7 +87,7 @@ public: } return *this; } -  + A& operator=(A &&other) { m = other.m; other.m = 0; @@ -276,29 +101,13 @@ void f() { std::vector<A> v{10}; A obj(12); std::fill(v.begin(), v.end(), obj); -} - +}
    -

    - - OOP58-CPP-EX0: - - Reference counting, and implementations such as - - std::shared_ptr<> - - constitute an exception to this rule. Any copy or assignment operation of a reference-counted object requires the reference count to be incremented. The semantics of reference counting are well-understood, and it can be argued that the reference count is not a salient part of the - - shared_pointer - - object. -

    +

    OOP58-CPP-EX0: Reference counting, and implementations such as std::shared_ptr<> constitute an exception to this rule. Any copy or assignment operation of a reference-counted object requires the reference count to be incremented. The semantics of reference counting are well-understood, and it can be argued that the reference count is not a salient part of the shared_pointer object.

    -

    - Copy operations that mutate the source operand or global state can lead to unexpected program behavior. Using such a type in a Standard Template Library container or algorithm can also lead to undefined behavior. -

    +

    Copy operations that mutate the source operand or global state can lead to unexpected program behavior. Using such a type in a Standard Template Library container or algorithm can also lead to undefined behavior.

    @@ -335,14 +144,10 @@ void f() { Low @@ -375,9 +180,7 @@ void f() { 2021.2 @@ -392,11 +195,7 @@ void f() { 2021.4 @@ -411,9 +210,7 @@ void f() { 2021.2 @@ -458,17 +253,7 @@ void f() {
    - - P9 - + P9 - - L2 - + L2
    - - C++4075 - + C++4075 - - - CERT.OOP.COPY_MUTATES - - + CERT.OOP.COPY_MUTATES - - CERT_CPP-OOP58-a - + CERT_CPP-OOP58-a Copy operations must not mutate the source object @@ -447,9 +244,7 @@ void f() { 4.4 - - 4075 - + 4075
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/STR50-CPP/BasicStringMayNotBeNullTerminatedCert-standard.qhelp b/cpp/cert/src/rules/STR50-CPP/BasicStringMayNotBeNullTerminatedCert-standard.qhelp index 63c03b5478..8ca1ca0627 100644 --- a/cpp/cert/src/rules/STR50-CPP/BasicStringMayNotBeNullTerminatedCert-standard.qhelp +++ b/cpp/cert/src/rules/STR50-CPP/BasicStringMayNotBeNullTerminatedCert-standard.qhelp @@ -1,148 +1,50 @@
    -

    - Copying data to a buffer that is not large enough to hold that data results in a buffer overflow. Buffer overflows occur frequently when manipulating strings [ - - Seacord 2013 - - ]. To prevent such errors, either limit copies through truncation or, preferably, ensure that the destination is of sufficient size to hold the data to be copied. C-style strings require a null character to indicate the end of the string, while the C++ - - std::basic_string - - template requires no such character. -

    +

    Copying data to a buffer that is not large enough to hold that data results in a buffer overflow. Buffer overflows occur frequently when manipulating strings [Seacord 2013]. To prevent such errors, either limit copies through truncation or, preferably, ensure that the destination is of sufficient size to hold the data to be copied. C-style strings require a null character to indicate the end of the string, while the C++ std::basic_string template requires no such character.

    -

    - Because the input is unbounded, the following code could lead to a buffer overflow. -

    - - #include <iostream> -  +

    Because the input is unbounded, the following code could lead to a buffer overflow.

    + #include <iostream> + void f() { char buf[12]; std::cin >> buf; -} - +}
    -

    - To solve this problem, it may be tempting to use the - - std::ios_base::width() - - method, but there still is a trap, as shown in this noncompliant code example. -

    - - #include <iostream> -  +

    To solve this problem, it may be tempting to use the std::ios_base::width() method, but there still is a trap, as shown in this noncompliant code example.

    + #include <iostream> + void f() { char bufOne[12]; char bufTwo[12]; std::cin.width(12); std::cin >> bufOne; std::cin >> bufTwo; -} - -

    - In this example, the first read will not overflow, but could fill - - bufOne - - with a truncated string. Furthermore, the second read still could overflow - - bufTwo - - . The C++ Standard, [istream.extractors], paragraphs 7–9  [ - - ISO/IEC 14882-2014 - - ], describes the behavior of - - operator>>(basic_istream &, charT *) - - and, in part, states the following: -

    +}
    +

    In this example, the first read will not overflow, but could fill bufOne with a truncated string. Furthermore, the second read still could overflow bufTwo. The C++ Standard, [istream.extractors], paragraphs 7–9 [ISO/IEC 14882-2014], describes the behavior of operator>>(basic_istream &, charT *) and, in part, states the following:

    -

    - - operator>> - - then stores a null byte ( - - charT() - - ) in the next position, which may be the first position if no characters were extracted. - - operator>> - - then calls - - width(0) - - . -

    +

    operator>> then stores a null byte (charT()) in the next position, which may be the first position if no characters were extracted. operator>> then calls width(0).

    -

    - Consequently, it is necessary to call - - width() - - prior to each - - operator>> - - call passing a bounded array. However, this does not account for the input being truncated, which may lead to information loss or a possible - - vulnerability - - . -

    +

    Consequently, it is necessary to call width() prior to each operator>> call passing a bounded array. However, this does not account for the input being truncated, which may lead to information loss or a possible vulnerability.

    -

    - The best solution for ensuring that data is not truncated and for guarding against buffer overflows is to use - - std::string - - instead of a bounded array, as in this compliant solution. -

    - - #include <iostream> +

    The best solution for ensuring that data is not truncated and for guarding against buffer overflows is to use std::string instead of a bounded array, as in this compliant solution.

    + #include <iostream> #include <string> -  + void f() { std::string input; std::string stringOne, stringTwo; std::cin >> stringOne >> stringTwo; -} - +}
    -

    - In this noncompliant example, the unformatted input function - - std::basic_istream<T>::read() - - is used to read an unformatted character array of 32 characters from the given file. However, the - - read() - - function does not guarantee that the string will be null terminated, so the subsequent call of the - - std::string - - constructor results in - - undefined behavior - - if the character array does not contain a null terminator. -

    - - #include <fstream> +

    In this noncompliant example, the unformatted input function std::basic_istream<T>::read() is used to read an unformatted character array of 32 characters from the given file. However, the read() function does not guarantee that the string will be null terminated, so the subsequent call of the std::string constructor results in undefined behavior if the character array does not contain a null terminator.

    + #include <fstream> #include <string> -  + void f(std::istream &in) { char buffer[32]; try { @@ -153,23 +55,11 @@ void f(std::istream &in) { std::string str(buffer); // ... -} - +}
    -

    - This compliant solution assumes that the input from the file is at most 32 characters. Instead of inserting a null terminator, it constructs the - - std::string - - object based on the number of characters read from the input stream. If the size of the input is uncertain, it is better to use - - std::basic_istream<T>::readsome() - - or a formatted input function, depending on need. -

    - - #include <fstream> +

    This compliant solution assumes that the input from the file is at most 32 characters. Instead of inserting a null terminator, it constructs the std::string object based on the number of characters read from the input stream. If the size of the input is uncertain, it is better to use std::basic_istream<T>::readsome() or a formatted input function, depending on need.

    + #include <fstream> #include <string> void f(std::istream &in) { @@ -181,17 +71,10 @@ void f(std::istream &in) { } std::string str(buffer, in.gcount()); // ... -} - +}
    -

    - Copying string data to a buffer that is too small to hold that data results in a buffer overflow. Attackers can - - exploit - - this condition to execute arbitrary code with the permissions of the vulnerable process. -

    +

    Copying string data to a buffer that is too small to hold that data results in a buffer overflow. Attackers can exploit this condition to execute arbitrary code with the permissions of the vulnerable process.

    @@ -228,14 +111,10 @@ void f(std::istream &in) { Medium @@ -265,16 +144,11 @@ void f(std::istream &in) { @@ -309,18 +181,10 @@ void f(std::istream &in) { 2021.4 @@ -334,9 +198,7 @@ void f(std::istream &in) { @@ -406,11 +258,7 @@ void f(std::istream &in) { 4.10 @@ -419,17 +267,7 @@ void f(std::istream &in) {
    - - P18 - + P18 - - L1 - + L1
    - 6.1p0 + 6.2p0 - - MISC.MEM.NTERM - - - LANG.MEM.BO - LANG.MEM.TO - + MISC.MEM.NTERM + LANG.MEM.BOLANG.MEM.TO No space for null terminator @@ -292,9 +166,7 @@ void f(std::istream &in) { 2021.2 - - C++2835, C++2836, C++2839, C++5216 - + C++2835, C++2836, C++2839, C++5216 - - NNTS.MIGHT - - - NNTS.TAINTED - - - NNTS.MUST - - - SV.UNBOUND_STRING_INPUT.CIN - + NNTS.MIGHT + NNTS.TAINTED + NNTS.MUST + SV.UNBOUND_STRING_INPUT.CIN - - 489 S, 66 X, 70 X, 71 X - + 489 S, 66 X, 70 X, 71 X Partially implemented @@ -352,21 +214,11 @@ void f(std::istream &in) { 2021.2 - - CERT_CPP-STR50-b - - - CERT_CPP-STR50-c - - - CERT_CPP-STR50-e - - - CERT_CPP-STR50-f - - - CERT_CPP-STR50-g - + CERT_CPP-STR50-b + CERT_CPP-STR50-c + CERT_CPP-STR50-e + CERT_CPP-STR50-f + CERT_CPP-STR50-g Avoid overflow due to reading a not zero terminated string @@ -392,7 +244,7 @@ void f(std::istream &in) { Checks for: - Use of dangerous standard function, missing null in string array, buffer overflow from incorrect string format specifier, destination buffer overflow in string manipulation. + Use of dangerous standard functionse of dangerous standard function, missing null in string arrayissing null in string array, buffer overflow from incorrect string format specifieruffer overflow from incorrect string format specifier, destination buffer overflow in string manipulationestination buffer overflow in string manipulation. Rule partially covered.
    - - - S3519 - - + S3519
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    @@ -462,9 +300,7 @@ void f(std::istream &in) { diff --git a/cpp/cert/src/rules/STR50-CPP/OperationMayNotNullTerminateCStyleStringCert-standard.qhelp b/cpp/cert/src/rules/STR50-CPP/OperationMayNotNullTerminateCStyleStringCert-standard.qhelp index 63c03b5478..8ca1ca0627 100644 --- a/cpp/cert/src/rules/STR50-CPP/OperationMayNotNullTerminateCStyleStringCert-standard.qhelp +++ b/cpp/cert/src/rules/STR50-CPP/OperationMayNotNullTerminateCStyleStringCert-standard.qhelp @@ -1,148 +1,50 @@
    -

    - Copying data to a buffer that is not large enough to hold that data results in a buffer overflow. Buffer overflows occur frequently when manipulating strings [ - - Seacord 2013 - - ]. To prevent such errors, either limit copies through truncation or, preferably, ensure that the destination is of sufficient size to hold the data to be copied. C-style strings require a null character to indicate the end of the string, while the C++ - - std::basic_string - - template requires no such character. -

    +

    Copying data to a buffer that is not large enough to hold that data results in a buffer overflow. Buffer overflows occur frequently when manipulating strings [Seacord 2013]. To prevent such errors, either limit copies through truncation or, preferably, ensure that the destination is of sufficient size to hold the data to be copied. C-style strings require a null character to indicate the end of the string, while the C++ std::basic_string template requires no such character.

    -

    - Because the input is unbounded, the following code could lead to a buffer overflow. -

    - - #include <iostream> -  +

    Because the input is unbounded, the following code could lead to a buffer overflow.

    + #include <iostream> + void f() { char buf[12]; std::cin >> buf; -} - +}
    -

    - To solve this problem, it may be tempting to use the - - std::ios_base::width() - - method, but there still is a trap, as shown in this noncompliant code example. -

    - - #include <iostream> -  +

    To solve this problem, it may be tempting to use the std::ios_base::width() method, but there still is a trap, as shown in this noncompliant code example.

    + #include <iostream> + void f() { char bufOne[12]; char bufTwo[12]; std::cin.width(12); std::cin >> bufOne; std::cin >> bufTwo; -} - -

    - In this example, the first read will not overflow, but could fill - - bufOne - - with a truncated string. Furthermore, the second read still could overflow - - bufTwo - - . The C++ Standard, [istream.extractors], paragraphs 7–9  [ - - ISO/IEC 14882-2014 - - ], describes the behavior of - - operator>>(basic_istream &, charT *) - - and, in part, states the following: -

    +}
    +

    In this example, the first read will not overflow, but could fill bufOne with a truncated string. Furthermore, the second read still could overflow bufTwo. The C++ Standard, [istream.extractors], paragraphs 7–9 [ISO/IEC 14882-2014], describes the behavior of operator>>(basic_istream &, charT *) and, in part, states the following:

    -

    - - operator>> - - then stores a null byte ( - - charT() - - ) in the next position, which may be the first position if no characters were extracted. - - operator>> - - then calls - - width(0) - - . -

    +

    operator>> then stores a null byte (charT()) in the next position, which may be the first position if no characters were extracted. operator>> then calls width(0).

    -

    - Consequently, it is necessary to call - - width() - - prior to each - - operator>> - - call passing a bounded array. However, this does not account for the input being truncated, which may lead to information loss or a possible - - vulnerability - - . -

    +

    Consequently, it is necessary to call width() prior to each operator>> call passing a bounded array. However, this does not account for the input being truncated, which may lead to information loss or a possible vulnerability.

    -

    - The best solution for ensuring that data is not truncated and for guarding against buffer overflows is to use - - std::string - - instead of a bounded array, as in this compliant solution. -

    - - #include <iostream> +

    The best solution for ensuring that data is not truncated and for guarding against buffer overflows is to use std::string instead of a bounded array, as in this compliant solution.

    + #include <iostream> #include <string> -  + void f() { std::string input; std::string stringOne, stringTwo; std::cin >> stringOne >> stringTwo; -} - +}
    -

    - In this noncompliant example, the unformatted input function - - std::basic_istream<T>::read() - - is used to read an unformatted character array of 32 characters from the given file. However, the - - read() - - function does not guarantee that the string will be null terminated, so the subsequent call of the - - std::string - - constructor results in - - undefined behavior - - if the character array does not contain a null terminator. -

    - - #include <fstream> +

    In this noncompliant example, the unformatted input function std::basic_istream<T>::read() is used to read an unformatted character array of 32 characters from the given file. However, the read() function does not guarantee that the string will be null terminated, so the subsequent call of the std::string constructor results in undefined behavior if the character array does not contain a null terminator.

    + #include <fstream> #include <string> -  + void f(std::istream &in) { char buffer[32]; try { @@ -153,23 +55,11 @@ void f(std::istream &in) { std::string str(buffer); // ... -} - +}
    -

    - This compliant solution assumes that the input from the file is at most 32 characters. Instead of inserting a null terminator, it constructs the - - std::string - - object based on the number of characters read from the input stream. If the size of the input is uncertain, it is better to use - - std::basic_istream<T>::readsome() - - or a formatted input function, depending on need. -

    - - #include <fstream> +

    This compliant solution assumes that the input from the file is at most 32 characters. Instead of inserting a null terminator, it constructs the std::string object based on the number of characters read from the input stream. If the size of the input is uncertain, it is better to use std::basic_istream<T>::readsome() or a formatted input function, depending on need.

    + #include <fstream> #include <string> void f(std::istream &in) { @@ -181,17 +71,10 @@ void f(std::istream &in) { } std::string str(buffer, in.gcount()); // ... -} - +}
    -

    - Copying string data to a buffer that is too small to hold that data results in a buffer overflow. Attackers can - - exploit - - this condition to execute arbitrary code with the permissions of the vulnerable process. -

    +

    Copying string data to a buffer that is too small to hold that data results in a buffer overflow. Attackers can exploit this condition to execute arbitrary code with the permissions of the vulnerable process.

    Subclause 27.7.2.2.3, " - - basic_istream::operator>> - + basic_istream::operator>> " Subclause 27.7.2.3, "Unformatted Input Functions"
    @@ -228,14 +111,10 @@ void f(std::istream &in) { Medium @@ -265,16 +144,11 @@ void f(std::istream &in) { @@ -309,18 +181,10 @@ void f(std::istream &in) { 2021.4 @@ -334,9 +198,7 @@ void f(std::istream &in) { @@ -406,11 +258,7 @@ void f(std::istream &in) { 4.10 @@ -419,17 +267,7 @@ void f(std::istream &in) {
    - - P18 - + P18 - - L1 - + L1
    - 6.1p0 + 6.2p0 - - MISC.MEM.NTERM - - - LANG.MEM.BO - LANG.MEM.TO - + MISC.MEM.NTERM + LANG.MEM.BOLANG.MEM.TO No space for null terminator @@ -292,9 +166,7 @@ void f(std::istream &in) { 2021.2 - - C++2835, C++2836, C++2839, C++5216 - + C++2835, C++2836, C++2839, C++5216 - - NNTS.MIGHT - - - NNTS.TAINTED - - - NNTS.MUST - - - SV.UNBOUND_STRING_INPUT.CIN - + NNTS.MIGHT + NNTS.TAINTED + NNTS.MUST + SV.UNBOUND_STRING_INPUT.CIN - - 489 S, 66 X, 70 X, 71 X - + 489 S, 66 X, 70 X, 71 X Partially implemented @@ -352,21 +214,11 @@ void f(std::istream &in) { 2021.2 - - CERT_CPP-STR50-b - - - CERT_CPP-STR50-c - - - CERT_CPP-STR50-e - - - CERT_CPP-STR50-f - - - CERT_CPP-STR50-g - + CERT_CPP-STR50-b + CERT_CPP-STR50-c + CERT_CPP-STR50-e + CERT_CPP-STR50-f + CERT_CPP-STR50-g Avoid overflow due to reading a not zero terminated string @@ -392,7 +244,7 @@ void f(std::istream &in) { Checks for: - Use of dangerous standard function, missing null in string array, buffer overflow from incorrect string format specifier, destination buffer overflow in string manipulation. + Use of dangerous standard functionse of dangerous standard function, missing null in string arrayissing null in string array, buffer overflow from incorrect string format specifieruffer overflow from incorrect string format specifier, destination buffer overflow in string manipulationestination buffer overflow in string manipulation. Rule partially covered.
    - - - S3519 - - + S3519
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    @@ -462,9 +300,7 @@ void f(std::istream &in) { diff --git a/cpp/cert/src/rules/STR51-CPP/DoNotAttemptToCreateAStringFromANullPointer-standard.qhelp b/cpp/cert/src/rules/STR51-CPP/DoNotAttemptToCreateAStringFromANullPointer-standard.qhelp index f8cd589d07..d13f380918 100644 --- a/cpp/cert/src/rules/STR51-CPP/DoNotAttemptToCreateAStringFromANullPointer-standard.qhelp +++ b/cpp/cert/src/rules/STR51-CPP/DoNotAttemptToCreateAStringFromANullPointer-standard.qhelp @@ -1,342 +1,65 @@
    -

    - The - - std::basic_string - - type uses the - - traits - - design pattern to handle implementation details of the various string types, resulting in a series of string-like classes with a common, underlying implementation. Specifically, the - - std::basic_string - - class is paired with - - std::char_traits - - to create the - - std::string - - , - - std::wstring - - , - - std::u16string - - , and - - std::u32string - - classes. The - - std::char_traits - - class is explicitly specialized to provide policy-based implementation details to the - - std::basic_string - - type. One such implementation detail is the - - std::char_traits::length() - - function, which is frequently used to determine the number of characters in a null-terminated string. According to the C++ Standard, [char.traits.require], Table 62 - [ - - ISO/IEC 14882-2014 - - ] - , passing a null pointer to this function is - - undefined behavior - - because it would result in dereferencing a null pointer. -

    -

    - The following - - std::basic_string - - member functions result in a call to - - std::char_traits::length() - - : -

    +

    The std::basic_string type uses the traits design pattern to handle implementation details of the various string types, resulting in a series of string-like classes with a common, underlying implementation. Specifically, the std::basic_string class is paired with std::char_traits to create the std::string, std::wstring, std::u16string, and std::u32string classes. The std::char_traits class is explicitly specialized to provide policy-based implementation details to the std::basic_string type. One such implementation detail is the std::char_traits::length() function, which is frequently used to determine the number of characters in a null-terminated string. According to the C++ Standard, [char.traits.require], Table 62 [ISO/IEC 14882-2014], passing a null pointer to this function is undefined behavior because it would result in dereferencing a null pointer.

    +

    The following std::basic_string member functions result in a call to std::char_traits::length():

      -
    • - - basic_string::basic_string(const charT *, const Allocator &) - -
    • -
    • - - basic_string &basic_string::append(const charT *) - -
    • -
    • - - basic_string &basic_string::assign(const charT *) - -
    • -
    • - - basic_string &basic_string::insert(size_type, const charT *) - -
    • -
    • - - basic_string &basic_string::replace(size_type, size_type, const charT *) - -
    • -
    • - - basic_string &basic_string::replace(const_iterator, const_iterator, const charT *) - -
    • -
    • - - size_type basic_string::find(const charT *, size_type) - -
    • -
    • - - size_type basic_string::rfind(const charT *, size_type) - -
    • -
    • - - size_type basic_string::find_first_of(const charT *, size_type) - -
    • -
    • - - size_type basic_string::find_last_of(const charT *, size_type) - -
    • -
    • - - size_type basic_string::find_first_not_of(const charT *, size_type) - -
    • -
    • - - size_type basic_string::find_last_not_of(const charT *, size_type) - -
    • -
    • - - int basic_string::compare(const charT *) - -
    • -
    • - - int basic_string::compare(size_type, size_type, const charT *) - -
    • -
    • - - basic_string &basic_string::operator=(const charT *) - -
    • -
    • - - basic_string &basic_string::operator+=(const charT *) - -
    • +
    • basic_string::basic_string(const charT *, const Allocator &)
    • +
    • basic_string &basic_string::append(const charT *)
    • +
    • basic_string &basic_string::assign(const charT *)
    • +
    • basic_string &basic_string::insert(size_type, const charT *)
    • +
    • basic_string &basic_string::replace(size_type, size_type, const charT *)
    • +
    • basic_string &basic_string::replace(const_iterator, const_iterator, const charT *)
    • +
    • size_type basic_string::find(const charT *, size_type)
    • +
    • size_type basic_string::rfind(const charT *, size_type)
    • +
    • size_type basic_string::find_first_of(const charT *, size_type)
    • +
    • size_type basic_string::find_last_of(const charT *, size_type)
    • +
    • size_type basic_string::find_first_not_of(const charT *, size_type)
    • +
    • size_type basic_string::find_last_not_of(const charT *, size_type)
    • +
    • int basic_string::compare(const charT *)
    • +
    • int basic_string::compare(size_type, size_type, const charT *)
    • +
    • basic_string &basic_string::operator=(const charT *)
    • +
    • basic_string &basic_string::operator+=(const charT *)
    -

    - The following - - std::basic_string - - nonmember functions result in a call to to - - std::char_traits::length() - - : -

    +

    The following std::basic_string nonmember functions result in a call to to std::char_traits::length():

      -
    • - - basic_string operator+(const charT *, const basic_string&) - -
    • -
    • - - basic_string operator+(const charT *, basic_string &&) - -
    • -
    • - - basic_string operator+(const basic_string &, const charT *) - -
    • -
    • - - basic_string operator+(basic_string &&, const charT *) - -
    • -
    • - - bool operator==(const charT *, const basic_string &) - -
    • -
    • - - bool operator==(const basic_string &, const charT *) - -
    • -
    • - - bool operator!=(const charT *, const basic_string &) - -
    • -
    • - - bool operator!=(const basic_string &, const charT *) - -
    • -
    • - - bool operator<(const charT *, const basic_string &) - -
    • -
    • - - bool operator<(const basic_string &, const charT *) - -
    • -
    • - - bool operator>(const charT *, const basic_string &) - -
    • -
    • - - bool operator>(const basic_string &, const charT *) - -
    • -
    • - - bool operator<=(const charT *, const basic_string &) - -
    • -
    • - - bool operator<=(const basic_string &, const charT *) - -
    • -
    • - - bool operator>=(const charT *, const basic_string &) - -
    • -
    • - - bool operator>=(const basic_string &, const charT *) - -
    • +
    • basic_string operator+(const charT *, const basic_string&)
    • +
    • basic_string operator+(const charT *, basic_string &&)
    • +
    • basic_string operator+(const basic_string &, const charT *)
    • +
    • basic_string operator+(basic_string &&, const charT *)
    • +
    • bool operator==(const charT *, const basic_string &)
    • +
    • bool operator==(const basic_string &, const charT *)
    • +
    • bool operator!=(const charT *, const basic_string &)
    • +
    • bool operator!=(const basic_string &, const charT *)
    • +
    • bool operator<(const charT *, const basic_string &)
    • +
    • bool operator<(const basic_string &, const charT *)
    • +
    • bool operator>(const charT *, const basic_string &)
    • +
    • bool operator>(const basic_string &, const charT *)
    • +
    • bool operator<=(const charT *, const basic_string &)
    • +
    • bool operator<=(const basic_string &, const charT *)
    • +
    • bool operator>=(const charT *, const basic_string &)
    • +
    • bool operator>=(const basic_string &, const charT *)
    -

    - Do not call any of the preceding functions with a null pointer as the - - const charT * - - argument. -

    -

    - This rule is a specific instance of - - EXP34-C. Do not dereference null pointers - - . -

    -

    - - Implementation Details - -

    -

    - Some standard library vendors, such as - - libstdc++, - - throw a - - std::logic_error - - when a null pointer is used in the above function calls, though not when calling - - std::char_traits::length() - - . However, - - std::logic_error - - is not a requirement of the C++ Standard, and some vendors (e.g., - - libc++ - - and the - - Microsoft Visual Studio STL - - ) do not implement this behavior. For portability, you should not rely on this behavior. -

    +

    Do not call any of the preceding functions with a null pointer as the const charT * argument.

    +

    This rule is a specific instance of EXP34-C. Do not dereference null pointers.

    +

    Implementation Details

    +

    Some standard library vendors, such as libstdc++, throw a std::logic_error when a null pointer is used in the above function calls, though not when calling std::char_traits::length(). However, std::logic_error is not a requirement of the C++ Standard, and some vendors (e.g., libc++ and the Microsoft Visual Studio STL) do not implement this behavior. For portability, you should not rely on this behavior.

    -

    - In this noncompliant code example, a - - std::string - - object is created from the results of a call to - - std::getenv() - - . However, because - - std::getenv() - - returns a null pointer on failure, this code can lead to - - undefined behavior - - when the environment variable does not exist (or some other error occurs). -

    - - #include <cstdlib> +

    In this noncompliant code example, a std::string object is created from the results of a call to std::getenv(). However, because std::getenv() returns a null pointer on failure, this code can lead to undefined behavior when the environment variable does not exist (or some other error occurs).

    + #include <cstdlib> #include <string> -  + void f() { std::string tmp(std::getenv("TMP")); if (!tmp.empty()) { // ... } -} - +}
    -

    - In this compliant solution, the results from the call to - - std::getenv() - - are checked for null before the - - std::string - - object is constructed. -

    - - #include <cstdlib> +

    In this compliant solution, the results from the call to std::getenv() are checked for null before the std::string object is constructed.

    + #include <cstdlib> #include <string> void f() { @@ -345,33 +68,10 @@ void f() { if (!tmp.empty()) { // ... } -} - +}
    -

    - Dereferencing a null pointer is - - undefined behavior - - , typically - - abnormal program termination - - . In some situations, however, dereferencing a null pointer can lead to the execution of arbitrary code [ - - Jack 2007 - - , - - van Sprundel 2006 - - ]. The indicated severity is for this more severe case; on platforms where it is not possible to - - exploit - - a null pointer dereference to execute arbitrary code, the actual severity is low. -

    +

    Dereferencing a null pointer is undefined behavior, typically abnormal program termination. In some situations, however, dereferencing a null pointer can lead to the execution of arbitrary code [Jack 2007, van Sprundel 2006]. The indicated severity is for this more severe case; on platforms where it is not possible to exploit a null pointer dereference to execute arbitrary code, the actual severity is low.

    Subclause 27.7.2.2.3, " - - basic_istream::operator>> - + basic_istream::operator>> " Subclause 27.7.2.3, "Unformatted Input Functions"
    @@ -408,14 +108,10 @@ void f() { Medium @@ -448,9 +144,7 @@ void f() { 20.10 @@ -465,9 +159,7 @@ void f() { 2021.2 @@ -482,81 +174,18 @@ void f() { 2021.4 @@ -571,9 +200,7 @@ void f() { 2021.2
    - - P18 - + P18 - - L1 - + L1
    - - assert_failure - + assert_failure - - C++4770, C++4771, C++4772, C++4773, C++4774 - + C++4770, C++4771, C++4772, C++4773, C++4774 - - - NPD.CHECK.CALL.MIGHT - - - - - NPD.CHECK.CALL.MUST - - - - - NPD.CHECK.MIGHT - - - - - NPD.CHECK.MUST - - - - - NPD.CONST.CALL - - - - - NPD.CONST.DEREF - - - - - NPD.FUNC.CALL.MIGHT - - - - - NPD.FUNC.CALL.MUST - - - - - NPD.FUNC.MIGHT - - - - - NPD.FUNC.MUST - - - - - NPD.GEN.CALL.MIGHT - - - NPD.GEN.CALL.MUST - - - NPD.GEN.MIGHT - - - NPD.GEN. - - - MUST - - - - - RNPD.CALL - - - RNPD.DEREF - - + NPD.CHECK.CALL.MIGHT + NPD.CHECK.CALL.MUST + NPD.CHECK.MIGHT + NPD.CHECK.MUST + NPD.CONST.CALL + NPD.CONST.DEREF + NPD.FUNC.CALL.MIGHT + NPD.FUNC.CALL.MUST + NPD.FUNC.MIGHT + NPD.FUNC.MUST + NPD.GEN.CALL.MIGHTNPD.GEN.CALL.MUSTNPD.GEN.MIGHTNPD.GEN.MUST + RNPD.CALLRNPD.DEREF - - CERT_CPP-STR51-a - + CERT_CPP-STR51-a Avoid null pointer dereferencing @@ -583,17 +210,7 @@ void f() {
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    diff --git a/cpp/cert/src/rules/STR52-CPP/UseValidReferencesForElementsOfString-standard.qhelp b/cpp/cert/src/rules/STR52-CPP/UseValidReferencesForElementsOfString-standard.qhelp index ad6cf14210..b437ef3527 100644 --- a/cpp/cert/src/rules/STR52-CPP/UseValidReferencesForElementsOfString-standard.qhelp +++ b/cpp/cert/src/rules/STR52-CPP/UseValidReferencesForElementsOfString-standard.qhelp @@ -1,144 +1,20 @@
    -

    - Since - - std::basic_string - - is a container of characters, this rule is a specific instance of - - CTR51-CPP. Use valid references, pointers, and iterators to reference elements of a container - - . As a container, it supports iterators just like other containers in the Standard Template Library. However, the - - std::basic_string - - template class has unusual invalidation semantics. The C++ Standard, [string.require], paragraph 5 [ - - ISO/IEC 14882-2014 - - ], states the following: -

    +

    Since std::basic_string is a container of characters, this rule is a specific instance of CTR51-CPP. Use valid references, pointers, and iterators to reference elements of a container. As a container, it supports iterators just like other containers in the Standard Template Library. However, the std::basic_string template class has unusual invalidation semantics. The C++ Standard, [string.require], paragraph 5 [ISO/IEC 14882-2014], states the following:

    -

    - References, pointers, and iterators referring to the elements of a - - basic_string - - sequence may be invalidated by the following uses of that - - basic_string - - object: -

    +

    References, pointers, and iterators referring to the elements of a basic_string sequence may be invalidated by the following uses of that basic_string object:

      -
    • - As an argument to any standard library function taking a reference to non-const - - basic_string - - as an argument. -
    • -
    • - Calling non-const member functions, except - - operator[] - - , - - at - - , - - front - - , - - back - - , - - begin - - , - - rbegin - - , - - end - - , and - - rend - - . -
    • +
    • As an argument to any standard library function taking a reference to non-const basic_string as an argument.
    • +
    • Calling non-const member functions, except operator[], at, front, back, begin, rbegin, end, and rend.
    -

    - Examples of standard library functions taking a reference to non- - - const - - - std::basic_string - - are - - std::swap() - - , - - ::operator>>(basic_istream &, string &) - - , and - - std::getline() - - . -

    -

    - Do not use an invalidated reference, pointer, or iterator because doing so results in - - undefined behavior - - . -

    -

    - Noncompliant Code Example -

    -

    - This noncompliant code example copies - - input - - into a - - std::string - - , replacing semicolon ( - - ;) - - characters with spaces. This example is noncompliant because the iterator - - loc - - is invalidated after the first call to - - insert() - - . The behavior of subsequent calls to - - insert() - - is undefined. -

    - - #include <string> -  +

    Examples of standard library functions taking a reference to non-const std::basic_string are std::swap(), ::operator>>(basic_istream &, string &), and std::getline().

    +

    Do not use an invalidated reference, pointer, or iterator because doing so results in undefined behavior.

    +

    Noncompliant Code Example

    +

    This noncompliant code example copies input into a std::string, replacing semicolon (;) characters with spaces. This example is noncompliant because the iterator loc is invalidated after the first call to insert(). The behavior of subsequent calls to insert() is undefined.

    + #include <string> + void f(const std::string &input) { std::string email; @@ -147,23 +23,11 @@ void f(const std::string &input) { for (auto i = input.begin(), e = input.end(); i != e; ++i, ++loc) { email.insert(loc, *i != ';' ? *i : ' '); } -} - +}
    -

    - In this compliant solution, the value of the iterator - - loc - - is updated as a result of each call to - - insert() - - so that the invalidated iterator is never accessed. The updated iterator is then incremented at the end of the loop. -

    - - #include <string> +

    In this compliant solution, the value of the iterator loc is updated as a result of each call to insert() so that the invalidated iterator is never accessed. The updated iterator is then incremented at the end of the loop.

    + #include <string> void f(const std::string &input) { std::string email; @@ -174,67 +38,36 @@ void f(const std::string &input) { loc = email.insert(loc, *i != ';' ? *i : ' '); } } - +
    -

    - This compliant solution uses a standard algorithm to perform the replacement. When possible, using a generic algorithm is preferable to inventing your own solution. -

    - - #include <algorithm> +

    This compliant solution uses a standard algorithm to perform the replacement. When possible, using a generic algorithm is preferable to inventing your own solution.

    + #include <algorithm> #include <string> void f(const std::string &input) { std::string email{input}; std::replace(email.begin(), email.end(), ';', ' '); -} - +}
    -

    - In this noncompliant code example, - - data - - is invalidated after the call to - - replace() - - , and so its use in - - g() - - is undefined behavior. -

    - - #include <iostream> +

    In this noncompliant code example, data is invalidated after the call to replace(), and so its use in g() is undefined behavior.

    + #include <iostream> #include <string> -  + extern void g(const char *); -  + void f(std::string &exampleString) { const char *data = exampleString.data(); // ... exampleString.replace(0, 2, "bb"); // ... g(data); -} - +}
    -

    - In this compliant solution, the pointer to - - exampleString - - 's internal buffer is not generated until after the modification from - - replace() - - has completed. -

    - - #include <iostream> +

    In this compliant solution, the pointer to exampleString's internal buffer is not generated until after the modification from replace() has completed.

    + #include <iostream> #include <string> extern void g(const char *); @@ -244,13 +77,10 @@ void f(std::string &exampleString) { exampleString.replace(0, 2, "bb"); // ... g(exampleString.data()); -} - +}
    -

    - Using an invalid reference, pointer, or iterator to a string object could allow an attacker to run arbitrary code. -

    +

    Using an invalid reference, pointer, or iterator to a string object could allow an attacker to run arbitrary code.

    @@ -287,14 +117,10 @@ void f(std::string &exampleString) { High @@ -317,6 +143,22 @@ void f(std::string &exampleString) { Description + + + + + + @@ -344,9 +184,7 @@ void f(std::string &exampleString) { 2021.2
    - - P6 - + P6 - - L2 - + L2
    + + CodeSonar + + + 6.2p0 + + ALLOC.UAF + + Use After Free +
    @@ -327,9 +169,7 @@ void f(std::string &exampleString) { 2021.2 - - C++4746, C++4747, C++4748, C++4749 - + C++4746, C++4747, C++4748, C++4749 - - CERT_CPP-STR52-a - + CERT_CPP-STR52-a Use valid references, pointers, and iterators to reference elements of a basic_string @@ -356,17 +194,7 @@ void f(std::string &exampleString) {
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    @@ -399,9 +227,7 @@ void f(std::string &exampleString) { diff --git a/cpp/cert/src/rules/STR53-CPP/RangeCheckStringElementAccess-standard.qhelp b/cpp/cert/src/rules/STR53-CPP/RangeCheckStringElementAccess-standard.qhelp index b55203807b..dc0c2c8df7 100644 --- a/cpp/cert/src/rules/STR53-CPP/RangeCheckStringElementAccess-standard.qhelp +++ b/cpp/cert/src/rules/STR53-CPP/RangeCheckStringElementAccess-standard.qhelp @@ -1,120 +1,24 @@
    -

    - The - - std::string - - index operators - - const_reference operator[](size_type) const - - and - - reference operator[](size_type) - - return the character stored at the specified position, - - pos - - . When - - pos >= size() - - , a reference to an object of type - - charT - - with value - - charT() - - is returned. The index operators are unchecked (no exceptions are thrown for range errors), and attempting to modify the resulting out-of-range object results in - - undefined behavior - - . -

    -

    - Similarly, the - - std::string::back() - - and - - std::string::front() - - functions are unchecked as they are defined to call through to the appropriate - - operator[]() - - without throwing. -

    -

    - Do not pass an out-of-range value as an argument to - - std::string::operator[]() - - . Similarly, do not call - - std::string::back() - - or - - std::string::front() - - on an empty string. This rule is a specific instance of - - CTR50-CPP. Guarantee that container indices and iterators are within the valid range - - . -

    +

    The std::string index operators const_reference operator[](size_type) const and reference operator[](size_type) return the character stored at the specified position, pos. When pos >= size(), a reference to an object of type charT with value charT() is returned. The index operators are unchecked (no exceptions are thrown for range errors), and attempting to modify the resulting out-of-range object results in undefined behavior.

    +

    Similarly, the std::string::back() and std::string::front() functions are unchecked as they are defined to call through to the appropriate operator[]() without throwing.

    +

    Do not pass an out-of-range value as an argument to std::string::operator[](). Similarly, do not call std::string::back() or std::string::front() on an empty string. This rule is a specific instance of CTR50-CPP. Guarantee that container indices and iterators are within the valid range.

    -

    - In this noncompliant code example, the value returned by the call to - - get_index() - - may be greater than the number of elements stored in the string, resulting in - - undefined behavior - - . -

    - - #include <string> -  +

    In this noncompliant code example, the value returned by the call to get_index() may be greater than the number of elements stored in the string, resulting in undefined behavior.

    + #include <string> + extern std::size_t get_index(); -  + void f() { std::string s("01234567"); s[get_index()] = '1'; -} - +}
    -

    - This compliant solution uses the - - std::basic_string::at() - - function, which behaves in a similar fashion to the index - - operator[] - - but throws a - - std::out_of_range - - exception if - - pos >= size(). - -

    - - #include <stdexcept> +

    This compliant solution uses the std::basic_string::at() function, which behaves in a similar fashion to the index operator[] but throws a std::out_of_range exception if pos >= size().

    + #include <stdexcept> #include <string> extern std::size_t get_index(); @@ -125,22 +29,11 @@ void f() { } catch (std::out_of_range &) { // Handle error } -} - +}
    -

    - This compliant solution checks that the value returned by - - get_index() - - is within a valid range before calling - - operator[](). - -

    - - #include <string> +

    This compliant solution checks that the value returned by get_index() is within a valid range before calling operator[]().

    + #include <string> extern std::size_t get_index(); @@ -152,37 +45,21 @@ void f() { } else { // Handle error } -} - +}
    -

    - This noncompliant code example attempts to replace the initial character in the string with a capitalized equivalent. However, if the given string is empty, the behavior is - - undefined - - . -

    - - #include <string> +

    This noncompliant code example attempts to replace the initial character in the string with a capitalized equivalent. However, if the given string is empty, the behavior is undefined.

    + #include <string> #include <locale> void capitalize(std::string &s) { std::locale loc; s.front() = std::use_facet<std::ctype<char>>(loc).toupper(s.front()); -} - +}
    -

    - In this compliant solution, the call to - - std::string::front() - - is made only if the string is not empty. -

    - - #include <string> +

    In this compliant solution, the call to std::string::front() is made only if the string is not empty.

    + #include <string> #include <locale> void capitalize(std::string &s) { @@ -192,17 +69,10 @@ void capitalize(std::string &s) { std::locale loc; s.front() = std::use_facet<std::ctype<char>>(loc).toupper(s.front()); -} - +}
    -

    - Unchecked element access can lead to out-of-bound reads and writes and write-anywhere - - exploits - - . These exploits can, in turn, lead to the execution of arbitrary code with the permissions of the vulnerable process. -

    +

    Unchecked element access can lead to out-of-bound reads and writes and write-anywhere exploits. These exploits can, in turn, lead to the execution of arbitrary code with the permissions of the vulnerable process.

    Subclause 21.4.1, " - - basic_string - + basic_string General Requirements"
    @@ -239,14 +109,10 @@ void capitalize(std::string &s) { Medium @@ -279,9 +145,7 @@ void capitalize(std::string &s) { 20.10 @@ -293,24 +157,14 @@ void capitalize(std::string &s) { @@ -347,9 +199,7 @@ void capitalize(std::string &s) { 2021.2 @@ -379,17 +229,7 @@ void capitalize(std::string &s) {
    - - P6 - + P6 - - L2 - + L2
    - - assert_failure - + assert_failure - 6.1p0 + 6.2p0 - - LANG.MEM.BO - - - LANG.MEM.BU - - - LANG.MEM.TBA - - - LANG.MEM.TO - - - LANG.MEM.TU - + LANG.MEM.BO + LANG.MEM.BU + LANG.MEM.TBA + LANG.MEM.TO + LANG.MEM.TU Buffer overrun @@ -330,9 +184,7 @@ void capitalize(std::string &s) { 2021.2 - - C++3162, C++3163, C++3164, C++3165 - + C++3162, C++3163, C++3164, C++3165 - - CERT_CPP-STR53-a - + CERT_CPP-STR53-a Guarantee that container indices are within the valid range @@ -371,7 +221,7 @@ void capitalize(std::string &s) { Checks for: - Array access out of bounds, array access with tainted index, pointer dereference with tainted offset. + Array access out of boundsrray access out of bounds, array access with tainted indexrray access with tainted index, pointer dereference with tainted offsetointer dereference with tainted offset. Rule partially covered.
    -

    - Search for - - vulnerabilities - - resulting from the violation of this rule on the - - CERT website - - . -

    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    @@ -422,9 +262,7 @@ void capitalize(std::string &s) { diff --git a/cpp/cert/test/qlpack.yml b/cpp/cert/test/qlpack.yml index adf42df072..9d0f025046 100644 --- a/cpp/cert/test/qlpack.yml +++ b/cpp/cert/test/qlpack.yml @@ -1,4 +1,4 @@ name: cert-cpp-coding-standards-tests -version: 2.0.0 +version: 2.1.0 libraryPathDependencies: cert-cpp-coding-standards extractor: cpp diff --git a/cpp/common/src/codingstandards/cpp/Expr.qll b/cpp/common/src/codingstandards/cpp/Expr.qll index 58275cf125..f5ece8b76a 100644 --- a/cpp/common/src/codingstandards/cpp/Expr.qll +++ b/cpp/common/src/codingstandards/cpp/Expr.qll @@ -13,6 +13,13 @@ class FullExpr extends Expr { } } +/** A subexpression of another expression. */ +class ConstituentExpr extends Expr { + ConstituentExpr() { exists(FullExpr e | e = this.getParent+()) } + + FullExpr getFullExpr() { result.getAChild+() = this } +} + /** An overloaded assign expression. */ class OverloadedAssignExpr extends FunctionCall { OverloadedAssignExpr() { this.getTarget().getName() = "operator=" } diff --git a/cpp/common/src/codingstandards/cpp/FgetsErrorManagement.qll b/cpp/common/src/codingstandards/cpp/FgetsErrorManagement.qll new file mode 100644 index 0000000000..9ca59bc4ce --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/FgetsErrorManagement.qll @@ -0,0 +1,160 @@ +/** + * A module for reasoning about the error management in the standard functions + * `fgets`, `fgets` and their wrappers. + */ + +import cpp +import semmle.code.cpp.dataflow.DataFlow +import semmle.code.cpp.controlflow.Guards + +/* + * Models calls to fgets fgetws and their wrappers + */ + +class FgetsLikeCall extends FunctionCall { + Expr buffer; + Expr stream; + + FgetsLikeCall() { + this.getTarget().hasGlobalName(["fgets", "fgetws"]) and + buffer = this.getArgument(0) and + stream = this.getArgument(2) + or + exists(FgetsLikeCall internalCall, ReturnStmt retStmt, int buffer_pos, int stream_pos | + internalCall.getEnclosingFunction() = this.getTarget() and + retStmt.getEnclosingFunction() = this.getTarget() and + // Map return value + DataFlow::localExprFlow(internalCall, retStmt.getExpr()) and + // Map buffer argument + buffer = this.getArgument(buffer_pos) and + DataFlow::localFlow(DataFlow::parameterNode(this.getTarget().getParameter(buffer_pos)), + DataFlow::exprNode(internalCall.getBuffer())) and + // Map stream argument + stream = this.getArgument(stream_pos) and + DataFlow::localFlow(DataFlow::parameterNode(this.getTarget().getParameter(stream_pos)), + DataFlow::exprNode(internalCall.getStream())) + ) + } + + Expr getBuffer() { result = buffer } + + Expr getStream() { result = stream } +} + +/* + * A simple boolean expression built on a fgets-like function call + * The boolean expression can span multiple statments + * (e.g. a = !x; b=!a;) + */ + +class BooleanFgetsExpr extends Expr { + boolean isNull; + FgetsLikeCall fgetCall; + Expr operand; + + BooleanFgetsExpr() { + // if(fgets) + fgetCall = this and + isNull = false and + operand = this + or + exists(BooleanFgetsExpr e | + e != this and + operand = e and + fgetCall = e.getFgetCall() and + ( + // if(x==0) + e = this.(EQExpr).getAnOperand() and + this.(EQExpr).getAnOperand() instanceof NullValue and + isNull = e.isNull().booleanNot() + or + // if(x!=0) + e = this.(NEExpr).getAnOperand() and + this.(NEExpr).getAnOperand() instanceof NullValue and + isNull = e.isNull() + or + // if(x) + DataFlow::localExprFlow(e, this) and + isNull = e.isNull() + or + // if(!x) + e = this.(NotExpr).getOperand() and + isNull = e.isNull().booleanNot() + or + // if(x && cond) + e = this.(LogicalAndExpr).getAnOperand() and + ( + e.isNull() = false and + isNull = false + or + e.isNull() = true and + ( + isNull = true + or + isNull = false + ) + ) + or + // if(x || cond) + e = this.(LogicalOrExpr).getAnOperand() and + ( + e.isNull() = true and + isNull = true + or + e.isNull() = false and + ( + isNull = true + or + isNull = false + ) + ) + ) + ) + } + + boolean isNull() { result = isNull } + + Expr getFgetCall() { result = fgetCall } + + Expr getOperand() { result = operand } +} + +class FgetsGuard extends BooleanFgetsExpr { + FgetsGuard() { + exists(IfStmt i | i.getCondition() = this) or exists(Loop i | i.getCondition() = this) + } + + Stmt getThenSuccessor() { + exists(IfStmt i | i.getCondition() = this and result = i.getThen()) + or + exists(Loop i | i.getCondition() = this and result = i.getStmt()) + } + + Stmt getElseSuccessor() { + exists(IfStmt i | + i.getCondition() = this and + ( + i.hasElse() and result = i.getElse() + or + not i.hasElse() and result = i.getFollowingStmt() + ) + ) + or + exists(Loop i | + i.getCondition() = this and + result = i.getFollowingStmt() + ) + } + + ControlFlowNode getNullSuccessor() { + this.isNull() = true and result = this.getThenSuccessor() + or + this.isNull() = false and result = getElseSuccessor() + } + + ControlFlowNode getNonNullSuccessor() { + this.isNull() = true and result = this.getElseSuccessor() + or + this.isNull() = false and result = getThenSuccessor() + } +} diff --git a/cpp/common/src/codingstandards/cpp/Ordering.qll b/cpp/common/src/codingstandards/cpp/Ordering.qll index 19577975b7..8f33e15b59 100644 --- a/cpp/common/src/codingstandards/cpp/Ordering.qll +++ b/cpp/common/src/codingstandards/cpp/Ordering.qll @@ -1,4 +1,5 @@ import cpp +import codingstandards.cpp.Expr import codingstandards.cpp.SideEffect module Ordering { diff --git a/cpp/common/src/codingstandards/cpp/SideEffect.qll b/cpp/common/src/codingstandards/cpp/SideEffect.qll index 4e933c0e76..4b78b5c818 100644 --- a/cpp/common/src/codingstandards/cpp/SideEffect.qll +++ b/cpp/common/src/codingstandards/cpp/SideEffect.qll @@ -1,12 +1,11 @@ /** A module to reason about side effects. */ import cpp -import semmle.code.cpp.security.FileWrite -import semmle.code.cpp.PODType03 import semmle.code.cpp.dataflow.DataFlow -import exceptions.ExceptionFlow -import codingstandards.cpp.Allocations -import codingstandards.cpp.Expr +private import exceptions.ExceptionFlow +private import codingstandards.cpp.Expr +private import codingstandards.cpp.Variable +private import codingstandards.cpp.sideeffect.Customizations /** * A side effect that captures external, global, and local side effects. @@ -17,14 +16,8 @@ import codingstandards.cpp.Expr */ class SideEffect extends Expr { SideEffect() { - not this instanceof SideEffect::Exclusion::Range and - ( - this instanceof ExternalSideEffect::Range - or - this instanceof GlobalSideEffect::Range - or - this instanceof LocalSideEffect::Range - ) + not this instanceof SideEffect::ExclusionRange and + this instanceof SideEffect::Range } } @@ -33,19 +26,13 @@ class NonLocalSideEffect extends SideEffect { NonLocalSideEffect() { not this instanceof LocalSideEffect } } -module SideEffect { - module Exclusion { - abstract class Range extends Expr { } - } -} - /** A compiler generated side effect (typicall of the type ClassObjectSideEffect) that we want to exclude. */ -private class CompilerGeneratedSideEffect extends SideEffect::Exclusion::Range { +private class CompilerGeneratedSideEffect extends SideEffect::ExclusionRange { CompilerGeneratedSideEffect() { this.isCompilerGenerated() } } /* A side effect occuring in a source file not part of the code repository (e.g. included standard header files) */ -private class NonSourceSideEffect extends SideEffect::Exclusion::Range { +private class NonSourceSideEffect extends SideEffect::ExclusionRange { NonSourceSideEffect() { not exists(this.getFile().getRelativePath()) } } @@ -72,10 +59,6 @@ class ExternalSideEffect extends SideEffect { ExternalSideEffect() { this instanceof ExternalSideEffect::Range } } -module ExternalSideEffect { - abstract class Range extends Expr { } -} - /** Holds if the expression `e` produces an external, global, or local (limited to expression `e`) side effect. */ predicate hasSideEffect(Expr e) { exists(getASideEffect(e)) } @@ -120,20 +103,11 @@ SideEffect getAnExternalOrGlobalSideEffectInFunction(Function f) { result = getAGlobalSideEffectInFunction(f) } -/** A function call that performs an IO operation and thus exhibts an external side effect. */ -private class IOFunctionCall extends FunctionCall, ExternalSideEffect::Range { - IOFunctionCall() { this instanceof BasicOStreamCall or this instanceof FileWrite } -} - /** A side effect that affects global the state of the program. */ class GlobalSideEffect extends SideEffect { GlobalSideEffect() { this instanceof GlobalSideEffect::Range } } -module GlobalSideEffect { - abstract class Range extends Expr { } -} - /** Gets a global side effect produced by the expression `e`. */ GlobalSideEffect getAGlobalSideEffect(Expr e) { result = e.getAChild*() @@ -193,83 +167,6 @@ private predicate modifyingOperator(Function op) { ] } -private class ResourceReleaseCall extends ExternalSideEffect::Range { - ResourceReleaseCall() { freeExpr(this, _, _) } -} - -/** A pointer or reference parameter. */ -class AliasParameter extends Parameter { - AliasParameter() { this.getUnspecifiedType() instanceof DerivedType } - - /** - * Gets an expression that modifies the object referenced by this parameter, but doesn't - * track whether the reference is changed (i.e., the alias parameter is reassigned a different object). - * This might attribute effects to an object that are performed on another object that happen after the pointer - * is changed. - */ - Expr getAnEffect() { - exists(VariableAccess va | va.getTarget() = this | - result = getAnEffect(va) and - ( - not this.getUnspecifiedType() instanceof PointerType - or - // Exclude effects that change the who we point to, since we care about changes to the referenced object. - not result.(AssignExpr).getLValue() = va and - not result.(CrementOperation).getOperand() = va - ) - ) - } - - /** Holds if there exists an expresison that modifies the value referred by the parameter. */ - predicate isModified() { exists(getAnEffect()) } -} - -/** An effect that changes the value of a variable. */ -class VariableEffect extends Expr { - VariableAccess va; - Variable v; - - VariableEffect() { this = getAnEffect(va) and v = va.getTarget() } - - Variable getTarget() { result = v } - - VariableAccess getAnAccess() { result = va } - - // Holds if an effect modifies the identity of an object and not the entire object. - predicate isPartial() { - exists(VariableAccess qualifiedAccess | qualifiedAccess.getQualifier() = getAnAccess()) - or - exists(ArrayExpr array | array.getArrayBase() = getAnAccess()) - } -} - -class MemberVariableEffect extends Expr { - MemberVariableEffect() { - this instanceof VariableEffect - or - this instanceof ConstructorFieldInit - } - - Variable getTarget() { - result = this.(VariableEffect).getTarget() - or - result = this.(ConstructorFieldInit).getTarget() - } -} - -/** Gets a member variable effect in function `f` or a function reachable from `f`. */ -MemberVariableEffect getAMemberVariableEffect(MemberFunction f) { - result.getEnclosingFunction() = f and - exists(MemberVariable v | v = result.getTarget() | v.getDeclaringType() = f.getDeclaringType()) - or - exists(FunctionCall call, MemberFunction other | - call.getQualifier() instanceof ThisExpr and - call.getEnclosingFunction() = f and - call.getTarget() = other and - result = getAMemberVariableEffect(other) - ) -} - /** Gets an effect directly applied to expression `base` or indirectly but changes the identity of `base`. */ Expr getAnEffect(Expr base) { // base cases @@ -324,83 +221,86 @@ Expr getAnEffect(Expr base) { ) } -private class DirectStaticStorageDurationVariableModification extends VariableEffect, - GlobalSideEffect::Range { - DirectStaticStorageDurationVariableModification() { - this.getTarget() instanceof StaticStorageDurationVariable - } -} - -private class ConstructorFieldInitEffect extends GlobalSideEffect::Range, ConstructorFieldInit { } - -private class AliasVariableModification extends VariableEffect, GlobalSideEffect::Range { - AliasVariableModification() { this.getTarget() instanceof AliasParameter } -} - -private class ViolatileAccess extends ExternalSideEffect::Range, VariableAccess { - ViolatileAccess() { this.getTarget().(Variable).isVolatile() } -} - /** A side effect happing as part of a subexpression that can result in unexpected/unspecified behavior when unsequenced. */ class LocalSideEffect extends SideEffect { LocalSideEffect() { this instanceof LocalSideEffect::Range } } -module LocalSideEffect { - abstract class Range extends Expr { } -} - /** Gets a local side effect produced by the expression `e`. */ LocalSideEffect getALocalSideEffect(Expr e) { result = e.getAChild*() } -/** A subexpression of another expression. */ -class ConstituentExpr extends Expr { - ConstituentExpr() { exists(FullExpr e | e = this.getParent+()) } +/** An effect that changes the value of a variable. */ +class VariableEffect extends Expr { + VariableAccess va; + Variable v; - FullExpr getFullExpr() { result.getAChild+() = this } -} + VariableEffect() { this = getAnEffect(va) and v = va.getTarget() } -/** A variable of type scalar. */ -class ScalarVariable extends Variable { - ScalarVariable() { isScalarType03(this.getType()) } -} + Variable getTarget() { result = v } -private Expr getAnOperandPlus(Operation op) { - result = op.getAnOperand() - or - exists(Operation oper | oper = op.getAnOperand() | result = getAnOperandPlus(oper)) -} + VariableAccess getAnAccess() { result = va } -/** Holds if the scalar variable is incremented or decremented using a prefix or postfix operation. */ -predicate hasScalarSideEffects(ConstituentExpr e, ScalarVariable v) { - exists(VariableAccess va | - va.getTarget() = v and - e.(CrementOperation).getAnOperand() = va - ) + // Holds if an effect modifies the identity of an object and not the entire object. + predicate isPartial() { + exists(VariableAccess qualifiedAccess | qualifiedAccess.getQualifier() = getAnAccess()) + or + exists(ArrayExpr array | array.getArrayBase() = getAnAccess()) + } } -private class LocalScalarValueModificationAndValueComputation extends LocalSideEffect::Range { - LocalScalarValueModificationAndValueComputation() { - exists(ScalarVariable v | - v instanceof LocalVariable and - hasScalarSideEffects(this, v) - ) +class MemberVariableEffect extends Expr { + MemberVariableEffect() { + this instanceof VariableEffect + or + this instanceof ConstructorFieldInit } -} -private class PointerCrementOperation extends CrementOperation, LocalSideEffect::Range { - PointerCrementOperation() { - exists(VariableAccess va | va.getType() instanceof PointerType | this.getAnOperand() = va) + Variable getTarget() { + result = this.(VariableEffect).getTarget() + or + result = this.(ConstructorFieldInit).getTarget() } } -private class ReturnedReferenceModificationAndValueComputation extends LocalSideEffect::Range { - ReturnedReferenceModificationAndValueComputation() { - exists(FunctionCall call | - this.(CrementOperation).getOperand() = call and - call.getType().getUnderlyingType().getUnspecifiedType() instanceof ReferenceType +/** Gets a member variable effect in function `f` or a function reachable from `f`. */ +MemberVariableEffect getAMemberVariableEffect(MemberFunction f) { + result.getEnclosingFunction() = f and + exists(MemberVariable v | v = result.getTarget() | v.getDeclaringType() = f.getDeclaringType()) + or + exists(FunctionCall call, MemberFunction other | + call.getQualifier() instanceof ThisExpr and + call.getEnclosingFunction() = f and + call.getTarget() = other and + result = getAMemberVariableEffect(other) + ) +} + +/** A pointer or reference parameter. */ +class AliasParameter extends Parameter { + AliasParameter() { this.getUnspecifiedType() instanceof DerivedType } + + /** + * Gets an expression that modifies the object referenced by this parameter, but doesn't + * track whether the reference is changed (i.e., the alias parameter is reassigned a different object). + * This might attribute effects to an object that are performed on another object that happen after the pointer + * is changed. + */ + Expr getAnEffect() { + exists(VariableAccess va | va.getTarget() = this | + result = getAnEffect(va) and + ( + // Any effect on a reference type + this.getUnspecifiedType() instanceof ReferenceType + or + // Exclude effects that change the who we point to, since we care about changes to the referenced object. + not result.(AssignExpr).getLValue() = va and + not result.(CrementOperation).getOperand() = va + ) ) } + + /** Holds if there exists an expresison that modifies the value referred by the parameter. */ + predicate isModified() { exists(getAnEffect()) } } module PathGraph { diff --git a/cpp/common/src/codingstandards/cpp/Variable.qll b/cpp/common/src/codingstandards/cpp/Variable.qll new file mode 100644 index 0000000000..dba7af480a --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/Variable.qll @@ -0,0 +1,7 @@ +import cpp +import semmle.code.cpp.PODType03 + +/** A variable of type scalar. */ +class ScalarVariable extends Variable { + ScalarVariable() { isScalarType03(this.getType()) } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/IO2.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/IO2.qll new file mode 100644 index 0000000000..6eca59ea3c --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/IO2.qll @@ -0,0 +1,74 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype IO2Query = + TDoNotCopyAFileObjectQuery() or + TResetStringsOnFgetsOrFgetwsFailureQuery() or + TDoNotCallGetcAndPutcWithSideEffectsQuery() or + TOnlyUseValuesForFsetposThatAreReturnedFromFgetposQuery() + +predicate isIO2QueryMetadata(Query query, string queryId, string ruleId) { + query = + // `Query` instance for the `doNotCopyAFileObject` query + IO2Package::doNotCopyAFileObjectQuery() and + queryId = + // `@id` for the `doNotCopyAFileObject` query + "c/cert/do-not-copy-a-file-object" and + ruleId = "FIO38-C" + or + query = + // `Query` instance for the `resetStringsOnFgetsOrFgetwsFailure` query + IO2Package::resetStringsOnFgetsOrFgetwsFailureQuery() and + queryId = + // `@id` for the `resetStringsOnFgetsOrFgetwsFailure` query + "c/cert/reset-strings-on-fgets-or-fgetws-failure" and + ruleId = "FIO40-C" + or + query = + // `Query` instance for the `doNotCallGetcAndPutcWithSideEffects` query + IO2Package::doNotCallGetcAndPutcWithSideEffectsQuery() and + queryId = + // `@id` for the `doNotCallGetcAndPutcWithSideEffects` query + "c/cert/do-not-call-getc-and-putc-with-side-effects" and + ruleId = "FIO41-C" + or + query = + // `Query` instance for the `onlyUseValuesForFsetposThatAreReturnedFromFgetpos` query + IO2Package::onlyUseValuesForFsetposThatAreReturnedFromFgetposQuery() and + queryId = + // `@id` for the `onlyUseValuesForFsetposThatAreReturnedFromFgetpos` query + "c/cert/only-use-values-for-fsetpos-that-are-returned-from-fgetpos" and + ruleId = "FIO44-C" +} + +module IO2Package { + Query doNotCopyAFileObjectQuery() { + //autogenerate `Query` type + result = + // `Query` type for `doNotCopyAFileObject` query + TQueryC(TIO2PackageQuery(TDoNotCopyAFileObjectQuery())) + } + + Query resetStringsOnFgetsOrFgetwsFailureQuery() { + //autogenerate `Query` type + result = + // `Query` type for `resetStringsOnFgetsOrFgetwsFailure` query + TQueryC(TIO2PackageQuery(TResetStringsOnFgetsOrFgetwsFailureQuery())) + } + + Query doNotCallGetcAndPutcWithSideEffectsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `doNotCallGetcAndPutcWithSideEffects` query + TQueryC(TIO2PackageQuery(TDoNotCallGetcAndPutcWithSideEffectsQuery())) + } + + Query onlyUseValuesForFsetposThatAreReturnedFromFgetposQuery() { + //autogenerate `Query` type + result = + // `Query` type for `onlyUseValuesForFsetposThatAreReturnedFromFgetpos` query + TQueryC(TIO2PackageQuery(TOnlyUseValuesForFsetposThatAreReturnedFromFgetposQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll index 1880b8daf0..54910ea2bc 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll @@ -3,15 +3,24 @@ import cpp import codingstandards.cpp.exclusions.RuleMetadata //** Import packages for this language **/ import IO1 +import IO2 import Preprocessor1 +import SideEffects1 +import Syntax /** The TQuery type representing this language * */ newtype TCQuery = TIO1PackageQuery(IO1Query q) or - TPreprocessor1PackageQuery(Preprocessor1Query q) + TIO2PackageQuery(IO2Query q) or + TPreprocessor1PackageQuery(Preprocessor1Query q) or + TSideEffects1PackageQuery(SideEffects1Query q) or + TSyntaxPackageQuery(SyntaxQuery q) /** The metadata predicate * */ predicate isQueryMetadata(Query query, string queryId, string ruleId) { isIO1QueryMetadata(query, queryId, ruleId) or - isPreprocessor1QueryMetadata(query, queryId, ruleId) + isIO2QueryMetadata(query, queryId, ruleId) or + isPreprocessor1QueryMetadata(query, queryId, ruleId) or + isSideEffects1QueryMetadata(query, queryId, ruleId) or + isSyntaxQueryMetadata(query, queryId, ruleId) } diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/SideEffects1.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/SideEffects1.qll new file mode 100644 index 0000000000..b3bcac75eb --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/SideEffects1.qll @@ -0,0 +1,170 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype SideEffects1Query = + TDependenceOnOrderOfScalarEvaluationForSideEffectsQuery() or + TDependenceOnOrderOfFunctionArgumentsForSideEffectsQuery() or + TUnevaluatedOperandWithSideEffectQuery() or + TAssignmentsInSelectionStatementsQuery() or + TUnenclosedSizeofOperandQuery() or + TImplicitPrecedenceOfOperatorsInExpressionQuery() or + TInitializerListsContainPersistentSideEffectsQuery() or + TResultOfAnAssignmentOperatorShouldNotBeUsedQuery() or + TPossibleSuppressedSideEffectInLogicOperatorOperandQuery() or + TSizeofOperandWithSideEffectQuery() + +predicate isSideEffects1QueryMetadata(Query query, string queryId, string ruleId) { + query = + // `Query` instance for the `dependenceOnOrderOfScalarEvaluationForSideEffects` query + SideEffects1Package::dependenceOnOrderOfScalarEvaluationForSideEffectsQuery() and + queryId = + // `@id` for the `dependenceOnOrderOfScalarEvaluationForSideEffects` query + "c/cert/dependence-on-order-of-scalar-evaluation-for-side-effects" and + ruleId = "EXP30-C" + or + query = + // `Query` instance for the `dependenceOnOrderOfFunctionArgumentsForSideEffects` query + SideEffects1Package::dependenceOnOrderOfFunctionArgumentsForSideEffectsQuery() and + queryId = + // `@id` for the `dependenceOnOrderOfFunctionArgumentsForSideEffects` query + "c/cert/dependence-on-order-of-function-arguments-for-side-effects" and + ruleId = "EXP30-C" + or + query = + // `Query` instance for the `unevaluatedOperandWithSideEffect` query + SideEffects1Package::unevaluatedOperandWithSideEffectQuery() and + queryId = + // `@id` for the `unevaluatedOperandWithSideEffect` query + "c/cert/unevaluated-operand-with-side-effect" and + ruleId = "EXP44-C" + or + query = + // `Query` instance for the `assignmentsInSelectionStatements` query + SideEffects1Package::assignmentsInSelectionStatementsQuery() and + queryId = + // `@id` for the `assignmentsInSelectionStatements` query + "c/cert/assignments-in-selection-statements" and + ruleId = "EXP45-C" + or + query = + // `Query` instance for the `unenclosedSizeofOperand` query + SideEffects1Package::unenclosedSizeofOperandQuery() and + queryId = + // `@id` for the `unenclosedSizeofOperand` query + "c/misra/unenclosed-sizeof-operand" and + ruleId = "RULE-12-1" + or + query = + // `Query` instance for the `implicitPrecedenceOfOperatorsInExpression` query + SideEffects1Package::implicitPrecedenceOfOperatorsInExpressionQuery() and + queryId = + // `@id` for the `implicitPrecedenceOfOperatorsInExpression` query + "c/misra/implicit-precedence-of-operators-in-expression" and + ruleId = "RULE-12-1" + or + query = + // `Query` instance for the `initializerListsContainPersistentSideEffects` query + SideEffects1Package::initializerListsContainPersistentSideEffectsQuery() and + queryId = + // `@id` for the `initializerListsContainPersistentSideEffects` query + "c/misra/initializer-lists-contain-persistent-side-effects" and + ruleId = "RULE-13-1" + or + query = + // `Query` instance for the `resultOfAnAssignmentOperatorShouldNotBeUsed` query + SideEffects1Package::resultOfAnAssignmentOperatorShouldNotBeUsedQuery() and + queryId = + // `@id` for the `resultOfAnAssignmentOperatorShouldNotBeUsed` query + "c/misra/result-of-an-assignment-operator-should-not-be-used" and + ruleId = "RULE-13-4" + or + query = + // `Query` instance for the `possibleSuppressedSideEffectInLogicOperatorOperand` query + SideEffects1Package::possibleSuppressedSideEffectInLogicOperatorOperandQuery() and + queryId = + // `@id` for the `possibleSuppressedSideEffectInLogicOperatorOperand` query + "c/misra/possible-suppressed-side-effect-in-logic-operator-operand" and + ruleId = "RULE-13-5" + or + query = + // `Query` instance for the `sizeofOperandWithSideEffect` query + SideEffects1Package::sizeofOperandWithSideEffectQuery() and + queryId = + // `@id` for the `sizeofOperandWithSideEffect` query + "c/misra/sizeof-operand-with-side-effect" and + ruleId = "RULE-13-6" +} + +module SideEffects1Package { + Query dependenceOnOrderOfScalarEvaluationForSideEffectsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `dependenceOnOrderOfScalarEvaluationForSideEffects` query + TQueryC(TSideEffects1PackageQuery(TDependenceOnOrderOfScalarEvaluationForSideEffectsQuery())) + } + + Query dependenceOnOrderOfFunctionArgumentsForSideEffectsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `dependenceOnOrderOfFunctionArgumentsForSideEffects` query + TQueryC(TSideEffects1PackageQuery(TDependenceOnOrderOfFunctionArgumentsForSideEffectsQuery())) + } + + Query unevaluatedOperandWithSideEffectQuery() { + //autogenerate `Query` type + result = + // `Query` type for `unevaluatedOperandWithSideEffect` query + TQueryC(TSideEffects1PackageQuery(TUnevaluatedOperandWithSideEffectQuery())) + } + + Query assignmentsInSelectionStatementsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `assignmentsInSelectionStatements` query + TQueryC(TSideEffects1PackageQuery(TAssignmentsInSelectionStatementsQuery())) + } + + Query unenclosedSizeofOperandQuery() { + //autogenerate `Query` type + result = + // `Query` type for `unenclosedSizeofOperand` query + TQueryC(TSideEffects1PackageQuery(TUnenclosedSizeofOperandQuery())) + } + + Query implicitPrecedenceOfOperatorsInExpressionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `implicitPrecedenceOfOperatorsInExpression` query + TQueryC(TSideEffects1PackageQuery(TImplicitPrecedenceOfOperatorsInExpressionQuery())) + } + + Query initializerListsContainPersistentSideEffectsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `initializerListsContainPersistentSideEffects` query + TQueryC(TSideEffects1PackageQuery(TInitializerListsContainPersistentSideEffectsQuery())) + } + + Query resultOfAnAssignmentOperatorShouldNotBeUsedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `resultOfAnAssignmentOperatorShouldNotBeUsed` query + TQueryC(TSideEffects1PackageQuery(TResultOfAnAssignmentOperatorShouldNotBeUsedQuery())) + } + + Query possibleSuppressedSideEffectInLogicOperatorOperandQuery() { + //autogenerate `Query` type + result = + // `Query` type for `possibleSuppressedSideEffectInLogicOperatorOperand` query + TQueryC(TSideEffects1PackageQuery(TPossibleSuppressedSideEffectInLogicOperatorOperandQuery())) + } + + Query sizeofOperandWithSideEffectQuery() { + //autogenerate `Query` type + result = + // `Query` type for `sizeofOperandWithSideEffect` query + TQueryC(TSideEffects1PackageQuery(TSizeofOperandWithSideEffectQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Syntax.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Syntax.qll new file mode 100644 index 0000000000..8109741e20 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Syntax.qll @@ -0,0 +1,122 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype SyntaxQuery = + TCharacterSequencesAndUsedWithinACommentQuery() or + TLineSplicingUsedInCommentsQuery() or + TOctalAndHexadecimalEscapeSequencesNotTerminatedQuery() or + TSectionsOfCodeShallNotBeCommentedOutQuery() or + TIdentifiersInTheSameNameSpaceUnambiguousQuery() or + TUOrUSuffixRepresentedInUnsignedTypeQuery() or + TLowercaseCharacterLUsedInLiteralSuffixQuery() + +predicate isSyntaxQueryMetadata(Query query, string queryId, string ruleId) { + query = + // `Query` instance for the `characterSequencesAndUsedWithinAComment` query + SyntaxPackage::characterSequencesAndUsedWithinACommentQuery() and + queryId = + // `@id` for the `characterSequencesAndUsedWithinAComment` query + "c/misra/character-sequences-and-used-within-a-comment" and + ruleId = "RULE-3-1" + or + query = + // `Query` instance for the `lineSplicingUsedInComments` query + SyntaxPackage::lineSplicingUsedInCommentsQuery() and + queryId = + // `@id` for the `lineSplicingUsedInComments` query + "c/misra/line-splicing-used-in-comments" and + ruleId = "RULE-3-2" + or + query = + // `Query` instance for the `octalAndHexadecimalEscapeSequencesNotTerminated` query + SyntaxPackage::octalAndHexadecimalEscapeSequencesNotTerminatedQuery() and + queryId = + // `@id` for the `octalAndHexadecimalEscapeSequencesNotTerminated` query + "c/misra/octal-and-hexadecimal-escape-sequences-not-terminated" and + ruleId = "RULE-4-1" + or + query = + // `Query` instance for the `sectionsOfCodeShallNotBeCommentedOut` query + SyntaxPackage::sectionsOfCodeShallNotBeCommentedOutQuery() and + queryId = + // `@id` for the `sectionsOfCodeShallNotBeCommentedOut` query + "c/misra/sections-of-code-shall-not-be-commented-out" and + ruleId = "RULE-4-4" + or + query = + // `Query` instance for the `identifiersInTheSameNameSpaceUnambiguous` query + SyntaxPackage::identifiersInTheSameNameSpaceUnambiguousQuery() and + queryId = + // `@id` for the `identifiersInTheSameNameSpaceUnambiguous` query + "c/misra/identifiers-in-the-same-name-space-unambiguous" and + ruleId = "DIR-4-5" + or + query = + // `Query` instance for the `uOrUSuffixRepresentedInUnsignedType` query + SyntaxPackage::uOrUSuffixRepresentedInUnsignedTypeQuery() and + queryId = + // `@id` for the `uOrUSuffixRepresentedInUnsignedType` query + "c/misra/u-or-u-suffix-represented-in-unsigned-type" and + ruleId = "RULE-7-2" + or + query = + // `Query` instance for the `lowercaseCharacterLUsedInLiteralSuffix` query + SyntaxPackage::lowercaseCharacterLUsedInLiteralSuffixQuery() and + queryId = + // `@id` for the `lowercaseCharacterLUsedInLiteralSuffix` query + "c/misra/lowercase-character-l-used-in-literal-suffix" and + ruleId = "RULE-7-3" +} + +module SyntaxPackage { + Query characterSequencesAndUsedWithinACommentQuery() { + //autogenerate `Query` type + result = + // `Query` type for `characterSequencesAndUsedWithinAComment` query + TQueryC(TSyntaxPackageQuery(TCharacterSequencesAndUsedWithinACommentQuery())) + } + + Query lineSplicingUsedInCommentsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `lineSplicingUsedInComments` query + TQueryC(TSyntaxPackageQuery(TLineSplicingUsedInCommentsQuery())) + } + + Query octalAndHexadecimalEscapeSequencesNotTerminatedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `octalAndHexadecimalEscapeSequencesNotTerminated` query + TQueryC(TSyntaxPackageQuery(TOctalAndHexadecimalEscapeSequencesNotTerminatedQuery())) + } + + Query sectionsOfCodeShallNotBeCommentedOutQuery() { + //autogenerate `Query` type + result = + // `Query` type for `sectionsOfCodeShallNotBeCommentedOut` query + TQueryC(TSyntaxPackageQuery(TSectionsOfCodeShallNotBeCommentedOutQuery())) + } + + Query identifiersInTheSameNameSpaceUnambiguousQuery() { + //autogenerate `Query` type + result = + // `Query` type for `identifiersInTheSameNameSpaceUnambiguous` query + TQueryC(TSyntaxPackageQuery(TIdentifiersInTheSameNameSpaceUnambiguousQuery())) + } + + Query uOrUSuffixRepresentedInUnsignedTypeQuery() { + //autogenerate `Query` type + result = + // `Query` type for `uOrUSuffixRepresentedInUnsignedType` query + TQueryC(TSyntaxPackageQuery(TUOrUSuffixRepresentedInUnsignedTypeQuery())) + } + + Query lowercaseCharacterLUsedInLiteralSuffixQuery() { + //autogenerate `Query` type + result = + // `Query` type for `lowercaseCharacterLUsedInLiteralSuffix` query + TQueryC(TSyntaxPackageQuery(TLowercaseCharacterLUsedInLiteralSuffixQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/rules/differentidentifiersnottypographicallyunambiguous/DifferentIdentifiersNotTypographicallyUnambiguous.qll b/cpp/common/src/codingstandards/cpp/rules/differentidentifiersnottypographicallyunambiguous/DifferentIdentifiersNotTypographicallyUnambiguous.qll new file mode 100644 index 0000000000..87a4580ab3 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/differentidentifiersnottypographicallyunambiguous/DifferentIdentifiersNotTypographicallyUnambiguous.qll @@ -0,0 +1,105 @@ +/** + * Provides a library which includes a `problems` predicate for reporting + * typographically ambiguous identifiers. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import codingstandards.cpp.Scope + +abstract class DifferentIdentifiersNotTypographicallyUnambiguousSharedQuery extends Query { } + +Query getQuery() { result instanceof DifferentIdentifiersNotTypographicallyUnambiguousSharedQuery } + +string getCanon(UserVariable v) { + result = + v.getName() + .toLowerCase() + .replaceAll("_", "") + .regexpReplaceAll("[il]", "1") + .replaceAll("s", "5") + .replaceAll("z", "2") + .replaceAll("b", "8") + .replaceAll("h", "n") + .replaceAll("m", "rn") + .replaceAll("o", "0") +} + +string step1(string s) { + s = "ACDEFGHJKLMNPQRTUVWXY".charAt(_) and result = s.toLowerCase() + or + s = "O" and result in ["0", "o"] + or + s = "I" and result in ["1", "l", "i"] + or + s = "l" and result = "1" + or + s = "S" and result in ["5", "s"] + or + s = "Z" and result in ["2", "z"] + or + s = "n" and result = "h" + or + s = "B" and result in ["8", "b"] +} + +string step2(string s) { s = "m_" and result = "rn" } + +predicate violation(UserVariable v1, UserVariable v2) { + v2 = getPotentialScopeOfVariable(v1) and + exists(string s1, string s2 | + // over-approximate a match, because it is cheaper to compute + getCanon(v1) = getCanon(v2) and + v1 != v2 and + not v1.getName() = v2.getName() and + // expand 'm' to 'm_' to match either 'm_' or 'rn' + s1 = v1.getName().replaceAll("_", "").replaceAll("m", "m_") and + s2 = v2.getName().replaceAll("_", "").replaceAll("m", "m_") and + // at this point the strings must have equal length, the substitutions do not expand nor contract the string + s1.length() = s2.length() and + forall(int i | i in [0 .. s1.length() - 1] | + exists(string c1, string c2 | + c1 = s1.charAt(i) and + c2 = s2.charAt(i) + | + c1 = c2 + or + step1(c1) = c2 // c1 and c2 are typographically unambiguous + or + step1(c2) = c1 // c1 and c2 are typographically unamibiguous + or + // Check for '[m]_' = '[r]n' and 'm[_]' = 'r[n]' where the character in brackets + // denote the character at index i. + // Note: because of the `forall` we need to make sure the above conjuction is true since 'n' = '_' is a contradiction. + exists(string c1_2, string c2_2 | + c1_2 = c1 + s1.charAt(i + 1) and + c2_2 = c2 + s2.charAt(i + 1) + or + c1_2 = s1.charAt(i - 1) + c1 and + c2_2 = s2.charAt(i - 1) + c2 + | + step2(c1_2) = c2_2 or + step2(c2_2) = c1_2 + ) + ) + ) + ) +} + +query predicate problems( + UserVariable v, string message, UserVariable v1, string v1Description, UserVariable v2, + string v2Description +) { + not isExcluded(v1, getQuery()) and + not isExcluded(v2, getQuery()) and + v = v1 and + // Exclude member variables because it is common to have function/construct parameters named after member variables.class + not (v1.isMember() or v2.isMember()) and + // Exclude variables that are fully or partially generated by macro's. The final name is not visible to the developer. + not (v1.isAffectedByMacro() or v2.isAffectedByMacro()) and + violation(v1, v2) and + v1Description = v1.getName() and + v2Description = v2.getName() and + message = "The identifier $@ is not typographically unambiguous from the identifier $@" +} diff --git a/cpp/common/src/codingstandards/cpp/rules/donotaccessaclosedfile/DoNotAccessAClosedFile.qll b/cpp/common/src/codingstandards/cpp/rules/donotaccessaclosedfile/DoNotAccessAClosedFile.qll index 41d7d9956d..bea25d6ffa 100644 --- a/cpp/common/src/codingstandards/cpp/rules/donotaccessaclosedfile/DoNotAccessAClosedFile.qll +++ b/cpp/common/src/codingstandards/cpp/rules/donotaccessaclosedfile/DoNotAccessAClosedFile.qll @@ -60,7 +60,7 @@ query predicate problems( // explicit access to a closed FILE object closedFileAccess(closedFile, fileAccess) ) and - message = "Access of closed file" + closedFile + "which was closed at $@" and + message = "Access of closed file" + closedFile + " which was closed at $@" and closeFCDescription = "this location." ) } diff --git a/cpp/common/src/codingstandards/cpp/rules/predicatefunctionobjectsshouldnotbemutable/PredicateFunctionObjectsShouldNotBeMutable.qll b/cpp/common/src/codingstandards/cpp/rules/predicatefunctionobjectsshouldnotbemutable/PredicateFunctionObjectsShouldNotBeMutable.qll index 19fb9bb04e..a8b6ab7576 100644 --- a/cpp/common/src/codingstandards/cpp/rules/predicatefunctionobjectsshouldnotbemutable/PredicateFunctionObjectsShouldNotBeMutable.qll +++ b/cpp/common/src/codingstandards/cpp/rules/predicatefunctionobjectsshouldnotbemutable/PredicateFunctionObjectsShouldNotBeMutable.qll @@ -6,6 +6,7 @@ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions import codingstandards.cpp.SideEffect +import codingstandards.cpp.sideeffect.DefaultEffects abstract class PredicateFunctionObjectsShouldNotBeMutableSharedQuery extends Query { } diff --git a/cpp/common/src/codingstandards/cpp/rules/sectionsofcodeshallnotbecommentedout/SectionsOfCodeShallNotBeCommentedOut.qll b/cpp/common/src/codingstandards/cpp/rules/sectionsofcodeshallnotbecommentedout/SectionsOfCodeShallNotBeCommentedOut.qll new file mode 100644 index 0000000000..7532f340c7 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/sectionsofcodeshallnotbecommentedout/SectionsOfCodeShallNotBeCommentedOut.qll @@ -0,0 +1,18 @@ +/** + * Provides a library which includes a `problems` predicate for reporting + * commented out blocks of code. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import codingstandards.cpp.CommentedOutCode + +abstract class SectionsOfCodeShallNotBeCommentedOutSharedQuery extends Query { } + +Query getQuery() { result instanceof SectionsOfCodeShallNotBeCommentedOutSharedQuery } + +query predicate problems(CommentedOutCode comment, string message) { + not isExcluded(comment, getQuery()) and + message = "This comment appears to contain commented-out code." +} diff --git a/cpp/common/src/codingstandards/cpp/sideeffect/Customizations.qll b/cpp/common/src/codingstandards/cpp/sideeffect/Customizations.qll new file mode 100644 index 0000000000..4201dc8e5e --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/sideeffect/Customizations.qll @@ -0,0 +1,19 @@ +import cpp + +module SideEffect { + abstract class ExclusionRange extends Expr { } + + abstract class Range extends Expr { } +} + +module LocalSideEffect { + abstract class Range extends SideEffect::Range { } +} + +module GlobalSideEffect { + abstract class Range extends SideEffect::Range { } +} + +module ExternalSideEffect { + abstract class Range extends SideEffect::Range { } +} diff --git a/cpp/common/src/codingstandards/cpp/sideeffect/DefaultEffects.qll b/cpp/common/src/codingstandards/cpp/sideeffect/DefaultEffects.qll new file mode 100644 index 0000000000..dbc4d13dda --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/sideeffect/DefaultEffects.qll @@ -0,0 +1,65 @@ +import cpp +import codingstandards.cpp.SideEffect +import codingstandards.cpp.sideeffect.Customizations +import codingstandards.cpp.Allocations +import codingstandards.cpp.Expr +import codingstandards.cpp.Variable +import semmle.code.cpp.security.FileWrite + +/** A function call that performs an IO operation and thus exhibts an external side effect. */ +private class IOFunctionCall extends FunctionCall, ExternalSideEffect::Range { + IOFunctionCall() { this instanceof BasicOStreamCall or this instanceof FileWrite } +} + +private class ResourceReleaseCall extends ExternalSideEffect::Range { + ResourceReleaseCall() { freeExpr(this, _, _) } +} + +private class DirectStaticStorageDurationVariableModification extends VariableEffect, + GlobalSideEffect::Range { + DirectStaticStorageDurationVariableModification() { + this.getTarget() instanceof StaticStorageDurationVariable + } +} + +private class ConstructorFieldInitEffect extends GlobalSideEffect::Range, ConstructorFieldInit { } + +private class AliasVariableModification extends VariableEffect, GlobalSideEffect::Range { + AliasVariableModification() { this.getTarget() instanceof AliasParameter } +} + +private class ViolatileAccess extends ExternalSideEffect::Range, VariableAccess { + ViolatileAccess() { this.getTarget().isVolatile() } +} + +/** Holds if the scalar variable is incremented or decremented using a prefix or postfix operation. */ +private predicate hasScalarSideEffects(ConstituentExpr e, ScalarVariable v) { + exists(VariableAccess va | + va.getTarget() = v and + e.(CrementOperation).getAnOperand() = va + ) +} + +private class LocalScalarValueModificationAndValueComputation extends LocalSideEffect::Range { + LocalScalarValueModificationAndValueComputation() { + exists(ScalarVariable v | + v instanceof LocalVariable and + hasScalarSideEffects(this, v) + ) + } +} + +private class PointerCrementOperation extends CrementOperation, LocalSideEffect::Range { + PointerCrementOperation() { + exists(VariableAccess va | va.getType() instanceof PointerType | this.getAnOperand() = va) + } +} + +private class ReturnedReferenceModificationAndValueComputation extends LocalSideEffect::Range { + ReturnedReferenceModificationAndValueComputation() { + exists(FunctionCall call | + this.(CrementOperation).getOperand() = call and + call.getType().getUnderlyingType().getUnspecifiedType() instanceof ReferenceType + ) + } +} diff --git a/cpp/common/src/codingstandards/cpp/standardlibrary/FileAccess.qll b/cpp/common/src/codingstandards/cpp/standardlibrary/FileAccess.qll index b8a4ec7f4a..5a3dd16b96 100644 --- a/cpp/common/src/codingstandards/cpp/standardlibrary/FileAccess.qll +++ b/cpp/common/src/codingstandards/cpp/standardlibrary/FileAccess.qll @@ -115,10 +115,10 @@ class FileReadFunctionCall extends FileAccess { this.getTarget().hasGlobalName(["getchar", "getwchar"]) and filePos = -1 or this.getTarget() - .hasGlobalName(["fgetc", "getc", "gets", "gets_s", "fgetwc", "getwc", "fscanf", "fscanf_s"]) and + .hasGlobalName(["getc", "getwc", "fgetc", "fgetwc", "gets", "gets_s", "fscanf", "fscanf_s"]) and filePos = 0 or - this.getTarget().hasGlobalName(["fgets", "getline", "getwline"]) and filePos = 2 + this.getTarget().hasGlobalName(["fgets", "fgetws", "getline", "getwline"]) and filePos = 2 or this.getTarget().hasGlobalName(["fread", "getdelim", "getwdelim"]) and filePos = 3 } diff --git a/cpp/common/src/qlpack.yml b/cpp/common/src/qlpack.yml index f1a0147457..b66d6f2831 100644 --- a/cpp/common/src/qlpack.yml +++ b/cpp/common/src/qlpack.yml @@ -1,3 +1,3 @@ name: common-cpp-coding-standards -version: 2.0.0 +version: 2.1.0 libraryPathDependencies: codeql-cpp diff --git a/cpp/common/test/qlpack.yml b/cpp/common/test/qlpack.yml index 5aa8100a6f..47f83b0926 100644 --- a/cpp/common/test/qlpack.yml +++ b/cpp/common/test/qlpack.yml @@ -1,4 +1,4 @@ name: common-cpp-coding-standards-tests -version: 2.0.0 +version: 2.1.0 libraryPathDependencies: common-cpp-coding-standards extractor: cpp diff --git a/cpp/common/test/rules/differentidentifiersnottypographicallyunambiguous/DifferentIdentifiersNotTypographicallyUnambiguous.expected b/cpp/common/test/rules/differentidentifiersnottypographicallyunambiguous/DifferentIdentifiersNotTypographicallyUnambiguous.expected new file mode 100644 index 0000000000..85fc9c161a --- /dev/null +++ b/cpp/common/test/rules/differentidentifiersnottypographicallyunambiguous/DifferentIdentifiersNotTypographicallyUnambiguous.expected @@ -0,0 +1,31 @@ +| test.cpp:2:5:2:13 | case1_FOO | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:2:5:2:13 | case1_FOO | case1_FOO | test.cpp:1:5:1:13 | case1_foo | case1_foo | +| test.cpp:2:5:2:13 | case1_FOO | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:2:5:2:13 | case1_FOO | case1_FOO | test.cpp:3:5:3:13 | case1_fOo | case1_fOo | +| test.cpp:3:5:3:13 | case1_fOo | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:3:5:3:13 | case1_fOo | case1_fOo | test.cpp:1:5:1:13 | case1_foo | case1_foo | +| test.cpp:6:5:6:15 | case2_f_o_o | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:6:5:6:15 | case2_f_o_o | case2_f_o_o | test.cpp:5:5:5:13 | case2_foo | case2_foo | +| test.cpp:9:5:9:13 | case3_fO0 | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:9:5:9:13 | case3_fO0 | case3_fO0 | test.cpp:8:5:8:13 | case3_fOO | case3_fOO | +| test.cpp:11:5:11:12 | case4_II | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:11:5:11:12 | case4_II | case4_II | test.cpp:13:5:13:12 | case4_Il | case4_Il | +| test.cpp:12:5:12:12 | case4_I1 | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:12:5:12:12 | case4_I1 | case4_I1 | test.cpp:11:5:11:12 | case4_II | case4_II | +| test.cpp:12:5:12:12 | case4_I1 | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:12:5:12:12 | case4_I1 | case4_I1 | test.cpp:13:5:13:12 | case4_Il | case4_Il | +| test.cpp:16:5:16:11 | case5_5 | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:16:5:16:11 | case5_5 | case5_5 | test.cpp:15:5:15:11 | case5_S | case5_S | +| test.cpp:19:5:19:11 | case6_2 | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:19:5:19:11 | case6_2 | case6_2 | test.cpp:18:5:18:11 | case6_Z | case6_Z | +| test.cpp:22:5:22:11 | case7_h | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:22:5:22:11 | case7_h | case7_h | test.cpp:21:5:21:11 | case7_n | case7_n | +| test.cpp:25:5:25:11 | case8_8 | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:25:5:25:11 | case8_8 | case8_8 | test.cpp:24:5:24:11 | case8_B | case8_B | +| test.cpp:28:5:28:11 | case9_m | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:28:5:28:11 | case9_m | case9_m | test.cpp:27:5:27:12 | case9_rn | case9_rn | +| test.cpp:29:5:29:12 | case9_rh | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:29:5:29:12 | case9_rh | case9_rh | test.cpp:27:5:27:12 | case9_rn | case9_rn | +| test.cpp:32:5:32:15 | case10_xmmx | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:32:5:32:15 | case10_xmmx | case10_xmmx | test.cpp:31:5:31:17 | case10_xrnrnx | case10_xrnrnx | +| test.cpp:32:5:32:15 | case10_xmmx | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:32:5:32:15 | case10_xmmx | case10_xmmx | test.cpp:33:5:33:16 | case10_xmrnx | case10_xmrnx | +| test.cpp:32:5:32:15 | case10_xmmx | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:32:5:32:15 | case10_xmmx | case10_xmmx | test.cpp:34:5:34:16 | case10_xrnmx | case10_xrnmx | +| test.cpp:33:5:33:16 | case10_xmrnx | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:33:5:33:16 | case10_xmrnx | case10_xmrnx | test.cpp:31:5:31:17 | case10_xrnrnx | case10_xrnrnx | +| test.cpp:33:5:33:16 | case10_xmrnx | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:33:5:33:16 | case10_xmrnx | case10_xmrnx | test.cpp:34:5:34:16 | case10_xrnmx | case10_xrnmx | +| test.cpp:33:5:33:16 | case10_xmrnx | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:33:5:33:16 | case10_xmrnx | case10_xmrnx | test.cpp:35:5:35:17 | case10_xrnrhx | case10_xrnrhx | +| test.cpp:34:5:34:16 | case10_xrnmx | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:34:5:34:16 | case10_xrnmx | case10_xrnmx | test.cpp:31:5:31:17 | case10_xrnrnx | case10_xrnrnx | +| test.cpp:35:5:35:17 | case10_xrnrhx | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:35:5:35:17 | case10_xrnrhx | case10_xrnrhx | test.cpp:31:5:31:17 | case10_xrnrnx | case10_xrnrnx | +| test.cpp:36:5:36:17 | case10_xrhrhx | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:36:5:36:17 | case10_xrhrhx | case10_xrhrhx | test.cpp:31:5:31:17 | case10_xrnrnx | case10_xrnrnx | +| test.cpp:36:5:36:17 | case10_xrhrhx | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:36:5:36:17 | case10_xrhrhx | case10_xrhrhx | test.cpp:35:5:35:17 | case10_xrnrhx | case10_xrnrhx | +| test.cpp:37:5:37:16 | case10_xmrhx | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:37:5:37:16 | case10_xmrhx | case10_xmrhx | test.cpp:31:5:31:17 | case10_xrnrnx | case10_xrnrnx | +| test.cpp:37:5:37:16 | case10_xmrhx | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:37:5:37:16 | case10_xmrhx | case10_xmrhx | test.cpp:33:5:33:16 | case10_xmrnx | case10_xmrnx | +| test.cpp:37:5:37:16 | case10_xmrhx | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:37:5:37:16 | case10_xmrhx | case10_xmrhx | test.cpp:35:5:35:17 | case10_xrnrhx | case10_xrnrhx | +| test.cpp:38:5:38:16 | case10_xrhmx | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:38:5:38:16 | case10_xrhmx | case10_xrhmx | test.cpp:31:5:31:17 | case10_xrnrnx | case10_xrnrnx | +| test.cpp:38:5:38:16 | case10_xrhmx | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:38:5:38:16 | case10_xrhmx | case10_xrhmx | test.cpp:34:5:34:16 | case10_xrnmx | case10_xrnmx | +| test.cpp:40:15:40:22 | case11_O | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:40:15:40:22 | case11_O | case11_O | test.cpp:40:5:40:12 | case11_o | case11_o | +| test.cpp:43:5:43:14 | case12_8bB | The identifier $@ is not typographically unambiguous from the identifier $@ | test.cpp:43:5:43:14 | case12_8bB | case12_8bB | test.cpp:42:5:42:14 | case12_BBb | case12_BBb | diff --git a/cpp/common/test/rules/differentidentifiersnottypographicallyunambiguous/DifferentIdentifiersNotTypographicallyUnambiguous.ql b/cpp/common/test/rules/differentidentifiersnottypographicallyunambiguous/DifferentIdentifiersNotTypographicallyUnambiguous.ql new file mode 100644 index 0000000000..17134b9eba --- /dev/null +++ b/cpp/common/test/rules/differentidentifiersnottypographicallyunambiguous/DifferentIdentifiersNotTypographicallyUnambiguous.ql @@ -0,0 +1,2 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.differentidentifiersnottypographicallyunambiguous.DifferentIdentifiersNotTypographicallyUnambiguous diff --git a/cpp/autosar/test/rules/M2-10-1/test.cpp b/cpp/common/test/rules/differentidentifiersnottypographicallyunambiguous/test.cpp similarity index 100% rename from cpp/autosar/test/rules/M2-10-1/test.cpp rename to cpp/common/test/rules/differentidentifiersnottypographicallyunambiguous/test.cpp diff --git a/cpp/common/test/rules/ownedpointervaluestoredinunrelatedsmartpointer/OwnedPointerValueStoredInUnrelatedSmartPointer.expected b/cpp/common/test/rules/ownedpointervaluestoredinunrelatedsmartpointer/OwnedPointerValueStoredInUnrelatedSmartPointer.expected index d5d138ec19..e291147d15 100644 --- a/cpp/common/test/rules/ownedpointervaluestoredinunrelatedsmartpointer/OwnedPointerValueStoredInUnrelatedSmartPointer.expected +++ b/cpp/common/test/rules/ownedpointervaluestoredinunrelatedsmartpointer/OwnedPointerValueStoredInUnrelatedSmartPointer.expected @@ -6,18 +6,36 @@ problems | test.cpp:12:28:12:29 | v2 | test.cpp:10:8:10:17 | new | test.cpp:12:28:12:29 | v2 | Raw pointer flows to initialize multiple unrelated smart pointers. | | 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 +| ../../includes/standard-library/memory.h:76:17:76:19 | ptr | ../../includes/standard-library/memory.h:76:17:76:19 | ptr | | 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:7:28:7:29 | v2 | | test.cpp:4:13:4:14 | v1 | test.cpp:7:28:7:29 | v2 | +| test.cpp:5:27:5:28 | v1 | ../../includes/standard-library/memory.h:76:17:76:19 | ptr | | test.cpp:5:27:5:29 | call to shared_ptr | test.cpp:6:31:6:33 | call to get | +| test.cpp:6:31:6:33 | call to get | ../../includes/standard-library/memory.h:76:17:76:19 | ptr | +| test.cpp:6:31:6:33 | call to get | ../../includes/standard-library/memory.h:76:17:76:19 | ptr | +| test.cpp:7:28:7:29 | v2 | ../../includes/standard-library/memory.h:76:17:76:19 | ptr | +| test.cpp:7:28:7:29 | v2 | ../../includes/standard-library/memory.h:76:17:76:19 | ptr | | test.cpp:8:8:8:14 | 0 | test.cpp:9:28:9:29 | v2 | +| test.cpp:9:28:9:29 | v2 | ../../includes/standard-library/memory.h:76:17:76:19 | ptr | +| test.cpp:10:8:10:17 | new | test.cpp:11:28:11: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 | +| test.cpp:11:28:11:29 | ref arg v2 | test.cpp:12:28:12:29 | v2 | +| test.cpp:11:28:11:29 | v2 | ../../includes/standard-library/memory.h:76:17:76:19 | ptr | +| test.cpp:11:28:11:29 | v2 | test.cpp:11:28:11:29 | ref arg v2 | +| test.cpp:12:28:12:29 | v2 | ../../includes/standard-library/memory.h:76:17:76:19 | ptr | +| test.cpp:16:13:16:22 | new | test.cpp:17:27:17:28 | v1 | | test.cpp:16:13:16:22 | new | test.cpp:17:27:17:28 | v1 | | test.cpp:16:13:16:22 | new | test.cpp:19:6:19:7 | v1 | +| test.cpp:17:27:17:28 | ref arg v1 | test.cpp:19:6:19:7 | v1 | +| test.cpp:17:27:17:28 | v1 | ../../includes/standard-library/memory.h:76:17:76:19 | ptr | +| test.cpp:17:27:17:28 | v1 | test.cpp:17:27:17:28 | ref arg v1 | | test.cpp:19:6:19:7 | v1 | test.cpp:3:14:3:15 | v1 | nodes +| ../../includes/standard-library/memory.h:76:17:76:19 | ptr | semmle.label | ptr | +| ../../includes/standard-library/memory.h:76:17:76:19 | ptr | semmle.label | ptr | | 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 | @@ -27,9 +45,15 @@ nodes | test.cpp:8:8:8:14 | 0 | semmle.label | 0 | | test.cpp:9:28:9:29 | v2 | semmle.label | v2 | | test.cpp:10:8:10:17 | new | semmle.label | new | +| test.cpp:11:28:11:29 | ref arg v2 | semmle.label | ref arg v2 | +| test.cpp:11:28:11:29 | v2 | semmle.label | v2 | | test.cpp:11:28:11:29 | v2 | semmle.label | v2 | | test.cpp:12:28:12:29 | v2 | semmle.label | v2 | | test.cpp:16:13:16:22 | new | semmle.label | new | +| test.cpp:17:27:17:28 | ref arg v1 | semmle.label | ref arg v1 | +| test.cpp:17:27:17:28 | v1 | semmle.label | v1 | | test.cpp:17:27:17:28 | v1 | semmle.label | v1 | | test.cpp:19:6:19:7 | v1 | semmle.label | v1 | subpaths +| test.cpp:11:28:11:29 | v2 | ../../includes/standard-library/memory.h:76:17:76:19 | ptr | ../../includes/standard-library/memory.h:76:17:76:19 | ptr | test.cpp:11:28:11:29 | ref arg v2 | +| test.cpp:17:27:17:28 | v1 | ../../includes/standard-library/memory.h:76:17:76:19 | ptr | ../../includes/standard-library/memory.h:76:17:76:19 | ptr | test.cpp:17:27:17:28 | ref arg v1 | diff --git a/cpp/autosar/test/rules/A2-7-2/SectionsOfCodeCommentedOut.expected b/cpp/common/test/rules/sectionsofcodeshallnotbecommentedout/SectionsOfCodeShallNotBeCommentedOut.expected similarity index 100% rename from cpp/autosar/test/rules/A2-7-2/SectionsOfCodeCommentedOut.expected rename to cpp/common/test/rules/sectionsofcodeshallnotbecommentedout/SectionsOfCodeShallNotBeCommentedOut.expected diff --git a/cpp/common/test/rules/sectionsofcodeshallnotbecommentedout/SectionsOfCodeShallNotBeCommentedOut.ql b/cpp/common/test/rules/sectionsofcodeshallnotbecommentedout/SectionsOfCodeShallNotBeCommentedOut.ql new file mode 100644 index 0000000000..c60068c7cc --- /dev/null +++ b/cpp/common/test/rules/sectionsofcodeshallnotbecommentedout/SectionsOfCodeShallNotBeCommentedOut.ql @@ -0,0 +1,2 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.sectionsofcodeshallnotbecommentedout.SectionsOfCodeShallNotBeCommentedOut diff --git a/cpp/common/test/rules/sectionsofcodeshallnotbecommentedout/config.h b/cpp/common/test/rules/sectionsofcodeshallnotbecommentedout/config.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/cpp/autosar/test/rules/A2-7-2/test.cpp b/cpp/common/test/rules/sectionsofcodeshallnotbecommentedout/test.cpp similarity index 100% rename from cpp/autosar/test/rules/A2-7-2/test.cpp rename to cpp/common/test/rules/sectionsofcodeshallnotbecommentedout/test.cpp diff --git a/cpp/misra/src/qlpack.yml b/cpp/misra/src/qlpack.yml index 5e928d0fc6..fbc916b8af 100644 --- a/cpp/misra/src/qlpack.yml +++ b/cpp/misra/src/qlpack.yml @@ -1,3 +1,3 @@ name: misra-cpp-coding-standards -version: 2.0.0 +version: 2.1.0 libraryPathDependencies: common-cpp-coding-standards diff --git a/cpp/misra/test/qlpack.yml b/cpp/misra/test/qlpack.yml index 295923be97..17b683f28c 100644 --- a/cpp/misra/test/qlpack.yml +++ b/cpp/misra/test/qlpack.yml @@ -1,4 +1,4 @@ name: misra-cpp-coding-standards-tests -version: 2.0.0 +version: 2.1.0 libraryPathDependencies: misra-cpp-coding-standards extractor: cpp diff --git a/cpp/report/src/qlpack.yml b/cpp/report/src/qlpack.yml index ed6297483e..e3c48fe632 100644 --- a/cpp/report/src/qlpack.yml +++ b/cpp/report/src/qlpack.yml @@ -1,3 +1,3 @@ name: report-cpp-coding-standards -version: 2.0.0 +version: 2.1.0 libraryPathDependencies: codeql-cpp diff --git a/rule_packages/c/IO1.json b/rule_packages/c/IO1.json index 2de76a3961..481843d7ff 100644 --- a/rule_packages/c/IO1.json +++ b/rule_packages/c/IO1.json @@ -19,7 +19,10 @@ ] } ], - "title": "Exclude user input from format strings" + "title": "Exclude user input from format strings", + "implementation_scope": { + "description": "None." + } }, "FIO34-C": { "properties": { @@ -51,7 +54,10 @@ ] } ], - "title": "Distinguish between characters read from a file and EOF or WEOF" + "title": "Distinguish between characters read from a file and EOF or WEOF", + "implementation_scope": { + "description": "The rule is enforced in the context of a single function. The query does not validate if the FILE status is handled correctly after being read." + } }, "FIO39-C": { "properties": { @@ -71,7 +77,10 @@ ] } ], - "title": "Do not alternately input and output from a stream without an intervening flush or positioning call" + "title": "Do not alternately input and output from a stream without an intervening flush or positioning call", + "implementation_scope": { + "description": "The rule is enforced in the context of a single function." + } }, "FIO42-C": { "properties": { @@ -91,7 +100,10 @@ ] } ], - "title": "Close files when they are no longer needed" + "title": "Close files when they are no longer needed", + "implementation_scope": { + "description": "The rule is enforced in the context of a single function." + } }, "FIO46-C": { "properties": { @@ -111,7 +123,10 @@ ] } ], - "title": "Do not access a closed file" + "title": "Do not access a closed file", + "implementation_scope": { + "description": "The rule is enforced in the context of a single function." + } } }, "MISRA-C-2012": { @@ -133,7 +148,10 @@ ] } ], - "title": "The value of a pointer to a FILE shall not be used after the associated stream has been closed" + "title": "The value of a pointer to a FILE shall not be used after the associated stream has been closed", + "implementation_scope": { + "description": "The rule is enforced in the context of a single function." + } } } -} +} \ No newline at end of file diff --git a/rule_packages/c/IO2.json b/rule_packages/c/IO2.json new file mode 100644 index 0000000000..453592b29e --- /dev/null +++ b/rule_packages/c/IO2.json @@ -0,0 +1,94 @@ +{ + "CERT-C": { + "FIO38-C": { + "properties": { + "obligation": "rule" + }, + "queries": [ + { + "description": "Using a copy of a FILE object may result in program failure.", + "kind": "problem", + "name": "Do not copy a FILE object", + "precision": "very-high", + "severity": "error", + "short_name": "DoNotCopyAFileObject", + "tags": [ + "correctness", + "security" + ] + } + ], + "title": "Do not copy a FILE object", + "implementation_scope": { + "description": "None." + } + }, + "FIO40-C": { + "properties": { + "obligation": "rule" + }, + "queries": [ + { + "description": "A string that used in a failing call to fgets() or fgetws() requires a reset before being referenced.", + "kind": "problem", + "name": "Reset strings on fgets() or fgetws() failure", + "precision": "very-high", + "severity": "error", + "short_name": "ResetStringsOnFgetsOrFgetwsFailure", + "tags": [ + "correctness", + "security" + ] + } + ], + "title": "Reset strings on fgets() or fgetws() failure", + "implementation_scope": { + "description": "The rule is enforced in the context of a single function. Not all failing calls can be recognized statically, the rule looks for specific patterns in comparisons against NULL." + } + }, + "FIO41-C": { + "properties": { + "obligation": "rule" + }, + "queries": [ + { + "description": "Using an expression that has side effects as the stream argument to `getc()` or `putc()` can result in unexpected behavior.", + "kind": "problem", + "name": "Do not call getc(), putc(), getwc(), or putwc() with a stream argument that has side effects", + "precision": "very-high", + "severity": "error", + "short_name": "DoNotCallGetcAndPutcWithSideEffects", + "tags": [ + "correctness" + ] + } + ], + "title": "Do not call getc(), putc(), getwc(), or putwc() with a stream argument that has side effects", + "implementation_scope": { + "description": "None." + } + }, + "FIO44-C": { + "properties": { + "obligation": "rule" + }, + "queries": [ + { + "description": "Arguments for `fsetpos()` can only be obtained from calls to `fgetpos()`.", + "kind": "problem", + "name": "Only use values for fsetpos() that are returned from fgetpos()", + "precision": "very-high", + "severity": "error", + "short_name": "OnlyUseValuesForFsetposThatAreReturnedFromFgetpos", + "tags": [ + "correctness" + ] + } + ], + "title": "Only use values for fsetpos() that are returned from fgetpos()", + "implementation_scope": { + "description": "None." + } + } + } +} \ No newline at end of file diff --git a/rule_packages/c/SideEffects1.json b/rule_packages/c/SideEffects1.json new file mode 100644 index 0000000000..e66f4c3136 --- /dev/null +++ b/rule_packages/c/SideEffects1.json @@ -0,0 +1,181 @@ +{ + "CERT-C": { + "EXP30-C": { + "properties": { + "obligation": "rule" + }, + "queries": [ + { + "description": "Depending on the order of evaluation for side effects for evaluation of scalar objects that are unsequenced results in undefined behavior.", + "kind": "problem", + "name": "Do not depend on the order of scalar object evaluation for side effects", + "precision": "high", + "severity": "warning", + "short_name": "DependenceOnOrderOfScalarEvaluationForSideEffects", + "tags": [ + "correctness" + ] + }, + { + "description": "Depending on the order of evaluation for side effects in function call arguments can result in unexpected program behavior.", + "kind": "problem", + "name": "Do not depend on the order of evaluation of function call arguments for side effects", + "precision": "high", + "severity": "warning", + "short_name": "DependenceOnOrderOfFunctionArgumentsForSideEffects", + "tags": [ + "correctness" + ] + } + ], + "title": "Do not depend on the order of evaluation for side effects" + }, + "EXP44-C": { + "properties": { + "obligation": "rule" + }, + "queries": [ + { + "description": "The operands to sizeof, _Alignof, or _Generic are not evaluated and their side effect will not be generated. Using operands with a side effect can result in unexpected program behavior.", + "kind": "problem", + "name": "Do not rely on side effects in operands to sizeof, _Alignof, or _Generic", + "precision": "very-high", + "severity": "error", + "short_name": "UnevaluatedOperandWithSideEffect", + "tags": [ + "correctness" + ] + } + ], + "title": "Do not rely on side effects in operands to sizeof, _Alignof, or _Generic" + }, + "EXP45-C": { + "properties": { + "obligation": "rule" + }, + "queries": [ + { + "description": "Assignments in selection statements is indicative of a programmer error and can result in unexpected program behavior.", + "kind": "problem", + "name": "Do not perform assignments in selection statements", + "precision": "very-high", + "severity": "error", + "short_name": "AssignmentsInSelectionStatements", + "tags": [ + "correctness" + ] + } + ], + "title": "Do not perform assignments in selection statements" + } + }, + "MISRA-C-2012": { + "RULE-12-1": { + "properties": { + "obligation": "advisory" + }, + "queries": [ + { + "description": "The relative precedences of operators are not intuitive and can lead to mistakes. The use of parentheses to make the precedence of operators explicit removes the possibility of incorrect expectations.", + "kind": "problem", + "name": "The operand of the sizeof operator should be enclosed in parentheses", + "precision": "very-high", + "severity": "warning", + "short_name": "UnenclosedSizeofOperand", + "tags": [ + "correctness" + ] + }, + { + "description": "The relative precedences of operators are not intuitive and can lead to mistakes. The use of parentheses to make the precedence of operators explicit removes the possibility of incorrect expectations.", + "kind": "problem", + "name": "The precedence of operators within expressions should be made explicit", + "precision": "very-high", + "severity": "warning", + "short_name": "ImplicitPrecedenceOfOperatorsInExpression", + "tags": [ + "correctness" + ] + } + ], + "title": "The precedence of operators within expressions should be made explicit" + }, + "RULE-13-1": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "The order in which side effects occur during the evaluation of the expressions in an initializer list is unspecified and can result in unexpected program behavior.", + "kind": "problem", + "name": "Initializer lists shall not contain persistent side effects", + "precision": "very-high", + "severity": "error", + "short_name": "InitializerListsContainPersistentSideEffects", + "tags": [ + "correctness" + ] + } + ], + "title": "Initializer lists shall not contain persistent side effects" + }, + "RULE-13-4": { + "properties": { + "obligation": "advisory" + }, + "queries": [ + { + "description": "The use of an assignment operator can impair the readability of the code and the introduced side effect may result in undefined behavior.", + "kind": "problem", + "name": "The result of an assignment operator should not be used", + "precision": "very-high", + "severity": "error", + "short_name": "ResultOfAnAssignmentOperatorShouldNotBeUsed", + "tags": [ + "correctness", + "readability" + ] + } + ], + "title": "The result of an assignment operator should not be used" + }, + "RULE-13-5": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "The evaluation of the right-hand operand of the && and || operators is conditional on the value of the left-hand operand. Any side effects in the right-hand operand may or may not occur and may result in unexpected program behavior.", + "kind": "problem", + "name": "The right hand operand of a logical && or || operator shall not contain persistent side effects", + "precision": "very-high", + "severity": "error", + "short_name": "PossibleSuppressedSideEffectInLogicOperatorOperand", + "tags": [ + "correctness" + ] + } + ], + "title": "The right hand operand of a logical && or || operator shall not contain persistent side effects" + }, + "RULE-13-6": { + "properties": { + "obligation": "mandatory" + }, + "queries": [ + { + "description": "The operand to sizeof is not evaluated and its side effect will not be generated. Using an operand with a side effect can result in unexpected program behavior.", + "kind": "problem", + "name": "The operand of the sizeof operator shall not contain any expression which has potential side effects", + "precision": "very-high", + "severity": "error", + "short_name": "SizeofOperandWithSideEffect", + "tags": [ + "correctness" + ] + } + ], + "title": "The operand of the sizeof operator shall not contain any expression which has potential side effects" + } + } +} \ No newline at end of file diff --git a/rule_packages/c/Syntax.json b/rule_packages/c/Syntax.json new file mode 100644 index 0000000000..476254130b --- /dev/null +++ b/rule_packages/c/Syntax.json @@ -0,0 +1,149 @@ +{ + "MISRA-C-2012": { + "RULE-3-1": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "A /* or // character sequence within a comment is sometimes indicative of a missed comment and should not be allowed.", + "kind": "problem", + "name": "The character sequences /* and // shall not be used within a comment", + "precision": "very-high", + "severity": "warning", + "short_name": "CharacterSequencesAndUsedWithinAComment", + "tags": [ + "maintainability", + "readability" + ] + } + ], + "title": "The character sequences /* and // shall not be used within a comment" + }, + "RULE-3-2": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Entering a newline following a '\\' character can erroneously commenting out regions of code.", + "kind": "problem", + "name": "Line-splicing shall not be used in // comments", + "precision": "very-high", + "severity": "warning", + "short_name": "LineSplicingUsedInComments", + "tags": [ + "maintainability", + "readability", + "correctness" + ] + } + ], + "title": "Line-splicing shall not be used in // comments" + }, + "RULE-4-1": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Not explicitly terminating octal and hexadecimal escape sequences can results in developer confusion and lead to programming errors.", + "kind": "problem", + "name": "Octal and hexadecimal escape sequences shall be terminated", + "precision": "very-high", + "severity": "warning", + "short_name": "OctalAndHexadecimalEscapeSequencesNotTerminated", + "tags": [ + "maintainability", + "readability", + "correctness" + ] + } + ], + "title": "Octal and hexadecimal escape sequences shall be terminated" + }, + "RULE-4-4": { + "properties": { + "obligation": "advisory" + }, + "queries": [ + { + "description": "Commented out code may become out of date leading to developer confusion.", + "kind": "problem", + "name": "Sections of code should not be commented out", + "precision": "high", + "severity": "warning", + "short_name": "SectionsOfCodeShallNotBeCommentedOut", + "shared_implementation_short_name": "SectionsOfCodeShallNotBeCommentedOut", + "tags": [ + "maintainability", + "readability", + "correctness" + ] + } + ], + "title": "Sections of code should not be commented out" + }, + "DIR-4-5": { + "properties": { + "obligation": "advisory" + }, + "queries": [ + { + "description": "Typographically ambiguous identifiers can lead to developer confusion.", + "kind": "problem", + "name": "Identifiers in the same name space with overlapping visibility should be typographically unambiguous", + "precision": "very-high", + "severity": "recommendation", + "short_name": "IdentifiersInTheSameNameSpaceUnambiguous", + "shared_implementation_short_name" : "DifferentIdentifiersNotTypographicallyUnambiguous", + "tags": [ + "readability", + "maintainability" + ] + } + ], + "title": "Identifiers in the same name space with overlapping visibility should be typographically unambiguous" + }, + "RULE-7-2": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "A 'U' or 'u' suffix shall be applied to all integer constants that are represented in an unsigned type.", + "kind": "problem", + "name": "A 'U' or 'u' suffix shall be applied to all unsigned integers constants", + "precision": "very-high", + "severity": "recommendation", + "short_name": "UOrUSuffixRepresentedInUnsignedType", + "tags": [ + "maintainability", + "readability" + ] + } + ], + "title": "A 'U' or 'u' suffix shall be applied to all integer constants that are represented in an unsigned type" + }, + "RULE-7-3": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Using the lowercase letter l in a literal suffix can be mistaken for other characters such as 1.", + "kind": "problem", + "name": "The lowercase character l shall not be used in a literal suffix", + "precision": "very-high", + "severity": "recommendation", + "short_name": "LowercaseCharacterLUsedInLiteralSuffix", + "tags": [ + "maintainability", + "readability" + ] + } + ], + "title": "The lowercase character l shall not be used in a literal suffix" + } + } +} \ No newline at end of file diff --git a/rule_packages/cpp/Comments.json b/rule_packages/cpp/Comments.json index d7895db810..d6364f01d6 100644 --- a/rule_packages/cpp/Comments.json +++ b/rule_packages/cpp/Comments.json @@ -41,6 +41,7 @@ "precision": "very-high", "severity": "warning", "short_name": "SectionsOfCodeCommentedOut", + "shared_implementation_short_name": "SectionsOfCodeShallNotBeCommentedOut", "tags": [ "maintainability", "readability", diff --git a/rule_packages/cpp/IO.json b/rule_packages/cpp/IO.json index 2d4f111337..87edd72e83 100644 --- a/rule_packages/cpp/IO.json +++ b/rule_packages/cpp/IO.json @@ -22,7 +22,10 @@ ] } ], - "title": "Alternate input and output operations on a file stream shall not be used without an intervening flush or positioning call." + "title": "Alternate input and output operations on a file stream shall not be used without an intervening flush or positioning call.", + "implementation_scope": { + "description": "The rule is enforced in the context of a single function." + } } }, "CERT-C++": { @@ -67,4 +70,4 @@ "title": "Close files when they are no longer needed" } } -} \ No newline at end of file +} diff --git a/rule_packages/cpp/Naming.json b/rule_packages/cpp/Naming.json index 01331e89de..82b20008df 100644 --- a/rule_packages/cpp/Naming.json +++ b/rule_packages/cpp/Naming.json @@ -289,6 +289,7 @@ "precision": "very-high", "severity": "recommendation", "short_name": "DifferentIdentifiersNotTypographicallyUnambiguous", + "shared_implementation_short_name" : "DifferentIdentifiersNotTypographicallyUnambiguous", "tags": [ "readability", "maintainability" diff --git a/rule_packages/cpp/TypeRanges.json b/rule_packages/cpp/TypeRanges.json index 1c073310da..16887f1d72 100644 --- a/rule_packages/cpp/TypeRanges.json +++ b/rule_packages/cpp/TypeRanges.json @@ -104,7 +104,10 @@ ] } ], - "title": "Inputs from independent components shall be validated." + "title": "Inputs from independent components shall be validated.", + "implementation_scope": { + "description": "The query is limited to the case of user input in format strings." + } }, "A7-2-1": { "properties": { diff --git a/rules.csv b/rules.csv index 005e9c9171..c4e9e02246 100755 --- a/rules.csv +++ b/rules.csv @@ -515,7 +515,7 @@ c,CERT-C,ERR30-C,Yes,Rule,,,"Set errno to zero before calling a library function c,CERT-C,ERR32-C,Yes,Rule,,,Do not rely on indeterminate values of errno,,Contracts,Hard, c,CERT-C,ERR33-C,Yes,Rule,,,Detect and handle standard library errors,MEM52-CPP,Contracts,Hard, c,CERT-C,ERR34-C,OutOfScope,Rule,,,Detect errors when converting a string to a number,,,, -c,CERT-C,EXP30-C,Yes,Rule,,,Do not depend on the order of evaluation for side effects,EXP50-CPP,SideEffects,Easy, +c,CERT-C,EXP30-C,Yes,Rule,,,Do not depend on the order of evaluation for side effects,EXP50-CPP,SideEffects1,Easy, c,CERT-C,EXP32-C,Yes,Rule,,,Do not access a volatile object through a nonvolatile reference,,Pointers,Easy, c,CERT-C,EXP33-C,Yes,Rule,,,Do not read uninitialized memory,EXP53-CPP,InvalidMemory,Easy, c,CERT-C,EXP34-C,Yes,Rule,,,Do not dereference null pointers,A5-3-2,InvalidMemory,Medium, @@ -526,20 +526,20 @@ c,CERT-C,EXP39-C,Yes,Rule,,,Do not access a variable through a pointer of an inc c,CERT-C,EXP40-C,Yes,Rule,,,Do not modify constant objects,,Contracts,Medium, c,CERT-C,EXP42-C,Yes,Rule,,,Do not compare padding data,,Memory,Medium, c,CERT-C,EXP43-C,Yes,Rule,,,Avoid undefined behavior when using restrict-qualified pointers,,Pointers,Medium, -c,CERT-C,EXP44-C,Yes,Rule,,,"Do not rely on side effects in operands to sizeof, _Alignof, or _Generic",M5-3-4,SideEffects,Medium, -c,CERT-C,EXP45-C,Yes,Rule,,,Do not perform assignments in selection statements,M6-2-1,SideEffects,Medium, +c,CERT-C,EXP44-C,Yes,Rule,,,"Do not rely on side effects in operands to sizeof, _Alignof, or _Generic",M5-3-4,SideEffects1,Medium, +c,CERT-C,EXP45-C,Yes,Rule,,,Do not perform assignments in selection statements,M6-2-1,SideEffects1,Medium, c,CERT-C,EXP46-C,Yes,Rule,,,Do not use a bitwise operator with a Boolean-like operand,,Expressions,Easy, c,CERT-C,EXP47-C,OutOfScope,Rule,,,Do not call va_arg with an argument of the incorrect type,,,, c,CERT-C,FIO30-C,Yes,Rule,,,Exclude user input from format strings,A27-0-1,IO1,Import, c,CERT-C,FIO32-C,Yes,Rule,,,Do not perform operations on devices that are only appropriate for files,,IO,Medium, c,CERT-C,FIO34-C,Yes,Rule,,,Distinguish between characters read from a file and EOF or WEOF,,IO1,Hard, c,CERT-C,FIO37-C,Yes,Rule,,,Do not assume that fgets() or fgetws() returns a nonempty string when successful,,IO,Medium, -c,CERT-C,FIO38-C,Yes,Rule,,,Do not copy a FILE object,,IO,Medium, +c,CERT-C,FIO38-C,Yes,Rule,,,Do not copy a FILE object,,IO2,Medium, c,CERT-C,FIO39-C,Yes,Rule,,,Do not alternately input and output from a stream without an intervening flush or positioning call,FIO50-CPP A27-0-3,IO1,Medium, -c,CERT-C,FIO40-C,Yes,Rule,,,Reset strings on fgets() or fgetws() failure,,IO,Medium, -c,CERT-C,FIO41-C,Yes,Rule,,,"Do not call getc(), putc(), getwc(), or putwc() with a stream argument that has side effects",,IO,Medium, +c,CERT-C,FIO40-C,Yes,Rule,,,Reset strings on fgets() or fgetws() failure,,IO2,Medium, +c,CERT-C,FIO41-C,Yes,Rule,,,"Do not call getc(), putc(), getwc(), or putwc() with a stream argument that has side effects",,IO2,Medium, c,CERT-C,FIO42-C,Yes,Rule,,,Close files when they are no longer needed,FIO51-CPP,IO1,Medium, -c,CERT-C,FIO44-C,Yes,Rule,,,Only use values for fsetpos() that are returned from fgetpos(),,IO,Medium, +c,CERT-C,FIO44-C,Yes,Rule,,,Only use values for fsetpos() that are returned from fgetpos(),,IO2,Medium, c,CERT-C,FIO45-C,Yes,Rule,,,Avoid TOCTOU race conditions while accessing files,,IO,Medium, c,CERT-C,FIO46-C,Yes,Rule,,,Do not access a closed file,FIO51-CPP,IO1,Hard, c,CERT-C,FIO47-C,Yes,Rule,,,Use valid format strings,,IO,Hard, @@ -606,7 +606,7 @@ c,MISRA-C-2012,RULE-4-1,No,Required,,,Run-time failures shall be minimized,,,, c,MISRA-C-2012,RULE-4-2,Yes,Advisory,,,All usage of assembly language should be documented,M7-4-1,Language,Import, c,MISRA-C-2012,RULE-4-3,Yes,Required,,,Assembly language shall be encapsulated and isolated,,Language,Medium, c,MISRA-C-2012,RULE-4-4,Yes,Advisory,,,Sections of code should not be commented out,A2-7-2,Syntax,Import, -c,MISRA-C-2012,RULE-4-5,Yes,Advisory,,,Identifiers in the same name space with overlapping visibility should be typographically unambiguous,M2-10-1,Syntax,Easy, +c,MISRA-C-2012,DIR-4-5,Yes,Advisory,,,Identifiers in the same name space with overlapping visibility should be typographically unambiguous,M2-10-1,Syntax,Easy, c,MISRA-C-2012,RULE-4-6,Yes,Advisory,,,typedefs that indicate size and signedness should be used in place of the basic numerical types,,Types,Hard, c,MISRA-C-2012,RULE-4-7,Yes,Required,,,"If a function returns error information, then that error information shall be tested",M0-3-2,Contracts,Import, c,MISRA-C-2012,RULE-4-8,Yes,Advisory,,,"If a pointer to a structure or union is never dereferenced within a translation unit, then the implementation of the object should be hidden",,Pointers,Medium, @@ -682,17 +682,17 @@ c,MISRA-C-2012,RULE-11-6,Yes,Required,,,A cast shall not be performed between po c,MISRA-C-2012,RULE-11-7,Yes,Required,,,A cast shall not be performed between pointer to object and a non- integer arithmetic type,,Pointers,Easy, c,MISRA-C-2012,RULE-11-8,Yes,Required,,,A cast shall not remove any const or volatile qualification from the type pointed to by a pointer,,Pointers,Easy, c,MISRA-C-2012,RULE-11-9,Yes,Required,,,The macro NULL shall be the only permitted form of integer null pointer constant,,Pointers,Easy, -c,MISRA-C-2012,RULE-12-1,Yes,Advisory,,,The precedence of operators within expressions should be made explicit,,SideEffects,Medium, +c,MISRA-C-2012,RULE-12-1,Yes,Advisory,,,The precedence of operators within expressions should be made explicit,,SideEffects1,Medium, c,MISRA-C-2012,RULE-12-2,Yes,Required,,,The right hand operand of a shift operator shall lie in the range zero to one less than the width in bits of the essential type of the left hand operand,,Contracts,Hard, c,MISRA-C-2012,RULE-12-3,Yes,Advisory,,,The comma operator should not be used,M5-18-1,Banned,Import, c,MISRA-C-2012,RULE-12-4,Yes,Advisory,,,Evaluation of constant expressions should not lead to unsigned integer wrap-around,INT30-C,Types,Easy, c,MISRA-C-2012,RULE-12-5,Yes,Mandatory,,,The sizeof operator shall not have an operand which is a function parameter declared as �array of type�,,Types,Medium, -c,MISRA-C-2012,RULE-13-1,Yes,Required,,,Initializer lists shall not contain persistent side effects,,SideEffects,Medium, -c,MISRA-C-2012,RULE-13-2,Yes,Required,,,The value of an expression and its persistent side effects shall be the same under all permitted evaluation orders,PRE31-C,SideEffects,Medium, -c,MISRA-C-2012,RULE-13-3,Yes,Advisory,,,A full expression containing an increment (++) or decrement (--) operator should have no other potential side effects other than that caused by the increment or decrement operator,,SideEffects,Medium, -c,MISRA-C-2012,RULE-13-4,Yes,Advisory,,,The result of an assignment operator should not be used,M6-2-1,SideEffects,Easy, -c,MISRA-C-2012,RULE-13-5,Yes,Required,,,The right hand operand of a logical && or || operator shall not contain persistent side effects,M5-14-1,SideEffects,Import, -c,MISRA-C-2012,RULE-13-6,Yes,Mandatory,,,The operand of the sizeof operator shall not contain any expression which has potential side effects,M5-3-4,SideEffects,Import, +c,MISRA-C-2012,RULE-13-1,Yes,Required,,,Initializer lists shall not contain persistent side effects,,SideEffects1,Medium, +c,MISRA-C-2012,RULE-13-2,Yes,Required,,,The value of an expression and its persistent side effects shall be the same under all permitted evaluation orders,PRE31-C,SideEffects2,Medium, +c,MISRA-C-2012,RULE-13-3,Yes,Advisory,,,A full expression containing an increment (++) or decrement (--) operator should have no other potential side effects other than that caused by the increment or decrement operator,,SideEffects2,Medium, +c,MISRA-C-2012,RULE-13-4,Yes,Advisory,,,The result of an assignment operator should not be used,M6-2-1,SideEffects1,Easy, +c,MISRA-C-2012,RULE-13-5,Yes,Required,,,The right hand operand of a logical && or || operator shall not contain persistent side effects,M5-14-1,SideEffects1,Import, +c,MISRA-C-2012,RULE-13-6,Yes,Mandatory,,,The operand of the sizeof operator shall not contain any expression which has potential side effects,M5-3-4,SideEffects1,Import, c,MISRA-C-2012,RULE-14-1,Yes,Required,,,A loop counter shall not have essentially floating type,FLP30-C A6-5-2,Types,Hard, c,MISRA-C-2012,RULE-14-2,Yes,Required,,,A for loop shall be well-formed,M6-5-1...M6-5-6,Statements,Medium, c,MISRA-C-2012,RULE-14-3,Yes,Required,,,Controlling expressions shall not be invariant,,Statements,Medium, @@ -718,7 +718,7 @@ c,MISRA-C-2012,RULE-17-4,Yes,Mandatory,,,All exit paths from a function with non c,MISRA-C-2012,RULE-17-5,Yes,Advisory,,,The function argument corresponding to a parameter declared to have an array type shall have an appropriate number of elements,,Contracts,Hard, c,MISRA-C-2012,RULE-17-6,Yes,Mandatory,,,The declaration of an array parameter shall not contain the static keyword between the [ ],,Declarations,Easy, c,MISRA-C-2012,RULE-17-7,Yes,Required,,,The value returned by a function having non-void return type shall be used,A0-1-2,Contracts,Import, -c,MISRA-C-2012,RULE-17-8,Yes,Advisory,,,A function parameter should not be modified,,SideEffects,Medium, +c,MISRA-C-2012,RULE-17-8,Yes,Advisory,,,A function parameter should not be modified,,SideEffects2,Medium, c,MISRA-C-2012,RULE-18-1,Yes,Required,,,A pointer resulting from arithmetic on a pointer operand shall address an element of the same array as that pointer operand,M5-0-16,Pointers,Import, c,MISRA-C-2012,RULE-18-2,Yes,Required,,,Subtraction between pointers shall only be applied to pointers that address elements of the same array,M5-0-17,Pointers,Import, c,MISRA-C-2012,RULE-18-3,Yes,Required,,,"The relational operators >, >=, < and <= shall not be applied to objects of pointer type except where they point into the same object",M5-0-18,Pointers,Import, diff --git a/scripts/generate_rules/generate_package_files.py b/scripts/generate_rules/generate_package_files.py index f9ba191f14..3830f1fb3e 100644 --- a/scripts/generate_rules/generate_package_files.py +++ b/scripts/generate_rules/generate_package_files.py @@ -21,7 +21,7 @@ entry in the `queries` array for each rule, we generate the following: - Query file in //src/rules//.ql - Query help file in //src/rules//.qhelp - - Implementation section in //src/rules//-implementation.xml + - Implementation section in //src/rules//.qhelp - Test reference in //test//.qlref - Test file in //test//test. @@ -63,6 +63,12 @@ } } +# Mapping from the QL language to source file extension used to generate a help example file. +ql_language_ext_mappings = { + "cpp": "cpp", + "c": "c" +} + parser = ArgumentParser(description=help_statement) parser.add_argument( "-a", @@ -178,9 +184,12 @@ def write_shared_implementation(package_name, rule_id, query, language_name, ql_ # Add a testref file for this query, that refers to the shared library test_ref_file = test_src_dir.joinpath( query["short_name"] + ".testref") - with open(test_ref_file, "w", newline="\n") as f: - f.write(str(shared_impl_test_query_path.relative_to( - repo_root)).replace("\\", "/")) + + # don't write it if it already exists + if not test_ref_file.exists(): + with open(test_ref_file, "w", newline="\n") as f: + f.write(str(shared_impl_test_query_path.relative_to( + repo_root)).replace("\\", "/")) def write_non_shared_testfiles(query, language_name, query_path, test_src_dir, src_pack_dir): @@ -337,16 +346,8 @@ def write_non_shared_testfiles(query, language_name, query_path, test_src_dir, s write_template(qhelp_template, query, package_name, qhelp_path) - # Add qhelp implementation file placeholder, if it doesn't exist - qhelp_impl_template = env.get_template( - "template-implementation.qhelp") - qhelp_impl_path = rule_src_dir.joinpath( - query["short_name"] + "-implementation.qhelp") - if not qhelp_impl_path.exists(): - write_template(qhelp_impl_template, query, - package_name, qhelp_impl_path) - # Add qhelp standard file placeholder, if it doesn't exist + query["sourcefile_ext"] = ql_language_ext_mappings[language_name] qhelp_std_template = env.get_template( "template-standard.qhelp") qhelp_std_path = rule_src_dir.joinpath( @@ -355,6 +356,9 @@ def write_non_shared_testfiles(query, language_name, query_path, test_src_dir, s write_template(qhelp_std_template, query, package_name, qhelp_std_path) + rule_src_dir.joinpath( + f"""standard-example.{query["sourcefile_ext"]}""").touch() + if "shared_implementation_short_name" in query: write_shared_implementation(package_name, rule_id, query, language_name, ql_language_name, common_src_pack_dir, common_test_pack_dir) else: @@ -389,4 +393,4 @@ def write_non_shared_testfiles(query, language_name, query_path, test_src_dir, s repo_root = Path(__file__).parent.parent.parent update_metadata_path = repo_root.joinpath( "scripts", "generate_metadata", "generate_metadata_for_language.py") -subprocess.run(["python", update_metadata_path, language_name]) +subprocess.run([sys.executable, update_metadata_path, language_name]) diff --git a/scripts/generate_rules/templates/template-standard.qhelp b/scripts/generate_rules/templates/template-standard.qhelp index ba5eaadab1..08e9d30f8d 100644 --- a/scripts/generate_rules/templates/template-standard.qhelp +++ b/scripts/generate_rules/templates/template-standard.qhelp @@ -22,7 +22,7 @@ - +
    diff --git a/scripts/generate_rules/templates/template.qhelp b/scripts/generate_rules/templates/template.qhelp index 7a6c52d922..144340ae0b 100644 --- a/scripts/generate_rules/templates/template.qhelp +++ b/scripts/generate_rules/templates/template.qhelp @@ -10,7 +10,7 @@ {% if implementation_scope is defined %}
    - {{ implementation_scope["description"] | escape }} +

    {{ implementation_scope["description"] | escape }}

    {% if implementation_scope["items"] is defined %}
      {% for implementation_scope_entry in implementation_scope["items"] %} diff --git a/scripts/help/cert-cpp-help-extraction.py b/scripts/help/cert-help-extraction.py similarity index 70% rename from scripts/help/cert-cpp-help-extraction.py rename to scripts/help/cert-help-extraction.py index a8f81e240b..15eb53973d 100644 --- a/scripts/help/cert-cpp-help-extraction.py +++ b/scripts/help/cert-help-extraction.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python import sys import requests from bs4 import BeautifulSoup @@ -5,15 +6,19 @@ import copy from pathlib import Path import hashlib -from urllib.parse import quote_plus +from urllib.parse import quote_plus, urlparse +import urllib.request +import re CERT_WIKI = "https://wiki.sei.cmu.edu" -RULES_LIST = "/confluence/display/cplusplus/2+Rules" +RULES_LIST_C = "/confluence/display/c/2+Rules" +RULES_LIST_CPP = "/confluence/display/cplusplus/2+Rules" script_path = Path(__file__) cache_path = script_path.parent.joinpath('.cache') cache_path.mkdir(exist_ok=True) repo_root = script_path.parent.parent.parent +rule_path = None def soupify(url: str) -> BeautifulSoup: @@ -23,7 +28,7 @@ def soupify(url: str) -> BeautifulSoup: cache_file = cache_path.joinpath(cache_key) if cache_file.exists(): with cache_file.open() as f: - content = f.read() + content = f.read().replace(u'\xa0', u' ') else: resp = requests.get(url) @@ -37,8 +42,24 @@ def soupify(url: str) -> BeautifulSoup: return BeautifulSoup(content, 'html.parser') -def get_rules(): - soup = soupify(f"{CERT_WIKI}{RULES_LIST}") +def get_rules_c(): + soup = soupify(f"{CERT_WIKI}{RULES_LIST_C}") + if soup == None: + return None + + rule_listing_start = soup.find( + "h1", string="Rule Listing") + rules = [] + for link in rule_listing_start.next_element.next_element.find_all('a'): + if '-C' in link.string: + rule, title = map(str.strip, link.string.split('.', 1)) + rules.append({'id': rule, 'title': title, 'link': link['href']}) + + return rules + + +def get_rules_cpp(): + soup = soupify(f"{CERT_WIKI}{RULES_LIST_CPP}") if soup == None: return None @@ -134,7 +155,6 @@ def text(e): SECTION_ELEMENTS = [e('example', none, any_block_element), e('fragment', none, any_block_element), - e('hr', none, none), e('include', any_of('hr'), none), e('overview', none, any_block_element), e('recommendation', none, any_block_element), @@ -171,7 +191,8 @@ def text(e): ELEMENTS = {e_tag(e): e for e in SECTION_ELEMENTS + BLOCK_ELEMENTS + LIST_ELEMENTS + TABLE_ELEMENTS + INLINE_ELEMENTS} -SUPPORTED_TAGS = list(ELEMENTS.keys()) + ['body', 'h1', 'h2', 'h3', 'h4'] +SUPPORTED_TAGS = list(ELEMENTS.keys()) + \ + ['body', 'h1', 'h2', 'h3', 'h4', 'h6', 'thead'] def is_code_table(tag): @@ -191,14 +212,20 @@ def is_navigation(node): return False -def transform_html(soup): +def transform_html(rule, soup): """Remove unsupported tags and attributes starting at node""" def helper(node): if isinstance(node, Tag): if node.name in SUPPORTED_TAGS: + # Fix a broken url present in many CERT-C pages + if node.name == 'a' and 'href' in node.attrs and node['href'] == "http://BB. Definitions#vulnerability": + node['href'] = "https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability" # Turn relative URLs into absolute URLS - if node.name == "a" and 'href' in node.attrs and node['href'].startswith("/confluence"): + elif node.name == 'a' and 'href' in node.attrs and node['href'].startswith("/confluence"): node['href'] = f"{CERT_WIKI}{node['href']}" + # Turn anchor references into absolute URLS + elif node.name == 'a' and 'href' in node.attrs and node['href'].startswith('#'): + node['href'] = f"{CERT_WIKI}{rule['link']}{node['href']}" # Percent encode exclude characters in fragments according to https://datatracker.ietf.org/doc/html/rfc2396#section-2.4.3 if node.name == 'a' and 'href' in node.attrs: href = node['href'] @@ -227,37 +254,33 @@ def helper(node): # Remove the navigation, we can only use the src attribute of the child because all other # attributes have been stripped if is_navigation(node): - if node.previous_sibling.name == 'hr': - node.previous_sibling.decompose() node.decompose() # Unwrap

      tags containing a list # Remove empty

      tags or tags containing a No-Break Space Unicode character representing a ` `. if node.name == "p" and (len(node.contents) == 0 or node.string == "\u00a0"): node.decompose() - # Remove non breaking spaces in headers - if node.name in ['h2', 'h3', 'h4']: - if len(node.contents) == 2 and node.contents[1].string == "\u00a0": - node.string = node.contents[0] # Smooth headers if node.name in ['h1', 'h2', 'h3', 'h4']: for child in node.contents: - if not isNavigableString(child): + if not text(child): child.unwrap() node.smooth() # Upgrade header levels :/ if node.name == 'h3' and node.string in ['Automated Detection', 'Related Vulnerabilities']: # print('Inconsistent header') node.name = 'h2' - # Wrap tr tags that are a direct child of a table without a tbody into a mandatory tbody - if node.name == 'table' and not node.tbody: + # All

    should be in a table inside a single + if node.name == 'table': + for b in node.find_all('thead', Recursive=False): + b.unwrap() + for b in node.find_all('tbody', Recursive=False): + b.unwrap() + tbody = soup.new_tag('tbody') for tr in node.find_all('tr', Recursive=False): - tbody.append(tr.extract()) + tbody.append(tr) node.append(tbody) - # Insert tr tags that are a direct child of a table with a tbody because are a result of an unwrapped thead - if node.name == 'table' and node.tbody and node.tr: - node.tbody.insert(0, node.tr.extract()) # Remove p tags from td and th tags if node.name in ['th', 'td'] and node.p: node.p.unwrap() @@ -266,6 +289,22 @@ def helper(node): node.decompose() if node.name == 'img' and 'data-macro-name' in node.attrs and node['data-macro-name'] == 'anchor': node.decompose() + # Retrieve Images + if node.name == 'img' and 'src' in node.attrs and node['src'].startswith("/confluence") and not node['src'].startswith("/confluence/plugins/"): + url = CERT_WIKI+node['src'] + filename = urlparse(url).path.split("/")[-1] + # exclude button arrows images + if not 'button_arrow' in filename: + full_name = repo_root.joinpath(rule_path, filename) + urllib.request.urlretrieve(url, full_name) + node['src'] = filename + # Unwrap , because can only contain text in QHelp + if node.name == 'code' and node.find_parent('a'): + node.unwrap() + # Swap containing , because can only contain text in QHelp + if node.name == 'a' and node.sup: + sup = node.sup.extract() + node.wrap(sup) # Swap containing , because can only contain text in QHelp if node.name == 'a' and node.strong: strong = node.strong.extract() @@ -291,10 +330,14 @@ def helper(node): # Replace with because in QLHelp
     is a block element while 
    with because in QLHelp is a block element while with because QLHelp doesn't support nested lists. if node.name == 'td' and node.ul: list_contents = ", ".join( - map(lambda n: n.string[0].lower() + n.string[1:], node.ul.find_all('li'))).capitalize() + map(lambda n: n.string.lower() + n.string[1:] if n.string else '', node.ul.find_all('li'))).capitalize() if not list_contents.endswith('.'): list_contents += '.' node.ul.replace_with(list_contents) @@ -303,28 +346,32 @@ def helper(node): for child in node.find_all('li', recursive=False): child.unwrap() node.unwrap() + # Replace
    • ...

    with the contents of the paragraph because QLHelp doesn't support paragraphs inside lists. + if node.name == 'p' and node.find_parent('li'): + node.unwrap() strip_attributes(node) + if node.name == 'h6': + node.name = 'p' else: node.unwrap() apply_post_order(soup.body, helper) def inject_versions(soup_with, soup_without): + def find_automated_detection_table(soup): + # Some help files use h2 and some use h3 + h = soup.find(text=re.compile("Automated Detection")) + return h.find_next('table') + def get_versions(): - # Some help files use h3 instead of :/ - h = soup_with.find(['h2', 'h3'], string="Automated Detection") - # Some help files use h2, but with additional content :/ - if not h: - for h2 in soup_with.find_all(['h2', 'h3']): - text = h2.contents[0] - if text.string == "Automated Detection": - h = h2 - break - if not h: - raise "Unable to find required 'Automated Detection' header" - table = h.next_sibling.table + table = find_automated_detection_table(soup_with) versions = [] - for tr in table.tbody.find_all('tr', Recursive=False): + trs = [] + if table.thead: + trs.extend(table.thead.find_all('tr', Recursive=False)) + if table.tbody: + trs.extend(table.tbody.find_all('tr', Recursive=False)) + for tr in trs: # Skip header row, if any if tr.th: continue @@ -332,29 +379,31 @@ def get_versions(): first_column = tr.td version_column = first_column.next_sibling - if version_column.div and version_column.div.p: + if version_column.div and version_column.div.div and version_column.div.div.p: + version = version_column.div.div.p.string + elif version_column.div and version_column.div.p: version = version_column.div.p.string elif version_column.div: version = version_column.div.string - elif (version_column.p and version_column.p.br) or version_column.br: - # No version information - version = "" - elif len(version_column.find_all(True)) > 0: - print(version_column) - raise "Unexpected version column" + elif version_column.p: + version = version_column.p.string + elif version_column.a: + version = version_column.a.string else: version = version_column.string - versions.append(version) + # replace None with the empty string + versions.append(version or '') return versions def set_versions(versions): - h = soup_without.find('h2', string="Automated Detection") - if not h: - print("Failed to find header 'Automated Detection'") - table = h.find_next('table') - + table = find_automated_detection_table(soup_without) i = 0 - for tr in table.tbody.find_all('tr', Recursive=False): + trs = [] + if table.thead: + trs.extend(table.thead.find_all('tr', Recursive=False)) + if table.tbody: + trs.extend(table.tbody.find_all('tr', Recursive=False)) + for tr in trs: # Skip header row, if any if tr.th: continue @@ -403,10 +452,6 @@ def aux(*args, **kwargs): return aux -def isNavigableString(t): - return isinstance(t, NavigableString) - - def get_help(rule): # print(rule) rule_view = soupify(f"{CERT_WIKI}{rule['link']}") @@ -420,24 +465,36 @@ def get_help(rule): return None soup.head.decompose() - transform_html(soup) + transform_html(rule, soup) inject_versions(rule_view, soup) qhelp_doc = convert2qhelp(soup) + # preserve whitespace when printing + qhelp_doc.preserve_whitespace_tags.update( + ['sample', 'code', 'strong', 'p', 'li']) return qhelp_doc.prettify() -rules = get_rules() -if rules == None: +rules_c = get_rules_c() +rules_cpp = get_rules_cpp() +if rules_c == None or rules_cpp == None: print("Failed to retrieve list of rules", file=sys.stdout) sys.exit(1) -for rule in rules: - print(f"ID: {rule['id']} url: {CERT_WIKI}{rule['link']}") - help = get_help(rule) +for rule in get_rules_c(): + rule_path = repo_root.joinpath('c', 'cert', 'src', 'rules', rule['id']) + # only consider implemented rules + if rule_path.exists(): + for help_rule_file in rule_path.glob('*-standard.qhelp'): + print(f"ID: {rule['id']} url: {CERT_WIKI}{rule['link']}") + with help_rule_file.open('w') as f: + f.write(get_help(rule)) + +for rule in get_rules_cpp(): rule_path = repo_root.joinpath('cpp', 'cert', 'src', 'rules', rule['id']) + # only consider implemented rules if rule_path.exists(): for help_rule_file in rule_path.glob('*-standard.qhelp'): - print(f"Writing {help_rule_file}") + print(f"ID: {rule['id']} url: {CERT_WIKI}{rule['link']}") with help_rule_file.open('w') as f: - f.write(help) + f.write(get_help(rule)) diff --git a/scripts/vscode/Get-TestOrQueryDirectoryForCurrentFile.ps1 b/scripts/vscode/Get-TestOrQueryDirectoryForCurrentFile.ps1 new file mode 100644 index 0000000000..23f784ce21 --- /dev/null +++ b/scripts/vscode/Get-TestOrQueryDirectoryForCurrentFile.ps1 @@ -0,0 +1,148 @@ +#!/usr/bin/env pwsh +param( + [Parameter(Mandatory)] + [string] + $CurrentFile +) +<# +We find the opposite of whatever they pass in. If the user gives us the query +directory, we give them the test directory and if they give us the test +directory, we give them the query directory. + +Note that this works for shared queries as well. +#> + +# Logic +# 1) Shared CPP queries get redirected to the Shared CPP Test +# 2) Shared CPP Tests get redirected to the Shared Query +# 3) Shared C Tests get redirected to the shared CPP Query +# 4) Shared C Queries Don't exist. +# 5) CPP Queries get redirected to the CPP Test +# 6) CPP Tests get redirected to the CPP Query +# 7) C Queries get redirected to C tests +# 8) C Tests get redirected to C queries + +# (1) Shared CPP Query +#$CurrentFile = "C:\Projects\codeql-coding-standards\cpp\common\src\codingstandards\cpp\rules\sectionsofcodeshallnotbecommentedout\SectionsOfCodeShallNotBeCommentedOut.qll" + +# (2) Shared CPP Test +#$CurrentFile = "C:\Projects\codeql-coding-standards\cpp\common\test\rules\catchblockshadowing\CatchBlockShadowing.ql" + +# (3) Shared C Test (***Not WOrking) +#$CurrentFile = "C:\Projects\codeql-coding-standards\c\common\test\rules\donotaccessaclosedfile\DoNotAccessAClosedFile.ql" + +# (4) Shared C Queries (DNE) + +# (5) CPP Query +#$CurrentFile = "C:\Projects\codeql-coding-standards\cpp\autosar\src\rules\A2-7-2\SectionsOfCodeCommentedOut.ql" + +# (6) CPP Test +#$CurrentFile = "C:\Projects\codeql-coding-standards\cpp\autosar\test\rules\A2-7-2\SectionsOfCodeCommentedOut.testref" + +# (7) C Query +#$CurrentFile = "C:\Projects\codeql-coding-standards\c\cert\src\rules\FIO42-C\CloseFilesWhenTheyAreNoLongerNeeded.ql" + +# (8) C Test +#$CurrentFile = "C:\Projects\codeql-coding-standards\c\cert\test\rules\FIO42-C\CloseFilesWhenTheyAreNoLongerNeeded.qlref" + + +$CurrentFile = Resolve-Path $CurrentFile # convert this to a real thing + + +$CPPSharedTest = $false +$CSharedTest = $false +# it's a cpp shared query +if(($CurrentFile.toString().IndexOf("\cpp\common\") -ge 0) -and ($CurrentFile.toString().IndexOf("\cpp\rules\") -ge 0)){ + Write-Host "Detected Shared CPP Query..." + + $OneAbove = Resolve-Path(Join-Path $CurrentFile ..\..\..\..\..\..\) + $CurrentPathSrcOrTest = Resolve-Path(Join-Path $CurrentFile ..\..\..\..\..\) + $CurrentRule = Resolve-Path(Join-Path $CurrentFile ..\) + + $Stem = Split-Path -Path $CurrentPathSrcOrTest -Leaf + $Rule = Split-Path -Path $CurrentRule -Leaf + +} +# shared cpp test \src\codingstandards\cpp\rules +elseif(($CurrentFile.toString().IndexOf("\cpp\common\test\rules") -ge 0)){ + Write-Host "Detected Shared CPP Test..." + + $OneAbove = Resolve-Path(Join-Path $CurrentFile ..\..\..\..\) + $CurrentPathSrcOrTest = Resolve-Path(Join-Path $CurrentFile ..\..\..\) + $CurrentRule = Resolve-Path(Join-Path $CurrentFile ..\) + + $Stem = Split-Path -Path $CurrentPathSrcOrTest -Leaf + $Rule = Split-Path -Path $CurrentRule -Leaf + + $CPPSharedTest = $true +} + +# it's a c shared test +elseif(($CurrentFile.toString().IndexOf("\c\common\test\rules\") -ge 0)){ + Write-Host "Detected Shared C Test..." + + $OneAbove = Resolve-Path(Join-Path $CurrentFile ..\..\..\..\..\..\) + $CurrentPathSrcOrTest = Resolve-Path(Join-Path $CurrentFile ..\..\..\) + $CurrentRule = Resolve-Path(Join-Path $CurrentFile ..\) + + $Stem = Split-Path -Path $CurrentPathSrcOrTest -Leaf + $Rule = Split-Path -Path $CurrentRule -Leaf + + + $CSharedTest = $true +} +# it's a normal query +else{ + Write-Host "Detected Non-Shared Query..." + $OneAbove = Resolve-Path(Join-Path $CurrentFile ..\..\..\..\) + $CurrentPathSrcOrTest = Resolve-Path(Join-Path $CurrentFile ..\..\..\) + $CurrentRule = Resolve-Path(Join-Path $CurrentFile ..\) + + $Stem = Split-Path -Path $CurrentPathSrcOrTest -Leaf + $Rule = Split-Path -Path $CurrentRule -Leaf +} +Write-Host "Input Path : $($CurrentFile)" +Write-Host "CurrentSrcOrTest Path: $($CurrentPathSrcOrTest)" +Write-Host "One Above : $($OneAbove)" +Write-Host "Stem : $($Stem)" +Write-Host "Rule : $($Rule)" + + +if($Stem -eq "test"){ + $SwitchTo = "src" + + # Small hack for inconsistent pathing + if($CPPSharedTest){ + $SwitchTo = "\src\codingstandards\cpp" + } + + if($CSharedTest){ + $SwitchTo = "cpp\common\src\codingstandards\cpp\" + } + +}elseif($Stem -eq "src"){ + $SwitchTo = "test" +}else{ + Write-Host "Not a query file. Exiting." + Exit +} + +Write-Host "Switch To : $($SwitchTo)" + + +$NewPath = (Join-Path (Join-Path (Join-Path $OneAbove $SwitchTo) "rules") $Rule) + +Write-Host "Switching to Path: $($NewPath)" + +# prefer ql files +$F = (Get-ChildItem "$($NewPath)\*.ql*") + +if($F.Length -eq 0){ + $Target = (Get-ChildItem "$($NewPath)\*")[0] +}else{ + $Target = $F[0] +} + +Write-Host "Target File $($Target.FullName)" + +code $Target.FullName diff --git a/supported_codeql_configs.json b/supported_codeql_configs.json index 1fca65f5ac..a0ad42a349 100644 --- a/supported_codeql_configs.json +++ b/supported_codeql_configs.json @@ -1,9 +1,9 @@ { "supported_environment": [ { - "codeql_cli": "2.6.3", - "codeql_standard_library": "codeql-cli/v2.6.3", - "codeql_cli_bundle": "codeql-bundle-20211005" + "codeql_cli": "2.7.6", + "codeql_standard_library": "codeql-cli/v2.7.6", + "codeql_cli_bundle": "codeql-bundle-20220120" } ], "supported_language" : [ From 9fd472d6aaf568850f1fb75951397b2c516746b9 Mon Sep 17 00:00:00 2001 From: Remco Vermeulen Date: Wed, 13 Jul 2022 12:16:56 +0200 Subject: [PATCH 0002/2973] Release v2.2.0 From 73ac82c1f1a8841aae2c3be272ea31ca091d3f00 Mon Sep 17 00:00:00 2001 From: Remco Vermeulen Date: Wed, 13 Jul 2022 12:17:08 +0200 Subject: [PATCH 0003/2973] Release v2.3.0 --- .github/workflows/code-scanning-pack-gen.yml | 1 - .github/workflows/codeql_unit_tests.yml | 23 +- .vscode/tasks.json | 45 +- c/cert/src/qlpack.yml | 2 +- ...gumentsForSideEffects-implementation.qhelp | 8 - ...tionArgumentsForSideEffects-standard.qhelp | 696 ++++++++++++++++- ...derOfFunctionArgumentsForSideEffects.qhelp | 3 - ...luationForSideEffects-implementation.qhelp | 8 - ...larEvaluationForSideEffects-standard.qhelp | 696 ++++++++++++++++- ...rderOfScalarEvaluationForSideEffects.qhelp | 3 - ...OperandWithSideEffect-implementation.qhelp | 8 - ...luatedOperandWithSideEffect-standard.qhelp | 500 +++++++++++- .../UnevaluatedOperandWithSideEffect.qhelp | 3 - ...InSelectionStatements-implementation.qhelp | 8 - ...nmentsInSelectionStatements-standard.qhelp | 715 +++++++++++++++++- .../AssignmentsInSelectionStatements.qhelp | 3 - ...nputFromFormatStrings-implementation.qhelp | 8 - .../ExcludeUserInputFromFormatStrings.qhelp | 3 - c/cert/src/rules/FIO30-C/standard-example.c | 0 ...FromAFileAndEofOrWeof-implementation.qhelp | 8 - ...BetweenCharReadFromAFileAndEofOrWeof.qhelp | 3 - ...fFileCheckPortability-implementation.qhelp | 8 - .../FIO34-C/EndOfFileCheckPortability.qhelp | 3 - c/cert/src/rules/FIO34-C/standard-example.c | 0 .../DoNotCopyAFileObject-implementation.qhelp | 8 - .../rules/FIO38-C/DoNotCopyAFileObject.qhelp | 3 - c/cert/src/rules/FIO38-C/standard-example.c | 0 ...eamWithoutPositioning-implementation.qhelp | 8 - ...atelyIOFromAStreamWithoutPositioning.qhelp | 3 - c/cert/src/rules/FIO39-C/standard-example.c | 0 ...nFgetsOrFgetwsFailure-implementation.qhelp | 8 - .../ResetStringsOnFgetsOrFgetwsFailure.qhelp | 3 - c/cert/src/rules/FIO40-C/standard-example.c | 0 ...ndPutcWithSideEffects-implementation.qhelp | 8 - .../DoNotCallGetcAndPutcWithSideEffects.qhelp | 3 - c/cert/src/rules/FIO41-C/standard-example.c | 0 ...TheyAreNoLongerNeeded-implementation.qhelp | 8 - .../CloseFilesWhenTheyAreNoLongerNeeded.qhelp | 3 - c/cert/src/rules/FIO42-C/standard-example.c | 0 ...reReturnedFromFgetpos-implementation.qhelp | 8 - ...ForFsetposThatAreReturnedFromFgetpos.qhelp | 3 - c/cert/src/rules/FIO44-C/standard-example.c | 0 ...rAccessingAClosedFile-implementation.qhelp | 8 - ...ndefinedBehaviorAccessingAClosedFile.qhelp | 3 - c/cert/src/rules/FIO46-C/standard-example.c | 0 ...neratingPseudorandomNumbers-standard.qhelp | 597 +++++++++++++++ ...UsedForGeneratingPseudorandomNumbers.qhelp | 18 + ...andUsedForGeneratingPseudorandomNumbers.ql | 21 + ...seudorandomNumberGenerators-standard.qhelp | 425 +++++++++++ ...erlySeedPseudorandomNumberGenerators.qhelp | 18 + ...roperlySeedPseudorandomNumberGenerators.ql | 44 ++ ...hesTheEndOfANonVoidFunction-standard.qhelp | 524 +++++++++++++ ...lFlowReachesTheEndOfANonVoidFunction.qhelp | 18 + ...trolFlowReachesTheEndOfANonVoidFunction.ql | 22 + ...temptToModifyStringLiterals-standard.qhelp | 33 + .../DoNotAttemptToModifyStringLiterals.qhelp | 18 + .../DoNotAttemptToModifyStringLiterals.ql | 154 ++++ c/cert/src/rules/STR30-C/standard-example.c | 0 ...ntSpaceForTheNullTerminator-standard.qhelp | 33 + ...sSufficientSpaceForTheNullTerminator.qhelp | 18 + ...sHasSufficientSpaceForTheNullTerminator.ql | 67 ++ c/cert/src/rules/STR31-C/standard-example.c | 0 ...oFunctionThatExpectsAString-standard.qhelp | 33 + ...rminatedToFunctionThatExpectsAString.qhelp | 18 + ...lTerminatedToFunctionThatExpectsAString.ql | 75 ++ c/cert/src/rules/STR32-C/standard-example.c | 0 c/cert/test/qlpack.yml | 2 +- .../FIO38-C/DoNotCopyAFileObject.expected | 10 +- c/cert/test/rules/FIO38-C/test.c | 6 + ...edForGeneratingPseudorandomNumbers.testref | 1 + ...ySeedPseudorandomNumberGenerators.expected | 3 + ...erlySeedPseudorandomNumberGenerators.qlref | 1 + c/cert/test/rules/MSC32-C/test.c | 26 + ...lowReachesTheEndOfANonVoidFunction.testref | 1 + ...oNotAttemptToModifyStringLiterals.expected | 53 ++ .../DoNotAttemptToModifyStringLiterals.qlref | 1 + c/cert/test/rules/STR30-C/test.c | 184 +++++ ...fficientSpaceForTheNullTerminator.expected | 7 + ...sSufficientSpaceForTheNullTerminator.qlref | 1 + c/cert/test/rules/STR31-C/test.c | 58 ++ ...natedToFunctionThatExpectsAString.expected | 16 + ...rminatedToFunctionThatExpectsAString.qlref | 1 + c/cert/test/rules/STR32-C/test.c | 87 +++ c/common/src/codingstandards/c/Expr.qll | 21 +- c/common/src/codingstandards/c/Ordering.qll | 4 + .../src/codingstandards/c/SideEffects.qll | 41 + c/common/src/qlpack.yml | 2 +- c/common/test/expr/FullExpr.expected | 17 +- c/common/test/expr/fullexpr.c | 6 +- c/common/test/qlpack.yml | 2 +- c/misra/src/qlpack.yml | 2 +- .../SideEffectAndCrementInFullExpression.ql | 27 + .../src/rules/RULE-13-3/standard-example.c | 0 .../ModificationOfFunctionParameter.ql | 23 + .../src/rules/RULE-17-8/standard-example.c | 0 .../src/rules/RULE-20-1/standard-example.c | 5 + .../src/rules/RULE-20-2/standard-example.c | 1 + .../src/rules/RULE-20-9/standard-example.c | 11 + c/misra/test/qlpack.yml | 2 +- ...eEffectAndCrementInFullExpression.expected | 4 + ...SideEffectAndCrementInFullExpression.qlref | 1 + c/misra/test/rules/RULE-13-3/test.c | 48 ++ .../ModificationOfFunctionParameter.expected | 2 + .../ModificationOfFunctionParameter.qlref | 1 + c/misra/test/rules/RULE-17-8/test.c | 9 + change_notes/2022-04-06-rand-refactor.md | 1 + cpp/autosar/src/qlpack.yml | 2 +- ...tualPublicOrProtectedFunctionsRedefined.ql | 2 +- .../VirtualFunctionsIntroducedInFinalClass.ql | 2 +- .../src/rules/A15-1-5/standard-example.cpp | 0 .../PseudorandomNumbersGeneratedUsingRand.ql | 13 +- cpp/autosar/test/qlpack.yml | 2 +- ...blicOrProtectedFunctionsRedefined.expected | 2 +- ...alFunctionsIntroducedInFinalClass.expected | 4 +- ...dorandomNumbersGeneratedUsingRand.expected | 1 - ...seudorandomNumbersGeneratedUsingRand.qlref | 1 - ...udorandomNumbersGeneratedUsingRand.testref | 1 + cpp/cert/src/qlpack.yml | 2 +- ...OutOfScopeWhileLocked-implementation.qhelp | 8 - ...AllowAMutexToGoOutOfScopeWhileLocked.qhelp | 3 - ...AMutexWhileItIsLocked-implementation.qhelp | 8 - .../DoNotDestroyAMutexWhileItIsLocked.qhelp | 3 - ...ExceptionalConditions-implementation.qhelp | 8 - ...ksAreReleasedOnExceptionalConditions.qhelp | 3 - ...dsFromMultipleThreads-implementation.qhelp | 8 - ...ccessingBitFieldsFromMultipleThreads.qhelp | 3 - ...kingInPredefinedOrder-implementation.qhelp | 8 - .../DeadlockByLockingInPredefinedOrder.qhelp | 3 - ...puriouslyWakeUpInLoop-implementation.qhelp | 8 - ...nctionsThatCanSpuriouslyWakeUpInLoop.qhelp | 3 - ...ingConditionVariables-implementation.qhelp | 8 - ...dLivenessWhenUsingConditionVariables.qhelp | 3 - ...ckedNonRecursiveMutex-implementation.qhelp | 8 - ...lativelyLockALockedNonRecursiveMutex.qhelp | 3 - ...onRecursiveMutexAudit-implementation.qhelp | 8 - .../LockedALockedNonRecursiveMutexAudit.qhelp | 3 - ...WithoutRangeCheckCert-implementation.qhelp | 8 - ...ContainerAccessWithoutRangeCheckCert.qhelp | 3 - ...ontainerElementAccess-implementation.qhelp | 8 - .../UsesValidContainerElementAccess.qhelp | 3 - ...unctionsDoNotOverflow-implementation.qhelp | 8 - ...ericCppLibraryFunctionsDoNotOverflow.qhelp | 3 - ...seValidIteratorRanges-implementation.qhelp | 8 - .../CTR53-CPP/UseValidIteratorRanges.qhelp | 3 - ...orDifferentContainers-implementation.qhelp | 8 - ...tractIteratorsForDifferentContainers.qhelp | 3 - ...eOperatorOnAnIterator-implementation.qhelp | 8 - ...NotUseAnAdditiveOperatorOnAnIterator.qhelp | 3 - ...cOnPolymorphicObjects-implementation.qhelp | 8 - ...ointerArithmeticOnPolymorphicObjects.qhelp | 3 - ...alidOrderingPredicate-implementation.qhelp | 8 - .../ProvideAValidOrderingPredicate.qhelp | 3 - ...ctsShouldNotBeMutable-implementation.qhelp | 8 - ...ateFunctionObjectsShouldNotBeMutable.qhelp | 3 - ...StyleVariadicFunction-implementation.qhelp | 8 - .../DoNotDefineACStyleVariadicFunction.qhelp | 3 - ...torReusesReservedName-implementation.qhelp | 8 - .../EnumeratorReusesReservedName.qhelp | 3 - ...ionReusesReservedName-implementation.qhelp | 8 - .../FunctionReusesReservedName.qhelp | 3 - ...ectReusesReservedName-implementation.qhelp | 8 - .../DCL51-CPP/ObjectReusesReservedName.qhelp | 3 - ...OfStandardLibraryName-implementation.qhelp | 8 - .../RedefiningOfStandardLibraryName.qhelp | 3 - ...eOfReservedIdentifier-implementation.qhelp | 8 - .../DCL51-CPP/ReuseOfReservedIdentifier.qhelp | 3 - ...erscoreReservedPrefix-implementation.qhelp | 8 - .../UseOfDoubleUnderscoreReservedPrefix.qhelp | 3 - ...teralSuffixIdentifier-implementation.qhelp | 8 - ...UseOfReservedLiteralSuffixIdentifier.qhelp | 3 - ...erscoreReservedPrefix-implementation.qhelp | 8 - .../UseOfSingleUnderscoreReservedPrefix.qhelp | 3 - ...ObjectHidesIdentifier-implementation.qhelp | 8 - ...ctorInitializedObjectHidesIdentifier.qhelp | 3 - ...alFunctionDeclaration-implementation.qhelp | 8 - .../DCL53-CPP/LocalFunctionDeclaration.qhelp | 3 - ...rloadOfMemoryFunction-implementation.qhelp | 8 - .../SingularOverloadOfMemoryFunction.qhelp | 3 - ...AcrossTrustBoundaries-implementation.qhelp | 8 - ...ormationLeakageAcrossTrustBoundaries.qhelp | 3 - ...uringStaticObjectInit-implementation.qhelp | 8 - .../CyclesDuringStaticObjectInit.qhelp | 3 - ...DeallocationFunctions-implementation.qhelp | 8 - ...omDestructorsOrDeallocationFunctions.qhelp | 3 - ...TheStandardNamespaces-implementation.qhelp | 8 - .../ModificationOfTheStandardNamespaces.qhelp | 3 - ...NamespaceInHeaderFile-implementation.qhelp | 8 - .../UnnamedNamespaceInHeaderFile.qhelp | 3 - ...finitionRuleNotObeyed-implementation.qhelp | 8 - .../OneDefinitionRuleNotObeyed.qhelp | 3 - ...stConditionFailedCert-implementation.qhelp | 8 - ...itionVariablePostConditionFailedCert.qhelp | 3 - ...erThrowsExceptionCert-implementation.qhelp | 8 - .../ExitHandlerThrowsExceptionCert.qhelp | 3 - ...AbruptTerminationCert-implementation.qhelp | 8 - .../ExplicitAbruptTerminationCert.qhelp | 3 - ...CopiedOrDestroyedCert-implementation.qhelp | 8 - .../JoinableThreadCopiedOrDestroyedCert.qhelp | 3 - ...tedWithoutCaptureCert-implementation.qhelp | 8 - .../RethrowNestedWithoutCaptureCert.qhelp | 3 - .../HandleAllExceptions-implementation.qhelp | 8 - .../rules/ERR51-CPP/HandleAllExceptions.qhelp | 3 - ...NotUseSetjmpOrLongjmp-implementation.qhelp | 8 - .../ERR52-CPP/DoNotUseSetjmpOrLongjmp.qhelp | 3 - ...rDestructorCatchBlock-implementation.qhelp | 8 - ...cedInConstructorDestructorCatchBlock.qhelp | 3 - ...tchBlockShadowingCert-implementation.qhelp | 8 - .../ERR54-CPP/CatchBlockShadowingCert.qhelp | 3 - ...ceptionSpecifications-implementation.qhelp | 8 - .../HonorExceptionSpecifications.qhelp | 3 - ...ranteeExceptionSafety-implementation.qhelp | 8 - .../ERR56-CPP/GuaranteeExceptionSafety.qhelp | 3 - ...henHandlingExceptions-implementation.qhelp | 8 - ...tLeakResourcesWhenHandlingExceptions.qhelp | 3 - ...reMainBeginsExecuting-implementation.qhelp | 8 - ...tionsThrownBeforeMainBeginsExecuting.qhelp | 3 - ...ssExecutionBoundaries-implementation.qhelp | 8 - ...AnExceptionAcrossExecutionBoundaries.qhelp | 3 - ...hrowCopyConstructible-implementation.qhelp | 8 - ...bjectsMustBeNothrowCopyConstructible.qhelp | 3 - ...ionsByLvalueReference-implementation.qhelp | 8 - .../CatchExceptionsByLvalueReference.qhelp | 3 - ...rtingAStringToANumber-implementation.qhelp | 8 - ...ErrorsWhenConvertingAStringToANumber.qhelp | 3 - ...lsAsFunctionArguments-implementation.qhelp | 8 - ...tsInFunctionCallsAsFunctionArguments.qhelp | 3 - ...luationForSideEffects-implementation.qhelp | 8 - ...ScalarObjectEvaluationForSideEffects.qhelp | 3 - ...terOfTheIncorrectType-implementation.qhelp | 8 - ...rayThroughAPointerOfTheIncorrectType.qhelp | 3 - ...ectsInDeclTypeOperand-implementation.qhelp | 8 - ...otRelyOnSideEffectsInDeclTypeOperand.qhelp | 3 - ...tsInDeclValExpression-implementation.qhelp | 8 - ...RelyOnSideEffectsInDeclValExpression.qhelp | 3 - ...ectsInNoExceptOperand-implementation.qhelp | 8 - ...otRelyOnSideEffectsInNoExceptOperand.qhelp | 3 - ...ffectsInSizeOfOperand-implementation.qhelp | 8 - ...oNotRelyOnSideEffectsInSizeOfOperand.qhelp | 3 - ...ffectsInTypeIdOperand-implementation.qhelp | 8 - ...oNotRelyOnSideEffectsInTypeIdOperand.qhelp | 3 - ...adUninitializedMemory-implementation.qhelp | 8 - .../DoNotReadUninitializedMemory.qhelp | 3 - ...ssedAfterLifetimeCert-implementation.qhelp | 8 - .../ObjectAccessedAfterLifetimeCert.qhelp | 3 - ...sedBeforeLifetimeCert-implementation.qhelp | 8 - .../ObjectAccessedBeforeLifetimeCert.qhelp | 3 - ...tileQualificationCert-implementation.qhelp | 8 - ...moveConstOrVolatileQualificationCert.qhelp | 3 - ...atchedLanguageLinkage-implementation.qhelp | 8 - ...unctionWithMismatchedLanguageLinkage.qhelp | 3 - ...nterToIncompleteClass-implementation.qhelp | 8 - .../CastOfPointerToIncompleteClass.qhelp | 3 - ...nterToIncompleteClass-implementation.qhelp | 8 - .../DeletingPointerToIncompleteClass.qhelp | 3 - ...rivialObjectToVaStart-implementation.qhelp | 8 - .../PassNonTrivialObjectToVaStart.qhelp | 3 - ...rimitiveTypeToVaStart-implementation.qhelp | 8 - ...PassPromotablePrimitiveTypeToVaStart.qhelp | 3 - ...eferenceTypeToVaStart-implementation.qhelp | 8 - .../PassReferenceTypeToVaStart.qhelp | 3 - ...OnInvalidTypeOrMember-implementation.qhelp | 8 - .../OffsetUsedOnInvalidTypeOrMember.qhelp | 3 - ...bjectAcrossBoundaries-implementation.qhelp | 8 - ...ssANonstandardObjectAcrossBoundaries.qhelp | 3 - ...ithCaptureByReference-implementation.qhelp | 8 - ...ngLambdaObjectWithCaptureByReference.qhelp | 3 - ...ithCaptureByReference-implementation.qhelp | 8 - ...ngLambdaObjectWithCaptureByReference.qhelp | 3 - ...sObjectRepresentation-implementation.qhelp | 8 - ...mcmpUsedToAccessObjectRepresentation.qhelp | 3 - ...sObjectRepresentation-implementation.qhelp | 8 - ...mcpyUsedToAccessObjectRepresentation.qhelp | 3 - ...sObjectRepresentation-implementation.qhelp | 8 - ...msetUsedToAccessObjectRepresentation.qhelp | 3 - ...lueOfAMovedFromObject-implementation.qhelp | 8 - ...oNotRelyOnTheValueOfAMovedFromObject.qhelp | 3 - ...OutputWithoutPosition-implementation.qhelp | 8 - ...nterleavedInputOutputWithoutPosition.qhelp | 3 - ...TheyAreNoLongerNeeded-implementation.qhelp | 8 - .../CloseFilesWhenTheyAreNoLongerNeeded.qhelp | 3 - ...RangeEnumerationValue-implementation.qhelp | 8 - ...otCastToAnOutOfRangeEnumerationValue.qhelp | 3 - .../UseAfterFree-implementation.qhelp | 8 - .../src/rules/MEM50-CPP/UseAfterFree.qhelp | 3 - ...llyAllocatedResources-implementation.qhelp | 8 - ...llocateDynamicallyAllocatedResources.qhelp | 3 - ...emoryAllocationErrors-implementation.qhelp | 8 - ...etectAndHandleMemoryAllocationErrors.qhelp | 3 - ...ManuallyManagedObject-implementation.qhelp | 8 - ...structorCallForManuallyManagedObject.qhelp | 3 - ...ManuallyManagedObject-implementation.qhelp | 8 - ...structorCallForManuallyManagedObject.qhelp | 3 - ...sufficientStorageCert-implementation.qhelp | 8 - .../PlacementNewInsufficientStorageCert.qhelp | 3 - ...otProperlyAlignedCert-implementation.qhelp | 8 - .../PlacementNewNotProperlyAlignedCert.qhelp | 3 - ...eteMissingPartnerCert-implementation.qhelp | 8 - .../OperatorDeleteMissingPartnerCert.qhelp | 3 - ...OperatorNewDeleteCert-implementation.qhelp | 8 - ...ThrowingNoThrowOperatorNewDeleteCert.qhelp | 3 - ...torNewReturnsNullCert-implementation.qhelp | 8 - .../ThrowingOperatorNewReturnsNullCert.qhelp | 3 - ...sInvalidExceptionCert-implementation.qhelp | 8 - ...peratorNewThrowsInvalidExceptionCert.qhelp | 3 - ...latedSmartPointerCert-implementation.qhelp | 8 - ...lueStoredInUnrelatedSmartPointerCert.qhelp | 3 - ...ewForOverAlignedTypes-implementation.qhelp | 8 - ...efaultOperatorNewForOverAlignedTypes.qhelp | 3 - ...ngPseudorandomNumbers-implementation.qhelp | 8 - ...RandForGeneratingPseudorandomNumbers.qhelp | 3 - ...UseRandForGeneratingPseudorandomNumbers.ql | 13 +- ...RandomNumberGenerator-implementation.qhelp | 8 - .../BadlySeededRandomNumberGenerator.qhelp | 3 - ...tionDoesNotReturnCert-implementation.qhelp | 8 - .../NonVoidFunctionDoesNotReturnCert.qhelp | 3 - ...ttributeConditionCert-implementation.qhelp | 8 - ...nctionNoReturnAttributeConditionCert.qhelp | 3 - ...stBeAPlainOldFunction-implementation.qhelp | 8 - ...SignalHandlerMustBeAPlainOldFunction.qhelp | 3 - ...tructorsOrDestructors-implementation.qhelp | 8 - ...nctionsFromConstructorsOrDestructors.qhelp | 3 - ...otSliceDerivedObjects-implementation.qhelp | 8 - .../OOP51-CPP/DoNotSliceDerivedObjects.qhelp | 3 - ...outAVirtualDestructor-implementation.qhelp | 8 - ...rphicObjectWithoutAVirtualDestructor.qhelp | 3 - .../src/rules/OOP52-CPP/standard-example.cpp | 0 ...calOrderForMemberInit-implementation.qhelp | 8 - .../UseCanonicalOrderForMemberInit.qhelp | 3 - ...dleSelfCopyAssignment-implementation.qhelp | 8 - .../GracefullyHandleSelfCopyAssignment.qhelp | 3 - ...StaticPointerToMember-implementation.qhelp | 8 - ...thUninitializedStaticPointerToMember.qhelp | 3 - ...cessNonexistentMember-implementation.qhelp | 8 - ...terToMemberToAccessNonexistentMember.qhelp | 3 - ...AccessUndefinedMember-implementation.qhelp | 8 - ...interToMemberToAccessUndefinedMember.qhelp | 3 - ...ntHandlerRequirements-implementation.qhelp | 8 - ...norNewReplacementHandlerRequirements.qhelp | 3 - ...ntHandlerRequirements-implementation.qhelp | 8 - ...nationReplacementHandlerRequirements.qhelp | 3 - ...ndardLibraryFunctions-implementation.qhelp | 8 - ...OperatorsToCStandardLibraryFunctions.qhelp | 3 - ...MutateTheSourceObject-implementation.qhelp | 8 - ...erationsMustNotMutateTheSourceObject.qhelp | 3 - ...tBeNullTerminatedCert-implementation.qhelp | 8 - ...asicStringMayNotBeNullTerminatedCert.qhelp | 3 - ...inateCStyleStringCert-implementation.qhelp | 8 - ...nMayNotNullTerminateCStyleStringCert.qhelp | 3 - ...tringFromANullPointer-implementation.qhelp | 8 - ...temptToCreateAStringFromANullPointer.qhelp | 3 - ...esForElementsOfString-implementation.qhelp | 8 - ...seValidReferencesForElementsOfString.qhelp | 3 - ...ckStringElementAccess-implementation.qhelp | 8 - .../RangeCheckStringElementAccess.qhelp | 3 - cpp/cert/test/qlpack.yml | 2 +- ...RandForGeneratingPseudorandomNumbers.qlref | 1 - ...ndForGeneratingPseudorandomNumbers.testref | 1 + cpp/cert/test/rules/MSC50-CPP/test.cpp | 3 - .../cpp/PossiblyUnsafeStringOperation.qll | 28 + .../cpp/deviations/InvalidDeviationPermits.ql | 1 - .../cpp/deviations/InvalidDeviationRecords.ql | 1 - .../codingstandards/cpp/exclusions/c/Misc.qll | 58 ++ .../cpp/exclusions/c/RuleMetadata.qll | 9 + .../cpp/exclusions/c/SideEffects2.qll | 42 + .../cpp/exclusions/c/Strings1.qll | 58 ++ ...seRandForGeneratingPseudorandomNumbers.qll | 18 + .../cpp/sideeffect/DefaultEffects.qll | 8 +- cpp/common/src/qlpack.yml | 2 +- cpp/common/test/qlpack.yml | 2 +- ...dForGeneratingPseudorandomNumbers.expected | 0 ...UseRandForGeneratingPseudorandomNumbers.ql | 2 + .../test.cpp | 0 cpp/misra/src/qlpack.yml | 2 +- cpp/misra/test/qlpack.yml | 2 +- cpp/report/src/qlpack.yml | 2 +- development_handbook.md | 4 +- rule_packages/c/Misc.json | 66 ++ rule_packages/c/Preprocessor1.json | 13 +- rule_packages/c/SideEffects2.json | 43 ++ rule_packages/c/Strings1.json | 67 ++ rule_packages/cpp/BannedFunctions.json | 2 + rule_packages/cpp/Macros.json | 12 +- rules.csv | 14 +- .../templates/template-implementation.qhelp | 8 - .../generate_rules/templates/template.qhelp | 3 - 385 files changed, 5784 insertions(+), 1678 deletions(-) delete mode 100644 c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects-implementation.qhelp delete mode 100644 c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects-implementation.qhelp delete mode 100644 c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect-implementation.qhelp delete mode 100644 c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements-implementation.qhelp delete mode 100644 c/cert/src/rules/FIO30-C/ExcludeUserInputFromFormatStrings-implementation.qhelp create mode 100644 c/cert/src/rules/FIO30-C/standard-example.c delete mode 100644 c/cert/src/rules/FIO34-C/DistinguishBetweenCharReadFromAFileAndEofOrWeof-implementation.qhelp delete mode 100644 c/cert/src/rules/FIO34-C/EndOfFileCheckPortability-implementation.qhelp create mode 100644 c/cert/src/rules/FIO34-C/standard-example.c delete mode 100644 c/cert/src/rules/FIO38-C/DoNotCopyAFileObject-implementation.qhelp create mode 100644 c/cert/src/rules/FIO38-C/standard-example.c delete mode 100644 c/cert/src/rules/FIO39-C/DoNotAlternatelyIOFromAStreamWithoutPositioning-implementation.qhelp create mode 100644 c/cert/src/rules/FIO39-C/standard-example.c delete mode 100644 c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure-implementation.qhelp create mode 100644 c/cert/src/rules/FIO40-C/standard-example.c delete mode 100644 c/cert/src/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects-implementation.qhelp create mode 100644 c/cert/src/rules/FIO41-C/standard-example.c delete mode 100644 c/cert/src/rules/FIO42-C/CloseFilesWhenTheyAreNoLongerNeeded-implementation.qhelp create mode 100644 c/cert/src/rules/FIO42-C/standard-example.c delete mode 100644 c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos-implementation.qhelp create mode 100644 c/cert/src/rules/FIO44-C/standard-example.c delete mode 100644 c/cert/src/rules/FIO46-C/UndefinedBehaviorAccessingAClosedFile-implementation.qhelp create mode 100644 c/cert/src/rules/FIO46-C/standard-example.c create mode 100644 c/cert/src/rules/MSC30-C/RandUsedForGeneratingPseudorandomNumbers-standard.qhelp create mode 100644 c/cert/src/rules/MSC30-C/RandUsedForGeneratingPseudorandomNumbers.qhelp create mode 100644 c/cert/src/rules/MSC30-C/RandUsedForGeneratingPseudorandomNumbers.ql create mode 100644 c/cert/src/rules/MSC32-C/ProperlySeedPseudorandomNumberGenerators-standard.qhelp create mode 100644 c/cert/src/rules/MSC32-C/ProperlySeedPseudorandomNumberGenerators.qhelp create mode 100644 c/cert/src/rules/MSC32-C/ProperlySeedPseudorandomNumberGenerators.ql create mode 100644 c/cert/src/rules/MSC37-C/ControlFlowReachesTheEndOfANonVoidFunction-standard.qhelp create mode 100644 c/cert/src/rules/MSC37-C/ControlFlowReachesTheEndOfANonVoidFunction.qhelp create mode 100644 c/cert/src/rules/MSC37-C/ControlFlowReachesTheEndOfANonVoidFunction.ql create mode 100644 c/cert/src/rules/STR30-C/DoNotAttemptToModifyStringLiterals-standard.qhelp create mode 100644 c/cert/src/rules/STR30-C/DoNotAttemptToModifyStringLiterals.qhelp create mode 100644 c/cert/src/rules/STR30-C/DoNotAttemptToModifyStringLiterals.ql create mode 100644 c/cert/src/rules/STR30-C/standard-example.c create mode 100644 c/cert/src/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator-standard.qhelp create mode 100644 c/cert/src/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.qhelp create mode 100644 c/cert/src/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.ql create mode 100644 c/cert/src/rules/STR31-C/standard-example.c create mode 100644 c/cert/src/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString-standard.qhelp create mode 100644 c/cert/src/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.qhelp create mode 100644 c/cert/src/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.ql create mode 100644 c/cert/src/rules/STR32-C/standard-example.c create mode 100644 c/cert/test/rules/MSC30-C/RandUsedForGeneratingPseudorandomNumbers.testref create mode 100644 c/cert/test/rules/MSC32-C/ProperlySeedPseudorandomNumberGenerators.expected create mode 100644 c/cert/test/rules/MSC32-C/ProperlySeedPseudorandomNumberGenerators.qlref create mode 100644 c/cert/test/rules/MSC32-C/test.c create mode 100644 c/cert/test/rules/MSC37-C/ControlFlowReachesTheEndOfANonVoidFunction.testref create mode 100644 c/cert/test/rules/STR30-C/DoNotAttemptToModifyStringLiterals.expected create mode 100644 c/cert/test/rules/STR30-C/DoNotAttemptToModifyStringLiterals.qlref create mode 100644 c/cert/test/rules/STR30-C/test.c create mode 100644 c/cert/test/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.expected create mode 100644 c/cert/test/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.qlref create mode 100644 c/cert/test/rules/STR31-C/test.c create mode 100644 c/cert/test/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.expected create mode 100644 c/cert/test/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.qlref create mode 100644 c/cert/test/rules/STR32-C/test.c create mode 100644 c/common/src/codingstandards/c/SideEffects.qll create mode 100644 c/misra/src/rules/RULE-13-3/SideEffectAndCrementInFullExpression.ql create mode 100644 c/misra/src/rules/RULE-13-3/standard-example.c create mode 100644 c/misra/src/rules/RULE-17-8/ModificationOfFunctionParameter.ql create mode 100644 c/misra/src/rules/RULE-17-8/standard-example.c create mode 100644 c/misra/src/rules/RULE-20-1/standard-example.c create mode 100644 c/misra/src/rules/RULE-20-2/standard-example.c create mode 100644 c/misra/src/rules/RULE-20-9/standard-example.c create mode 100644 c/misra/test/rules/RULE-13-3/SideEffectAndCrementInFullExpression.expected create mode 100644 c/misra/test/rules/RULE-13-3/SideEffectAndCrementInFullExpression.qlref create mode 100644 c/misra/test/rules/RULE-13-3/test.c create mode 100644 c/misra/test/rules/RULE-17-8/ModificationOfFunctionParameter.expected create mode 100644 c/misra/test/rules/RULE-17-8/ModificationOfFunctionParameter.qlref create mode 100644 c/misra/test/rules/RULE-17-8/test.c create mode 100644 change_notes/2022-04-06-rand-refactor.md create mode 100644 cpp/autosar/src/rules/A15-1-5/standard-example.cpp delete mode 100644 cpp/autosar/test/rules/A26-5-1/PseudorandomNumbersGeneratedUsingRand.expected delete mode 100644 cpp/autosar/test/rules/A26-5-1/PseudorandomNumbersGeneratedUsingRand.qlref create mode 100644 cpp/autosar/test/rules/A26-5-1/PseudorandomNumbersGeneratedUsingRand.testref delete mode 100644 cpp/cert/src/rules/CON50-CPP/DoNotAllowAMutexToGoOutOfScopeWhileLocked-implementation.qhelp delete mode 100644 cpp/cert/src/rules/CON50-CPP/DoNotDestroyAMutexWhileItIsLocked-implementation.qhelp delete mode 100644 cpp/cert/src/rules/CON51-CPP/EnsureActivelyHeldLocksAreReleasedOnExceptionalConditions-implementation.qhelp delete mode 100644 cpp/cert/src/rules/CON52-CPP/PreventDataRacesWhenAccessingBitFieldsFromMultipleThreads-implementation.qhelp delete mode 100644 cpp/cert/src/rules/CON53-CPP/DeadlockByLockingInPredefinedOrder-implementation.qhelp delete mode 100644 cpp/cert/src/rules/CON54-CPP/WrapFunctionsThatCanSpuriouslyWakeUpInLoop-implementation.qhelp delete mode 100644 cpp/cert/src/rules/CON55-CPP/PreserveThreadSafetyAndLivenessWhenUsingConditionVariables-implementation.qhelp delete mode 100644 cpp/cert/src/rules/CON56-CPP/DoNotSpeculativelyLockALockedNonRecursiveMutex-implementation.qhelp delete mode 100644 cpp/cert/src/rules/CON56-CPP/LockedALockedNonRecursiveMutexAudit-implementation.qhelp delete mode 100644 cpp/cert/src/rules/CTR50-CPP/ContainerAccessWithoutRangeCheckCert-implementation.qhelp delete mode 100644 cpp/cert/src/rules/CTR51-CPP/UsesValidContainerElementAccess-implementation.qhelp delete mode 100644 cpp/cert/src/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow-implementation.qhelp delete mode 100644 cpp/cert/src/rules/CTR53-CPP/UseValidIteratorRanges-implementation.qhelp delete mode 100644 cpp/cert/src/rules/CTR54-CPP/DoNotSubtractIteratorsForDifferentContainers-implementation.qhelp delete mode 100644 cpp/cert/src/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator-implementation.qhelp delete mode 100644 cpp/cert/src/rules/CTR56-CPP/DoNotUsePointerArithmeticOnPolymorphicObjects-implementation.qhelp delete mode 100644 cpp/cert/src/rules/CTR57-CPP/ProvideAValidOrderingPredicate-implementation.qhelp delete mode 100644 cpp/cert/src/rules/CTR58-CPP/PredicateFunctionObjectsShouldNotBeMutable-implementation.qhelp delete mode 100644 cpp/cert/src/rules/DCL50-CPP/DoNotDefineACStyleVariadicFunction-implementation.qhelp delete mode 100644 cpp/cert/src/rules/DCL51-CPP/EnumeratorReusesReservedName-implementation.qhelp delete mode 100644 cpp/cert/src/rules/DCL51-CPP/FunctionReusesReservedName-implementation.qhelp delete mode 100644 cpp/cert/src/rules/DCL51-CPP/ObjectReusesReservedName-implementation.qhelp delete mode 100644 cpp/cert/src/rules/DCL51-CPP/RedefiningOfStandardLibraryName-implementation.qhelp delete mode 100644 cpp/cert/src/rules/DCL51-CPP/ReuseOfReservedIdentifier-implementation.qhelp delete mode 100644 cpp/cert/src/rules/DCL51-CPP/UseOfDoubleUnderscoreReservedPrefix-implementation.qhelp delete mode 100644 cpp/cert/src/rules/DCL51-CPP/UseOfReservedLiteralSuffixIdentifier-implementation.qhelp delete mode 100644 cpp/cert/src/rules/DCL51-CPP/UseOfSingleUnderscoreReservedPrefix-implementation.qhelp delete mode 100644 cpp/cert/src/rules/DCL53-CPP/LocalConstructorInitializedObjectHidesIdentifier-implementation.qhelp delete mode 100644 cpp/cert/src/rules/DCL53-CPP/LocalFunctionDeclaration-implementation.qhelp delete mode 100644 cpp/cert/src/rules/DCL54-CPP/SingularOverloadOfMemoryFunction-implementation.qhelp delete mode 100644 cpp/cert/src/rules/DCL55-CPP/InformationLeakageAcrossTrustBoundaries-implementation.qhelp delete mode 100644 cpp/cert/src/rules/DCL56-CPP/CyclesDuringStaticObjectInit-implementation.qhelp delete mode 100644 cpp/cert/src/rules/DCL57-CPP/DoNotLetExceptionsEscapeFromDestructorsOrDeallocationFunctions-implementation.qhelp delete mode 100644 cpp/cert/src/rules/DCL58-CPP/ModificationOfTheStandardNamespaces-implementation.qhelp delete mode 100644 cpp/cert/src/rules/DCL59-CPP/UnnamedNamespaceInHeaderFile-implementation.qhelp delete mode 100644 cpp/cert/src/rules/DCL60-CPP/OneDefinitionRuleNotObeyed-implementation.qhelp delete mode 100644 cpp/cert/src/rules/ERR50-CPP/ConditionVariablePostConditionFailedCert-implementation.qhelp delete mode 100644 cpp/cert/src/rules/ERR50-CPP/ExitHandlerThrowsExceptionCert-implementation.qhelp delete mode 100644 cpp/cert/src/rules/ERR50-CPP/ExplicitAbruptTerminationCert-implementation.qhelp delete mode 100644 cpp/cert/src/rules/ERR50-CPP/JoinableThreadCopiedOrDestroyedCert-implementation.qhelp delete mode 100644 cpp/cert/src/rules/ERR50-CPP/RethrowNestedWithoutCaptureCert-implementation.qhelp delete mode 100644 cpp/cert/src/rules/ERR51-CPP/HandleAllExceptions-implementation.qhelp delete mode 100644 cpp/cert/src/rules/ERR52-CPP/DoNotUseSetjmpOrLongjmp-implementation.qhelp delete mode 100644 cpp/cert/src/rules/ERR53-CPP/DestroyedValueReferencedInConstructorDestructorCatchBlock-implementation.qhelp delete mode 100644 cpp/cert/src/rules/ERR54-CPP/CatchBlockShadowingCert-implementation.qhelp delete mode 100644 cpp/cert/src/rules/ERR55-CPP/HonorExceptionSpecifications-implementation.qhelp delete mode 100644 cpp/cert/src/rules/ERR56-CPP/GuaranteeExceptionSafety-implementation.qhelp delete mode 100644 cpp/cert/src/rules/ERR57-CPP/DoNotLeakResourcesWhenHandlingExceptions-implementation.qhelp delete mode 100644 cpp/cert/src/rules/ERR58-CPP/HandleAllExceptionsThrownBeforeMainBeginsExecuting-implementation.qhelp delete mode 100644 cpp/cert/src/rules/ERR59-CPP/DoNotThrowAnExceptionAcrossExecutionBoundaries-implementation.qhelp delete mode 100644 cpp/cert/src/rules/ERR60-CPP/ExceptionObjectsMustBeNothrowCopyConstructible-implementation.qhelp delete mode 100644 cpp/cert/src/rules/ERR61-CPP/CatchExceptionsByLvalueReference-implementation.qhelp delete mode 100644 cpp/cert/src/rules/ERR62-CPP/DetectErrorsWhenConvertingAStringToANumber-implementation.qhelp delete mode 100644 cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments-implementation.qhelp delete mode 100644 cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfScalarObjectEvaluationForSideEffects-implementation.qhelp delete mode 100644 cpp/cert/src/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType-implementation.qhelp delete mode 100644 cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclTypeOperand-implementation.qhelp delete mode 100644 cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclValExpression-implementation.qhelp delete mode 100644 cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInNoExceptOperand-implementation.qhelp delete mode 100644 cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInSizeOfOperand-implementation.qhelp delete mode 100644 cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInTypeIdOperand-implementation.qhelp delete mode 100644 cpp/cert/src/rules/EXP53-CPP/DoNotReadUninitializedMemory-implementation.qhelp delete mode 100644 cpp/cert/src/rules/EXP54-CPP/ObjectAccessedAfterLifetimeCert-implementation.qhelp delete mode 100644 cpp/cert/src/rules/EXP54-CPP/ObjectAccessedBeforeLifetimeCert-implementation.qhelp delete mode 100644 cpp/cert/src/rules/EXP55-CPP/RemoveConstOrVolatileQualificationCert-implementation.qhelp delete mode 100644 cpp/cert/src/rules/EXP56-CPP/FunctionWithMismatchedLanguageLinkage-implementation.qhelp delete mode 100644 cpp/cert/src/rules/EXP57-CPP/CastOfPointerToIncompleteClass-implementation.qhelp delete mode 100644 cpp/cert/src/rules/EXP57-CPP/DeletingPointerToIncompleteClass-implementation.qhelp delete mode 100644 cpp/cert/src/rules/EXP58-CPP/PassNonTrivialObjectToVaStart-implementation.qhelp delete mode 100644 cpp/cert/src/rules/EXP58-CPP/PassPromotablePrimitiveTypeToVaStart-implementation.qhelp delete mode 100644 cpp/cert/src/rules/EXP58-CPP/PassReferenceTypeToVaStart-implementation.qhelp delete mode 100644 cpp/cert/src/rules/EXP59-CPP/OffsetUsedOnInvalidTypeOrMember-implementation.qhelp delete mode 100644 cpp/cert/src/rules/EXP60-CPP/DoNotPassANonstandardObjectAcrossBoundaries-implementation.qhelp delete mode 100644 cpp/cert/src/rules/EXP61-CPP/EscapingLambdaObjectWithCaptureByReference-implementation.qhelp delete mode 100644 cpp/cert/src/rules/EXP61-CPP/ReturningLambdaObjectWithCaptureByReference-implementation.qhelp delete mode 100644 cpp/cert/src/rules/EXP62-CPP/MemcmpUsedToAccessObjectRepresentation-implementation.qhelp delete mode 100644 cpp/cert/src/rules/EXP62-CPP/MemcpyUsedToAccessObjectRepresentation-implementation.qhelp delete mode 100644 cpp/cert/src/rules/EXP62-CPP/MemsetUsedToAccessObjectRepresentation-implementation.qhelp delete mode 100644 cpp/cert/src/rules/EXP63-CPP/DoNotRelyOnTheValueOfAMovedFromObject-implementation.qhelp delete mode 100644 cpp/cert/src/rules/FIO50-CPP/InterleavedInputOutputWithoutPosition-implementation.qhelp delete mode 100644 cpp/cert/src/rules/FIO51-CPP/CloseFilesWhenTheyAreNoLongerNeeded-implementation.qhelp delete mode 100644 cpp/cert/src/rules/INT50-CPP/DoNotCastToAnOutOfRangeEnumerationValue-implementation.qhelp delete mode 100644 cpp/cert/src/rules/MEM50-CPP/UseAfterFree-implementation.qhelp delete mode 100644 cpp/cert/src/rules/MEM51-CPP/ProperlyDeallocateDynamicallyAllocatedResources-implementation.qhelp delete mode 100644 cpp/cert/src/rules/MEM52-CPP/DetectAndHandleMemoryAllocationErrors-implementation.qhelp delete mode 100644 cpp/cert/src/rules/MEM53-CPP/MissingConstructorCallForManuallyManagedObject-implementation.qhelp delete mode 100644 cpp/cert/src/rules/MEM53-CPP/MissingDestructorCallForManuallyManagedObject-implementation.qhelp delete mode 100644 cpp/cert/src/rules/MEM54-CPP/PlacementNewInsufficientStorageCert-implementation.qhelp delete mode 100644 cpp/cert/src/rules/MEM54-CPP/PlacementNewNotProperlyAlignedCert-implementation.qhelp delete mode 100644 cpp/cert/src/rules/MEM55-CPP/OperatorDeleteMissingPartnerCert-implementation.qhelp delete mode 100644 cpp/cert/src/rules/MEM55-CPP/ThrowingNoThrowOperatorNewDeleteCert-implementation.qhelp delete mode 100644 cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewReturnsNullCert-implementation.qhelp delete mode 100644 cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewThrowsInvalidExceptionCert-implementation.qhelp delete mode 100644 cpp/cert/src/rules/MEM56-CPP/OwnedPointerValueStoredInUnrelatedSmartPointerCert-implementation.qhelp delete mode 100644 cpp/cert/src/rules/MEM57-CPP/UsingDefaultOperatorNewForOverAlignedTypes-implementation.qhelp delete mode 100644 cpp/cert/src/rules/MSC50-CPP/DoNotUseRandForGeneratingPseudorandomNumbers-implementation.qhelp delete mode 100644 cpp/cert/src/rules/MSC51-CPP/BadlySeededRandomNumberGenerator-implementation.qhelp delete mode 100644 cpp/cert/src/rules/MSC52-CPP/NonVoidFunctionDoesNotReturnCert-implementation.qhelp delete mode 100644 cpp/cert/src/rules/MSC53-CPP/FunctionNoReturnAttributeConditionCert-implementation.qhelp delete mode 100644 cpp/cert/src/rules/MSC54-CPP/SignalHandlerMustBeAPlainOldFunction-implementation.qhelp delete mode 100644 cpp/cert/src/rules/OOP50-CPP/DoNotInvokeVirtualFunctionsFromConstructorsOrDestructors-implementation.qhelp delete mode 100644 cpp/cert/src/rules/OOP51-CPP/DoNotSliceDerivedObjects-implementation.qhelp delete mode 100644 cpp/cert/src/rules/OOP52-CPP/DoNotDeleteAPolymorphicObjectWithoutAVirtualDestructor-implementation.qhelp create mode 100644 cpp/cert/src/rules/OOP52-CPP/standard-example.cpp delete mode 100644 cpp/cert/src/rules/OOP53-CPP/UseCanonicalOrderForMemberInit-implementation.qhelp delete mode 100644 cpp/cert/src/rules/OOP54-CPP/GracefullyHandleSelfCopyAssignment-implementation.qhelp delete mode 100644 cpp/cert/src/rules/OOP55-CPP/MemberAccessWithUninitializedStaticPointerToMember-implementation.qhelp delete mode 100644 cpp/cert/src/rules/OOP55-CPP/UseOfPointerToMemberToAccessNonexistentMember-implementation.qhelp delete mode 100644 cpp/cert/src/rules/OOP55-CPP/UseOfPointerToMemberToAccessUndefinedMember-implementation.qhelp delete mode 100644 cpp/cert/src/rules/OOP56-CPP/HonorNewReplacementHandlerRequirements-implementation.qhelp delete mode 100644 cpp/cert/src/rules/OOP56-CPP/HonorTerminationReplacementHandlerRequirements-implementation.qhelp delete mode 100644 cpp/cert/src/rules/OOP57-CPP/PreferSpecialMemberFunctionsAndOverloadedOperatorsToCStandardLibraryFunctions-implementation.qhelp delete mode 100644 cpp/cert/src/rules/OOP58-CPP/CopyOperationsMustNotMutateTheSourceObject-implementation.qhelp delete mode 100644 cpp/cert/src/rules/STR50-CPP/BasicStringMayNotBeNullTerminatedCert-implementation.qhelp delete mode 100644 cpp/cert/src/rules/STR50-CPP/OperationMayNotNullTerminateCStyleStringCert-implementation.qhelp delete mode 100644 cpp/cert/src/rules/STR51-CPP/DoNotAttemptToCreateAStringFromANullPointer-implementation.qhelp delete mode 100644 cpp/cert/src/rules/STR52-CPP/UseValidReferencesForElementsOfString-implementation.qhelp delete mode 100644 cpp/cert/src/rules/STR53-CPP/RangeCheckStringElementAccess-implementation.qhelp delete mode 100644 cpp/cert/test/rules/MSC50-CPP/DoNotUseRandForGeneratingPseudorandomNumbers.qlref create mode 100644 cpp/cert/test/rules/MSC50-CPP/DoNotUseRandForGeneratingPseudorandomNumbers.testref delete mode 100644 cpp/cert/test/rules/MSC50-CPP/test.cpp create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/c/Misc.qll create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/c/SideEffects2.qll create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/c/Strings1.qll create mode 100644 cpp/common/src/codingstandards/cpp/rules/donotuserandforgeneratingpseudorandomnumbers/DoNotUseRandForGeneratingPseudorandomNumbers.qll rename cpp/{cert/test/rules/MSC50-CPP => common/test/rules/donotuserandforgeneratingpseudorandomnumbers}/DoNotUseRandForGeneratingPseudorandomNumbers.expected (100%) create mode 100644 cpp/common/test/rules/donotuserandforgeneratingpseudorandomnumbers/DoNotUseRandForGeneratingPseudorandomNumbers.ql rename cpp/{autosar/test/rules/A26-5-1 => common/test/rules/donotuserandforgeneratingpseudorandomnumbers}/test.cpp (100%) create mode 100644 rule_packages/c/Misc.json create mode 100644 rule_packages/c/SideEffects2.json create mode 100644 rule_packages/c/Strings1.json delete mode 100644 scripts/generate_rules/templates/template-implementation.qhelp diff --git a/.github/workflows/code-scanning-pack-gen.yml b/.github/workflows/code-scanning-pack-gen.yml index 7406218e44..fdad8f9325 100644 --- a/.github/workflows/code-scanning-pack-gen.yml +++ b/.github/workflows/code-scanning-pack-gen.yml @@ -105,7 +105,6 @@ jobs: mkdir -p "$query_dir" # Copy each selected ql file, plus the related files (qhelp, qhelp implementation) cp "$copy_from_root_name.ql" "lgtm-cpp-query-pack/$copy_to_root_name.ql" - cp "$copy_from_root_name-implementation.qhelp" "lgtm-cpp-query-pack/$copy_to_root_name-implementation.qhelp" cp "$copy_from_root_name.qhelp" "lgtm-cpp-query-pack/$copy_to_root_name.qhelp" done } diff --git a/.github/workflows/codeql_unit_tests.yml b/.github/workflows/codeql_unit_tests.yml index 605489a0e0..c4e26abc08 100644 --- a/.github/workflows/codeql_unit_tests.yml +++ b/.github/workflows/codeql_unit_tests.yml @@ -65,6 +65,13 @@ jobs: codeql-home: ${{ github.workspace }}/codeql_home add-to-path: false + - name: Pre-Compile Queries + id: pre-compile-queries + run: | + ${{ github.workspace }}/codeql_home/codeql/codeql query compile --search-path cpp --threads 0 cpp + ${{ github.workspace }}/codeql_home/codeql/codeql query compile --search-path c --search-path cpp --threads 0 c + + - name: Run test suites id: run-test-suites env: @@ -108,12 +115,20 @@ jobs: # XL runners have 8 cores, so split the tests into 8 "slices", and run one per thread num_slices = 8 procs = [] + for slice in range(1, num_slices+1): test_report_path = os.path.join(runner_temp, "${{ matrix.language }}", f"test_report_{runner_os}_{cli_version}_{stdlib_ref_ident}_slice_{slice}_of_{num_slices}.json") os.makedirs(os.path.dirname(test_report_path), exist_ok=True) test_report_file = open(test_report_path, 'w') files_to_close.append(test_report_file) - procs.append(subprocess.Popen([codeql_bin, "test", "run", "--failing-exitcode=122", f"--slice={slice}/{num_slices}", "--ram=2048", "--format=json", f'--search-path={language_root}', *test_roots], stdout=test_report_file, stderr=subprocess.PIPE)) + if "${{ matrix.language }}".casefold() == "c".casefold(): + # c tests require cpp -- but we don't want c things on the cpp + # path in case of design errors. + cpp_language_root = Path(workspace, 'cpp') + procs.append(subprocess.Popen([codeql_bin, "test", "run", "--failing-exitcode=122", f"--slice={slice}/{num_slices}", "--ram=2048", "--format=json", f'--search-path={cpp_language_root}', f'--search-path={language_root}', *test_roots], stdout=test_report_file, stderr=subprocess.PIPE)) + else: + procs.append(subprocess.Popen([codeql_bin, "test", "run", "--failing-exitcode=122", f"--slice={slice}/{num_slices}", "--ram=2048", "--format=json", f'--search-path={language_root}', f'--search-path={language_root}', *test_roots], stdout=test_report_file, stderr=subprocess.PIPE)) + for p in procs: p.wait() if p.returncode != 0: @@ -133,7 +148,7 @@ jobs: - name: Upload test results uses: actions/upload-artifact@v2 with: - name: test-results-${{ runner.os }}-${{ matrix.codeql_cli }}-${{ matrix.codeql_standard_library_ident }} + name: ${{ matrix.language }}-test-results-${{ runner.os }}-${{ matrix.codeql_cli }}-${{ matrix.codeql_standard_library_ident }} path: | ${{ runner.temp }}/${{ matrix.language }}/test_report_${{ runner.os }}_${{ matrix.codeql_cli }}_${{ matrix.codeql_standard_library_ident }}_slice_*.json if-no-files-found: error @@ -148,11 +163,11 @@ jobs: - name: Validate test results run: | - for json_report in test-results-*/test_report_* + for json_report in *-test-results-*/test_report_* do jq --raw-output '"PASS \(map(select(.pass == true)) | length)/\(length)'" $json_report\"" "$json_report" done - FAILING_TESTS=$(jq --raw-output '.[] | select(.pass == false)' test-results-*/test_report_*.json) + FAILING_TESTS=$(jq --raw-output '.[] | select(.pass == false)' *-test-results-*/test_report_*.json) if [[ ! -z "$FAILING_TESTS" ]]; then echo "ERROR: The following tests failed:" echo $FAILING_TESTS | jq . diff --git a/.vscode/tasks.json b/.vscode/tasks.json index efcee24155..24432cd317 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -12,7 +12,6 @@ }, "problemMatcher": [] }, - { "label": "🔃 Standards Automation: Switch To Test or Implementation", "type": "shell", @@ -23,7 +22,6 @@ }, "problemMatcher": [] }, - { "label": "Standards Automation: Install Deps", "type": "shell", @@ -165,49 +163,52 @@ "type": "pickString", "options": [ "Allocations", + "BannedFunctions", "BannedSyntax", "BannedTypes", - "BannedFunctions", + "Classes", + "Classes", "Classes", "Comments", "Concurrency", + "Conditionals", "Const", + "DeadCode", "Declarations", "Exceptions1", "Exceptions2", + "Expressions", + "Freed", + "Functions", + "IO", "Includes", + "Initialization", + "IntegerConversion", "Invariants", - "IO", "Iterators", + "Lambdas", "Literals", "Loops", "Macros", + "Misc", + "MoveForward", "Naming", + "Null", + "OperatorInvariants", + "Operators", + "Pointers", "Scope", - "Classes", - "SmartPointers1", - "SmartPointers2", "SideEffects1", "SideEffects2", + "SmartPointers1", + "SmartPointers2", "Strings", + "Strings1", + "Strings2", "Syntax", "Templates", - "Classes", - "Freed", - "Initialization", - "Functions", - "Null", - "OperatorInvariants", - "VirtualFunctions", - "Conditionals", - "MoveForward", - "Operators", "TypeRanges", - "Lambdas", - "Pointers", - "IntegerConversion", - "Expressions", - "DeadCode" + "VirtualFunctions" ] }, { diff --git a/c/cert/src/qlpack.yml b/c/cert/src/qlpack.yml index 586a651e22..9ecaaadc79 100644 --- a/c/cert/src/qlpack.yml +++ b/c/cert/src/qlpack.yml @@ -1,4 +1,4 @@ name: cert-c-coding-standards -version: 2.1.0 +version: 2.3.0 suites: codeql-suites libraryPathDependencies: common-c-coding-standards \ No newline at end of file diff --git a/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects-implementation.qhelp b/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects-standard.qhelp b/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects-standard.qhelp index 458fbe3f7d..628d8290fb 100644 --- a/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects-standard.qhelp +++ b/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects-standard.qhelp @@ -1,33 +1,679 @@ -
    -
      -
    • required
    • -
    • implementation
    • -
    • automated
    • -
    -
    +
    +

    Evaluation of an expression may produce side effects. At specific points during execution, known as sequence points, all side effects of previous evaluations are complete, and no side effects of subsequent evaluations have yet taken place. Do not depend on the order of evaluation for side effects unless there is an intervening sequence point.

    +

    The C Standard, 6.5, paragraph 2 [ISO/IEC 9899:2011], states

    +
    +

    If a side effect on a scalar object is unsequenced relative to either a different side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined. If there are multiple allowable orderings of the subexpressions of an expression, the behavior is undefined if such an unsequenced side effect occurs in any of the orderings.

    +
    +

    This requirement must be met for each allowable ordering of the subexpressions of a full expression; otherwise, the behavior is undefined. (See undefined behavior 35.)

    +

    The following sequence points are defined in the C Standard, Annex C [ISO/IEC 9899:2011]:

    +
      +
    • Between the evaluations of the function designator and actual arguments in a function call and the actual call
    • +
    • Between the evaluations of the first and second operands of the following operators:Logical AND: &&Logical OR: ||Comma: ,
    • +
    • Between the evaluations of the first operand of the conditional ?: operator and whichever of the second and third operands is evaluated
    • +
    • The end of a full declarator
    • +
    • Between the evaluation of a full expression and the next full expression to be evaluated; the following are full expressions:An initializer that is not part of a compound literalThe expression in an expression statementThe controlling expression of a selection statement (if or switch)The controlling expression of a while or do statementEach of the (optional) expressions of a for statementThe (optional) expression in a return statement
    • +
    • Immediately before a library function returns
    • +
    • After the actions associated with each formatted input/output function conversion specifier
    • +
    • Immediately before and immediately after each call to a comparison function, and also between any call to a comparison function and any movement of the objects passed as arguments to that call
    • +
    +

    Furthermore, Section 6.5.16, paragraph 3 says (regarding assignment operations):

    +
    +

    The side effect of updating the stored value of the left operand is sequenced after the value computations of the left and right operands.

    +
    +

    This rule means that statements such as

    + i = i + 1; +a[i] = i; + +

    have defined behavior, and statements such as the following do not:

    + /* i is modified twice between sequence points */ +i = ++i + 1; -
    -

    - ... -

    +/* i is read other than to determine the value to be stored */ +a[i++] = i; + +

    Not all instances of a comma in C code denote a usage of the comma operator. For example, the comma between arguments in a function call is not a sequence point. However, according to the C Standard, 6.5.2.2, paragraph 10 [ISO/IEC 9899:2011]

    +
    +

    Every evaluation in the calling function (including other function calls) that is not otherwise specifically sequenced before or after the execution of the body of the called function is indeterminately sequenced with respect to the execution of the called function.

    +
    +

    This rule means that the order of evaluation for function call arguments is unspecified and can happen in any order.

    +
    +
    +

    Programs cannot safely rely on the order of evaluation of operands between sequence points. In this noncompliant code example, i is evaluated twice without an intervening sequence point, so the behavior of the expression is undefined:

    + #include <stdio.h> -
    +void func(int i, int *b) { + int a = i + b[++i]; + printf("%d, %d", a, i); +}
    +
    +
    +

    These examples are independent of the order of evaluation of the operands and can be interpreted in only one way:

    + #include <stdio.h> -
    -

    - ... -

    -
    +void func(int i, int *b) { + int a; + ++i; + a = i + b[i]; + printf("%d, %d", a, i); +}
    +

    Alternatively:

    + #include <stdio.h> - - - +void func(int i, int *b) { + int a = i + b[i + 1]; + ++i; + printf("%d, %d", a, i); +} +
    +
    +

    The call to func() in this noncompliant code example has undefined behavior because there is no sequence point between the argument expressions:

    + extern void func(int i, int j); + +void f(int i) { + func(i++, i); +} +

    The first (left) argument expression reads the value of i (to determine the value to be stored) and then modifies i. The second (right) argument expression reads the value of i between the same pair of sequence points as the first argument, but not to determine the value to be stored in i. This additional attempt to read the value of i has undefined behavior.

    +
    +
    +

    This compliant solution is appropriate when the programmer intends for both arguments to func() to be equivalent:

    + extern void func(int i, int j); + +void f(int i) { + i++; + func(i, i); +} +

    This compliant solution is appropriate when the programmer intends for the second argument to be 1 greater than the first:

    + extern void func(int i, int j); + +void f(int i) { + int j = i++; + func(j, i); +} +
    +
    +

    The order of evaluation for function arguments is unspecified. This noncompliant code example exhibits unspecified behavior but not undefined behavior:

    + extern void c(int i, int j); +int glob; + +int a(void) { + return glob + 10; +} -
    -
      -
    • ...
    • -
    -
    +int b(void) { + glob = 42; + return glob; +} + +void func(void) { + c(a(), b()); +}
    +

    It is unspecified what order a() and b() are called in; the only guarantee is that both a() and b() will be called before c() is called. If a() or b() rely on shared state when calculating their return value, as they do in this example, the resulting arguments passed to c() may differ between compilers or architectures.

    +
    +
    +

    In this compliant solution, the order of evaluation for a() and b() is fixed, and so no unspecified behavior occurs:

    + extern void c(int i, int j); +int glob; + +int a(void) { + return glob + 10; +} +int b(void) { + glob = 42; + return glob; +} + +void func(void) { + int a_val, b_val; + + a_val = a(); + b_val = b(); + + c(a_val, b_val); +} +
    +
    +

    Attempting to modify an object multiple times between sequence points may cause that object to take on an unexpected value, which can lead to unexpected program behavior.

    +
    Subclause 21.4.5, " - - basic_string - + basic_string Element Access"
    ...
    ... only allows inline content elements. if node.name == 'td' and node.pre: node.pre.name = 'code' + # Replace ...... only allows inline content elements. + if node.name == 'td' and node.sample: + node.sample.attrs = {} + node.sample.name = 'code' # Replace
      ...
    - ..., ...
    + + + + + + + + + + + + + + + + + + +
    + Rule + + Severity + + Likelihood + + Remediation Cost + + Priority + + Level +
    + EXP30-C + + Medium + + Probable + + Medium + + P8 + + L2 +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Tool + + Version + + Checker + + Description +
    + + Astrée + + + 20.10 + + evaluation-order + multiple-volatile-accesses + + Fully checked +
    + + Axivion Bauhaus Suite + + + 7.2.0 + + CertC-EXP30 + +
    + + Clang + + + 3.9 + + -Wunsequenced + + Detects simple violations of this rule, but does not diagnose unsequenced function call arguments. +
    + + Compass/ROSE + + + + + Can detect simple violations of this rule. It needs to examine each expression and make sure that no variable is modified twice in the expression. It also must check that no variable is modified once, then read elsewhere, with the single exception that a variable may appear on both the left and right of an assignment operator +
    + + Coverity + + + 2017.07 + + EVALUATION_ORDER + + Can detect the specific instance where a statement contains multiple side effects on the same value with an undefined evaluation order because, with different compiler flags or different compilers or platforms, the statement may behave differently +
    + + ECLAIR + + + 1.2 + + CC2.EXP30 + + Fully implemented +
    + + GCC + + + 4.3.5 + + + Can detect violations of this rule when the + -Wsequence-point + flag is used +
    + + Helix QAC + + + 2022.1 + + C0400, C0401, C0402, C0403, C0404, C0405 + +
    + + Klocwork + + + 2022.1 + + PORTING.VAR.EFFECTS + MISRA.INCR_DECR.OTHER + +
    + + LDRA tool suite + + + 9.7.1 + + 35 D, 1 Q, 9 S, 30 S, 134 S + + Partially implemented +
    + + Parasoft C/C++test + + + 2021.2 + + CERT_C-EXP30-a + CERT_C-EXP30-b + CERT_C-EXP30-c + CERT_C-EXP30-d + + The value of an expression shall be the same under any order of evaluation that the standard permits + Don't write code that depends on the order of evaluation of function arguments + Don't write code that depends on the order of evaluation of function designator and function arguments + Don't write code that depends on the order of evaluation of expression that involves a function call +
    + + PC-lint Plus + + + 1.4 + + 564 + + Partially supported +
    + + Polyspace Bug Finder + + + R2021a + + + CERT C: Rule EXP30-C + + + Checks for situations when expression value depends on order of evaluation or of side effects (rule partially covered) +
    + + PRQA QA-C + + + 9.7 + + 0400, 0401, 0402, + 0403, 0404, 0405 + + Fully implemented +
    + + PVS-Studio + + + 7.18 + + V532 + + , + + V567 + +
    + + RuleChecker + + + 20.10 + + evaluation-order + multiple-volatile-accesses + + Fully checked +
    + + Splint + + + 3.1.1 + + +
    + + SonarQube C/C++ Plugin + + + 3.11 + + IncAndDecMixedWithOtherOperators + +
    + + TrustInSoft Analyzer + + + 1.38 + + separated + + Exhaustively verified (see + + one compliant and one non-compliant example + + ). +
    +
    +
    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    +
    +
    +

    Key here (explains table format and definitions)

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Taxonomy + + Taxonomy item + + Relationship +
    + + CERT C + + + + EXP50-CPP. Do not depend on the order of evaluation for side effects + + + Prior to 2018-01-12: CERT: Unspecified Relationship +
    + + CERT Oracle Secure Coding Standard for Java + + + + EXP05-J. Do not follow a write by a subsequent write or read of the same object within an expression + + + Prior to 2018-01-12: CERT: Unspecified Relationship +
    + + ISO/IEC TR 24772:2013 + + + Operator Precedence/Order of Evaluation [JCW] + + Prior to 2018-01-12: CERT: Unspecified Relationship +
    + + ISO/IEC TR 24772:2013 + + + Side-effects and Order of Evaluation [SAM] + + Prior to 2018-01-12: CERT: Unspecified Relationship +
    + + MISRA C:2012 + + + Rule 13.2 (required) + + CERT cross-reference in + + MISRA C:2012 – Addendum 3 + +
    + + CWE 2.11 + + + + CWE-758 + + + 2017-07-07: CERT: Rule subset of CWE +
    +
    +
    +

    Key here for mapping notes

    +

    CWE-758 and EXP30-C

    +

    Independent( INT34-C, INT36-C, MEM30-C, MSC37-C, FLP32-C, EXP33-C, EXP30-C, ERR34-C, ARR32-C)

    +

    CWE-758 = Union( EXP30-C, list) where list =

    +
      +
    • Undefined behavior that results from anything other than reading and writing to a variable twice without an intervening sequence point.
    • +
    +
    +
    + + + + + + + + + + + + + + + +
    + [ + + ISO/IEC 9899:2011 + + ] + + 6.5, "Expressions" + 6.5.2.2, "Function Calls" + Annex C, "Sequence Points" +
    + [ + + Saks 2007 + + ] + +
    + [ + + Summit 2005 + + ] + + Questions 3.1, 3.2, 3.3, 3.3b, 3.7, 3.8, 3.9, 3.10a, 3.10b, and 3.11 +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.qhelp b/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.qhelp index f7783bface..0ad32f85e2 100644 --- a/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.qhelp +++ b/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C: diff --git a/c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects-implementation.qhelp b/c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects-standard.qhelp b/c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects-standard.qhelp index 458fbe3f7d..628d8290fb 100644 --- a/c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects-standard.qhelp +++ b/c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects-standard.qhelp @@ -1,33 +1,679 @@ -
    -
      -
    • required
    • -
    • implementation
    • -
    • automated
    • -
    -
    +
    +

    Evaluation of an expression may produce side effects. At specific points during execution, known as sequence points, all side effects of previous evaluations are complete, and no side effects of subsequent evaluations have yet taken place. Do not depend on the order of evaluation for side effects unless there is an intervening sequence point.

    +

    The C Standard, 6.5, paragraph 2 [ISO/IEC 9899:2011], states

    +
    +

    If a side effect on a scalar object is unsequenced relative to either a different side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined. If there are multiple allowable orderings of the subexpressions of an expression, the behavior is undefined if such an unsequenced side effect occurs in any of the orderings.

    +
    +

    This requirement must be met for each allowable ordering of the subexpressions of a full expression; otherwise, the behavior is undefined. (See undefined behavior 35.)

    +

    The following sequence points are defined in the C Standard, Annex C [ISO/IEC 9899:2011]:

    +
      +
    • Between the evaluations of the function designator and actual arguments in a function call and the actual call
    • +
    • Between the evaluations of the first and second operands of the following operators:Logical AND: &&Logical OR: ||Comma: ,
    • +
    • Between the evaluations of the first operand of the conditional ?: operator and whichever of the second and third operands is evaluated
    • +
    • The end of a full declarator
    • +
    • Between the evaluation of a full expression and the next full expression to be evaluated; the following are full expressions:An initializer that is not part of a compound literalThe expression in an expression statementThe controlling expression of a selection statement (if or switch)The controlling expression of a while or do statementEach of the (optional) expressions of a for statementThe (optional) expression in a return statement
    • +
    • Immediately before a library function returns
    • +
    • After the actions associated with each formatted input/output function conversion specifier
    • +
    • Immediately before and immediately after each call to a comparison function, and also between any call to a comparison function and any movement of the objects passed as arguments to that call
    • +
    +

    Furthermore, Section 6.5.16, paragraph 3 says (regarding assignment operations):

    +
    +

    The side effect of updating the stored value of the left operand is sequenced after the value computations of the left and right operands.

    +
    +

    This rule means that statements such as

    + i = i + 1; +a[i] = i; + +

    have defined behavior, and statements such as the following do not:

    + /* i is modified twice between sequence points */ +i = ++i + 1; -
    -

    - ... -

    +/* i is read other than to determine the value to be stored */ +a[i++] = i; + +

    Not all instances of a comma in C code denote a usage of the comma operator. For example, the comma between arguments in a function call is not a sequence point. However, according to the C Standard, 6.5.2.2, paragraph 10 [ISO/IEC 9899:2011]

    +
    +

    Every evaluation in the calling function (including other function calls) that is not otherwise specifically sequenced before or after the execution of the body of the called function is indeterminately sequenced with respect to the execution of the called function.

    +
    +

    This rule means that the order of evaluation for function call arguments is unspecified and can happen in any order.

    +
    +
    +

    Programs cannot safely rely on the order of evaluation of operands between sequence points. In this noncompliant code example, i is evaluated twice without an intervening sequence point, so the behavior of the expression is undefined:

    + #include <stdio.h> -
    +void func(int i, int *b) { + int a = i + b[++i]; + printf("%d, %d", a, i); +}
    +
    +
    +

    These examples are independent of the order of evaluation of the operands and can be interpreted in only one way:

    + #include <stdio.h> -
    -

    - ... -

    -
    +void func(int i, int *b) { + int a; + ++i; + a = i + b[i]; + printf("%d, %d", a, i); +}
    +

    Alternatively:

    + #include <stdio.h> - - - +void func(int i, int *b) { + int a = i + b[i + 1]; + ++i; + printf("%d, %d", a, i); +} +
    +
    +

    The call to func() in this noncompliant code example has undefined behavior because there is no sequence point between the argument expressions:

    + extern void func(int i, int j); + +void f(int i) { + func(i++, i); +} +

    The first (left) argument expression reads the value of i (to determine the value to be stored) and then modifies i. The second (right) argument expression reads the value of i between the same pair of sequence points as the first argument, but not to determine the value to be stored in i. This additional attempt to read the value of i has undefined behavior.

    +
    +
    +

    This compliant solution is appropriate when the programmer intends for both arguments to func() to be equivalent:

    + extern void func(int i, int j); + +void f(int i) { + i++; + func(i, i); +} +

    This compliant solution is appropriate when the programmer intends for the second argument to be 1 greater than the first:

    + extern void func(int i, int j); + +void f(int i) { + int j = i++; + func(j, i); +} +
    +
    +

    The order of evaluation for function arguments is unspecified. This noncompliant code example exhibits unspecified behavior but not undefined behavior:

    + extern void c(int i, int j); +int glob; + +int a(void) { + return glob + 10; +} -
    -
      -
    • ...
    • -
    -
    +int b(void) { + glob = 42; + return glob; +} + +void func(void) { + c(a(), b()); +}
    +

    It is unspecified what order a() and b() are called in; the only guarantee is that both a() and b() will be called before c() is called. If a() or b() rely on shared state when calculating their return value, as they do in this example, the resulting arguments passed to c() may differ between compilers or architectures.

    +
    +
    +

    In this compliant solution, the order of evaluation for a() and b() is fixed, and so no unspecified behavior occurs:

    + extern void c(int i, int j); +int glob; + +int a(void) { + return glob + 10; +} +int b(void) { + glob = 42; + return glob; +} + +void func(void) { + int a_val, b_val; + + a_val = a(); + b_val = b(); + + c(a_val, b_val); +} +
    +
    +

    Attempting to modify an object multiple times between sequence points may cause that object to take on an unexpected value, which can lead to unexpected program behavior.

    + + + + + + + + + + + + + + + + + + + +
    + Rule + + Severity + + Likelihood + + Remediation Cost + + Priority + + Level +
    + EXP30-C + + Medium + + Probable + + Medium + + P8 + + L2 +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Tool + + Version + + Checker + + Description +
    + + Astrée + + + 20.10 + + evaluation-order + multiple-volatile-accesses + + Fully checked +
    + + Axivion Bauhaus Suite + + + 7.2.0 + + CertC-EXP30 + +
    + + Clang + + + 3.9 + + -Wunsequenced + + Detects simple violations of this rule, but does not diagnose unsequenced function call arguments. +
    + + Compass/ROSE + + + + + Can detect simple violations of this rule. It needs to examine each expression and make sure that no variable is modified twice in the expression. It also must check that no variable is modified once, then read elsewhere, with the single exception that a variable may appear on both the left and right of an assignment operator +
    + + Coverity + + + 2017.07 + + EVALUATION_ORDER + + Can detect the specific instance where a statement contains multiple side effects on the same value with an undefined evaluation order because, with different compiler flags or different compilers or platforms, the statement may behave differently +
    + + ECLAIR + + + 1.2 + + CC2.EXP30 + + Fully implemented +
    + + GCC + + + 4.3.5 + + + Can detect violations of this rule when the + -Wsequence-point + flag is used +
    + + Helix QAC + + + 2022.1 + + C0400, C0401, C0402, C0403, C0404, C0405 + +
    + + Klocwork + + + 2022.1 + + PORTING.VAR.EFFECTS + MISRA.INCR_DECR.OTHER + +
    + + LDRA tool suite + + + 9.7.1 + + 35 D, 1 Q, 9 S, 30 S, 134 S + + Partially implemented +
    + + Parasoft C/C++test + + + 2021.2 + + CERT_C-EXP30-a + CERT_C-EXP30-b + CERT_C-EXP30-c + CERT_C-EXP30-d + + The value of an expression shall be the same under any order of evaluation that the standard permits + Don't write code that depends on the order of evaluation of function arguments + Don't write code that depends on the order of evaluation of function designator and function arguments + Don't write code that depends on the order of evaluation of expression that involves a function call +
    + + PC-lint Plus + + + 1.4 + + 564 + + Partially supported +
    + + Polyspace Bug Finder + + + R2021a + + + CERT C: Rule EXP30-C + + + Checks for situations when expression value depends on order of evaluation or of side effects (rule partially covered) +
    + + PRQA QA-C + + + 9.7 + + 0400, 0401, 0402, + 0403, 0404, 0405 + + Fully implemented +
    + + PVS-Studio + + + 7.18 + + V532 + + , + + V567 + +
    + + RuleChecker + + + 20.10 + + evaluation-order + multiple-volatile-accesses + + Fully checked +
    + + Splint + + + 3.1.1 + + +
    + + SonarQube C/C++ Plugin + + + 3.11 + + IncAndDecMixedWithOtherOperators + +
    + + TrustInSoft Analyzer + + + 1.38 + + separated + + Exhaustively verified (see + + one compliant and one non-compliant example + + ). +
    +
    +
    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    +
    +
    +

    Key here (explains table format and definitions)

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Taxonomy + + Taxonomy item + + Relationship +
    + + CERT C + + + + EXP50-CPP. Do not depend on the order of evaluation for side effects + + + Prior to 2018-01-12: CERT: Unspecified Relationship +
    + + CERT Oracle Secure Coding Standard for Java + + + + EXP05-J. Do not follow a write by a subsequent write or read of the same object within an expression + + + Prior to 2018-01-12: CERT: Unspecified Relationship +
    + + ISO/IEC TR 24772:2013 + + + Operator Precedence/Order of Evaluation [JCW] + + Prior to 2018-01-12: CERT: Unspecified Relationship +
    + + ISO/IEC TR 24772:2013 + + + Side-effects and Order of Evaluation [SAM] + + Prior to 2018-01-12: CERT: Unspecified Relationship +
    + + MISRA C:2012 + + + Rule 13.2 (required) + + CERT cross-reference in + + MISRA C:2012 – Addendum 3 + +
    + + CWE 2.11 + + + + CWE-758 + + + 2017-07-07: CERT: Rule subset of CWE +
    +
    +
    +

    Key here for mapping notes

    +

    CWE-758 and EXP30-C

    +

    Independent( INT34-C, INT36-C, MEM30-C, MSC37-C, FLP32-C, EXP33-C, EXP30-C, ERR34-C, ARR32-C)

    +

    CWE-758 = Union( EXP30-C, list) where list =

    +
      +
    • Undefined behavior that results from anything other than reading and writing to a variable twice without an intervening sequence point.
    • +
    +
    +
    + + + + + + + + + + + + + + + +
    + [ + + ISO/IEC 9899:2011 + + ] + + 6.5, "Expressions" + 6.5.2.2, "Function Calls" + Annex C, "Sequence Points" +
    + [ + + Saks 2007 + + ] + +
    + [ + + Summit 2005 + + ] + + Questions 3.1, 3.2, 3.3, 3.3b, 3.7, 3.8, 3.9, 3.10a, 3.10b, and 3.11 +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects.qhelp b/c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects.qhelp index 6313114ff9..b1a3a347d1 100644 --- a/c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects.qhelp +++ b/c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C: diff --git a/c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect-implementation.qhelp b/c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect-standard.qhelp b/c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect-standard.qhelp index 458fbe3f7d..f439c63755 100644 --- a/c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect-standard.qhelp +++ b/c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect-standard.qhelp @@ -1,33 +1,481 @@ -
    -
      -
    • required
    • -
    • implementation
    • -
    • automated
    • -
    -
    +
    +

    Some operators do not evaluate their operands beyond the type information the operands provide. When using one of these operators, do not pass an operand that would otherwise yield a side effect since the side effect will not be generated.

    +

    The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. In most cases, the operand is not evaluated. A possible exception is when the type of the operand is a variable length array type (VLA); then the expression is evaluated. When part of the operand of the sizeof operator is a VLA type and when changing the value of the VLA's size expression would not affect the result of the operator, it is unspecified whether or not the size expression is evaluated. (See unspecified behavior 22.)

    +

    The operand passed to_Alignof is never evaluated, despite not being an expression. For instance, if the operand is a VLA type and the VLA's size expression contains a side effect, that side effect is never evaluated.

    +

    The operand used in the controlling expression of a _Generic selection expression is never evaluated.

    +

    Providing an expression that appears to produce side effects may be misleading to programmers who are not aware that these expressions are not evaluated, and in the case of a VLA used in sizeof, have unspecified results. As a result, programmers may make invalid assumptions about program state, leading to errors and possible software vulnerabilities.

    +

    This rule is similar to PRE31-C. Avoid side effects in arguments to unsafe macros.

    +
    +
    +

    In this noncompliant code example, the expression a++ is not evaluated:

    + #include <stdio.h> + +void func(void) { + int a = 14; + int b = sizeof(a++); + printf("%d, %d\n", a, b); +} +

    Consequently, the value of a after b has been initialized is 14.

    +
    +
    +

    In this compliant solution, the variable a is incremented outside of the sizeof operation:

    + #include <stdio.h> + +void func(void) { + int a = 14; + int b = sizeof(a); + ++a; + printf("%d, %d\n", a, b); +} +
    +
    +

    In this noncompliant code example, the expression ++n in the initialization expression of a must be evaluated because its value affects the size of the VLA operand of the sizeof operator. However, in the initialization expression of b, the expression ++n % 1 evaluates to 0. This means that the value of n does not affect the result of the sizeof operator. Consequently, it is unspecified whether or not n will be incremented when initializing b.

    + #include <stddef.h> +#include <stdio.h> + +void f(size_t n) { + /* n must be incremented */ + size_t a = sizeof(int[++n]); + + /* n need not be incremented */ + size_t b = sizeof(int[++n % 1 + 1]); -
    -

    - ... -

    + printf("%zu, %zu, %zu\n", a, b, n); + /* ... */ +} +
    +
    +

    This compliant solution avoids changing the value of the variable n used in each sizeof expression and instead increments n safely afterwards:

    + #include <stddef.h> +#include <stdio.h> + +void f(size_t n) { + size_t a = sizeof(int[n + 1]); + ++n; -
    + size_t b = sizeof(int[n % 1 + 1]); + ++n; + printf("%zu, %zu, %zu\n", a, b, n); + /* ... */ +} +
    +
    +
    +

    This noncompliant code example attempts to modify a variable's value as part of the _Generic selection control expression. The programmer may expect that a is incremented, but because _Generic does not evaluate its control expression, the value of a is not modified.

    + #include <stdio.h> -
    -

    - ... -

    -
    +#define S(val) _Generic(val, int : 2, \ + short : 3, \ + default : 1) +void func(void) { + int a = 0; + int b = S(a++); + printf("%d, %d\n", a, b); +}
    +
    +
    +

    In this compliant solution, a is incremented outside of the _Generic selection expression:

    + #include <stdio.h> - - - - -
    -
      -
    • ...
    • -
    -
    +#define S(val) _Generic(val, int : 2, \ + short : 3, \ + default : 1) +void func(void) { + int a = 0; + int b = S(a); + ++a; + printf("%d, %d\n", a, b); +}
    +
    +
    +

    This noncompliant code example attempts to modify a variable while getting its default alignment value. The user may have expected val to be incremented as part of the _Alignof expression, but because _Alignof does not evaluate its operand, val is unchanged.

    + #include <stdio.h> + +void func(void) { + int val = 0; + /* ... */ + size_t align = _Alignof(int[++val]); + printf("%zu, %d\n", align, val); + /* ... */ +} +
    +
    +

    This compliant solution moves the expression out of the _Alignof operator:

    + #include <stdio.h> +void func(void) { + int val = 0; + /* ... */ + ++val; + size_t align = _Alignof(int[val]); + printf("%zu, %d\n", align, val); + /* ... */ +} +
    +
    +

    EXP44-C-EX1: Reading a volatile-qualified value is a side-effecting operation. However, accessing a value through a volatile-qualified type does not guarantee side effects will happen on the read of the value unless the underlying object is also volatile-qualified. Idiomatic reads of a volatile-qualified object are permissible as an operand to a sizeof(), _Alignof(), or _Generic expression, as in the following example:

    + void f(void) { + int * volatile v; + (void)sizeof(*v); +} +
    +
    +

    If expressions that appear to produce side effects are supplied to an operator that does not evaluate its operands, the results may be different than expected. Depending on how this result is used, it can lead to unintended program behavior.

    + + + + + + + + + + + + + + + + + + + +
    + Rule + + Severity + + Likelihood + + Remediation Cost + + Priority + + Level +
    + EXP44-C + + Low + + Unlikely + + Low + + P3 + + L3 +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Tool + + Version + + Checker + + Description +
    + + Astrée + + + 20.10 + + alignof-side-effectgeneric-selection-side-effectsizeof + + Fully checked +
    + + Axivion Bauhaus Suite + + + 7.2.0 + + CertC-EXP44 + +
    + + Clang + + + 3.9 + + -Wunevaluated-expression + + Can diagnose some instance of this rule, but not all (such as the + _Alignof + NCCE). +
    + + CodeSonar + + + 6.2p0 + + LANG.STRUCT.SE.SIZEOF + + Side effects in sizeof +
    + + Compass/ROSE + + + + +
    + + Coverity + + + 2017.07 + + MISRA C 2004 Rule 12.3 + + Partially implemented +
    + + ECLAIR + + + 1.2 + + CC2.EXP06 + + Fully implemented +
    + + Helix QAC + + + 2022.1 + + C3307 + +
    + + Klocwork + + + 2022.1 + + MISRA.SIZEOF.SIDE_EFFECT + +
    + + LDRA tool suite + + + 9.7.1 + + 54 S, 653 S + + Fully implemented +
    + + Parasoft C/C++test + + + 2021.2 + + CERT_C-EXP44-a + CERT_C-EXP44-b + + Object designated by a volatile lvalue should not be accessed in the operand of the sizeof operator + The function call that causes the side effect shall not be the operand of the sizeof operator +
    + + PC-lint Plus + + + 1.4 + + 9006 + + Partially supported: reports use of sizeof with an expression that would have side effects +
    + + Polyspace Bug Finder + + + R2021a + + + CERT C: Rule EXP44-C + + + Checks for situations when side effects of specified expressions are ignored (rule fully covered) +
    + + PRQA QA-C + + + 9.7 + + 3307 + + Fully implemented +
    + + PVS-Studio + + + 7.18 + + V568 + +
    + + RuleChecker + + + 20.10 + + alignof-side-effectgeneric-selection-side-effectsizeof + + Fully checked +
    +
    +
    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    +
    +
    +

    Key here (explains table format and definitions)

    + + + + + + + + + + + + + +
    + Taxonomy + + Taxonomy item + + Relationship +
    + + CERT C + + + + EXP52-CPP. Do not rely on side effects in unevaluated operands + + + Prior to 2018-01-12: CERT: Unspecified Relationship +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect.qhelp b/c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect.qhelp index 1069bc4211..b33510d090 100644 --- a/c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect.qhelp +++ b/c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C: diff --git a/c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements-implementation.qhelp b/c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements-standard.qhelp b/c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements-standard.qhelp index 458fbe3f7d..01036cbe97 100644 --- a/c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements-standard.qhelp +++ b/c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements-standard.qhelp @@ -1,33 +1,688 @@ -
    -
      -
    • required
    • -
    • implementation
    • -
    • automated
    • -
    -
    - -
    -

    - ... -

    - -
    - -
    -

    - ... -

    -
    - - - - - -
    -
      -
    • ...
    • -
    -
    +
    +

    Do not use the assignment operator in the contexts listed in the following table because doing so typically indicates programmer error and can result in unexpected behavior.

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Operator + + Context +
    + if + + Controlling expression +
    + while + + Controlling expression +
    + do ... while + + Controlling expression +
    + for + + Second operand +
    + ?: + + First operand +
    + ?: + + Second or third operands, where the ternary expression is used in any of these contexts +
    + && + + Either operand +
    + || + + either operand +
    + , + + Second operand, when the comma expression is used in any of these contexts +
    +

    Performing assignment statements in other contexts do not violate this rule. However, they may violate other rules, such as EXP30-C. Do not depend on the order of evaluation for side effects.

    +

    Noncompliant Code Example

    +

    In this noncompliant code example, an assignment expression is the outermost expression in an if statement:

    + if (a = b) { + /* ... */ +} + +

    Although the intent of the code may be to assign b to a and test the value of the result for equality to 0, it is frequently a case of the programmer mistakenly using the assignment operator = instead of the equals operator ==. Consequently, many compilers will warn about this condition, making this coding error detectable by adhering to MSC00-C. Compile cleanly at high warning levels.

    +
    +
    +

    When the assignment of b to a is not intended, the conditional block is now executed when a is equal to b:

    + if (a == b) { + /* ... */ +} + +
    +
    +

    When the assignment is intended, this compliant solution explicitly uses inequality as the outermost expression while performing the assignment in the inner expression:

    + if ((a = b) != 0) { + /* ... */ +} + +

    It is less desirable in general, depending on what was intended, because it mixes the assignment in the condition, but it is clear that the programmer intended the assignment to occur.

    +
    +
    +

    In this noncompliant code example, the expression x = y is used as the controlling expression of the while statement:

    + do { /* ... */ } while (foo(), x = y); +
    +
    +

    When the assignment of y to x is not intended, the conditional block should be executed only when x is equal to y, as in this compliant solution:

    + do { /* ... */ } while (foo(), x == y); + +
    +
    +

    When the assignment is intended, this compliant solution can be used:

    + do { /* ... */ } while (foo(), (x = y) != 0); + +
    +
    +

    The same result can be obtained using the for statement, which is specifically designed to evaluate an expression on each iteration of the loop, just before performing the test in its controlling expression. Remember that its controlling expression is the second operand, where the assignment occurs in its third operand:

    + for (; x; foo(), x = y) { /* ... */ } +
    +
    +

    In this noncompliant example, the expression p = q is used as the controlling expression of the while statement:

    + do { /* ... */ } while (x = y, p = q); +
    +
    +

    In this compliant solution, the expression x = y is not used as the controlling expression of the while statement:

    + do { /* ... */ } while (x = y, p == q); + +
    +
    +

    This noncompliant code example has a typo that results in an assignment rather than a comparison.

    + while (ch = '\t' || ch == ' ' || ch == '\n') { + /* ... */ +} + +

    Many compilers will warn about this condition. This coding error would typically be eliminated by adherence to MSC00-C. Compile cleanly at high warning levels. Although this code compiles, it will cause unexpected behavior to an unsuspecting programmer. If the intent was to verify a string such as a password, user name, or group user ID, the code may produce significant vulnerabilities and require significant debugging.

    +
    +
    +

    When comparisons are made between a variable and a literal or const-qualified variable, placing the variable on the right of the comparison operation can prevent a spurious assignment.

    +

    In this code example, the literals are placed on the left-hand side of each comparison. If the programmer were to inadvertently use an assignment operator, the statement would assign ch to '\t', which is invalid and produces a diagnostic message.

    + while ('\t' = ch || ' ' == ch || '\n' == ch) { + /* ... */ +} +

    Due to the diagnostic, the typo will be easily spotted and fixed.

    + while ('\t' == ch || ' ' == ch || '\n' == ch) { + /* ... */ +} +

    As a result, any mistaken use of the assignment operator that could otherwise create a vulnerability for operations such as string verification will result in a compiler diagnostic regardless of compiler, warning level, or implementation.

    +
    +
    +

    EXP45-C-EX1: Assignment can be used where the result of the assignment is itself an operand to a comparison expression or relational expression. In this compliant example, the expression x = y is itself an operand to a comparison operation:

    + if ((x = y) != 0) { /* ... */ } +

    EXP45-C-EX2: Assignment can be used where the expression consists of a single primary expression. The following code is compliant because the expression x = y is a single primary expression:

    + if ((x = y)) { /* ... */ } +

    The following controlling expression is noncompliant because && is not a comparison or relational operator and the entire expression is not primary:

    + if ((v = w) && flag) { /* ... */ } +

    When the assignment of v to w is not intended, the following controlling expression can be used to execute the conditional block when v is equal to w:

    + if ((v == w) && flag) { /* ... */ }; +

    When the assignment is intended, the following controlling expression can be used:

    + if (((v = w) != 0) && flag) { /* ... */ }; +

    EXP45-C-EX3: Assignment can be used in a function argument or array index. In this compliant solution, the expression x = y is used in a function argument:

    + if (foo(x = y)) { /* ... */ } +
    +
    +

    Errors of omission can result in unintended program flow.

    + + + + + + + + + + + + + + + + + + + +
    + Recommendation + + Severity + + Likelihood + + Remediation Cost + + Priority + + Level +
    + EXP45-C + + Low + + Likely + + Medium + + P6 + + L2 +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Tool + + Version + + Checker + + Description +
    + + Astrée + + + 20.10 + + assignment-conditional + + Fully checked +
    + + Axivion Bauhaus Suite + + + 7.2.0 + + CertC-EXP45 + +
    + + Clang + + + 3.9 + + -Wparentheses + + Can detect some instances of this rule, but does not detect all +
    + + CodeSonar + + + 6.2p0 + + LANG.STRUCT.CONDASSIGLANG.STRUCT.SE.CONDLANG.STRUCT.USEASSIGN + + Assignment in conditional + Condition contains side effects + Assignment result in expression +
    + + Compass/ROSE + + + + + Could detect violations of this recommendation by identifying any assignment expression as the top-level expression in an + if + or + while + statement +
    + + ECLAIR + + + 1.2 + + CC2.EXP18 + CC2.EXP21 + + Fully implemented +
    + + GCC + + + 4.3.5 + + + Can detect violations of this recommendation when the + -Wall + flag is used +
    + + Helix QAC + + + 2022.1 + + C3314, C3326, C3344, C3416 + C++4071, C++4074 + +
    + + Klocwork + + + 2022.1 + + ASSIGCOND.CALL + ASSIGCOND.GENMISRA.ASSIGN.COND + +
    + + LDRA tool suite + + + 9.7.1 + + 114 S, 132 S + + Enhanced Enforcement +
    + + Parasoft C/C++test + + + 2021.2 + + CERT_C-EXP45-b + CERT_C-EXP45-d + + Assignment operators shall not be used in conditions without brackets + Assignment operators shall not be used in expressions that yield a Boolean value +
    + + PC-lint Plus + + + 1.4 + + 720 + + Partially supported: reports Boolean test of unparenthesized assignment +
    + + Polyspace Bug Finder + + + R2021a + + + CERT C: Rule EXP45-C + + + Checks for invalid use of = (assignment) operator (rule fully covered) +
    + + PRQA QA-C + + + 9.7 + + 3314, 3326, 3344, 3416 + + Partially implemented +
    + + PRQA QA-C++ + + + 4.4 + + 4071, 4074 + +
    + + PVS-Studio + + + 7.18 + + V559 + , + V633 + , + V699 + +
    + + RuleChecker + + + 20.10 + + assignment-conditional + + Fully checked +
    + + SonarQube C/C++ Plugin + + + 3.11 + + AssignmentInSubExpression + +
    +
    +
    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    +
    +
    +

    Key here (explains table format and definitions)

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Taxonomy + + Taxonomy item + + Relationship +
    + + CERT C + + + + EXP19-CPP. Do not perform assignments in conditional expressions + + + Prior to 2018-01-12: CERT: Unspecified Relationship +
    + + CERT Oracle Secure Coding Standard for Java + + + + EXP51-J. Do not perform assignments in conditional expressions + + + Prior to 2018-01-12: CERT: Unspecified Relationship +
    + + ISO/IEC TR 24772:2013 + + + Likely Incorrect Expression [KOA] + + Prior to 2018-01-12: CERT: Unspecified Relationship +
    + + ISO/IEC TS 17961 + + + No assignment in conditional expressions [boolasgn] + + Prior to 2018-01-12: CERT: Unspecified Relationship +
    + + CWE 2.11 + + + + CWE-480 + + , Use of Incorrect Operator + + 2017-07-05: CERT: Rule subset of CWE +
    + + CWE 2.11 + + + + CWE-481 + + + 2017-07-05: CERT: Rule subset of CWE +
    +
    +
    +

    Key here for mapping notes

    +

    CWE-480 and EXP45-C

    +

    Intersection( EXP45-C, EXP46-C) = Ø

    +

    CWE-480 = Union( EXP45-C, list) where list =

    +
      +
    • Usage of incorrect operator besides s/=/==/
    • +
    +

    CWE-569 and EXP45-C

    +

    CWE-480 = Subset( CWE-569)

    +
    +
    + + + + + + + + + + + +
    + [ + + Dutta 03 + + ] + + "Best Practices for Programming in C" +
    + [ + + Hatton 1995 + + ] + + Section 2.7.2, "Errors of Omission and Addition" +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements.qhelp b/c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements.qhelp index 240fef3e3e..82c72bc417 100644 --- a/c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements.qhelp +++ b/c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C: diff --git a/c/cert/src/rules/FIO30-C/ExcludeUserInputFromFormatStrings-implementation.qhelp b/c/cert/src/rules/FIO30-C/ExcludeUserInputFromFormatStrings-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/c/cert/src/rules/FIO30-C/ExcludeUserInputFromFormatStrings-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO30-C/ExcludeUserInputFromFormatStrings.qhelp b/c/cert/src/rules/FIO30-C/ExcludeUserInputFromFormatStrings.qhelp index 7cd34ab9f2..c289d0a58b 100644 --- a/c/cert/src/rules/FIO30-C/ExcludeUserInputFromFormatStrings.qhelp +++ b/c/cert/src/rules/FIO30-C/ExcludeUserInputFromFormatStrings.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C: diff --git a/c/cert/src/rules/FIO30-C/standard-example.c b/c/cert/src/rules/FIO30-C/standard-example.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/cert/src/rules/FIO34-C/DistinguishBetweenCharReadFromAFileAndEofOrWeof-implementation.qhelp b/c/cert/src/rules/FIO34-C/DistinguishBetweenCharReadFromAFileAndEofOrWeof-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/c/cert/src/rules/FIO34-C/DistinguishBetweenCharReadFromAFileAndEofOrWeof-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO34-C/DistinguishBetweenCharReadFromAFileAndEofOrWeof.qhelp b/c/cert/src/rules/FIO34-C/DistinguishBetweenCharReadFromAFileAndEofOrWeof.qhelp index 5ba4f7c808..ddb42c3df5 100644 --- a/c/cert/src/rules/FIO34-C/DistinguishBetweenCharReadFromAFileAndEofOrWeof.qhelp +++ b/c/cert/src/rules/FIO34-C/DistinguishBetweenCharReadFromAFileAndEofOrWeof.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C: diff --git a/c/cert/src/rules/FIO34-C/EndOfFileCheckPortability-implementation.qhelp b/c/cert/src/rules/FIO34-C/EndOfFileCheckPortability-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/c/cert/src/rules/FIO34-C/EndOfFileCheckPortability-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO34-C/EndOfFileCheckPortability.qhelp b/c/cert/src/rules/FIO34-C/EndOfFileCheckPortability.qhelp index 4a648e11b0..980ea8be38 100644 --- a/c/cert/src/rules/FIO34-C/EndOfFileCheckPortability.qhelp +++ b/c/cert/src/rules/FIO34-C/EndOfFileCheckPortability.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C: diff --git a/c/cert/src/rules/FIO34-C/standard-example.c b/c/cert/src/rules/FIO34-C/standard-example.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/cert/src/rules/FIO38-C/DoNotCopyAFileObject-implementation.qhelp b/c/cert/src/rules/FIO38-C/DoNotCopyAFileObject-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/c/cert/src/rules/FIO38-C/DoNotCopyAFileObject-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO38-C/DoNotCopyAFileObject.qhelp b/c/cert/src/rules/FIO38-C/DoNotCopyAFileObject.qhelp index c9cb5b93ee..88766992b3 100644 --- a/c/cert/src/rules/FIO38-C/DoNotCopyAFileObject.qhelp +++ b/c/cert/src/rules/FIO38-C/DoNotCopyAFileObject.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C: diff --git a/c/cert/src/rules/FIO38-C/standard-example.c b/c/cert/src/rules/FIO38-C/standard-example.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/cert/src/rules/FIO39-C/DoNotAlternatelyIOFromAStreamWithoutPositioning-implementation.qhelp b/c/cert/src/rules/FIO39-C/DoNotAlternatelyIOFromAStreamWithoutPositioning-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/c/cert/src/rules/FIO39-C/DoNotAlternatelyIOFromAStreamWithoutPositioning-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO39-C/DoNotAlternatelyIOFromAStreamWithoutPositioning.qhelp b/c/cert/src/rules/FIO39-C/DoNotAlternatelyIOFromAStreamWithoutPositioning.qhelp index 7de21baaa1..333b34b2f1 100644 --- a/c/cert/src/rules/FIO39-C/DoNotAlternatelyIOFromAStreamWithoutPositioning.qhelp +++ b/c/cert/src/rules/FIO39-C/DoNotAlternatelyIOFromAStreamWithoutPositioning.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C: diff --git a/c/cert/src/rules/FIO39-C/standard-example.c b/c/cert/src/rules/FIO39-C/standard-example.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure-implementation.qhelp b/c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.qhelp b/c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.qhelp index d2b9fa3373..753fc0162f 100644 --- a/c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.qhelp +++ b/c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C: diff --git a/c/cert/src/rules/FIO40-C/standard-example.c b/c/cert/src/rules/FIO40-C/standard-example.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/cert/src/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects-implementation.qhelp b/c/cert/src/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/c/cert/src/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects.qhelp b/c/cert/src/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects.qhelp index 0468a54e20..9555b25cf1 100644 --- a/c/cert/src/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects.qhelp +++ b/c/cert/src/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C: diff --git a/c/cert/src/rules/FIO41-C/standard-example.c b/c/cert/src/rules/FIO41-C/standard-example.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/cert/src/rules/FIO42-C/CloseFilesWhenTheyAreNoLongerNeeded-implementation.qhelp b/c/cert/src/rules/FIO42-C/CloseFilesWhenTheyAreNoLongerNeeded-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/c/cert/src/rules/FIO42-C/CloseFilesWhenTheyAreNoLongerNeeded-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO42-C/CloseFilesWhenTheyAreNoLongerNeeded.qhelp b/c/cert/src/rules/FIO42-C/CloseFilesWhenTheyAreNoLongerNeeded.qhelp index d3b9cfb2f5..8349d80e59 100644 --- a/c/cert/src/rules/FIO42-C/CloseFilesWhenTheyAreNoLongerNeeded.qhelp +++ b/c/cert/src/rules/FIO42-C/CloseFilesWhenTheyAreNoLongerNeeded.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C: diff --git a/c/cert/src/rules/FIO42-C/standard-example.c b/c/cert/src/rules/FIO42-C/standard-example.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos-implementation.qhelp b/c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.qhelp b/c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.qhelp index cdbaab7a86..9bd681d3f1 100644 --- a/c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.qhelp +++ b/c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C: diff --git a/c/cert/src/rules/FIO44-C/standard-example.c b/c/cert/src/rules/FIO44-C/standard-example.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/cert/src/rules/FIO46-C/UndefinedBehaviorAccessingAClosedFile-implementation.qhelp b/c/cert/src/rules/FIO46-C/UndefinedBehaviorAccessingAClosedFile-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/c/cert/src/rules/FIO46-C/UndefinedBehaviorAccessingAClosedFile-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO46-C/UndefinedBehaviorAccessingAClosedFile.qhelp b/c/cert/src/rules/FIO46-C/UndefinedBehaviorAccessingAClosedFile.qhelp index f36147e9bf..7858cad959 100644 --- a/c/cert/src/rules/FIO46-C/UndefinedBehaviorAccessingAClosedFile.qhelp +++ b/c/cert/src/rules/FIO46-C/UndefinedBehaviorAccessingAClosedFile.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C: diff --git a/c/cert/src/rules/FIO46-C/standard-example.c b/c/cert/src/rules/FIO46-C/standard-example.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/cert/src/rules/MSC30-C/RandUsedForGeneratingPseudorandomNumbers-standard.qhelp b/c/cert/src/rules/MSC30-C/RandUsedForGeneratingPseudorandomNumbers-standard.qhelp new file mode 100644 index 0000000000..7d0bdffbc0 --- /dev/null +++ b/c/cert/src/rules/MSC30-C/RandUsedForGeneratingPseudorandomNumbers-standard.qhelp @@ -0,0 +1,597 @@ + + +
    +

    Pseudorandom number generators use mathematical algorithms to produce a sequence of numbers with good statistical properties, but the numbers produced are not genuinely random.

    +

    The C Standard rand() function makes no guarantees as to the quality of the random sequence produced. The numbers generated by some implementations of rand() have a comparatively short cycle and the numbers can be predictable. Applications that have strong pseudorandom number requirements must use a generator that is known to be sufficient for their needs.

    +
    +
    +

    The following noncompliant code generates an ID with a numeric part produced by calling the rand() function. The IDs produced are predictable and have limited randomness.

    + #include <stdio.h> +#include <stdlib.h> +  +enum { len = 12 }; +  +void func(void) { + /* + * id will hold the ID, starting with the characters + * "ID" followed by a random integer. + */ +  char id[len]; + int r; + int num; + /* ... */ + r = rand(); /* Generate a random integer */ + num = snprintf(id, len, "ID%-d", r); /* Generate the ID */ + /* ... */ +} +
    +
    +

    This compliant solution replaces the rand() function with the POSIX random() function:

    + #include <stdio.h> +#include <stdlib.h> +#include <time.h> + +enum { len = 12 };  + +void func(void) { + /* + * id will hold the ID, starting with the characters + * "ID" followed by a random integer. + */ +  char id[len]; + int r; + int num; + /* ... */ + struct timespec ts; + if (timespec_get(&ts, TIME_UTC) == 0) { +  /* Handle error */ + } + srandom(ts.tv_nsec ^ ts.tv_sec); /* Seed the PRNG */ + /* ... */ + r = random(); /* Generate a random integer */ + num = snprintf(id, len, "ID%-d", r); /* Generate the ID */ + /* ... */ +} +

    The POSIX random() function is a better pseudorandom number generator. Although on some platforms the low dozen bits generated by rand() go through a cyclic pattern, all the bits generated by random() are usable. The rand48 family of functions provides another alternative for pseudorandom numbers.

    +

    Although not specified by POSIX, arc4random() is another possibility for systems that support it. The arc4random(3) manual page [OpenBSD] states

    +
    +

    ... provides higher quality of data than those described in rand(3), random(3), and drand48(3).

    +
    +

    To achieve the best random numbers possible, an implementation-specific function must be used. When unpredictability is crucial and speed is not an issue, as in the creation of strong cryptographic keys, use a true entropy source, such as /dev/random, or a hardware device capable of generating random numbers. The /dev/random device can block for a long time if there are not enough events going on to generate sufficient entropy.

    +
    +
    +

    On Windows platforms, the BCryptGenRandom() function can be used to generate cryptographically strong random numbers. The Microsoft Developer Network BCryptGenRandom() reference [MSDN] states:

    +
    +

    The default random number provider implements an algorithm for generating random numbers that complies with the NIST SP800-90 standard, specifically the CTR_DRBG portion of that standard.

    +
    + #include <Windows.h> +#include <bcrypt.h> +#include <stdio.h> + +#pragma comment(lib, "Bcrypt") + +void func(void) { + BCRYPT_ALG_HANDLE Prov; + int Buffer; + if (!BCRYPT_SUCCESS( + BCryptOpenAlgorithmProvider(&Prov, BCRYPT_RNG_ALGORITHM, + NULL, 0))) { + /* handle error */ + } + if (!BCRYPT_SUCCESS(BCryptGenRandom(Prov, (PUCHAR) (&Buffer), + sizeof(Buffer), 0))) { + /* handle error */ + } + printf("Random number: %d\n", Buffer); + BCryptCloseAlgorithmProvider(Prov, 0); +} +
    +
    +

    The use of the rand() function can result in predictable random numbers.

    + + + + + + + + + + + + + + + + + + + +
    + Rule + + Severity + + Likelihood + + Remediation Cost + + Priority + + Level +
    + MSC30-C + + Medium + + Unlikely + + Low + + P6 + + L2 +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Tool + + Version + + Checker + + Description +
    + + Astrée + + + 20.10 + + stdlib-use-rand + + Fully checked +
    + + Axivion Bauhaus Suite + + + 7.2.0 + + CertC-MSC30 + +
    + + Clang + + + 4.0 (prerelease) + + cert-msc30-c + + Checked by + clang-tidy +
    + + CodeSonar + + + 6.2p0 + + BADFUNC.RANDOM.RAND + + Use of rand +
    + + Compass/ROSE + + + + +
    + + Coverity + + + 2017.07 + + DONTCALL + + Implemented - weak support +
    + + ECLAIR + + + 1.2 + + CC2.MSC30 + + Fully implemented +
    + + Helix QAC + + + 2022.1 + + C5022 + C++5029 + +
    + + Klocwork + + + 2022.1 + + CERT.MSC.STD_RAND_CALL + +
    + + LDRA tool suite + + + 9.7.1 + + 44 S + + Enhanced enforcement +
    + + Parasoft C/C++test + + + 2021.2 + + CERT_C-MSC30-a + + Do not use the rand() function for generating pseudorandom numbers +
    + + PC-lint Plus + + + 1.4 + + 586 + + Fully supported +
    + + Polyspace Bug Finder + + + R2021a + + + CERT C: Rule MSC30-C + + + Checks for vulnerable pseudo-random number generator (rule fully covered) +
    + + PRQA QA-C + + + 9.7 + + 5022 + + Fully implemented +
    + + PRQA QA-C++ + + + 4.4 + + 5029 + +
    + + RuleChecker + + + 20.10 + + stdlib-use-rand + + Fully checked +
    +
    +
    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    +
    +
    +

    Key here (explains table format and definitions)

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Taxonomy + + Taxonomy item + + Relationship +
    + + CERT C + + + + MSC50-CPP. Do not use std::rand() for generating pseudorandom numbers + + + Prior to 2018-01-12: CERT: Unspecified Relationship +
    + + CERT Oracle Secure Coding Standard for Java + + + + MSC02-J. Generate strong random numbers + + + Prior to 2018-01-12: CERT: Unspecified Relationship +
    + + CWE 2.11 + + + + CWE-327 + + , Use of a Broken or Risky Cryptographic Algorithm + + 2017-05-16: CERT: Rule subset of CWE +
    + + CWE 2.11 + + + + CWE-330 + + , Use of Insufficiently Random Values + + 2017-06-28: CERT: Rule subset of CWE +
    + + CWE 2.11 + + + + CWE-338 + + , Use of Cryptographically Weak Pseudo-Random Number Generator (PRNG) + + 2017-06-28: CERT: Rule subset of CWE +
    + + CWE 2.11 + + + + CWE-676 + + + 2017-05-18: CERT: Rule subset of CWE +
    +
    +
    +

    Key here for mapping notes

    +

    CWE-327 and MSC30-C

    +
      +
    • CWE-327 forbids “broken or risky cryptographic algorithms” but does not specify what constitutes such an algo.
    • +
    +
      +
    • Per CERT judgement, rand() qualifies, so:
    • +
    +
      +
    • CWE-327 = Union( MSC30-C, list) where list =
    • +
    +
      +
    • Invocation of broken/risky crypto algorithms besides rand()
    • +
    +

    CWE-338 and MSC30-C

    +

    CWE-338 = Union( MSC30-C, list) where list =

    +
      +
    • Use of a weak PRNG besides standard C rand().
    • +
    +

    CWE-330 and MSC30-C

    +

    Independent( MSC30-C, MSC32-C, CON33-C)

    +

    CWE-330 = Union( MSC30-C, MSC32-C, CON33-C, list) where list = other improper use or creation of random values. (EG the would qualify)

    +

    MSC30-C, MSC32-C and CON33-C are independent, they have no intersections. They each specify distinct errors regarding PRNGs.

    +

    CWE-676 and MSC30-C

    +
      +
    • Independent( ENV33-C, CON33-C, STR31-C, EXP33-C, MSC30-C, ERR34-C)
    • +
    +
      +
    • MSC30-C implies that rand() is dangerous.
    • +
    +
      +
    • CWE-676 = Union( MSC30-C, list) where list =
    • +
    +
      +
    • Invocation of other dangerous functions, besides rand().
    • +
    +
    +
    + + + + + + + + + + + +
    + [ + + MSDN + + ] + + " + + BCryptGenRandom() Function + + " +
    + [ + + OpenBSD + + ] + + + arc4random() + +
    +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/MSC30-C/RandUsedForGeneratingPseudorandomNumbers.qhelp b/c/cert/src/rules/MSC30-C/RandUsedForGeneratingPseudorandomNumbers.qhelp new file mode 100644 index 0000000000..fa84110011 --- /dev/null +++ b/c/cert/src/rules/MSC30-C/RandUsedForGeneratingPseudorandomNumbers.qhelp @@ -0,0 +1,18 @@ + + + + +

    This query implements the CERT-C rule MSC30-C:

    +
    +

    Do not use the rand() function for generating pseudorandom numbers

    +
    +
    + + +
  • + CERT-C: + MSC30-C: Do not use the rand() function for generating pseudorandom numbers + . +
  • +
    + \ No newline at end of file diff --git a/c/cert/src/rules/MSC30-C/RandUsedForGeneratingPseudorandomNumbers.ql b/c/cert/src/rules/MSC30-C/RandUsedForGeneratingPseudorandomNumbers.ql new file mode 100644 index 0000000000..5feb7d5f99 --- /dev/null +++ b/c/cert/src/rules/MSC30-C/RandUsedForGeneratingPseudorandomNumbers.ql @@ -0,0 +1,21 @@ +/** + * @id c/cert/rand-used-for-generating-pseudorandom-numbers + * @name MSC30-C: Do not use the rand() function for generating pseudorandom numbers + * @description rand() shall not be used to generate pseudorandom numbers. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/cert/id/msc30-c + * security + * external/cert/obligation/rule + */ + +import cpp +import codingstandards.c.cert +import codingstandards.cpp.rules.donotuserandforgeneratingpseudorandomnumbers.DoNotUseRandForGeneratingPseudorandomNumbers + +class RandUsedForGeneratingPseudorandomNumbersQuery extends DoNotUseRandForGeneratingPseudorandomNumbersSharedQuery { + RandUsedForGeneratingPseudorandomNumbersQuery() { + this = MiscPackage::randUsedForGeneratingPseudorandomNumbersQuery() + } +} diff --git a/c/cert/src/rules/MSC32-C/ProperlySeedPseudorandomNumberGenerators-standard.qhelp b/c/cert/src/rules/MSC32-C/ProperlySeedPseudorandomNumberGenerators-standard.qhelp new file mode 100644 index 0000000000..ee66852ba9 --- /dev/null +++ b/c/cert/src/rules/MSC32-C/ProperlySeedPseudorandomNumberGenerators-standard.qhelp @@ -0,0 +1,425 @@ + + +
    +

    A pseudorandom number generator (PRNG) is a deterministic algorithm capable of generating sequences of numbers that approximate the properties of random numbers. Each sequence is completely determined by the initial state of the PRNG and the algorithm for changing the state. Most PRNGs make it possible to set the initial state, also called the seed state. Setting the initial state is called seeding the PRNG.

    +

    Calling a PRNG in the same initial state, either without seeding it explicitly or by seeding it with the same value, results in generating the same sequence of random numbers in different runs of the program. Consider a PRNG function that is seeded with some initial seed value and is consecutively called to produce a sequence of random numbers, S. If the PRNG is subsequently seeded with the same initial seed value, then it will generate the same sequence S.

    +

    As a result, after the first run of an improperly seeded PRNG, an attacker can predict the sequence of random numbers that will be generated in the future runs. Improperly seeding or failing to seed the PRNG can lead to vulnerabilities, especially in security protocols.

    +

    The solution is to ensure that the PRNG is always properly seeded. A properly seeded PRNG will generate a different sequence of random numbers each time it is run.

    +

    Not all random number generators can be seeded. True random number generators that rely on hardware to produce completely unpredictable results do not need to be and cannot be seeded. Some high-quality PRNGs, such as the /dev/random device on some UNIX systems, also cannot be seeded. This rule applies only to algorithmic pseudorandom number generators that can be seeded.

    +
    +
    +

    This noncompliant code example generates a sequence of 10 pseudorandom numbers using the random() function. When random() is not seeded, it behaves like rand(), producing the same sequence of random numbers each time any program that uses it is run.

    + #include <stdio.h> +#include <stdlib.h> +  +void func(void) { + for (unsigned int i = 0; i < 10; ++i) { + /* Always generates the same sequence */ + printf("%ld, ", random()); + } +} +

    The output is as follows:

    + 1st run: 1804289383, 846930886, 1681692777, 1714636915, 1957747793, 424238335, 719885386, 1649760492, 596516649, + 1189641421, +2nd run: 1804289383, 846930886, 1681692777, 1714636915, 1957747793, 424238335, 719885386, 1649760492, 596516649, + 1189641421, +... +nth run: 1804289383, 846930886, 1681692777, 1714636915, 1957747793, 424238335, 719885386, 1649760492, 596516649, + 1189641421, +
    +
    +

    Call srandom() before invoking random() to seed the random sequence generated by random(). This compliant solution produces different random number sequences each time the function is called, depending on the resolution of the system clock:

    + #include <stdio.h> +#include <stdlib.h> +#include <time.h> +  +void func(void) { + struct timespec ts; + if (timespec_get(&ts, TIME_UTC) == 0) { + /* Handle error */ + } else { + srandom(ts.tv_nsec ^ ts.tv_sec); + for (unsigned int i = 0; i < 10; ++i) { + /* Generates different sequences at different runs */ +  printf("%ld, ", random()); + } + } +} + +

    The output is as follows:

    + 1st run: 198682410, 2076262355, 910374899, 428635843, 2084827500, 1558698420, 4459146, 733695321, 2044378618, 1649046624, +2nd run: 1127071427, 252907983, 1358798372, 2101446505, 1514711759, 229790273, 954268511, 1116446419, 368192457, + 1297948050, +3rd run: 2052868434, 1645663878, 731874735, 1624006793, 938447420, 1046134947, 1901136083, 418123888, 836428296, + 2017467418, +

    This may not be sufficiently random for concurrent execution, which may lead to correlated generated series in different threads. Depending on the application and the desired level of security, a programmer may choose alternative ways to seed PRNGs. In general, hardware is more capable than software of generating real random numbers (for example, by sampling the thermal noise of a diode).

    +
    +
    +

    The BCryptGenRandom() function does not run the risk of not being properly seeded because its arguments serve as seeders:

    + #include <stdio.h> +#include <Windows.h> +#include <Bcrypt.h> +#include <Ntstatus.h> +#include <Wincrypt.h> + +void func(void) { + BCRYPT_ALG_HANDLE hAlgorithm = NULL; + long rand_buf; + PUCHAR pbBuffer = (PUCHAR) &rand_buf; + ULONG cbBuffer = sizeof(rand_buf); + ULONG dwFlags = BCRYPT_USE_SYSTEM_PREFERRED_RNG; + NTSTATUS status; + for (unsigned int i = 0; i < 10; ++i) { + status = BCryptGenRandom(hAlgorithm, pbBuffer, cbBuffer, dwFlags); + if (status == STATUS_SUCCESS) { + printf("%ld, ", rand_buf); + } else { + /* Handle Error */ + } + } +} + +

    The output is as follows:

    + 1st run: -683378946, 1957231690, 1933176011, -1745403355, -883473417, 882992405, 169629816, 1824800038, 899851668, 1702784647, +2nd run: -58750553, -1921870721, -1973269161, 1512649964, -673518452, 234003619, -1622633366, 1312389688, -2125631172, 2067680022, +3rd run: -189899579, 1220698973, 752205360, -1826365616, 79310867, 1430950090, -283206168, -941773185, 129633665, 543448789, +
    +
    + + + + + + + + + + + + + + + + + + + +
    + Rule + + Severity + + Likelihood + + Remediation Cost + + Priority + + Level +
    + MSC32-C + + Medium + + Likely + + Low + + P18 + + L1 +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Tool + + Version + + Checker + + Description +
    + + Astrée + + + 20.10 + + + Supported, but no explicit checker +
    + + Axivion Bauhaus Suite + + + 7.2.0 + + CertC-MSC32 + +
    + + Helix QAC + + + 2022.1 + + C5031 + C++5036 + +
    + + Klocwork + + + 2022.1 + + CERT.MSC.SEED_RANDOM + +
    + + PC-lint Plus + + + 1.4 + + 2460, 2461, 2760 + + Fully supported +
    + + Polyspace Bug Finder + + + R2021a + + + CERT C: Rule MSC32-C + + + Checks for: + Deterministic random output from constant seedeterministic random output from constant seed, predictable random output from predictable seedredictable random output from predictable seed. + Rule fully covered. +
    + + Parasoft C/C++test + + + 2021.2 + + CERT_C-MSC32-d + + Properly seed pseudorandom number generators +
    + + PRQA QA-C + + + 9.7 + + 5031  + +
    +
    +
    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    +
    +
    +

    Key here (explains table format and definitions)

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Taxonomy + + Taxonomy item + + Relationship +
    + + CERT C Secure Coding Standard + + + + MSC30-C. Do not use the rand() function for generating pseudorandom numbers + + + Prior to 2018-01-12: CERT: Unspecified Relationship +
    + + CERT C + + + + MSC51-CPP. Ensure your random number generator is properly seeded + + + Prior to 2018-01-12: CERT: Unspecified Relationship +
    + + CWE 2.11 + + + + CWE-327 + + , Use of a Broken or Risky Cryptographic Algorithm + + 2017-05-16: CERT: Rule subset of CWE +
    + + CWE 2.11 + + + + CWE-330 + + , Use of Insufficiently Random Values + + 2017-06-28: CERT: Rule subset of CWE +
    + + CWE 2.11 + + + + CWE-331 + + , Insufficient Entropy + + 2017-06-28: CERT: Exact +
    +
    +
    +

    Key here for mapping notes

    +

    CWE-327 and MSC32-C

    +
      +
    • Intersection( MSC30-C, MSC32-C) = Ø
    • +
    +
      +
    • MSC32-C says to properly seed pseudorandom number generators. For example, if you call rand(), make sure to seed it properly by calling srand() first. So far, we haven’t found any calls to rand().
    • +
    +
      +
    • Failure to seed a PRNG causes it to produce reproducible (hence insecure) series of random numbers.
    • +
    +
      +
    • CWE-327 = Union( MSC32-C, list) where list =
    • +
    +
      +
    • Invocation of broken/risky crypto algorithms that are not properly seeded
    • +
    +

    CWE-330 and MSC32-C

    +

    Independent( MSC30-C, MSC32-C, CON33-C)

    +

    CWE-330 = Union( MSC30-C, MSC32-C, CON33-C, list) where list = other improper use or creation of random values. (EG the would qualify)

    +

    MSC30-C, MSC32-C and CON33-C are independent, they have no intersections. They each specify distinct errors regarding PRNGs.

    +
    +
    + + + + + + + +
    + [ + + MSDN + + ] + + " + + BCryptGenRandom() Function + + " +
    +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/MSC32-C/ProperlySeedPseudorandomNumberGenerators.qhelp b/c/cert/src/rules/MSC32-C/ProperlySeedPseudorandomNumberGenerators.qhelp new file mode 100644 index 0000000000..70be073e93 --- /dev/null +++ b/c/cert/src/rules/MSC32-C/ProperlySeedPseudorandomNumberGenerators.qhelp @@ -0,0 +1,18 @@ + + + + +

    This query implements the CERT-C rule MSC32-C:

    +
    +

    Properly seed pseudorandom number generators

    +
    +
    + + +
  • + CERT-C: + MSC32-C: Properly seed pseudorandom number generators + . +
  • +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/MSC32-C/ProperlySeedPseudorandomNumberGenerators.ql b/c/cert/src/rules/MSC32-C/ProperlySeedPseudorandomNumberGenerators.ql new file mode 100644 index 0000000000..b175dd5fa2 --- /dev/null +++ b/c/cert/src/rules/MSC32-C/ProperlySeedPseudorandomNumberGenerators.ql @@ -0,0 +1,44 @@ +/** + * @id c/cert/properly-seed-pseudorandom-number-generators + * @name MSC32-C: Properly seed pseudorandom number generators + * @description Improperly seeded random number generators can lead to insecure code. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/cert/id/msc32-c + * security + * external/cert/obligation/rule + */ + +import cpp +import codingstandards.c.cert + +/** Defines a class that models function calls to srandom() */ +class SRandomCall extends FunctionCall { + SRandomCall(){ + getTarget().hasGlobalOrStdName("srandom") + } + + /** Holds if the call is not obviously trivial. */ + predicate isTrivial(){ + getArgument(0) instanceof Literal + } +} + +from FunctionCall fc +where + not isExcluded(fc, MiscPackage::properlySeedPseudorandomNumberGeneratorsQuery()) and + + // find all calls to random() + fc.getTarget().hasGlobalOrStdName("random") and + + // where there isn't a call to srandom that comes before it that is + // non-trivial + not exists(SRandomCall sr | + // normally we would want to do this in reverse --- but srandom() is + // not pure and the order does not matter. + sr.getASuccessor*() = fc and not sr.isTrivial() + ) + + +select fc, "Call to `random()` without a valid call to `srandom()`." diff --git a/c/cert/src/rules/MSC37-C/ControlFlowReachesTheEndOfANonVoidFunction-standard.qhelp b/c/cert/src/rules/MSC37-C/ControlFlowReachesTheEndOfANonVoidFunction-standard.qhelp new file mode 100644 index 0000000000..08dadda262 --- /dev/null +++ b/c/cert/src/rules/MSC37-C/ControlFlowReachesTheEndOfANonVoidFunction-standard.qhelp @@ -0,0 +1,524 @@ + + +
    +

    If control reaches the closing curly brace (}) of a non-void function without evaluating a return statement, using the return value of the function call is undefined behavior. (See undefined behavior 88.)

    +
    +
    +

    In this noncompliant code example, control reaches the end of the checkpass() function when the two strings passed to strcmp() are not equal, resulting in undefined behavior. Many compilers will generate code for the checkpass() function, returning various values along the execution path where no return statement is defined.

    + #include <string.h> +#include <stdio.h> +  +int checkpass(const char *password) { + if (strcmp(password, "pass") == 0) { + return 1; + } +} + +void func(const char *userinput) { + if (checkpass(userinput)) { + printf("Success\n"); + } +} +

    This error is frequently diagnosed by compilers. (See MSC00-C. Compile cleanly at high warning levels.)

    +
    +
    +

    This compliant solution ensures that the checkpass() function always returns a value:

    + #include <string.h> +#include <stdio.h> +  +int checkpass(const char *password) { + if (strcmp(password, "pass") == 0) { + return 1; + } + return 0; +} + +void func(const char *userinput) { + if (checkpass(userinput)) { + printf("Success!\n"); + } +} +
    +
    +

    In this noncompliant code example, control reaches the end of the getlen() function when input does not contain the integer delim. Because the potentially undefined return value of getlen() is later used as an index into an array, a buffer overflow may occur.

    + #include <stddef.h> +  +size_t getlen(const int *input, size_t maxlen, int delim) { + for (size_t i = 0; i < maxlen; ++i) { + if (input[i] == delim) { + return i; + } + } +} +  +void func(int userdata) { + size_t i; + int data[] = { 1, 1, 1 }; + i = getlen(data, sizeof(data), 0); + data[i] = userdata; +} +

    Implementation Details (GCC)

    +

    Violating this rule can have unexpected consequences, as in the following example:

    + #include <stdio.h> + +size_t getlen(const int *input, size_t maxlen, int delim) { + for (size_t i = 0; i < maxlen; ++i) { + if (input[i] == delim) { + return i; + } + } +} + +int main(int argc, char **argv) { + size_t i; + int data[] = { 1, 1, 1 }; + + i = getlen(data, sizeof(data), 0); + printf("Returned: %zu\n", i); + data[i] = 0; + + return 0; +} +

    When this program is compiled with -Wall on most versions of the GCC compiler, the following warning is generated:

    + example.c: In function 'getlen': +example.c:12: warning: control reaches end of non-void function + +

    None of the inputs to the function equal the delimiter, so when run with GCC 5.3 on Linux, control reaches the end of the getlen() function, which is undefined behavior and in this test returns 3, causing an out-of-bounds write to the data array.

    +
    +
    +

    This compliant solution changes the interface of getlen() to store the result in a user-provided pointer and returns a status indicator to report success or failure. The best method for handling this type of error is specific to the application and the type of error. (See ERR00-C. Adopt and implement a consistent and comprehensive error-handling policy for more on error handling.)

    + #include <stddef.h> +  +int getlen(const int *input, size_t maxlen, int delim, +  size_t *result) { + if (result == NULL) { + return -1; + } + for (size_t i = 0; i < maxlen; ++i) { + if (input[i] == delim) { + *result = i; + return 0; + } + } + return -1; +} + +void func(int userdata) { + size_t i; + int data[] = {1, 1, 1}; + if (getlen(data, sizeof(data), 0, &i) != 0) { + /* Handle error */ + } else { + data[i] = userdata; + } +} + +
    +
    +

    MSC37-C-EX1: According to the C Standard, 5.1.2.2.3, paragraph 1 [ISO/IEC 9899:2011], "Reaching the } that terminates the main function returns a value of 0." As a result, it is permissible for control to reach the end of the main() function without executing a return statement.

    +

    MSC37-C-EX2: It is permissible for a control path to not return a value if that code path is never taken and a function marked _Noreturn is called as part of that code path. For example:

    + #include <stdio.h> +#include <stdlib.h> + +_Noreturn void unreachable(const char *msg) { + printf("Unreachable code reached: %s\n", msg); + exit(1); +} + +enum E { + One, + Two, + Three +}; + +int f(enum E e) { + switch (e) { + case One: return 1; + case Two: return 2; + case Three: return 3; + } + unreachable("Can never get here"); +} +
    +
    +

    Using the return value from a non-void function where control reaches the end of the function without evaluating a return statement can lead to buffer overflow vulnerabilities as well as other unexpected program behaviors.

    + + + + + + + + + + + + + + + + + + + +
    + Rule + + Severity + + Likelihood + + Remediation Cost + + Priority + + Level +
    + MSC37-C + + High + + Unlikely + + Low + + P9 + + L2 +
    +
    +
    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Tool + + Version + + Checker + + Description +
    + + Astrée + + + 20.10 + + return-implicit + + Fully checked +
    + + Axivion Bauhaus Suite + + + 7.2.0 + + CertC-MSC37 + +
    + + CodeSonar + + + 6.2p0 + + LANG.STRUCT.MRS + + Missing return statement +
    + + Coverity + + + 2017.07 + + MISSING_RETURN + + Implemented +
    + + Helix QAC + + + 2022.1 + + C2888 + C++2888, C++4022 + +
    + + Klocwork + + + 2022.1 + + FUNCRET.GEN + FUNCRET.IMPLICIT + +
    + + LDRA tool suite + + + 9.7.1 + + 2 D, 36 S, 66 S + + Fully implemented +
    + + Parasoft C/C++test + + + 2021.2 + + CERT_C-MSC37-a + + All exit paths from a function with non-void return type shall have an explicit return statement with an expression +
    + + PC-lint Plus + + + 1.4 + + 533 + + Fully supported +
    + + Polyspace Bug Finder + + + R2021a + + + CERT C: Rule MSC37-C + + + Checks for missing return statement (rule fully covered) +
    + + PRQA QA-C + + + 9.7 + + 2888 + +
    + + PRQA QA-C++ + + + 4.4 + + 2888, 4022  + +
    + + RuleChecker + + + 20.10 + + return-implicit + + Fully checked +
    + + SonarQube C/C++ Plugin + + + 3.11 + + S935 + +
    + + TrustInSoft Analyzer + + + 1.38 + + Body of function falls-through + + Exhaustively verified. +
    +
    +
    +

    Key here (explains table format and definitions)

    + + + + + + + + + + + + + + + + + + +
    + Taxonomy + + Taxonomy item + + Relationship +
    + + CERT C Secure Coding Standard + + + + MSC01-C. Strive for logical completeness + + + Prior to 2018-01-12: CERT: Unspecified Relationship +
    + + CWE 2.11 + + + + CWE-758 + + + 2017-07-07: CERT: Rule subset of CWE +
    +
    +
    +

    Key here for mapping notes

    +

    CWE-758 and MSC37-C

    +

    Independent( INT34-C, INT36-C, MEM30-C, MSC37-C, FLP32-C, EXP33-C, EXP30-C, ERR34-C, ARR32-C)

    +

    CWE-758 = Union( MSC37-C, list) where list =

    +

    Undefined behavior that results from anything other than failing to return a value from a function that expects one

    +
    +
    + + + + + + + +
    + [ + + ISO/IEC 9899:2011 + + ] + + 5.1.2.2.3, "Program Termination" +
    +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/MSC37-C/ControlFlowReachesTheEndOfANonVoidFunction.qhelp b/c/cert/src/rules/MSC37-C/ControlFlowReachesTheEndOfANonVoidFunction.qhelp new file mode 100644 index 0000000000..28a45a9317 --- /dev/null +++ b/c/cert/src/rules/MSC37-C/ControlFlowReachesTheEndOfANonVoidFunction.qhelp @@ -0,0 +1,18 @@ + + + + +

    This query implements the CERT-C rule MSC37-C:

    +
    +

    Ensure that control never reaches the end of a non-void function

    +
    +
    + + +
  • + CERT-C: + MSC37-C: Ensure that control never reaches the end of a non-void function + . +
  • +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/MSC37-C/ControlFlowReachesTheEndOfANonVoidFunction.ql b/c/cert/src/rules/MSC37-C/ControlFlowReachesTheEndOfANonVoidFunction.ql new file mode 100644 index 0000000000..2f141417bf --- /dev/null +++ b/c/cert/src/rules/MSC37-C/ControlFlowReachesTheEndOfANonVoidFunction.ql @@ -0,0 +1,22 @@ +/** + * @id c/cert/control-flow-reaches-the-end-of-a-non-void-function + * @name MSC37-C: Ensure that control never reaches the end of a non-void function + * @description Non-void functions that end without an explicit return can produce unpredictable + * results. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/cert/id/msc37-c + * correctness + * external/cert/obligation/rule + */ + +import cpp +import codingstandards.c.cert +import codingstandards.cpp.rules.nonvoidfunctiondoesnotreturn.NonVoidFunctionDoesNotReturn + +class ControlFlowReachesTheEndOfANonVoidFunctionQuery extends NonVoidFunctionDoesNotReturnSharedQuery { + ControlFlowReachesTheEndOfANonVoidFunctionQuery() { + this = MiscPackage::controlFlowReachesTheEndOfANonVoidFunctionQuery() + } +} diff --git a/c/cert/src/rules/STR30-C/DoNotAttemptToModifyStringLiterals-standard.qhelp b/c/cert/src/rules/STR30-C/DoNotAttemptToModifyStringLiterals-standard.qhelp new file mode 100644 index 0000000000..458fbe3f7d --- /dev/null +++ b/c/cert/src/rules/STR30-C/DoNotAttemptToModifyStringLiterals-standard.qhelp @@ -0,0 +1,33 @@ + + +
    +
      +
    • required
    • +
    • implementation
    • +
    • automated
    • +
    +
    + +
    +

    + ... +

    + +
    + +
    +

    + ... +

    +
    + + + + + +
    +
      +
    • ...
    • +
    +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/STR30-C/DoNotAttemptToModifyStringLiterals.qhelp b/c/cert/src/rules/STR30-C/DoNotAttemptToModifyStringLiterals.qhelp new file mode 100644 index 0000000000..9d78ccdf9d --- /dev/null +++ b/c/cert/src/rules/STR30-C/DoNotAttemptToModifyStringLiterals.qhelp @@ -0,0 +1,18 @@ + + + + +

    This query implements the CERT-C rule STR30-C:

    +
    +

    Do not attempt to modify string literals

    +
    +
    + + +
  • + CERT-C: + STR30-C: Do not attempt to modify string literals + . +
  • +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/STR30-C/DoNotAttemptToModifyStringLiterals.ql b/c/cert/src/rules/STR30-C/DoNotAttemptToModifyStringLiterals.ql new file mode 100644 index 0000000000..b26cc1a040 --- /dev/null +++ b/c/cert/src/rules/STR30-C/DoNotAttemptToModifyStringLiterals.ql @@ -0,0 +1,154 @@ +/** + * @id c/cert/do-not-attempt-to-modify-string-literals + * @name STR30-C: Do not attempt to modify string literals + * @description Modifying a string literal can produce unexpected effects. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/cert/id/str30-c + * correctness + * security + * external/cert/obligation/rule + */ + +import cpp +import codingstandards.c.cert +import semmle.code.cpp.security.BufferWrite +import semmle.code.cpp.dataflow.DataFlow + +/** + * Class that includes into `BufferWrite` functions that will modify their + * first argument. This is an extension of `BufferWrite` which covers the case + * of opaque writes via library functions. + */ +class ModifiesFirstArgFunction extends BufferWrite, FunctionCall { + Expr modifiedExpr; + + ModifiesFirstArgFunction() { + getTarget().getName() = ["mkstemp", "memset", "memcpy", "memmove"] and + getArgument(0) = modifiedExpr + } + + override Type getBufferType() { none() } + + override Expr getDest() { result = modifiedExpr } +} + +/** + * Models a dataflow wherein a source is either a implicit or explicit string + * 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) { + // usage through variables + exists(Variable v | + v.getAnAssignedValue() = node.asExpr() and + ( + node.asExpr() instanceof ImplicitStringLiteral or + node.asExpr() instanceof StringLiteralOrConstChar + ) and + v.getType().getUnderlyingType() instanceof CharPointerType + ) + or + // direct usage of string literals as function parameters + exists(BufferWrite bw | + bw.getDest() = node.asExpr() and + ( + node.asExpr() instanceof ImplicitStringLiteral or + node.asExpr() instanceof StringLiteralOrConstChar + ) + ) + } + + override 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()) + or + // or it is a direct assignment of some kind - including reassignment of the pointer + exists(AssignExpr aexp | aexp.getLValue().(ArrayExpr).getArrayBase() = node.asExpr()) + or + exists(AssignExpr aexp | aexp.getLValue().(PointerDereferenceExpr).getOperand() = node.asExpr()) + } +} + +class MaybeReturnsStringLiteralFunctionCall extends FunctionCall { + MaybeReturnsStringLiteralFunctionCall() { + getTarget().getName() in [ + "strpbrk", "strchr", "strrchr", "strstr", "wcspbrk", "wcschr", "wcsrchr", "wcsstr", + "memchr", "wmemchr" + ] + } +} + +class ImplicitStringLiteral extends Expr { + ImplicitStringLiteral() { + exists(MaybeReturnsStringLiteralFunctionCall fc, Variable e | + e.getAnAssignedValue() = fc and + this = fc and + // additionally, we require that the first argument is either an explicit + // or implicit string literal + ( + // directly a string literal + fc.getArgument(0) instanceof StringLiteralOrConstChar + or + // a string literal flows into it + exists(StringLiteralOrConstChar sl | + DataFlow::localFlow(DataFlow::exprNode(sl), DataFlow::exprNode(fc.getArgument(0))) + ) + or + // or a base flows into it + exists(ImplicitStringLiteralBase base | + DataFlow::localFlow(DataFlow::exprNode(base), DataFlow::exprNode(fc.getArgument(0))) + ) + ) + ) + } +} + +class StringLiteralOrConstChar extends Expr { + StringLiteralOrConstChar() { + this instanceof StringLiteral + or + getUnspecifiedType() instanceof CharPointerType and + getType().(PointerType).getBaseType().isConst() + } +} + +/** + * Since it is possible to produce an implicit literal by either + * an explicit literal being passed to one of these functions this + * class exists to establish the "base" type, that is an explicit + * string literal passed or flowing into the first argument. The other + * Implicit string literal class will then check to see if it is inductively + * an implicit string literal. + */ +class ImplicitStringLiteralBase extends Expr { + ImplicitStringLiteralBase() { + exists(MaybeReturnsStringLiteralFunctionCall fc, Variable e | + e.getAnAssignedValue() = fc and + this = fc and + // it either directly gets a string literal or one via flow + ( + fc.getArgument(0) instanceof StringLiteralOrConstChar or + exists(StringLiteralOrConstChar sl | + DataFlow::localFlow(DataFlow::exprNode(sl), DataFlow::exprNode(fc.getArgument(0))) + ) + ) + ) + } +} + +from Expr literal, Expr literalWrite, ImplicitOrExplicitStringLiteralModifiedConfiguration config +where + not isExcluded(literal, Strings1Package::doNotAttemptToModifyStringLiteralsQuery()) and + not isExcluded(literalWrite, Strings1Package::doNotAttemptToModifyStringLiteralsQuery()) and + config.hasFlow(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/cert/src/rules/STR30-C/standard-example.c b/c/cert/src/rules/STR30-C/standard-example.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/cert/src/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator-standard.qhelp b/c/cert/src/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator-standard.qhelp new file mode 100644 index 0000000000..458fbe3f7d --- /dev/null +++ b/c/cert/src/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator-standard.qhelp @@ -0,0 +1,33 @@ + + +
    +
      +
    • required
    • +
    • implementation
    • +
    • automated
    • +
    +
    + +
    +

    + ... +

    + +
    + +
    +

    + ... +

    +
    + + + + + +
    +
      +
    • ...
    • +
    +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.qhelp b/c/cert/src/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.qhelp new file mode 100644 index 0000000000..4cd91b96b8 --- /dev/null +++ b/c/cert/src/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.qhelp @@ -0,0 +1,18 @@ + + + + +

    This query implements the CERT-C rule STR31-C:

    +
    +

    Guarantee that storage for strings has sufficient space for character data and the null terminator

    +
    +
    + + +
  • + CERT-C: + STR31-C: Guarantee that storage for strings has sufficient space for character data and the null terminator + . +
  • +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.ql b/c/cert/src/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.ql new file mode 100644 index 0000000000..24e55f80d3 --- /dev/null +++ b/c/cert/src/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.ql @@ -0,0 +1,67 @@ +/** + * @id c/cert/strings-has-sufficient-space-for-the-null-terminator + * @name STR31-C: Guarantee that storage for strings has sufficient space for character data and the null terminator + * @description Many library functions in the C standard library assume C strings are null + * terminated and failing to null terminate strings may lead to unpredictable program + * behavior. + * @kind problem + * @precision medium + * @problem.severity error + * @tags external/cert/id/str31-c + * correctness + * security + * external/cert/obligation/rule + */ + +import cpp +import codingstandards.c.cert +import semmle.code.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.internal.TaintTrackingUtil +import codingstandards.cpp.PossiblyUnsafeStringOperation + +/** + * Models a class of function calls that are unsafe. + */ +class PossiblyUnsafeStringFunctionCall extends FunctionCall { + PossiblyUnsafeStringFunctionCall() { getTarget().getName() = ["gets", "getchar"] } +} + +/** + * Models a family of expression that produce results that are + * potentially unbounded. + */ +class PossiblyUnboundedExpr extends Expr { + PossiblyUnboundedExpr() { + // argv + exists(Function f | + f.hasName("main") and + this = f.getParameter(1).getAnAccess() + ) + or + // getenv + exists(FunctionCall fc | + fc.getTarget().hasName("getenv") and + this = fc + ) + } +} + +from Expr e +where + not isExcluded(e, Strings1Package::stringsHasSufficientSpaceForTheNullTerminatorQuery()) and + e instanceof PossiblyUnsafeStringOperation + or + e instanceof PossiblyUnsafeStringFunctionCall + or + exists(CharArrayInitializedWithStringLiteral cl | + cl.getContainerLength() <= cl.getStringLiteralLength() and + TaintTracking::localTaint(DataFlow::exprNode(cl), DataFlow::exprNode(e)) + ) + or + e instanceof PossiblyUnboundedExpr and + exists(FunctionCall fc | + fc.getTarget() instanceof StandardCStringFunction and + TaintTracking::localTaint(DataFlow::exprNode(e), DataFlow::exprNode(fc.getAnArgument())) + ) +select e, + "Expression produces or consumes a string that may not have sufficient space for a null-terminator." diff --git a/c/cert/src/rules/STR31-C/standard-example.c b/c/cert/src/rules/STR31-C/standard-example.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/cert/src/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString-standard.qhelp b/c/cert/src/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString-standard.qhelp new file mode 100644 index 0000000000..458fbe3f7d --- /dev/null +++ b/c/cert/src/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString-standard.qhelp @@ -0,0 +1,33 @@ + + +
    +
      +
    • required
    • +
    • implementation
    • +
    • automated
    • +
    +
    + +
    +

    + ... +

    + +
    + +
    +

    + ... +

    +
    + + + + + +
    +
      +
    • ...
    • +
    +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.qhelp b/c/cert/src/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.qhelp new file mode 100644 index 0000000000..c1f38a0a52 --- /dev/null +++ b/c/cert/src/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.qhelp @@ -0,0 +1,18 @@ + + + + +

    This query implements the CERT-C rule STR32-C:

    +
    +

    Do not pass a non-null-terminated character sequence to a library function that expects a string

    +
    +
    + + +
  • + CERT-C: + STR32-C: Do not pass a non-null-terminated character sequence to a library function that expects a string + . +
  • +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.ql b/c/cert/src/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.ql new file mode 100644 index 0000000000..a65e7958be --- /dev/null +++ b/c/cert/src/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.ql @@ -0,0 +1,75 @@ +/** + * @id c/cert/non-null-terminated-to-function-that-expects-a-string + * @name STR32-C: Do not pass a non-null-terminated character sequence to a library function that expects a string + * @description Passing a string that is not null-terminated can lead to unpredictable program + * behavior. + * @kind problem + * @precision medium + * @problem.severity error + * @tags external/cert/id/str32-c + * correctness + * security + * external/cert/obligation/rule + */ + +import cpp +import codingstandards.c.cert +import codingstandards.cpp.Naming +import semmle.code.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.internal.TaintTrackingUtil +import codingstandards.cpp.PossiblyUnsafeStringOperation + +/** + * Models a function that is part of the standard library that expects a + * null-terminated string as an argument. Note that most standard library + * functions expect this; as a simplifying assumption we assume that a flow + * into these functions implies such a usage. + */ +class ExpectsNullTerminatedStringAsArgumentFunctionCall extends FunctionCall { + Expr e; + + ExpectsNullTerminatedStringAsArgumentFunctionCall() { + Naming::Cpp14::hasStandardLibraryFunctionName(getTarget().getName()) and + exists(Type t | + e = getAnArgument() and + t = getTarget().getAParameter().getType().(DerivedType).getBaseType*() and + (t instanceof CharType or t instanceof Wchar_t) + ) + } + + /** + * This predicate will produce a result equal to any argument of a function + * that expects null-terminated strings. + */ + Expr getAnExpectingExpr() { result = e } +} + +from ExpectsNullTerminatedStringAsArgumentFunctionCall fc, Expr e, Expr target +where + target = fc.getAnExpectingExpr() and + not isExcluded(fc, Strings1Package::nonNullTerminatedToFunctionThatExpectsAStringQuery()) and + ( + exists(PossiblyUnsafeStringOperation op | + // don't report violations of the same function call. + not op = fc and + e = op and + TaintTracking::localTaint(DataFlow::exprNode(op.getAnArgument()), DataFlow::exprNode(target)) + ) + or + exists(CharArrayInitializedWithStringLiteral op | + e = op and + op.getContainerLength() <= op.getStringLiteralLength() and + TaintTracking::localTaint(DataFlow::exprNode(op), DataFlow::exprNode(target)) + ) + ) and + // don't report cases flowing to this node where there is a flow from a + // literal assignment of a null terminator + not exists(AssignExpr aexp | + aexp.getLValue() instanceof ArrayExpr and + aexp.getRValue() instanceof Zero and + TaintTracking::localTaint(DataFlow::exprNode(aexp.getRValue()), DataFlow::exprNode(target)) and + // this must be AFTER the operation causing the non-null termination to be valid. + aexp.getAPredecessor*() = e + ) +select fc, "String modified by $@ is passed to function expecting a null-terminated string.", e, + "this expression" diff --git a/c/cert/src/rules/STR32-C/standard-example.c b/c/cert/src/rules/STR32-C/standard-example.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/cert/test/qlpack.yml b/c/cert/test/qlpack.yml index 2ff75c7471..dfe16b190e 100644 --- a/c/cert/test/qlpack.yml +++ b/c/cert/test/qlpack.yml @@ -1,4 +1,4 @@ name: cert-c-coding-standards-tests -version: 2.1.0 +version: 2.3.0 libraryPathDependencies: cert-c-coding-standards extractor: cpp \ No newline at end of file diff --git a/c/cert/test/rules/FIO38-C/DoNotCopyAFileObject.expected b/c/cert/test/rules/FIO38-C/DoNotCopyAFileObject.expected index 50449f4a2f..f131146842 100644 --- a/c/cert/test/rules/FIO38-C/DoNotCopyAFileObject.expected +++ b/c/cert/test/rules/FIO38-C/DoNotCopyAFileObject.expected @@ -1,5 +1,5 @@ -| test.c:4:20:4:26 | * ... | A FILE object is being copied. | -| test.c:11:21:11:30 | * ... | A FILE object is being copied. | -| test.c:17:21:17:31 | * ... | A FILE object is being copied. | -| test.c:23:15:23:21 | * ... | A FILE object is being copied. | -| test.c:36:19:36:28 | * ... | A FILE object is being copied. | +| test.c:10:20:10:26 | * ... | A FILE object is being copied. | +| test.c:17:21:17:30 | * ... | A FILE object is being copied. | +| test.c:23:21:23:31 | * ... | A FILE object is being copied. | +| test.c:29:15:29:21 | * ... | A FILE object is being copied. | +| test.c:42:19:42:28 | * ... | A FILE object is being copied. | \ No newline at end of file diff --git a/c/cert/test/rules/FIO38-C/test.c b/c/cert/test/rules/FIO38-C/test.c index f1b3f616ca..0f0eb111ac 100644 --- a/c/cert/test/rules/FIO38-C/test.c +++ b/c/cert/test/rules/FIO38-C/test.c @@ -1,4 +1,10 @@ #include +#if !defined(__DEFINED_struct__IO_FILE) +struct _IO_FILE { + char __x; +}; +#define __DEFINED_struct__IO_FILE +#endif int f1(void) { FILE my_stdout = *stdout; // NON_COMPLIANT diff --git a/c/cert/test/rules/MSC30-C/RandUsedForGeneratingPseudorandomNumbers.testref b/c/cert/test/rules/MSC30-C/RandUsedForGeneratingPseudorandomNumbers.testref new file mode 100644 index 0000000000..31cba60b74 --- /dev/null +++ b/c/cert/test/rules/MSC30-C/RandUsedForGeneratingPseudorandomNumbers.testref @@ -0,0 +1 @@ +cpp/common/test/rules/donotuserandforgeneratingpseudorandomnumbers/DoNotUseRandForGeneratingPseudorandomNumbers.ql \ No newline at end of file diff --git a/c/cert/test/rules/MSC32-C/ProperlySeedPseudorandomNumberGenerators.expected b/c/cert/test/rules/MSC32-C/ProperlySeedPseudorandomNumberGenerators.expected new file mode 100644 index 0000000000..f905fb4559 --- /dev/null +++ b/c/cert/test/rules/MSC32-C/ProperlySeedPseudorandomNumberGenerators.expected @@ -0,0 +1,3 @@ +| test.c:6:19:6:24 | call to random | Call to `random()` without a valid call to `srandom()`. | +| test.c:18:19:18:24 | call to random | Call to `random()` without a valid call to `srandom()`. | +| test.c:25:19:25:24 | call to random | Call to `random()` without a valid call to `srandom()`. | diff --git a/c/cert/test/rules/MSC32-C/ProperlySeedPseudorandomNumberGenerators.qlref b/c/cert/test/rules/MSC32-C/ProperlySeedPseudorandomNumberGenerators.qlref new file mode 100644 index 0000000000..c00a554d47 --- /dev/null +++ b/c/cert/test/rules/MSC32-C/ProperlySeedPseudorandomNumberGenerators.qlref @@ -0,0 +1 @@ +rules/MSC32-C/ProperlySeedPseudorandomNumberGenerators.ql \ No newline at end of file diff --git a/c/cert/test/rules/MSC32-C/test.c b/c/cert/test/rules/MSC32-C/test.c new file mode 100644 index 0000000000..c147bc1e96 --- /dev/null +++ b/c/cert/test/rules/MSC32-C/test.c @@ -0,0 +1,26 @@ +#include +#include +#include + +void f1(void) { + printf("%ld, ", random()); // NON_COMPLIANT +} + +void f2(void) { + struct timespec ts; + timespec_get(&ts, TIME_UTC); + srandom(ts.tv_nsec ^ ts.tv_sec); + printf("%ld, ", random()); // COMPLIANT +} + +void f3(void) { + srandom(1); + printf("%ld, ", random()); // NON_COMPLIANT +} + +#define SEED 100 + +void f4(void) { + srandom(SEED); + printf("%ld, ", random()); // NON_COMPLIANT +} \ No newline at end of file diff --git a/c/cert/test/rules/MSC37-C/ControlFlowReachesTheEndOfANonVoidFunction.testref b/c/cert/test/rules/MSC37-C/ControlFlowReachesTheEndOfANonVoidFunction.testref new file mode 100644 index 0000000000..6ddd134ce3 --- /dev/null +++ b/c/cert/test/rules/MSC37-C/ControlFlowReachesTheEndOfANonVoidFunction.testref @@ -0,0 +1 @@ +c/common/test/rules/nonvoidfunctiondoesnotreturn/NonVoidFunctionDoesNotReturn.ql \ No newline at end of file diff --git a/c/cert/test/rules/STR30-C/DoNotAttemptToModifyStringLiterals.expected b/c/cert/test/rules/STR30-C/DoNotAttemptToModifyStringLiterals.expected new file mode 100644 index 0000000000..27ef66bc7a --- /dev/null +++ b/c/cert/test/rules/STR30-C/DoNotAttemptToModifyStringLiterals.expected @@ -0,0 +1,53 @@ +| test.c:7:3:7:3 | a | This operation may write to a string that may be a string literal that was $@. | test.c:6:13:6:20 | codeql | created here | +| test.c:30:3:30:3 | a | This operation may write to a string that may be a string literal that was $@. | test.c:29:13:29:18 | call to strchr | created here | +| test.c:36:3:36:3 | b | This operation may write to a string that may be a string literal that was $@. | test.c:35:13:35:18 | call to strchr | created here | +| test.c:58:3:58:3 | b | This operation may write to a string that may be a string literal that was $@. | test.c:56:13:56:18 | call to strchr | created here | +| test.c:65:6:65:6 | b | This operation may write to a string that may be a string literal that was $@. | test.c:63:7:63:13 | call to strrchr | created here | +| test.c:87:13:87:20 | codeql | This operation may write to a string that may be a string literal that was $@. | test.c:87:13:87:20 | codeql | created here | +| test.c:88:12:88:19 | codeql | This operation may write to a string that may be a string literal that was $@. | test.c:88:12:88:19 | codeql | created here | +| test.c:89:12:89:19 | codeql | This operation may write to a string that may be a string literal that was $@. | test.c:89:12:89:19 | codeql | created here | +| test.c:90:13:90:20 | codeql | This operation may write to a string that may be a string literal that was $@. | test.c:90:13:90:20 | codeql | created here | +| test.c:91:12:91:19 | codeql | This operation may write to a string that may be a string literal that was $@. | test.c:91:12:91:19 | codeql | created here | +| test.c:92:13:92:20 | codeql | This operation may write to a string that may be a string literal that was $@. | test.c:92:13:92:20 | codeql | created here | +| test.c:93:12:93:19 | codeql | This operation may write to a string that may be a string literal that was $@. | test.c:93:12:93:19 | codeql | created here | +| test.c:94:13:94:20 | codeql | This operation may write to a string that may be a string literal that was $@. | test.c:94:13:94:20 | codeql | created here | +| test.c:100:13:100:13 | a | This operation may write to a string that may be a string literal that was $@. | test.c:99:15:99:22 | codeql | created here | +| test.c:101:12:101:12 | a | This operation may write to a string that may be a string literal that was $@. | test.c:99:15:99:22 | codeql | created here | +| test.c:102:12:102:12 | a | This operation may write to a string that may be a string literal that was $@. | test.c:99:15:99:22 | codeql | created here | +| test.c:103:13:103:13 | a | This operation may write to a string that may be a string literal that was $@. | test.c:99:15:99:22 | codeql | created here | +| test.c:104:12:104:12 | a | This operation may write to a string that may be a string literal that was $@. | test.c:99:15:99:22 | codeql | created here | +| test.c:105:13:105:13 | a | This operation may write to a string that may be a string literal that was $@. | test.c:99:15:99:22 | codeql | created here | +| test.c:106:12:106:12 | a | This operation may write to a string that may be a string literal that was $@. | test.c:99:15:99:22 | codeql | created here | +| test.c:107:13:107:13 | a | This operation may write to a string that may be a string literal that was $@. | test.c:99:15:99:22 | codeql | created here | +| test.c:113:13:113:13 | a | This operation may write to a string that may be a string literal that was $@. | test.c:112:15:112:20 | call to strchr | created here | +| test.c:114:12:114:12 | a | This operation may write to a string that may be a string literal that was $@. | test.c:112:15:112:20 | call to strchr | created here | +| test.c:115:12:115:12 | a | This operation may write to a string that may be a string literal that was $@. | test.c:112:15:112:20 | call to strchr | created here | +| test.c:116:13:116:13 | a | This operation may write to a string that may be a string literal that was $@. | test.c:112:15:112:20 | call to strchr | created here | +| test.c:117:12:117:12 | a | This operation may write to a string that may be a string literal that was $@. | test.c:112:15:112:20 | call to strchr | created here | +| test.c:118:13:118:13 | a | This operation may write to a string that may be a string literal that was $@. | test.c:112:15:112:20 | call to strchr | created here | +| test.c:119:12:119:12 | a | This operation may write to a string that may be a string literal that was $@. | test.c:112:15:112:20 | call to strchr | created here | +| test.c:120:13:120:13 | a | This operation may write to a string that may be a string literal that was $@. | test.c:112:15:112:20 | call to strchr | created here | +| test.c:125:13:125:14 | aa | This operation may write to a string that may be a string literal that was $@. | test.c:125:13:125:14 | aa | created here | +| test.c:126:12:126:13 | aa | This operation may write to a string that may be a string literal that was $@. | test.c:126:12:126:13 | aa | created here | +| test.c:127:12:127:13 | aa | This operation may write to a string that may be a string literal that was $@. | test.c:127:12:127:13 | aa | created here | +| test.c:128:13:128:14 | aa | This operation may write to a string that may be a string literal that was $@. | test.c:128:13:128:14 | aa | created here | +| test.c:129:12:129:13 | aa | This operation may write to a string that may be a string literal that was $@. | test.c:129:12:129:13 | aa | created here | +| test.c:130:13:130:14 | aa | This operation may write to a string that may be a string literal that was $@. | test.c:130:13:130:14 | aa | created here | +| test.c:131:12:131:13 | aa | This operation may write to a string that may be a string literal that was $@. | test.c:131:12:131:13 | aa | created here | +| test.c:132:13:132:14 | aa | This operation may write to a string that may be a string literal that was $@. | test.c:132:13:132:14 | aa | created here | +| test.c:137:11:137:11 | a | This operation may write to a string that may be a string literal that was $@. | test.c:148:13:148:20 | codeql | created here | +| test.c:138:10:138:10 | a | This operation may write to a string that may be a string literal that was $@. | test.c:148:13:148:20 | codeql | created here | +| test.c:139:10:139:10 | a | This operation may write to a string that may be a string literal that was $@. | test.c:148:13:148:20 | codeql | created here | +| test.c:140:11:140:11 | a | This operation may write to a string that may be a string literal that was $@. | test.c:148:13:148:20 | codeql | created here | +| test.c:141:10:141:10 | a | This operation may write to a string that may be a string literal that was $@. | test.c:148:13:148:20 | codeql | created here | +| test.c:142:11:142:11 | a | This operation may write to a string that may be a string literal that was $@. | test.c:148:13:148:20 | codeql | created here | +| test.c:143:10:143:10 | a | This operation may write to a string that may be a string literal that was $@. | test.c:148:13:148:20 | codeql | created here | +| test.c:144:11:144:11 | a | This operation may write to a string that may be a string literal that was $@. | test.c:148:13:148:20 | codeql | created here | +| test.c:154:11:154:11 | a | This operation may write to a string that may be a string literal that was $@. | test.c:165:13:165:18 | call to strchr | created here | +| test.c:155:10:155:10 | a | This operation may write to a string that may be a string literal that was $@. | test.c:165:13:165:18 | call to strchr | created here | +| test.c:156:10:156:10 | a | This operation may write to a string that may be a string literal that was $@. | test.c:165:13:165:18 | call to strchr | created here | +| test.c:157:11:157:11 | a | This operation may write to a string that may be a string literal that was $@. | test.c:165:13:165:18 | call to strchr | created here | +| test.c:158:10:158:10 | a | This operation may write to a string that may be a string literal that was $@. | test.c:165:13:165:18 | call to strchr | created here | +| test.c:159:11:159:11 | a | This operation may write to a string that may be a string literal that was $@. | test.c:165:13:165:18 | call to strchr | created here | +| test.c:160:10:160:10 | a | This operation may write to a string that may be a string literal that was $@. | test.c:165:13:165:18 | call to strchr | created here | +| test.c:161:11:161:11 | a | This operation may write to a string that may be a string literal that was $@. | test.c:165:13:165:18 | call to strchr | created here | diff --git a/c/cert/test/rules/STR30-C/DoNotAttemptToModifyStringLiterals.qlref b/c/cert/test/rules/STR30-C/DoNotAttemptToModifyStringLiterals.qlref new file mode 100644 index 0000000000..e780711b64 --- /dev/null +++ b/c/cert/test/rules/STR30-C/DoNotAttemptToModifyStringLiterals.qlref @@ -0,0 +1 @@ +rules/STR30-C/DoNotAttemptToModifyStringLiterals.ql \ No newline at end of file diff --git a/c/cert/test/rules/STR30-C/test.c b/c/cert/test/rules/STR30-C/test.c new file mode 100644 index 0000000000..8c30592058 --- /dev/null +++ b/c/cert/test/rules/STR30-C/test.c @@ -0,0 +1,184 @@ +#include +#include + +// explicit string literals +void f1_explicit() { + char *a = "codeql"; + a[0] = 'a'; // NON_COMPLIANT +} + +void f2_explicit() { + char a[] = "codeql"; + a[0] = 'a'; // COMPLIANT +} + +void f3_explicit() { + char a[7] = "codeql"; + a[0] = 'a'; // COMPLIANT +} + +void f4_explicit() { + char *a = "codeql"; + if (a[0] == 'a') { // COMPLIANT + ; + } +} + +// implicit string literals +void f1_implicit() { + char *a = strchr("codeql", 'c'); + a[0] = 'a'; // NON_COMPLIANT +} + +void f2_implicit() { + char *a = strchr("codeql", 'c'); + char *b = strchr(a, 'c'); + b[0] = 'a'; // NON_COMPLIANT - implicitly literal +} + +void f3_implicit() { + char a_base[7]; + char *a = strchr(a_base, 'c'); + char *b = strchr(a, 'c'); + b[0] = 'a'; // COMPLIANT -- not implicitly literal +} + +void f4_implicit() { + char *a = strchr("codeql", 'c'); + if (a[0] == 'a') { // COMPLIANT + ; + } +} + +void f5_implicit() { + char *a_base = "codeql"; + char *a = strchr(a_base, 'c'); + char *b = strchr(a, 'c'); + + b[0] = 'a'; // NON_COMPLIANT - implicitly literal +} + +void f7_implicit(const char *a) { + char *b; + b = strrchr(a, 'c'); + if (b) { + *b = '\0'; // NON_COMPLIANT + } +} + +// local scope +void f5_local(const char *aa) { + + // allowed cases + { + char a[] = "codeql"; + mkstemp(a); // COMPLIANT + memset(a, '0', 100); // COMPLIANT + memcpy(a, "0", 100); // COMPLIANT + memmove(a, "0", 100); // COMPLIANT + strcat(a, "0"); // COMPLIANT + strncat(a, "0", 100); // COMPLIANT + strcpy(a, "0"); // COMPLIANT + strncpy(a, "0", 100); // COMPLIANT + } + + // explicit 1 + { + mkstemp("codeql"); // NON_COMPLIANT + memset("codeql", '0', 100); // NON_COMPLIANT + memcpy("codeql", "0", 100); // NON_COMPLIANT + memmove("codeql", "0", 100); // NON_COMPLIANT + strcat("codeql", "0"); // NON_COMPLIANT + strncat("codeql", "0", 100); // NON_COMPLIANT + strcpy("codeql", "0"); // NON_COMPLIANT + strncpy("codeql", "0", 100); // NON_COMPLIANT + } + + // explicit 2 + { + char *a = "codeql"; + mkstemp(a); // NON_COMPLIANT + memset(a, '0', 100); // NON_COMPLIANT + memcpy(a, "0", 100); // NON_COMPLIANT + memmove(a, "0", 100); // NON_COMPLIANT + strcat(a, "0"); // NON_COMPLIANT + strncat(a, "0", 100); // NON_COMPLIANT + strcpy(a, "0"); // NON_COMPLIANT + strncpy(a, "0", 100); // NON_COMPLIANT + } + + { + // implicit + char *a = strchr("codeql", 'c'); + mkstemp(a); // NON_COMPLIANT + memset(a, '0', 100); // NON_COMPLIANT + memcpy(a, "0", 100); // NON_COMPLIANT + memmove(a, "0", 100); // NON_COMPLIANT + strcat(a, "0"); // NON_COMPLIANT + strncat(a, "0", 100); // NON_COMPLIANT + strcpy(a, "0"); // NON_COMPLIANT + strncpy(a, "0", 100); // NON_COMPLIANT + } + + { + // implicit + mkstemp(aa); // NON_COMPLIANT + memset(aa, '0', 100); // NON_COMPLIANT + memcpy(aa, "0", 100); // NON_COMPLIANT + memmove(aa, "0", 100); // NON_COMPLIANT + strcat(aa, "0"); // NON_COMPLIANT + strncat(aa, "0", 100); // NON_COMPLIANT + strcpy(aa, "0"); // NON_COMPLIANT + strncpy(aa, "0", 100); // NON_COMPLIANT + } +} +// flow scope +void f5_flow(char *a) { + mkstemp(a); // NON_COMPLIANT + memset(a, '0', 100); // NON_COMPLIANT + memcpy(a, "0", 100); // NON_COMPLIANT + memmove(a, "0", 100); // NON_COMPLIANT + strcat(a, "0"); // NON_COMPLIANT + strncat(a, "0", 100); // NON_COMPLIANT + strcpy(a, "0"); // NON_COMPLIANT + strncpy(a, "0", 100); // NON_COMPLIANT +} + +void f5_explicit() { + char *a = "codeql"; + f5_flow(a); + f5_flow("codeql"); +} + +void f6_flow(char *a) { + mkstemp(a); // NON_COMPLIANT + memset(a, '0', 100); // NON_COMPLIANT + memcpy(a, "0", 100); // NON_COMPLIANT + memmove(a, "0", 100); // NON_COMPLIANT + strcat(a, "0"); // NON_COMPLIANT + strncat(a, "0", 100); // NON_COMPLIANT + strcpy(a, "0"); // NON_COMPLIANT + strncpy(a, "0", 100); // NON_COMPLIANT +} + +void f6_implicit() { + char *a = strchr("codeql", 'c'); + f6_flow(a); + f6_flow("codeql"); +} + +void f7_flow(char *a) { + mkstemp(a); // COMPLIANT + memset(a, '0', 100); // COMPLIANT + memcpy(a, "0", 100); // COMPLIANT + memmove(a, "0", 100); // COMPLIANT + strcat(a, "0"); // COMPLIANT + strncat(a, "0", 100); // COMPLIANT + strcpy(a, "0"); // COMPLIANT + strncpy(a, "0", 100); // COMPLIANT +} + +void f7_ok() { + char a[10] = "codeql"; + f7_flow(a); +} \ No newline at end of file diff --git a/c/cert/test/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.expected b/c/cert/test/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.expected new file mode 100644 index 0000000000..d5529dd26d --- /dev/null +++ b/c/cert/test/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.expected @@ -0,0 +1,7 @@ +| test.c:10:20:10:24 | Co | Expression produces or consumes a string that may not have sufficient space for a null-terminator. | +| test.c:16:3:16:9 | call to strncpy | Expression produces or consumes a string that may not have sufficient space for a null-terminator. | +| test.c:26:3:26:10 | call to snprintf | Expression produces or consumes a string that may not have sufficient space for a null-terminator. | +| test.c:32:3:32:9 | call to strncat | Expression produces or consumes a string that may not have sufficient space for a null-terminator. | +| test.c:37:7:37:10 | call to gets | Expression produces or consumes a string that may not have sufficient space for a null-terminator. | +| test.c:48:14:48:19 | call to getenv | Expression produces or consumes a string that may not have sufficient space for a null-terminator. | +| test.c:53:20:53:23 | argv | Expression produces or consumes a string that may not have sufficient space for a null-terminator. | diff --git a/c/cert/test/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.qlref b/c/cert/test/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.qlref new file mode 100644 index 0000000000..77925ee7ad --- /dev/null +++ b/c/cert/test/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.qlref @@ -0,0 +1 @@ +rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.ql \ No newline at end of file diff --git a/c/cert/test/rules/STR31-C/test.c b/c/cert/test/rules/STR31-C/test.c new file mode 100644 index 0000000000..1abfeba84d --- /dev/null +++ b/c/cert/test/rules/STR31-C/test.c @@ -0,0 +1,58 @@ +#include +#include +#include + +char *gets(char *s); // Needs to be forward declared because it is an inherently + // dangerous function + +void f1() { + char a1_nt[7] = "CodeQL"; // COMPLIANT + char a1_nnt[3] = "Cod"; // NON_COMPLIANT + + char a1[9]; + char a2[10]; + char a9[10]; + + strncpy(a2, a1, + 5); // NON_COMPLIANT - not null terminated because n < length(src) + strncpy(a9, a1, 10); // COMPLIANT - is null terminated; n > length(src) +} + +void f2() { + char a1[10]; + char a2[10]; + + snprintf(a1, 10, "CodeQL %d", 3); // COMPLIANT - will be null terminated + snprintf(a2, 11, "CodeQL %d", + 3); // NON_COMPLIANT - will not be null terminated +} + +void f3() { + char a1[2]; + strncat(a1, "CodeQL", 5); // NON_COMPLIANT - will not be null terminated +} + +void f4() { + char s2[10]; + if (gets(s2) == NULL) { // NON_COMPLIANT + } +} + +void f5() { + char a1[100]; + char *a2 = getenv("editor"); +} + +void f6() { + char a1[100]; + char *a2 = getenv("editor"); // NON_COMPLIANT + strcpy(a1, a2); +} + +int main(int argc, char *argv[]) { + char *const a1 = argv[0]; // NON_COMPLIANT + char a2[100]; + strcpy(a2, a1); + + return 0; +} \ No newline at end of file diff --git a/c/cert/test/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.expected b/c/cert/test/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.expected new file mode 100644 index 0000000000..bddddc6cb6 --- /dev/null +++ b/c/cert/test/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.expected @@ -0,0 +1,16 @@ +| test.c:19:3:19:8 | call to printf | String modified by $@ is passed to function expecting a null-terminated string. | test.c:7:20:7:24 | Co | this expression | +| test.c:20:3:20:8 | call to printf | String modified by $@ is passed to function expecting a null-terminated string. | test.c:7:20:7:24 | Co | this expression | +| test.c:22:3:22:8 | call to printf | String modified by $@ is passed to function expecting a null-terminated string. | test.c:13:3:13:9 | call to strncpy | this expression | +| test.c:23:3:23:8 | call to printf | String modified by $@ is passed to function expecting a null-terminated string. | test.c:13:3:13:9 | call to strncpy | this expression | +| test.c:24:3:24:8 | call to strlen | String modified by $@ is passed to function expecting a null-terminated string. | test.c:13:3:13:9 | call to strncpy | this expression | +| test.c:33:3:33:9 | call to wprintf | String modified by $@ is passed to function expecting a null-terminated string. | test.c:30:24:30:29 | Co | this expression | +| test.c:46:3:46:8 | call to printf | String modified by $@ is passed to function expecting a null-terminated string. | test.c:41:3:41:10 | call to snprintf | this expression | +| test.c:47:3:47:8 | call to printf | String modified by $@ is passed to function expecting a null-terminated string. | test.c:41:3:41:10 | call to snprintf | this expression | +| test.c:55:3:55:8 | call to printf | String modified by $@ is passed to function expecting a null-terminated string. | test.c:53:3:53:9 | call to strncat | this expression | +| test.c:56:3:56:8 | call to printf | String modified by $@ is passed to function expecting a null-terminated string. | test.c:53:3:53:9 | call to strncat | this expression | +| test.c:62:3:62:8 | call to printf | String modified by $@ is passed to function expecting a null-terminated string. | test.c:60:20:60:24 | Co | this expression | +| test.c:63:3:63:8 | call to printf | String modified by $@ is passed to function expecting a null-terminated string. | test.c:60:20:60:24 | Co | this expression | +| test.c:75:3:75:8 | call to printf | String modified by $@ is passed to function expecting a null-terminated string. | test.c:72:20:72:24 | Co | this expression | +| test.c:76:3:76:8 | call to printf | String modified by $@ is passed to function expecting a null-terminated string. | test.c:72:20:72:24 | Co | this expression | +| test.c:85:3:85:8 | call to printf | String modified by $@ is passed to function expecting a null-terminated string. | test.c:83:3:83:9 | call to strncpy | this expression | +| test.c:86:3:86:8 | call to printf | String modified by $@ is passed to function expecting a null-terminated string. | test.c:83:3:83:9 | call to strncpy | this expression | diff --git a/c/cert/test/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.qlref b/c/cert/test/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.qlref new file mode 100644 index 0000000000..bb2e2338e7 --- /dev/null +++ b/c/cert/test/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.qlref @@ -0,0 +1 @@ +rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.ql \ No newline at end of file diff --git a/c/cert/test/rules/STR32-C/test.c b/c/cert/test/rules/STR32-C/test.c new file mode 100644 index 0000000000..288ef7e5e0 --- /dev/null +++ b/c/cert/test/rules/STR32-C/test.c @@ -0,0 +1,87 @@ +#include +#include +#include + +void f1() { + char a1_nt[7] = "CodeQL"; // is null terminated + char a1_nnt[3] = "Cod"; // is NOT null termianted + + char a1[9]; + char a2[10]; + char a9[10]; + + strncpy(a2, a1, 5); // not null terminated because n < length(src) + strncpy(a9, a1, 10); // is null terminated; n > length(src) + + printf("%s", a1_nt); // COMPLIANT + printf(a1_nt); // COMPLIANT + + printf("%s", a1_nnt); // NON_COMPLIANT + printf(a1_nnt); // NON_COMPLIANT + + printf("%s", a2); // NON_COMPLIANT + printf(a2); // NON_COMPLIANT + strlen(a2); // NON_COMPLIANT + + printf(a9); // COMPLIANT + printf(a9); // COMPLIANT + + wchar_t wa1_nt[7] = L"CodeQL"; // is null terminated + wchar_t wa1_nnt[3] = L"Cod"; // is NOT null termianted + + wprintf(wa1_nt); // COMPLIANT + wprintf(wa1_nnt); // NON_COMPLIANT +} + +void f2() { + char a1[10]; + char a2[10]; + + snprintf(a1, 10, "CodeQL %d", 3); // will be null terminated + snprintf(a2, 11, "CodeQL %d", 3); // will not be null terminated + + printf("%s", a1); // COMPLIANT + printf(a1); // COMPLIANT + + printf("%s", a2); // NON_COMPLIANT + printf(a2); // NON_COMPLIANT +} + +void f3() { + char a1[2]; + + strncat(a1, "CodeQL", 5); // will not be null terminated + + printf(a1); // NON_COMPLIANT + printf("%s", a1); // NON_COMPLIANT +} + +void f4() { + char a1_nnt[3] = "Cod"; // is NOT null termianted + + printf("%s", a1_nnt); // NON_COMPLIANT + printf(a1_nnt); // NON_COMPLIANT + + a1_nnt[2] = '\0'; + + printf("%s", a1_nnt); // COMPLIANT + printf(a1_nnt); // COMPLIANT +} + +f5() { + char a1_nnt[3] = "Cod"; // is NOT null termianted + char a2[10] = "CodeQL"; + + printf("%s", a1_nnt); // NON_COMPLIANT + printf(a1_nnt); // NON_COMPLIANT + + a1_nnt[2] = '\0'; + + printf("%s", a1_nnt); // COMPLIANT + printf(a1_nnt); // COMPLIANT + + strncpy(a1_nnt, a2, 1); // not null terminated because n < length(src) + + printf("%s", a1_nnt); // NON_COMPLIANT + printf(a1_nnt); // NON_COMPLIANT +} \ No newline at end of file diff --git a/c/common/src/codingstandards/c/Expr.qll b/c/common/src/codingstandards/c/Expr.qll index 200f67ff7b..eadc870486 100644 --- a/c/common/src/codingstandards/c/Expr.qll +++ b/c/common/src/codingstandards/c/Expr.qll @@ -1,25 +1,10 @@ import cpp -/* A full expression as defined in ISO/IEC 9899:2011 Annex C point 1. */ +/* A full expression as defined in ISO/IEC 9899:2011 6.8 point 4 and Annex C point 1 item 5. */ class FullExpr extends Expr { FullExpr() { - // An initializer that is not part of a compound literal (see 6.7.9). - this instanceof AssignExpr and not this.getParent+() instanceof AggregateLiteral - or - // The expression in an expression statement (see 6.8.3) - any(ExprStmt s).getExpr() = this - or - // The controlling expression of a selection statement (see 6.8.4) or - // the controlling expression of a `while`, `do`, or `for` statement (see 6.8.5) - any(ControlStructure s).getControllingExpr() = this - or - // Each of the possible optional expressions, besides the controlling expression, - // of a `for` statement (see 6.8.5.3). Note that if `clause-1` will be an expression statement if - // it is an expression and is therefore handle in the expression statement case. - any(ForStmt s).getUpdate() = this - or - // The expression in a `return` statement, if any (see 6.8.6.4) - any(ReturnStmt s).getExpr() = this + not this.getParent() instanceof Expr and + not exists(Variable v | v.getInitializer().getExpr() = this) } } diff --git a/c/common/src/codingstandards/c/Ordering.qll b/c/common/src/codingstandards/c/Ordering.qll index 14f776f93e..955cba5e50 100644 --- a/c/common/src/codingstandards/c/Ordering.qll +++ b/c/common/src/codingstandards/c/Ordering.qll @@ -64,6 +64,10 @@ module Ordering { // Note we don't strictly check if `e2` is the next to be evaluated full expression and rely on the // `isCandidate` configuration to minimze the scope or related full expressions. e1 instanceof FullExpr and e2 instanceof FullExpr + or + // The side effect of updating the stored value of the left operand is sequenced after the value computations of the left and right operands. + // See 6.5.16 + e2.(Assignment).getAnOperand().getAChild*() = e1 ) } diff --git a/c/common/src/codingstandards/c/SideEffects.qll b/c/common/src/codingstandards/c/SideEffects.qll new file mode 100644 index 0000000000..3cea568e3e --- /dev/null +++ b/c/common/src/codingstandards/c/SideEffects.qll @@ -0,0 +1,41 @@ +/** A module that implements the side effects described in 5.1.2.3 section 1 of the ISO/IEC 9899:2011 standard. */ + +import cpp +import semmle.code.cpp.security.FileWrite +import codingstandards.cpp.SideEffect +import codingstandards.cpp.sideeffect.Customizations + +private class ModifyingLocalObject extends LocalSideEffect::Range { + ModifyingLocalObject() { + this.(AssignExpr).getLValue().(VariableAccess).getTarget() instanceof LocalScopeVariable + or + this.(CrementOperation).getOperand().(VariableAccess).getTarget() instanceof LocalScopeVariable + } +} + +private class ModifyingGlobalObject extends GlobalSideEffect::Range { + ModifyingGlobalObject() { + this.(AssignExpr).getLValue().(VariableAccess).getTarget() instanceof GlobalVariable + or + this.(CrementOperation).getOperand().(VariableAccess).getTarget() instanceof GlobalVariable + } +} + +private class VolatileAccess extends GlobalSideEffect::Range, VariableAccess { + VolatileAccess() { + this.getTarget().isVolatile() and + // Exclude value computation of an lvalue expression soley used to determine the identity + // of the object. As noted in the footnote of 6.5.16 point 3 it is implementation dependend + // whether the value of the assignment expression deterived from the left operand after the assignment + // is determined by reading the object. We assume it is not for assignments that are a child of an + // expression statement because the value is not used and is required for the compliant MISRA-C:2012 case: + // `extern volatile int v; v = v & 0x80;` + not exists(ExprStmt s | s.getExpr().(Assignment).getLValue() = this) + } +} + +private class ExternalFunctionCall extends GlobalSideEffect::Range, FunctionCall { + ExternalFunctionCall() { not exists(this.getTarget().getBlock()) } +} + +private class FileWriteEffect extends ExternalSideEffect::Range, FileWrite { } diff --git a/c/common/src/qlpack.yml b/c/common/src/qlpack.yml index d5851968b6..ddab9cafc2 100644 --- a/c/common/src/qlpack.yml +++ b/c/common/src/qlpack.yml @@ -1,3 +1,3 @@ name: common-c-coding-standards -version: 2.1.0 +version: 2.3.0 libraryPathDependencies: common-cpp-coding-standards diff --git a/c/common/test/expr/FullExpr.expected b/c/common/test/expr/FullExpr.expected index b25672bc29..4785b90024 100644 --- a/c/common/test/expr/FullExpr.expected +++ b/c/common/test/expr/FullExpr.expected @@ -1,8 +1,9 @@ -| fullexpr.c:11:3:11:5 | ... ++ | -| fullexpr.c:13:7:13:7 | i | -| fullexpr.c:15:10:15:10 | i | -| fullexpr.c:18:12:18:12 | i | -| fullexpr.c:20:8:20:12 | ... = ... | -| fullexpr.c:20:15:20:20 | ... < ... | -| fullexpr.c:20:23:20:25 | ++ ... | -| fullexpr.c:23:10:23:10 | i | +| fullexpr.c:8:18:11:37 | temporary object | +| fullexpr.c:13:3:13:5 | ... ++ | +| fullexpr.c:15:7:15:7 | i | +| fullexpr.c:17:10:17:10 | i | +| fullexpr.c:20:12:20:12 | i | +| fullexpr.c:22:8:22:12 | ... = ... | +| fullexpr.c:22:15:22:20 | ... < ... | +| fullexpr.c:22:23:22:25 | ++ ... | +| fullexpr.c:25:10:25:10 | i | diff --git a/c/common/test/expr/fullexpr.c b/c/common/test/expr/fullexpr.c index f4229e3bd3..5384f6add2 100644 --- a/c/common/test/expr/fullexpr.c +++ b/c/common/test/expr/fullexpr.c @@ -5,8 +5,10 @@ struct foo { void full_expr() { int i; - struct foo f = (struct foo){ - .i = 0, .j = 0}; // Not a full expression, part of a compound expression. + struct foo f = (struct foo){// Compound expression is a full expression. + .i = 0, // Assignments not a full expression, part + // of a compound expression. + .j = 0}; i++; // Full expression, part of expression statement diff --git a/c/common/test/qlpack.yml b/c/common/test/qlpack.yml index 7f28bccc17..35fc480d26 100644 --- a/c/common/test/qlpack.yml +++ b/c/common/test/qlpack.yml @@ -1,4 +1,4 @@ name: common-c-coding-standards-tests -version: 2.1.0 +version: 2.3.0 libraryPathDependencies: common-c-coding-standards extractor: cpp diff --git a/c/misra/src/qlpack.yml b/c/misra/src/qlpack.yml index 2002dd53e5..2925a83ae7 100644 --- a/c/misra/src/qlpack.yml +++ b/c/misra/src/qlpack.yml @@ -1,4 +1,4 @@ name: misra-c-coding-standards -version: 2.1.0 +version: 2.3.0 suites: codeql-suites libraryPathDependencies: common-c-coding-standards diff --git a/c/misra/src/rules/RULE-13-3/SideEffectAndCrementInFullExpression.ql b/c/misra/src/rules/RULE-13-3/SideEffectAndCrementInFullExpression.ql new file mode 100644 index 0000000000..808aa1ba7c --- /dev/null +++ b/c/misra/src/rules/RULE-13-3/SideEffectAndCrementInFullExpression.ql @@ -0,0 +1,27 @@ +/** + * @id c/misra/side-effect-and-crement-in-full-expression + * @name RULE-13-3: A full expression containing an increment (++) or decrement (--) operator should have no other + * @description A full expression containing an increment (++) or decrement (--) operator should + * have no other potential side effects other than that caused by the increment or + * decrement operator + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/misra/id/rule-13-3 + * readability + * correctness + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.Expr +import codingstandards.c.SideEffects + +from FullExpr e, SideEffect se, CrementOperation op +where + not isExcluded(e, SideEffects2Package::sideEffectAndCrementInFullExpressionQuery()) and + e.getAChild+() = op and + se = getASideEffect(e) and + not se instanceof CrementOperation +select e, "The full expression contains the $@ and the $@.", op, op.getOperator(), se, "side effect" diff --git a/c/misra/src/rules/RULE-13-3/standard-example.c b/c/misra/src/rules/RULE-13-3/standard-example.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/misra/src/rules/RULE-17-8/ModificationOfFunctionParameter.ql b/c/misra/src/rules/RULE-17-8/ModificationOfFunctionParameter.ql new file mode 100644 index 0000000000..6867455a45 --- /dev/null +++ b/c/misra/src/rules/RULE-17-8/ModificationOfFunctionParameter.ql @@ -0,0 +1,23 @@ +/** + * @id c/misra/modification-of-function-parameter + * @name RULE-17-8: A function parameter should not be modified + * @description A function parameter behaves in the same manner as an object with automatic storage + * duration and the effects of modifying a parameter are not visible in the calling + * function. + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/misra/id/rule-17-8 + * correctness + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.c.misra + +from Parameter p, VariableAccess va +where + not isExcluded(va, SideEffects2Package::modificationOfFunctionParameterQuery()) and + p.getAnAccess() = va and + va.isModified() +select va, "The parameter $@ is modified.", p, p.getName() diff --git a/c/misra/src/rules/RULE-17-8/standard-example.c b/c/misra/src/rules/RULE-17-8/standard-example.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/misra/src/rules/RULE-20-1/standard-example.c b/c/misra/src/rules/RULE-20-1/standard-example.c new file mode 100644 index 0000000000..b52af7fb03 --- /dev/null +++ b/c/misra/src/rules/RULE-20-1/standard-example.c @@ -0,0 +1,5 @@ +#define F1_MACRO +#include "f1.h" /* Compliant */ +#include "f2.h" /* Compliant */ +int32_t i = 0; +#include "f3.h" /* Non-compliant */ \ No newline at end of file diff --git a/c/misra/src/rules/RULE-20-2/standard-example.c b/c/misra/src/rules/RULE-20-2/standard-example.c new file mode 100644 index 0000000000..cfccf247a7 --- /dev/null +++ b/c/misra/src/rules/RULE-20-2/standard-example.c @@ -0,0 +1 @@ +#include "fi'le.h" /* Non-compliant */ \ No newline at end of file diff --git a/c/misra/src/rules/RULE-20-9/standard-example.c b/c/misra/src/rules/RULE-20-9/standard-example.c new file mode 100644 index 0000000000..9ecd802b4c --- /dev/null +++ b/c/misra/src/rules/RULE-20-9/standard-example.c @@ -0,0 +1,11 @@ +#if M == 0 /* Non-compliant */ +/* Does 'M' expand to zero or is it undefined? */ +#endif +#if defined(M) /* Compliant - M is not evaluated */ +#if M == 0 /* Compliant - M is known to be defined */ +/* 'M' must expand to zero. */ +#endif +#endif +/* Compliant - B is only evaluated in ( B == 0 ) if it is defined */ +#if defined(B) && (B == 0) +#endif \ No newline at end of file diff --git a/c/misra/test/qlpack.yml b/c/misra/test/qlpack.yml index c91e0ca32f..87c89cb5ce 100644 --- a/c/misra/test/qlpack.yml +++ b/c/misra/test/qlpack.yml @@ -1,4 +1,4 @@ name: misra-c-coding-standards-tests -version: 2.1.0 +version: 2.3.0 libraryPathDependencies: misra-c-coding-standards extractor: cpp \ No newline at end of file diff --git a/c/misra/test/rules/RULE-13-3/SideEffectAndCrementInFullExpression.expected b/c/misra/test/rules/RULE-13-3/SideEffectAndCrementInFullExpression.expected new file mode 100644 index 0000000000..9226e89ce0 --- /dev/null +++ b/c/misra/test/rules/RULE-13-3/SideEffectAndCrementInFullExpression.expected @@ -0,0 +1,4 @@ +| test.c:16:3:16:11 | ... = ... | The full expression contains the $@ and the $@. | test.c:16:8:16:11 | ... ++ | ++ | test.c:16:3:16:11 | ... = ... | side effect | +| test.c:21:7:21:23 | ... > ... | The full expression contains the $@ and the $@. | test.c:21:15:21:18 | -- ... | -- | test.c:3:19:3:20 | g1 | side effect | +| test.c:25:7:25:23 | ... > ... | The full expression contains the $@ and the $@. | test.c:25:15:25:18 | -- ... | -- | test.c:25:8:25:9 | call to f2 | side effect | +| test.c:33:3:33:28 | ... = ... | The full expression contains the $@ and the $@. | test.c:33:25:33:28 | ... ++ | ++ | test.c:33:3:33:28 | ... = ... | side effect | diff --git a/c/misra/test/rules/RULE-13-3/SideEffectAndCrementInFullExpression.qlref b/c/misra/test/rules/RULE-13-3/SideEffectAndCrementInFullExpression.qlref new file mode 100644 index 0000000000..ab7975eb5e --- /dev/null +++ b/c/misra/test/rules/RULE-13-3/SideEffectAndCrementInFullExpression.qlref @@ -0,0 +1 @@ +rules/RULE-13-3/SideEffectAndCrementInFullExpression.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-13-3/test.c b/c/misra/test/rules/RULE-13-3/test.c new file mode 100644 index 0000000000..6187de20b7 --- /dev/null +++ b/c/misra/test/rules/RULE-13-3/test.c @@ -0,0 +1,48 @@ + +extern volatile int g1; +int f1() { return g1 + 1; } + +extern int f2(); + +int f3() { return 1; } + +struct S1 { + int l1; +}; + +void test() { + int l1, l2; + + l2 = l1++; // NON_COMPLIANT + + int l3 = l1; + l1++; // COMPLIANT + + if ((f1() + --l1) > 0) // NON_COMPLIANT + { + } + + if ((f2() + --l1) > 0) // NON_COMPLIANT + { + } + + if ((f3() + --l1) > 0) // COMPLIANT + { + } + + l3 = (l2 == l2) ? 0 : l1++; // NON_COMPLIANT + + int l4[1] = {0}; + l4[0]++; // COMPLIANT + + struct S1 l5 = {.l1 = 0}; + l5.l1++; // COMPLIANT + + struct S1 *l6; + l6->l1++; // COMPLIANT + + int *l7 = &l1; + ++(*l7); // COMPLIANT + *l7++; // COMPLIANT + (*l7)++; // COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-17-8/ModificationOfFunctionParameter.expected b/c/misra/test/rules/RULE-17-8/ModificationOfFunctionParameter.expected new file mode 100644 index 0000000000..1b8c6e5ba6 --- /dev/null +++ b/c/misra/test/rules/RULE-17-8/ModificationOfFunctionParameter.expected @@ -0,0 +1,2 @@ +| test.c:2:3:2:4 | p1 | The parameter $@ is modified. | test.c:1:13:1:14 | p1 | p1 | +| test.c:7:3:7:4 | p1 | The parameter $@ is modified. | test.c:6:14:6:15 | p1 | p1 | diff --git a/c/misra/test/rules/RULE-17-8/ModificationOfFunctionParameter.qlref b/c/misra/test/rules/RULE-17-8/ModificationOfFunctionParameter.qlref new file mode 100644 index 0000000000..6d759d1579 --- /dev/null +++ b/c/misra/test/rules/RULE-17-8/ModificationOfFunctionParameter.qlref @@ -0,0 +1 @@ +rules/RULE-17-8/ModificationOfFunctionParameter.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-17-8/test.c b/c/misra/test/rules/RULE-17-8/test.c new file mode 100644 index 0000000000..62e06622b0 --- /dev/null +++ b/c/misra/test/rules/RULE-17-8/test.c @@ -0,0 +1,9 @@ +void f1(int p1) { + p1 = 1; // NON_COMPLIANT +} + +int g1 = 1; +void f2(int *p1) { + p1 = &g1; // NON_COMPLIANT + *p1 = g1; // COMPLIANT +} \ No newline at end of file diff --git a/change_notes/2022-04-06-rand-refactor.md b/change_notes/2022-04-06-rand-refactor.md new file mode 100644 index 0000000000..744c3255b5 --- /dev/null +++ b/change_notes/2022-04-06-rand-refactor.md @@ -0,0 +1 @@ +- Refactored `A26-5-1` and `MSC50-CPP` to share the same query with `MSC30-C`. \ No newline at end of file diff --git a/cpp/autosar/src/qlpack.yml b/cpp/autosar/src/qlpack.yml index 21a87c80cc..31eb8beee7 100644 --- a/cpp/autosar/src/qlpack.yml +++ b/cpp/autosar/src/qlpack.yml @@ -1,4 +1,4 @@ name: autosar-cpp-coding-standards -version: 2.1.0 +version: 2.3.0 suites: codeql-suites libraryPathDependencies: common-cpp-coding-standards diff --git a/cpp/autosar/src/rules/A10-2-1/NonVirtualPublicOrProtectedFunctionsRedefined.ql b/cpp/autosar/src/rules/A10-2-1/NonVirtualPublicOrProtectedFunctionsRedefined.ql index ef14664bf9..8a377b9f65 100644 --- a/cpp/autosar/src/rules/A10-2-1/NonVirtualPublicOrProtectedFunctionsRedefined.ql +++ b/cpp/autosar/src/rules/A10-2-1/NonVirtualPublicOrProtectedFunctionsRedefined.ql @@ -44,5 +44,5 @@ where subclass = shadowingVariable.getDeclaringType() ) ) -select f, "Member function $@ is shadowed by $@ in derived class @a", f, f.getName(), e, +select f, "Member function $@ is shadowed by $@ in derived class $@", f, f.getName(), e, description, subclass, subclass.getName() diff --git a/cpp/autosar/src/rules/A10-3-3/VirtualFunctionsIntroducedInFinalClass.ql b/cpp/autosar/src/rules/A10-3-3/VirtualFunctionsIntroducedInFinalClass.ql index 4e9d5c3131..2085be5b99 100644 --- a/cpp/autosar/src/rules/A10-3-3/VirtualFunctionsIntroducedInFinalClass.ql +++ b/cpp/autosar/src/rules/A10-3-3/VirtualFunctionsIntroducedInFinalClass.ql @@ -27,5 +27,5 @@ where not f.isDefaulted() and not f.isCompilerGenerated() and not f.getBlock().getLocation().hasLocationInfo("", 0, 0, 0, 0) -select f, "Non-final virtual function $@ is introduced in final class @$.", f, f.getName(), +select f, "Non-final virtual function $@ is introduced in final class $@.", f, f.getName(), f.getDeclaringType(), f.getDeclaringType().getName() diff --git a/cpp/autosar/src/rules/A15-1-5/standard-example.cpp b/cpp/autosar/src/rules/A15-1-5/standard-example.cpp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/cpp/autosar/src/rules/A26-5-1/PseudorandomNumbersGeneratedUsingRand.ql b/cpp/autosar/src/rules/A26-5-1/PseudorandomNumbersGeneratedUsingRand.ql index 38872a3182..bcf5357f57 100644 --- a/cpp/autosar/src/rules/A26-5-1/PseudorandomNumbersGeneratedUsingRand.ql +++ b/cpp/autosar/src/rules/A26-5-1/PseudorandomNumbersGeneratedUsingRand.ql @@ -14,11 +14,10 @@ import cpp import codingstandards.cpp.autosar +import codingstandards.cpp.rules.donotuserandforgeneratingpseudorandomnumbers.DoNotUseRandForGeneratingPseudorandomNumbers -predicate isRand(FunctionCall fc) { fc.getTarget().hasGlobalOrStdName("rand") } - -from FunctionCall fc -where - not isExcluded(fc, BannedFunctionsPackage::pseudorandomNumbersGeneratedUsingRandQuery()) and - isRand(fc) -select fc, "Use of banned function " + fc.getTarget().getQualifiedName() + "." +class PseudorandomNumbersGeneratedUsingRandQuery extends DoNotUseRandForGeneratingPseudorandomNumbersSharedQuery { + PseudorandomNumbersGeneratedUsingRandQuery() { + this = BannedFunctionsPackage::pseudorandomNumbersGeneratedUsingRandQuery() + } +} diff --git a/cpp/autosar/test/qlpack.yml b/cpp/autosar/test/qlpack.yml index ec8efd6777..195698fe83 100644 --- a/cpp/autosar/test/qlpack.yml +++ b/cpp/autosar/test/qlpack.yml @@ -1,4 +1,4 @@ name: autosar-cpp-coding-standards-tests -version: 2.1.0 +version: 2.3.0 libraryPathDependencies: autosar-cpp-coding-standards extractor: cpp diff --git a/cpp/autosar/test/rules/A10-2-1/NonVirtualPublicOrProtectedFunctionsRedefined.expected b/cpp/autosar/test/rules/A10-2-1/NonVirtualPublicOrProtectedFunctionsRedefined.expected index 6983b4ddcb..b8fd44dc43 100644 --- a/cpp/autosar/test/rules/A10-2-1/NonVirtualPublicOrProtectedFunctionsRedefined.expected +++ b/cpp/autosar/test/rules/A10-2-1/NonVirtualPublicOrProtectedFunctionsRedefined.expected @@ -1 +1 @@ -| test.cpp:4:8:4:9 | f1 | Member function $@ is shadowed by $@ in derived class @a | test.cpp:4:8:4:9 | f1 | f1 | test.cpp:13:8:13:9 | f1 | this member function | test.cpp:11:7:11:13 | Derived | Derived | +| test.cpp:4:8:4:9 | f1 | Member function $@ is shadowed by $@ in derived class $@ | test.cpp:4:8:4:9 | f1 | f1 | test.cpp:13:8:13:9 | f1 | this member function | test.cpp:11:7:11:13 | Derived | Derived | \ No newline at end of file diff --git a/cpp/autosar/test/rules/A10-3-3/VirtualFunctionsIntroducedInFinalClass.expected b/cpp/autosar/test/rules/A10-3-3/VirtualFunctionsIntroducedInFinalClass.expected index d16f6aee9c..7c35a98c9c 100644 --- a/cpp/autosar/test/rules/A10-3-3/VirtualFunctionsIntroducedInFinalClass.expected +++ b/cpp/autosar/test/rules/A10-3-3/VirtualFunctionsIntroducedInFinalClass.expected @@ -1,2 +1,2 @@ -| test.cpp:12:8:12:8 | g | Non-final virtual function $@ is introduced in final class @$. | test.cpp:12:8:12:8 | g | g | test.cpp:9:7:9:13 | Derived | Derived | -| test.cpp:14:16:14:16 | h | Non-final virtual function $@ is introduced in final class @$. | test.cpp:14:16:14:16 | h | h | test.cpp:9:7:9:13 | Derived | Derived | +| test.cpp:12:8:12:8 | g | Non-final virtual function $@ is introduced in final class $@. | test.cpp:12:8:12:8 | g | g | test.cpp:9:7:9:13 | Derived | Derived | +| test.cpp:14:16:14:16 | h | Non-final virtual function $@ is introduced in final class $@. | test.cpp:14:16:14:16 | h | h | test.cpp:9:7:9:13 | Derived | Derived | \ No newline at end of file diff --git a/cpp/autosar/test/rules/A26-5-1/PseudorandomNumbersGeneratedUsingRand.expected b/cpp/autosar/test/rules/A26-5-1/PseudorandomNumbersGeneratedUsingRand.expected deleted file mode 100644 index 1a3344c361..0000000000 --- a/cpp/autosar/test/rules/A26-5-1/PseudorandomNumbersGeneratedUsingRand.expected +++ /dev/null @@ -1 +0,0 @@ -| test.cpp:3:47:3:55 | call to rand | Use of banned function std::rand. | diff --git a/cpp/autosar/test/rules/A26-5-1/PseudorandomNumbersGeneratedUsingRand.qlref b/cpp/autosar/test/rules/A26-5-1/PseudorandomNumbersGeneratedUsingRand.qlref deleted file mode 100644 index 968fd714a7..0000000000 --- a/cpp/autosar/test/rules/A26-5-1/PseudorandomNumbersGeneratedUsingRand.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/A26-5-1/PseudorandomNumbersGeneratedUsingRand.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A26-5-1/PseudorandomNumbersGeneratedUsingRand.testref b/cpp/autosar/test/rules/A26-5-1/PseudorandomNumbersGeneratedUsingRand.testref new file mode 100644 index 0000000000..31cba60b74 --- /dev/null +++ b/cpp/autosar/test/rules/A26-5-1/PseudorandomNumbersGeneratedUsingRand.testref @@ -0,0 +1 @@ +cpp/common/test/rules/donotuserandforgeneratingpseudorandomnumbers/DoNotUseRandForGeneratingPseudorandomNumbers.ql \ No newline at end of file diff --git a/cpp/cert/src/qlpack.yml b/cpp/cert/src/qlpack.yml index 26346cf48b..003fb7b7cf 100644 --- a/cpp/cert/src/qlpack.yml +++ b/cpp/cert/src/qlpack.yml @@ -1,4 +1,4 @@ name: cert-cpp-coding-standards -version: 2.1.0 +version: 2.3.0 suites: codeql-suites libraryPathDependencies: common-cpp-coding-standards diff --git a/cpp/cert/src/rules/CON50-CPP/DoNotAllowAMutexToGoOutOfScopeWhileLocked-implementation.qhelp b/cpp/cert/src/rules/CON50-CPP/DoNotAllowAMutexToGoOutOfScopeWhileLocked-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/CON50-CPP/DoNotAllowAMutexToGoOutOfScopeWhileLocked-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/CON50-CPP/DoNotAllowAMutexToGoOutOfScopeWhileLocked.qhelp b/cpp/cert/src/rules/CON50-CPP/DoNotAllowAMutexToGoOutOfScopeWhileLocked.qhelp index 9e888978c1..75d7fdfc64 100644 --- a/cpp/cert/src/rules/CON50-CPP/DoNotAllowAMutexToGoOutOfScopeWhileLocked.qhelp +++ b/cpp/cert/src/rules/CON50-CPP/DoNotAllowAMutexToGoOutOfScopeWhileLocked.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/CON50-CPP/DoNotDestroyAMutexWhileItIsLocked-implementation.qhelp b/cpp/cert/src/rules/CON50-CPP/DoNotDestroyAMutexWhileItIsLocked-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/CON50-CPP/DoNotDestroyAMutexWhileItIsLocked-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/CON50-CPP/DoNotDestroyAMutexWhileItIsLocked.qhelp b/cpp/cert/src/rules/CON50-CPP/DoNotDestroyAMutexWhileItIsLocked.qhelp index 1f8ae81b6f..808cb603e4 100644 --- a/cpp/cert/src/rules/CON50-CPP/DoNotDestroyAMutexWhileItIsLocked.qhelp +++ b/cpp/cert/src/rules/CON50-CPP/DoNotDestroyAMutexWhileItIsLocked.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/CON51-CPP/EnsureActivelyHeldLocksAreReleasedOnExceptionalConditions-implementation.qhelp b/cpp/cert/src/rules/CON51-CPP/EnsureActivelyHeldLocksAreReleasedOnExceptionalConditions-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/CON51-CPP/EnsureActivelyHeldLocksAreReleasedOnExceptionalConditions-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/CON51-CPP/EnsureActivelyHeldLocksAreReleasedOnExceptionalConditions.qhelp b/cpp/cert/src/rules/CON51-CPP/EnsureActivelyHeldLocksAreReleasedOnExceptionalConditions.qhelp index 92b70ccf68..20b4d1923b 100644 --- a/cpp/cert/src/rules/CON51-CPP/EnsureActivelyHeldLocksAreReleasedOnExceptionalConditions.qhelp +++ b/cpp/cert/src/rules/CON51-CPP/EnsureActivelyHeldLocksAreReleasedOnExceptionalConditions.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/CON52-CPP/PreventDataRacesWhenAccessingBitFieldsFromMultipleThreads-implementation.qhelp b/cpp/cert/src/rules/CON52-CPP/PreventDataRacesWhenAccessingBitFieldsFromMultipleThreads-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/CON52-CPP/PreventDataRacesWhenAccessingBitFieldsFromMultipleThreads-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/CON52-CPP/PreventDataRacesWhenAccessingBitFieldsFromMultipleThreads.qhelp b/cpp/cert/src/rules/CON52-CPP/PreventDataRacesWhenAccessingBitFieldsFromMultipleThreads.qhelp index 0b0874bf87..ba85c19d8d 100644 --- a/cpp/cert/src/rules/CON52-CPP/PreventDataRacesWhenAccessingBitFieldsFromMultipleThreads.qhelp +++ b/cpp/cert/src/rules/CON52-CPP/PreventDataRacesWhenAccessingBitFieldsFromMultipleThreads.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/CON53-CPP/DeadlockByLockingInPredefinedOrder-implementation.qhelp b/cpp/cert/src/rules/CON53-CPP/DeadlockByLockingInPredefinedOrder-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/CON53-CPP/DeadlockByLockingInPredefinedOrder-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/CON53-CPP/DeadlockByLockingInPredefinedOrder.qhelp b/cpp/cert/src/rules/CON53-CPP/DeadlockByLockingInPredefinedOrder.qhelp index b11939010d..a5ded3d35b 100644 --- a/cpp/cert/src/rules/CON53-CPP/DeadlockByLockingInPredefinedOrder.qhelp +++ b/cpp/cert/src/rules/CON53-CPP/DeadlockByLockingInPredefinedOrder.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/CON54-CPP/WrapFunctionsThatCanSpuriouslyWakeUpInLoop-implementation.qhelp b/cpp/cert/src/rules/CON54-CPP/WrapFunctionsThatCanSpuriouslyWakeUpInLoop-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/CON54-CPP/WrapFunctionsThatCanSpuriouslyWakeUpInLoop-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/CON54-CPP/WrapFunctionsThatCanSpuriouslyWakeUpInLoop.qhelp b/cpp/cert/src/rules/CON54-CPP/WrapFunctionsThatCanSpuriouslyWakeUpInLoop.qhelp index 0da21dcc6f..af8e3fd47e 100644 --- a/cpp/cert/src/rules/CON54-CPP/WrapFunctionsThatCanSpuriouslyWakeUpInLoop.qhelp +++ b/cpp/cert/src/rules/CON54-CPP/WrapFunctionsThatCanSpuriouslyWakeUpInLoop.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/CON55-CPP/PreserveThreadSafetyAndLivenessWhenUsingConditionVariables-implementation.qhelp b/cpp/cert/src/rules/CON55-CPP/PreserveThreadSafetyAndLivenessWhenUsingConditionVariables-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/CON55-CPP/PreserveThreadSafetyAndLivenessWhenUsingConditionVariables-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/CON55-CPP/PreserveThreadSafetyAndLivenessWhenUsingConditionVariables.qhelp b/cpp/cert/src/rules/CON55-CPP/PreserveThreadSafetyAndLivenessWhenUsingConditionVariables.qhelp index 6daf7ea91a..af50203caa 100644 --- a/cpp/cert/src/rules/CON55-CPP/PreserveThreadSafetyAndLivenessWhenUsingConditionVariables.qhelp +++ b/cpp/cert/src/rules/CON55-CPP/PreserveThreadSafetyAndLivenessWhenUsingConditionVariables.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/CON56-CPP/DoNotSpeculativelyLockALockedNonRecursiveMutex-implementation.qhelp b/cpp/cert/src/rules/CON56-CPP/DoNotSpeculativelyLockALockedNonRecursiveMutex-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/CON56-CPP/DoNotSpeculativelyLockALockedNonRecursiveMutex-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/CON56-CPP/DoNotSpeculativelyLockALockedNonRecursiveMutex.qhelp b/cpp/cert/src/rules/CON56-CPP/DoNotSpeculativelyLockALockedNonRecursiveMutex.qhelp index f1b7dc7a0b..752a10d867 100644 --- a/cpp/cert/src/rules/CON56-CPP/DoNotSpeculativelyLockALockedNonRecursiveMutex.qhelp +++ b/cpp/cert/src/rules/CON56-CPP/DoNotSpeculativelyLockALockedNonRecursiveMutex.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/CON56-CPP/LockedALockedNonRecursiveMutexAudit-implementation.qhelp b/cpp/cert/src/rules/CON56-CPP/LockedALockedNonRecursiveMutexAudit-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/CON56-CPP/LockedALockedNonRecursiveMutexAudit-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/CON56-CPP/LockedALockedNonRecursiveMutexAudit.qhelp b/cpp/cert/src/rules/CON56-CPP/LockedALockedNonRecursiveMutexAudit.qhelp index 2438bf8d26..06299a50dd 100644 --- a/cpp/cert/src/rules/CON56-CPP/LockedALockedNonRecursiveMutexAudit.qhelp +++ b/cpp/cert/src/rules/CON56-CPP/LockedALockedNonRecursiveMutexAudit.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/CTR50-CPP/ContainerAccessWithoutRangeCheckCert-implementation.qhelp b/cpp/cert/src/rules/CTR50-CPP/ContainerAccessWithoutRangeCheckCert-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/CTR50-CPP/ContainerAccessWithoutRangeCheckCert-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/CTR50-CPP/ContainerAccessWithoutRangeCheckCert.qhelp b/cpp/cert/src/rules/CTR50-CPP/ContainerAccessWithoutRangeCheckCert.qhelp index 3731f713a4..ba1165f575 100644 --- a/cpp/cert/src/rules/CTR50-CPP/ContainerAccessWithoutRangeCheckCert.qhelp +++ b/cpp/cert/src/rules/CTR50-CPP/ContainerAccessWithoutRangeCheckCert.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/CTR51-CPP/UsesValidContainerElementAccess-implementation.qhelp b/cpp/cert/src/rules/CTR51-CPP/UsesValidContainerElementAccess-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/CTR51-CPP/UsesValidContainerElementAccess-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/CTR51-CPP/UsesValidContainerElementAccess.qhelp b/cpp/cert/src/rules/CTR51-CPP/UsesValidContainerElementAccess.qhelp index 05b8fe2633..9c8ecf1ce8 100644 --- a/cpp/cert/src/rules/CTR51-CPP/UsesValidContainerElementAccess.qhelp +++ b/cpp/cert/src/rules/CTR51-CPP/UsesValidContainerElementAccess.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow-implementation.qhelp b/cpp/cert/src/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow.qhelp b/cpp/cert/src/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow.qhelp index 09e6adb30e..10164978a5 100644 --- a/cpp/cert/src/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow.qhelp +++ b/cpp/cert/src/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/CTR53-CPP/UseValidIteratorRanges-implementation.qhelp b/cpp/cert/src/rules/CTR53-CPP/UseValidIteratorRanges-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/CTR53-CPP/UseValidIteratorRanges-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/CTR53-CPP/UseValidIteratorRanges.qhelp b/cpp/cert/src/rules/CTR53-CPP/UseValidIteratorRanges.qhelp index 51cd887adb..3a2e37be8e 100644 --- a/cpp/cert/src/rules/CTR53-CPP/UseValidIteratorRanges.qhelp +++ b/cpp/cert/src/rules/CTR53-CPP/UseValidIteratorRanges.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/CTR54-CPP/DoNotSubtractIteratorsForDifferentContainers-implementation.qhelp b/cpp/cert/src/rules/CTR54-CPP/DoNotSubtractIteratorsForDifferentContainers-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/CTR54-CPP/DoNotSubtractIteratorsForDifferentContainers-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/CTR54-CPP/DoNotSubtractIteratorsForDifferentContainers.qhelp b/cpp/cert/src/rules/CTR54-CPP/DoNotSubtractIteratorsForDifferentContainers.qhelp index 4dbb447a8a..4acb8354e3 100644 --- a/cpp/cert/src/rules/CTR54-CPP/DoNotSubtractIteratorsForDifferentContainers.qhelp +++ b/cpp/cert/src/rules/CTR54-CPP/DoNotSubtractIteratorsForDifferentContainers.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator-implementation.qhelp b/cpp/cert/src/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator.qhelp b/cpp/cert/src/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator.qhelp index 5d1561f97f..27710371de 100644 --- a/cpp/cert/src/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator.qhelp +++ b/cpp/cert/src/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/CTR56-CPP/DoNotUsePointerArithmeticOnPolymorphicObjects-implementation.qhelp b/cpp/cert/src/rules/CTR56-CPP/DoNotUsePointerArithmeticOnPolymorphicObjects-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/CTR56-CPP/DoNotUsePointerArithmeticOnPolymorphicObjects-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/CTR56-CPP/DoNotUsePointerArithmeticOnPolymorphicObjects.qhelp b/cpp/cert/src/rules/CTR56-CPP/DoNotUsePointerArithmeticOnPolymorphicObjects.qhelp index 92aa867675..d2a83dd11e 100644 --- a/cpp/cert/src/rules/CTR56-CPP/DoNotUsePointerArithmeticOnPolymorphicObjects.qhelp +++ b/cpp/cert/src/rules/CTR56-CPP/DoNotUsePointerArithmeticOnPolymorphicObjects.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/CTR57-CPP/ProvideAValidOrderingPredicate-implementation.qhelp b/cpp/cert/src/rules/CTR57-CPP/ProvideAValidOrderingPredicate-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/CTR57-CPP/ProvideAValidOrderingPredicate-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/CTR57-CPP/ProvideAValidOrderingPredicate.qhelp b/cpp/cert/src/rules/CTR57-CPP/ProvideAValidOrderingPredicate.qhelp index a80e7888ad..e844de0b06 100644 --- a/cpp/cert/src/rules/CTR57-CPP/ProvideAValidOrderingPredicate.qhelp +++ b/cpp/cert/src/rules/CTR57-CPP/ProvideAValidOrderingPredicate.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/CTR58-CPP/PredicateFunctionObjectsShouldNotBeMutable-implementation.qhelp b/cpp/cert/src/rules/CTR58-CPP/PredicateFunctionObjectsShouldNotBeMutable-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/CTR58-CPP/PredicateFunctionObjectsShouldNotBeMutable-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/CTR58-CPP/PredicateFunctionObjectsShouldNotBeMutable.qhelp b/cpp/cert/src/rules/CTR58-CPP/PredicateFunctionObjectsShouldNotBeMutable.qhelp index 1030c85c27..6bf05bffe4 100644 --- a/cpp/cert/src/rules/CTR58-CPP/PredicateFunctionObjectsShouldNotBeMutable.qhelp +++ b/cpp/cert/src/rules/CTR58-CPP/PredicateFunctionObjectsShouldNotBeMutable.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/DCL50-CPP/DoNotDefineACStyleVariadicFunction-implementation.qhelp b/cpp/cert/src/rules/DCL50-CPP/DoNotDefineACStyleVariadicFunction-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/DCL50-CPP/DoNotDefineACStyleVariadicFunction-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/DCL50-CPP/DoNotDefineACStyleVariadicFunction.qhelp b/cpp/cert/src/rules/DCL50-CPP/DoNotDefineACStyleVariadicFunction.qhelp index 0928595f3f..db2fd3c761 100644 --- a/cpp/cert/src/rules/DCL50-CPP/DoNotDefineACStyleVariadicFunction.qhelp +++ b/cpp/cert/src/rules/DCL50-CPP/DoNotDefineACStyleVariadicFunction.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/DCL51-CPP/EnumeratorReusesReservedName-implementation.qhelp b/cpp/cert/src/rules/DCL51-CPP/EnumeratorReusesReservedName-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/DCL51-CPP/EnumeratorReusesReservedName-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/DCL51-CPP/EnumeratorReusesReservedName.qhelp b/cpp/cert/src/rules/DCL51-CPP/EnumeratorReusesReservedName.qhelp index 72e29bcf7b..1e47f79818 100644 --- a/cpp/cert/src/rules/DCL51-CPP/EnumeratorReusesReservedName.qhelp +++ b/cpp/cert/src/rules/DCL51-CPP/EnumeratorReusesReservedName.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/DCL51-CPP/FunctionReusesReservedName-implementation.qhelp b/cpp/cert/src/rules/DCL51-CPP/FunctionReusesReservedName-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/DCL51-CPP/FunctionReusesReservedName-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/DCL51-CPP/FunctionReusesReservedName.qhelp b/cpp/cert/src/rules/DCL51-CPP/FunctionReusesReservedName.qhelp index 692b744e35..7a4d271e5e 100644 --- a/cpp/cert/src/rules/DCL51-CPP/FunctionReusesReservedName.qhelp +++ b/cpp/cert/src/rules/DCL51-CPP/FunctionReusesReservedName.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/DCL51-CPP/ObjectReusesReservedName-implementation.qhelp b/cpp/cert/src/rules/DCL51-CPP/ObjectReusesReservedName-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/DCL51-CPP/ObjectReusesReservedName-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/DCL51-CPP/ObjectReusesReservedName.qhelp b/cpp/cert/src/rules/DCL51-CPP/ObjectReusesReservedName.qhelp index d26212f76e..fb1c4bd2c9 100644 --- a/cpp/cert/src/rules/DCL51-CPP/ObjectReusesReservedName.qhelp +++ b/cpp/cert/src/rules/DCL51-CPP/ObjectReusesReservedName.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/DCL51-CPP/RedefiningOfStandardLibraryName-implementation.qhelp b/cpp/cert/src/rules/DCL51-CPP/RedefiningOfStandardLibraryName-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/DCL51-CPP/RedefiningOfStandardLibraryName-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/DCL51-CPP/RedefiningOfStandardLibraryName.qhelp b/cpp/cert/src/rules/DCL51-CPP/RedefiningOfStandardLibraryName.qhelp index e6ba11db60..82a8a64a7b 100644 --- a/cpp/cert/src/rules/DCL51-CPP/RedefiningOfStandardLibraryName.qhelp +++ b/cpp/cert/src/rules/DCL51-CPP/RedefiningOfStandardLibraryName.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/DCL51-CPP/ReuseOfReservedIdentifier-implementation.qhelp b/cpp/cert/src/rules/DCL51-CPP/ReuseOfReservedIdentifier-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/DCL51-CPP/ReuseOfReservedIdentifier-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/DCL51-CPP/ReuseOfReservedIdentifier.qhelp b/cpp/cert/src/rules/DCL51-CPP/ReuseOfReservedIdentifier.qhelp index 5aab15a778..1d0dbd4c40 100644 --- a/cpp/cert/src/rules/DCL51-CPP/ReuseOfReservedIdentifier.qhelp +++ b/cpp/cert/src/rules/DCL51-CPP/ReuseOfReservedIdentifier.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/DCL51-CPP/UseOfDoubleUnderscoreReservedPrefix-implementation.qhelp b/cpp/cert/src/rules/DCL51-CPP/UseOfDoubleUnderscoreReservedPrefix-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/DCL51-CPP/UseOfDoubleUnderscoreReservedPrefix-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/DCL51-CPP/UseOfDoubleUnderscoreReservedPrefix.qhelp b/cpp/cert/src/rules/DCL51-CPP/UseOfDoubleUnderscoreReservedPrefix.qhelp index 56fa858e67..1d25d68604 100644 --- a/cpp/cert/src/rules/DCL51-CPP/UseOfDoubleUnderscoreReservedPrefix.qhelp +++ b/cpp/cert/src/rules/DCL51-CPP/UseOfDoubleUnderscoreReservedPrefix.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/DCL51-CPP/UseOfReservedLiteralSuffixIdentifier-implementation.qhelp b/cpp/cert/src/rules/DCL51-CPP/UseOfReservedLiteralSuffixIdentifier-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/DCL51-CPP/UseOfReservedLiteralSuffixIdentifier-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/DCL51-CPP/UseOfReservedLiteralSuffixIdentifier.qhelp b/cpp/cert/src/rules/DCL51-CPP/UseOfReservedLiteralSuffixIdentifier.qhelp index 0cc04c2da3..11c8ba2ae3 100644 --- a/cpp/cert/src/rules/DCL51-CPP/UseOfReservedLiteralSuffixIdentifier.qhelp +++ b/cpp/cert/src/rules/DCL51-CPP/UseOfReservedLiteralSuffixIdentifier.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/DCL51-CPP/UseOfSingleUnderscoreReservedPrefix-implementation.qhelp b/cpp/cert/src/rules/DCL51-CPP/UseOfSingleUnderscoreReservedPrefix-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/DCL51-CPP/UseOfSingleUnderscoreReservedPrefix-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/DCL51-CPP/UseOfSingleUnderscoreReservedPrefix.qhelp b/cpp/cert/src/rules/DCL51-CPP/UseOfSingleUnderscoreReservedPrefix.qhelp index db3263896e..00e3f9dba6 100644 --- a/cpp/cert/src/rules/DCL51-CPP/UseOfSingleUnderscoreReservedPrefix.qhelp +++ b/cpp/cert/src/rules/DCL51-CPP/UseOfSingleUnderscoreReservedPrefix.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/DCL53-CPP/LocalConstructorInitializedObjectHidesIdentifier-implementation.qhelp b/cpp/cert/src/rules/DCL53-CPP/LocalConstructorInitializedObjectHidesIdentifier-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/DCL53-CPP/LocalConstructorInitializedObjectHidesIdentifier-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/DCL53-CPP/LocalConstructorInitializedObjectHidesIdentifier.qhelp b/cpp/cert/src/rules/DCL53-CPP/LocalConstructorInitializedObjectHidesIdentifier.qhelp index a92d5f0842..e47ceb43db 100644 --- a/cpp/cert/src/rules/DCL53-CPP/LocalConstructorInitializedObjectHidesIdentifier.qhelp +++ b/cpp/cert/src/rules/DCL53-CPP/LocalConstructorInitializedObjectHidesIdentifier.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/DCL53-CPP/LocalFunctionDeclaration-implementation.qhelp b/cpp/cert/src/rules/DCL53-CPP/LocalFunctionDeclaration-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/DCL53-CPP/LocalFunctionDeclaration-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/DCL53-CPP/LocalFunctionDeclaration.qhelp b/cpp/cert/src/rules/DCL53-CPP/LocalFunctionDeclaration.qhelp index 9c8408d47c..f6d47b4e22 100644 --- a/cpp/cert/src/rules/DCL53-CPP/LocalFunctionDeclaration.qhelp +++ b/cpp/cert/src/rules/DCL53-CPP/LocalFunctionDeclaration.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/DCL54-CPP/SingularOverloadOfMemoryFunction-implementation.qhelp b/cpp/cert/src/rules/DCL54-CPP/SingularOverloadOfMemoryFunction-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/DCL54-CPP/SingularOverloadOfMemoryFunction-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/DCL54-CPP/SingularOverloadOfMemoryFunction.qhelp b/cpp/cert/src/rules/DCL54-CPP/SingularOverloadOfMemoryFunction.qhelp index fceae59e3d..cbdf56b80c 100644 --- a/cpp/cert/src/rules/DCL54-CPP/SingularOverloadOfMemoryFunction.qhelp +++ b/cpp/cert/src/rules/DCL54-CPP/SingularOverloadOfMemoryFunction.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/DCL55-CPP/InformationLeakageAcrossTrustBoundaries-implementation.qhelp b/cpp/cert/src/rules/DCL55-CPP/InformationLeakageAcrossTrustBoundaries-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/DCL55-CPP/InformationLeakageAcrossTrustBoundaries-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/DCL55-CPP/InformationLeakageAcrossTrustBoundaries.qhelp b/cpp/cert/src/rules/DCL55-CPP/InformationLeakageAcrossTrustBoundaries.qhelp index e58c04c852..ea0b927cc5 100644 --- a/cpp/cert/src/rules/DCL55-CPP/InformationLeakageAcrossTrustBoundaries.qhelp +++ b/cpp/cert/src/rules/DCL55-CPP/InformationLeakageAcrossTrustBoundaries.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/DCL56-CPP/CyclesDuringStaticObjectInit-implementation.qhelp b/cpp/cert/src/rules/DCL56-CPP/CyclesDuringStaticObjectInit-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/DCL56-CPP/CyclesDuringStaticObjectInit-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/DCL56-CPP/CyclesDuringStaticObjectInit.qhelp b/cpp/cert/src/rules/DCL56-CPP/CyclesDuringStaticObjectInit.qhelp index b1c4ac046f..3a93c502ff 100644 --- a/cpp/cert/src/rules/DCL56-CPP/CyclesDuringStaticObjectInit.qhelp +++ b/cpp/cert/src/rules/DCL56-CPP/CyclesDuringStaticObjectInit.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/DCL57-CPP/DoNotLetExceptionsEscapeFromDestructorsOrDeallocationFunctions-implementation.qhelp b/cpp/cert/src/rules/DCL57-CPP/DoNotLetExceptionsEscapeFromDestructorsOrDeallocationFunctions-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/DCL57-CPP/DoNotLetExceptionsEscapeFromDestructorsOrDeallocationFunctions-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/DCL57-CPP/DoNotLetExceptionsEscapeFromDestructorsOrDeallocationFunctions.qhelp b/cpp/cert/src/rules/DCL57-CPP/DoNotLetExceptionsEscapeFromDestructorsOrDeallocationFunctions.qhelp index 0f1237d943..7781d75a4a 100644 --- a/cpp/cert/src/rules/DCL57-CPP/DoNotLetExceptionsEscapeFromDestructorsOrDeallocationFunctions.qhelp +++ b/cpp/cert/src/rules/DCL57-CPP/DoNotLetExceptionsEscapeFromDestructorsOrDeallocationFunctions.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/DCL58-CPP/ModificationOfTheStandardNamespaces-implementation.qhelp b/cpp/cert/src/rules/DCL58-CPP/ModificationOfTheStandardNamespaces-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/DCL58-CPP/ModificationOfTheStandardNamespaces-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/DCL58-CPP/ModificationOfTheStandardNamespaces.qhelp b/cpp/cert/src/rules/DCL58-CPP/ModificationOfTheStandardNamespaces.qhelp index 3085f98eba..7bca071087 100644 --- a/cpp/cert/src/rules/DCL58-CPP/ModificationOfTheStandardNamespaces.qhelp +++ b/cpp/cert/src/rules/DCL58-CPP/ModificationOfTheStandardNamespaces.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/DCL59-CPP/UnnamedNamespaceInHeaderFile-implementation.qhelp b/cpp/cert/src/rules/DCL59-CPP/UnnamedNamespaceInHeaderFile-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/DCL59-CPP/UnnamedNamespaceInHeaderFile-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/DCL59-CPP/UnnamedNamespaceInHeaderFile.qhelp b/cpp/cert/src/rules/DCL59-CPP/UnnamedNamespaceInHeaderFile.qhelp index 113b3eefbe..eacdf902c1 100644 --- a/cpp/cert/src/rules/DCL59-CPP/UnnamedNamespaceInHeaderFile.qhelp +++ b/cpp/cert/src/rules/DCL59-CPP/UnnamedNamespaceInHeaderFile.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/DCL60-CPP/OneDefinitionRuleNotObeyed-implementation.qhelp b/cpp/cert/src/rules/DCL60-CPP/OneDefinitionRuleNotObeyed-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/DCL60-CPP/OneDefinitionRuleNotObeyed-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/DCL60-CPP/OneDefinitionRuleNotObeyed.qhelp b/cpp/cert/src/rules/DCL60-CPP/OneDefinitionRuleNotObeyed.qhelp index 8fa5f43910..0a909aa735 100644 --- a/cpp/cert/src/rules/DCL60-CPP/OneDefinitionRuleNotObeyed.qhelp +++ b/cpp/cert/src/rules/DCL60-CPP/OneDefinitionRuleNotObeyed.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/ERR50-CPP/ConditionVariablePostConditionFailedCert-implementation.qhelp b/cpp/cert/src/rules/ERR50-CPP/ConditionVariablePostConditionFailedCert-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/ERR50-CPP/ConditionVariablePostConditionFailedCert-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/ERR50-CPP/ConditionVariablePostConditionFailedCert.qhelp b/cpp/cert/src/rules/ERR50-CPP/ConditionVariablePostConditionFailedCert.qhelp index b50a1bb53f..5243c6e6f9 100644 --- a/cpp/cert/src/rules/ERR50-CPP/ConditionVariablePostConditionFailedCert.qhelp +++ b/cpp/cert/src/rules/ERR50-CPP/ConditionVariablePostConditionFailedCert.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/ERR50-CPP/ExitHandlerThrowsExceptionCert-implementation.qhelp b/cpp/cert/src/rules/ERR50-CPP/ExitHandlerThrowsExceptionCert-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/ERR50-CPP/ExitHandlerThrowsExceptionCert-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/ERR50-CPP/ExitHandlerThrowsExceptionCert.qhelp b/cpp/cert/src/rules/ERR50-CPP/ExitHandlerThrowsExceptionCert.qhelp index d55f61c6c1..a9ccd96a73 100644 --- a/cpp/cert/src/rules/ERR50-CPP/ExitHandlerThrowsExceptionCert.qhelp +++ b/cpp/cert/src/rules/ERR50-CPP/ExitHandlerThrowsExceptionCert.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/ERR50-CPP/ExplicitAbruptTerminationCert-implementation.qhelp b/cpp/cert/src/rules/ERR50-CPP/ExplicitAbruptTerminationCert-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/ERR50-CPP/ExplicitAbruptTerminationCert-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/ERR50-CPP/ExplicitAbruptTerminationCert.qhelp b/cpp/cert/src/rules/ERR50-CPP/ExplicitAbruptTerminationCert.qhelp index 98f4e75388..f871c5c3f5 100644 --- a/cpp/cert/src/rules/ERR50-CPP/ExplicitAbruptTerminationCert.qhelp +++ b/cpp/cert/src/rules/ERR50-CPP/ExplicitAbruptTerminationCert.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/ERR50-CPP/JoinableThreadCopiedOrDestroyedCert-implementation.qhelp b/cpp/cert/src/rules/ERR50-CPP/JoinableThreadCopiedOrDestroyedCert-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/ERR50-CPP/JoinableThreadCopiedOrDestroyedCert-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/ERR50-CPP/JoinableThreadCopiedOrDestroyedCert.qhelp b/cpp/cert/src/rules/ERR50-CPP/JoinableThreadCopiedOrDestroyedCert.qhelp index c5a6537d4c..86efd7d17f 100644 --- a/cpp/cert/src/rules/ERR50-CPP/JoinableThreadCopiedOrDestroyedCert.qhelp +++ b/cpp/cert/src/rules/ERR50-CPP/JoinableThreadCopiedOrDestroyedCert.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/ERR50-CPP/RethrowNestedWithoutCaptureCert-implementation.qhelp b/cpp/cert/src/rules/ERR50-CPP/RethrowNestedWithoutCaptureCert-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/ERR50-CPP/RethrowNestedWithoutCaptureCert-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/ERR50-CPP/RethrowNestedWithoutCaptureCert.qhelp b/cpp/cert/src/rules/ERR50-CPP/RethrowNestedWithoutCaptureCert.qhelp index b69bdc6d95..68e8276df2 100644 --- a/cpp/cert/src/rules/ERR50-CPP/RethrowNestedWithoutCaptureCert.qhelp +++ b/cpp/cert/src/rules/ERR50-CPP/RethrowNestedWithoutCaptureCert.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/ERR51-CPP/HandleAllExceptions-implementation.qhelp b/cpp/cert/src/rules/ERR51-CPP/HandleAllExceptions-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/ERR51-CPP/HandleAllExceptions-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/ERR51-CPP/HandleAllExceptions.qhelp b/cpp/cert/src/rules/ERR51-CPP/HandleAllExceptions.qhelp index f78844a827..473f9fb2a7 100644 --- a/cpp/cert/src/rules/ERR51-CPP/HandleAllExceptions.qhelp +++ b/cpp/cert/src/rules/ERR51-CPP/HandleAllExceptions.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/ERR52-CPP/DoNotUseSetjmpOrLongjmp-implementation.qhelp b/cpp/cert/src/rules/ERR52-CPP/DoNotUseSetjmpOrLongjmp-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/ERR52-CPP/DoNotUseSetjmpOrLongjmp-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/ERR52-CPP/DoNotUseSetjmpOrLongjmp.qhelp b/cpp/cert/src/rules/ERR52-CPP/DoNotUseSetjmpOrLongjmp.qhelp index 4f740363af..d06a4066ae 100644 --- a/cpp/cert/src/rules/ERR52-CPP/DoNotUseSetjmpOrLongjmp.qhelp +++ b/cpp/cert/src/rules/ERR52-CPP/DoNotUseSetjmpOrLongjmp.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/ERR53-CPP/DestroyedValueReferencedInConstructorDestructorCatchBlock-implementation.qhelp b/cpp/cert/src/rules/ERR53-CPP/DestroyedValueReferencedInConstructorDestructorCatchBlock-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/ERR53-CPP/DestroyedValueReferencedInConstructorDestructorCatchBlock-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/ERR53-CPP/DestroyedValueReferencedInConstructorDestructorCatchBlock.qhelp b/cpp/cert/src/rules/ERR53-CPP/DestroyedValueReferencedInConstructorDestructorCatchBlock.qhelp index 7e9dad10c0..56ed5b76e7 100644 --- a/cpp/cert/src/rules/ERR53-CPP/DestroyedValueReferencedInConstructorDestructorCatchBlock.qhelp +++ b/cpp/cert/src/rules/ERR53-CPP/DestroyedValueReferencedInConstructorDestructorCatchBlock.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/ERR54-CPP/CatchBlockShadowingCert-implementation.qhelp b/cpp/cert/src/rules/ERR54-CPP/CatchBlockShadowingCert-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/ERR54-CPP/CatchBlockShadowingCert-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/ERR54-CPP/CatchBlockShadowingCert.qhelp b/cpp/cert/src/rules/ERR54-CPP/CatchBlockShadowingCert.qhelp index e440b6f961..4b3f30df6f 100644 --- a/cpp/cert/src/rules/ERR54-CPP/CatchBlockShadowingCert.qhelp +++ b/cpp/cert/src/rules/ERR54-CPP/CatchBlockShadowingCert.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/ERR55-CPP/HonorExceptionSpecifications-implementation.qhelp b/cpp/cert/src/rules/ERR55-CPP/HonorExceptionSpecifications-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/ERR55-CPP/HonorExceptionSpecifications-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/ERR55-CPP/HonorExceptionSpecifications.qhelp b/cpp/cert/src/rules/ERR55-CPP/HonorExceptionSpecifications.qhelp index 33d637bda5..97ddffd886 100644 --- a/cpp/cert/src/rules/ERR55-CPP/HonorExceptionSpecifications.qhelp +++ b/cpp/cert/src/rules/ERR55-CPP/HonorExceptionSpecifications.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/ERR56-CPP/GuaranteeExceptionSafety-implementation.qhelp b/cpp/cert/src/rules/ERR56-CPP/GuaranteeExceptionSafety-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/ERR56-CPP/GuaranteeExceptionSafety-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/ERR56-CPP/GuaranteeExceptionSafety.qhelp b/cpp/cert/src/rules/ERR56-CPP/GuaranteeExceptionSafety.qhelp index 715b977b41..729647f547 100644 --- a/cpp/cert/src/rules/ERR56-CPP/GuaranteeExceptionSafety.qhelp +++ b/cpp/cert/src/rules/ERR56-CPP/GuaranteeExceptionSafety.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/ERR57-CPP/DoNotLeakResourcesWhenHandlingExceptions-implementation.qhelp b/cpp/cert/src/rules/ERR57-CPP/DoNotLeakResourcesWhenHandlingExceptions-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/ERR57-CPP/DoNotLeakResourcesWhenHandlingExceptions-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/ERR57-CPP/DoNotLeakResourcesWhenHandlingExceptions.qhelp b/cpp/cert/src/rules/ERR57-CPP/DoNotLeakResourcesWhenHandlingExceptions.qhelp index 304c230848..6feed00907 100644 --- a/cpp/cert/src/rules/ERR57-CPP/DoNotLeakResourcesWhenHandlingExceptions.qhelp +++ b/cpp/cert/src/rules/ERR57-CPP/DoNotLeakResourcesWhenHandlingExceptions.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/ERR58-CPP/HandleAllExceptionsThrownBeforeMainBeginsExecuting-implementation.qhelp b/cpp/cert/src/rules/ERR58-CPP/HandleAllExceptionsThrownBeforeMainBeginsExecuting-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/ERR58-CPP/HandleAllExceptionsThrownBeforeMainBeginsExecuting-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/ERR58-CPP/HandleAllExceptionsThrownBeforeMainBeginsExecuting.qhelp b/cpp/cert/src/rules/ERR58-CPP/HandleAllExceptionsThrownBeforeMainBeginsExecuting.qhelp index e896263925..91102cdf0c 100644 --- a/cpp/cert/src/rules/ERR58-CPP/HandleAllExceptionsThrownBeforeMainBeginsExecuting.qhelp +++ b/cpp/cert/src/rules/ERR58-CPP/HandleAllExceptionsThrownBeforeMainBeginsExecuting.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/ERR59-CPP/DoNotThrowAnExceptionAcrossExecutionBoundaries-implementation.qhelp b/cpp/cert/src/rules/ERR59-CPP/DoNotThrowAnExceptionAcrossExecutionBoundaries-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/ERR59-CPP/DoNotThrowAnExceptionAcrossExecutionBoundaries-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/ERR59-CPP/DoNotThrowAnExceptionAcrossExecutionBoundaries.qhelp b/cpp/cert/src/rules/ERR59-CPP/DoNotThrowAnExceptionAcrossExecutionBoundaries.qhelp index ab2e069b43..46a5bf7c99 100644 --- a/cpp/cert/src/rules/ERR59-CPP/DoNotThrowAnExceptionAcrossExecutionBoundaries.qhelp +++ b/cpp/cert/src/rules/ERR59-CPP/DoNotThrowAnExceptionAcrossExecutionBoundaries.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/ERR60-CPP/ExceptionObjectsMustBeNothrowCopyConstructible-implementation.qhelp b/cpp/cert/src/rules/ERR60-CPP/ExceptionObjectsMustBeNothrowCopyConstructible-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/ERR60-CPP/ExceptionObjectsMustBeNothrowCopyConstructible-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/ERR60-CPP/ExceptionObjectsMustBeNothrowCopyConstructible.qhelp b/cpp/cert/src/rules/ERR60-CPP/ExceptionObjectsMustBeNothrowCopyConstructible.qhelp index e8390cab03..0c8a21a0e0 100644 --- a/cpp/cert/src/rules/ERR60-CPP/ExceptionObjectsMustBeNothrowCopyConstructible.qhelp +++ b/cpp/cert/src/rules/ERR60-CPP/ExceptionObjectsMustBeNothrowCopyConstructible.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/ERR61-CPP/CatchExceptionsByLvalueReference-implementation.qhelp b/cpp/cert/src/rules/ERR61-CPP/CatchExceptionsByLvalueReference-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/ERR61-CPP/CatchExceptionsByLvalueReference-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/ERR61-CPP/CatchExceptionsByLvalueReference.qhelp b/cpp/cert/src/rules/ERR61-CPP/CatchExceptionsByLvalueReference.qhelp index 96bbff9709..024d2d9d5b 100644 --- a/cpp/cert/src/rules/ERR61-CPP/CatchExceptionsByLvalueReference.qhelp +++ b/cpp/cert/src/rules/ERR61-CPP/CatchExceptionsByLvalueReference.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/ERR62-CPP/DetectErrorsWhenConvertingAStringToANumber-implementation.qhelp b/cpp/cert/src/rules/ERR62-CPP/DetectErrorsWhenConvertingAStringToANumber-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/ERR62-CPP/DetectErrorsWhenConvertingAStringToANumber-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/ERR62-CPP/DetectErrorsWhenConvertingAStringToANumber.qhelp b/cpp/cert/src/rules/ERR62-CPP/DetectErrorsWhenConvertingAStringToANumber.qhelp index 9fd4014c2c..a4d5567099 100644 --- a/cpp/cert/src/rules/ERR62-CPP/DetectErrorsWhenConvertingAStringToANumber.qhelp +++ b/cpp/cert/src/rules/ERR62-CPP/DetectErrorsWhenConvertingAStringToANumber.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments-implementation.qhelp b/cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.qhelp b/cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.qhelp index 30485d51cd..98ea01687f 100644 --- a/cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.qhelp +++ b/cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfScalarObjectEvaluationForSideEffects-implementation.qhelp b/cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfScalarObjectEvaluationForSideEffects-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfScalarObjectEvaluationForSideEffects-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfScalarObjectEvaluationForSideEffects.qhelp b/cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfScalarObjectEvaluationForSideEffects.qhelp index 699dcae3ba..2e2043586f 100644 --- a/cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfScalarObjectEvaluationForSideEffects.qhelp +++ b/cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfScalarObjectEvaluationForSideEffects.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType-implementation.qhelp b/cpp/cert/src/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.qhelp b/cpp/cert/src/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.qhelp index bab2733028..d4221a920e 100644 --- a/cpp/cert/src/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.qhelp +++ b/cpp/cert/src/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclTypeOperand-implementation.qhelp b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclTypeOperand-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclTypeOperand-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclTypeOperand.qhelp b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclTypeOperand.qhelp index 5c737b5cb7..61fb64f7b0 100644 --- a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclTypeOperand.qhelp +++ b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclTypeOperand.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclValExpression-implementation.qhelp b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclValExpression-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclValExpression-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclValExpression.qhelp b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclValExpression.qhelp index e61f7fd5f9..16e28086e6 100644 --- a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclValExpression.qhelp +++ b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclValExpression.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInNoExceptOperand-implementation.qhelp b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInNoExceptOperand-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInNoExceptOperand-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInNoExceptOperand.qhelp b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInNoExceptOperand.qhelp index 3ca2680fa0..cb380a43a5 100644 --- a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInNoExceptOperand.qhelp +++ b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInNoExceptOperand.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInSizeOfOperand-implementation.qhelp b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInSizeOfOperand-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInSizeOfOperand-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInSizeOfOperand.qhelp b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInSizeOfOperand.qhelp index 854075684e..29ba45f75d 100644 --- a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInSizeOfOperand.qhelp +++ b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInSizeOfOperand.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInTypeIdOperand-implementation.qhelp b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInTypeIdOperand-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInTypeIdOperand-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInTypeIdOperand.qhelp b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInTypeIdOperand.qhelp index ebaa58fa52..0050a16236 100644 --- a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInTypeIdOperand.qhelp +++ b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInTypeIdOperand.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/EXP53-CPP/DoNotReadUninitializedMemory-implementation.qhelp b/cpp/cert/src/rules/EXP53-CPP/DoNotReadUninitializedMemory-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/EXP53-CPP/DoNotReadUninitializedMemory-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/EXP53-CPP/DoNotReadUninitializedMemory.qhelp b/cpp/cert/src/rules/EXP53-CPP/DoNotReadUninitializedMemory.qhelp index 92cb07e3fa..163b713517 100644 --- a/cpp/cert/src/rules/EXP53-CPP/DoNotReadUninitializedMemory.qhelp +++ b/cpp/cert/src/rules/EXP53-CPP/DoNotReadUninitializedMemory.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/EXP54-CPP/ObjectAccessedAfterLifetimeCert-implementation.qhelp b/cpp/cert/src/rules/EXP54-CPP/ObjectAccessedAfterLifetimeCert-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/EXP54-CPP/ObjectAccessedAfterLifetimeCert-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/EXP54-CPP/ObjectAccessedAfterLifetimeCert.qhelp b/cpp/cert/src/rules/EXP54-CPP/ObjectAccessedAfterLifetimeCert.qhelp index b70aed5741..30ec446462 100644 --- a/cpp/cert/src/rules/EXP54-CPP/ObjectAccessedAfterLifetimeCert.qhelp +++ b/cpp/cert/src/rules/EXP54-CPP/ObjectAccessedAfterLifetimeCert.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/EXP54-CPP/ObjectAccessedBeforeLifetimeCert-implementation.qhelp b/cpp/cert/src/rules/EXP54-CPP/ObjectAccessedBeforeLifetimeCert-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/EXP54-CPP/ObjectAccessedBeforeLifetimeCert-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/EXP54-CPP/ObjectAccessedBeforeLifetimeCert.qhelp b/cpp/cert/src/rules/EXP54-CPP/ObjectAccessedBeforeLifetimeCert.qhelp index 594bededd7..c2c00bf442 100644 --- a/cpp/cert/src/rules/EXP54-CPP/ObjectAccessedBeforeLifetimeCert.qhelp +++ b/cpp/cert/src/rules/EXP54-CPP/ObjectAccessedBeforeLifetimeCert.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/EXP55-CPP/RemoveConstOrVolatileQualificationCert-implementation.qhelp b/cpp/cert/src/rules/EXP55-CPP/RemoveConstOrVolatileQualificationCert-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/EXP55-CPP/RemoveConstOrVolatileQualificationCert-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/EXP55-CPP/RemoveConstOrVolatileQualificationCert.qhelp b/cpp/cert/src/rules/EXP55-CPP/RemoveConstOrVolatileQualificationCert.qhelp index 97c36b86d1..4c4bca1e51 100644 --- a/cpp/cert/src/rules/EXP55-CPP/RemoveConstOrVolatileQualificationCert.qhelp +++ b/cpp/cert/src/rules/EXP55-CPP/RemoveConstOrVolatileQualificationCert.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/EXP56-CPP/FunctionWithMismatchedLanguageLinkage-implementation.qhelp b/cpp/cert/src/rules/EXP56-CPP/FunctionWithMismatchedLanguageLinkage-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/EXP56-CPP/FunctionWithMismatchedLanguageLinkage-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/EXP56-CPP/FunctionWithMismatchedLanguageLinkage.qhelp b/cpp/cert/src/rules/EXP56-CPP/FunctionWithMismatchedLanguageLinkage.qhelp index 5c75dda2fd..63512d0915 100644 --- a/cpp/cert/src/rules/EXP56-CPP/FunctionWithMismatchedLanguageLinkage.qhelp +++ b/cpp/cert/src/rules/EXP56-CPP/FunctionWithMismatchedLanguageLinkage.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/EXP57-CPP/CastOfPointerToIncompleteClass-implementation.qhelp b/cpp/cert/src/rules/EXP57-CPP/CastOfPointerToIncompleteClass-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/EXP57-CPP/CastOfPointerToIncompleteClass-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/EXP57-CPP/CastOfPointerToIncompleteClass.qhelp b/cpp/cert/src/rules/EXP57-CPP/CastOfPointerToIncompleteClass.qhelp index 8c52759b7a..c7a9a20a8e 100644 --- a/cpp/cert/src/rules/EXP57-CPP/CastOfPointerToIncompleteClass.qhelp +++ b/cpp/cert/src/rules/EXP57-CPP/CastOfPointerToIncompleteClass.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/EXP57-CPP/DeletingPointerToIncompleteClass-implementation.qhelp b/cpp/cert/src/rules/EXP57-CPP/DeletingPointerToIncompleteClass-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/EXP57-CPP/DeletingPointerToIncompleteClass-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/EXP57-CPP/DeletingPointerToIncompleteClass.qhelp b/cpp/cert/src/rules/EXP57-CPP/DeletingPointerToIncompleteClass.qhelp index 09bb4a5719..520541c4ed 100644 --- a/cpp/cert/src/rules/EXP57-CPP/DeletingPointerToIncompleteClass.qhelp +++ b/cpp/cert/src/rules/EXP57-CPP/DeletingPointerToIncompleteClass.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/EXP58-CPP/PassNonTrivialObjectToVaStart-implementation.qhelp b/cpp/cert/src/rules/EXP58-CPP/PassNonTrivialObjectToVaStart-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/EXP58-CPP/PassNonTrivialObjectToVaStart-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/EXP58-CPP/PassNonTrivialObjectToVaStart.qhelp b/cpp/cert/src/rules/EXP58-CPP/PassNonTrivialObjectToVaStart.qhelp index d6dc4cf082..83cd57e245 100644 --- a/cpp/cert/src/rules/EXP58-CPP/PassNonTrivialObjectToVaStart.qhelp +++ b/cpp/cert/src/rules/EXP58-CPP/PassNonTrivialObjectToVaStart.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/EXP58-CPP/PassPromotablePrimitiveTypeToVaStart-implementation.qhelp b/cpp/cert/src/rules/EXP58-CPP/PassPromotablePrimitiveTypeToVaStart-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/EXP58-CPP/PassPromotablePrimitiveTypeToVaStart-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/EXP58-CPP/PassPromotablePrimitiveTypeToVaStart.qhelp b/cpp/cert/src/rules/EXP58-CPP/PassPromotablePrimitiveTypeToVaStart.qhelp index 35845e58ca..c0df5abcf6 100644 --- a/cpp/cert/src/rules/EXP58-CPP/PassPromotablePrimitiveTypeToVaStart.qhelp +++ b/cpp/cert/src/rules/EXP58-CPP/PassPromotablePrimitiveTypeToVaStart.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/EXP58-CPP/PassReferenceTypeToVaStart-implementation.qhelp b/cpp/cert/src/rules/EXP58-CPP/PassReferenceTypeToVaStart-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/EXP58-CPP/PassReferenceTypeToVaStart-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/EXP58-CPP/PassReferenceTypeToVaStart.qhelp b/cpp/cert/src/rules/EXP58-CPP/PassReferenceTypeToVaStart.qhelp index c8fa7c609e..3405f83f2a 100644 --- a/cpp/cert/src/rules/EXP58-CPP/PassReferenceTypeToVaStart.qhelp +++ b/cpp/cert/src/rules/EXP58-CPP/PassReferenceTypeToVaStart.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/EXP59-CPP/OffsetUsedOnInvalidTypeOrMember-implementation.qhelp b/cpp/cert/src/rules/EXP59-CPP/OffsetUsedOnInvalidTypeOrMember-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/EXP59-CPP/OffsetUsedOnInvalidTypeOrMember-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/EXP59-CPP/OffsetUsedOnInvalidTypeOrMember.qhelp b/cpp/cert/src/rules/EXP59-CPP/OffsetUsedOnInvalidTypeOrMember.qhelp index 5d10c114db..9c422eb68c 100644 --- a/cpp/cert/src/rules/EXP59-CPP/OffsetUsedOnInvalidTypeOrMember.qhelp +++ b/cpp/cert/src/rules/EXP59-CPP/OffsetUsedOnInvalidTypeOrMember.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/EXP60-CPP/DoNotPassANonstandardObjectAcrossBoundaries-implementation.qhelp b/cpp/cert/src/rules/EXP60-CPP/DoNotPassANonstandardObjectAcrossBoundaries-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/EXP60-CPP/DoNotPassANonstandardObjectAcrossBoundaries-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/EXP60-CPP/DoNotPassANonstandardObjectAcrossBoundaries.qhelp b/cpp/cert/src/rules/EXP60-CPP/DoNotPassANonstandardObjectAcrossBoundaries.qhelp index a48b6f90f0..25f5f152eb 100644 --- a/cpp/cert/src/rules/EXP60-CPP/DoNotPassANonstandardObjectAcrossBoundaries.qhelp +++ b/cpp/cert/src/rules/EXP60-CPP/DoNotPassANonstandardObjectAcrossBoundaries.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/EXP61-CPP/EscapingLambdaObjectWithCaptureByReference-implementation.qhelp b/cpp/cert/src/rules/EXP61-CPP/EscapingLambdaObjectWithCaptureByReference-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/EXP61-CPP/EscapingLambdaObjectWithCaptureByReference-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/EXP61-CPP/EscapingLambdaObjectWithCaptureByReference.qhelp b/cpp/cert/src/rules/EXP61-CPP/EscapingLambdaObjectWithCaptureByReference.qhelp index 561708c291..47350453c2 100644 --- a/cpp/cert/src/rules/EXP61-CPP/EscapingLambdaObjectWithCaptureByReference.qhelp +++ b/cpp/cert/src/rules/EXP61-CPP/EscapingLambdaObjectWithCaptureByReference.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/EXP61-CPP/ReturningLambdaObjectWithCaptureByReference-implementation.qhelp b/cpp/cert/src/rules/EXP61-CPP/ReturningLambdaObjectWithCaptureByReference-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/EXP61-CPP/ReturningLambdaObjectWithCaptureByReference-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/EXP61-CPP/ReturningLambdaObjectWithCaptureByReference.qhelp b/cpp/cert/src/rules/EXP61-CPP/ReturningLambdaObjectWithCaptureByReference.qhelp index 365bf5cd85..14b0826e4f 100644 --- a/cpp/cert/src/rules/EXP61-CPP/ReturningLambdaObjectWithCaptureByReference.qhelp +++ b/cpp/cert/src/rules/EXP61-CPP/ReturningLambdaObjectWithCaptureByReference.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/EXP62-CPP/MemcmpUsedToAccessObjectRepresentation-implementation.qhelp b/cpp/cert/src/rules/EXP62-CPP/MemcmpUsedToAccessObjectRepresentation-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/EXP62-CPP/MemcmpUsedToAccessObjectRepresentation-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/EXP62-CPP/MemcmpUsedToAccessObjectRepresentation.qhelp b/cpp/cert/src/rules/EXP62-CPP/MemcmpUsedToAccessObjectRepresentation.qhelp index 70ee335874..d974ca606e 100644 --- a/cpp/cert/src/rules/EXP62-CPP/MemcmpUsedToAccessObjectRepresentation.qhelp +++ b/cpp/cert/src/rules/EXP62-CPP/MemcmpUsedToAccessObjectRepresentation.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/EXP62-CPP/MemcpyUsedToAccessObjectRepresentation-implementation.qhelp b/cpp/cert/src/rules/EXP62-CPP/MemcpyUsedToAccessObjectRepresentation-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/EXP62-CPP/MemcpyUsedToAccessObjectRepresentation-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/EXP62-CPP/MemcpyUsedToAccessObjectRepresentation.qhelp b/cpp/cert/src/rules/EXP62-CPP/MemcpyUsedToAccessObjectRepresentation.qhelp index 9709abc106..70f10334c2 100644 --- a/cpp/cert/src/rules/EXP62-CPP/MemcpyUsedToAccessObjectRepresentation.qhelp +++ b/cpp/cert/src/rules/EXP62-CPP/MemcpyUsedToAccessObjectRepresentation.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/EXP62-CPP/MemsetUsedToAccessObjectRepresentation-implementation.qhelp b/cpp/cert/src/rules/EXP62-CPP/MemsetUsedToAccessObjectRepresentation-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/EXP62-CPP/MemsetUsedToAccessObjectRepresentation-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/EXP62-CPP/MemsetUsedToAccessObjectRepresentation.qhelp b/cpp/cert/src/rules/EXP62-CPP/MemsetUsedToAccessObjectRepresentation.qhelp index 8807a291d8..ef2663ac6f 100644 --- a/cpp/cert/src/rules/EXP62-CPP/MemsetUsedToAccessObjectRepresentation.qhelp +++ b/cpp/cert/src/rules/EXP62-CPP/MemsetUsedToAccessObjectRepresentation.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/EXP63-CPP/DoNotRelyOnTheValueOfAMovedFromObject-implementation.qhelp b/cpp/cert/src/rules/EXP63-CPP/DoNotRelyOnTheValueOfAMovedFromObject-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/EXP63-CPP/DoNotRelyOnTheValueOfAMovedFromObject-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/EXP63-CPP/DoNotRelyOnTheValueOfAMovedFromObject.qhelp b/cpp/cert/src/rules/EXP63-CPP/DoNotRelyOnTheValueOfAMovedFromObject.qhelp index 4e38c3b1c0..cf87df9f2a 100644 --- a/cpp/cert/src/rules/EXP63-CPP/DoNotRelyOnTheValueOfAMovedFromObject.qhelp +++ b/cpp/cert/src/rules/EXP63-CPP/DoNotRelyOnTheValueOfAMovedFromObject.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/FIO50-CPP/InterleavedInputOutputWithoutPosition-implementation.qhelp b/cpp/cert/src/rules/FIO50-CPP/InterleavedInputOutputWithoutPosition-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/FIO50-CPP/InterleavedInputOutputWithoutPosition-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/FIO50-CPP/InterleavedInputOutputWithoutPosition.qhelp b/cpp/cert/src/rules/FIO50-CPP/InterleavedInputOutputWithoutPosition.qhelp index 9e842328e5..7241204eef 100644 --- a/cpp/cert/src/rules/FIO50-CPP/InterleavedInputOutputWithoutPosition.qhelp +++ b/cpp/cert/src/rules/FIO50-CPP/InterleavedInputOutputWithoutPosition.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/FIO51-CPP/CloseFilesWhenTheyAreNoLongerNeeded-implementation.qhelp b/cpp/cert/src/rules/FIO51-CPP/CloseFilesWhenTheyAreNoLongerNeeded-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/FIO51-CPP/CloseFilesWhenTheyAreNoLongerNeeded-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/FIO51-CPP/CloseFilesWhenTheyAreNoLongerNeeded.qhelp b/cpp/cert/src/rules/FIO51-CPP/CloseFilesWhenTheyAreNoLongerNeeded.qhelp index 6cb834b3c4..c4f28931d5 100644 --- a/cpp/cert/src/rules/FIO51-CPP/CloseFilesWhenTheyAreNoLongerNeeded.qhelp +++ b/cpp/cert/src/rules/FIO51-CPP/CloseFilesWhenTheyAreNoLongerNeeded.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/INT50-CPP/DoNotCastToAnOutOfRangeEnumerationValue-implementation.qhelp b/cpp/cert/src/rules/INT50-CPP/DoNotCastToAnOutOfRangeEnumerationValue-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/INT50-CPP/DoNotCastToAnOutOfRangeEnumerationValue-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/INT50-CPP/DoNotCastToAnOutOfRangeEnumerationValue.qhelp b/cpp/cert/src/rules/INT50-CPP/DoNotCastToAnOutOfRangeEnumerationValue.qhelp index 25a87e7213..3876482d71 100644 --- a/cpp/cert/src/rules/INT50-CPP/DoNotCastToAnOutOfRangeEnumerationValue.qhelp +++ b/cpp/cert/src/rules/INT50-CPP/DoNotCastToAnOutOfRangeEnumerationValue.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/MEM50-CPP/UseAfterFree-implementation.qhelp b/cpp/cert/src/rules/MEM50-CPP/UseAfterFree-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/MEM50-CPP/UseAfterFree-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/MEM50-CPP/UseAfterFree.qhelp b/cpp/cert/src/rules/MEM50-CPP/UseAfterFree.qhelp index e3b5de6a2b..6038851fba 100644 --- a/cpp/cert/src/rules/MEM50-CPP/UseAfterFree.qhelp +++ b/cpp/cert/src/rules/MEM50-CPP/UseAfterFree.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/MEM51-CPP/ProperlyDeallocateDynamicallyAllocatedResources-implementation.qhelp b/cpp/cert/src/rules/MEM51-CPP/ProperlyDeallocateDynamicallyAllocatedResources-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/MEM51-CPP/ProperlyDeallocateDynamicallyAllocatedResources-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/MEM51-CPP/ProperlyDeallocateDynamicallyAllocatedResources.qhelp b/cpp/cert/src/rules/MEM51-CPP/ProperlyDeallocateDynamicallyAllocatedResources.qhelp index 6ec536afe9..b199f60451 100644 --- a/cpp/cert/src/rules/MEM51-CPP/ProperlyDeallocateDynamicallyAllocatedResources.qhelp +++ b/cpp/cert/src/rules/MEM51-CPP/ProperlyDeallocateDynamicallyAllocatedResources.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/MEM52-CPP/DetectAndHandleMemoryAllocationErrors-implementation.qhelp b/cpp/cert/src/rules/MEM52-CPP/DetectAndHandleMemoryAllocationErrors-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/MEM52-CPP/DetectAndHandleMemoryAllocationErrors-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/MEM52-CPP/DetectAndHandleMemoryAllocationErrors.qhelp b/cpp/cert/src/rules/MEM52-CPP/DetectAndHandleMemoryAllocationErrors.qhelp index 41775fd8d2..3155e7f4d8 100644 --- a/cpp/cert/src/rules/MEM52-CPP/DetectAndHandleMemoryAllocationErrors.qhelp +++ b/cpp/cert/src/rules/MEM52-CPP/DetectAndHandleMemoryAllocationErrors.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/MEM53-CPP/MissingConstructorCallForManuallyManagedObject-implementation.qhelp b/cpp/cert/src/rules/MEM53-CPP/MissingConstructorCallForManuallyManagedObject-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/MEM53-CPP/MissingConstructorCallForManuallyManagedObject-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/MEM53-CPP/MissingConstructorCallForManuallyManagedObject.qhelp b/cpp/cert/src/rules/MEM53-CPP/MissingConstructorCallForManuallyManagedObject.qhelp index cd10bab2fe..3a0979f97b 100644 --- a/cpp/cert/src/rules/MEM53-CPP/MissingConstructorCallForManuallyManagedObject.qhelp +++ b/cpp/cert/src/rules/MEM53-CPP/MissingConstructorCallForManuallyManagedObject.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/MEM53-CPP/MissingDestructorCallForManuallyManagedObject-implementation.qhelp b/cpp/cert/src/rules/MEM53-CPP/MissingDestructorCallForManuallyManagedObject-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/MEM53-CPP/MissingDestructorCallForManuallyManagedObject-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/MEM53-CPP/MissingDestructorCallForManuallyManagedObject.qhelp b/cpp/cert/src/rules/MEM53-CPP/MissingDestructorCallForManuallyManagedObject.qhelp index 76b5d56818..1f026cc345 100644 --- a/cpp/cert/src/rules/MEM53-CPP/MissingDestructorCallForManuallyManagedObject.qhelp +++ b/cpp/cert/src/rules/MEM53-CPP/MissingDestructorCallForManuallyManagedObject.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/MEM54-CPP/PlacementNewInsufficientStorageCert-implementation.qhelp b/cpp/cert/src/rules/MEM54-CPP/PlacementNewInsufficientStorageCert-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/MEM54-CPP/PlacementNewInsufficientStorageCert-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/MEM54-CPP/PlacementNewInsufficientStorageCert.qhelp b/cpp/cert/src/rules/MEM54-CPP/PlacementNewInsufficientStorageCert.qhelp index 802d356750..180d3837f4 100644 --- a/cpp/cert/src/rules/MEM54-CPP/PlacementNewInsufficientStorageCert.qhelp +++ b/cpp/cert/src/rules/MEM54-CPP/PlacementNewInsufficientStorageCert.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/MEM54-CPP/PlacementNewNotProperlyAlignedCert-implementation.qhelp b/cpp/cert/src/rules/MEM54-CPP/PlacementNewNotProperlyAlignedCert-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/MEM54-CPP/PlacementNewNotProperlyAlignedCert-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/MEM54-CPP/PlacementNewNotProperlyAlignedCert.qhelp b/cpp/cert/src/rules/MEM54-CPP/PlacementNewNotProperlyAlignedCert.qhelp index 93f8399f1b..d477c38ce6 100644 --- a/cpp/cert/src/rules/MEM54-CPP/PlacementNewNotProperlyAlignedCert.qhelp +++ b/cpp/cert/src/rules/MEM54-CPP/PlacementNewNotProperlyAlignedCert.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/MEM55-CPP/OperatorDeleteMissingPartnerCert-implementation.qhelp b/cpp/cert/src/rules/MEM55-CPP/OperatorDeleteMissingPartnerCert-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/MEM55-CPP/OperatorDeleteMissingPartnerCert-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/MEM55-CPP/OperatorDeleteMissingPartnerCert.qhelp b/cpp/cert/src/rules/MEM55-CPP/OperatorDeleteMissingPartnerCert.qhelp index 74b4259210..c9ddb67c0e 100644 --- a/cpp/cert/src/rules/MEM55-CPP/OperatorDeleteMissingPartnerCert.qhelp +++ b/cpp/cert/src/rules/MEM55-CPP/OperatorDeleteMissingPartnerCert.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/MEM55-CPP/ThrowingNoThrowOperatorNewDeleteCert-implementation.qhelp b/cpp/cert/src/rules/MEM55-CPP/ThrowingNoThrowOperatorNewDeleteCert-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/MEM55-CPP/ThrowingNoThrowOperatorNewDeleteCert-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/MEM55-CPP/ThrowingNoThrowOperatorNewDeleteCert.qhelp b/cpp/cert/src/rules/MEM55-CPP/ThrowingNoThrowOperatorNewDeleteCert.qhelp index 24b1f19164..9f878aa7c0 100644 --- a/cpp/cert/src/rules/MEM55-CPP/ThrowingNoThrowOperatorNewDeleteCert.qhelp +++ b/cpp/cert/src/rules/MEM55-CPP/ThrowingNoThrowOperatorNewDeleteCert.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewReturnsNullCert-implementation.qhelp b/cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewReturnsNullCert-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewReturnsNullCert-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewReturnsNullCert.qhelp b/cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewReturnsNullCert.qhelp index fb683fda9a..d6125106e8 100644 --- a/cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewReturnsNullCert.qhelp +++ b/cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewReturnsNullCert.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewThrowsInvalidExceptionCert-implementation.qhelp b/cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewThrowsInvalidExceptionCert-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewThrowsInvalidExceptionCert-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewThrowsInvalidExceptionCert.qhelp b/cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewThrowsInvalidExceptionCert.qhelp index 1579bf3922..1d4ae1f835 100644 --- a/cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewThrowsInvalidExceptionCert.qhelp +++ b/cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewThrowsInvalidExceptionCert.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/MEM56-CPP/OwnedPointerValueStoredInUnrelatedSmartPointerCert-implementation.qhelp b/cpp/cert/src/rules/MEM56-CPP/OwnedPointerValueStoredInUnrelatedSmartPointerCert-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/MEM56-CPP/OwnedPointerValueStoredInUnrelatedSmartPointerCert-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/MEM56-CPP/OwnedPointerValueStoredInUnrelatedSmartPointerCert.qhelp b/cpp/cert/src/rules/MEM56-CPP/OwnedPointerValueStoredInUnrelatedSmartPointerCert.qhelp index ccbf2c9419..3f6689d244 100644 --- a/cpp/cert/src/rules/MEM56-CPP/OwnedPointerValueStoredInUnrelatedSmartPointerCert.qhelp +++ b/cpp/cert/src/rules/MEM56-CPP/OwnedPointerValueStoredInUnrelatedSmartPointerCert.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/MEM57-CPP/UsingDefaultOperatorNewForOverAlignedTypes-implementation.qhelp b/cpp/cert/src/rules/MEM57-CPP/UsingDefaultOperatorNewForOverAlignedTypes-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/MEM57-CPP/UsingDefaultOperatorNewForOverAlignedTypes-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/MEM57-CPP/UsingDefaultOperatorNewForOverAlignedTypes.qhelp b/cpp/cert/src/rules/MEM57-CPP/UsingDefaultOperatorNewForOverAlignedTypes.qhelp index b9db9ba421..dbe04bcf7a 100644 --- a/cpp/cert/src/rules/MEM57-CPP/UsingDefaultOperatorNewForOverAlignedTypes.qhelp +++ b/cpp/cert/src/rules/MEM57-CPP/UsingDefaultOperatorNewForOverAlignedTypes.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/MSC50-CPP/DoNotUseRandForGeneratingPseudorandomNumbers-implementation.qhelp b/cpp/cert/src/rules/MSC50-CPP/DoNotUseRandForGeneratingPseudorandomNumbers-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/MSC50-CPP/DoNotUseRandForGeneratingPseudorandomNumbers-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/MSC50-CPP/DoNotUseRandForGeneratingPseudorandomNumbers.qhelp b/cpp/cert/src/rules/MSC50-CPP/DoNotUseRandForGeneratingPseudorandomNumbers.qhelp index 34cd311084..ae3d8bd918 100644 --- a/cpp/cert/src/rules/MSC50-CPP/DoNotUseRandForGeneratingPseudorandomNumbers.qhelp +++ b/cpp/cert/src/rules/MSC50-CPP/DoNotUseRandForGeneratingPseudorandomNumbers.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/MSC50-CPP/DoNotUseRandForGeneratingPseudorandomNumbers.ql b/cpp/cert/src/rules/MSC50-CPP/DoNotUseRandForGeneratingPseudorandomNumbers.ql index 28467b825f..ea2f3be3e5 100644 --- a/cpp/cert/src/rules/MSC50-CPP/DoNotUseRandForGeneratingPseudorandomNumbers.ql +++ b/cpp/cert/src/rules/MSC50-CPP/DoNotUseRandForGeneratingPseudorandomNumbers.ql @@ -12,11 +12,10 @@ import cpp import codingstandards.cpp.cert +import codingstandards.cpp.rules.donotuserandforgeneratingpseudorandomnumbers.DoNotUseRandForGeneratingPseudorandomNumbers -predicate isRand(FunctionCall fc) { fc.getTarget().hasGlobalOrStdName("rand") } - -from FunctionCall fc -where - not isExcluded(fc, BannedFunctionsPackage::doNotUseRandForGeneratingPseudorandomNumbersQuery()) and - isRand(fc) -select fc, "Use of banned function " + fc.getTarget().getQualifiedName() + "." +class DoNotUseRandForGeneratingPseudorandomNumbersQuery extends DoNotUseRandForGeneratingPseudorandomNumbersSharedQuery { + DoNotUseRandForGeneratingPseudorandomNumbersQuery() { + this = BannedFunctionsPackage::doNotUseRandForGeneratingPseudorandomNumbersQuery() + } +} diff --git a/cpp/cert/src/rules/MSC51-CPP/BadlySeededRandomNumberGenerator-implementation.qhelp b/cpp/cert/src/rules/MSC51-CPP/BadlySeededRandomNumberGenerator-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/MSC51-CPP/BadlySeededRandomNumberGenerator-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/MSC51-CPP/BadlySeededRandomNumberGenerator.qhelp b/cpp/cert/src/rules/MSC51-CPP/BadlySeededRandomNumberGenerator.qhelp index 84e3c43ebc..5e7142dc63 100644 --- a/cpp/cert/src/rules/MSC51-CPP/BadlySeededRandomNumberGenerator.qhelp +++ b/cpp/cert/src/rules/MSC51-CPP/BadlySeededRandomNumberGenerator.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/MSC52-CPP/NonVoidFunctionDoesNotReturnCert-implementation.qhelp b/cpp/cert/src/rules/MSC52-CPP/NonVoidFunctionDoesNotReturnCert-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/MSC52-CPP/NonVoidFunctionDoesNotReturnCert-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/MSC52-CPP/NonVoidFunctionDoesNotReturnCert.qhelp b/cpp/cert/src/rules/MSC52-CPP/NonVoidFunctionDoesNotReturnCert.qhelp index 6b483ec441..ee98722262 100644 --- a/cpp/cert/src/rules/MSC52-CPP/NonVoidFunctionDoesNotReturnCert.qhelp +++ b/cpp/cert/src/rules/MSC52-CPP/NonVoidFunctionDoesNotReturnCert.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/MSC53-CPP/FunctionNoReturnAttributeConditionCert-implementation.qhelp b/cpp/cert/src/rules/MSC53-CPP/FunctionNoReturnAttributeConditionCert-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/MSC53-CPP/FunctionNoReturnAttributeConditionCert-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/MSC53-CPP/FunctionNoReturnAttributeConditionCert.qhelp b/cpp/cert/src/rules/MSC53-CPP/FunctionNoReturnAttributeConditionCert.qhelp index 626d147afc..8c0ae3f926 100644 --- a/cpp/cert/src/rules/MSC53-CPP/FunctionNoReturnAttributeConditionCert.qhelp +++ b/cpp/cert/src/rules/MSC53-CPP/FunctionNoReturnAttributeConditionCert.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/MSC54-CPP/SignalHandlerMustBeAPlainOldFunction-implementation.qhelp b/cpp/cert/src/rules/MSC54-CPP/SignalHandlerMustBeAPlainOldFunction-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/MSC54-CPP/SignalHandlerMustBeAPlainOldFunction-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/MSC54-CPP/SignalHandlerMustBeAPlainOldFunction.qhelp b/cpp/cert/src/rules/MSC54-CPP/SignalHandlerMustBeAPlainOldFunction.qhelp index 0090cc162e..ec6d3c36a5 100644 --- a/cpp/cert/src/rules/MSC54-CPP/SignalHandlerMustBeAPlainOldFunction.qhelp +++ b/cpp/cert/src/rules/MSC54-CPP/SignalHandlerMustBeAPlainOldFunction.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/OOP50-CPP/DoNotInvokeVirtualFunctionsFromConstructorsOrDestructors-implementation.qhelp b/cpp/cert/src/rules/OOP50-CPP/DoNotInvokeVirtualFunctionsFromConstructorsOrDestructors-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/OOP50-CPP/DoNotInvokeVirtualFunctionsFromConstructorsOrDestructors-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/OOP50-CPP/DoNotInvokeVirtualFunctionsFromConstructorsOrDestructors.qhelp b/cpp/cert/src/rules/OOP50-CPP/DoNotInvokeVirtualFunctionsFromConstructorsOrDestructors.qhelp index 5b29f05c2f..1eb3013748 100644 --- a/cpp/cert/src/rules/OOP50-CPP/DoNotInvokeVirtualFunctionsFromConstructorsOrDestructors.qhelp +++ b/cpp/cert/src/rules/OOP50-CPP/DoNotInvokeVirtualFunctionsFromConstructorsOrDestructors.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/OOP51-CPP/DoNotSliceDerivedObjects-implementation.qhelp b/cpp/cert/src/rules/OOP51-CPP/DoNotSliceDerivedObjects-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/OOP51-CPP/DoNotSliceDerivedObjects-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/OOP51-CPP/DoNotSliceDerivedObjects.qhelp b/cpp/cert/src/rules/OOP51-CPP/DoNotSliceDerivedObjects.qhelp index 4747aa95ce..a17536cd98 100644 --- a/cpp/cert/src/rules/OOP51-CPP/DoNotSliceDerivedObjects.qhelp +++ b/cpp/cert/src/rules/OOP51-CPP/DoNotSliceDerivedObjects.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/OOP52-CPP/DoNotDeleteAPolymorphicObjectWithoutAVirtualDestructor-implementation.qhelp b/cpp/cert/src/rules/OOP52-CPP/DoNotDeleteAPolymorphicObjectWithoutAVirtualDestructor-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/OOP52-CPP/DoNotDeleteAPolymorphicObjectWithoutAVirtualDestructor-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/OOP52-CPP/DoNotDeleteAPolymorphicObjectWithoutAVirtualDestructor.qhelp b/cpp/cert/src/rules/OOP52-CPP/DoNotDeleteAPolymorphicObjectWithoutAVirtualDestructor.qhelp index 3f48aa04eb..6e42d3cc05 100644 --- a/cpp/cert/src/rules/OOP52-CPP/DoNotDeleteAPolymorphicObjectWithoutAVirtualDestructor.qhelp +++ b/cpp/cert/src/rules/OOP52-CPP/DoNotDeleteAPolymorphicObjectWithoutAVirtualDestructor.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/OOP52-CPP/standard-example.cpp b/cpp/cert/src/rules/OOP52-CPP/standard-example.cpp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/cpp/cert/src/rules/OOP53-CPP/UseCanonicalOrderForMemberInit-implementation.qhelp b/cpp/cert/src/rules/OOP53-CPP/UseCanonicalOrderForMemberInit-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/OOP53-CPP/UseCanonicalOrderForMemberInit-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/OOP53-CPP/UseCanonicalOrderForMemberInit.qhelp b/cpp/cert/src/rules/OOP53-CPP/UseCanonicalOrderForMemberInit.qhelp index f2016bd3d8..a889e932bd 100644 --- a/cpp/cert/src/rules/OOP53-CPP/UseCanonicalOrderForMemberInit.qhelp +++ b/cpp/cert/src/rules/OOP53-CPP/UseCanonicalOrderForMemberInit.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/OOP54-CPP/GracefullyHandleSelfCopyAssignment-implementation.qhelp b/cpp/cert/src/rules/OOP54-CPP/GracefullyHandleSelfCopyAssignment-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/OOP54-CPP/GracefullyHandleSelfCopyAssignment-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/OOP54-CPP/GracefullyHandleSelfCopyAssignment.qhelp b/cpp/cert/src/rules/OOP54-CPP/GracefullyHandleSelfCopyAssignment.qhelp index e155b4552b..24ec825f7f 100644 --- a/cpp/cert/src/rules/OOP54-CPP/GracefullyHandleSelfCopyAssignment.qhelp +++ b/cpp/cert/src/rules/OOP54-CPP/GracefullyHandleSelfCopyAssignment.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/OOP55-CPP/MemberAccessWithUninitializedStaticPointerToMember-implementation.qhelp b/cpp/cert/src/rules/OOP55-CPP/MemberAccessWithUninitializedStaticPointerToMember-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/OOP55-CPP/MemberAccessWithUninitializedStaticPointerToMember-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/OOP55-CPP/MemberAccessWithUninitializedStaticPointerToMember.qhelp b/cpp/cert/src/rules/OOP55-CPP/MemberAccessWithUninitializedStaticPointerToMember.qhelp index 923368136f..d4118a33ef 100644 --- a/cpp/cert/src/rules/OOP55-CPP/MemberAccessWithUninitializedStaticPointerToMember.qhelp +++ b/cpp/cert/src/rules/OOP55-CPP/MemberAccessWithUninitializedStaticPointerToMember.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/OOP55-CPP/UseOfPointerToMemberToAccessNonexistentMember-implementation.qhelp b/cpp/cert/src/rules/OOP55-CPP/UseOfPointerToMemberToAccessNonexistentMember-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/OOP55-CPP/UseOfPointerToMemberToAccessNonexistentMember-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/OOP55-CPP/UseOfPointerToMemberToAccessNonexistentMember.qhelp b/cpp/cert/src/rules/OOP55-CPP/UseOfPointerToMemberToAccessNonexistentMember.qhelp index 3644ad6551..4c9929ef75 100644 --- a/cpp/cert/src/rules/OOP55-CPP/UseOfPointerToMemberToAccessNonexistentMember.qhelp +++ b/cpp/cert/src/rules/OOP55-CPP/UseOfPointerToMemberToAccessNonexistentMember.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/OOP55-CPP/UseOfPointerToMemberToAccessUndefinedMember-implementation.qhelp b/cpp/cert/src/rules/OOP55-CPP/UseOfPointerToMemberToAccessUndefinedMember-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/OOP55-CPP/UseOfPointerToMemberToAccessUndefinedMember-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/OOP55-CPP/UseOfPointerToMemberToAccessUndefinedMember.qhelp b/cpp/cert/src/rules/OOP55-CPP/UseOfPointerToMemberToAccessUndefinedMember.qhelp index c1ecb19027..ae912456e7 100644 --- a/cpp/cert/src/rules/OOP55-CPP/UseOfPointerToMemberToAccessUndefinedMember.qhelp +++ b/cpp/cert/src/rules/OOP55-CPP/UseOfPointerToMemberToAccessUndefinedMember.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/OOP56-CPP/HonorNewReplacementHandlerRequirements-implementation.qhelp b/cpp/cert/src/rules/OOP56-CPP/HonorNewReplacementHandlerRequirements-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/OOP56-CPP/HonorNewReplacementHandlerRequirements-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/OOP56-CPP/HonorNewReplacementHandlerRequirements.qhelp b/cpp/cert/src/rules/OOP56-CPP/HonorNewReplacementHandlerRequirements.qhelp index 95b1501a6b..0989b59e1d 100644 --- a/cpp/cert/src/rules/OOP56-CPP/HonorNewReplacementHandlerRequirements.qhelp +++ b/cpp/cert/src/rules/OOP56-CPP/HonorNewReplacementHandlerRequirements.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/OOP56-CPP/HonorTerminationReplacementHandlerRequirements-implementation.qhelp b/cpp/cert/src/rules/OOP56-CPP/HonorTerminationReplacementHandlerRequirements-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/OOP56-CPP/HonorTerminationReplacementHandlerRequirements-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/OOP56-CPP/HonorTerminationReplacementHandlerRequirements.qhelp b/cpp/cert/src/rules/OOP56-CPP/HonorTerminationReplacementHandlerRequirements.qhelp index d33ab9e086..8be1346a27 100644 --- a/cpp/cert/src/rules/OOP56-CPP/HonorTerminationReplacementHandlerRequirements.qhelp +++ b/cpp/cert/src/rules/OOP56-CPP/HonorTerminationReplacementHandlerRequirements.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/OOP57-CPP/PreferSpecialMemberFunctionsAndOverloadedOperatorsToCStandardLibraryFunctions-implementation.qhelp b/cpp/cert/src/rules/OOP57-CPP/PreferSpecialMemberFunctionsAndOverloadedOperatorsToCStandardLibraryFunctions-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/OOP57-CPP/PreferSpecialMemberFunctionsAndOverloadedOperatorsToCStandardLibraryFunctions-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/OOP57-CPP/PreferSpecialMemberFunctionsAndOverloadedOperatorsToCStandardLibraryFunctions.qhelp b/cpp/cert/src/rules/OOP57-CPP/PreferSpecialMemberFunctionsAndOverloadedOperatorsToCStandardLibraryFunctions.qhelp index a99655f0e7..e90c025f2a 100644 --- a/cpp/cert/src/rules/OOP57-CPP/PreferSpecialMemberFunctionsAndOverloadedOperatorsToCStandardLibraryFunctions.qhelp +++ b/cpp/cert/src/rules/OOP57-CPP/PreferSpecialMemberFunctionsAndOverloadedOperatorsToCStandardLibraryFunctions.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/OOP58-CPP/CopyOperationsMustNotMutateTheSourceObject-implementation.qhelp b/cpp/cert/src/rules/OOP58-CPP/CopyOperationsMustNotMutateTheSourceObject-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/OOP58-CPP/CopyOperationsMustNotMutateTheSourceObject-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/OOP58-CPP/CopyOperationsMustNotMutateTheSourceObject.qhelp b/cpp/cert/src/rules/OOP58-CPP/CopyOperationsMustNotMutateTheSourceObject.qhelp index 641d8c9ef1..b1a12b0a47 100644 --- a/cpp/cert/src/rules/OOP58-CPP/CopyOperationsMustNotMutateTheSourceObject.qhelp +++ b/cpp/cert/src/rules/OOP58-CPP/CopyOperationsMustNotMutateTheSourceObject.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/STR50-CPP/BasicStringMayNotBeNullTerminatedCert-implementation.qhelp b/cpp/cert/src/rules/STR50-CPP/BasicStringMayNotBeNullTerminatedCert-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/STR50-CPP/BasicStringMayNotBeNullTerminatedCert-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/STR50-CPP/BasicStringMayNotBeNullTerminatedCert.qhelp b/cpp/cert/src/rules/STR50-CPP/BasicStringMayNotBeNullTerminatedCert.qhelp index ddc7b58e1d..3280090bf2 100644 --- a/cpp/cert/src/rules/STR50-CPP/BasicStringMayNotBeNullTerminatedCert.qhelp +++ b/cpp/cert/src/rules/STR50-CPP/BasicStringMayNotBeNullTerminatedCert.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/STR50-CPP/OperationMayNotNullTerminateCStyleStringCert-implementation.qhelp b/cpp/cert/src/rules/STR50-CPP/OperationMayNotNullTerminateCStyleStringCert-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/STR50-CPP/OperationMayNotNullTerminateCStyleStringCert-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/STR50-CPP/OperationMayNotNullTerminateCStyleStringCert.qhelp b/cpp/cert/src/rules/STR50-CPP/OperationMayNotNullTerminateCStyleStringCert.qhelp index 61310c9399..2b753a2392 100644 --- a/cpp/cert/src/rules/STR50-CPP/OperationMayNotNullTerminateCStyleStringCert.qhelp +++ b/cpp/cert/src/rules/STR50-CPP/OperationMayNotNullTerminateCStyleStringCert.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/STR51-CPP/DoNotAttemptToCreateAStringFromANullPointer-implementation.qhelp b/cpp/cert/src/rules/STR51-CPP/DoNotAttemptToCreateAStringFromANullPointer-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/STR51-CPP/DoNotAttemptToCreateAStringFromANullPointer-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/STR51-CPP/DoNotAttemptToCreateAStringFromANullPointer.qhelp b/cpp/cert/src/rules/STR51-CPP/DoNotAttemptToCreateAStringFromANullPointer.qhelp index d023c155e3..87becb82cc 100644 --- a/cpp/cert/src/rules/STR51-CPP/DoNotAttemptToCreateAStringFromANullPointer.qhelp +++ b/cpp/cert/src/rules/STR51-CPP/DoNotAttemptToCreateAStringFromANullPointer.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/STR52-CPP/UseValidReferencesForElementsOfString-implementation.qhelp b/cpp/cert/src/rules/STR52-CPP/UseValidReferencesForElementsOfString-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/STR52-CPP/UseValidReferencesForElementsOfString-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/STR52-CPP/UseValidReferencesForElementsOfString.qhelp b/cpp/cert/src/rules/STR52-CPP/UseValidReferencesForElementsOfString.qhelp index 9a82fa5e18..940566ee9c 100644 --- a/cpp/cert/src/rules/STR52-CPP/UseValidReferencesForElementsOfString.qhelp +++ b/cpp/cert/src/rules/STR52-CPP/UseValidReferencesForElementsOfString.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/src/rules/STR53-CPP/RangeCheckStringElementAccess-implementation.qhelp b/cpp/cert/src/rules/STR53-CPP/RangeCheckStringElementAccess-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/cpp/cert/src/rules/STR53-CPP/RangeCheckStringElementAccess-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/STR53-CPP/RangeCheckStringElementAccess.qhelp b/cpp/cert/src/rules/STR53-CPP/RangeCheckStringElementAccess.qhelp index 421fb87c8d..f3dbea681d 100644 --- a/cpp/cert/src/rules/STR53-CPP/RangeCheckStringElementAccess.qhelp +++ b/cpp/cert/src/rules/STR53-CPP/RangeCheckStringElementAccess.qhelp @@ -8,9 +8,6 @@ -
    - -
  • CERT-C++: diff --git a/cpp/cert/test/qlpack.yml b/cpp/cert/test/qlpack.yml index 9d0f025046..11d4756c24 100644 --- a/cpp/cert/test/qlpack.yml +++ b/cpp/cert/test/qlpack.yml @@ -1,4 +1,4 @@ name: cert-cpp-coding-standards-tests -version: 2.1.0 +version: 2.3.0 libraryPathDependencies: cert-cpp-coding-standards extractor: cpp diff --git a/cpp/cert/test/rules/MSC50-CPP/DoNotUseRandForGeneratingPseudorandomNumbers.qlref b/cpp/cert/test/rules/MSC50-CPP/DoNotUseRandForGeneratingPseudorandomNumbers.qlref deleted file mode 100644 index 5c79d42038..0000000000 --- a/cpp/cert/test/rules/MSC50-CPP/DoNotUseRandForGeneratingPseudorandomNumbers.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/MSC50-CPP/DoNotUseRandForGeneratingPseudorandomNumbers.ql \ No newline at end of file diff --git a/cpp/cert/test/rules/MSC50-CPP/DoNotUseRandForGeneratingPseudorandomNumbers.testref b/cpp/cert/test/rules/MSC50-CPP/DoNotUseRandForGeneratingPseudorandomNumbers.testref new file mode 100644 index 0000000000..31cba60b74 --- /dev/null +++ b/cpp/cert/test/rules/MSC50-CPP/DoNotUseRandForGeneratingPseudorandomNumbers.testref @@ -0,0 +1 @@ +cpp/common/test/rules/donotuserandforgeneratingpseudorandomnumbers/DoNotUseRandForGeneratingPseudorandomNumbers.ql \ No newline at end of file diff --git a/cpp/cert/test/rules/MSC50-CPP/test.cpp b/cpp/cert/test/rules/MSC50-CPP/test.cpp deleted file mode 100644 index 03d820a15e..0000000000 --- a/cpp/cert/test/rules/MSC50-CPP/test.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include - -void test_use_of_rand() { int random_number = std::rand() % 10; } \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/PossiblyUnsafeStringOperation.qll b/cpp/common/src/codingstandards/cpp/PossiblyUnsafeStringOperation.qll index 5fbd40ae5e..ab454957e1 100644 --- a/cpp/common/src/codingstandards/cpp/PossiblyUnsafeStringOperation.qll +++ b/cpp/common/src/codingstandards/cpp/PossiblyUnsafeStringOperation.qll @@ -78,3 +78,31 @@ class PossiblyUnsafeStringOperation extends FunctionCall { ) } } + +/** + * Models a character array that is initialized with a string literal. + */ +class CharArrayInitializedWithStringLiteral extends Expr { + int stringLiteralLength; + int containerLength; + + CharArrayInitializedWithStringLiteral() { + exists(Variable v, StringLiteral sl | + v.getInitializer().getExpr() = sl and + ( + // `getValueText()` includes the quotes of the string + // this calculation is to subtract that overage. This also handles + // wide strings initialized with L"" + if sl.getValueText().charAt(0) = "L" + then sl.getValueText().length() - 3 = stringLiteralLength + else sl.getValueText().length() - 2 = stringLiteralLength + ) and + containerLength = v.getType().(ArrayType).getArraySize() and + this = sl + ) + } + + int getStringLiteralLength() { result = stringLiteralLength } + + int getContainerLength() { result = containerLength } +} diff --git a/cpp/common/src/codingstandards/cpp/deviations/InvalidDeviationPermits.ql b/cpp/common/src/codingstandards/cpp/deviations/InvalidDeviationPermits.ql index 4c968ae152..bb4cabd80a 100644 --- a/cpp/common/src/codingstandards/cpp/deviations/InvalidDeviationPermits.ql +++ b/cpp/common/src/codingstandards/cpp/deviations/InvalidDeviationPermits.ql @@ -2,7 +2,6 @@ * @id cpp/coding-standards/invalid-deviation-permits * @name Invalid deviation permits * @description Deviation permits marked as invalid will not be applied. - * @kind problem */ import cpp diff --git a/cpp/common/src/codingstandards/cpp/deviations/InvalidDeviationRecords.ql b/cpp/common/src/codingstandards/cpp/deviations/InvalidDeviationRecords.ql index 2004ad90f2..ec555a8a57 100644 --- a/cpp/common/src/codingstandards/cpp/deviations/InvalidDeviationRecords.ql +++ b/cpp/common/src/codingstandards/cpp/deviations/InvalidDeviationRecords.ql @@ -2,7 +2,6 @@ * @id cpp/coding-standards/invalid-deviations * @name Invalid deviations * @description Deviation records marked as invalid will not be applied. - * @kind problem */ import cpp diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Misc.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Misc.qll new file mode 100644 index 0000000000..c63fe7c7d2 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Misc.qll @@ -0,0 +1,58 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype MiscQuery = + TRandUsedForGeneratingPseudorandomNumbersQuery() or + TProperlySeedPseudorandomNumberGeneratorsQuery() or + TControlFlowReachesTheEndOfANonVoidFunctionQuery() + +predicate isMiscQueryMetadata(Query query, string queryId, string ruleId) { + query = + // `Query` instance for the `randUsedForGeneratingPseudorandomNumbers` query + MiscPackage::randUsedForGeneratingPseudorandomNumbersQuery() and + queryId = + // `@id` for the `randUsedForGeneratingPseudorandomNumbers` query + "c/cert/rand-used-for-generating-pseudorandom-numbers" and + ruleId = "MSC30-C" + or + query = + // `Query` instance for the `properlySeedPseudorandomNumberGenerators` query + MiscPackage::properlySeedPseudorandomNumberGeneratorsQuery() and + queryId = + // `@id` for the `properlySeedPseudorandomNumberGenerators` query + "c/cert/properly-seed-pseudorandom-number-generators" and + ruleId = "MSC32-C" + or + query = + // `Query` instance for the `controlFlowReachesTheEndOfANonVoidFunction` query + MiscPackage::controlFlowReachesTheEndOfANonVoidFunctionQuery() and + queryId = + // `@id` for the `controlFlowReachesTheEndOfANonVoidFunction` query + "c/cert/control-flow-reaches-the-end-of-a-non-void-function" and + ruleId = "MSC37-C" +} + +module MiscPackage { + Query randUsedForGeneratingPseudorandomNumbersQuery() { + //autogenerate `Query` type + result = + // `Query` type for `randUsedForGeneratingPseudorandomNumbers` query + TQueryC(TMiscPackageQuery(TRandUsedForGeneratingPseudorandomNumbersQuery())) + } + + Query properlySeedPseudorandomNumberGeneratorsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `properlySeedPseudorandomNumberGenerators` query + TQueryC(TMiscPackageQuery(TProperlySeedPseudorandomNumberGeneratorsQuery())) + } + + Query controlFlowReachesTheEndOfANonVoidFunctionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `controlFlowReachesTheEndOfANonVoidFunction` query + TQueryC(TMiscPackageQuery(TControlFlowReachesTheEndOfANonVoidFunctionQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll index 54910ea2bc..9f5fb09566 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll @@ -4,23 +4,32 @@ import codingstandards.cpp.exclusions.RuleMetadata //** Import packages for this language **/ import IO1 import IO2 +import Misc import Preprocessor1 import SideEffects1 +import SideEffects2 +import Strings1 import Syntax /** The TQuery type representing this language * */ newtype TCQuery = TIO1PackageQuery(IO1Query q) or TIO2PackageQuery(IO2Query q) or + TMiscPackageQuery(MiscQuery q) or TPreprocessor1PackageQuery(Preprocessor1Query q) or TSideEffects1PackageQuery(SideEffects1Query q) or + TSideEffects2PackageQuery(SideEffects2Query q) or + TStrings1PackageQuery(Strings1Query q) or TSyntaxPackageQuery(SyntaxQuery q) /** The metadata predicate * */ predicate isQueryMetadata(Query query, string queryId, string ruleId) { isIO1QueryMetadata(query, queryId, ruleId) or isIO2QueryMetadata(query, queryId, ruleId) or + isMiscQueryMetadata(query, queryId, ruleId) or isPreprocessor1QueryMetadata(query, queryId, ruleId) or isSideEffects1QueryMetadata(query, queryId, ruleId) or + isSideEffects2QueryMetadata(query, queryId, ruleId) or + isStrings1QueryMetadata(query, queryId, ruleId) or isSyntaxQueryMetadata(query, queryId, ruleId) } diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/SideEffects2.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/SideEffects2.qll new file mode 100644 index 0000000000..c14446ee92 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/SideEffects2.qll @@ -0,0 +1,42 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype SideEffects2Query = + TSideEffectAndCrementInFullExpressionQuery() or + TModificationOfFunctionParameterQuery() + +predicate isSideEffects2QueryMetadata(Query query, string queryId, string ruleId) { + query = + // `Query` instance for the `sideEffectAndCrementInFullExpression` query + SideEffects2Package::sideEffectAndCrementInFullExpressionQuery() and + queryId = + // `@id` for the `sideEffectAndCrementInFullExpression` query + "c/misra/side-effect-and-crement-in-full-expression" and + ruleId = "RULE-13-3" + or + query = + // `Query` instance for the `modificationOfFunctionParameter` query + SideEffects2Package::modificationOfFunctionParameterQuery() and + queryId = + // `@id` for the `modificationOfFunctionParameter` query + "c/misra/modification-of-function-parameter" and + ruleId = "RULE-17-8" +} + +module SideEffects2Package { + Query sideEffectAndCrementInFullExpressionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `sideEffectAndCrementInFullExpression` query + TQueryC(TSideEffects2PackageQuery(TSideEffectAndCrementInFullExpressionQuery())) + } + + Query modificationOfFunctionParameterQuery() { + //autogenerate `Query` type + result = + // `Query` type for `modificationOfFunctionParameter` query + TQueryC(TSideEffects2PackageQuery(TModificationOfFunctionParameterQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Strings1.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Strings1.qll new file mode 100644 index 0000000000..7a401ea5b3 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Strings1.qll @@ -0,0 +1,58 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype Strings1Query = + TDoNotAttemptToModifyStringLiteralsQuery() or + TStringsHasSufficientSpaceForTheNullTerminatorQuery() or + TNonNullTerminatedToFunctionThatExpectsAStringQuery() + +predicate isStrings1QueryMetadata(Query query, string queryId, string ruleId) { + query = + // `Query` instance for the `doNotAttemptToModifyStringLiterals` query + Strings1Package::doNotAttemptToModifyStringLiteralsQuery() and + queryId = + // `@id` for the `doNotAttemptToModifyStringLiterals` query + "c/cert/do-not-attempt-to-modify-string-literals" and + ruleId = "STR30-C" + or + query = + // `Query` instance for the `stringsHasSufficientSpaceForTheNullTerminator` query + Strings1Package::stringsHasSufficientSpaceForTheNullTerminatorQuery() and + queryId = + // `@id` for the `stringsHasSufficientSpaceForTheNullTerminator` query + "c/cert/strings-has-sufficient-space-for-the-null-terminator" and + ruleId = "STR31-C" + or + query = + // `Query` instance for the `nonNullTerminatedToFunctionThatExpectsAString` query + Strings1Package::nonNullTerminatedToFunctionThatExpectsAStringQuery() and + queryId = + // `@id` for the `nonNullTerminatedToFunctionThatExpectsAString` query + "c/cert/non-null-terminated-to-function-that-expects-a-string" and + ruleId = "STR32-C" +} + +module Strings1Package { + Query doNotAttemptToModifyStringLiteralsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `doNotAttemptToModifyStringLiterals` query + TQueryC(TStrings1PackageQuery(TDoNotAttemptToModifyStringLiteralsQuery())) + } + + Query stringsHasSufficientSpaceForTheNullTerminatorQuery() { + //autogenerate `Query` type + result = + // `Query` type for `stringsHasSufficientSpaceForTheNullTerminator` query + TQueryC(TStrings1PackageQuery(TStringsHasSufficientSpaceForTheNullTerminatorQuery())) + } + + Query nonNullTerminatedToFunctionThatExpectsAStringQuery() { + //autogenerate `Query` type + result = + // `Query` type for `nonNullTerminatedToFunctionThatExpectsAString` query + TQueryC(TStrings1PackageQuery(TNonNullTerminatedToFunctionThatExpectsAStringQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/rules/donotuserandforgeneratingpseudorandomnumbers/DoNotUseRandForGeneratingPseudorandomNumbers.qll b/cpp/common/src/codingstandards/cpp/rules/donotuserandforgeneratingpseudorandomnumbers/DoNotUseRandForGeneratingPseudorandomNumbers.qll new file mode 100644 index 0000000000..d4c26ad34d --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/donotuserandforgeneratingpseudorandomnumbers/DoNotUseRandForGeneratingPseudorandomNumbers.qll @@ -0,0 +1,18 @@ +/** + * Provides a library which includes a `problems` predicate for uses of rand() + * for generating random numbers. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class DoNotUseRandForGeneratingPseudorandomNumbersSharedQuery extends Query { } + +Query getQuery() { result instanceof DoNotUseRandForGeneratingPseudorandomNumbersSharedQuery } + +query predicate problems(FunctionCall fc, string message) { + not isExcluded(fc, getQuery()) and + fc.getTarget().hasGlobalOrStdName("rand") and + message = "Use of banned function " + fc.getTarget().getQualifiedName() + "." +} diff --git a/cpp/common/src/codingstandards/cpp/sideeffect/DefaultEffects.qll b/cpp/common/src/codingstandards/cpp/sideeffect/DefaultEffects.qll index dbc4d13dda..bb3fb7fad7 100644 --- a/cpp/common/src/codingstandards/cpp/sideeffect/DefaultEffects.qll +++ b/cpp/common/src/codingstandards/cpp/sideeffect/DefaultEffects.qll @@ -1,10 +1,10 @@ import cpp import codingstandards.cpp.SideEffect import codingstandards.cpp.sideeffect.Customizations -import codingstandards.cpp.Allocations -import codingstandards.cpp.Expr -import codingstandards.cpp.Variable -import semmle.code.cpp.security.FileWrite +private import codingstandards.cpp.Allocations +private import codingstandards.cpp.Expr +private import codingstandards.cpp.Variable +private import semmle.code.cpp.security.FileWrite /** A function call that performs an IO operation and thus exhibts an external side effect. */ private class IOFunctionCall extends FunctionCall, ExternalSideEffect::Range { diff --git a/cpp/common/src/qlpack.yml b/cpp/common/src/qlpack.yml index b66d6f2831..109077ece2 100644 --- a/cpp/common/src/qlpack.yml +++ b/cpp/common/src/qlpack.yml @@ -1,3 +1,3 @@ name: common-cpp-coding-standards -version: 2.1.0 +version: 2.3.0 libraryPathDependencies: codeql-cpp diff --git a/cpp/common/test/qlpack.yml b/cpp/common/test/qlpack.yml index 47f83b0926..907404ca8d 100644 --- a/cpp/common/test/qlpack.yml +++ b/cpp/common/test/qlpack.yml @@ -1,4 +1,4 @@ name: common-cpp-coding-standards-tests -version: 2.1.0 +version: 2.3.0 libraryPathDependencies: common-cpp-coding-standards extractor: cpp diff --git a/cpp/cert/test/rules/MSC50-CPP/DoNotUseRandForGeneratingPseudorandomNumbers.expected b/cpp/common/test/rules/donotuserandforgeneratingpseudorandomnumbers/DoNotUseRandForGeneratingPseudorandomNumbers.expected similarity index 100% rename from cpp/cert/test/rules/MSC50-CPP/DoNotUseRandForGeneratingPseudorandomNumbers.expected rename to cpp/common/test/rules/donotuserandforgeneratingpseudorandomnumbers/DoNotUseRandForGeneratingPseudorandomNumbers.expected diff --git a/cpp/common/test/rules/donotuserandforgeneratingpseudorandomnumbers/DoNotUseRandForGeneratingPseudorandomNumbers.ql b/cpp/common/test/rules/donotuserandforgeneratingpseudorandomnumbers/DoNotUseRandForGeneratingPseudorandomNumbers.ql new file mode 100644 index 0000000000..05388363d1 --- /dev/null +++ b/cpp/common/test/rules/donotuserandforgeneratingpseudorandomnumbers/DoNotUseRandForGeneratingPseudorandomNumbers.ql @@ -0,0 +1,2 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.donotuserandforgeneratingpseudorandomnumbers.DoNotUseRandForGeneratingPseudorandomNumbers diff --git a/cpp/autosar/test/rules/A26-5-1/test.cpp b/cpp/common/test/rules/donotuserandforgeneratingpseudorandomnumbers/test.cpp similarity index 100% rename from cpp/autosar/test/rules/A26-5-1/test.cpp rename to cpp/common/test/rules/donotuserandforgeneratingpseudorandomnumbers/test.cpp diff --git a/cpp/misra/src/qlpack.yml b/cpp/misra/src/qlpack.yml index fbc916b8af..173ccaa1d8 100644 --- a/cpp/misra/src/qlpack.yml +++ b/cpp/misra/src/qlpack.yml @@ -1,3 +1,3 @@ name: misra-cpp-coding-standards -version: 2.1.0 +version: 2.3.0 libraryPathDependencies: common-cpp-coding-standards diff --git a/cpp/misra/test/qlpack.yml b/cpp/misra/test/qlpack.yml index 17b683f28c..c269fe7d74 100644 --- a/cpp/misra/test/qlpack.yml +++ b/cpp/misra/test/qlpack.yml @@ -1,4 +1,4 @@ name: misra-cpp-coding-standards-tests -version: 2.1.0 +version: 2.3.0 libraryPathDependencies: misra-cpp-coding-standards extractor: cpp diff --git a/cpp/report/src/qlpack.yml b/cpp/report/src/qlpack.yml index e3c48fe632..5a8be4085e 100644 --- a/cpp/report/src/qlpack.yml +++ b/cpp/report/src/qlpack.yml @@ -1,3 +1,3 @@ name: report-cpp-coding-standards -version: 2.1.0 +version: 2.3.0 libraryPathDependencies: codeql-cpp diff --git a/development_handbook.md b/development_handbook.md index acc2da6f03..2c0967afbb 100644 --- a/development_handbook.md +++ b/development_handbook.md @@ -60,7 +60,6 @@ In the repository, this will be organised as follows: / .ql .qhelp - -implementation.qhelp codeql-suites/ -default.qls ... @@ -205,7 +204,6 @@ python3 scripts/generate_rules/generate_package_files.py After running this script, the following files will be generated in the `//src/rules//` directory: - A `.ql` query file with the query metadata pre-populated, and the standard imports included. - A `.qhelp` query help file with some boilerplate text describing the purpose of the query. - - A `-implementation.qhelp` query help file with a space to enter details about the implementation of this rule in the query. In addition, the following files will be generated in the `//test/rules//` directory: - An empty `test.cpp` file. @@ -214,7 +212,7 @@ In addition, the following files will be generated in the `//tes The script can be safely re-run, except in a few notable cases listed below. Re-running the script has the following effect: - Overwrites the `.qhelp` file and `.qlref` file. - - Touches the `-implementation.qhelp`, `test.cpp` and `.expected` files, to ensure they exist on disk, but does not modify them if they exist. + - Touches the `test.cpp` and `.expected` files, to ensure they exist on disk, but does not modify them if they exist. - Updates the `.ql` query by overwriting the query metadata block only. The QL portion of the file is left untouched. The notable exceptions are: diff --git a/rule_packages/c/Misc.json b/rule_packages/c/Misc.json new file mode 100644 index 0000000000..8d7f515e2e --- /dev/null +++ b/rule_packages/c/Misc.json @@ -0,0 +1,66 @@ +{ + "CERT-C": { + "MSC30-C": { + "properties": { + "obligation": "rule" + }, + "queries": [ + { + "description": "rand() shall not be used to generate pseudorandom numbers.", + "kind": "problem", + "name": "Do not use the rand() function for generating pseudorandom numbers", + "precision": "very-high", + "severity": "error", + "short_name": "RandUsedForGeneratingPseudorandomNumbers", + "shared_implementation_short_name" : "DoNotUseRandForGeneratingPseudorandomNumbers", + "tags": [ + "security" + ] + } + ], + "title": "Do not use the rand() function for generating pseudorandom numbers" + }, + "MSC32-C": { + "properties": { + "obligation": "rule" + }, + "queries": [ + { + "description": "Improperly seeded random number generators can lead to insecure code.", + "kind": "problem", + "name": "Properly seed pseudorandom number generators", + "precision": "very-high", + "severity": "error", + "short_name": "ProperlySeedPseudorandomNumberGenerators", + "tags": [ + "security" + ] + } + ], + "title": "Properly seed pseudorandom number generators", + "implementation_scope": { + "description": "This rule will be checked by looking for calls to random that are no preceded by a call to srandom(). We perform a simple check for the argument to srandom() and verify it is not a literal (or a value easily deduced to be a literal)." + } + }, + "MSC37-C": { + "properties": { + "obligation": "rule" + }, + "queries": [ + { + "description": "Non-void functions that end without an explicit return can produce unpredictable results.", + "kind": "problem", + "name": "Ensure that control never reaches the end of a non-void function", + "precision": "very-high", + "severity": "error", + "short_name": "ControlFlowReachesTheEndOfANonVoidFunction", + "shared_implementation_short_name": "NonVoidFunctionDoesNotReturn", + "tags": [ + "correctness" + ] + } + ], + "title": "Ensure that control never reaches the end of a non-void function" + } + } +} \ No newline at end of file diff --git a/rule_packages/c/Preprocessor1.json b/rule_packages/c/Preprocessor1.json index 21ad88ea15..b93bc72731 100644 --- a/rule_packages/c/Preprocessor1.json +++ b/rule_packages/c/Preprocessor1.json @@ -37,6 +37,7 @@ "correctness" ] } + ], "title": "The # and ## preprocessor operators should not be used" }, @@ -55,7 +56,11 @@ "shared_implementation_short_name": "PreprocessorIncludesForbiddenHeaderNames", "tags": [ "correctness" - ] + ], + "implementation_scope": { + "description": "This query identifies the use of the ', \\, /*, // characters in header file names. The query is not able to detect the use of the \" character in header file names.", + "items": [] + } } ], "title": "The ', \" or \\ characters and the /* or // character sequences shall not occur in a header file name" @@ -76,7 +81,11 @@ "tags": [ "correctness", "readability" - ] + ], + "implementation_scope": { + "description": "This query does not detect the case where an undefined character is used but not actually evaluated, for example, as a result of the inclusion of a logical AND operator in the #if expression.", + "items": [] + } } ], "title": "All identifiers used in the controlling expression of #if or #elif preprocessing directives shall be #define\ufffdd before evaluation" diff --git a/rule_packages/c/SideEffects2.json b/rule_packages/c/SideEffects2.json new file mode 100644 index 0000000000..9c8c3b71ec --- /dev/null +++ b/rule_packages/c/SideEffects2.json @@ -0,0 +1,43 @@ +{ + "MISRA-C-2012": { + "RULE-13-3": { + "properties": { + "obligation": "advisory" + }, + "queries": [ + { + "description": "A full expression containing an increment (++) or decrement (--) operator should have no other potential side effects other than that caused by the increment or decrement operator", + "kind": "problem", + "name": "A full expression containing an increment (++) or decrement (--) operator should have no other", + "precision": "very-high", + "severity": "warning", + "short_name": "SideEffectAndCrementInFullExpression", + "tags": [ + "readability", + "correctness" + ] + } + ], + "title": "A full expression containing an increment (++) or decrement (--) operator should have no other potential side effects other than that caused by the increment or decrement operator" + }, + "RULE-17-8": { + "properties": { + "obligation": "advisory" + }, + "queries": [ + { + "description": "A function parameter behaves in the same manner as an object with automatic storage duration and the effects of modifying a parameter are not visible in the calling function.", + "kind": "problem", + "name": "A function parameter should not be modified", + "precision": "very-high", + "severity": "warning", + "short_name": "ModificationOfFunctionParameter", + "tags": [ + "correctness" + ] + } + ], + "title": "A function parameter should not be modified" + } + } +} \ No newline at end of file diff --git a/rule_packages/c/Strings1.json b/rule_packages/c/Strings1.json new file mode 100644 index 0000000000..159034b4aa --- /dev/null +++ b/rule_packages/c/Strings1.json @@ -0,0 +1,67 @@ +{ + "CERT-C": { + "STR30-C": { + "properties": { + "obligation": "rule" + }, + "queries": [ + { + "description": "Modifying a string literal can produce unexpected effects.", + "kind": "problem", + "name": "Do not attempt to modify string literals", + "precision": "very-high", + "severity": "error", + "short_name": "DoNotAttemptToModifyStringLiterals", + "tags": [ + "correctness", + "security" + ] + } + ], + "title": "Do not attempt to modify string literals" + }, + "STR31-C": { + "properties": { + "obligation": "rule" + }, + "queries": [ + { + "description": "Many library functions in the C standard library assume C strings are null terminated and failing to null terminate strings may lead to unpredictable program behavior.", + "kind": "problem", + "name": "Guarantee that storage for strings has sufficient space for character data and the null terminator", + "precision": "medium", + "severity": "error", + "short_name": "StringsHasSufficientSpaceForTheNullTerminator", + "tags": [ + "correctness", + "security" + ] + } + ], + "title": "Guarantee that storage for strings has sufficient space for character data and the null terminator", + "implementation_scope": { + "description": "The enforcement of this rule does not try to approximate the effects of loops and as such may not find cases where a loop operation on a string fails to null terminate a string (or causes an overflow)." + } + }, + "STR32-C": { + "properties": { + "obligation": "rule" + }, + "queries": [ + { + "description": "Passing a string that is not null-terminated can lead to unpredictable program behavior.", + "kind": "problem", + "name": "Do not pass a non-null-terminated character sequence to a library function that expects a string", + "precision": "medium", + "severity": "error", + "short_name": "NonNullTerminatedToFunctionThatExpectsAString", + "tags": [ + "correctness", + "security" + ] + } + ], + "title": "Do not pass a non-null-terminated character sequence to a library function that expects a string" + } + } +} \ No newline at end of file diff --git a/rule_packages/cpp/BannedFunctions.json b/rule_packages/cpp/BannedFunctions.json index 2ea991c641..a6b37765dd 100644 --- a/rule_packages/cpp/BannedFunctions.json +++ b/rule_packages/cpp/BannedFunctions.json @@ -62,6 +62,7 @@ "precision": "very-high", "severity": "error", "short_name": "PseudorandomNumbersGeneratedUsingRand", + "shared_implementation_short_name" : "DoNotUseRandForGeneratingPseudorandomNumbers", "tags": [ "security" ] @@ -220,6 +221,7 @@ "precision": "very-high", "severity": "error", "short_name": "DoNotUseRandForGeneratingPseudorandomNumbers", + "shared_implementation_short_name" : "DoNotUseRandForGeneratingPseudorandomNumbers", "tags": [ "security" ] diff --git a/rule_packages/cpp/Macros.json b/rule_packages/cpp/Macros.json index dc4d22047b..c244016887 100644 --- a/rule_packages/cpp/Macros.json +++ b/rule_packages/cpp/Macros.json @@ -44,7 +44,11 @@ "shared_implementation_short_name": "PreprocessorIncludesForbiddenHeaderNames", "tags": [ "correctness" - ] + ], + "implementation_scope": { + "description": "This query identifies the use of the ', \\, /*, // characters in header file names. The query is not able to detect the use of the \" character in header file names.", + "items": [] + } } ], "title": "The ', \", /*, //, \\ characters shall not occur in a header file name or in #include directive." @@ -211,7 +215,11 @@ "tags": [ "correctness", "readability" - ] + ], + "implementation_scope": { + "description": "This query does not detect the case where an undefined character is used but not actually evaluated, for example, as a result of the inclusion of a logical AND operator in the #if expression.", + "items": [] + } } ], "title": "Undefined macro identifiers shall not be used in #if or #elif pre-processor directives, except as operands to the defined operator." diff --git a/rules.csv b/rules.csv index c4e9e02246..a9c0272804 100755 --- a/rules.csv +++ b/rules.csv @@ -592,12 +592,12 @@ c,CERT-C,SIG30-C,Yes,Rule,,,Call only asynchronous-safe functions within signal c,CERT-C,SIG31-C,Yes,Rule,,,Do not access shared objects in signal handlers,,Contracts,Medium, c,CERT-C,SIG34-C,Yes,Rule,,,Do not call signal() from within interruptible signal handlers,,Contracts,Medium, c,CERT-C,SIG35-C,Yes,Rule,,,Do not return from a computational exception signal handler,,Contracts,Easy, -c,CERT-C,STR30-C,Yes,Rule,,,Do not attempt to modify string literals,,Strings,Medium, -c,CERT-C,STR31-C,Yes,Rule,,,Guarantee that storage for strings has sufficient space for character data and the null terminator,STR50-CPP,Strings,Very Hard, -c,CERT-C,STR32-C,Yes,Rule,,,Do not pass a non-null-terminated character sequence to a library function that expects a string,STR51-CPP,Strings,Very Hard, -c,CERT-C,STR34-C,Yes,Rule,,,Cast characters to unsigned char before converting to larger integer sizes,,Strings,Hard, -c,CERT-C,STR37-C,Yes,Rule,,,Arguments to character-handling functions must be representable as an unsigned char,,Strings,Medium, -c,CERT-C,STR38-C,Yes,Rule,,,Do not confuse narrow and wide character strings and functions,,Strings,Medium, +c,CERT-C,STR30-C,Yes,Rule,,,Do not attempt to modify string literals,,Strings1,Medium, +c,CERT-C,STR31-C,Yes,Rule,,,Guarantee that storage for strings has sufficient space for character data and the null terminator,STR50-CPP,Strings1,Very Hard, +c,CERT-C,STR32-C,Yes,Rule,,,Do not pass a non-null-terminated character sequence to a library function that expects a string,STR51-CPP,Strings1,Very Hard, +c,CERT-C,STR34-C,Yes,Rule,,,Cast characters to unsigned char before converting to larger integer sizes,,Strings2,Hard, +c,CERT-C,STR37-C,Yes,Rule,,,Arguments to character-handling functions must be representable as an unsigned char,,Strings2,Medium, +c,CERT-C,STR38-C,Yes,Rule,,,Do not confuse narrow and wide character strings and functions,,Strings2,Medium, c,CERT-C,WIN30-C,OutOfScope,Rule,,,Properly pair allocation and deallocation functions,DCL54-CPP,,Easy, c,MISRA-C-2012,RULE-1-1,No,Required,,,Any implementation-defined behaviour on which the output of the program depends shall be documented and understood,,,, c,MISRA-C-2012,RULE-2-1,Yes,Required,,,All source files shall compile without any compilation errors,A1-4-3,Language,Medium, @@ -688,7 +688,7 @@ c,MISRA-C-2012,RULE-12-3,Yes,Advisory,,,The comma operator should not be used,M5 c,MISRA-C-2012,RULE-12-4,Yes,Advisory,,,Evaluation of constant expressions should not lead to unsigned integer wrap-around,INT30-C,Types,Easy, c,MISRA-C-2012,RULE-12-5,Yes,Mandatory,,,The sizeof operator shall not have an operand which is a function parameter declared as �array of type�,,Types,Medium, c,MISRA-C-2012,RULE-13-1,Yes,Required,,,Initializer lists shall not contain persistent side effects,,SideEffects1,Medium, -c,MISRA-C-2012,RULE-13-2,Yes,Required,,,The value of an expression and its persistent side effects shall be the same under all permitted evaluation orders,PRE31-C,SideEffects2,Medium, +c,MISRA-C-2012,RULE-13-2,Yes,Required,,,The value of an expression and its persistent side effects shall be the same under all permitted evaluation orders,PRE31-C,SideEffects,Medium, c,MISRA-C-2012,RULE-13-3,Yes,Advisory,,,A full expression containing an increment (++) or decrement (--) operator should have no other potential side effects other than that caused by the increment or decrement operator,,SideEffects2,Medium, c,MISRA-C-2012,RULE-13-4,Yes,Advisory,,,The result of an assignment operator should not be used,M6-2-1,SideEffects1,Easy, c,MISRA-C-2012,RULE-13-5,Yes,Required,,,The right hand operand of a logical && or || operator shall not contain persistent side effects,M5-14-1,SideEffects1,Import, diff --git a/scripts/generate_rules/templates/template-implementation.qhelp b/scripts/generate_rules/templates/template-implementation.qhelp deleted file mode 100644 index a01fab8d10..0000000000 --- a/scripts/generate_rules/templates/template-implementation.qhelp +++ /dev/null @@ -1,8 +0,0 @@ - - - -

    None

    -
    -
    \ No newline at end of file diff --git a/scripts/generate_rules/templates/template.qhelp b/scripts/generate_rules/templates/template.qhelp index 144340ae0b..dbad358130 100644 --- a/scripts/generate_rules/templates/template.qhelp +++ b/scripts/generate_rules/templates/template.qhelp @@ -20,9 +20,6 @@ {% endif %}
  • {% endif %} -
    - -
    {% if standard_title | length %}
  • From c9218647fb1f13e3cf1793c8f6acca5a55fcb1f9 Mon Sep 17 00:00:00 2001 From: Remco Vermeulen Date: Wed, 13 Jul 2022 12:17:21 +0200 Subject: [PATCH 0004/2973] Release v2.4.0 --- .github/workflows/code-scanning-pack-gen.yml | 2 +- .vscode/tasks.json | 12 +- c/cert/src/qlpack.yml | 2 +- ...formFileOperationsOnDevices-standard.qhelp | 594 ++++++++++++++++++ .../DoNotPerformFileOperationsOnDevices.qhelp | 18 + .../DoNotPerformFileOperationsOnDevices.ql | 64 ++ ...getwsMayReturnAnEmptyString-standard.qhelp | 392 ++++++++++++ ...lFgetsOrFgetwsMayReturnAnEmptyString.qhelp | 18 + ...sfulFgetsOrFgetwsMayReturnAnEmptyString.ql | 48 ++ .../ResetStringsOnFgetsOrFgetwsFailure.ql | 3 - ...nctionsRepresentableAsUChar-standard.qhelp | 33 + ...andlingFunctionsRepresentableAsUChar.qhelp | 18 + ...erHandlingFunctionsRepresentableAsUChar.ql | 29 + .../{FIO39-C => STR37-C}/standard-example.c | 0 c/cert/test/qlpack.yml | 2 +- ...NotPerformFileOperationsOnDevices.expected | 40 ++ .../DoNotPerformFileOperationsOnDevices.qlref | 1 + c/cert/test/rules/FIO32-C/test.c | 50 ++ .../EndOfFileCheckPortability.expected | 1 - c/cert/test/rules/FIO34-C/test.c | 2 +- ...etsOrFgetwsMayReturnAnEmptyString.expected | 1 + ...lFgetsOrFgetwsMayReturnAnEmptyString.qlref | 1 + c/cert/test/rules/FIO37-C/test.c | 56 ++ ...lingFunctionsRepresentableAsUChar.expected | 28 + ...andlingFunctionsRepresentableAsUChar.qlref | 1 + c/cert/test/rules/STR37-C/test.c | 86 +++ c/common/src/qlpack.yml | 2 +- .../test/{ => library}/expr/FullExpr.expected | 0 c/common/test/{ => library}/expr/FullExpr.ql | 0 c/common/test/{ => library}/expr/fullexpr.c | 0 .../fgetserrormanagement/FgetsGuard.expected | 20 + .../fgetserrormanagement/FgetsGuard.ql | 5 + .../test/library/fgetserrormanagement/test.c | 195 ++++++ c/common/test/qlpack.yml | 2 +- .../HashOperatorsUsed.expected | 4 - .../hashoperatorsused/HashOperatorsUsed.ql | 2 - c/common/test/rules/hashoperatorsused/test.c | 19 - .../IncludeGuardsNotUsed.expected | 4 + .../IncludeGuardsNotUsed.ql | 2 + .../includeguardsnotused/headers/test1.h | 0 .../includeguardsnotused/headers/test2.h | 0 .../includeguardsnotused/headers/test3.h | 0 .../includeguardsnotused/headers/test4.h | 0 .../includeguardsnotused/headers/test5.h | 0 .../includeguardsnotused/headers/test6.h | 5 + .../includeguardsnotused/headers/test7.h | 5 + .../test/rules/includeguardsnotused/test.c | 14 + c/misra/src/qlpack.yml | 2 +- ...oreThanOneHashOperatorInMacroDefinition.ql | 26 + .../src/rules/RULE-20-11/standard-example.c | 3 + .../MacroParameterUsedAsHashOperand.ql | 39 ++ .../src/rules/RULE-20-12/standard-example.c | 7 + .../rules/RULE-20-5/UndefShouldNotBeUsed.ql | 19 + .../src/rules/RULE-20-5/standard-example.c | 7 + ...leOpenForReadAndWriteOnDifferentStreams.ql | 68 ++ .../src/rules/RULE-22-3/standard-example.c | 5 + .../AttemptToWriteToAReadOnlyStream.ql | 36 ++ .../src/rules/RULE-22-4/standard-example.c | 6 + .../PointerToAFileObjectDereferenced.ql | 38 ++ .../src/rules/RULE-22-5/standard-example.c | 8 + ...allBeComparedWithUnmodifiedReturnValues.ql | 60 ++ .../src/rules/RULE-22-7/standard-example1.c | 10 + .../src/rules/RULE-22-7/standard-example2.c | 19 + .../PrecautionIncludeGuardsNotProvided.ql | 24 + .../src/rules/RULE-4-10/standard-example.c | 12 + c/misra/test/qlpack.yml | 2 +- ...nOneHashOperatorInMacroDefinition.expected | 1 + ...ThanOneHashOperatorInMacroDefinition.qlref | 1 + c/misra/test/rules/RULE-20-11/test.c | 27 + .../MacroParameterUsedAsHashOperand.expected | 2 + .../MacroParameterUsedAsHashOperand.qlref | 1 + c/misra/test/rules/RULE-20-12/test.c | 25 + .../RULE-20-5/UndefShouldNotBeUsed.expected | 1 + .../RULE-20-5/UndefShouldNotBeUsed.qlref | 1 + c/misra/test/rules/RULE-20-5/test.c | 2 + ...ForReadAndWriteOnDifferentStreams.expected | 5 + ...penForReadAndWriteOnDifferentStreams.qlref | 1 + c/misra/test/rules/RULE-22-3/test.c | 60 ++ .../AttemptToWriteToAReadOnlyStream.expected | 2 + .../AttemptToWriteToAReadOnlyStream.qlref | 1 + c/misra/test/rules/RULE-22-4/test.c | 21 + .../PointerToAFileObjectDereferenced.expected | 7 + .../PointerToAFileObjectDereferenced.qlref | 1 + c/misra/test/rules/RULE-22-5/test.c | 28 + ...omparedWithUnmodifiedReturnValues.expected | 2 + ...BeComparedWithUnmodifiedReturnValues.qlref | 1 + c/misra/test/rules/RULE-22-7/test.c | 31 + .../RULE-4-10/NonUniqueIncludeGuards.testref | 1 + ...PrecautionIncludeGuardsNotProvided.testref | 1 + ...-20-M16-3-1-exclude-non-function-macros.md | 2 + cpp/autosar/src/qlpack.yml | 2 +- .../rules/M16-2-3/IncludeGuardsNotProvided.ql | 52 +- ...OccurrenceHashOperatorInMacroDefinition.ql | 19 +- cpp/autosar/test/qlpack.yml | 2 +- .../M16-2-3/IncludeGuardsNotProvided.expected | 3 - .../M16-2-3/IncludeGuardsNotProvided.qlref | 1 - .../M16-2-3/IncludeGuardsNotProvided.testref | 1 + .../M16-2-3/NonUniqueIncludeGuardsCpp.testref | 1 + ...enceHashOperatorInMacroDefinition.expected | 1 - cpp/autosar/test/rules/M16-3-1/test.cpp | 3 +- cpp/cert/src/qlpack.yml | 2 +- cpp/cert/test/qlpack.yml | 2 +- .../src/codingstandards/cpp/CharFunctions.qll | 31 + .../src/codingstandards/cpp/Dereferenced.qll | 3 + .../cpp/FgetsErrorManagement.qll | 93 +-- cpp/common/src/codingstandards/cpp/Macro.qll | 65 ++ .../codingstandards/cpp/ReadErrorsAndEOF.qll | 6 +- .../codingstandards/cpp/exclusions/c/IO3.qll | 106 ++++ .../cpp/exclusions/c/Preprocessor2.qll | 74 +++ .../cpp/exclusions/c/RuleMetadata.qll | 9 + .../cpp/exclusions/c/Strings2.qll | 25 + .../IncludeGuardsNotUsed.qll | 40 ++ .../cpp/standardlibrary/FileAccess.qll | 21 + cpp/common/src/qlpack.yml | 2 +- cpp/common/test/qlpack.yml | 2 +- .../IncludeGuardsNotUsed.expected | 4 + .../IncludeGuardsNotUsed.ql | 2 + .../includeguardsnotused/headers/test1.hpp | 4 + .../includeguardsnotused/headers/test2.hpp | 4 + .../includeguardsnotused/headers/test3.hpp | 2 + .../includeguardsnotused/headers/test4.hpp | 4 + .../includeguardsnotused/headers/test5.hpp | 6 + .../includeguardsnotused/headers/test6.hpp | 5 + .../test/rules/includeguardsnotused}/test.cpp | 4 +- cpp/misra/src/qlpack.yml | 2 +- cpp/misra/test/qlpack.yml | 2 +- cpp/report/src/qlpack.yml | 2 +- rule_packages/c/IO3.json | 139 ++++ rule_packages/c/Preprocessor2.json | 93 +++ rule_packages/c/Strings2.json | 24 + rule_packages/cpp/Includes.json | 7 +- rule_packages/cpp/Macros.json | 6 +- rules.csv | 34 +- .../generate_rules/generate_package_files.py | 89 +-- .../templates/exclusions.qll.template | 4 + 135 files changed, 3186 insertions(+), 214 deletions(-) create mode 100644 c/cert/src/rules/FIO32-C/DoNotPerformFileOperationsOnDevices-standard.qhelp create mode 100644 c/cert/src/rules/FIO32-C/DoNotPerformFileOperationsOnDevices.qhelp create mode 100644 c/cert/src/rules/FIO32-C/DoNotPerformFileOperationsOnDevices.ql create mode 100644 c/cert/src/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString-standard.qhelp create mode 100644 c/cert/src/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString.qhelp create mode 100644 c/cert/src/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString.ql create mode 100644 c/cert/src/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar-standard.qhelp create mode 100644 c/cert/src/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar.qhelp create mode 100644 c/cert/src/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar.ql rename c/cert/src/rules/{FIO39-C => STR37-C}/standard-example.c (100%) create mode 100644 c/cert/test/rules/FIO32-C/DoNotPerformFileOperationsOnDevices.expected create mode 100644 c/cert/test/rules/FIO32-C/DoNotPerformFileOperationsOnDevices.qlref create mode 100644 c/cert/test/rules/FIO32-C/test.c create mode 100644 c/cert/test/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString.expected create mode 100644 c/cert/test/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString.qlref create mode 100644 c/cert/test/rules/FIO37-C/test.c create mode 100644 c/cert/test/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar.expected create mode 100644 c/cert/test/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar.qlref create mode 100644 c/cert/test/rules/STR37-C/test.c rename c/common/test/{ => library}/expr/FullExpr.expected (100%) rename c/common/test/{ => library}/expr/FullExpr.ql (100%) rename c/common/test/{ => library}/expr/fullexpr.c (100%) create mode 100644 c/common/test/library/fgetserrormanagement/FgetsGuard.expected create mode 100644 c/common/test/library/fgetserrormanagement/FgetsGuard.ql create mode 100644 c/common/test/library/fgetserrormanagement/test.c delete mode 100644 c/common/test/rules/hashoperatorsused/HashOperatorsUsed.expected delete mode 100644 c/common/test/rules/hashoperatorsused/HashOperatorsUsed.ql delete mode 100644 c/common/test/rules/hashoperatorsused/test.c create mode 100644 c/common/test/rules/includeguardsnotused/IncludeGuardsNotUsed.expected create mode 100644 c/common/test/rules/includeguardsnotused/IncludeGuardsNotUsed.ql rename cpp/autosar/test/rules/M16-2-3/headers/test1.hpp => c/common/test/rules/includeguardsnotused/headers/test1.h (100%) rename cpp/autosar/test/rules/M16-2-3/headers/test2.hpp => c/common/test/rules/includeguardsnotused/headers/test2.h (100%) rename cpp/autosar/test/rules/M16-2-3/headers/test3.hpp => c/common/test/rules/includeguardsnotused/headers/test3.h (100%) rename cpp/autosar/test/rules/M16-2-3/headers/test4.hpp => c/common/test/rules/includeguardsnotused/headers/test4.h (100%) rename cpp/autosar/test/rules/M16-2-3/headers/test5.hpp => c/common/test/rules/includeguardsnotused/headers/test5.h (100%) create mode 100644 c/common/test/rules/includeguardsnotused/headers/test6.h create mode 100644 c/common/test/rules/includeguardsnotused/headers/test7.h create mode 100644 c/common/test/rules/includeguardsnotused/test.c create mode 100644 c/misra/src/rules/RULE-20-11/MoreThanOneHashOperatorInMacroDefinition.ql create mode 100644 c/misra/src/rules/RULE-20-11/standard-example.c create mode 100644 c/misra/src/rules/RULE-20-12/MacroParameterUsedAsHashOperand.ql create mode 100644 c/misra/src/rules/RULE-20-12/standard-example.c create mode 100644 c/misra/src/rules/RULE-20-5/UndefShouldNotBeUsed.ql create mode 100644 c/misra/src/rules/RULE-20-5/standard-example.c create mode 100644 c/misra/src/rules/RULE-22-3/FileOpenForReadAndWriteOnDifferentStreams.ql create mode 100644 c/misra/src/rules/RULE-22-3/standard-example.c create mode 100644 c/misra/src/rules/RULE-22-4/AttemptToWriteToAReadOnlyStream.ql create mode 100644 c/misra/src/rules/RULE-22-4/standard-example.c create mode 100644 c/misra/src/rules/RULE-22-5/PointerToAFileObjectDereferenced.ql create mode 100644 c/misra/src/rules/RULE-22-5/standard-example.c create mode 100644 c/misra/src/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.ql create mode 100644 c/misra/src/rules/RULE-22-7/standard-example1.c create mode 100644 c/misra/src/rules/RULE-22-7/standard-example2.c create mode 100644 c/misra/src/rules/RULE-4-10/PrecautionIncludeGuardsNotProvided.ql create mode 100644 c/misra/src/rules/RULE-4-10/standard-example.c create mode 100644 c/misra/test/rules/RULE-20-11/MoreThanOneHashOperatorInMacroDefinition.expected create mode 100644 c/misra/test/rules/RULE-20-11/MoreThanOneHashOperatorInMacroDefinition.qlref create mode 100644 c/misra/test/rules/RULE-20-11/test.c create mode 100644 c/misra/test/rules/RULE-20-12/MacroParameterUsedAsHashOperand.expected create mode 100644 c/misra/test/rules/RULE-20-12/MacroParameterUsedAsHashOperand.qlref create mode 100644 c/misra/test/rules/RULE-20-12/test.c create mode 100644 c/misra/test/rules/RULE-20-5/UndefShouldNotBeUsed.expected create mode 100644 c/misra/test/rules/RULE-20-5/UndefShouldNotBeUsed.qlref create mode 100644 c/misra/test/rules/RULE-20-5/test.c create mode 100644 c/misra/test/rules/RULE-22-3/FileOpenForReadAndWriteOnDifferentStreams.expected create mode 100644 c/misra/test/rules/RULE-22-3/FileOpenForReadAndWriteOnDifferentStreams.qlref create mode 100644 c/misra/test/rules/RULE-22-3/test.c create mode 100644 c/misra/test/rules/RULE-22-4/AttemptToWriteToAReadOnlyStream.expected create mode 100644 c/misra/test/rules/RULE-22-4/AttemptToWriteToAReadOnlyStream.qlref create mode 100644 c/misra/test/rules/RULE-22-4/test.c create mode 100644 c/misra/test/rules/RULE-22-5/PointerToAFileObjectDereferenced.expected create mode 100644 c/misra/test/rules/RULE-22-5/PointerToAFileObjectDereferenced.qlref create mode 100644 c/misra/test/rules/RULE-22-5/test.c create mode 100644 c/misra/test/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.expected create mode 100644 c/misra/test/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.qlref create mode 100644 c/misra/test/rules/RULE-22-7/test.c create mode 100644 c/misra/test/rules/RULE-4-10/NonUniqueIncludeGuards.testref create mode 100644 c/misra/test/rules/RULE-4-10/PrecautionIncludeGuardsNotProvided.testref create mode 100644 change_notes/2022-05-20-M16-3-1-exclude-non-function-macros.md delete mode 100644 cpp/autosar/test/rules/M16-2-3/IncludeGuardsNotProvided.expected delete mode 100644 cpp/autosar/test/rules/M16-2-3/IncludeGuardsNotProvided.qlref create mode 100644 cpp/autosar/test/rules/M16-2-3/IncludeGuardsNotProvided.testref create mode 100644 cpp/autosar/test/rules/M16-2-3/NonUniqueIncludeGuardsCpp.testref create mode 100644 cpp/common/src/codingstandards/cpp/CharFunctions.qll create mode 100644 cpp/common/src/codingstandards/cpp/Macro.qll create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/c/IO3.qll create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/c/Preprocessor2.qll create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/c/Strings2.qll create mode 100644 cpp/common/src/codingstandards/cpp/rules/includeguardsnotused/IncludeGuardsNotUsed.qll create mode 100644 cpp/common/test/rules/includeguardsnotused/IncludeGuardsNotUsed.expected create mode 100644 cpp/common/test/rules/includeguardsnotused/IncludeGuardsNotUsed.ql create mode 100644 cpp/common/test/rules/includeguardsnotused/headers/test1.hpp create mode 100644 cpp/common/test/rules/includeguardsnotused/headers/test2.hpp create mode 100644 cpp/common/test/rules/includeguardsnotused/headers/test3.hpp create mode 100644 cpp/common/test/rules/includeguardsnotused/headers/test4.hpp create mode 100644 cpp/common/test/rules/includeguardsnotused/headers/test5.hpp create mode 100644 cpp/common/test/rules/includeguardsnotused/headers/test6.hpp rename cpp/{autosar/test/rules/M16-2-3 => common/test/rules/includeguardsnotused}/test.cpp (57%) create mode 100644 rule_packages/c/IO3.json create mode 100644 rule_packages/c/Preprocessor2.json create mode 100644 rule_packages/c/Strings2.json diff --git a/.github/workflows/code-scanning-pack-gen.yml b/.github/workflows/code-scanning-pack-gen.yml index fdad8f9325..b734cdd5ef 100644 --- a/.github/workflows/code-scanning-pack-gen.yml +++ b/.github/workflows/code-scanning-pack-gen.yml @@ -73,7 +73,7 @@ jobs: PATH=$PATH:$CODEQL_HOME/codeql pip install -r scripts/requirements.txt find rule_packages/cpp -name '*.json' -exec basename {} .json \; | xargs --max-procs "$XARGS_MAX_PROCS" --max-args 1 python3 scripts/generate_rules/generate_package_files.py -a cpp - find rule_packages/c -name '*.json' -exec basename {} .json \; | xargs --max-procs "$XARGS_MAX_PROCS" --max-args 1 python3 scripts/generate_rules/generate_package_files.py -a c + find rule_packages/c -name '*.json' -exec basename {} .json \; | xargs --max-procs "$XARGS_MAX_PROCS" --max-args 1 python3 scripts/generate_rules/generate_package_files.py --skip-shared-test-generation -a c echo "Generating help markdown file for cert" $CODEQL_LATEST_HOME/codeql/codeql generate query-help -vvv --format=markdown -o cpp/cert/src/ cpp/cert/src/rules diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 24432cd317..8e5b1b4ccc 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -180,7 +180,9 @@ "Expressions", "Freed", "Functions", - "IO", + "IO1", + "IO2", + "IO3", "Includes", "Initialization", "IntegerConversion", @@ -205,9 +207,17 @@ "Strings", "Strings1", "Strings2", + "Strings3", "Syntax", "Templates", "TypeRanges", + "Lambdas", + "Pointers", + "Preprocessor1", + "Preprocessor2", + "IntegerConversion", + "Expressions", + "DeadCode" "VirtualFunctions" ] }, diff --git a/c/cert/src/qlpack.yml b/c/cert/src/qlpack.yml index 9ecaaadc79..b3cd47c3a4 100644 --- a/c/cert/src/qlpack.yml +++ b/c/cert/src/qlpack.yml @@ -1,4 +1,4 @@ name: cert-c-coding-standards -version: 2.3.0 +version: 2.4.0 suites: codeql-suites libraryPathDependencies: common-c-coding-standards \ No newline at end of file diff --git a/c/cert/src/rules/FIO32-C/DoNotPerformFileOperationsOnDevices-standard.qhelp b/c/cert/src/rules/FIO32-C/DoNotPerformFileOperationsOnDevices-standard.qhelp new file mode 100644 index 0000000000..44fd54fffd --- /dev/null +++ b/c/cert/src/rules/FIO32-C/DoNotPerformFileOperationsOnDevices-standard.qhelp @@ -0,0 +1,594 @@ + + +
    +

    File names on many operating systems, including Windows and UNIX, may be used to access special files, which are actually devices. Reserved Microsoft Windows device names include AUX, CON, PRN, COM1, and LPT1 or paths using the \\.\ device namespace. Device files on UNIX systems are used to apply access rights and to direct operations on the files to the appropriate device drivers.

    +

    Performing operations on device files that are intended for ordinary character or binary files can result in crashes and denial-of-service attacks. For example, when Windows attempts to interpret the device name as a file resource, it performs an invalid resource access that usually results in a crash [Howard 2002].

    +

    Device files in UNIX can be a security risk when an attacker can access them in an unauthorized way. For example, if attackers can read or write to the /dev/kmem device, they may be able to alter the priority, UID, or other attributes of their process or simply crash the system. Similarly, access to disk devices, tape devices, network devices, and terminals being used by other processes can lead to problems [Garfinkel 1996].

    +

    On Linux, it is possible to lock certain applications by attempting to open devices rather than files. Consider the following example:

    + /dev/mouse +/dev/console +/dev/tty0 +/dev/zero + +

    A Web browser that failed to check for these devices would allow an attacker to create a website with image tags such as <IMG src="file:///dev/mouse"> that would lock the user's mouse [Howard 2002].

    +
    +
    +

    In this noncompliant code example, the user can specify a locked device or a FIFO (first-in, first-out) file name, which can cause the program to hang on the call to fopen():

    + #include <stdio.h> +  +void func(const char *file_name) { + FILE *file; + if ((file = fopen(file_name, "wb")) == NULL) { + /* Handle error */ + } + + /* Operate on the file */ + + if (fclose(file) == EOF) { + /* Handle error */ + } +} +
    +
    +

    POSIX defines the O_NONBLOCK flag to open(), which ensures that delayed operations on a file do not hang the program [IEEE Std 1003.1:2013].

    +
    +

    When opening a FIFO with O_RDONLY or O_WRONLY set:

    +
      +
    • If O_NONBLOCK is set, an open() for reading-only returns without delay. An open() for writing-only returns an error if no process currently has the file open for reading.
    • +
    • If O_NONBLOCK is clear, an open() for reading-only blocks the calling thread until a thread opens the file for writing. An open() for writing-only blocks the calling thread until a thread opens the file for reading.
    • +
    +

    When opening a block special or character special file that supports nonblocking opens:

    +
      +
    • If O_NONBLOCK is set, the open() function returns without blocking for the device to be ready or available; subsequent behavior is device-specific.
    • +
    • If O_NONBLOCK is clear, the open() function blocks the calling thread until the device is ready or available before returning.
    • +
    +

    Otherwise, the behavior of O_NONBLOCK is unspecified.

    +
    +

    Once the file is open, programmers can use the POSIX lstat() and fstat() functions to obtain information about a file and the S_ISREG() macro to determine if the file is a regular file. 

    +

    Because the behavior of O_NONBLOCK on subsequent calls to read() or write() is unspecified, it is advisable to disable the flag after it has been determined that the file in question is not a special device.

    +

    When available (Linux 2.1.126+, FreeBSD, Solaris 10, POSIX.1-2008), the O_NOFOLLOW flag should also be used. (See POS01-C. Check for the existence of links when dealing with files.) When O_NOFOLLOW is not available, symbolic link checks should use the method from POS35-C. Avoid race conditions while checking for the existence of a symbolic link.

    + #include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +#ifdef O_NOFOLLOW + #define OPEN_FLAGS O_NOFOLLOW | O_NONBLOCK +#else + #define OPEN_FLAGS O_NONBLOCK +#endif + +void func(const char *file_name) { + struct stat orig_st; + struct stat open_st; + int fd; + int flags; + + if ((lstat(file_name, &orig_st) != 0) || + (!S_ISREG(orig_st.st_mode))) { + /* Handle error */ + } + + /* Race window */ + + fd = open(file_name, OPEN_FLAGS | O_WRONLY); + if (fd == -1) { + /* Handle error */ + } + + if (fstat(fd, &open_st) != 0) { + /* Handle error */ + } + + if ((orig_st.st_mode != open_st.st_mode) || + (orig_st.st_ino != open_st.st_ino) || + (orig_st.st_dev != open_st.st_dev)) { + /* The file was tampered with */ + } + + /* + * Optional: drop the O_NONBLOCK now that we are sure + * this is a good file. +  */ + if ((flags = fcntl(fd, F_GETFL)) == -1) { + /* Handle error */ + } + + if (fcntl(fd, F_SETFL, flags & ~O_NONBLOCK) == -1) { + /* Handle error */ + } + + /* Operate on the file */ + + if (close(fd) == -1) { + /* Handle error */ + } +} +

    This code contains an intractable TOCTOU (time-of-check, time-of-use) race condition under which an attacker can alter the file referenced by file_name following the call to lstat() but before the call to open(). The switch will be discovered after the file is opened, but opening the file cannot be prevented in the case where this action itself causes undesired behavior. (See FIO45-C. Avoid TOCTOU race conditions while accessing files for more information about TOCTOU race conditions.)

    +

    Essentially, an attacker can switch out a file for one of the file types shown in the following table with the specified effect.

    +

    File Types and Effects

    + + + + + + + + + + + + + + + + + + + + + + + +
    + Type + + Note on Effect +
    + Another regular file + + The + fstat() + verification fails. +
    + FIFO + + Either + open() + returns + -1 + and sets + errno + to + ENXIO + , or + open() + succeeds and the + fstat() + verification fails. +
    + Symbolic link + + open() + returns + -1 + if + O_NOFOLLOW + is available; otherwise, the + fstat() + verification fails. +
    + Special device + + Usually the + fstat() + verification fails on + st_mode + . This can still be a problem if the device is one for which just opening (or closing) it causes a side effect. If + st_mode + compares equal, then the device is one that, after opening, appears to be a regular file. It would then fail the + fstat() + verification on + st_dev + and + st_ino + (unless it happens to be the + + same + + file, as can happen with + /dev/fd/* + on Solaris, but this would not be a problem). +
    +

    To be compliant with this rule and to prevent this TOCTOU race condition, file_name must refer to a file in a secure directory. (See FIO15-C. Ensure that file operations are performed in a secure directory.)

    +
    +
    +

    This noncompliant code example uses the GetFileType() function to attempt to prevent opening a special file: 

    + #include <Windows.h> + +void func(const TCHAR *file_name) { + HANDLE hFile = CreateFile( + file_name, + GENERIC_READ | GENERIC_WRITE, 0, + NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL + ); + if (hFile == INVALID_HANDLE_VALUE) { + /* Handle error */ + } else if (GetFileType(hFile) != FILE_TYPE_DISK) { + /* Handle error */ + CloseHandle(hFile); + } else { + /* Operate on the file */ + CloseHandle(hFile); + } +} +

    Although tempting, the Win32 GetFileType() function is dangerous in this case. If the file name given identifies a named pipe that is currently blocking on a read request, the call to GetFileType() will block until the read request completes. This provides an effective attack vector for a denial-of-service attack on the application. Furthermore, the act of opening a file handle may cause side effects, such as line states being set to their default voltage when opening a serial device.

    +
    +
    +

    Microsoft documents a list of reserved identifiers that represent devices and have a device namespace to be used specifically by devices [MSDN]. In this compliant solution, the isReservedName() function can be used to determine if a specified path refers to a device. Care must be taken to avoid a TOCTOU race condition when first testing a path name using the isReservedName() function and then later operating on that path name.

    + #include <ctype.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +static bool isReservedName(const char *path) { + /* This list of reserved names comes from MSDN */ + static const char *reserved[] = { + "nul", "con", "prn", "aux", "com1", "com2", "com3", + "com4", "com5", "com6", "com7", "com8", "com9", + "lpt1", "lpt2", "lpt3", "lpt4", "lpt5", "lpt6", + "lpt7", "lpt8", "lpt9" + }; + bool ret = false; + +/* + * First, check to see if this is a device namespace, which + * always starts with \\.\, because device namespaces are not + * valid file paths. + */ + +  if (!path || 0 == strncmp(path, "\\\\.\\", 4)) { + return true; + } + + /* Compare against the list of ancient reserved names */ + for (size_t i = 0; !ret && + i < sizeof(reserved) / sizeof(*reserved); ++i) { + /* + * Because Windows uses a case-insensitive file system, operate on + * a lowercase version of the given filename. Note: This ignores + * globalization issues and assumes ASCII characters. + */ + if (0 == _stricmp(path, reserved[i])) { + ret = true; + } + } + return ret; +} +
    +
    +

    Allowing operations that are appropriate only for regular files to be performed on devices can result in denial-of-service attacks or more serious exploits depending on the platform.

    + + + + + + + + + + + + + + + + + + + +
    + Rule + + Severity + + Likelihood + + Remediation Cost + + Priority + + Level +
    + FIO32-C + + Medium + + Unlikely + + Medium + + P4 + + L3 +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Tool + + Version + + Checker + + Description +
    + + Compass/ROSE + + + + + Could detect some violations of this rule. This rule applies only to untrusted file name strings, and ROSE cannot tell which strings are trusted and which are not. The best heuristic is to note if there is any verification of the file name before or after the + fopen() + call. If there is any verification, then the file opening should be preceded by an + lstat() + call and succeeded by an + fstat() + call. Although that does not enforce the rule completely, it does indicate that the coder is aware of the + lstat-fopen + - + fstat + idiom +
    + + Helix QAC + + + 2022.1 + + C4921, C4922, C4923 + C++4921, C++4922, C++4923 + +
    + + Parasoft C/C++test + + + 2021.2 + + CERT_C-FIO32-a + + Protect against file name injection +
    + + Polyspace Bug Finder + + + R2022a + + + CERT C: Rule FIO32-C + + + Checks for inappropriate I/O operation on device files (rule fully covered) +
    + + PRQA QA-C + + + 9.7 + + 4921, 4922, 4923 + + Enforced by QAC +
    + + PRQA QA-C++ + + + 4.4 + + 4921, 4922, 4923 + +
    +
    +
    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    +
    +
    +

    Key here (explains table format and definitions)

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Taxonomy + + Taxonomy item + + Relationship +
    + + CERT C Secure Coding Standard + + + + FIO05-C. Identify files using multiple file attributes + + + Prior to 2018-01-12: CERT: Unspecified Relationship +
    + + CERT C Secure Coding Standard + + + + FIO15-C. Ensure that file operations are performed in a secure directory + + + Prior to 2018-01-12: CERT: Unspecified Relationship +
    + + CERT C Secure Coding Standard + + + + POS01-C. Check for the existence of links when dealing with files + + + Prior to 2018-01-12: CERT: Unspecified Relationship +
    + + CERT C Secure Coding Standard + + + + POS35-C. Avoid race conditions while checking for the existence of a symbolic link + + + Prior to 2018-01-12: CERT: Unspecified Relationship +
    + + CERT Oracle Secure Coding Standard for Java + + + + FIO00-J. Do not operate on files in shared directories + + + Prior to 2018-01-12: CERT: Unspecified Relationship +
    +
    +
    +

    Key here for mapping notes

    +

    CWE-67 and FIO32-C

    +

    FIO32-C = Union( CWE-67, list) where list =

    +
      +
    • Treating trusted device names like regular files in Windows.
    • +
    +
      +
    • Treating device names (both trusted and untrusted) like regular files in POSIX
    • +
    +
    +
    + + + + + + + + + + + + + + + + + + + +
    + [ + + Garfinkel 1996 + + ] + + Section 5.6, "Device Files" +
    + [ + + Howard 2002 + + ] + + Chapter 11, "Canonical Representation Issues" +
    + [ + + IEEE Std 1003.1:2013 + + ] + + XSH, System Interfaces, + open +
    + [ + + MSDN + + ] + +
    +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO32-C/DoNotPerformFileOperationsOnDevices.qhelp b/c/cert/src/rules/FIO32-C/DoNotPerformFileOperationsOnDevices.qhelp new file mode 100644 index 0000000000..439daed07c --- /dev/null +++ b/c/cert/src/rules/FIO32-C/DoNotPerformFileOperationsOnDevices.qhelp @@ -0,0 +1,18 @@ + + + + +

    This query implements the CERT-C rule FIO32-C:

    +
    +

    Do not perform operations on devices that are only appropriate for files

    +
    +
    + + +
  • + CERT-C: + FIO32-C: Do not perform operations on devices that are only appropriate for files + . +
  • +
    + \ No newline at end of file diff --git a/c/cert/src/rules/FIO32-C/DoNotPerformFileOperationsOnDevices.ql b/c/cert/src/rules/FIO32-C/DoNotPerformFileOperationsOnDevices.ql new file mode 100644 index 0000000000..2d16b2ffea --- /dev/null +++ b/c/cert/src/rules/FIO32-C/DoNotPerformFileOperationsOnDevices.ql @@ -0,0 +1,64 @@ +/** + * @id c/cert/do-not-perform-file-operations-on-devices + * @name FIO32-C: Do not perform operations on devices that are only appropriate for files + * @description Performing file operations on devices can result in crashes. + * @kind path-problem + * @precision medium + * @problem.severity error + * @tags external/cert/id/fio32-c + * correctness + * security + * external/cert/obligation/rule + */ + +import cpp +import codingstandards.c.cert +import semmle.code.cpp.security.FunctionWithWrappers +import semmle.code.cpp.security.Security +import semmle.code.cpp.security.TaintTracking +import TaintedWithPath + +// Query TaintedPath.ql from the CodeQL standard library +/** + * A function for opening a file. + */ +class FileFunction extends FunctionWithWrappers { + FileFunction() { + exists(string nme | this.hasGlobalName(nme) | + nme = ["fopen", "_fopen", "_wfopen", "open", "_open", "_wopen"] + or + // create file function on windows + nme.matches("CreateFile%") + ) + or + this.hasQualifiedName("std", "fopen") + or + // on any of the fstream classes, or filebuf + exists(string nme | this.getDeclaringType().hasQualifiedName("std", nme) | + nme = ["basic_fstream", "basic_ifstream", "basic_ofstream", "basic_filebuf"] + ) and + // we look for either the open method or the constructor + (this.getName() = "open" or this instanceof Constructor) + } + + // conveniently, all of these functions take the path as the first parameter! + override predicate interestingArg(int arg) { arg = 0 } +} + +class TaintedPathConfiguration extends TaintTrackingConfiguration { + override predicate isSink(Element tainted) { + exists(FileFunction fileFunction | fileFunction.outermostWrapperFunctionCall(tainted, _)) + } +} + +from + FileFunction fileFunction, Expr taintedArg, Expr taintSource, PathNode sourceNode, + PathNode sinkNode, string taintCause, string callChain +where + not isExcluded(taintedArg, IO3Package::doNotPerformFileOperationsOnDevicesQuery()) and + fileFunction.outermostWrapperFunctionCall(taintedArg, callChain) and + taintedWithPath(taintSource, taintedArg, sourceNode, sinkNode) and + isUserInput(taintSource, taintCause) +select taintedArg, sourceNode, sinkNode, + "This argument to a file access function is derived from $@ and then passed to " + callChain, + taintSource, "user input (" + taintCause + ")" diff --git a/c/cert/src/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString-standard.qhelp b/c/cert/src/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString-standard.qhelp new file mode 100644 index 0000000000..e4ce1eaf65 --- /dev/null +++ b/c/cert/src/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString-standard.qhelp @@ -0,0 +1,392 @@ + + +
    +

    Errors can occur when incorrect assumptions are made about the type of data being read. These assumptions may be violated, for example, when binary data has been read from a file instead of text from a user's terminal or the output of a process is piped to stdin. (See FIO14-C. Understand the difference between text mode and binary mode with file streams.) On some systems, it may also be possible to input a null byte (as well as other binary codes) from the keyboard.

    +

    Subclause 7.21.7.2 of the C Standard [ISO/IEC 9899:2011] says,

    +
    +

    The fgets function returns s if successful. If end-of-file is encountered and no characters have been read into the array, the contents of the array remain unchanged and a null pointer is returned.

    +
    +

    The wide-character function fgetws() has the same behavior. Therefore, if fgets() or fgetws() returns a non-null pointer, it is safe to assume that the array contains data. However, it is erroneous to assume that the array contains a nonempty string because the data may contain null characters.

    +
    +
    +

    This noncompliant code example attempts to remove the trailing newline (\n) from an input line. The fgets() function is typically used to read a newline-terminated line of input from a stream. It takes a size parameter for the destination buffer and copies, at most, size - 1 characters from a stream to a character array.

    + #include <stdio.h> +#include <string.h> + +enum { BUFFER_SIZE = 1024 }; + +void func(void) { + char buf[BUFFER_SIZE]; + + if (fgets(buf, sizeof(buf), stdin) == NULL) { + /* Handle error */ + } + buf[strlen(buf) - 1] = '\0'; +} +

    The strlen() function computes the length of a string by determining the number of characters that precede the terminating null character. A problem occurs if the first character read from the input by fgets() happens to be a null character. This may occur, for example, if a binary data file is read by the fgets() call [Lai 2006]. If the first character in buf is a null character, strlen(buf) returns 0, the expression strlen(buf) - 1 wraps around to a large positive value, and a write-outside-array-bounds error occurs.

    +
    +
    +

    This compliant solution uses strchr() to replace the newline character in the string if it exists:

    + #include <stdio.h> +#include <string.h> + +enum { BUFFER_SIZE = 1024 }; + +void func(void) { + char buf[BUFFER_SIZE]; + char *p; + + if (fgets(buf, sizeof(buf), stdin)) { + p = strchr(buf, '\n'); + if (p) { + *p = '\0'; + } + } else { + /* Handle error */ + } +} +
    +
    +

    Incorrectly assuming that character data has been read can result in an out-of-bounds memory write or other flawed logic.

    + + + + + + + + + + + + + + + + + + + +
    + Rule + + Severity + + Likelihood + + Remediation Cost + + Priority + + Level +
    + FIO37-C + + High + + Probable + + Medium + + P12 + + L1 +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Tool + + Version + + Checker + + Description +
    + + Astrée + + + 20.10 + + + Supported: Astrée reports defects due to returned (empty) strings. +
    + + Axivion Bauhaus Suite + + + 7.2.0 + + CertC-FIO37 + +
    + + CodeSonar + + + 6.2p0 + + (general) + + Considers the possibility that + fgets() + and + fgetws() + may return empty strings (Warnings of various classes may be triggered depending on subsequent operations on those strings. For example, the noncompliant code example cited above would trigger a buffer underrun warning.) +
    + + Compass/ROSE + + + + + Could detect some violations of this rule (In particular, it could detect the noncompliant code example by searching for + fgets() + , followed by + strlen() - 1 + , which could be −1. The crux of this rule is that a string returned by + fgets() + could still be empty, because the first + char + is ' + \0 + '. There are probably other code examples that violate this guideline; they would need to be enumerated before ROSE could detect them.) +
    + + Helix QAC + + + 2022.1 + + C4911, C4912, C4913 + C++4911, C++4912, C++4913 + +
    + + LDRA tool suite + + + 9.7.1 + + 44 S + + Enhanced enforcement +
    + + Parasoft C/C++test + + + 2021.2 + + CERT_C-FIO37-a + + Avoid accessing arrays out of bounds +
    + + Polyspace Bug Finder + + + R2022a + + + CERT C: Rule FIO37-C + + + Checks for use of indeterminate string (rule fully covered) +
    + + PRQA QA-C++ + + + 4.4 + + 2844 + +
    +
    +
    +

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    +
    +
    +

    Key here (explains table format and definitions)

    + + + + + + + + + + + + + + + + + + + + + + + +
    + Taxonomy + + Taxonomy item + + Relationship +
    + + CERT C Secure Coding Standard + + + + FIO14-C. Understand the difference between text mode and binary mode with file streams + + + Prior to 2018-01-12: CERT: Unspecified Relationship +
    + + CERT C Secure Coding Standard + + + + FIO20-C. Avoid unintentional truncation when using fgets() or fgetws() + + + Prior to 2018-01-12: CERT: Unspecified Relationship +
    + + CWE 2.11 + + + + CWE-241 + + , Improper Handling of Unexpected Data Type + + 2017-07-05: CERT: Rule subset of CWE +
    +
    +
    +

    Key here for mapping notes

    +

    CWE-241 and FIO37-C

    +

    CWE-241 = Union( FIO37-C, list) where list =

    +
      +
    • Improper handling of unexpected data type that does not come from the fgets() function.
    • +
    +
    +
    + + + + + + + + + + + + + + + +
    + [ + + ISO/IEC 9899:2011 + + ] + + Subclause 7.21.7.2, "The + fgets + Function" + Subclause 7.29.3.2, "The + fgetws + Function" +
    + [ + + Lai 2006 + + ] + +
    + [ + + Seacord 2013 + + ] + + Chapter 2, "Strings" +
    +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString.qhelp b/c/cert/src/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString.qhelp new file mode 100644 index 0000000000..0ef132869f --- /dev/null +++ b/c/cert/src/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString.qhelp @@ -0,0 +1,18 @@ + + + + +

    This query implements the CERT-C rule FIO37-C:

    +
    +

    Do not assume that fgets() or fgetws() returns a nonempty string when successful

    +
    +
    + + +
  • + CERT-C: + FIO37-C: Do not assume that fgets() or fgetws() returns a nonempty string when successful + . +
  • +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString.ql b/c/cert/src/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString.ql new file mode 100644 index 0000000000..54f555d7cb --- /dev/null +++ b/c/cert/src/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString.ql @@ -0,0 +1,48 @@ +/** + * @id c/cert/successful-fgets-or-fgetws-may-return-an-empty-string + * @name FIO37-C: Do not assume that fgets() or fgetws() returns a nonempty string when successful + * @description A string returned by fgets() or fegtws() might be empty. + * @kind problem + * @precision high + * @problem.severity error + * @tags external/cert/id/fio37-c + * correctness + * external/cert/obligation/rule + */ + +import cpp +import codingstandards.c.cert +import codingstandards.cpp.FgetsErrorManagement +import codingstandards.cpp.Dereferenced +import semmle.code.cpp.dataflow.TaintTracking + +/* + * CFG nodes that follows a successful call to `fgets` + */ + +ControlFlowNode followsNonnullFgets(FgetsLikeCall fgets) { + exists(FgetsGuard guard | + //fgets.getLocation().getStartLine() = [60] and + fgets = guard.getFgetCall() and + ( + result = guard.getNonNullSuccessor() + or + result = followsNonnullFgets(fgets).getASuccessor() + ) + ) +} + +from Expr e, FgetsLikeCall fgets +where + not isExcluded(e, IO3Package::successfulFgetsOrFgetwsMayReturnAnEmptyStringQuery()) and + e = followsNonnullFgets(fgets) and + ( + e instanceof ArrayExpr + or + e instanceof PointerDereferenceExpr + ) and + not exists(GuardCondition guard | + guard.controls(e.getBasicBlock(), _) and guard = followsNonnullFgets(fgets) + ) +select e, "The string $@ could be empty when accessed at this location.", fgets.getBuffer(), + fgets.getBuffer().toString() diff --git a/c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.ql b/c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.ql index 30432797ad..69fb92a15c 100644 --- a/c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.ql +++ b/c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.ql @@ -58,9 +58,6 @@ class BuffAccessExpr extends Expr { // dereferenced expressions this instanceof DereferencedExpr or - // any array access `array[0]` - this = any(ArrayExpr ae).getArrayBase() - or // any parameter to a function this = any(FunctionCall fc).getAnArgument() } diff --git a/c/cert/src/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar-standard.qhelp b/c/cert/src/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar-standard.qhelp new file mode 100644 index 0000000000..458fbe3f7d --- /dev/null +++ b/c/cert/src/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar-standard.qhelp @@ -0,0 +1,33 @@ + + +
    +
      +
    • required
    • +
    • implementation
    • +
    • automated
    • +
    +
    + +
    +

    + ... +

    + +
    + +
    +

    + ... +

    +
    + + + + + +
    +
      +
    • ...
    • +
    +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar.qhelp b/c/cert/src/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar.qhelp new file mode 100644 index 0000000000..63fc3848bb --- /dev/null +++ b/c/cert/src/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar.qhelp @@ -0,0 +1,18 @@ + + + + +

    This query implements the CERT-C rule STR37-C:

    +
    +

    Arguments to character-handling functions must be representable as an unsigned char

    +
    +
    + + +
  • + CERT-C: + STR37-C: Arguments to character-handling functions must be representable as an unsigned char + . +
  • +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar.ql b/c/cert/src/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar.ql new file mode 100644 index 0000000000..cb742859cc --- /dev/null +++ b/c/cert/src/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar.ql @@ -0,0 +1,29 @@ +/** + * @id c/cert/to-character-handling-functions-representable-as-u-char + * @name STR37-C: Arguments to character-handling functions must be representable as an unsigned char + * @description Arguments that are not representable as an unsigned char may produce unpredictable + * program behavior. + * @kind problem + * @precision high + * @problem.severity error + * @tags external/cert/id/str37-c + * correctness + * security + * external/cert/obligation/rule + */ + +import cpp +import codingstandards.c.cert +import codingstandards.cpp.CharFunctions + +from FunctionCall fc, Expr arg +where + not isExcluded(fc, Strings2Package::toCharacterHandlingFunctionsRepresentableAsUCharQuery()) and + // examine all impacted functions + fc.getTarget() instanceof CToOrIsCharFunction and + arg = fc.getArgument(0).getFullyConverted() and + // report on cases where either the explicit or implicit cast + // on the parameter type is not unsigned + not arg.(CStyleCast).getExpr().getType() instanceof UnsignedCharType +select fc, "$@ to character-handling function may not be representable as an unsigned char.", arg, + "Argument" diff --git a/c/cert/src/rules/FIO39-C/standard-example.c b/c/cert/src/rules/STR37-C/standard-example.c similarity index 100% rename from c/cert/src/rules/FIO39-C/standard-example.c rename to c/cert/src/rules/STR37-C/standard-example.c diff --git a/c/cert/test/qlpack.yml b/c/cert/test/qlpack.yml index dfe16b190e..4ae74b3c81 100644 --- a/c/cert/test/qlpack.yml +++ b/c/cert/test/qlpack.yml @@ -1,4 +1,4 @@ name: cert-c-coding-standards-tests -version: 2.3.0 +version: 2.4.0 libraryPathDependencies: cert-c-coding-standards extractor: cpp \ No newline at end of file diff --git a/c/cert/test/rules/FIO32-C/DoNotPerformFileOperationsOnDevices.expected b/c/cert/test/rules/FIO32-C/DoNotPerformFileOperationsOnDevices.expected new file mode 100644 index 0000000000..c9252151d5 --- /dev/null +++ b/c/cert/test/rules/FIO32-C/DoNotPerformFileOperationsOnDevices.expected @@ -0,0 +1,40 @@ +edges +| test.c:20:15:20:23 | array to pointer conversion | test.c:21:8:21:16 | (const char *)... | +| test.c:20:15:20:23 | array to pointer conversion | test.c:21:8:21:16 | file_name | +| test.c:20:15:20:23 | array to pointer conversion | test.c:21:8:21:16 | file_name indirection | +| test.c:20:15:20:23 | file_name | test.c:21:8:21:16 | (const char *)... | +| test.c:20:15:20:23 | file_name | test.c:21:8:21:16 | file_name | +| test.c:20:15:20:23 | file_name | test.c:21:8:21:16 | file_name indirection | +| test.c:20:15:20:23 | scanf output argument | test.c:21:8:21:16 | (const char *)... | +| test.c:20:15:20:23 | scanf output argument | test.c:21:8:21:16 | file_name | +| test.c:20:15:20:23 | scanf output argument | test.c:21:8:21:16 | file_name indirection | +| test.c:45:15:45:23 | array to pointer conversion | test.c:46:29:46:37 | (LPCTSTR)... | +| test.c:45:15:45:23 | array to pointer conversion | test.c:46:29:46:37 | file_name | +| test.c:45:15:45:23 | array to pointer conversion | test.c:46:29:46:37 | file_name indirection | +| test.c:45:15:45:23 | file_name | test.c:46:29:46:37 | (LPCTSTR)... | +| test.c:45:15:45:23 | file_name | test.c:46:29:46:37 | file_name | +| test.c:45:15:45:23 | file_name | test.c:46:29:46:37 | file_name indirection | +| test.c:45:15:45:23 | scanf output argument | test.c:46:29:46:37 | (LPCTSTR)... | +| test.c:45:15:45:23 | scanf output argument | test.c:46:29:46:37 | file_name | +| test.c:45:15:45:23 | scanf output argument | test.c:46:29:46:37 | file_name indirection | +subpaths +nodes +| test.c:20:15:20:23 | array to pointer conversion | semmle.label | array to pointer conversion | +| test.c:20:15:20:23 | file_name | semmle.label | file_name | +| test.c:20:15:20:23 | scanf output argument | semmle.label | scanf output argument | +| test.c:21:8:21:16 | (const char *)... | semmle.label | (const char *)... | +| test.c:21:8:21:16 | (const char *)... | semmle.label | (const char *)... | +| test.c:21:8:21:16 | file_name | semmle.label | file_name | +| test.c:21:8:21:16 | file_name indirection | semmle.label | file_name indirection | +| test.c:21:8:21:16 | file_name indirection | semmle.label | file_name indirection | +| test.c:45:15:45:23 | array to pointer conversion | semmle.label | array to pointer conversion | +| test.c:45:15:45:23 | file_name | semmle.label | file_name | +| test.c:45:15:45:23 | scanf output argument | semmle.label | scanf output argument | +| test.c:46:29:46:37 | (LPCTSTR)... | semmle.label | (LPCTSTR)... | +| test.c:46:29:46:37 | (LPCTSTR)... | semmle.label | (LPCTSTR)... | +| test.c:46:29:46:37 | file_name | semmle.label | file_name | +| test.c:46:29:46:37 | file_name indirection | semmle.label | file_name indirection | +| test.c:46:29:46:37 | file_name indirection | semmle.label | file_name indirection | +#select +| test.c:21:8:21:16 | file_name | test.c:20:15:20:23 | file_name | test.c:21:8:21:16 | file_name | This argument to a file access function is derived from $@ and then passed to func(file_name), which calls fopen((unnamed parameter 0)) | test.c:20:15:20:23 | file_name | user input (scanf) | +| test.c:46:29:46:37 | file_name | test.c:45:15:45:23 | file_name | test.c:46:29:46:37 | file_name | This argument to a file access function is derived from $@ and then passed to CreateFile(lpFileName) | test.c:45:15:45:23 | file_name | user input (scanf) | diff --git a/c/cert/test/rules/FIO32-C/DoNotPerformFileOperationsOnDevices.qlref b/c/cert/test/rules/FIO32-C/DoNotPerformFileOperationsOnDevices.qlref new file mode 100644 index 0000000000..a6c5fea94d --- /dev/null +++ b/c/cert/test/rules/FIO32-C/DoNotPerformFileOperationsOnDevices.qlref @@ -0,0 +1 @@ +rules/FIO32-C/DoNotPerformFileOperationsOnDevices.ql \ No newline at end of file diff --git a/c/cert/test/rules/FIO32-C/test.c b/c/cert/test/rules/FIO32-C/test.c new file mode 100644 index 0000000000..063cd287d8 --- /dev/null +++ b/c/cert/test/rules/FIO32-C/test.c @@ -0,0 +1,50 @@ +#include +#include +#include + +void func(const char *file_name) { + FILE *file; + if ((file = fopen(file_name, "wb")) == NULL) { + /* Handle error */ + } + + /* Operate on the file */ + + if (fclose(file) == EOF) { + /* Handle error */ + } +} + +int main(int argc, char **argv) { + char file_name[20]; + scanf("%s", file_name); + func(file_name); // NON_COMPLIANT + func("file_name"); // COMPLIANT +} + +// --- Windows --- + +typedef void *HANDLE; +#define GENERIC_READ 0x80000000 +#define GENERIC_WRITE 0x40000000 +#define OPEN_EXISTING 3 +#define FILE_ATTRIBUTE_NORMAL 0x00000080 +typedef const char *LPCTSTR; +typedef unsigned long DWORD; +typedef struct _SECURITY_ATTRIBUTES { +} * LPSECURITY_ATTRIBUTES; +typedef bool BOOL; +HANDLE CreateFile(LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, + LPSECURITY_ATTRIBUTES lpSecurityAttributes, + DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, + HANDLE hTemplateFile); +BOOL CloseHandle(HANDLE hObject); + +void funcWin() { + char file_name[20]; + scanf("%s", file_name); + HANDLE hFile = CreateFile(file_name, // NON_COMPLIANT + GENERIC_READ | GENERIC_WRITE, 0, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + CloseHandle(hFile); +} \ No newline at end of file diff --git a/c/cert/test/rules/FIO34-C/EndOfFileCheckPortability.expected b/c/cert/test/rules/FIO34-C/EndOfFileCheckPortability.expected index 38df60ea29..7ba0133dcc 100644 --- a/c/cert/test/rules/FIO34-C/EndOfFileCheckPortability.expected +++ b/c/cert/test/rules/FIO34-C/EndOfFileCheckPortability.expected @@ -1,6 +1,5 @@ | test.c:11:12:11:19 | ... != ... | This check is only portable to platforms where type `char` is less wide than type `int`. | | test.c:19:12:19:19 | ... != ... | This check is only portable to platforms where type `char` is less wide than type `int`. | -| test.c:77:13:77:22 | ... != ... | This check is only portable to platforms where type `char` is less wide than type `int`. | | test.c:96:12:96:19 | ... != ... | This check is only portable to platforms where type `char` is less wide than type `int`. | | test.c:101:10:102:15 | ... != ... | This check is only portable to platforms where type `char` is less wide than type `int`. | | test.c:116:12:116:19 | ... != ... | This check is only portable to platforms where type `char` is less wide than type `int`. | diff --git a/c/cert/test/rules/FIO34-C/test.c b/c/cert/test/rules/FIO34-C/test.c index 7bf1119c00..0faf978cd7 100644 --- a/c/cert/test/rules/FIO34-C/test.c +++ b/c/cert/test/rules/FIO34-C/test.c @@ -74,7 +74,7 @@ void f4(void) { size_t i = 0; while ((wc = getwc(stdin)) != L'\n' // COMPLIANT - && wc != WEOF) { // NON_PORTABLE + && wc != WEOF) { // PORTABLE if (i < BUFFER_SIZE - 1) { buf[i++] = wc; } diff --git a/c/cert/test/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString.expected b/c/cert/test/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString.expected new file mode 100644 index 0000000000..36b28900c6 --- /dev/null +++ b/c/cert/test/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString.expected @@ -0,0 +1 @@ +| test.c:13:3:13:22 | access to array | The string $@ could be empty when accessed at this location. | test.c:8:13:8:15 | buf | buf | diff --git a/c/cert/test/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString.qlref b/c/cert/test/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString.qlref new file mode 100644 index 0000000000..a831b3dcf6 --- /dev/null +++ b/c/cert/test/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString.qlref @@ -0,0 +1 @@ +rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString.ql \ No newline at end of file diff --git a/c/cert/test/rules/FIO37-C/test.c b/c/cert/test/rules/FIO37-C/test.c new file mode 100644 index 0000000000..5c59d855aa --- /dev/null +++ b/c/cert/test/rules/FIO37-C/test.c @@ -0,0 +1,56 @@ +#include +#include +#include + +char buf[1024]; + +void f1() { + if (fgets(buf, sizeof(buf), stdin) == NULL) { + /*null*/ + return; + } + /*notnull*/ + buf[strlen(buf) - 1] = '\0'; // NON_COMPLIANT + return; +} + +void f2() { + char *p; + if (fgets(buf, sizeof(buf), stdin)) { + /*notnull*/ + p = strchr(buf, '\n'); + if (p) { + *p = '\0'; // COMPLIANT + } + } + return; +} + +static inline bool strends(const char *str, const char *postfix) { + if (strlen(str) < strlen(postfix)) + return false; + + return strcmp(str + strlen(str) - strlen(postfix), postfix) == 0; +} +void f3() { + if (fgets(buf, sizeof(buf), stdin)) { + /*notnull*/ + if (strends(buf, "\n")) { + buf[strlen(buf) - 1] = '\0'; // COMPLIANT + } + } + return; +} + +void f4() { + char *p; + if (fgets(buf, sizeof(buf), stdin) == NULL) { + return; + } + p = strchr(buf, '\n'); + if (p) { + *p = '\0'; // COMPLIANT + } + + return; +} diff --git a/c/cert/test/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar.expected b/c/cert/test/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar.expected new file mode 100644 index 0000000000..b655289f4e --- /dev/null +++ b/c/cert/test/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar.expected @@ -0,0 +1,28 @@ +| test.c:7:3:7:9 | call to isalnum | $@ to character-handling function may not be representable as an unsigned char. | test.c:7:11:7:12 | (int)... | Argument | +| test.c:8:3:8:13 | call to isalpha | $@ to character-handling function may not be representable as an unsigned char. | test.c:8:11:8:12 | (int)... | Argument | +| test.c:10:3:10:9 | call to isblank | $@ to character-handling function may not be representable as an unsigned char. | test.c:10:11:10:12 | (int)... | Argument | +| test.c:11:3:11:9 | call to iscntrl | $@ to character-handling function may not be representable as an unsigned char. | test.c:11:11:11:12 | (int)... | Argument | +| test.c:12:3:12:13 | call to isdigit | $@ to character-handling function may not be representable as an unsigned char. | test.c:12:11:12:12 | (int)... | Argument | +| test.c:13:3:13:13 | call to isgraph | $@ to character-handling function may not be representable as an unsigned char. | test.c:13:11:13:12 | (int)... | Argument | +| test.c:14:3:14:13 | call to islower | $@ to character-handling function may not be representable as an unsigned char. | test.c:14:11:14:12 | (int)... | Argument | +| test.c:15:3:15:13 | call to isprint | $@ to character-handling function may not be representable as an unsigned char. | test.c:15:11:15:12 | (int)... | Argument | +| test.c:16:3:16:9 | call to ispunct | $@ to character-handling function may not be representable as an unsigned char. | test.c:16:11:16:12 | (int)... | Argument | +| test.c:17:3:17:13 | call to __isspace | $@ to character-handling function may not be representable as an unsigned char. | test.c:17:11:17:12 | (int)... | Argument | +| test.c:18:3:18:13 | call to isupper | $@ to character-handling function may not be representable as an unsigned char. | test.c:18:11:18:12 | (int)... | Argument | +| test.c:19:3:19:10 | call to isxdigit | $@ to character-handling function may not be representable as an unsigned char. | test.c:19:12:19:13 | (int)... | Argument | +| test.c:21:3:21:9 | call to toupper | $@ to character-handling function may not be representable as an unsigned char. | test.c:21:11:21:12 | (int)... | Argument | +| test.c:22:3:22:9 | call to tolower | $@ to character-handling function may not be representable as an unsigned char. | test.c:22:11:22:12 | (int)... | Argument | +| test.c:70:3:70:9 | call to isalnum | $@ to character-handling function may not be representable as an unsigned char. | test.c:70:11:70:11 | t | Argument | +| test.c:71:3:71:12 | call to isalpha | $@ to character-handling function may not be representable as an unsigned char. | test.c:71:11:71:11 | t | Argument | +| test.c:73:3:73:9 | call to isblank | $@ to character-handling function may not be representable as an unsigned char. | test.c:73:11:73:11 | t | Argument | +| test.c:74:3:74:9 | call to iscntrl | $@ to character-handling function may not be representable as an unsigned char. | test.c:74:11:74:11 | t | Argument | +| test.c:75:3:75:12 | call to isdigit | $@ to character-handling function may not be representable as an unsigned char. | test.c:75:11:75:11 | t | Argument | +| test.c:76:3:76:12 | call to isgraph | $@ to character-handling function may not be representable as an unsigned char. | test.c:76:11:76:11 | t | Argument | +| test.c:77:3:77:12 | call to islower | $@ to character-handling function may not be representable as an unsigned char. | test.c:77:11:77:11 | t | Argument | +| test.c:78:3:78:12 | call to isprint | $@ to character-handling function may not be representable as an unsigned char. | test.c:78:11:78:11 | t | Argument | +| test.c:79:3:79:9 | call to ispunct | $@ to character-handling function may not be representable as an unsigned char. | test.c:79:11:79:11 | t | Argument | +| test.c:80:3:80:12 | call to __isspace | $@ to character-handling function may not be representable as an unsigned char. | test.c:80:11:80:11 | t | Argument | +| test.c:81:3:81:12 | call to isupper | $@ to character-handling function may not be representable as an unsigned char. | test.c:81:11:81:11 | t | Argument | +| test.c:82:3:82:10 | call to isxdigit | $@ to character-handling function may not be representable as an unsigned char. | test.c:82:12:82:12 | t | Argument | +| test.c:84:3:84:9 | call to toupper | $@ to character-handling function may not be representable as an unsigned char. | test.c:84:11:84:11 | t | Argument | +| test.c:85:3:85:9 | call to tolower | $@ to character-handling function may not be representable as an unsigned char. | test.c:85:11:85:11 | t | Argument | diff --git a/c/cert/test/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar.qlref b/c/cert/test/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar.qlref new file mode 100644 index 0000000000..d796e16538 --- /dev/null +++ b/c/cert/test/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar.qlref @@ -0,0 +1 @@ +rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar.ql \ No newline at end of file diff --git a/c/cert/test/rules/STR37-C/test.c b/c/cert/test/rules/STR37-C/test.c new file mode 100644 index 0000000000..639e4b8f0c --- /dev/null +++ b/c/cert/test/rules/STR37-C/test.c @@ -0,0 +1,86 @@ +#include +#include + +void f1() { + char *t; + + isalnum(*t); // NON_COMPLIANT + isalpha(*t); // NON_COMPLIANT + // isascii(*t); // Not part of the C Standard + isblank(*t); // NON_COMPLIANT + iscntrl(*t); // NON_COMPLIANT + isdigit(*t); // NON_COMPLIANT + isgraph(*t); // NON_COMPLIANT + islower(*t); // NON_COMPLIANT + isprint(*t); // NON_COMPLIANT + ispunct(*t); // NON_COMPLIANT + isspace(*t); // NON_COMPLIANT + isupper(*t); // NON_COMPLIANT + isxdigit(*t); // NON_COMPLIANT + // toascii(i); // Not part of the C Standard + toupper(*t); // NON_COMPLIANT + tolower(*t); // NON_COMPLIANT +} + +void f2() { + unsigned char *t; + + isalnum(*t); // COMPLIANT + isalpha(*t); // COMPLIANT + // isascii(*t); // Not part of the C Standard + isblank(*t); // COMPLIANT + iscntrl(*t); // COMPLIANT + isdigit(*t); // COMPLIANT + isgraph(*t); // COMPLIANT + islower(*t); // COMPLIANT + isprint(*t); // COMPLIANT + ispunct(*t); // COMPLIANT + isspace(*t); // COMPLIANT + isupper(*t); // COMPLIANT + isxdigit(*t); // COMPLIANT + // toascii(i); // Not part of the C Standard + toupper(*t); // COMPLIANT + tolower(*t); // COMPLIANT +} + +void f3() { + char *t; + + isalnum((unsigned char)*t); // COMPLIANT + isalpha((unsigned char)*t); // COMPLIANT + // isascii((unsigned char*)*t); // Not part of the C Standard + isblank((unsigned char)*t); // COMPLIANT + iscntrl((unsigned char)*t); // COMPLIANT + isdigit((unsigned char)*t); // COMPLIANT + isgraph((unsigned char)*t); // COMPLIANT + islower((unsigned char)*t); // COMPLIANT + isprint((unsigned char)*t); // COMPLIANT + ispunct((unsigned char)*t); // COMPLIANT + isspace((unsigned char)*t); // COMPLIANT + isupper((unsigned char)*t); // COMPLIANT + isxdigit((unsigned char)*t); // COMPLIANT + // toascii((unsigned int) i); // Not part of the C Standard + toupper((unsigned char)*t); // COMPLIANT + tolower((unsigned char)*t); // COMPLIANT +} + +void f4() { + int t; + + isalnum(t); // NON_COMPLIANT + isalpha(t); // NON_COMPLIANT + // isascii(t); // Not part of the C Standard + isblank(t); // NON_COMPLIANT + iscntrl(t); // NON_COMPLIANT + isdigit(t); // NON_COMPLIANT + isgraph(t); // NON_COMPLIANT + islower(t); // NON_COMPLIANT + isprint(t); // NON_COMPLIANT + ispunct(t); // NON_COMPLIANT + isspace(t); // NON_COMPLIANT + isupper(t); // NON_COMPLIANT + isxdigit(t); // NON_COMPLIANT + // toascii(i); // Not part of the C Standard + toupper(t); // NON_COMPLIANT + tolower(t); // NON_COMPLIANT +} diff --git a/c/common/src/qlpack.yml b/c/common/src/qlpack.yml index ddab9cafc2..586aa97554 100644 --- a/c/common/src/qlpack.yml +++ b/c/common/src/qlpack.yml @@ -1,3 +1,3 @@ name: common-c-coding-standards -version: 2.3.0 +version: 2.4.0 libraryPathDependencies: common-cpp-coding-standards diff --git a/c/common/test/expr/FullExpr.expected b/c/common/test/library/expr/FullExpr.expected similarity index 100% rename from c/common/test/expr/FullExpr.expected rename to c/common/test/library/expr/FullExpr.expected diff --git a/c/common/test/expr/FullExpr.ql b/c/common/test/library/expr/FullExpr.ql similarity index 100% rename from c/common/test/expr/FullExpr.ql rename to c/common/test/library/expr/FullExpr.ql diff --git a/c/common/test/expr/fullexpr.c b/c/common/test/library/expr/fullexpr.c similarity index 100% rename from c/common/test/expr/fullexpr.c rename to c/common/test/library/expr/fullexpr.c diff --git a/c/common/test/library/fgetserrormanagement/FgetsGuard.expected b/c/common/test/library/fgetserrormanagement/FgetsGuard.expected new file mode 100644 index 0000000000..5dd4ca1f61 --- /dev/null +++ b/c/common/test/library/fgetserrormanagement/FgetsGuard.expected @@ -0,0 +1,20 @@ +| test.c:9:10:11:3 | { ... } | test.c:7:38:9:3 | { ... } | +| test.c:16:39:18:3 | { ... } | test.c:18:10:20:3 | { ... } | +| test.c:25:43:27:3 | { ... } | test.c:27:10:29:3 | { ... } | +| test.c:36:10:38:3 | { ... } | test.c:34:43:36:3 | { ... } | +| test.c:45:10:47:3 | { ... } | test.c:43:46:45:3 | { ... } | +| test.c:53:10:55:3 | { ... } | test.c:51:49:53:3 | { ... } | +| test.c:66:3:66:13 | return ... | test.c:60:49:62:3 | { ... } | +| test.c:72:10:74:3 | { ... } | test.c:70:48:72:3 | { ... } | +| test.c:83:3:83:13 | return ... | test.c:79:48:81:3 | { ... } | +| test.c:87:46:89:3 | { ... } | test.c:89:10:91:3 | { ... } | +| test.c:98:13:100:3 | { ... } | test.c:100:10:102:3 | { ... } | +| test.c:111:10:113:3 | { ... } | test.c:109:14:111:3 | { ... } | +| test.c:118:66:121:3 | { ... } | test.c:118:66:121:3 | { ... } | +| test.c:128:63:131:3 | { ... } | test.c:128:63:131:3 | { ... } | +| test.c:140:10:142:3 | { ... } | test.c:138:54:140:3 | { ... } | +| test.c:147:54:149:3 | { ... } | test.c:149:10:151:3 | { ... } | +| test.c:158:10:161:3 | { ... } | test.c:158:10:161:3 | { ... } | +| test.c:168:10:171:3 | { ... } | test.c:168:10:171:3 | { ... } | +| test.c:176:54:179:3 | { ... } | test.c:179:10:182:3 | { ... } | +| test.c:190:10:193:3 | { ... } | test.c:187:54:190:3 | { ... } | diff --git a/c/common/test/library/fgetserrormanagement/FgetsGuard.ql b/c/common/test/library/fgetserrormanagement/FgetsGuard.ql new file mode 100644 index 0000000000..f5dbde2757 --- /dev/null +++ b/c/common/test/library/fgetserrormanagement/FgetsGuard.ql @@ -0,0 +1,5 @@ +import cpp +import codingstandards.cpp.FgetsErrorManagement + +from FgetsGuard e +select e.getNullSuccessor(), e.getNonNullSuccessor() diff --git a/c/common/test/library/fgetserrormanagement/test.c b/c/common/test/library/fgetserrormanagement/test.c new file mode 100644 index 0000000000..13ba911170 --- /dev/null +++ b/c/common/test/library/fgetserrormanagement/test.c @@ -0,0 +1,195 @@ +#include +#include + +char buf[1024]; + +void f0(FILE *file) { + if (fgets(buf, sizeof(buf), file)) { + /*notNull*/ + } else { + /*null*/ + } + return; +} + +void f1(FILE *file) { + if (!fgets(buf, sizeof(buf), file)) { + /*null*/ + } else { + /*notNull*/ + } + return; +} + +void f2(FILE *file) { + if (fgets(buf, sizeof(buf), file) == 0) { + /*null*/ + } else { + /*notNull*/ + } + return; +} + +void f3(FILE *file) { + if (fgets(buf, sizeof(buf), file) != 0) { + /*notNull*/ + } else { + /*null*/ + } + return; +} + +void f4(FILE *file) { + if (!(fgets(buf, sizeof(buf), file) == 0)) { + /*notNull*/ + } else { + /*null*/ + } + return; +} +char *f4a(FILE *file) { + if (!(fgets(buf, sizeof(buf), file) == NULL)) { + /*notNull*/ + } else { + /*null*/ + } + return buf; // NON_COMPLIANT +} + +char *f4b(FILE *file) { + if (!(fgets(buf, sizeof(buf), file) == NULL)) { + /*notNull*/ + } + /*notNull*/ + /*null*/ + + return buf; // NON_COMPLIANT +} + +char *f4c(FILE *file) { + if ((fgets(buf, sizeof(buf), file) != NULL)) { + /*notNull*/ + } else { + /*null*/ + } + return buf; // NON_COMPLIANT +} + +char *f4d(FILE *file) { + if ((fgets(buf, sizeof(buf), file) != NULL)) { + /*notNull*/ + } + /*null*/ + return buf; // NON_COMPLIANT +} + +void f5(FILE *file) { + if (!(fgets(buf, sizeof(buf), file) != 0)) { + /*null*/ + } else { + /*notNull*/ + } + return; +} + +void f6(FILE *file) { + char *ret = fgets(buf, sizeof(buf), file); + bool flag = (ret == NULL); + if (flag) { + /*null*/ + } else { + /*notNull*/ + } + return; +} + +void f7(FILE *file) { + char *ret = fgets(buf, sizeof(buf), file); + bool flag = (ret == NULL); + if (!flag) { + /*notNull*/ + } else { + /*null*/ + } + return; +} + +void f8(FILE *file, bool cond) { + if (fgets(buf, sizeof(buf), file) == NULL || /*notNull*/ cond) { + /*null*/ + /*notNull*/ + } else { + /*notNull*/ + } + return; +} + +void f9a(FILE *file, bool cond) { + if (fgets(buf, sizeof(buf), file) != NULL || /*null*/ cond) { + /*null*/ + /*notNull*/ + } else { + /*null*/ + } + return; +} + +void f9b(FILE *file, bool cond) { + if (cond || fgets(buf, sizeof(buf), file) != NULL) { + /*notNull*/ + } else { + /*null*/ + } + return; +} + +void f9c(FILE *file, bool cond) { + if (cond || fgets(buf, sizeof(buf), file) == NULL) { + /*null*/ + } else { + /*notNnull*/ + } + return; +} + +void f10(FILE *file, bool cond) { + if (fgets(buf, sizeof(buf), file) == NULL && /*null*/ cond) { + /*null*/ + } else { + /*null*/ + /*notNull*/ + } + return; +} + +void f11a(FILE *file, bool cond) { + if (fgets(buf, sizeof(buf), file) != NULL && /*notNull*/ cond) { + /*notNull*/ + } else { + /*null*/ + /*notNull*/ + } + return; +} + +void f11b(FILE *file, bool cond) { + if (cond && fgets(buf, sizeof(buf), file) == NULL) { + /*null*/ + fprintf(stderr, "Read error or end of file.\n"); + } else { + /*notNull*/ + fprintf(stderr, "Read OK.\n"); + } + return; +} + +void f11c(FILE *file, bool cond) { + if (cond && fgets(buf, sizeof(buf), file) != NULL) { + /*notNull*/ + fprintf(stderr, "Read error or end of file.\n"); + } else { + /*null*/ + fprintf(stderr, "Read OK.\n"); + } + return; +} \ No newline at end of file diff --git a/c/common/test/qlpack.yml b/c/common/test/qlpack.yml index 35fc480d26..123450b5ec 100644 --- a/c/common/test/qlpack.yml +++ b/c/common/test/qlpack.yml @@ -1,4 +1,4 @@ name: common-c-coding-standards-tests -version: 2.3.0 +version: 2.4.0 libraryPathDependencies: common-c-coding-standards extractor: cpp diff --git a/c/common/test/rules/hashoperatorsused/HashOperatorsUsed.expected b/c/common/test/rules/hashoperatorsused/HashOperatorsUsed.expected deleted file mode 100644 index e844aafb01..0000000000 --- a/c/common/test/rules/hashoperatorsused/HashOperatorsUsed.expected +++ /dev/null @@ -1,4 +0,0 @@ -| test.c:9:1:9:22 | #define MACROFIVE(X) #X | Macro definition uses the # or ## operator. | -| test.c:11:1:11:26 | #define MACROSIX(X,Y) X ## Y | Macro definition uses the # or ## operator. | -| test.c:13:1:13:29 | #define MACROSEVEN "##'" #"#" | Macro definition uses the # or ## operator. | -| test.c:15:1:15:28 | #define MACROEIGHT '##' #"#" | Macro definition uses the # or ## operator. | diff --git a/c/common/test/rules/hashoperatorsused/HashOperatorsUsed.ql b/c/common/test/rules/hashoperatorsused/HashOperatorsUsed.ql deleted file mode 100644 index d0ead0b289..0000000000 --- a/c/common/test/rules/hashoperatorsused/HashOperatorsUsed.ql +++ /dev/null @@ -1,2 +0,0 @@ -// GENERATED FILE - DO NOT MODIFY -import codingstandards.cpp.rules.hashoperatorsused.HashOperatorsUsed diff --git a/c/common/test/rules/hashoperatorsused/test.c b/c/common/test/rules/hashoperatorsused/test.c deleted file mode 100644 index 422bde164c..0000000000 --- a/c/common/test/rules/hashoperatorsused/test.c +++ /dev/null @@ -1,19 +0,0 @@ -#define MACROONE 1 // COMPLIANT - -#define MACROTWO '#' // COMPLIANT - -#define MACROTHREE "##" // COMPLIANT - -#define MACROFOUR "##" + "#" // COMPLIANT - -#define MACROFIVE(X) #X // NON_COMPLIANT - -#define MACROSIX(X, Y) X##Y // NON_COMPLIANT - -#define MACROSEVEN "##'" #"#" // NON_COMPLIANT - -#define MACROEIGHT '##' #"#" // NON_COMPLIANT - -#define MACRONINE "##\"\"" + "#" // COMPLIANT - -#define MACROTEN "##\"\"'" + "#" // COMPLIANT \ No newline at end of file diff --git a/c/common/test/rules/includeguardsnotused/IncludeGuardsNotUsed.expected b/c/common/test/rules/includeguardsnotused/IncludeGuardsNotUsed.expected new file mode 100644 index 0000000000..8d72392ed5 --- /dev/null +++ b/c/common/test/rules/includeguardsnotused/IncludeGuardsNotUsed.expected @@ -0,0 +1,4 @@ +| headers/test3.h:0:0:0:0 | headers/test3.h | Header file test3.h is missing expected include guard. | headers/test3.h:0:0:0:0 | headers/test3.h | | +| headers/test4.h:0:0:0:0 | headers/test4.h | Header file test4.h is missing expected include guard. | headers/test4.h:0:0:0:0 | headers/test4.h | | +| headers/test5.h:0:0:0:0 | headers/test5.h | Header file test5.h is missing expected include guard. | headers/test5.h:0:0:0:0 | headers/test5.h | | +| headers/test7.h:0:0:0:0 | headers/test7.h | Header file test7.h is never included by reusing the include guard used by $@. | headers/test6.h:0:0:0:0 | headers/test6.h | include guard | diff --git a/c/common/test/rules/includeguardsnotused/IncludeGuardsNotUsed.ql b/c/common/test/rules/includeguardsnotused/IncludeGuardsNotUsed.ql new file mode 100644 index 0000000000..2fcfddeca9 --- /dev/null +++ b/c/common/test/rules/includeguardsnotused/IncludeGuardsNotUsed.ql @@ -0,0 +1,2 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.includeguardsnotused.IncludeGuardsNotUsed diff --git a/cpp/autosar/test/rules/M16-2-3/headers/test1.hpp b/c/common/test/rules/includeguardsnotused/headers/test1.h similarity index 100% rename from cpp/autosar/test/rules/M16-2-3/headers/test1.hpp rename to c/common/test/rules/includeguardsnotused/headers/test1.h diff --git a/cpp/autosar/test/rules/M16-2-3/headers/test2.hpp b/c/common/test/rules/includeguardsnotused/headers/test2.h similarity index 100% rename from cpp/autosar/test/rules/M16-2-3/headers/test2.hpp rename to c/common/test/rules/includeguardsnotused/headers/test2.h diff --git a/cpp/autosar/test/rules/M16-2-3/headers/test3.hpp b/c/common/test/rules/includeguardsnotused/headers/test3.h similarity index 100% rename from cpp/autosar/test/rules/M16-2-3/headers/test3.hpp rename to c/common/test/rules/includeguardsnotused/headers/test3.h diff --git a/cpp/autosar/test/rules/M16-2-3/headers/test4.hpp b/c/common/test/rules/includeguardsnotused/headers/test4.h similarity index 100% rename from cpp/autosar/test/rules/M16-2-3/headers/test4.hpp rename to c/common/test/rules/includeguardsnotused/headers/test4.h diff --git a/cpp/autosar/test/rules/M16-2-3/headers/test5.hpp b/c/common/test/rules/includeguardsnotused/headers/test5.h similarity index 100% rename from cpp/autosar/test/rules/M16-2-3/headers/test5.hpp rename to c/common/test/rules/includeguardsnotused/headers/test5.h diff --git a/c/common/test/rules/includeguardsnotused/headers/test6.h b/c/common/test/rules/includeguardsnotused/headers/test6.h new file mode 100644 index 0000000000..48dc2ab428 --- /dev/null +++ b/c/common/test/rules/includeguardsnotused/headers/test6.h @@ -0,0 +1,5 @@ +// NON_COMPLIANT +#ifndef HEADER_SIX +#define HEADER_SIX +int g5; +#endif \ No newline at end of file diff --git a/c/common/test/rules/includeguardsnotused/headers/test7.h b/c/common/test/rules/includeguardsnotused/headers/test7.h new file mode 100644 index 0000000000..48dc2ab428 --- /dev/null +++ b/c/common/test/rules/includeguardsnotused/headers/test7.h @@ -0,0 +1,5 @@ +// NON_COMPLIANT +#ifndef HEADER_SIX +#define HEADER_SIX +int g5; +#endif \ No newline at end of file diff --git a/c/common/test/rules/includeguardsnotused/test.c b/c/common/test/rules/includeguardsnotused/test.c new file mode 100644 index 0000000000..8c63904fc4 --- /dev/null +++ b/c/common/test/rules/includeguardsnotused/test.c @@ -0,0 +1,14 @@ +#include "headers/test1.h" + +#include "headers/test2.h" + +#include "headers/test3.h" //NON_COMPLIANT + +#include "headers/test4.h" //NON_COMPLIANT +#define HEADER_FOUR + +#include "headers/test5.h" //NON_COMPLIANT + +#include "headers/test6.h" //NON_COMPLIANT - non unique and reported in alert for the next + +#include "headers/test7.h" //NON_COMPLIANT - non unique \ No newline at end of file diff --git a/c/misra/src/qlpack.yml b/c/misra/src/qlpack.yml index 2925a83ae7..01973953c8 100644 --- a/c/misra/src/qlpack.yml +++ b/c/misra/src/qlpack.yml @@ -1,4 +1,4 @@ name: misra-c-coding-standards -version: 2.3.0 +version: 2.4.0 suites: codeql-suites libraryPathDependencies: common-c-coding-standards diff --git a/c/misra/src/rules/RULE-20-11/MoreThanOneHashOperatorInMacroDefinition.ql b/c/misra/src/rules/RULE-20-11/MoreThanOneHashOperatorInMacroDefinition.ql new file mode 100644 index 0000000000..6ea7aa0a13 --- /dev/null +++ b/c/misra/src/rules/RULE-20-11/MoreThanOneHashOperatorInMacroDefinition.ql @@ -0,0 +1,26 @@ +/** + * @id c/misra/more-than-one-hash-operator-in-macro-definition + * @name RULE-20-11: A macro parameter immediately following a # operator shall not immediately be followed by a ## + * @description The order of evaluation for the '#' and '##' operators may differ between compilers, + * which can cause unexpected behaviour if more than one '#' or '##' operator is used. + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/misra/id/rule-20-11 + * correctness + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.Macro + +from Macro m +where + not isExcluded(m, Preprocessor2Package::moreThanOneHashOperatorInMacroDefinitionQuery()) and + exists(StringizingOperator one, TokenPastingOperator two | + one.getMacro() = m and + two.getMacro() = m and + one.getOffset() < two.getOffset() + ) +select m, "Macro definition uses an # operator followed by a ## operator." diff --git a/c/misra/src/rules/RULE-20-11/standard-example.c b/c/misra/src/rules/RULE-20-11/standard-example.c new file mode 100644 index 0000000000..97d0f68bad --- /dev/null +++ b/c/misra/src/rules/RULE-20-11/standard-example.c @@ -0,0 +1,3 @@ +#define A(x) #x /* Compliant */ +#define B(x, y) x##y /* Compliant */ +#define C(x, y) #x##y /* Non-compliant */ \ No newline at end of file diff --git a/c/misra/src/rules/RULE-20-12/MacroParameterUsedAsHashOperand.ql b/c/misra/src/rules/RULE-20-12/MacroParameterUsedAsHashOperand.ql new file mode 100644 index 0000000000..779c14176c --- /dev/null +++ b/c/misra/src/rules/RULE-20-12/MacroParameterUsedAsHashOperand.ql @@ -0,0 +1,39 @@ +/** + * @id c/misra/macro-parameter-used-as-hash-operand + * @name RULE-20-12: A macro parameter used as an operand to the # or ## operators shall only be used as an operand to these operators + * @description A macro parameter used in different contexts such as: 1) an operand to the # or ## + * operators where it is not expanded, versus 2) elsewhere where it is expanded, makes + * code more difficult to understand. + * @kind problem + * @precision high + * @problem.severity warning + * @tags external/misra/id/rule-20-12 + * maintainability + * readability + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.Macro + +from FunctionLikeMacro m, MacroInvocation mi, int i, string expanded, string param +where + not isExcluded(m, Preprocessor2Package::macroParameterUsedAsHashOperandQuery()) and + mi = m.getAnInvocation() and + param = m.getParameter(i) and + ( + exists(TokenPastingOperator op | op.getMacro() = m and op.getOperand() = param) + or + exists(StringizingOperator op | op.getMacro() = m and op.getOperand() = param) + ) and + // An expansion that is equal to "" means the expansion is not used and is optimized away by EDG. This happens when the expanded argument is an operand to `#` or `##`. + // This check ensure there is an expansion that is used. + expanded = mi.getExpandedArgument(i) and + not expanded = "" and + exists(Macro furtherExpandedMacro | + mi.getUnexpandedArgument(i).matches(furtherExpandedMacro.getName() + "%") + ) +select m, + "Macro " + m.getName() + " contains use of parameter " + m.getParameter(i) + + " used in multiple contexts." diff --git a/c/misra/src/rules/RULE-20-12/standard-example.c b/c/misra/src/rules/RULE-20-12/standard-example.c new file mode 100644 index 0000000000..bcfaea6e28 --- /dev/null +++ b/c/misra/src/rules/RULE-20-12/standard-example.c @@ -0,0 +1,7 @@ +#define AA 0xffff +#define BB(x) (x) + wow##x /* Non-compliant */ +void f(void) { + int32_t wowAA = 0; + /* Expands as wowAA = ( 0xffff ) + wowAA; */ + wowAA = BB(AA); +} \ No newline at end of file diff --git a/c/misra/src/rules/RULE-20-5/UndefShouldNotBeUsed.ql b/c/misra/src/rules/RULE-20-5/UndefShouldNotBeUsed.ql new file mode 100644 index 0000000000..c253c795e8 --- /dev/null +++ b/c/misra/src/rules/RULE-20-5/UndefShouldNotBeUsed.ql @@ -0,0 +1,19 @@ +/** + * @id c/misra/undef-should-not-be-used + * @name RULE-20-5: #undef should not be used + * @description Using the #undef preprocessor directive makes code more difficult to understand. + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/misra/id/rule-20-5 + * maintainability + * readability + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.c.misra + +from PreprocessorUndef d +where not isExcluded(d, Preprocessor2Package::undefShouldNotBeUsedQuery()) +select d, "Use of undef found." diff --git a/c/misra/src/rules/RULE-20-5/standard-example.c b/c/misra/src/rules/RULE-20-5/standard-example.c new file mode 100644 index 0000000000..ad77838996 --- /dev/null +++ b/c/misra/src/rules/RULE-20-5/standard-example.c @@ -0,0 +1,7 @@ +#define QUALIFIER volatile +#undef QUALIFIER /* Non-compliant */ +void f(QUALIFIER int32_t p) { + while (p != 0) { + ; /* Wait... */ + } +} \ No newline at end of file diff --git a/c/misra/src/rules/RULE-22-3/FileOpenForReadAndWriteOnDifferentStreams.ql b/c/misra/src/rules/RULE-22-3/FileOpenForReadAndWriteOnDifferentStreams.ql new file mode 100644 index 0000000000..877fbea9aa --- /dev/null +++ b/c/misra/src/rules/RULE-22-3/FileOpenForReadAndWriteOnDifferentStreams.ql @@ -0,0 +1,68 @@ +/** + * @id c/misra/file-open-for-read-and-write-on-different-streams + * @name RULE-22-3: The same file shall not be open for read and write access at the same time on different streams + * @description Accessing the same file for read and write from different streams is undefined + * behavior. + * @kind problem + * @precision high + * @problem.severity error + * @tags external/misra/id/rule-22-3 + * correctness + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.standardlibrary.FileAccess +import semmle.code.cpp.dataflow.DataFlow +import semmle.code.cpp.valuenumbering.GlobalValueNumbering +import semmle.code.cpp.controlflow.SubBasicBlocks + +/** + * Models calls to `fopen` with different read/write modes + */ +class FOpenSBB extends SubBasicBlockCutNode { + FOpenSBB() { + this instanceof FOpenCall or + this instanceof FileCloseFunctionCall + } +} + +SubBasicBlock followsOpen(FOpenCall fopen) { + result = fopen + or + exists(SubBasicBlock mid | + result = mid.getASuccessor() and + mid = followsOpen(fopen) and + // stop recursion when the first stream is closed + not DataFlow::localExprFlow(fopen, result.(FileCloseFunctionCall).getFileExpr()) + ) +} + +class MatchedFOpenCall extends FOpenCall { + FOpenCall pair; + + MatchedFOpenCall() { + not pair = this and + pair.getEnclosingFunction() = this.getEnclosingFunction() and + this = followsOpen(pair) + } + + FOpenCall getMatch() { result = pair } +} + +from MatchedFOpenCall fst, FOpenCall snd +where + not isExcluded(fst, IO3Package::fileOpenForReadAndWriteOnDifferentStreamsQuery()) and + // must be opening the same filename + snd = fst.getMatch() and + globalValueNumber(fst.getFilenameExpr()) = globalValueNumber(snd.getFilenameExpr()) and + ( + // different open mode + fst.isReadMode() and snd.isWriteMode() + or + fst.isWriteMode() and snd.isReadMode() + ) +select fst, + "The same file was already opened $@. Files should not be read and written at the same time using different streams.", + snd, "here" diff --git a/c/misra/src/rules/RULE-22-3/standard-example.c b/c/misra/src/rules/RULE-22-3/standard-example.c new file mode 100644 index 0000000000..757aa27115 --- /dev/null +++ b/c/misra/src/rules/RULE-22-3/standard-example.c @@ -0,0 +1,5 @@ +#include +void fn(void) { + FILE *fw = fopen("tmp", "r+"); /* "r+" opens for read/write */ + FILE *fr = fopen("tmp", "r"); /* Non-compliant */ +} \ No newline at end of file diff --git a/c/misra/src/rules/RULE-22-4/AttemptToWriteToAReadOnlyStream.ql b/c/misra/src/rules/RULE-22-4/AttemptToWriteToAReadOnlyStream.ql new file mode 100644 index 0000000000..c4acbf7aca --- /dev/null +++ b/c/misra/src/rules/RULE-22-4/AttemptToWriteToAReadOnlyStream.ql @@ -0,0 +1,36 @@ +/** + * @id c/misra/attempt-to-write-to-a-read-only-stream + * @name RULE-22-4: There shall be no attempt to write to a stream which has been opened as read-only + * @description Attempting to write on a read-only stream is undefined behavior. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-22-4 + * correctness + * external/misra/obligation/mandatory + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.standardlibrary.FileAccess +import semmle.code.cpp.dataflow.DataFlow + +class FileDFConf extends DataFlow::Configuration { + FileDFConf() { this = "FileDFConf" } + + override 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) { + // sink must be the second parameter of a FsetposCall call + sink.asExpr() = any(FileWriteFunctionCall write).getFileExpr() + } +} + +from FileDFConf dfConf, DataFlow::Node source, FileWriteFunctionCall sink +where + not isExcluded(sink, IO3Package::attemptToWriteToAReadOnlyStreamQuery()) and + dfConf.hasFlow(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-4/standard-example.c b/c/misra/src/rules/RULE-22-4/standard-example.c new file mode 100644 index 0000000000..1b5a2d9423 --- /dev/null +++ b/c/misra/src/rules/RULE-22-4/standard-example.c @@ -0,0 +1,6 @@ +#include +void fn(void) { + FILE *fp = fopen("tmp", "r"); + (void)fprintf(fp, "What happens now?"); /* Non-compliant */ + (void)fclose(fp); +} \ No newline at end of file diff --git a/c/misra/src/rules/RULE-22-5/PointerToAFileObjectDereferenced.ql b/c/misra/src/rules/RULE-22-5/PointerToAFileObjectDereferenced.ql new file mode 100644 index 0000000000..86e0b76e21 --- /dev/null +++ b/c/misra/src/rules/RULE-22-5/PointerToAFileObjectDereferenced.ql @@ -0,0 +1,38 @@ +/** + * @id c/misra/pointer-to-a-file-object-dereferenced + * @name RULE-22-5: A pointer to a FILE object shall not be dereferenced + * @description A FILE object should not be directly manipulated. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-22-5 + * correctness + * external/misra/obligation/mandatory + */ + +import cpp +import codingstandards.c.misra + +class IndirectlyDereferencedExpr extends Expr { + IndirectlyDereferencedExpr() { + exists(Call call, string names | + names = ["memcmp", "memcpy"] and + ( + call.getTarget().hasGlobalOrStdName(names) + or + exists(MacroInvocation mi | mi.getMacroName() = names and call = mi.getExpr()) + ) and + this = [call.getArgument(0), call.getArgument(1)] + ) + } +} + +from Expr e +where + not isExcluded(e, IO3Package::pointerToAFileObjectDereferencedQuery()) and + ( + e.(PointerDereferenceExpr).getType().hasName("FILE") or + e.(PointerFieldAccess).getQualifier().getType().(DerivedType).getBaseType().hasName("FILE") or + e.(IndirectlyDereferencedExpr).getType().(DerivedType).getBaseType().hasName("FILE") + ) +select e, "Dereferencing an object of type `FILE`." diff --git a/c/misra/src/rules/RULE-22-5/standard-example.c b/c/misra/src/rules/RULE-22-5/standard-example.c new file mode 100644 index 0000000000..a9a110ec5a --- /dev/null +++ b/c/misra/src/rules/RULE-22-5/standard-example.c @@ -0,0 +1,8 @@ +#include + +FILE *pf1; +FILE *pf2; +FILE f3; + +pf2 = pf1; /* Compliant */ +f3 = *pf2; /* Non-compliant */ diff --git a/c/misra/src/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.ql b/c/misra/src/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.ql new file mode 100644 index 0000000000..457084f35c --- /dev/null +++ b/c/misra/src/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.ql @@ -0,0 +1,60 @@ +/** + * @id c/misra/eof-shall-be-compared-with-unmodified-return-values + * @name RULE-22-7: The macro EOF shall only be compared with the unmodified return value from any Standard Library + * @description The macro EOF shall only be compared with the unmodified return value from any + * Standard Library function capable of returning EOF + * @kind problem + * @precision high + * @problem.severity error + * @tags external/misra/id/rule-22-7 + * correctness + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +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) { + source.asExpr() instanceof InBandErrorReadFunctionCall + } + + override predicate isSink(DataFlow::Node sink) { + exists(EOFWEOFInvocation mi, EqualityOperation eq | + // one operand is the sink + sink.asExpr() = eq.getAnOperand() and + // one operand is an invocation of the EOF macro + mi.getAGeneratedElement() = eq.getAnOperand() + ) + } + + override predicate isBarrier(DataFlow::Node barrier) { + barrier.asExpr() = any(IntegralConversion c).getExpr() + } +} + +// The equality operation `eq` checks a char fetched from `read` against a macro +predicate isWeakMacroCheck(EqualityOperation eq, InBandErrorReadFunctionCall read) { + exists(Expr c, EOFWEOFInvocation mi | + // one operand is the char c fetched from `read` + c = eq.getAnOperand() and + // an operand is an invocation of the EOF macro + mi.getAGeneratedElement() = eq.getAnOperand() and + DataFlow::localExprFlow(read, c) + ) +} + +from EqualityOperation eq, InBandErrorReadFunctionCall read, DFConf dfConf +where + not isExcluded(eq, IO3Package::eofShallBeComparedWithUnmodifiedReturnValuesQuery()) and + isWeakMacroCheck(eq, read) and + not dfConf.hasFlow(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-22-7/standard-example1.c b/c/misra/src/rules/RULE-22-7/standard-example1.c new file mode 100644 index 0000000000..5bfcfe840d --- /dev/null +++ b/c/misra/src/rules/RULE-22-7/standard-example1.c @@ -0,0 +1,10 @@ +void f1(void) { + char ch; + ch = (char)getchar(); + /* + * The following test is non-compliant. It will not be reliable as the + * return value is cast to a narrower type before checking for EOF. + */ + if (EOF != (int32_t)ch) { + } +} \ No newline at end of file diff --git a/c/misra/src/rules/RULE-22-7/standard-example2.c b/c/misra/src/rules/RULE-22-7/standard-example2.c new file mode 100644 index 0000000000..8a0505b8ca --- /dev/null +++ b/c/misra/src/rules/RULE-22-7/standard-example2.c @@ -0,0 +1,19 @@ +void f2(void) { + char ch; + ch = (char)getchar(); + if (!feof(stdin)) { + } +} + +void f3(void) { + int32_t i_ch; + i_ch = getchar(); + /* + * The following test is compliant. It will be reliable as the + * unconverted return value is used when checking for EOF. + */ + if (EOF != i_ch) { + char ch; + ch = (char)i_ch; + } +} \ No newline at end of file diff --git a/c/misra/src/rules/RULE-4-10/PrecautionIncludeGuardsNotProvided.ql b/c/misra/src/rules/RULE-4-10/PrecautionIncludeGuardsNotProvided.ql new file mode 100644 index 0000000000..deea2afa83 --- /dev/null +++ b/c/misra/src/rules/RULE-4-10/PrecautionIncludeGuardsNotProvided.ql @@ -0,0 +1,24 @@ +/** + * @id c/misra/precaution-include-guards-not-provided + * @name RULE-4-10: Precautions shall be taken in order to prevent the contents of a header file being included more than once + * @description Using anything other than a standard include guard form can make code confusing and + * can lead to multiple or conflicting definitions. + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/misra/id/rule-4-10 + * correctness + * maintainability + * readability + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.rules.includeguardsnotused.IncludeGuardsNotUsed + +class PrecautionIncludeGuardsNotProvidedQuery extends IncludeGuardsNotUsedSharedQuery { + PrecautionIncludeGuardsNotProvidedQuery() { + this = Preprocessor2Package::precautionIncludeGuardsNotProvidedQuery() + } +} diff --git a/c/misra/src/rules/RULE-4-10/standard-example.c b/c/misra/src/rules/RULE-4-10/standard-example.c new file mode 100644 index 0000000000..65b8a2685d --- /dev/null +++ b/c/misra/src/rules/RULE-4-10/standard-example.c @@ -0,0 +1,12 @@ + +#if !defined ( identifier ) +#define identifier +/* Contents of file */ +#endif + + +#ifndef identifier +#define identifier +/* Contents of file */ +#endif + \ No newline at end of file diff --git a/c/misra/test/qlpack.yml b/c/misra/test/qlpack.yml index 87c89cb5ce..2e9d46e7b1 100644 --- a/c/misra/test/qlpack.yml +++ b/c/misra/test/qlpack.yml @@ -1,4 +1,4 @@ name: misra-c-coding-standards-tests -version: 2.3.0 +version: 2.4.0 libraryPathDependencies: misra-c-coding-standards extractor: cpp \ No newline at end of file diff --git a/c/misra/test/rules/RULE-20-11/MoreThanOneHashOperatorInMacroDefinition.expected b/c/misra/test/rules/RULE-20-11/MoreThanOneHashOperatorInMacroDefinition.expected new file mode 100644 index 0000000000..406010428c --- /dev/null +++ b/c/misra/test/rules/RULE-20-11/MoreThanOneHashOperatorInMacroDefinition.expected @@ -0,0 +1 @@ +| test.c:25:1:25:29 | #define MACROTHIRTEEN(X) #X ## X | Macro definition uses an # operator followed by a ## operator. | diff --git a/c/misra/test/rules/RULE-20-11/MoreThanOneHashOperatorInMacroDefinition.qlref b/c/misra/test/rules/RULE-20-11/MoreThanOneHashOperatorInMacroDefinition.qlref new file mode 100644 index 0000000000..35ef457cac --- /dev/null +++ b/c/misra/test/rules/RULE-20-11/MoreThanOneHashOperatorInMacroDefinition.qlref @@ -0,0 +1 @@ +rules/RULE-20-11/MoreThanOneHashOperatorInMacroDefinition.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-20-11/test.c b/c/misra/test/rules/RULE-20-11/test.c new file mode 100644 index 0000000000..ad2c205970 --- /dev/null +++ b/c/misra/test/rules/RULE-20-11/test.c @@ -0,0 +1,27 @@ +#define MACROONE 1 // COMPLIANT + +#define MACROTWO '#\'-#' + '#' // COMPLIANT + +#define MACROTHREE "##" // COMPLIANT + +#define MACROFOUR "##" + "#" // COMPLIANT + +#define MACROFIVE(X) #X // COMPLIANT + +#define MACROSIX(X, Y) X##Y // COMPLIANT + +#define MACROSEVEN "##'" #"#" // COMPLIANT + +#define MACROEIGHT '##' #"#" // COMPLIANT + +#define MACRONINE "##\"\"" + "#" // COMPLIANT + +#define MACROTEN "##\"\"'" + "#" // COMPLIANT + +#define MACROELEVEN(X) X #X #X // COMPLIANT + +#define MACROTWELVE(X) X##X##X // COMPLIANT + +#define MACROTHIRTEEN(X) #X##X // NON_COMPLIANT + +#define MACROFOURTEEN '#\'-#' + 1 #1 #1 + '#' // COMPLIANT \ No newline at end of file diff --git a/c/misra/test/rules/RULE-20-12/MacroParameterUsedAsHashOperand.expected b/c/misra/test/rules/RULE-20-12/MacroParameterUsedAsHashOperand.expected new file mode 100644 index 0000000000..be347218b3 --- /dev/null +++ b/c/misra/test/rules/RULE-20-12/MacroParameterUsedAsHashOperand.expected @@ -0,0 +1,2 @@ +| test.c:4:1:4:41 | #define BAD_MACRO_WITH_ARG(x) (x) + wow ## x | Macro BAD_MACRO_WITH_ARG contains use of parameter x used in multiple contexts. | +| test.c:5:1:5:48 | #define BAD_MACRO_WITH_ARG_TWO(x,y) (x) + wow ## x | Macro BAD_MACRO_WITH_ARG_TWO contains use of parameter x used in multiple contexts. | diff --git a/c/misra/test/rules/RULE-20-12/MacroParameterUsedAsHashOperand.qlref b/c/misra/test/rules/RULE-20-12/MacroParameterUsedAsHashOperand.qlref new file mode 100644 index 0000000000..a2edc3acc4 --- /dev/null +++ b/c/misra/test/rules/RULE-20-12/MacroParameterUsedAsHashOperand.qlref @@ -0,0 +1 @@ +rules/RULE-20-12/MacroParameterUsedAsHashOperand.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-20-12/test.c b/c/misra/test/rules/RULE-20-12/test.c new file mode 100644 index 0000000000..768238f36d --- /dev/null +++ b/c/misra/test/rules/RULE-20-12/test.c @@ -0,0 +1,25 @@ + +#define GOOD_MACRO_WITH_ARG(X) ((X)*X##_scale) // COMPLIANT +#define MACRO 1 +#define BAD_MACRO_WITH_ARG(x) (x) + wow##x // NON_COMPLIANT +#define BAD_MACRO_WITH_ARG_TWO(x, y) (x) + wow##x // NON_COMPLIANT +#define MACROONE(x) #x // COMPLIANT +#define MACROTWO(x) x *x // COMPLIANT +#define MACROTHREE(x) "##\"\"'" + (x) // COMPLIANT +#define FOO(x) #x MACROONE(x) // COMPLIANT - no further arg expansion + +void f() { + + int x; + int x_scale; + int y; + int wowMACRO = 0; + + y = GOOD_MACRO_WITH_ARG(x); + wowMACRO = BAD_MACRO_WITH_ARG(MACRO); + wowMACRO = BAD_MACRO_WITH_ARG_TWO(MACRO, 1); + char s[] = MACROONE(MACRO); + y = MACROTWO(MACRO); + MACROTHREE(MACRO); + FOO(x); +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-20-5/UndefShouldNotBeUsed.expected b/c/misra/test/rules/RULE-20-5/UndefShouldNotBeUsed.expected new file mode 100644 index 0000000000..0cda5466c5 --- /dev/null +++ b/c/misra/test/rules/RULE-20-5/UndefShouldNotBeUsed.expected @@ -0,0 +1 @@ +| test.c:2:1:2:11 | #undef TEST | Use of undef found. | diff --git a/c/misra/test/rules/RULE-20-5/UndefShouldNotBeUsed.qlref b/c/misra/test/rules/RULE-20-5/UndefShouldNotBeUsed.qlref new file mode 100644 index 0000000000..632afdd4d2 --- /dev/null +++ b/c/misra/test/rules/RULE-20-5/UndefShouldNotBeUsed.qlref @@ -0,0 +1 @@ +rules/RULE-20-5/UndefShouldNotBeUsed.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-20-5/test.c b/c/misra/test/rules/RULE-20-5/test.c new file mode 100644 index 0000000000..d9b96e5861 --- /dev/null +++ b/c/misra/test/rules/RULE-20-5/test.c @@ -0,0 +1,2 @@ +#define TEST 1 // COMPLIANT +#undef TEST // NON_COMPLIANT \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-3/FileOpenForReadAndWriteOnDifferentStreams.expected b/c/misra/test/rules/RULE-22-3/FileOpenForReadAndWriteOnDifferentStreams.expected new file mode 100644 index 0000000000..6111072ba8 --- /dev/null +++ b/c/misra/test/rules/RULE-22-3/FileOpenForReadAndWriteOnDifferentStreams.expected @@ -0,0 +1,5 @@ +| test.c:6:14:6:18 | call to fopen | The same file was already opened $@. Files should not be read and written at the same time using different streams. | test.c:5:14:5:18 | call to fopen | here | +| test.c:17:14:17:18 | call to fopen | The same file was already opened $@. Files should not be read and written at the same time using different streams. | test.c:16:14:16:18 | call to fopen | here | +| test.c:33:14:33:18 | call to fopen | The same file was already opened $@. Files should not be read and written at the same time using different streams. | test.c:32:14:32:18 | call to fopen | here | +| test.c:43:14:43:18 | call to fopen | The same file was already opened $@. Files should not be read and written at the same time using different streams. | test.c:42:14:42:18 | call to fopen | here | +| test.c:59:14:59:18 | call to fopen | The same file was already opened $@. Files should not be read and written at the same time using different streams. | test.c:58:14:58:18 | call to fopen | here | diff --git a/c/misra/test/rules/RULE-22-3/FileOpenForReadAndWriteOnDifferentStreams.qlref b/c/misra/test/rules/RULE-22-3/FileOpenForReadAndWriteOnDifferentStreams.qlref new file mode 100644 index 0000000000..6a67ba5967 --- /dev/null +++ b/c/misra/test/rules/RULE-22-3/FileOpenForReadAndWriteOnDifferentStreams.qlref @@ -0,0 +1 @@ +rules/RULE-22-3/FileOpenForReadAndWriteOnDifferentStreams.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-3/test.c b/c/misra/test/rules/RULE-22-3/test.c new file mode 100644 index 0000000000..7e51ee9963 --- /dev/null +++ b/c/misra/test/rules/RULE-22-3/test.c @@ -0,0 +1,60 @@ +#include +#include + +void f1(void) { + FILE *fw = fopen("tmp1", "r+"); + FILE *fr = fopen("tmp1", "r"); // NON_COMPLIANT +} + +void f2(void) { + FILE *fw = fopen("tmp2", "r+"); + fclose(fw); + FILE *fr = fopen("tmp2", "r"); // COMPLIANT +} + +void f3(void) { + FILE *fr = fopen("tmp3", "r"); + FILE *fw = fopen("tmp3", "r+"); // NON_COMPLIANT + fclose(fw); +} + +void f4(void) { + FILE *fw = fopen("tmp4", "r"); + FILE *fr = fopen("tmp4", "r"); // COMPLIANT +} + +void f5(void) { + FILE *fr = fopen("tmp5a", "r"); + FILE *fw = fopen("tmp5b", "r+"); // COMPLIANT +} + +void f6(void) { + FILE *fw = fopen("tmp6", "w"); + FILE *fr = fopen("tmp6", "r"); // NON_COMPLIANT +} + +void f7(void) { + FILE *fw = fopen("tmp1", "r"); // COMPLIANT +} + +void f8(void) { + char file[] = "tmp8"; + FILE *fw = fopen(file, "r+"); + FILE *fr = fopen(file, "r"); // NON_COMPLIANT +} + +void f9(void) { + char name[50] = "tmp9"; + char ext[] = "txt"; + char file[] = strcat(name, ext); + FILE *fw = fopen(file, "r+"); + FILE *fr = fopen(strcat(name, ext), "r"); // NON_COMPLIANT[FALSE_NEGATIVE] +} + +void f10(void) { + char name[50] = "tmp10"; + char ext[] = "txt"; + strcat(name, ext); + FILE *fw = fopen(name, "r+"); + FILE *fr = fopen(name, "r"); // NON_COMPLIANT +} diff --git a/c/misra/test/rules/RULE-22-4/AttemptToWriteToAReadOnlyStream.expected b/c/misra/test/rules/RULE-22-4/AttemptToWriteToAReadOnlyStream.expected new file mode 100644 index 0000000000..0bfce133c5 --- /dev/null +++ b/c/misra/test/rules/RULE-22-4/AttemptToWriteToAReadOnlyStream.expected @@ -0,0 +1,2 @@ +| test.c:10:3:10:9 | call to fprintf | Attempt to write to a $@ opened as read-only. | test.c:9:14:9:18 | call to fopen | stream | +| test.c:15:3:15:9 | call to fprintf | Attempt to write to a $@ opened as read-only. | test.c:18:14:18:18 | call to fopen | stream | diff --git a/c/misra/test/rules/RULE-22-4/AttemptToWriteToAReadOnlyStream.qlref b/c/misra/test/rules/RULE-22-4/AttemptToWriteToAReadOnlyStream.qlref new file mode 100644 index 0000000000..c636f2d9a7 --- /dev/null +++ b/c/misra/test/rules/RULE-22-4/AttemptToWriteToAReadOnlyStream.qlref @@ -0,0 +1 @@ +rules/RULE-22-4/AttemptToWriteToAReadOnlyStream.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-4/test.c b/c/misra/test/rules/RULE-22-4/test.c new file mode 100644 index 0000000000..c69e2fd4ff --- /dev/null +++ b/c/misra/test/rules/RULE-22-4/test.c @@ -0,0 +1,21 @@ +#include +void f0() { + FILE *fp = fopen("file", "r+"); + fprintf(fp, "text"); // COMPLIANT + fclose(fp); +} + +void f1() { + FILE *fp = fopen("file", "r"); + fprintf(fp, "text"); // NON_COMPLIANT + fclose(fp); +} + +void f2help(FILE *fp) { + fprintf(fp, "text"); // NON_COMPLIANT +} +void f2() { + FILE *fp = fopen("file", "r"); + f2help(fp); + fclose(fp); +} diff --git a/c/misra/test/rules/RULE-22-5/PointerToAFileObjectDereferenced.expected b/c/misra/test/rules/RULE-22-5/PointerToAFileObjectDereferenced.expected new file mode 100644 index 0000000000..81c499eafa --- /dev/null +++ b/c/misra/test/rules/RULE-22-5/PointerToAFileObjectDereferenced.expected @@ -0,0 +1,7 @@ +| test.c:13:8:13:11 | * ... | Dereferencing an object of type `FILE`. | +| test.c:14:8:14:10 | pos | Dereferencing an object of type `FILE`. | +| test.c:16:10:16:12 | pf1 | Dereferencing an object of type `FILE`. | +| test.c:16:15:16:17 | pf2 | Dereferencing an object of type `FILE`. | +| test.c:17:10:17:12 | pf1 | Dereferencing an object of type `FILE`. | +| test.c:17:15:17:17 | pf2 | Dereferencing an object of type `FILE`. | +| test.c:22:8:22:10 | pos | Dereferencing an object of type `FILE`. | diff --git a/c/misra/test/rules/RULE-22-5/PointerToAFileObjectDereferenced.qlref b/c/misra/test/rules/RULE-22-5/PointerToAFileObjectDereferenced.qlref new file mode 100644 index 0000000000..a35c11f4d2 --- /dev/null +++ b/c/misra/test/rules/RULE-22-5/PointerToAFileObjectDereferenced.qlref @@ -0,0 +1 @@ +rules/RULE-22-5/PointerToAFileObjectDereferenced.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-5/test.c b/c/misra/test/rules/RULE-22-5/test.c new file mode 100644 index 0000000000..bd1463b80f --- /dev/null +++ b/c/misra/test/rules/RULE-22-5/test.c @@ -0,0 +1,28 @@ +//#include +#include + +typedef struct { + int pos; +} FILE; + +void f() { + FILE *pf1; + FILE *pf2; + FILE f3; + pf2 = pf1; // COMPLIANT + f3 = *pf2; // NON_COMPLIANT + pf1->pos = 0; // NON_COMPLIANT + + memcpy(pf1, pf2, 1); // NON_COMPLIANT + memcmp(pf1, pf2, 1); // NON_COMPLIANT +} + +void f1help(FILE *pf1, FILE *pf2) { + pf2 = pf1; // COMPLIANT + pf1->pos = 0; // NON_COMPLIANT +} +void f1() { + FILE *pf1; + FILE *pf2; + f1help(pf1, pf2); +} diff --git a/c/misra/test/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.expected b/c/misra/test/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.expected new file mode 100644 index 0000000000..709d8b002c --- /dev/null +++ b/c/misra/test/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.expected @@ -0,0 +1,2 @@ +| test.c:6:7:6:20 | ... != ... | The check is not reliable as the type of the return value of $@ is converted. | test.c:5:14:5:20 | call to getchar | call to getchar | +| test.c:13:7:13:15 | ... != ... | The check is not reliable as the type of the return value of $@ is converted. | test.c:12:14:12:20 | call to getchar | call to getchar | diff --git a/c/misra/test/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.qlref b/c/misra/test/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.qlref new file mode 100644 index 0000000000..78887cb47c --- /dev/null +++ b/c/misra/test/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.qlref @@ -0,0 +1 @@ +rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-7/test.c b/c/misra/test/rules/RULE-22-7/test.c new file mode 100644 index 0000000000..8100969517 --- /dev/null +++ b/c/misra/test/rules/RULE-22-7/test.c @@ -0,0 +1,31 @@ +#include + +void f1a(void) { + char ch; + ch = (char)getchar(); + if (EOF != (int)ch) { // NON_COMPLIANT + } +} + +void f1b(void) { + int ch; + ch = (char)getchar(); + if (EOF != ch) { // NON_COMPLIANT + } +} + +void f2(void) { + char ch; + ch = (char)getchar(); + if (!feof(stdin)) { // COMPLIANT + } +} + +void f3(void) { + int i_ch; + i_ch = getchar(); + if (EOF != i_ch) { // COMPLIANT + char ch; + ch = (char)i_ch; + } +} diff --git a/c/misra/test/rules/RULE-4-10/NonUniqueIncludeGuards.testref b/c/misra/test/rules/RULE-4-10/NonUniqueIncludeGuards.testref new file mode 100644 index 0000000000..e38907a2fc --- /dev/null +++ b/c/misra/test/rules/RULE-4-10/NonUniqueIncludeGuards.testref @@ -0,0 +1 @@ +c/common/test/rules/nonuniqueincludeguardsused/NonUniqueIncludeGuardsUsed.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-4-10/PrecautionIncludeGuardsNotProvided.testref b/c/misra/test/rules/RULE-4-10/PrecautionIncludeGuardsNotProvided.testref new file mode 100644 index 0000000000..065354082f --- /dev/null +++ b/c/misra/test/rules/RULE-4-10/PrecautionIncludeGuardsNotProvided.testref @@ -0,0 +1 @@ +c/common/test/rules/includeguardsnotused/IncludeGuardsNotUsed.ql \ No newline at end of file diff --git a/change_notes/2022-05-20-M16-3-1-exclude-non-function-macros.md b/change_notes/2022-05-20-M16-3-1-exclude-non-function-macros.md new file mode 100644 index 0000000000..e3ff564ca9 --- /dev/null +++ b/change_notes/2022-05-20-M16-3-1-exclude-non-function-macros.md @@ -0,0 +1,2 @@ +- `M16-3-1` - `MoreThanOneOccurrenceHashOperatorInMacroDefinition.ql`: + - Removes detection of more than one occurrence in non function like Macros. \ No newline at end of file diff --git a/cpp/autosar/src/qlpack.yml b/cpp/autosar/src/qlpack.yml index 31eb8beee7..2d991b16e4 100644 --- a/cpp/autosar/src/qlpack.yml +++ b/cpp/autosar/src/qlpack.yml @@ -1,4 +1,4 @@ name: autosar-cpp-coding-standards -version: 2.3.0 +version: 2.4.0 suites: codeql-suites libraryPathDependencies: common-cpp-coding-standards diff --git a/cpp/autosar/src/rules/M16-2-3/IncludeGuardsNotProvided.ql b/cpp/autosar/src/rules/M16-2-3/IncludeGuardsNotProvided.ql index 9dd06713d6..5cc518f8fc 100644 --- a/cpp/autosar/src/rules/M16-2-3/IncludeGuardsNotProvided.ql +++ b/cpp/autosar/src/rules/M16-2-3/IncludeGuardsNotProvided.ql @@ -17,54 +17,10 @@ import cpp import codingstandards.cpp.autosar +import codingstandards.cpp.rules.includeguardsnotused.IncludeGuardsNotUsed -pragma[noinline] -predicate isPreprocFileAndLine(Element pd, string filepath, int startLine) { - pd.getLocation().hasLocationInfo(filepath, startLine, _, _, _) -} - -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) - ) -} - -class GuardMacro extends Macro { - GuardMacro() { - //wrapper #ifndef present for use as include guard - //and they only suffice if there are no non comment elements above them - exists(PreprocessorIfndef wrapper | - getAGuard(this) = wrapper and - not exists(Element above, string filepath, int aboveStartLine, int ifdefStartLine | - aboveStartLine < ifdefStartLine and - isPreprocFileAndLine(wrapper, filepath, ifdefStartLine) and - isPreprocFileAndLine(above, filepath, aboveStartLine) and - not (above instanceof Comment or above instanceof File) - ) - ) +class PrecautionIncludeGuardsNotProvidedQuery extends IncludeGuardsNotUsedSharedQuery { + PrecautionIncludeGuardsNotProvidedQuery() { + this = IncludesPackage::includeGuardsNotProvidedQuery() } } - -/** - * An optimised version of `PreprocessorBranchDirective.getAGuard()`. - */ -private PreprocessorBranch getAGuard(Element guardedElement) { - exists(string filepath, int ifStartLine, int guardedElementStartLine, int endifStartLine | - isPreprocConditionalRange(result, filepath, ifStartLine, endifStartLine) and - isPreprocFileAndLine(guardedElement, filepath, guardedElementStartLine) and - ifStartLine < guardedElementStartLine and - guardedElementStartLine < endifStartLine - ) -} - -from File file -where - not exists(GuardMacro guard | guard.getFile() = file) and - //headers are anything included - exists(Include i | i.getIncludedFile() = file) and - not isExcluded(file, IncludesPackage::includeGuardsNotProvidedQuery()) -select file, "Header file $@ is missing expected include guard.", file, file.getBaseName() diff --git a/cpp/autosar/src/rules/M16-3-1/MoreThanOneOccurrenceHashOperatorInMacroDefinition.ql b/cpp/autosar/src/rules/M16-3-1/MoreThanOneOccurrenceHashOperatorInMacroDefinition.ql index 5c6243a7de..96fd46907d 100644 --- a/cpp/autosar/src/rules/M16-3-1/MoreThanOneOccurrenceHashOperatorInMacroDefinition.ql +++ b/cpp/autosar/src/rules/M16-3-1/MoreThanOneOccurrenceHashOperatorInMacroDefinition.ql @@ -15,16 +15,17 @@ import cpp import codingstandards.cpp.autosar +import codingstandards.cpp.Macro -from Macro m, string body +from Macro m where - body = - m.getBody() - .regexpReplaceAll("#+", "#") - .regexpReplaceAll("\\\\\"", "") - .regexpReplaceAll("\\\\'", "") - .regexpReplaceAll("\"[^\"]+\"", "") - .regexpReplaceAll("'[^']+'", "") and - exists(int c | c = count(int x | x = body.indexOf("#")) and c > 1) and + count(StringizingOperator op | op.getMacro() = m | op) > 1 + or + count(any(TokenPastingOperator op | op.getMacro() = m | op.getOffset())) > 1 + or + exists(StringizingOperator one, TokenPastingOperator two | + one.getMacro() = m and + two.getMacro() = m + ) and not isExcluded(m, MacrosPackage::moreThanOneOccurrenceHashOperatorInMacroDefinitionQuery()) select m, "Macro definition uses the # or ## operator more than once." diff --git a/cpp/autosar/test/qlpack.yml b/cpp/autosar/test/qlpack.yml index 195698fe83..1c37efaa14 100644 --- a/cpp/autosar/test/qlpack.yml +++ b/cpp/autosar/test/qlpack.yml @@ -1,4 +1,4 @@ name: autosar-cpp-coding-standards-tests -version: 2.3.0 +version: 2.4.0 libraryPathDependencies: autosar-cpp-coding-standards extractor: cpp diff --git a/cpp/autosar/test/rules/M16-2-3/IncludeGuardsNotProvided.expected b/cpp/autosar/test/rules/M16-2-3/IncludeGuardsNotProvided.expected deleted file mode 100644 index 9d17b9fc43..0000000000 --- a/cpp/autosar/test/rules/M16-2-3/IncludeGuardsNotProvided.expected +++ /dev/null @@ -1,3 +0,0 @@ -| headers/test3.hpp:0:0:0:0 | headers/test3.hpp | Header file $@ is missing expected include guard. | headers/test3.hpp:0:0:0:0 | headers/test3.hpp | test3.hpp | -| headers/test4.hpp:0:0:0:0 | headers/test4.hpp | Header file $@ is missing expected include guard. | headers/test4.hpp:0:0:0:0 | headers/test4.hpp | test4.hpp | -| headers/test5.hpp:0:0:0:0 | headers/test5.hpp | Header file $@ is missing expected include guard. | headers/test5.hpp:0:0:0:0 | headers/test5.hpp | test5.hpp | diff --git a/cpp/autosar/test/rules/M16-2-3/IncludeGuardsNotProvided.qlref b/cpp/autosar/test/rules/M16-2-3/IncludeGuardsNotProvided.qlref deleted file mode 100644 index bc180f825a..0000000000 --- a/cpp/autosar/test/rules/M16-2-3/IncludeGuardsNotProvided.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/M16-2-3/IncludeGuardsNotProvided.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M16-2-3/IncludeGuardsNotProvided.testref b/cpp/autosar/test/rules/M16-2-3/IncludeGuardsNotProvided.testref new file mode 100644 index 0000000000..2fac3f74cf --- /dev/null +++ b/cpp/autosar/test/rules/M16-2-3/IncludeGuardsNotProvided.testref @@ -0,0 +1 @@ +cpp/common/test/rules/includeguardsnotused/IncludeGuardsNotUsed.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M16-2-3/NonUniqueIncludeGuardsCpp.testref b/cpp/autosar/test/rules/M16-2-3/NonUniqueIncludeGuardsCpp.testref new file mode 100644 index 0000000000..e8adc6dc8d --- /dev/null +++ b/cpp/autosar/test/rules/M16-2-3/NonUniqueIncludeGuardsCpp.testref @@ -0,0 +1 @@ +cpp/common/test/rules/nonuniqueincludeguardsused/NonUniqueIncludeGuardsUsed.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M16-3-1/MoreThanOneOccurrenceHashOperatorInMacroDefinition.expected b/cpp/autosar/test/rules/M16-3-1/MoreThanOneOccurrenceHashOperatorInMacroDefinition.expected index e957365b30..96c5d3449b 100644 --- a/cpp/autosar/test/rules/M16-3-1/MoreThanOneOccurrenceHashOperatorInMacroDefinition.expected +++ b/cpp/autosar/test/rules/M16-3-1/MoreThanOneOccurrenceHashOperatorInMacroDefinition.expected @@ -1,4 +1,3 @@ | test.cpp:21:1:21:29 | #define MACROELEVEN(X) X #X #X | Macro definition uses the # or ## operator more than once. | | test.cpp:23:1:23:29 | #define MACROTWELVE(X) X ## X ## X | Macro definition uses the # or ## operator more than once. | | test.cpp:25:1:25:29 | #define MACROTHIRTEEN(X) #X ## X | Macro definition uses the # or ## operator more than once. | -| test.cpp:27:1:27:45 | #define MACROFOURTEEN '#\\'-#' + 1 #1 #1 + '#' | Macro definition uses the # or ## operator more than once. | diff --git a/cpp/autosar/test/rules/M16-3-1/test.cpp b/cpp/autosar/test/rules/M16-3-1/test.cpp index df1cf8b8ab..e8b7f752fc 100644 --- a/cpp/autosar/test/rules/M16-3-1/test.cpp +++ b/cpp/autosar/test/rules/M16-3-1/test.cpp @@ -24,4 +24,5 @@ #define MACROTHIRTEEN(X) #X##X // NON_COMPLIANT -#define MACROFOURTEEN '#\'-#' + 1 #1 #1 + '#' // NON_COMPLIANT \ No newline at end of file +#define MACROFOURTEEN \ + '#\'-#' + 1 #1 #1 + '#' // COMPLIANT, not a function-like macro. \ No newline at end of file diff --git a/cpp/cert/src/qlpack.yml b/cpp/cert/src/qlpack.yml index 003fb7b7cf..b7f113b391 100644 --- a/cpp/cert/src/qlpack.yml +++ b/cpp/cert/src/qlpack.yml @@ -1,4 +1,4 @@ name: cert-cpp-coding-standards -version: 2.3.0 +version: 2.4.0 suites: codeql-suites libraryPathDependencies: common-cpp-coding-standards diff --git a/cpp/cert/test/qlpack.yml b/cpp/cert/test/qlpack.yml index 11d4756c24..f212d1000d 100644 --- a/cpp/cert/test/qlpack.yml +++ b/cpp/cert/test/qlpack.yml @@ -1,4 +1,4 @@ name: cert-cpp-coding-standards-tests -version: 2.3.0 +version: 2.4.0 libraryPathDependencies: cert-cpp-coding-standards extractor: cpp diff --git a/cpp/common/src/codingstandards/cpp/CharFunctions.qll b/cpp/common/src/codingstandards/cpp/CharFunctions.qll new file mode 100644 index 0000000000..352f61858c --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/CharFunctions.qll @@ -0,0 +1,31 @@ +import cpp + +/** + * Models a class of functions that are either testers of characters + * or standard library conversion functions. + */ +class CToOrIsCharFunction extends Function { + CToOrIsCharFunction() { + this instanceof CIsCharFunction or + this instanceof CToCharFunction + } +} + +/** + * Models a class of functions that test characters. + */ +class CIsCharFunction extends Function { + CIsCharFunction() { + getName() in [ + "isalnum", "isalpha", "isascii", "isblank", "iscntrl", "isdigit", "isgraph", "islower", + "isprint", "ispunct", "isspace", "isupper", "isxdigit", "__isspace" + ] + } +} + +/** + * Models a class of functions convert characters. + */ +class CToCharFunction extends Function { + CToCharFunction() { getName() in ["toascii", "toupper", "tolower"] } +} diff --git a/cpp/common/src/codingstandards/cpp/Dereferenced.qll b/cpp/common/src/codingstandards/cpp/Dereferenced.qll index f2fde03f3a..ffcd74728b 100644 --- a/cpp/common/src/codingstandards/cpp/Dereferenced.qll +++ b/cpp/common/src/codingstandards/cpp/Dereferenced.qll @@ -24,6 +24,9 @@ class DereferencedExpr extends Expr { c.getTarget() instanceof StarOperator ) or + // And access to arrays `array[0]` + this = any(ArrayExpr ae).getArrayBase() + or this instanceof StandardLibraryDereferencedExpr ) } diff --git a/cpp/common/src/codingstandards/cpp/FgetsErrorManagement.qll b/cpp/common/src/codingstandards/cpp/FgetsErrorManagement.qll index 9ca59bc4ce..4f99b02e2e 100644 --- a/cpp/common/src/codingstandards/cpp/FgetsErrorManagement.qll +++ b/cpp/common/src/codingstandards/cpp/FgetsErrorManagement.qll @@ -49,6 +49,7 @@ class FgetsLikeCall extends FunctionCall { class BooleanFgetsExpr extends Expr { boolean isNull; + boolean isNotNull; FgetsLikeCall fgetCall; Expr operand; @@ -56,6 +57,7 @@ class BooleanFgetsExpr extends Expr { // if(fgets) fgetCall = this and isNull = false and + isNotNull = true and operand = this or exists(BooleanFgetsExpr e | @@ -63,50 +65,47 @@ class BooleanFgetsExpr extends Expr { operand = e and fgetCall = e.getFgetCall() and ( - // if(x==0) - e = this.(EQExpr).getAnOperand() and - this.(EQExpr).getAnOperand() instanceof NullValue and - isNull = e.isNull().booleanNot() - or - // if(x!=0) - e = this.(NEExpr).getAnOperand() and - this.(NEExpr).getAnOperand() instanceof NullValue and - isNull = e.isNull() - or - // if(x) - DataFlow::localExprFlow(e, this) and - isNull = e.isNull() - or - // if(!x) - e = this.(NotExpr).getOperand() and - isNull = e.isNull().booleanNot() - or - // if(x && cond) - e = this.(LogicalAndExpr).getAnOperand() and + isNotNull = isNull.booleanNot() and ( - e.isNull() = false and - isNull = false + // if(e==0) + e = this.(EQExpr).getAnOperand() and + this.(EQExpr).getAnOperand() instanceof NullValue and + isNull = e.isNull().booleanNot() + or + // if(e!=0) + e = this.(NEExpr).getAnOperand() and + this.(NEExpr).getAnOperand() instanceof NullValue and + isNull = e.isNull() or - e.isNull() = true and - ( - isNull = true - or - isNull = false - ) + // if(e) + DataFlow::localExprFlow(e, this) and + isNull = e.isNull() + or + // if(!e) + e = this.(NotExpr).getOperand() and + isNull = e.isNull().booleanNot() + or + // if(cond && e) + e = this.(LogicalAndExpr).getRightOperand() and + isNull = e.isNull() + or + // if(cond || e) + e = this.(LogicalOrExpr).getRightOperand() and + isNull = e.isNull() ) or - // if(x || cond) - e = this.(LogicalOrExpr).getAnOperand() and + // if(e && cond) + e = this.(LogicalAndExpr).getLeftOperand() and ( - e.isNull() = true and - isNull = true - or - e.isNull() = false and - ( - isNull = true - or - isNull = false - ) + isNull = false and + isNotNull = false + ) + or + // if(e || cond) + e = this.(LogicalOrExpr).getLeftOperand() and + ( + isNull = true and + isNotNull = true ) ) ) @@ -114,14 +113,22 @@ class BooleanFgetsExpr extends Expr { boolean isNull() { result = isNull } + boolean isNotNull() { result = isNotNull } + Expr getFgetCall() { result = fgetCall } Expr getOperand() { result = operand } } +/* + * A guard controlled by a `BooleanFgetsExpr` + */ + class FgetsGuard extends BooleanFgetsExpr { FgetsGuard() { - exists(IfStmt i | i.getCondition() = this) or exists(Loop i | i.getCondition() = this) + exists(IfStmt i | i.getCondition() = this) + or + exists(Loop i | i.getCondition() = this) } Stmt getThenSuccessor() { @@ -153,8 +160,10 @@ class FgetsGuard extends BooleanFgetsExpr { } ControlFlowNode getNonNullSuccessor() { - this.isNull() = true and result = this.getElseSuccessor() + this.isNotNull() = true and + result = this.getThenSuccessor() or - this.isNull() = false and result = getThenSuccessor() + this.isNotNull() = false and + result = getElseSuccessor() } } diff --git a/cpp/common/src/codingstandards/cpp/Macro.qll b/cpp/common/src/codingstandards/cpp/Macro.qll new file mode 100644 index 0000000000..24b0bc4379 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/Macro.qll @@ -0,0 +1,65 @@ +import cpp + +/** + * Macros with a parameter + */ +class FunctionLikeMacro extends Macro { + FunctionLikeMacro() { this.getHead().regexpMatch("[_a-zA-Z0-9]+\\s*\\([^\\)]*?\\)") } + + string getParameter(int i) { + result = + this.getHead().regexpCapture("[_a-zA-Z0-9]+\\s*\\(([^\\)]*)\\)", 1).splitAt(",", i).trim() + } + + string getAParameter() { result = getParameter(_) } + + int getAParameterUse(int index) { + exists(string parameter | parameter = getParameter(index) | + result = this.getBody().indexOf(parameter) + ) + } +} + +newtype TMacroOperator = + TTokenPastingOperator(FunctionLikeMacro m, string operand, int operatorOffset, int operandOffset) { + m.getAParameter() = operand and + ( + exists(string match | + match = m.getBody().regexpFind("#{2}\\s*" + operand, _, operatorOffset) + | + operandOffset = operatorOffset + match.indexOf(operand) + ) + or + exists(string match | match = m.getBody().regexpFind(operand + "\\s*#{2}", _, operandOffset) | + operatorOffset = operandOffset + match.indexOf("##") + ) + ) + } or + TStringizingOperator(FunctionLikeMacro m, string operand, int operatorOffset, int operandOffset) { + operand = m.getAParameter() and + exists(string match | + match = m.getBody().regexpFind("(? or ""filename"" sequence",,Preprocessor,Easy, +c,MISRA-C-2012,RULE-20-3,No,Required,,,"The #include directive shall be followed by either a or ""filename"" sequence",,,Easy,This is verified by the compiler c,MISRA-C-2012,RULE-20-4,Yes,Required,,,A macro shall not be defined with the same name as a keyword,A17-0-1,Preprocessor,Medium, -c,MISRA-C-2012,RULE-20-5,Yes,Advisory,,,#undef should not be used,,Preprocessor,Easy, +c,MISRA-C-2012,RULE-20-5,Yes,Advisory,,,#undef should not be used,,Preprocessor2,Easy, c,MISRA-C-2012,RULE-20-6,Yes,Required,,,Tokens that look like a preprocessing directive shall not occur within a macro argument,M16-0-5,Preprocessor,Import, c,MISRA-C-2012,RULE-20-7,Yes,Required,,,Expressions resulting from the expansion of macro parameters shall be enclosed in parentheses,M16-0-6,Preprocessor,Easy, -c,MISRA-C-2012,RULE-20-8,Yes,Required,,,The controlling expression of a #if or #elif preprocessing directive shall evaluate to 0 or 1,,Preprocessor,Hard, +c,MISRA-C-2012,RULE-20-8,Yes,Required,,,The controlling expression of a #if or #elif preprocessing directive shall evaluate to 0 or 1,,,Hard, c,MISRA-C-2012,RULE-20-9,Yes,Required,,,All identifiers used in the controlling expression of #if or #elif preprocessing directives shall be #defined before evaluation,M16-0-7,Preprocessor1,Import, c,MISRA-C-2012,RULE-20-10,Yes,Advisory,,,The # and ## preprocessor operators should not be used,M16-3-2,Preprocessor1,Import, -c,MISRA-C-2012,RULE-20-11,Yes,Required,,,A macro parameter immediately following a # operator shall not immediately be followed by a ## operator,M16-3-1,Preprocessor,Easy, -c,MISRA-C-2012,RULE-20-12,Yes,Required,,,"A macro parameter used as an operand to the # or ## operators, which is itself subject to further macro replacement, shall only be used as an operand to these operators",,Preprocessor,Medium, -c,MISRA-C-2012,RULE-20-13,Yes,Required,,,A line whose first token is # shall be a valid preprocessing directive,M16-0-8,Preprocessor,Easy, -c,MISRA-C-2012,RULE-20-14,Yes,Required,,,"All #else, #elif and #endif preprocessor directives shall reside in the same file as the #if, #ifdef or #ifndef directive to which they are related",M16-1-2,Preprocessor,Import, -c,MISRA-C-2012,RULE-21-1,Yes,Required,,,#define and #undef shall not be used on a reserved identifier or reserved macro name,,Preprocessor,Hard, +c,MISRA-C-2012,RULE-20-11,Yes,Required,,,A macro parameter immediately following a # operator shall not immediately be followed by a ## operator,M16-3-1,Preprocessor2,Easy, +c,MISRA-C-2012,RULE-20-12,Yes,Required,,,"A macro parameter used as an operand to the # or ## operators, which is itself subject to further macro replacement, shall only be used as an operand to these operators",,Preprocessor2,Medium, +c,MISRA-C-2012,RULE-20-13,No,Required,,,A line whose first token is # shall be a valid preprocessing directive,M16-0-8,,,This is verified by the compiler in the cases where the token is not within an ifdef branch that's never taken +c,MISRA-C-2012,RULE-20-14,No,Required,,,"All #else, #elif and #endif preprocessor directives shall reside in the same file as the #if, #ifdef or #ifndef directive to which they are related",M16-1-2,,,Compilers already prohibit this case +c,MISRA-C-2012,RULE-21-1,Yes,Required,,,#define and #undef shall not be used on a reserved identifier or reserved macro name,,,Hard, c,MISRA-C-2012,RULE-21-2,Yes,Required,,,A reserved identifier or reserved macro name shall not be declared,,Declarations,Hard, c,MISRA-C-2012,RULE-21-3,Yes,Required,,,The memory allocation and deallocation functions of shall not be used,,Banned,Medium, c,MISRA-C-2012,RULE-21-4,Yes,Required,,,The standard header file shall not be used ,,Banned,Easy, @@ -766,11 +766,11 @@ c,MISRA-C-2012,RULE-21-20,Yes,Mandatory,,,"The pointer returned by the Standard c,MISRA-C-2012,RULE-21-21,Yes,Required,,,The Standard Library function system of shall not be used,ENV33-C,Banned,Import, c,MISRA-C-2012,RULE-22-1,Yes,Required,,,All resources obtained dynamically by means of Standard Library functions shall be explicitly released,,Memory,Hard, c,MISRA-C-2012,RULE-22-2,Yes,Mandatory,,,A block of memory shall only be freed if it was allocated by means of a Standard Library function,,Memory,Hard, -c,MISRA-C-2012,RULE-22-3,Yes,Required,,,The same file shall not be open for read and write access at the same time on different streams,,IO,Hard, -c,MISRA-C-2012,RULE-22-4,Yes,Mandatory,,,There shall be no attempt to write to a stream which has been opened as read-only,,IO,Medium, -c,MISRA-C-2012,RULE-22-5,Yes,Mandatory,,,A pointer to a FILE object shall not be dereferenced,,IO,Medium, +c,MISRA-C-2012,RULE-22-3,Yes,Required,,,The same file shall not be open for read and write access at the same time on different streams,,IO3,Hard, +c,MISRA-C-2012,RULE-22-4,Yes,Mandatory,,,There shall be no attempt to write to a stream which has been opened as read-only,,IO3,Medium, +c,MISRA-C-2012,RULE-22-5,Yes,Mandatory,,,A pointer to a FILE object shall not be dereferenced,,IO3,Medium, c,MISRA-C-2012,RULE-22-6,Yes,Mandatory,,,The value of a pointer to a FILE shall not be used after the associated stream has been closed,FIO46-C,IO1,Import, -c,MISRA-C-2012,RULE-22-7,Yes,Required,,,The macro EOF shall only be compared with the unmodified return value from any Standard Library function capable of returning EOF,,IO,Hard, +c,MISRA-C-2012,RULE-22-7,Yes,Required,,,The macro EOF shall only be compared with the unmodified return value from any Standard Library function capable of returning EOF,,IO3,Hard, c,MISRA-C-2012,RULE-22-8,Yes,Required,,,The value of errno shall be set to zero prior to a call to an errno- setting-function,ERR30-C,Contracts,Import, c,MISRA-C-2012,RULE-22-9,Yes,Required,,,The value of errno shall be tested against zero after calling an errno-setting-function,,Contracts,Medium, c,MISRA-C-2012,RULE-22-10,Yes,Required,,,The value of errno shall only be tested when the last function to be called was an errno-setting-function,,Contracts,Medium, diff --git a/scripts/generate_rules/generate_package_files.py b/scripts/generate_rules/generate_package_files.py index 3830f1fb3e..aee6e145ca 100644 --- a/scripts/generate_rules/generate_package_files.py +++ b/scripts/generate_rules/generate_package_files.py @@ -78,6 +78,16 @@ default=False, help="create anonymized versions of the queries, without identifying rule information", ) +# Skip the generation of tests. This is useful when creating releases +# wherein we should preserve the author's intention to not provide c-specific +# test cases. +parser.add_argument( + "--skip-shared-test-generation", + action="store_true", + dest="skip_shared_test_generation", + default=False, + help="Do not generate tests.", +) parser.add_argument("language_name", help="the language of the package") parser.add_argument( "package_name", help="the name of the package to generate query files for") @@ -105,7 +115,7 @@ -def write_shared_implementation(package_name, rule_id, query, language_name, ql_language_name, common_src_pack_dir, common_test_pack_dir): +def write_shared_implementation(package_name, rule_id, query, language_name, ql_language_name, common_src_pack_dir, common_test_pack_dir, skip_tests=False): shared_impl_dir_name = query["shared_implementation_short_name"].lower() @@ -146,50 +156,51 @@ def write_shared_implementation(package_name, rule_id, query, language_name, ql_ # Write out the test. Test are always stored under the `language_name` # directory. - shared_impl_test_dir = common_test_pack_dir.joinpath( - "rules", - shared_impl_dir_name - ) + if not skip_tests: + shared_impl_test_dir = common_test_pack_dir.joinpath( + "rules", + shared_impl_dir_name + ) - shared_impl_test_dir.mkdir(exist_ok=True, parents=True) + shared_impl_test_dir.mkdir(exist_ok=True, parents=True) - # Generate test query file - shared_impl_test_query_path = shared_impl_test_dir.joinpath( - f"{query['shared_implementation_short_name']}.ql" - ) - - with open(shared_impl_test_query_path, "w", newline="\n") as f: - f.write("// GENERATED FILE - DO NOT MODIFY\n") - f.write( - "import " - + str(shared_impl_query_library_path.relative_to(common_src_pack_dir).with_suffix('')) - .replace("\\", "/") - .replace("/", ".") - + "\n" + # Generate test query file + shared_impl_test_query_path = shared_impl_test_dir.joinpath( + f"{query['shared_implementation_short_name']}.ql" ) + + with open(shared_impl_test_query_path, "w", newline="\n") as f: + f.write("// GENERATED FILE - DO NOT MODIFY\n") + f.write( + "import " + + str(shared_impl_query_library_path.relative_to(common_src_pack_dir).with_suffix('')) + .replace("\\", "/") + .replace("/", ".") + + "\n" + ) - # Create an empty test file, if one doesn't already exist - shared_impl_test_dir.joinpath( - "test." + language_name).touch() + # Create an empty test file, if one doesn't already exist + shared_impl_test_dir.joinpath( + "test." + language_name).touch() - # Add an empty expected results file - this makes it possible to see the results the - # first time you run the test in VS Code - expected_results_file = shared_impl_test_dir.joinpath( - query["shared_implementation_short_name"] + ".expected") - if not expected_results_file.exists(): - with open(expected_results_file, "w", newline="\n") as f: - f.write( - "No expected results have yet been specified") + # Add an empty expected results file - this makes it possible to see the results the + # first time you run the test in VS Code + expected_results_file = shared_impl_test_dir.joinpath( + query["shared_implementation_short_name"] + ".expected") + if not expected_results_file.exists(): + with open(expected_results_file, "w", newline="\n") as f: + f.write( + "No expected results have yet been specified") - # Add a testref file for this query, that refers to the shared library - test_ref_file = test_src_dir.joinpath( - query["short_name"] + ".testref") + # Add a testref file for this query, that refers to the shared library + test_ref_file = test_src_dir.joinpath( + query["short_name"] + ".testref") - # don't write it if it already exists - if not test_ref_file.exists(): - with open(test_ref_file, "w", newline="\n") as f: - f.write(str(shared_impl_test_query_path.relative_to( - repo_root)).replace("\\", "/")) + # don't write it if it already exists + if not test_ref_file.exists(): + with open(test_ref_file, "w", newline="\n") as f: + f.write(str(shared_impl_test_query_path.relative_to( + repo_root)).replace("\\", "/")) def write_non_shared_testfiles(query, language_name, query_path, test_src_dir, src_pack_dir): @@ -360,7 +371,7 @@ def write_non_shared_testfiles(query, language_name, query_path, test_src_dir, s f"""standard-example.{query["sourcefile_ext"]}""").touch() if "shared_implementation_short_name" in query: - write_shared_implementation(package_name, rule_id, query, language_name, ql_language_name, common_src_pack_dir, common_test_pack_dir) + write_shared_implementation(package_name, rule_id, query, language_name, ql_language_name, common_src_pack_dir, common_test_pack_dir, args.skip_shared_test_generation) else: write_non_shared_testfiles(query, language_name, query_path, test_src_dir, src_pack_dir) # Exclusions diff --git a/scripts/generate_rules/templates/exclusions.qll.template b/scripts/generate_rules/templates/exclusions.qll.template index 2016871ea1..25d1927722 100644 --- a/scripts/generate_rules/templates/exclusions.qll.template +++ b/scripts/generate_rules/templates/exclusions.qll.template @@ -3,11 +3,15 @@ import cpp import RuleMetadata import codingstandards.cpp.exclusions.RuleMetadata +{% if data | length == 1 %} +newtype {{ package_name }}Query = T{{ data[0]['queryname']}}Query() +{% else %} newtype {{ package_name }}Query = {% for query in data%} T{{ query['queryname']}}Query(){% if not loop.last %} or {% endif %}{% endfor %} +{% endif %} predicate is{{package_name}}QueryMetadata(Query query, string queryId, string ruleId) { {% for item in data %} From e78f15b6a27ec4390a89bf825dca0ee783e79154 Mon Sep 17 00:00:00 2001 From: Remco Vermeulen Date: Wed, 13 Jul 2022 12:17:35 +0200 Subject: [PATCH 0005/2973] Release v2.5.0 --- .vscode/tasks.json | 6 + c/cert/src/qlpack.yml | 2 +- ...ataRacesWithMultipleThreads-standard.qhelp | 33 ++ .../PreventDataRacesWithMultipleThreads.qhelp | 18 + .../PreventDataRacesWithMultipleThreads.ql | 23 ++ c/cert/src/rules/CON32-C/standard-example.c | 0 ...nsWhenUsingLibraryFunctions-standard.qhelp | 33 ++ ...eConditionsWhenUsingLibraryFunctions.qhelp | 18 + ...RaceConditionsWhenUsingLibraryFunctions.ql | 28 ++ c/cert/src/rules/CON33-C/standard-example.c | 0 ...ignalInMultithreadedProgram-standard.qhelp | 33 ++ ...oNotCallSignalInMultithreadedProgram.qhelp | 21 + .../DoNotCallSignalInMultithreadedProgram.ql | 28 ++ c/cert/src/rules/CON37-C/standard-example.c | 0 ...foreConvertingToLargerSizes-standard.qhelp | 33 ++ ...astCharBeforeConvertingToLargerSizes.qhelp | 18 + .../CastCharBeforeConvertingToLargerSizes.ql | 31 ++ c/cert/src/rules/STR34-C/standard-example.c | 0 ...nfuseNarrowAndWideFunctions-standard.qhelp | 33 ++ .../DoNotConfuseNarrowAndWideFunctions.qhelp | 18 + .../DoNotConfuseNarrowAndWideFunctions.ql | 68 +++ c/cert/src/rules/STR38-C/standard-example.c | 0 c/cert/test/qlpack.yml | 2 +- ...reventDataRacesWithMultipleThreads.testref | 1 + ...nditionsWhenUsingLibraryFunctions.expected | 2 + ...eConditionsWhenUsingLibraryFunctions.qlref | 1 + c/cert/test/rules/CON33-C/test.c | 31 ++ ...tCallSignalInMultithreadedProgram.expected | 1 + ...oNotCallSignalInMultithreadedProgram.qlref | 1 + c/cert/test/rules/CON37-C/test.c | 13 + ...CharBeforeConvertingToLargerSizes.expected | 21 + ...astCharBeforeConvertingToLargerSizes.qlref | 1 + c/cert/test/rules/STR34-C/test.c | 109 +++++ ...oNotConfuseNarrowAndWideFunctions.expected | 12 + .../DoNotConfuseNarrowAndWideFunctions.qlref | 1 + c/cert/test/rules/STR38-C/test.c | 39 ++ c/common/src/codingstandards/c/Pointers.qll | 38 ++ c/common/src/qlpack.yml | 2 +- c/common/test/qlpack.yml | 2 +- ...sOfAutoStorageObjectToOtherObject.expected | 1 + ...AddressOfAutoStorageObjectToOtherObject.ql | 2 + .../test.c | 0 ...PointersAddressingDifferentArrays.expected | 26 ++ ...btractPointersAddressingDifferentArrays.ql | 2 + .../test.c | 0 ...ThanTwoLevelsOfPointerIndirection.expected | 5 + ...seMoreThanTwoLevelsOfPointerIndirection.ql | 2 + .../test.c | 21 + ...rithmeticToAddressDifferentArrays.expected | 5 + ...interArithmeticToAddressDifferentArrays.ql | 2 + .../test.c | 0 ...ionalOperatorsWithDifferingArrays.expected | 44 ++ ...eRelationalOperatorsWithDifferingArrays.ql | 2 + .../test.c | 0 .../GuardAccessToBitFields.expected | 3 + .../GuardAccessToBitFields.ql | 2 + .../test/rules/guardaccesstobitfields/test.c | 69 ++++ ...ArrayIndexingForPointerArithmetic.expected | 4 + ...seOnlyArrayIndexingForPointerArithmetic.ql | 2 + .../test.c | 23 ++ c/misra/src/qlpack.yml | 2 +- ...rsionBetweenFunctionPointerAndOtherType.ql | 35 ++ .../src/rules/RULE-11-1/standard-example.c | 0 ...etweenIncompleteTypePointerAndOtherType.ql | 34 ++ .../src/rules/RULE-11-2/standard-example.c | 0 ...weenObjectPointerAndDifferentObjectType.ql | 37 ++ .../src/rules/RULE-11-3/standard-example.c | 0 ...ionBetweenPointerToObjectAndIntegerType.ql | 27 ++ .../src/rules/RULE-11-4/standard-example.c | 0 ...ionFromPointerToVoidIntoPointerToObject.ql | 25 ++ .../src/rules/RULE-11-5/standard-example.c | 0 ...stBetweenPointerToVoidAndArithmeticType.ql | 26 ++ .../src/rules/RULE-11-6/standard-example.c | 0 ...nPointerToObjectAndNonIntArithmeticType.ql | 35 ++ .../src/rules/RULE-11-7/standard-example.c | 0 ...CastRemovesConstOrVolatileQualification.ql | 27 ++ .../src/rules/RULE-11-8/standard-example.c | 0 ...NullNotUsedAsIntegerNullPointerConstant.ql | 54 +++ .../src/rules/RULE-11-9/standard-example.c | 0 ...erAndDerivedPointerMustAddressSameArray.ql | 22 + .../src/rules/RULE-18-1/standard-example.c | 0 ...tionBetweenPointersMustAddressSameArray.ql | 22 + .../src/rules/RULE-18-2/standard-example.c | 0 ...OperatorComparesPointerToDifferentArray.ql | 22 + .../src/rules/RULE-18-3/standard-example.c | 0 ...dditionOrSubtractionOperatorsOnPointers.ql | 22 + .../src/rules/RULE-18-4/standard-example.c | 0 ...TwoLevelsOfPointerNestingInDeclarations.ql | 22 + .../src/rules/RULE-18-5/standard-example.c | 0 ...StorageObjectAddressCopiedToOtherObject.ql | 23 ++ .../src/rules/RULE-18-6/standard-example.c | 0 .../ControllingExpressionIfDirective.ql | 96 +++++ .../src/rules/RULE-20-8/standard-example.c | 11 + ...tWithNoPointerDereferenceShouldBeOpaque.ql | 47 +++ c/misra/src/rules/RULE-4-8/standard-example.c | 0 ...interShouldPointToConstTypeWhenPossible.ql | 51 +++ .../src/rules/RULE-8-13/standard-example.c | 0 c/misra/test/qlpack.yml | 2 +- ...etweenFunctionPointerAndOtherType.expected | 5 + ...onBetweenFunctionPointerAndOtherType.qlref | 1 + ...BetweenFunctionPointerAndOtherType.testref | 1 + c/misra/test/rules/RULE-11-1/test.c | 23 ++ ...IncompleteTypePointerAndOtherType.expected | 3 + ...eenIncompleteTypePointerAndOtherType.qlref | 1 + c/misra/test/rules/RULE-11-2/test.c | 21 + ...jectPointerAndDifferentObjectType.expected | 4 + ...nObjectPointerAndDifferentObjectType.qlref | 1 + c/misra/test/rules/RULE-11-3/test.c | 16 + ...weenPointerToObjectAndIntegerType.expected | 6 + ...BetweenPointerToObjectAndIntegerType.qlref | 1 + c/misra/test/rules/RULE-11-4/test.c | 13 + ...mPointerToVoidIntoPointerToObject.expected | 1 + ...FromPointerToVoidIntoPointerToObject.qlref | 1 + c/misra/test/rules/RULE-11-5/test.c | 10 + ...eenPointerToVoidAndArithmeticType.expected | 3 + ...etweenPointerToVoidAndArithmeticType.qlref | 1 + c/misra/test/rules/RULE-11-6/test.c | 9 + ...erToObjectAndNonIntArithmeticType.expected | 3 + ...interToObjectAndNonIntArithmeticType.qlref | 1 + c/misra/test/rules/RULE-11-7/test.c | 10 + ...movesConstOrVolatileQualification.expected | 2 + ...tRemovesConstOrVolatileQualification.qlref | 1 + c/misra/test/rules/RULE-11-8/test.c | 9 + ...tUsedAsIntegerNullPointerConstant.expected | 4 + ...lNotUsedAsIntegerNullPointerConstant.qlref | 1 + c/misra/test/rules/RULE-11-9/test.c | 27 ++ ...DerivedPointerMustAddressSameArray.testref | 1 + ...etweenPointersMustAddressSameArray.testref | 1 + ...torComparesPointerToDifferentArray.testref | 1 + ...onOrSubtractionOperatorsOnPointers.testref | 1 + ...velsOfPointerNestingInDeclarations.testref | 1 + ...geObjectAddressCopiedToOtherObject.testref | 1 + .../ControllingExpressionIfDirective.expected | 7 + .../ControllingExpressionIfDirective.qlref | 1 + c/misra/test/rules/RULE-20-8/test.c | 76 ++++ ...oPointerDereferenceShouldBeOpaque.expected | 6 + ...thNoPointerDereferenceShouldBeOpaque.qlref | 1 + c/misra/test/rules/RULE-4-8/test.c | 46 +++ c/misra/test/rules/RULE-4-8/test.h | 10 + c/misra/test/rules/RULE-4-8/test_2.c | 46 +++ c/misra/test/rules/RULE-4-8/test_shared.h | 28 ++ ...houldPointToConstTypeWhenPossible.expected | 14 + ...erShouldPointToConstTypeWhenPossible.qlref | 1 + c/misra/test/rules/RULE-8-13/test.c | 78 ++++ cpp/autosar/src/qlpack.yml | 2 +- ...onContainLessThanTwoLevelsOfIndirection.ql | 29 +- ...dexingNotTheOnlyFormOfPointerArithmetic.ql | 47 +-- ...erAndDerivedPointerAccessDifferentArray.ql | 168 +------- .../M5-0-18/AppliedToObjectsOfPointerType.ql | 74 +--- .../M7-5-2/AssignmentOfEscapingAutoStorage.ql | 47 +-- cpp/autosar/test/qlpack.yml | 2 +- ...ontainLessThanTwoLevelsOfIndirection.qlref | 1 - ...tainLessThanTwoLevelsOfIndirection.testref | 1 + ...ingNotTheOnlyFormOfPointerArithmetic.qlref | 1 - ...gNotTheOnlyFormOfPointerArithmetic.testref | 1 + ...ndDerivedPointerAccessDifferentArray.qlref | 1 - ...DerivedPointerAccessDifferentArray.testref | 1 + .../PointerSubtractionOnDifferentArrays.qlref | 1 - ...ointerSubtractionOnDifferentArrays.testref | 1 + .../AppliedToObjectsOfPointerType.qlref | 1 - .../AppliedToObjectsOfPointerType.testref | 1 + .../AssignmentOfEscapingAutoStorage.qlref | 1 - .../AssignmentOfEscapingAutoStorage.testref | 1 + cpp/cert/src/qlpack.yml | 2 +- ...ldAccessFromMultipleThreads-standard.qhelp | 33 ++ ...ntBitFieldAccessFromMultipleThreads.qhelp} | 2 +- ...reventBitFieldAccessFromMultipleThreads.ql | 23 ++ ...itFieldsFromMultipleThreads-standard.qhelp | 302 -------------- .../src/rules/CON52-CPP/standard-example.cpp | 0 .../src/rules/CTR56-CPP/standard-example.cpp | 0 .../src/rules/EXP51-CPP/standard-example.cpp | 0 .../src/rules/EXP54-CPP/standard-example.cpp | 0 .../src/rules/EXP57-CPP/standard-example.cpp | 0 .../src/rules/MEM50-CPP/standard-example.cpp | 0 .../src/rules/OOP55-CPP/standard-example.cpp | 0 cpp/cert/test/qlpack.yml | 2 +- ...tBitFieldAccessFromMultipleThreads.testref | 1 + ...ccessingBitFieldsFromMultipleThreads.qlref | 1 - .../src/codingstandards/cpp/Concurrency.qll | 181 +++++++- .../cpp/exclusions/c/Concurrency1.qll | 58 +++ .../cpp/exclusions/c/Pointers1.qll | 282 +++++++++++++ .../cpp/exclusions/c/Preprocessor3.qll | 25 ++ .../cpp/exclusions/c/RuleMetadata.qll | 12 + .../cpp/exclusions/c/Strings3.qll | 42 ++ .../cpp/exclusions/cpp/Concurrency.qll | 16 +- ...ddressOfAutoStorageObjectToOtherObject.qll | 57 +++ ...tractPointersAddressingDifferentArrays.qll | 72 ++++ ...eMoreThanTwoLevelsOfPointerIndirection.qll | 40 ++ ...nterArithmeticToAddressDifferentArrays.qll | 181 ++++++++ ...RelationalOperatorsWithDifferingArrays.qll | 92 +++++ .../GuardAccessToBitFields.qll} | 31 +- ...eOnlyArrayIndexingForPointerArithmetic.qll | 58 +++ cpp/common/src/qlpack.yml | 2 +- cpp/common/test/qlpack.yml | 2 +- ...OfAutoStorageObjectToOtherObject.expected} | 0 ...AddressOfAutoStorageObjectToOtherObject.ql | 2 + .../manager.cpp | 0 .../stack_escapes_test.cpp | 0 .../test.cpp | 9 + ...ointersAddressingDifferentArrays.expected} | 10 +- ...btractPointersAddressingDifferentArrays.ql | 2 + .../test.cpp | 15 + ...hanTwoLevelsOfPointerIndirection.expected} | 0 ...seMoreThanTwoLevelsOfPointerIndirection.ql | 2 + .../test.cpp | 0 ...ithmeticToAddressDifferentArrays.expected} | 0 ...interArithmeticToAddressDifferentArrays.ql | 2 + .../test.cpp | 20 + ...onalOperatorsWithDifferingArrays.expected} | 22 +- ...eRelationalOperatorsWithDifferingArrays.ql | 2 + .../test.cpp | 27 ++ .../GuardAccessToBitFields.expected} | 0 .../GuardAccessToBitFields.ql | 2 + .../rules/guardaccesstobitfields}/test.cpp | 0 ...rrayIndexingForPointerArithmetic.expected} | 0 ...seOnlyArrayIndexingForPointerArithmetic.ql | 2 + .../test.cpp | 0 cpp/misra/src/qlpack.yml | 2 +- cpp/misra/test/qlpack.yml | 2 +- cpp/report/src/qlpack.yml | 2 +- rule_packages/c/Concurrency1.json | 66 +++ rule_packages/c/Pointers1.json | 388 ++++++++++++++++++ rule_packages/c/Preprocessor3.json | 24 ++ rule_packages/c/Strings3.json | 44 ++ rule_packages/cpp/Concurrency.json | 3 +- rule_packages/cpp/Freed.json | 1 + rule_packages/cpp/Pointers.json | 5 + rules.csv | 72 ++-- 228 files changed, 3933 insertions(+), 768 deletions(-) create mode 100644 c/cert/src/rules/CON32-C/PreventDataRacesWithMultipleThreads-standard.qhelp create mode 100644 c/cert/src/rules/CON32-C/PreventDataRacesWithMultipleThreads.qhelp create mode 100644 c/cert/src/rules/CON32-C/PreventDataRacesWithMultipleThreads.ql create mode 100644 c/cert/src/rules/CON32-C/standard-example.c create mode 100644 c/cert/src/rules/CON33-C/RaceConditionsWhenUsingLibraryFunctions-standard.qhelp create mode 100644 c/cert/src/rules/CON33-C/RaceConditionsWhenUsingLibraryFunctions.qhelp create mode 100644 c/cert/src/rules/CON33-C/RaceConditionsWhenUsingLibraryFunctions.ql create mode 100644 c/cert/src/rules/CON33-C/standard-example.c create mode 100644 c/cert/src/rules/CON37-C/DoNotCallSignalInMultithreadedProgram-standard.qhelp create mode 100644 c/cert/src/rules/CON37-C/DoNotCallSignalInMultithreadedProgram.qhelp create mode 100644 c/cert/src/rules/CON37-C/DoNotCallSignalInMultithreadedProgram.ql create mode 100644 c/cert/src/rules/CON37-C/standard-example.c create mode 100644 c/cert/src/rules/STR34-C/CastCharBeforeConvertingToLargerSizes-standard.qhelp create mode 100644 c/cert/src/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.qhelp create mode 100644 c/cert/src/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.ql create mode 100644 c/cert/src/rules/STR34-C/standard-example.c create mode 100644 c/cert/src/rules/STR38-C/DoNotConfuseNarrowAndWideFunctions-standard.qhelp create mode 100644 c/cert/src/rules/STR38-C/DoNotConfuseNarrowAndWideFunctions.qhelp create mode 100644 c/cert/src/rules/STR38-C/DoNotConfuseNarrowAndWideFunctions.ql create mode 100644 c/cert/src/rules/STR38-C/standard-example.c create mode 100644 c/cert/test/rules/CON32-C/PreventDataRacesWithMultipleThreads.testref create mode 100644 c/cert/test/rules/CON33-C/RaceConditionsWhenUsingLibraryFunctions.expected create mode 100644 c/cert/test/rules/CON33-C/RaceConditionsWhenUsingLibraryFunctions.qlref create mode 100644 c/cert/test/rules/CON33-C/test.c create mode 100644 c/cert/test/rules/CON37-C/DoNotCallSignalInMultithreadedProgram.expected create mode 100644 c/cert/test/rules/CON37-C/DoNotCallSignalInMultithreadedProgram.qlref create mode 100644 c/cert/test/rules/CON37-C/test.c create mode 100644 c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.expected create mode 100644 c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.qlref create mode 100644 c/cert/test/rules/STR34-C/test.c create mode 100644 c/cert/test/rules/STR38-C/DoNotConfuseNarrowAndWideFunctions.expected create mode 100644 c/cert/test/rules/STR38-C/DoNotConfuseNarrowAndWideFunctions.qlref create mode 100644 c/cert/test/rules/STR38-C/test.c create mode 100644 c/common/src/codingstandards/c/Pointers.qll create mode 100644 c/common/test/rules/donotcopyaddressofautostorageobjecttootherobject/DoNotCopyAddressOfAutoStorageObjectToOtherObject.expected create mode 100644 c/common/test/rules/donotcopyaddressofautostorageobjecttootherobject/DoNotCopyAddressOfAutoStorageObjectToOtherObject.ql rename cpp/autosar/test/rules/M7-5-2/test.cpp => c/common/test/rules/donotcopyaddressofautostorageobjecttootherobject/test.c (100%) create mode 100644 c/common/test/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.expected create mode 100644 c/common/test/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.ql rename cpp/autosar/test/rules/M5-0-17/test.cpp => c/common/test/rules/donotsubtractpointersaddressingdifferentarrays/test.c (100%) create mode 100644 c/common/test/rules/donotusemorethantwolevelsofpointerindirection/DoNotUseMoreThanTwoLevelsOfPointerIndirection.expected create mode 100644 c/common/test/rules/donotusemorethantwolevelsofpointerindirection/DoNotUseMoreThanTwoLevelsOfPointerIndirection.ql create mode 100644 c/common/test/rules/donotusemorethantwolevelsofpointerindirection/test.c create mode 100644 c/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.expected create mode 100644 c/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.ql rename cpp/autosar/test/rules/M5-0-16/test.cpp => c/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/test.c (100%) create mode 100644 c/common/test/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.expected create mode 100644 c/common/test/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.ql rename cpp/autosar/test/rules/M5-0-18/test.cpp => c/common/test/rules/donotuserelationaloperatorswithdifferingarrays/test.c (100%) create mode 100644 c/common/test/rules/guardaccesstobitfields/GuardAccessToBitFields.expected create mode 100644 c/common/test/rules/guardaccesstobitfields/GuardAccessToBitFields.ql create mode 100644 c/common/test/rules/guardaccesstobitfields/test.c create mode 100644 c/common/test/rules/useonlyarrayindexingforpointerarithmetic/UseOnlyArrayIndexingForPointerArithmetic.expected create mode 100644 c/common/test/rules/useonlyarrayindexingforpointerarithmetic/UseOnlyArrayIndexingForPointerArithmetic.ql create mode 100644 c/common/test/rules/useonlyarrayindexingforpointerarithmetic/test.c create mode 100644 c/misra/src/rules/RULE-11-1/ConversionBetweenFunctionPointerAndOtherType.ql create mode 100644 c/misra/src/rules/RULE-11-1/standard-example.c create mode 100644 c/misra/src/rules/RULE-11-2/ConversionBetweenIncompleteTypePointerAndOtherType.ql create mode 100644 c/misra/src/rules/RULE-11-2/standard-example.c create mode 100644 c/misra/src/rules/RULE-11-3/CastBetweenObjectPointerAndDifferentObjectType.ql create mode 100644 c/misra/src/rules/RULE-11-3/standard-example.c create mode 100644 c/misra/src/rules/RULE-11-4/ConversionBetweenPointerToObjectAndIntegerType.ql create mode 100644 c/misra/src/rules/RULE-11-4/standard-example.c create mode 100644 c/misra/src/rules/RULE-11-5/ConversionFromPointerToVoidIntoPointerToObject.ql create mode 100644 c/misra/src/rules/RULE-11-5/standard-example.c create mode 100644 c/misra/src/rules/RULE-11-6/CastBetweenPointerToVoidAndArithmeticType.ql create mode 100644 c/misra/src/rules/RULE-11-6/standard-example.c create mode 100644 c/misra/src/rules/RULE-11-7/CastBetweenPointerToObjectAndNonIntArithmeticType.ql create mode 100644 c/misra/src/rules/RULE-11-7/standard-example.c create mode 100644 c/misra/src/rules/RULE-11-8/CastRemovesConstOrVolatileQualification.ql create mode 100644 c/misra/src/rules/RULE-11-8/standard-example.c create mode 100644 c/misra/src/rules/RULE-11-9/MacroNullNotUsedAsIntegerNullPointerConstant.ql create mode 100644 c/misra/src/rules/RULE-11-9/standard-example.c create mode 100644 c/misra/src/rules/RULE-18-1/PointerAndDerivedPointerMustAddressSameArray.ql create mode 100644 c/misra/src/rules/RULE-18-1/standard-example.c create mode 100644 c/misra/src/rules/RULE-18-2/SubtractionBetweenPointersMustAddressSameArray.ql create mode 100644 c/misra/src/rules/RULE-18-2/standard-example.c create mode 100644 c/misra/src/rules/RULE-18-3/RelationalOperatorComparesPointerToDifferentArray.ql create mode 100644 c/misra/src/rules/RULE-18-3/standard-example.c create mode 100644 c/misra/src/rules/RULE-18-4/DoNotUseAdditionOrSubtractionOperatorsOnPointers.ql create mode 100644 c/misra/src/rules/RULE-18-4/standard-example.c create mode 100644 c/misra/src/rules/RULE-18-5/NoMoreThanTwoLevelsOfPointerNestingInDeclarations.ql create mode 100644 c/misra/src/rules/RULE-18-5/standard-example.c create mode 100644 c/misra/src/rules/RULE-18-6/AutomaticStorageObjectAddressCopiedToOtherObject.ql create mode 100644 c/misra/src/rules/RULE-18-6/standard-example.c create mode 100644 c/misra/src/rules/RULE-20-8/ControllingExpressionIfDirective.ql create mode 100644 c/misra/src/rules/RULE-20-8/standard-example.c create mode 100644 c/misra/src/rules/RULE-4-8/ObjectWithNoPointerDereferenceShouldBeOpaque.ql create mode 100644 c/misra/src/rules/RULE-4-8/standard-example.c create mode 100644 c/misra/src/rules/RULE-8-13/PointerShouldPointToConstTypeWhenPossible.ql create mode 100644 c/misra/src/rules/RULE-8-13/standard-example.c create mode 100644 c/misra/test/rules/RULE-11-1/ConversionBetweenFunctionPointerAndOtherType.expected create mode 100644 c/misra/test/rules/RULE-11-1/ConversionBetweenFunctionPointerAndOtherType.qlref create mode 100644 c/misra/test/rules/RULE-11-1/ConversionBetweenFunctionPointerAndOtherType.testref create mode 100644 c/misra/test/rules/RULE-11-1/test.c create mode 100644 c/misra/test/rules/RULE-11-2/ConversionBetweenIncompleteTypePointerAndOtherType.expected create mode 100644 c/misra/test/rules/RULE-11-2/ConversionBetweenIncompleteTypePointerAndOtherType.qlref create mode 100644 c/misra/test/rules/RULE-11-2/test.c create mode 100644 c/misra/test/rules/RULE-11-3/CastBetweenObjectPointerAndDifferentObjectType.expected create mode 100644 c/misra/test/rules/RULE-11-3/CastBetweenObjectPointerAndDifferentObjectType.qlref create mode 100644 c/misra/test/rules/RULE-11-3/test.c create mode 100644 c/misra/test/rules/RULE-11-4/ConversionBetweenPointerToObjectAndIntegerType.expected create mode 100644 c/misra/test/rules/RULE-11-4/ConversionBetweenPointerToObjectAndIntegerType.qlref create mode 100644 c/misra/test/rules/RULE-11-4/test.c create mode 100644 c/misra/test/rules/RULE-11-5/ConversionFromPointerToVoidIntoPointerToObject.expected create mode 100644 c/misra/test/rules/RULE-11-5/ConversionFromPointerToVoidIntoPointerToObject.qlref create mode 100644 c/misra/test/rules/RULE-11-5/test.c create mode 100644 c/misra/test/rules/RULE-11-6/CastBetweenPointerToVoidAndArithmeticType.expected create mode 100644 c/misra/test/rules/RULE-11-6/CastBetweenPointerToVoidAndArithmeticType.qlref create mode 100644 c/misra/test/rules/RULE-11-6/test.c create mode 100644 c/misra/test/rules/RULE-11-7/CastBetweenPointerToObjectAndNonIntArithmeticType.expected create mode 100644 c/misra/test/rules/RULE-11-7/CastBetweenPointerToObjectAndNonIntArithmeticType.qlref create mode 100644 c/misra/test/rules/RULE-11-7/test.c create mode 100644 c/misra/test/rules/RULE-11-8/CastRemovesConstOrVolatileQualification.expected create mode 100644 c/misra/test/rules/RULE-11-8/CastRemovesConstOrVolatileQualification.qlref create mode 100644 c/misra/test/rules/RULE-11-8/test.c create mode 100644 c/misra/test/rules/RULE-11-9/MacroNullNotUsedAsIntegerNullPointerConstant.expected create mode 100644 c/misra/test/rules/RULE-11-9/MacroNullNotUsedAsIntegerNullPointerConstant.qlref create mode 100644 c/misra/test/rules/RULE-11-9/test.c create mode 100644 c/misra/test/rules/RULE-18-1/PointerAndDerivedPointerMustAddressSameArray.testref create mode 100644 c/misra/test/rules/RULE-18-2/SubtractionBetweenPointersMustAddressSameArray.testref create mode 100644 c/misra/test/rules/RULE-18-3/RelationalOperatorComparesPointerToDifferentArray.testref create mode 100644 c/misra/test/rules/RULE-18-4/DoNotUseAdditionOrSubtractionOperatorsOnPointers.testref create mode 100644 c/misra/test/rules/RULE-18-5/NoMoreThanTwoLevelsOfPointerNestingInDeclarations.testref create mode 100644 c/misra/test/rules/RULE-18-6/AutomaticStorageObjectAddressCopiedToOtherObject.testref create mode 100644 c/misra/test/rules/RULE-20-8/ControllingExpressionIfDirective.expected create mode 100644 c/misra/test/rules/RULE-20-8/ControllingExpressionIfDirective.qlref create mode 100644 c/misra/test/rules/RULE-20-8/test.c create mode 100644 c/misra/test/rules/RULE-4-8/ObjectWithNoPointerDereferenceShouldBeOpaque.expected create mode 100644 c/misra/test/rules/RULE-4-8/ObjectWithNoPointerDereferenceShouldBeOpaque.qlref create mode 100644 c/misra/test/rules/RULE-4-8/test.c create mode 100644 c/misra/test/rules/RULE-4-8/test.h create mode 100644 c/misra/test/rules/RULE-4-8/test_2.c create mode 100644 c/misra/test/rules/RULE-4-8/test_shared.h create mode 100644 c/misra/test/rules/RULE-8-13/PointerShouldPointToConstTypeWhenPossible.expected create mode 100644 c/misra/test/rules/RULE-8-13/PointerShouldPointToConstTypeWhenPossible.qlref create mode 100644 c/misra/test/rules/RULE-8-13/test.c delete mode 100644 cpp/autosar/test/rules/A5-0-3/DeclarationContainLessThanTwoLevelsOfIndirection.qlref create mode 100644 cpp/autosar/test/rules/A5-0-3/DeclarationContainLessThanTwoLevelsOfIndirection.testref delete mode 100644 cpp/autosar/test/rules/M5-0-15/IndexingNotTheOnlyFormOfPointerArithmetic.qlref create mode 100644 cpp/autosar/test/rules/M5-0-15/IndexingNotTheOnlyFormOfPointerArithmetic.testref delete mode 100644 cpp/autosar/test/rules/M5-0-16/PointerAndDerivedPointerAccessDifferentArray.qlref create mode 100644 cpp/autosar/test/rules/M5-0-16/PointerAndDerivedPointerAccessDifferentArray.testref delete mode 100644 cpp/autosar/test/rules/M5-0-17/PointerSubtractionOnDifferentArrays.qlref create mode 100644 cpp/autosar/test/rules/M5-0-17/PointerSubtractionOnDifferentArrays.testref delete mode 100644 cpp/autosar/test/rules/M5-0-18/AppliedToObjectsOfPointerType.qlref create mode 100644 cpp/autosar/test/rules/M5-0-18/AppliedToObjectsOfPointerType.testref delete mode 100644 cpp/autosar/test/rules/M7-5-2/AssignmentOfEscapingAutoStorage.qlref create mode 100644 cpp/autosar/test/rules/M7-5-2/AssignmentOfEscapingAutoStorage.testref create mode 100644 cpp/cert/src/rules/CON52-CPP/PreventBitFieldAccessFromMultipleThreads-standard.qhelp rename cpp/cert/src/rules/CON52-CPP/{PreventDataRacesWhenAccessingBitFieldsFromMultipleThreads.qhelp => PreventBitFieldAccessFromMultipleThreads.qhelp} (86%) create mode 100644 cpp/cert/src/rules/CON52-CPP/PreventBitFieldAccessFromMultipleThreads.ql delete mode 100644 cpp/cert/src/rules/CON52-CPP/PreventDataRacesWhenAccessingBitFieldsFromMultipleThreads-standard.qhelp create mode 100644 cpp/cert/src/rules/CON52-CPP/standard-example.cpp create mode 100644 cpp/cert/src/rules/CTR56-CPP/standard-example.cpp create mode 100644 cpp/cert/src/rules/EXP51-CPP/standard-example.cpp create mode 100644 cpp/cert/src/rules/EXP54-CPP/standard-example.cpp create mode 100644 cpp/cert/src/rules/EXP57-CPP/standard-example.cpp create mode 100644 cpp/cert/src/rules/MEM50-CPP/standard-example.cpp create mode 100644 cpp/cert/src/rules/OOP55-CPP/standard-example.cpp create mode 100644 cpp/cert/test/rules/CON52-CPP/PreventBitFieldAccessFromMultipleThreads.testref delete mode 100644 cpp/cert/test/rules/CON52-CPP/PreventDataRacesWhenAccessingBitFieldsFromMultipleThreads.qlref create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/c/Concurrency1.qll create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/c/Pointers1.qll create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/c/Preprocessor3.qll create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/c/Strings3.qll create mode 100644 cpp/common/src/codingstandards/cpp/rules/donotcopyaddressofautostorageobjecttootherobject/DoNotCopyAddressOfAutoStorageObjectToOtherObject.qll create mode 100644 cpp/common/src/codingstandards/cpp/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.qll create mode 100644 cpp/common/src/codingstandards/cpp/rules/donotusemorethantwolevelsofpointerindirection/DoNotUseMoreThanTwoLevelsOfPointerIndirection.qll create mode 100644 cpp/common/src/codingstandards/cpp/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.qll create mode 100644 cpp/common/src/codingstandards/cpp/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.qll rename cpp/{cert/src/rules/CON52-CPP/PreventDataRacesWhenAccessingBitFieldsFromMultipleThreads.ql => common/src/codingstandards/cpp/rules/guardaccesstobitfields/GuardAccessToBitFields.qll} (59%) create mode 100644 cpp/common/src/codingstandards/cpp/rules/useonlyarrayindexingforpointerarithmetic/UseOnlyArrayIndexingForPointerArithmetic.qll rename cpp/{autosar/test/rules/M7-5-2/AssignmentOfEscapingAutoStorage.expected => common/test/rules/donotcopyaddressofautostorageobjecttootherobject/DoNotCopyAddressOfAutoStorageObjectToOtherObject.expected} (100%) create mode 100644 cpp/common/test/rules/donotcopyaddressofautostorageobjecttootherobject/DoNotCopyAddressOfAutoStorageObjectToOtherObject.ql rename cpp/{autosar/test/rules/M7-5-2 => common/test/rules/donotcopyaddressofautostorageobjecttootherobject}/manager.cpp (100%) rename cpp/{autosar/test/rules/M7-5-2 => common/test/rules/donotcopyaddressofautostorageobjecttootherobject}/stack_escapes_test.cpp (100%) create mode 100644 cpp/common/test/rules/donotcopyaddressofautostorageobjecttootherobject/test.cpp rename cpp/{autosar/test/rules/M5-0-17/PointerSubtractionOnDifferentArrays.expected => common/test/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.expected} (99%) create mode 100644 cpp/common/test/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.ql create mode 100644 cpp/common/test/rules/donotsubtractpointersaddressingdifferentarrays/test.cpp rename cpp/{autosar/test/rules/A5-0-3/DeclarationContainLessThanTwoLevelsOfIndirection.expected => common/test/rules/donotusemorethantwolevelsofpointerindirection/DoNotUseMoreThanTwoLevelsOfPointerIndirection.expected} (100%) create mode 100644 cpp/common/test/rules/donotusemorethantwolevelsofpointerindirection/DoNotUseMoreThanTwoLevelsOfPointerIndirection.ql rename cpp/{autosar/test/rules/A5-0-3 => common/test/rules/donotusemorethantwolevelsofpointerindirection}/test.cpp (100%) rename cpp/{autosar/test/rules/M5-0-16/PointerAndDerivedPointerAccessDifferentArray.expected => common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.expected} (100%) create mode 100644 cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.ql create mode 100644 cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/test.cpp rename cpp/{autosar/test/rules/M5-0-18/AppliedToObjectsOfPointerType.expected => common/test/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.expected} (99%) create mode 100644 cpp/common/test/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.ql create mode 100644 cpp/common/test/rules/donotuserelationaloperatorswithdifferingarrays/test.cpp rename cpp/{cert/test/rules/CON52-CPP/PreventDataRacesWhenAccessingBitFieldsFromMultipleThreads.expected => common/test/rules/guardaccesstobitfields/GuardAccessToBitFields.expected} (100%) create mode 100644 cpp/common/test/rules/guardaccesstobitfields/GuardAccessToBitFields.ql rename cpp/{cert/test/rules/CON52-CPP => common/test/rules/guardaccesstobitfields}/test.cpp (100%) rename cpp/{autosar/test/rules/M5-0-15/IndexingNotTheOnlyFormOfPointerArithmetic.expected => common/test/rules/useonlyarrayindexingforpointerarithmetic/UseOnlyArrayIndexingForPointerArithmetic.expected} (100%) create mode 100644 cpp/common/test/rules/useonlyarrayindexingforpointerarithmetic/UseOnlyArrayIndexingForPointerArithmetic.ql rename cpp/{autosar/test/rules/M5-0-15 => common/test/rules/useonlyarrayindexingforpointerarithmetic}/test.cpp (100%) create mode 100644 rule_packages/c/Concurrency1.json create mode 100644 rule_packages/c/Pointers1.json create mode 100644 rule_packages/c/Preprocessor3.json create mode 100644 rule_packages/c/Strings3.json diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 8e5b1b4ccc..9de0bd3ae7 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -171,6 +171,10 @@ "Classes", "Comments", "Concurrency", + "Concurrency", + "Concurrency1", + "Concurrency2", + "Concurrency3", "Conditionals", "Const", "DeadCode", @@ -199,6 +203,8 @@ "OperatorInvariants", "Operators", "Pointers", + "Pointers1", + "Pointers2", "Scope", "SideEffects1", "SideEffects2", diff --git a/c/cert/src/qlpack.yml b/c/cert/src/qlpack.yml index b3cd47c3a4..2feb43f3b8 100644 --- a/c/cert/src/qlpack.yml +++ b/c/cert/src/qlpack.yml @@ -1,4 +1,4 @@ name: cert-c-coding-standards -version: 2.4.0 +version: 2.5.0 suites: codeql-suites libraryPathDependencies: common-c-coding-standards \ No newline at end of file diff --git a/c/cert/src/rules/CON32-C/PreventDataRacesWithMultipleThreads-standard.qhelp b/c/cert/src/rules/CON32-C/PreventDataRacesWithMultipleThreads-standard.qhelp new file mode 100644 index 0000000000..458fbe3f7d --- /dev/null +++ b/c/cert/src/rules/CON32-C/PreventDataRacesWithMultipleThreads-standard.qhelp @@ -0,0 +1,33 @@ + + +
    +
      +
    • required
    • +
    • implementation
    • +
    • automated
    • +
    +
    + +
    +

    + ... +

    + +
    + +
    +

    + ... +

    +
    + + + + + +
    +
      +
    • ...
    • +
    +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/CON32-C/PreventDataRacesWithMultipleThreads.qhelp b/c/cert/src/rules/CON32-C/PreventDataRacesWithMultipleThreads.qhelp new file mode 100644 index 0000000000..3100741c68 --- /dev/null +++ b/c/cert/src/rules/CON32-C/PreventDataRacesWithMultipleThreads.qhelp @@ -0,0 +1,18 @@ + + + + +

    This query implements the CERT-C rule CON32-C:

    +
    +

    Prevent data races when accessing bit-fields from multiple threads

    +
    +
    + + +
  • + CERT-C: + CON32-C: Prevent data races when accessing bit-fields from multiple threads + . +
  • +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/CON32-C/PreventDataRacesWithMultipleThreads.ql b/c/cert/src/rules/CON32-C/PreventDataRacesWithMultipleThreads.ql new file mode 100644 index 0000000000..d4f3cbbe10 --- /dev/null +++ b/c/cert/src/rules/CON32-C/PreventDataRacesWithMultipleThreads.ql @@ -0,0 +1,23 @@ +/** + * @id c/cert/prevent-data-races-with-multiple-threads + * @name CON32-C: Prevent data races when accessing bit-fields from multiple threads + * @description Accesses to bit fields without proper concurrency protection can result in data + * races. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/cert/id/con32-c + * correctness + * concurrency + * external/cert/obligation/rule + */ + +import cpp +import codingstandards.c.cert +import codingstandards.cpp.rules.guardaccesstobitfields.GuardAccessToBitFields + +class PreventDataRacesWithMultipleThreadsQuery extends GuardAccessToBitFieldsSharedQuery { + PreventDataRacesWithMultipleThreadsQuery() { + this = Concurrency1Package::preventDataRacesWithMultipleThreadsQuery() + } +} diff --git a/c/cert/src/rules/CON32-C/standard-example.c b/c/cert/src/rules/CON32-C/standard-example.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/cert/src/rules/CON33-C/RaceConditionsWhenUsingLibraryFunctions-standard.qhelp b/c/cert/src/rules/CON33-C/RaceConditionsWhenUsingLibraryFunctions-standard.qhelp new file mode 100644 index 0000000000..458fbe3f7d --- /dev/null +++ b/c/cert/src/rules/CON33-C/RaceConditionsWhenUsingLibraryFunctions-standard.qhelp @@ -0,0 +1,33 @@ + + +
    +
      +
    • required
    • +
    • implementation
    • +
    • automated
    • +
    +
    + +
    +

    + ... +

    + +
    + +
    +

    + ... +

    +
    + + + + + +
    +
      +
    • ...
    • +
    +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/CON33-C/RaceConditionsWhenUsingLibraryFunctions.qhelp b/c/cert/src/rules/CON33-C/RaceConditionsWhenUsingLibraryFunctions.qhelp new file mode 100644 index 0000000000..e15b789b7d --- /dev/null +++ b/c/cert/src/rules/CON33-C/RaceConditionsWhenUsingLibraryFunctions.qhelp @@ -0,0 +1,18 @@ + + + + +

    This query implements the CERT-C rule CON33-C:

    +
    +

    Avoid race conditions when using library functions

    +
    +
    + + +
  • + CERT-C: + CON33-C: Avoid race conditions when using library functions + . +
  • +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/CON33-C/RaceConditionsWhenUsingLibraryFunctions.ql b/c/cert/src/rules/CON33-C/RaceConditionsWhenUsingLibraryFunctions.ql new file mode 100644 index 0000000000..ff9f0884d7 --- /dev/null +++ b/c/cert/src/rules/CON33-C/RaceConditionsWhenUsingLibraryFunctions.ql @@ -0,0 +1,28 @@ +/** + * @id c/cert/race-conditions-when-using-library-functions + * @name CON33-C: Avoid race conditions when using library functions + * @description Certain functions may cause race conditions when used from a threaded context. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/cert/id/con33-c + * correctness + * concurrency + * external/cert/obligation/rule + */ + +import cpp +import codingstandards.c.cert +import codingstandards.cpp.Concurrency + +from ThreadedCFN node +where + not isExcluded(node, Concurrency1Package::raceConditionsWhenUsingLibraryFunctionsQuery()) and + node.(FunctionCall).getTarget().getName() = + [ + "rand", "srand", "getenv", "strtok", "strerror", "asctime", "ctime", "localtime", "gmtime", + "setlocale", "atomic_init", "ATOMIC_VAR_INIT", "tmpnam", "mbrtoc16", "c16rtomb", "mbrtoc32", + "c32rtomb" + ] +select node, + "Concurrent call to non-reeantrant function $@.", node.(FunctionCall).getTarget(), node.(FunctionCall).getTarget().getName() diff --git a/c/cert/src/rules/CON33-C/standard-example.c b/c/cert/src/rules/CON33-C/standard-example.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/cert/src/rules/CON37-C/DoNotCallSignalInMultithreadedProgram-standard.qhelp b/c/cert/src/rules/CON37-C/DoNotCallSignalInMultithreadedProgram-standard.qhelp new file mode 100644 index 0000000000..458fbe3f7d --- /dev/null +++ b/c/cert/src/rules/CON37-C/DoNotCallSignalInMultithreadedProgram-standard.qhelp @@ -0,0 +1,33 @@ + + +
    +
      +
    • required
    • +
    • implementation
    • +
    • automated
    • +
    +
    + +
    +

    + ... +

    + +
    + +
    +

    + ... +

    +
    + + + + + +
    +
      +
    • ...
    • +
    +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/CON37-C/DoNotCallSignalInMultithreadedProgram.qhelp b/c/cert/src/rules/CON37-C/DoNotCallSignalInMultithreadedProgram.qhelp new file mode 100644 index 0000000000..3aa2f3347e --- /dev/null +++ b/c/cert/src/rules/CON37-C/DoNotCallSignalInMultithreadedProgram.qhelp @@ -0,0 +1,21 @@ + + + + +

    This query implements the CERT-C rule CON37-C:

    +
    +

    Do not call signal() in a multithreaded program

    +
    +
    + +
    +

    +
    + +
  • + CERT-C: + CON37-C: Do not call signal() in a multithreaded program + . +
  • +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/CON37-C/DoNotCallSignalInMultithreadedProgram.ql b/c/cert/src/rules/CON37-C/DoNotCallSignalInMultithreadedProgram.ql new file mode 100644 index 0000000000..68e0c97ea9 --- /dev/null +++ b/c/cert/src/rules/CON37-C/DoNotCallSignalInMultithreadedProgram.ql @@ -0,0 +1,28 @@ +/** + * @id c/cert/do-not-call-signal-in-multithreaded-program + * @name CON37-C: Do not call signal() in a multithreaded program + * @description Calling signal() from within a multithreaded program can result in unpredictable + * program behavior. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/cert/id/con37-c + * correctness + * concurrency + * external/cert/obligation/rule + */ + +import cpp +import codingstandards.c.cert +import codingstandards.cpp.Concurrency + +from FunctionCall fc +// This should only be applied in the context of a multi-threaded program (since +// it is valid to be used in a non-threaded program) so we filter those types of +// programs out here +where + not isExcluded(fc, Concurrency1Package::doNotCallSignalInMultithreadedProgramQuery()) and + fc.getTarget().getName() = "signal" and + exists(ThreadedFunction f) +select fc, + "Call to `signal()` in multithreaded programs." diff --git a/c/cert/src/rules/CON37-C/standard-example.c b/c/cert/src/rules/CON37-C/standard-example.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/cert/src/rules/STR34-C/CastCharBeforeConvertingToLargerSizes-standard.qhelp b/c/cert/src/rules/STR34-C/CastCharBeforeConvertingToLargerSizes-standard.qhelp new file mode 100644 index 0000000000..458fbe3f7d --- /dev/null +++ b/c/cert/src/rules/STR34-C/CastCharBeforeConvertingToLargerSizes-standard.qhelp @@ -0,0 +1,33 @@ + + +
    +
      +
    • required
    • +
    • implementation
    • +
    • automated
    • +
    +
    + +
    +

    + ... +

    + +
    + +
    +

    + ... +

    +
    + + + + + +
    +
      +
    • ...
    • +
    +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.qhelp b/c/cert/src/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.qhelp new file mode 100644 index 0000000000..13f1c41ec1 --- /dev/null +++ b/c/cert/src/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.qhelp @@ -0,0 +1,18 @@ + + + + +

    This query implements the CERT-C rule STR34-C:

    +
    +

    Cast characters to unsigned char before converting to larger integer sizes

    +
    +
    + + +
  • + CERT-C: + STR34-C: Cast characters to unsigned char before converting to larger integer sizes + . +
  • +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.ql b/c/cert/src/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.ql new file mode 100644 index 0000000000..b0d4088f9f --- /dev/null +++ b/c/cert/src/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.ql @@ -0,0 +1,31 @@ +/** + * @id c/cert/cast-char-before-converting-to-larger-sizes + * @name STR34-C: Cast characters to unsigned char before converting to larger integer sizes + * @description Not casting smaller char sizes to unsigned char before converting to lager integer + * sizes may lead to unpredictable program behavior. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/cert/id/str34-c + * correctness + * security + * external/cert/obligation/rule + */ + +import cpp +import codingstandards.c.cert +import semmle.code.cpp.commons.CommonType + +from Cast c +where + not isExcluded(c, Strings3Package::castCharBeforeConvertingToLargerSizesQuery()) and + // find cases where there is a conversion happening wherein the + // base type is a char + c.getExpr().getType() instanceof CharType and + not c.getExpr().getType() instanceof UnsignedCharType and + // it's a bigger type + c.getType().getSize() > c.getExpr().getType().getSize() and + // and it's some kind of integer type + c.getType() instanceof IntegralType +select c.getExpr(), + "Expression not converted to `unsigned char` before converting to a larger integer type." diff --git a/c/cert/src/rules/STR34-C/standard-example.c b/c/cert/src/rules/STR34-C/standard-example.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/cert/src/rules/STR38-C/DoNotConfuseNarrowAndWideFunctions-standard.qhelp b/c/cert/src/rules/STR38-C/DoNotConfuseNarrowAndWideFunctions-standard.qhelp new file mode 100644 index 0000000000..458fbe3f7d --- /dev/null +++ b/c/cert/src/rules/STR38-C/DoNotConfuseNarrowAndWideFunctions-standard.qhelp @@ -0,0 +1,33 @@ + + +
    +
      +
    • required
    • +
    • implementation
    • +
    • automated
    • +
    +
    + +
    +

    + ... +

    + +
    + +
    +

    + ... +

    +
    + + + + + +
    +
      +
    • ...
    • +
    +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/STR38-C/DoNotConfuseNarrowAndWideFunctions.qhelp b/c/cert/src/rules/STR38-C/DoNotConfuseNarrowAndWideFunctions.qhelp new file mode 100644 index 0000000000..194c2526b3 --- /dev/null +++ b/c/cert/src/rules/STR38-C/DoNotConfuseNarrowAndWideFunctions.qhelp @@ -0,0 +1,18 @@ + + + + +

    This query implements the CERT-C rule STR38-C:

    +
    +

    Do not confuse narrow and wide character strings and functions

    +
    +
    + + +
  • + CERT-C: + STR38-C: Do not confuse narrow and wide character strings and functions + . +
  • +
    +
    \ No newline at end of file diff --git a/c/cert/src/rules/STR38-C/DoNotConfuseNarrowAndWideFunctions.ql b/c/cert/src/rules/STR38-C/DoNotConfuseNarrowAndWideFunctions.ql new file mode 100644 index 0000000000..efc8889e16 --- /dev/null +++ b/c/cert/src/rules/STR38-C/DoNotConfuseNarrowAndWideFunctions.ql @@ -0,0 +1,68 @@ +/** + * @id c/cert/do-not-confuse-narrow-and-wide-functions + * @name STR38-C: Do not confuse narrow and wide character strings and functions + * @description Mixing narrow and wide character strings may cause unpredictable program behavior. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/cert/id/str38-c + * correctness + * security + * external/cert/obligation/rule + */ + +import cpp +import codingstandards.c.cert + +class NarrowCharStringType extends DerivedType { + NarrowCharStringType() { + // Use the transitive closure to include cv qualified character strings + getBaseType+() instanceof CharType + or + // Use the transitive closure to include cv qualified character strings + getBaseType+() instanceof Char8Type + } +} + +class WideCharStringType extends DerivedType { + WideCharStringType() { + // Use the transitive closure to include cv qualified character strings + getBaseType+() instanceof Char16Type + or + // Use the transitive closure to include cv qualified character strings + getBaseType+() instanceof Char32Type + or + // Use the transitive closure to include cv qualified character strings + // `wchar_t` can be a typedef so we use the class `Wchar_t` + getBaseType+() instanceof Wchar_t + } +} + +class WideToNarrowCast extends Cast { + WideToNarrowCast() { + this.getType() instanceof NarrowCharStringType and + this.getExpr().getType() instanceof WideCharStringType + } +} + +class NarrowToWideCast extends Cast { + NarrowToWideCast() { + this.getType() instanceof WideCharStringType and + this.getExpr().getType() instanceof NarrowCharStringType + } +} + +from FunctionCall call, Expr arg, Parameter p, Cast c, string actual, string expected +where + exists(int i | call.getArgument(i) = arg and call.getTarget().getParameter(i) = p) and + // Use the transitive closure to handle arrays that are converted to pointers before other type conversions. + arg.getConversion+() = c and + ( + c instanceof NarrowToWideCast and actual = "narrow" and expected = "wide" + or + c instanceof WideToNarrowCast and actual = "wide" and expected = "narrow" + ) +select call, + "Call to function $@ with a " + actual + " character string $@ where a " + expected + + " character string $@ is expected.", call.getTarget(), call.getTarget().getName(), arg, + "argument", p, "parameter" diff --git a/c/cert/src/rules/STR38-C/standard-example.c b/c/cert/src/rules/STR38-C/standard-example.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/cert/test/qlpack.yml b/c/cert/test/qlpack.yml index 4ae74b3c81..ca1c02a93f 100644 --- a/c/cert/test/qlpack.yml +++ b/c/cert/test/qlpack.yml @@ -1,4 +1,4 @@ name: cert-c-coding-standards-tests -version: 2.4.0 +version: 2.5.0 libraryPathDependencies: cert-c-coding-standards extractor: cpp \ No newline at end of file diff --git a/c/cert/test/rules/CON32-C/PreventDataRacesWithMultipleThreads.testref b/c/cert/test/rules/CON32-C/PreventDataRacesWithMultipleThreads.testref new file mode 100644 index 0000000000..d85fad08f5 --- /dev/null +++ b/c/cert/test/rules/CON32-C/PreventDataRacesWithMultipleThreads.testref @@ -0,0 +1 @@ +c/common/test/rules/guardaccesstobitfields/GuardAccessToBitFields.ql \ No newline at end of file diff --git a/c/cert/test/rules/CON33-C/RaceConditionsWhenUsingLibraryFunctions.expected b/c/cert/test/rules/CON33-C/RaceConditionsWhenUsingLibraryFunctions.expected new file mode 100644 index 0000000000..545e4dc9f2 --- /dev/null +++ b/c/cert/test/rules/CON33-C/RaceConditionsWhenUsingLibraryFunctions.expected @@ -0,0 +1,2 @@ +| test.c:11:3:11:8 | call to strtok | Concurrent call to non-reeantrant function $@. | test.c:6:7:6:12 | strtok | strtok | +| test.c:17:3:17:8 | call to strtok | Concurrent call to non-reeantrant function $@. | test.c:6:7:6:12 | strtok | strtok | diff --git a/c/cert/test/rules/CON33-C/RaceConditionsWhenUsingLibraryFunctions.qlref b/c/cert/test/rules/CON33-C/RaceConditionsWhenUsingLibraryFunctions.qlref new file mode 100644 index 0000000000..199ab06f60 --- /dev/null +++ b/c/cert/test/rules/CON33-C/RaceConditionsWhenUsingLibraryFunctions.qlref @@ -0,0 +1 @@ +rules/CON33-C/RaceConditionsWhenUsingLibraryFunctions.ql \ No newline at end of file diff --git a/c/cert/test/rules/CON33-C/test.c b/c/cert/test/rules/CON33-C/test.c new file mode 100644 index 0000000000..073dc157fb --- /dev/null +++ b/c/cert/test/rules/CON33-C/test.c @@ -0,0 +1,31 @@ +#include + +// defined in but we get absolute +// paths using the current alert so they are defined here. +// to prevent absolute paths from being generated. +char *strtok(char *__restrict, const char *__restrict); + +void f1() { + char str[] = "codeql"; + + strtok(str, 'c'); // NON_COMPLIANT +} + +int t1(void *param) { + char str[] = "codeql"; + + strtok(str, 'c'); // NON_COMPLIANT + + f1(); + + return 0; +} + +int main() { + + char str[] = "codeql"; + + strtok(str, 'c'); // COMPLIANT + thrd_t t; + thrd_create(&t, t1, NULL); +} \ No newline at end of file diff --git a/c/cert/test/rules/CON37-C/DoNotCallSignalInMultithreadedProgram.expected b/c/cert/test/rules/CON37-C/DoNotCallSignalInMultithreadedProgram.expected new file mode 100644 index 0000000000..ac56c21f7f --- /dev/null +++ b/c/cert/test/rules/CON37-C/DoNotCallSignalInMultithreadedProgram.expected @@ -0,0 +1 @@ +| test.c:8:3:8:8 | call to signal | Call to `signal()` in multithreaded programs. | diff --git a/c/cert/test/rules/CON37-C/DoNotCallSignalInMultithreadedProgram.qlref b/c/cert/test/rules/CON37-C/DoNotCallSignalInMultithreadedProgram.qlref new file mode 100644 index 0000000000..c7e3e88a9f --- /dev/null +++ b/c/cert/test/rules/CON37-C/DoNotCallSignalInMultithreadedProgram.qlref @@ -0,0 +1 @@ +rules/CON37-C/DoNotCallSignalInMultithreadedProgram.ql \ No newline at end of file diff --git a/c/cert/test/rules/CON37-C/test.c b/c/cert/test/rules/CON37-C/test.c new file mode 100644 index 0000000000..3ae45ebfec --- /dev/null +++ b/c/cert/test/rules/CON37-C/test.c @@ -0,0 +1,13 @@ +#include +#include +#include + +int f(void *param) { return 0; } + +int main(void) { + signal(SIGUSR1, NULL); // NON_COMPLIANT + thrd_t t; + thrd_create(&t, f, NULL); + + return 0; +} \ No newline at end of file diff --git a/c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.expected b/c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.expected new file mode 100644 index 0000000000..1c6424dc0c --- /dev/null +++ b/c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.expected @@ -0,0 +1,21 @@ +| test.c:7:7:7:14 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:28:11:28:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:29:3:29:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:29:11:29:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:31:11:31:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:32:11:32:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:33:3:33:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:33:11:33:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:34:3:34:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:34:11:34:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:35:3:35:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:35:11:35:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:36:3:36:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:36:11:36:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:37:11:37:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:38:11:38:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:39:3:39:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:39:11:39:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:40:12:40:13 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:42:11:42:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:43:11:43:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | diff --git a/c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.qlref b/c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.qlref new file mode 100644 index 0000000000..379d3b3f68 --- /dev/null +++ b/c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.qlref @@ -0,0 +1 @@ +rules/STR34-C/CastCharBeforeConvertingToLargerSizes.ql \ No newline at end of file diff --git a/c/cert/test/rules/STR34-C/test.c b/c/cert/test/rules/STR34-C/test.c new file mode 100644 index 0000000000..d4bd825c8e --- /dev/null +++ b/c/cert/test/rules/STR34-C/test.c @@ -0,0 +1,109 @@ +#include +#include + +int f1() { + char *c_str; + int c; + c = *c_str++; // NON_COMPLIANT + return (c); +} + +int f2() { + unsigned char *c_str; + int c; + c = *c_str++; // COMPLIANT + return (c); +} + +int f3(void) { + char *c_str; + int c; + c = (unsigned char)*c_str++; // COMPLIANT + return (c); +} + +void f4() { + char *t; + + isalnum(*t); // NON_COMPLIANT + isalpha(*t); // NON_COMPLIANT + // isascii(*t); // Not part of the C Standard + isblank(*t); // NON_COMPLIANT + iscntrl(*t); // NON_COMPLIANT + isdigit(*t); // NON_COMPLIANT + isgraph(*t); // NON_COMPLIANT + islower(*t); // NON_COMPLIANT + isprint(*t); // NON_COMPLIANT + ispunct(*t); // NON_COMPLIANT + isspace(*t); // NON_COMPLIANT + isupper(*t); // NON_COMPLIANT + isxdigit(*t); // NON_COMPLIANT + // toascii(i); // Not part of the C Standard + toupper(*t); // NON_COMPLIANT + tolower(*t); // NON_COMPLIANT +} + +void f5() { + unsigned char *t; + + isalnum(*t); // COMPLIANT + isalpha(*t); // COMPLIANT + // isascii(*t); // Not part of the C Standard + isblank(*t); // COMPLIANT + iscntrl(*t); // COMPLIANT + isdigit(*t); // COMPLIANT + isgraph(*t); // COMPLIANT + islower(*t); // COMPLIANT + isprint(*t); // COMPLIANT + ispunct(*t); // COMPLIANT + isspace(*t); // COMPLIANT + isupper(*t); // COMPLIANT + isxdigit(*t); // COMPLIANT + // toascii(i); // Not part of the C Standard + toupper(*t); // COMPLIANT + tolower(*t); // COMPLIANT +} + +void f6() { + char *t; + + isalnum((unsigned char)*t); // COMPLIANT + isalpha((unsigned char)*t); // COMPLIANT + // isascii((unsigned char*)*t); // Not part of the C Standard + isblank((unsigned char)*t); // COMPLIANT + iscntrl((unsigned char)*t); // COMPLIANT + isdigit((unsigned char)*t); // COMPLIANT + isgraph((unsigned char)*t); // COMPLIANT + islower((unsigned char)*t); // COMPLIANT + isprint((unsigned char)*t); // COMPLIANT + ispunct((unsigned char)*t); // COMPLIANT + isspace((unsigned char)*t); // COMPLIANT + isupper((unsigned char)*t); // COMPLIANT + isxdigit((unsigned char)*t); // COMPLIANT + // toascii((unsigned int) i); // Not part of the C Standard + toupper((unsigned char)*t); // COMPLIANT + tolower((unsigned char)*t); // COMPLIANT +} + +void f7() { + int t; + + // Note these are all NON_COMPLIANT under STR37-C + + isalnum(t); // COMPLIANT + isalpha(t); // COMPLIANT + // isascii(t); // Not part of the C Standard + isblank(t); // COMPLIANT + iscntrl(t); // COMPLIANT + isdigit(t); // COMPLIANT + isgraph(t); // COMPLIANT + islower(t); // COMPLIANT + isprint(t); // COMPLIANT + ispunct(t); // COMPLIANT + isspace(t); // COMPLIANT + isupper(t); // COMPLIANT + isxdigit(t); // COMPLIANT + // toascii(i); // Not part of the C Standard + toupper(t); // COMPLIANT + tolower(t); // COMPLIANT +} diff --git a/c/cert/test/rules/STR38-C/DoNotConfuseNarrowAndWideFunctions.expected b/c/cert/test/rules/STR38-C/DoNotConfuseNarrowAndWideFunctions.expected new file mode 100644 index 0000000000..f9499d3be5 --- /dev/null +++ b/c/cert/test/rules/STR38-C/DoNotConfuseNarrowAndWideFunctions.expected @@ -0,0 +1,12 @@ +| test.c:15:3:15:9 | call to strncpy | Call to function $@ with a wide character string $@ where a narrow character string $@ is expected. | test.c:6:7:6:13 | strncpy | strncpy | test.c:15:11:15:12 | w2 | argument | test.c:6:15:6:18 | (unnamed parameter 0) | parameter | +| test.c:15:3:15:9 | call to strncpy | Call to function $@ with a wide character string $@ where a narrow character string $@ is expected. | test.c:6:7:6:13 | strncpy | strncpy | test.c:15:15:15:16 | w1 | argument | test.c:6:33:6:42 | (unnamed parameter 1) | parameter | +| test.c:16:3:16:9 | call to strncpy | Call to function $@ with a wide character string $@ where a narrow character string $@ is expected. | test.c:6:7:6:13 | strncpy | strncpy | test.c:16:11:16:12 | w2 | argument | test.c:6:15:6:18 | (unnamed parameter 0) | parameter | +| test.c:26:3:26:9 | call to wcsncpy | Call to function $@ with a narrow character string $@ where a wide character string $@ is expected. | test.c:7:10:7:16 | wcsncpy | wcsncpy | test.c:26:11:26:12 | n2 | argument | test.c:7:18:7:24 | (unnamed parameter 0) | parameter | +| test.c:26:3:26:9 | call to wcsncpy | Call to function $@ with a narrow character string $@ where a wide character string $@ is expected. | test.c:7:10:7:16 | wcsncpy | wcsncpy | test.c:26:15:26:16 | n1 | argument | test.c:7:45:7:51 | (unnamed parameter 1) | parameter | +| test.c:27:3:27:9 | call to wcsncpy | Call to function $@ with a narrow character string $@ where a wide character string $@ is expected. | test.c:7:10:7:16 | wcsncpy | wcsncpy | test.c:27:15:27:16 | n1 | argument | test.c:7:45:7:51 | (unnamed parameter 1) | parameter | +| test.c:32:3:32:9 | call to strncpy | Call to function $@ with a wide character string $@ where a narrow character string $@ is expected. | test.c:6:7:6:13 | strncpy | strncpy | test.c:32:11:32:12 | w2 | argument | test.c:6:15:6:18 | (unnamed parameter 0) | parameter | +| test.c:32:3:32:9 | call to strncpy | Call to function $@ with a wide character string $@ where a narrow character string $@ is expected. | test.c:6:7:6:13 | strncpy | strncpy | test.c:32:15:32:16 | w1 | argument | test.c:6:33:6:42 | (unnamed parameter 1) | parameter | +| test.c:33:3:33:9 | call to strncpy | Call to function $@ with a wide character string $@ where a narrow character string $@ is expected. | test.c:6:7:6:13 | strncpy | strncpy | test.c:33:11:33:12 | w2 | argument | test.c:6:15:6:18 | (unnamed parameter 0) | parameter | +| test.c:36:3:36:9 | call to wcsncpy | Call to function $@ with a narrow character string $@ where a wide character string $@ is expected. | test.c:7:10:7:16 | wcsncpy | wcsncpy | test.c:36:11:36:12 | n2 | argument | test.c:7:18:7:24 | (unnamed parameter 0) | parameter | +| test.c:36:3:36:9 | call to wcsncpy | Call to function $@ with a narrow character string $@ where a wide character string $@ is expected. | test.c:7:10:7:16 | wcsncpy | wcsncpy | test.c:36:15:36:16 | n1 | argument | test.c:7:45:7:51 | (unnamed parameter 1) | parameter | +| test.c:37:3:37:9 | call to wcsncpy | Call to function $@ with a narrow character string $@ where a wide character string $@ is expected. | test.c:7:10:7:16 | wcsncpy | wcsncpy | test.c:37:15:37:16 | n1 | argument | test.c:7:45:7:51 | (unnamed parameter 1) | parameter | diff --git a/c/cert/test/rules/STR38-C/DoNotConfuseNarrowAndWideFunctions.qlref b/c/cert/test/rules/STR38-C/DoNotConfuseNarrowAndWideFunctions.qlref new file mode 100644 index 0000000000..0312561ed4 --- /dev/null +++ b/c/cert/test/rules/STR38-C/DoNotConfuseNarrowAndWideFunctions.qlref @@ -0,0 +1 @@ +rules/STR38-C/DoNotConfuseNarrowAndWideFunctions.ql \ No newline at end of file diff --git a/c/cert/test/rules/STR38-C/test.c b/c/cert/test/rules/STR38-C/test.c new file mode 100644 index 0000000000..e4464a6d71 --- /dev/null +++ b/c/cert/test/rules/STR38-C/test.c @@ -0,0 +1,39 @@ +#include + +// defined in and but we get absolute +// paths using the current alert so they are defined here. +// to prevent absolute paths from being generated. +char *strncpy(char *__restrict, const char *__restrict, size_t); +wchar_t *wcsncpy(wchar_t *__restrict, const wchar_t *__restrict, size_t); + +void f1() { + wchar_t w1[] = L"codeql"; + wchar_t w2[] = L"codeql"; + char n1[] = "codeql"; + char n2[] = "codeql"; + + strncpy(w2, w1, 1); // NON_COMPLIANT (2x) + strncpy(w2, n1, 1); // NON_COMPLIANT (1x) + strncpy(n2, n1, 1); // COMPLIANT +} + +void f2() { + wchar_t w1[] = L"codeql"; + wchar_t w2[] = L"codeql"; + char n1[] = "codeql"; + char n2[] = "codeql"; + + wcsncpy(n2, n1, 1); // NON_COMPLIANT (2x) + wcsncpy(w2, n1, 1); // NON_COMPLIANT (1x) + wcsncpy(w2, w1, 1); // COMPLIANT +} + +void f3(wchar_t *w1, wchar_t *w2, char *n1, char *n2) { + strncpy(w2, w1, 1); // NON_COMPLIANT (2x) + strncpy(w2, n1, 1); // NON_COMPLIANT (1x) + strncpy(n2, n1, 1); // COMPLIANT + + wcsncpy(n2, n1, 1); // NON_COMPLIANT (2x) + wcsncpy(w2, n1, 1); // NON_COMPLIANT (1x) + wcsncpy(w2, w1, 1); // COMPLIANT +} \ No newline at end of file diff --git a/c/common/src/codingstandards/c/Pointers.qll b/c/common/src/codingstandards/c/Pointers.qll new file mode 100644 index 0000000000..87ade425e1 --- /dev/null +++ b/c/common/src/codingstandards/c/Pointers.qll @@ -0,0 +1,38 @@ +/** + * A module for representing pointers + */ + +import cpp +import codingstandards.cpp.Type + +/** + * A null pointer constant, which is either in the form `NULL` or `(void *)0`. + */ +predicate isNullPointerConstant(Expr e) { + e.findRootCause() instanceof NULLMacro + or + exists(CStyleCast c | + not c.isImplicit() and + c.getExpr() = e and + e instanceof Zero and + c.getType() instanceof VoidPointerType + ) +} + +predicate isCastNullPointerConstant(Cast c) { + isNullPointerConstant(c.getExpr()) and + c.getUnderlyingType() instanceof PointerType +} + +/** + * A type representing a pointer to object + */ +class PointerToObjectType extends PointerType { + PointerToObjectType() { + not ( + this.getUnderlyingType() instanceof FunctionPointerType or + this.getUnderlyingType() instanceof VoidPointerType or + this.getBaseType().getUnderlyingType() instanceof IncompleteType + ) + } +} diff --git a/c/common/src/qlpack.yml b/c/common/src/qlpack.yml index 586aa97554..8a350ed757 100644 --- a/c/common/src/qlpack.yml +++ b/c/common/src/qlpack.yml @@ -1,3 +1,3 @@ name: common-c-coding-standards -version: 2.4.0 +version: 2.5.0 libraryPathDependencies: common-cpp-coding-standards diff --git a/c/common/test/qlpack.yml b/c/common/test/qlpack.yml index 123450b5ec..39adb5dad3 100644 --- a/c/common/test/qlpack.yml +++ b/c/common/test/qlpack.yml @@ -1,4 +1,4 @@ name: common-c-coding-standards-tests -version: 2.4.0 +version: 2.5.0 libraryPathDependencies: common-c-coding-standards extractor: cpp diff --git a/c/common/test/rules/donotcopyaddressofautostorageobjecttootherobject/DoNotCopyAddressOfAutoStorageObjectToOtherObject.expected b/c/common/test/rules/donotcopyaddressofautostorageobjecttootherobject/DoNotCopyAddressOfAutoStorageObjectToOtherObject.expected new file mode 100644 index 0000000000..35d825b16e --- /dev/null +++ b/c/common/test/rules/donotcopyaddressofautostorageobjecttootherobject/DoNotCopyAddressOfAutoStorageObjectToOtherObject.expected @@ -0,0 +1 @@ +| test.c:7:5:7:10 | ... = ... | A stack address ($@) may be assigned to a non-local variable. | test.c:7:10:7:10 | c | source | diff --git a/c/common/test/rules/donotcopyaddressofautostorageobjecttootherobject/DoNotCopyAddressOfAutoStorageObjectToOtherObject.ql b/c/common/test/rules/donotcopyaddressofautostorageobjecttootherobject/DoNotCopyAddressOfAutoStorageObjectToOtherObject.ql new file mode 100644 index 0000000000..9f0c40ef4c --- /dev/null +++ b/c/common/test/rules/donotcopyaddressofautostorageobjecttootherobject/DoNotCopyAddressOfAutoStorageObjectToOtherObject.ql @@ -0,0 +1,2 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.donotcopyaddressofautostorageobjecttootherobject.DoNotCopyAddressOfAutoStorageObjectToOtherObject diff --git a/cpp/autosar/test/rules/M7-5-2/test.cpp b/c/common/test/rules/donotcopyaddressofautostorageobjecttootherobject/test.c similarity index 100% rename from cpp/autosar/test/rules/M7-5-2/test.cpp rename to c/common/test/rules/donotcopyaddressofautostorageobjecttootherobject/test.c diff --git a/c/common/test/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.expected b/c/common/test/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.expected new file mode 100644 index 0000000000..0011556fd0 --- /dev/null +++ b/c/common/test/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.expected @@ -0,0 +1,26 @@ +problems +| test.c:12:10:12:11 | p1 | test.c:4:14:4:15 | l1 | test.c:12:10:12:11 | p1 | Subtraction between left 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 | +| test.c:12:15:12:16 | p2 | test.c:5:14:5:15 | l2 | test.c:12:15:12:16 | p2 | Subtraction between right 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: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 | +nodes +| test.c:4:14:4:15 | l1 | semmle.label | l1 | +| test.c:5:14:5:15 | l2 | semmle.label | l2 | +| 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 | +| test.c:11:15:11:16 | l2 | semmle.label | l2 | +| test.c:12:10:12:11 | p1 | semmle.label | p1 | +| test.c:12:15:12:16 | p2 | semmle.label | p2 | +| test.c:13:10:13:11 | p4 | semmle.label | p4 | +| test.c:13:15:13:16 | l1 | semmle.label | l1 | +| test.c:14:10:14:11 | p4 | semmle.label | p4 | +| test.c:14:15:14:16 | l2 | semmle.label | l2 | +subpaths diff --git a/c/common/test/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.ql b/c/common/test/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.ql new file mode 100644 index 0000000000..bf47bf28f1 --- /dev/null +++ b/c/common/test/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.ql @@ -0,0 +1,2 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.donotsubtractpointersaddressingdifferentarrays.DoNotSubtractPointersAddressingDifferentArrays diff --git a/cpp/autosar/test/rules/M5-0-17/test.cpp b/c/common/test/rules/donotsubtractpointersaddressingdifferentarrays/test.c similarity index 100% rename from cpp/autosar/test/rules/M5-0-17/test.cpp rename to c/common/test/rules/donotsubtractpointersaddressingdifferentarrays/test.c diff --git a/c/common/test/rules/donotusemorethantwolevelsofpointerindirection/DoNotUseMoreThanTwoLevelsOfPointerIndirection.expected b/c/common/test/rules/donotusemorethantwolevelsofpointerindirection/DoNotUseMoreThanTwoLevelsOfPointerIndirection.expected new file mode 100644 index 0000000000..5d97707d54 --- /dev/null +++ b/c/common/test/rules/donotusemorethantwolevelsofpointerindirection/DoNotUseMoreThanTwoLevelsOfPointerIndirection.expected @@ -0,0 +1,5 @@ +| test.c:7:14:7:14 | d | The declaration of d contain more than two levels of pointer indirection. | +| test.c:13:8:13:9 | s4 | The declaration of s4 contain more than two levels of pointer indirection. | +| test.c:17:16:17:17 | p3 | The declaration of p3 contain more than two levels of pointer indirection. | +| test.c:18:28:18:31 | par5 | The declaration of par5 contain more than two levels of pointer indirection. | +| test.c:20:15:20:18 | par7 | The declaration of par7 contain more than two levels of pointer indirection. | diff --git a/c/common/test/rules/donotusemorethantwolevelsofpointerindirection/DoNotUseMoreThanTwoLevelsOfPointerIndirection.ql b/c/common/test/rules/donotusemorethantwolevelsofpointerindirection/DoNotUseMoreThanTwoLevelsOfPointerIndirection.ql new file mode 100644 index 0000000000..6fdfb9c928 --- /dev/null +++ b/c/common/test/rules/donotusemorethantwolevelsofpointerindirection/DoNotUseMoreThanTwoLevelsOfPointerIndirection.ql @@ -0,0 +1,2 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.donotusemorethantwolevelsofpointerindirection.DoNotUseMoreThanTwoLevelsOfPointerIndirection diff --git a/c/common/test/rules/donotusemorethantwolevelsofpointerindirection/test.c b/c/common/test/rules/donotusemorethantwolevelsofpointerindirection/test.c new file mode 100644 index 0000000000..0c305a743d --- /dev/null +++ b/c/common/test/rules/donotusemorethantwolevelsofpointerindirection/test.c @@ -0,0 +1,21 @@ +typedef int *intptr_t; + +typedef struct S { + int *a; // COMPLIANT + intptr_t b; // COMPLIANT + intptr_t *c; // COMPLIANT + intptr_t **d // NON_COMPLIANT +} S_t; + +S_t s1; // COMPLIANT +S_t *s2; // COMPLIANT +S_t **s3; // COMPLIANT +S_t ***s4; // NON_COMPLIANT + +void f1(int *p1, // COMPLIANT + int **p2, // COMPLIANT + int ***p3, // NON_COMPLIANT + int **const *const par5, // NON_COMPLIANT + int *par6[], // COMPLIANT + int **par7[] // NON_COMPLIANT +); \ No newline at end of file diff --git a/c/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.expected b/c/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.expected new file mode 100644 index 0000000000..1d487765df --- /dev/null +++ b/c/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.expected @@ -0,0 +1,5 @@ +| test.c:4:13:4:18 | ... + ... | Array pointer p2 points 1 element passed the end of $@. | test.c:2:7:2:8 | l1 | l1 | +| test.c:5:13:5:18 | ... + ... | Array pointer p3 points 1 element passed the end of $@. | test.c:2:7:2:8 | l1 | l1 | +| test.c:6:13:6:18 | & ... | Array pointer p4 points 1 element passed the end of $@. | test.c:2:7:2:8 | l1 | l1 | +| test.c:11:8:11:11 | ... -- | Array pointer p7 points 1 element passed the end of $@. | test.c:2:7:2:8 | l1 | l1 | +| test.c:12:8:12:9 | p3 | Array pointer p8 points 1 element passed the end of $@. | test.c:2:7:2:8 | l1 | l1 | diff --git a/c/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.ql b/c/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.ql new file mode 100644 index 0000000000..b06daa52b7 --- /dev/null +++ b/c/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.ql @@ -0,0 +1,2 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.donotusepointerarithmetictoaddressdifferentarrays.DoNotUsePointerArithmeticToAddressDifferentArrays diff --git a/cpp/autosar/test/rules/M5-0-16/test.cpp b/c/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/test.c similarity index 100% rename from cpp/autosar/test/rules/M5-0-16/test.cpp rename to c/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/test.c diff --git a/c/common/test/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.expected b/c/common/test/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.expected new file mode 100644 index 0000000000..5431867345 --- /dev/null +++ b/c/common/test/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.expected @@ -0,0 +1,44 @@ +problems +| test.c:17:7:17:13 | ... < ... | test.c:7:14:7:15 | l1 | test.c:17:7:17:8 | p1 | Compare operation < comparing left 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 | +| test.c:17:7:17:13 | ... < ... | test.c:17:12:17:13 | l2 | test.c:17:12:17:13 | l2 | Compare operation < comparing right 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:19:7:19:13 | ... < ... | test.c:19:7:19:8 | l1 | test.c:19:7:19:8 | l1 | Compare operation < comparing left 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 | +| test.c:19:7:19:13 | ... < ... | test.c:19:12:19:13 | l2 | test.c:19:12:19:13 | l2 | Compare operation < comparing right 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:21:7:21:13 | ... < ... | test.c:8:14:8:15 | l1 | test.c:21:7:21:8 | p2 | Compare operation < comparing left 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 | +| test.c:21:7:21:13 | ... < ... | test.c:9:14:9:15 | l2 | test.c:21:12:21:13 | p3 | Compare operation < comparing right 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:23:7:23:14 | ... <= ... | test.c:7:14:7:15 | l1 | test.c:23:13:23:14 | p1 | Compare operation <= comparing 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 | +| test.c:23:7:23:14 | ... <= ... | test.c:23:7:23:8 | l2 | test.c:23:7:23:8 | l2 | Compare operation <= comparing 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:25:7:25:14 | ... >= ... | test.c:7:14:7:15 | l1 | test.c:25:7:25:8 | p1 | Compare operation >= comparing left operand pointing to array $@ and other operand pointing to array $@. | test.c:2:7:2:8 | l1 | l1 | test.c:4:7:4:8 | l3 | l3 | +| 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 | +nodes +| test.c:6:13:6:14 | l1 | semmle.label | l1 | +| test.c:7:14:7:15 | l1 | semmle.label | l1 | +| test.c:8:14:8:15 | l1 | semmle.label | l1 | +| test.c:9:14:9:15 | l2 | semmle.label | l2 | +| 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 | +| test.c:13:12:13:13 | p0 | semmle.label | p0 | +| test.c:15:7:15:8 | l1 | semmle.label | l1 | +| test.c:15:13:15:14 | p1 | semmle.label | p1 | +| test.c:17:7:17:8 | p1 | semmle.label | p1 | +| test.c:17:12:17:13 | l2 | semmle.label | l2 | +| test.c:19:7:19:8 | l1 | semmle.label | l1 | +| test.c:19:12:19:13 | l2 | semmle.label | l2 | +| test.c:21:7:21:8 | p2 | semmle.label | p2 | +| test.c:21:12:21:13 | p3 | semmle.label | p3 | +| test.c:23:7:23:8 | l2 | semmle.label | l2 | +| test.c:23:13:23:14 | p1 | semmle.label | p1 | +| test.c:25:7:25:8 | p1 | semmle.label | p1 | +| test.c:25:13:25:14 | l3 | semmle.label | l3 | +subpaths diff --git a/c/common/test/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.ql b/c/common/test/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.ql new file mode 100644 index 0000000000..c6cca37aa2 --- /dev/null +++ b/c/common/test/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.ql @@ -0,0 +1,2 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.donotuserelationaloperatorswithdifferingarrays.DoNotUseRelationalOperatorsWithDifferingArrays diff --git a/cpp/autosar/test/rules/M5-0-18/test.cpp b/c/common/test/rules/donotuserelationaloperatorswithdifferingarrays/test.c similarity index 100% rename from cpp/autosar/test/rules/M5-0-18/test.cpp rename to c/common/test/rules/donotuserelationaloperatorswithdifferingarrays/test.c diff --git a/c/common/test/rules/guardaccesstobitfields/GuardAccessToBitFields.expected b/c/common/test/rules/guardaccesstobitfields/GuardAccessToBitFields.expected new file mode 100644 index 0000000000..205cfd5143 --- /dev/null +++ b/c/common/test/rules/guardaccesstobitfields/GuardAccessToBitFields.expected @@ -0,0 +1,3 @@ +| test.c:11:9:11:13 | flag1 | Access to a bit-field without a concurrency guard. | +| test.c:16:9:16:13 | flag2 | Access to a bit-field without a concurrency guard. | +| test.c:47:12:47:16 | flag2 | Access to a bit-field without a concurrency guard. | diff --git a/c/common/test/rules/guardaccesstobitfields/GuardAccessToBitFields.ql b/c/common/test/rules/guardaccesstobitfields/GuardAccessToBitFields.ql new file mode 100644 index 0000000000..693dae8f57 --- /dev/null +++ b/c/common/test/rules/guardaccesstobitfields/GuardAccessToBitFields.ql @@ -0,0 +1,2 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.guardaccesstobitfields.GuardAccessToBitFields diff --git a/c/common/test/rules/guardaccesstobitfields/test.c b/c/common/test/rules/guardaccesstobitfields/test.c new file mode 100644 index 0000000000..9f3a443e6e --- /dev/null +++ b/c/common/test/rules/guardaccesstobitfields/test.c @@ -0,0 +1,69 @@ +#include + +struct BitFieldStruct { + unsigned int flag1 : 2; + unsigned int flag2 : 2; +}; + +struct BitFieldStruct flags; + +int f1(void *arg) { + flags.flag1 = 1; // NON_COMPLIANT + return 0; +} + +int f2(void *arg) { + flags.flag2 = 2; // NON_COMPLIANT + return 0; +} + +struct MutexStruct { + struct BitFieldStruct s; + mtx_t mutex; +}; + +struct MutexStruct flags2; + +int f3(void *arg) { + if (thrd_success != mtx_lock(&flags2.mutex)) { + return 0; + } + flags2.s.flag1 = 1; // COMPLIANT + return 0; +} + +int f4(void *arg) { + if (thrd_success != mtx_lock(&flags2.mutex)) { + return 0; + } + flags2.s.flag2 = 2; // COMPLIANT + mtx_unlock(&flags2.mutex); + return 0; +} + +int f5(void *arg) { + mtx_lock(&flags2.mutex); + mtx_unlock(&flags2.mutex); + flags2.s.flag2 = 2; // NON_COMPLIANT + + return 0; +} + +int f6(void *arg) { + mtx_lock(&flags2.mutex); + mtx_unlock(&flags2.mutex); + mtx_lock(&flags2.mutex); + flags2.s.flag2 = 2; // COMPLIANT + + return 0; +} + +void m() { + + thrd_create(NULL, (thrd_start_t)f1, NULL); + thrd_create(NULL, (thrd_start_t)f2, NULL); + thrd_create(NULL, (thrd_start_t)f3, NULL); + thrd_create(NULL, (thrd_start_t)f4, NULL); + thrd_create(NULL, (thrd_start_t)f5, NULL); + thrd_create(NULL, (thrd_start_t)f6, NULL); +} \ No newline at end of file diff --git a/c/common/test/rules/useonlyarrayindexingforpointerarithmetic/UseOnlyArrayIndexingForPointerArithmetic.expected b/c/common/test/rules/useonlyarrayindexingforpointerarithmetic/UseOnlyArrayIndexingForPointerArithmetic.expected new file mode 100644 index 0000000000..9bdc5e261d --- /dev/null +++ b/c/common/test/rules/useonlyarrayindexingforpointerarithmetic/UseOnlyArrayIndexingForPointerArithmetic.expected @@ -0,0 +1,4 @@ +| test.c:11:8:11:13 | ... + ... | Use of pointer arithmetic other than array indexing or indexing pointer not declared as an array. | +| test.c:12:3:12:7 | access to array | Use of pointer arithmetic other than array indexing or indexing pointer not declared as an array. | +| test.c:13:9:13:13 | access to array | Use of pointer arithmetic other than array indexing or indexing pointer not declared as an array. | +| test.c:17:5:17:10 | ... + ... | Use of pointer arithmetic other than array indexing or indexing pointer not declared as an array. | diff --git a/c/common/test/rules/useonlyarrayindexingforpointerarithmetic/UseOnlyArrayIndexingForPointerArithmetic.ql b/c/common/test/rules/useonlyarrayindexingforpointerarithmetic/UseOnlyArrayIndexingForPointerArithmetic.ql new file mode 100644 index 0000000000..819d12c4e8 --- /dev/null +++ b/c/common/test/rules/useonlyarrayindexingforpointerarithmetic/UseOnlyArrayIndexingForPointerArithmetic.ql @@ -0,0 +1,2 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.useonlyarrayindexingforpointerarithmetic.UseOnlyArrayIndexingForPointerArithmetic diff --git a/c/common/test/rules/useonlyarrayindexingforpointerarithmetic/test.c b/c/common/test/rules/useonlyarrayindexingforpointerarithmetic/test.c new file mode 100644 index 0000000000..3fd62bfae7 --- /dev/null +++ b/c/common/test/rules/useonlyarrayindexingforpointerarithmetic/test.c @@ -0,0 +1,23 @@ +struct S { + int m[3]; +}; + +void f(int p1[], struct S *p2) { + int l1 = 0; + int *l2; + int l3[10]; + int *l4; + + l2 = l2 + 1; // NON_COMPLIANT + l2[0] = 0; // NON_COMPLIANT - l2 is not declared as array + l4 = &l2[0]; // NON_COMPLIANT - l2 is not declared as array + l3[l1] = 0; // COMPLIANT + l4 = &l3[1]; // COMPLIANT + l4 = l3; + *(l4 + 1) = 0; // NON_COMPLIANT + l1 = l4[0]; // COMPLIANT + l1 = p1[0]; // COMPLIANT + + int *l5 = p2->m; + l1 = l5[0]; // COMPLIANT +} diff --git a/c/misra/src/qlpack.yml b/c/misra/src/qlpack.yml index 01973953c8..3f2b21007a 100644 --- a/c/misra/src/qlpack.yml +++ b/c/misra/src/qlpack.yml @@ -1,4 +1,4 @@ name: misra-c-coding-standards -version: 2.4.0 +version: 2.5.0 suites: codeql-suites libraryPathDependencies: common-c-coding-standards diff --git a/c/misra/src/rules/RULE-11-1/ConversionBetweenFunctionPointerAndOtherType.ql b/c/misra/src/rules/RULE-11-1/ConversionBetweenFunctionPointerAndOtherType.ql new file mode 100644 index 0000000000..9825eae3f9 --- /dev/null +++ b/c/misra/src/rules/RULE-11-1/ConversionBetweenFunctionPointerAndOtherType.ql @@ -0,0 +1,35 @@ +/** + * @id c/misra/conversion-between-function-pointer-and-other-type + * @name RULE-11-1: Conversions shall not be performed between a pointer to a function and any other type + * @description Converting between a function pointer into an incompatible type results in undefined + * behaviour. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-11-1 + * correctness + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.Pointers + +from CStyleCast cast, Type type, Type newType +where + not isExcluded(cast, Pointers1Package::conversionBetweenFunctionPointerAndOtherTypeQuery()) and + type = cast.getExpr().getUnderlyingType() and + newType = cast.getUnderlyingType() and + [type, newType] instanceof FunctionPointerType and + type != newType and + // exception 1 (null pointer constant) + not isNullPointerConstant(cast.getExpr()) and + // exception 2 (conversion to void) + not newType instanceof VoidType and + // exception 3 (implicit conversion of function to function pointer) + not ( + cast.isImplicit() and + newType instanceof FunctionPointerType and + cast.getExpr() instanceof FunctionAccess + ) +select cast, "Cast performed between a function pointer and another type." diff --git a/c/misra/src/rules/RULE-11-1/standard-example.c b/c/misra/src/rules/RULE-11-1/standard-example.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/misra/src/rules/RULE-11-2/ConversionBetweenIncompleteTypePointerAndOtherType.ql b/c/misra/src/rules/RULE-11-2/ConversionBetweenIncompleteTypePointerAndOtherType.ql new file mode 100644 index 0000000000..007b43963b --- /dev/null +++ b/c/misra/src/rules/RULE-11-2/ConversionBetweenIncompleteTypePointerAndOtherType.ql @@ -0,0 +1,34 @@ +/** + * @id c/misra/conversion-between-incomplete-type-pointer-and-other-type + * @name RULE-11-2: Conversions shall not be performed between a pointer to an incomplete type and any other type + * @description Converting between a pointer to an incomplete type to another type can result in + * undefined behaviour or violate encapsulation. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-11-2 + * correctness + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.Pointers +import codingstandards.cpp.Type + +from Cast cast, Type type, Type newType +where + not isExcluded(cast, Pointers1Package::conversionBetweenIncompleteTypePointerAndOtherTypeQuery()) and + cast.getExpr().getUnderlyingType() = type and + cast.getType().getUnderlyingType() = newType and + type != newType and + // exception: conversion to void type + not newType instanceof VoidType and + // exception: conversion from null pointer constant + not isCastNullPointerConstant(cast) and + // verify that at least one of the types are incomplete + ( + type.(PointerType).getBaseType() instanceof IncompleteType or + newType.(PointerType).getBaseType() instanceof IncompleteType + ) +select cast, "Cast performed between a pointer to incomplete type and another type." diff --git a/c/misra/src/rules/RULE-11-2/standard-example.c b/c/misra/src/rules/RULE-11-2/standard-example.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/misra/src/rules/RULE-11-3/CastBetweenObjectPointerAndDifferentObjectType.ql b/c/misra/src/rules/RULE-11-3/CastBetweenObjectPointerAndDifferentObjectType.ql new file mode 100644 index 0000000000..ede0a2834e --- /dev/null +++ b/c/misra/src/rules/RULE-11-3/CastBetweenObjectPointerAndDifferentObjectType.ql @@ -0,0 +1,37 @@ +/** + * @id c/misra/cast-between-object-pointer-and-different-object-type + * @name RULE-11-3: A cast shall not be performed between a pointer to object type and a pointer to a different object + * @description Casting between an object pointer and a pointer to a different object type can + * result in a pointer that is incorrectly aligned or that results in undefined + * behaviour if accessed. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-11-3 + * correctness + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.Pointers + +from CStyleCast cast, Type baseTypeFrom, Type baseTypeTo +where + not isExcluded(cast, Pointers1Package::castBetweenObjectPointerAndDifferentObjectTypeQuery()) and + baseTypeFrom = cast.getExpr().getType().(PointerToObjectType).getBaseType() and + baseTypeTo = cast.getType().(PointerToObjectType).getBaseType() and + // exception: cast to a char, signed char, or unsigned char is permitted + not baseTypeTo.stripType() instanceof CharType and + ( + ( + baseTypeFrom.isVolatile() and not baseTypeTo.isVolatile() + or + baseTypeFrom.isConst() and not baseTypeTo.isConst() + ) + or + baseTypeFrom.stripType() != baseTypeTo.stripType() + ) +select cast, + "Cast performed between a pointer to object type (" + baseTypeFrom.getName() + + ") and a pointer to a different object type (" + baseTypeTo.getName() + ")." diff --git a/c/misra/src/rules/RULE-11-3/standard-example.c b/c/misra/src/rules/RULE-11-3/standard-example.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/misra/src/rules/RULE-11-4/ConversionBetweenPointerToObjectAndIntegerType.ql b/c/misra/src/rules/RULE-11-4/ConversionBetweenPointerToObjectAndIntegerType.ql new file mode 100644 index 0000000000..4071cf63b5 --- /dev/null +++ b/c/misra/src/rules/RULE-11-4/ConversionBetweenPointerToObjectAndIntegerType.ql @@ -0,0 +1,27 @@ +/** + * @id c/misra/conversion-between-pointer-to-object-and-integer-type + * @name RULE-11-4: A conversion should not be performed between a pointer to object and an integer type + * @description Converting between a pointer to an object and an integer type may result in + * undefined behaviour. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-11-4 + * correctness + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.Pointers + +from CStyleCast cast, Type typeFrom, Type typeTo +where + not isExcluded(cast, Pointers1Package::castBetweenObjectPointerAndDifferentObjectTypeQuery()) and + typeFrom = cast.getExpr().getUnderlyingType() and + typeTo = cast.getUnderlyingType() and + [typeFrom, typeTo] instanceof IntegralType and + [typeFrom, typeTo] instanceof PointerToObjectType and + not isNullPointerConstant(cast.getExpr()) +select cast, + "Cast performed between a pointer to object type and a pointer to an integer type." diff --git a/c/misra/src/rules/RULE-11-4/standard-example.c b/c/misra/src/rules/RULE-11-4/standard-example.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/misra/src/rules/RULE-11-5/ConversionFromPointerToVoidIntoPointerToObject.ql b/c/misra/src/rules/RULE-11-5/ConversionFromPointerToVoidIntoPointerToObject.ql new file mode 100644 index 0000000000..3450f1ae90 --- /dev/null +++ b/c/misra/src/rules/RULE-11-5/ConversionFromPointerToVoidIntoPointerToObject.ql @@ -0,0 +1,25 @@ +/** + * @id c/misra/conversion-from-pointer-to-void-into-pointer-to-object + * @name RULE-11-5: A conversion should not be performed from pointer to void into pointer to object + * @description Converting from a pointer to void into a pointer to an object may result in an + * incorrectly aligned pointer and undefined behaviour. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-11-5 + * correctness + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.Pointers + +from Cast cast, VoidPointerType type, PointerToObjectType newType +where + not isExcluded(cast, Pointers1Package::conversionFromPointerToVoidIntoPointerToObjectQuery()) and + type = cast.getExpr().getUnderlyingType() and + newType = cast.getUnderlyingType() and + not isNullPointerConstant(cast.getExpr()) +select cast, + "Cast performed from a void pointer into a pointer to an object (" + newType.getName() + ")." diff --git a/c/misra/src/rules/RULE-11-5/standard-example.c b/c/misra/src/rules/RULE-11-5/standard-example.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/misra/src/rules/RULE-11-6/CastBetweenPointerToVoidAndArithmeticType.ql b/c/misra/src/rules/RULE-11-6/CastBetweenPointerToVoidAndArithmeticType.ql new file mode 100644 index 0000000000..b36d8dafb1 --- /dev/null +++ b/c/misra/src/rules/RULE-11-6/CastBetweenPointerToVoidAndArithmeticType.ql @@ -0,0 +1,26 @@ +/** + * @id c/misra/cast-between-pointer-to-void-and-arithmetic-type + * @name RULE-11-6: A cast shall not be performed between pointer to void and an arithmetic type + * @description Converting from an integer into a pointer to void may result in an incorrectly + * aligned pointer and undefined behaviour. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-11-6 + * correctness + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.Pointers + +from CStyleCast cast, Type typeFrom, Type typeTo +where + not isExcluded(cast, Pointers1Package::castBetweenPointerToVoidAndArithmeticTypeQuery()) and + typeFrom = cast.getExpr().getUnderlyingType() and + typeTo = cast.getUnderlyingType() and + [typeFrom, typeTo] instanceof ArithmeticType and + [typeFrom, typeTo] instanceof VoidPointerType and + not isNullPointerConstant(cast.getExpr()) +select cast, "Cast performed between a pointer to void type and an arithmetic type." diff --git a/c/misra/src/rules/RULE-11-6/standard-example.c b/c/misra/src/rules/RULE-11-6/standard-example.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/misra/src/rules/RULE-11-7/CastBetweenPointerToObjectAndNonIntArithmeticType.ql b/c/misra/src/rules/RULE-11-7/CastBetweenPointerToObjectAndNonIntArithmeticType.ql new file mode 100644 index 0000000000..2aa49ae2a0 --- /dev/null +++ b/c/misra/src/rules/RULE-11-7/CastBetweenPointerToObjectAndNonIntArithmeticType.ql @@ -0,0 +1,35 @@ +/** + * @id c/misra/cast-between-pointer-to-object-and-non-int-arithmetic-type + * @name RULE-11-7: A cast shall not be performed between pointer to object and a non-integer arithmetic type + * @description Converting between a pointer to an object and a pointer to a non-integer arithmetic + * type can result in undefined behaviour. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-11-7 + * correctness + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.Pointers + +class MisraNonIntegerArithmeticType extends Type { + MisraNonIntegerArithmeticType() { + this instanceof BoolType or + this instanceof CharType or + this instanceof Enum or + this instanceof FloatingPointType + } +} + +from CStyleCast cast, Type typeFrom, Type typeTo +where + not isExcluded(cast, Pointers1Package::castBetweenPointerToObjectAndNonIntArithmeticTypeQuery()) and + typeFrom = cast.getExpr().getUnderlyingType() and + typeTo = cast.getUnderlyingType() and + [typeFrom, typeTo] instanceof MisraNonIntegerArithmeticType and + [typeFrom, typeTo] instanceof PointerToObjectType +select cast, + "Cast performed between a pointer to void type and a non-integer arithmetic type." \ No newline at end of file diff --git a/c/misra/src/rules/RULE-11-7/standard-example.c b/c/misra/src/rules/RULE-11-7/standard-example.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/misra/src/rules/RULE-11-8/CastRemovesConstOrVolatileQualification.ql b/c/misra/src/rules/RULE-11-8/CastRemovesConstOrVolatileQualification.ql new file mode 100644 index 0000000000..17b0df1a0e --- /dev/null +++ b/c/misra/src/rules/RULE-11-8/CastRemovesConstOrVolatileQualification.ql @@ -0,0 +1,27 @@ +/** + * @id c/misra/cast-removes-const-or-volatile-qualification + * @name RULE-11-8: A cast shall not remove any const or volatile qualification from the type pointed to by a pointer + * @description Casting away const or volatile qualifications violates the principle of type + * qualification and can result in unpredictable behaviour. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-11-8 + * correctness + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra + +from Cast cast, Type baseTypeFrom, Type baseTypeTo, string qualificationName +where + not isExcluded(cast, Pointers1Package::castRemovesConstOrVolatileQualificationQuery()) and + baseTypeFrom = cast.getExpr().getType().(PointerType).getBaseType() and + baseTypeTo = cast.getType().(PointerType).getBaseType() and + ( + baseTypeFrom.isVolatile() and not baseTypeTo.isVolatile() and qualificationName = "volatile" + or + baseTypeFrom.isConst() and not baseTypeTo.isConst() and qualificationName = "const" + ) +select cast, "Cast of pointer removes " + qualificationName + " qualification from its base type." diff --git a/c/misra/src/rules/RULE-11-8/standard-example.c b/c/misra/src/rules/RULE-11-8/standard-example.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/misra/src/rules/RULE-11-9/MacroNullNotUsedAsIntegerNullPointerConstant.ql b/c/misra/src/rules/RULE-11-9/MacroNullNotUsedAsIntegerNullPointerConstant.ql new file mode 100644 index 0000000000..844229de2f --- /dev/null +++ b/c/misra/src/rules/RULE-11-9/MacroNullNotUsedAsIntegerNullPointerConstant.ql @@ -0,0 +1,54 @@ +/** + * @id c/misra/macro-null-not-used-as-integer-null-pointer-constant + * @name RULE-11-9: The macro NULL shall be the only permitted form of integer null pointer constant + * @description The macro NULL unambiguously signifies the intended use of a null pointer constant. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-11-9 + * readability + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.Pointers +import codingstandards.cpp.Type + + +from Zero zero, Expr e, string type +where + not isExcluded(zero, Pointers1Package::macroNullNotUsedAsIntegerNullPointerConstantQuery()) and + // exclude the base-case (NULL macros and void pointer casts) + not isNullPointerConstant(zero) and + ( + // ?: operator + exists(ConditionalExpr parent | + ( + parent.getThen().getAChild*() = zero and parent.getElse().getType() instanceof PointerType + or + parent.getElse().getAChild*() = zero and parent.getThen().getType() instanceof PointerType + ) and + // exclude a common conditional pattern used in macros such as 'assert' + not parent.isInMacroExpansion() and + e = parent and + type = "Ternary operator" + ) + or + // == or != operator + exists(EqualityOperation op | + op.getAnOperand() = zero and + op.getAnOperand().getType() instanceof PointerType and + e = op and + type = "Equality operator" + ) + or + // assignment to a pointer + exists(AssignExpr expr | + expr.getLValue().getType() instanceof PointerType and + expr.getRValue() = zero and + e = expr and + type = "Assignment to pointer" + ) + ) +select zero, "$@ uses zero-value integer constant expression as null pointer constant.", e, type diff --git a/c/misra/src/rules/RULE-11-9/standard-example.c b/c/misra/src/rules/RULE-11-9/standard-example.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/misra/src/rules/RULE-18-1/PointerAndDerivedPointerMustAddressSameArray.ql b/c/misra/src/rules/RULE-18-1/PointerAndDerivedPointerMustAddressSameArray.ql new file mode 100644 index 0000000000..689d711ec2 --- /dev/null +++ b/c/misra/src/rules/RULE-18-1/PointerAndDerivedPointerMustAddressSameArray.ql @@ -0,0 +1,22 @@ +/** + * @id c/misra/pointer-and-derived-pointer-must-address-same-array + * @name RULE-18-1: A pointer resulting from arithmetic on a pointer operand shall address an element of the same array + * @description A pointer resulting from arithmetic on a pointer operand shall address an element of + * the same array as that pointer operand. + * @kind problem + * @precision medium + * @problem.severity error + * @tags external/misra/id/rule-18-1 + * correctness + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.rules.donotusepointerarithmetictoaddressdifferentarrays.DoNotUsePointerArithmeticToAddressDifferentArrays + +class PointerAndDerivedPointerMustAddressSameArrayQuery extends DoNotUsePointerArithmeticToAddressDifferentArraysSharedQuery { + PointerAndDerivedPointerMustAddressSameArrayQuery() { + this = Pointers1Package::pointerAndDerivedPointerMustAddressSameArrayQuery() + } +} diff --git a/c/misra/src/rules/RULE-18-1/standard-example.c b/c/misra/src/rules/RULE-18-1/standard-example.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/misra/src/rules/RULE-18-2/SubtractionBetweenPointersMustAddressSameArray.ql b/c/misra/src/rules/RULE-18-2/SubtractionBetweenPointersMustAddressSameArray.ql new file mode 100644 index 0000000000..4eb5c5b7fb --- /dev/null +++ b/c/misra/src/rules/RULE-18-2/SubtractionBetweenPointersMustAddressSameArray.ql @@ -0,0 +1,22 @@ +/** + * @id c/misra/subtraction-between-pointers-must-address-same-array + * @name RULE-18-2: Subtraction between pointers shall only be applied to pointers that address elements of the same array + * @description Subtraction between pointers which do not both point to elements of the same array + * results in undefined behavior. + * @kind path-problem + * @precision high + * @problem.severity error + * @tags external/misra/id/rule-18-2 + * correctness + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.rules.donotsubtractpointersaddressingdifferentarrays.DoNotSubtractPointersAddressingDifferentArrays + +class SubtractionBetweenPointersMustAddressSameArrayQuery extends DoNotSubtractPointersAddressingDifferentArraysSharedQuery { + SubtractionBetweenPointersMustAddressSameArrayQuery() { + this = Pointers1Package::subtractionBetweenPointersMustAddressSameArrayQuery() + } +} diff --git a/c/misra/src/rules/RULE-18-2/standard-example.c b/c/misra/src/rules/RULE-18-2/standard-example.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/misra/src/rules/RULE-18-3/RelationalOperatorComparesPointerToDifferentArray.ql b/c/misra/src/rules/RULE-18-3/RelationalOperatorComparesPointerToDifferentArray.ql new file mode 100644 index 0000000000..7e6cd78a6a --- /dev/null +++ b/c/misra/src/rules/RULE-18-3/RelationalOperatorComparesPointerToDifferentArray.ql @@ -0,0 +1,22 @@ +/** + * @id c/misra/relational-operator-compares-pointer-to-different-array + * @name RULE-18-3: The relational operators >, >=, < and <= shall not be applied to pointers unless they point to the same object + * @description The relational operators >, >=, <, <= applied to pointers produces undefined + * behavior, except where they point to the same object. + * @kind path-problem + * @precision high + * @problem.severity error + * @tags external/misra/id/rule-18-3 + * correctness + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.rules.donotuserelationaloperatorswithdifferingarrays.DoNotUseRelationalOperatorsWithDifferingArrays + +class RelationalOperatorComparesPointerToDifferentArrayQuery extends DoNotUseRelationalOperatorsWithDifferingArraysSharedQuery { + RelationalOperatorComparesPointerToDifferentArrayQuery() { + this = Pointers1Package::relationalOperatorComparesPointerToDifferentArrayQuery() + } +} diff --git a/c/misra/src/rules/RULE-18-3/standard-example.c b/c/misra/src/rules/RULE-18-3/standard-example.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/misra/src/rules/RULE-18-4/DoNotUseAdditionOrSubtractionOperatorsOnPointers.ql b/c/misra/src/rules/RULE-18-4/DoNotUseAdditionOrSubtractionOperatorsOnPointers.ql new file mode 100644 index 0000000000..3263640266 --- /dev/null +++ b/c/misra/src/rules/RULE-18-4/DoNotUseAdditionOrSubtractionOperatorsOnPointers.ql @@ -0,0 +1,22 @@ +/** + * @id c/misra/do-not-use-addition-or-subtraction-operators-on-pointers + * @name RULE-18-4: The +, -, += and -= operators should not be applied to an expression of pointer type + * @description Array indexing should be used to perform pointer arithmetic as it is less prone to + * errors and undefined behaviour. + * @kind problem + * @precision high + * @problem.severity error + * @tags external/misra/id/rule-18-4 + * correctness + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.rules.useonlyarrayindexingforpointerarithmetic.UseOnlyArrayIndexingForPointerArithmetic + +class DoNotUseAdditionOrSubtractionOperatorsOnPointersQuery extends UseOnlyArrayIndexingForPointerArithmeticSharedQuery { + DoNotUseAdditionOrSubtractionOperatorsOnPointersQuery() { + this = Pointers1Package::doNotUseAdditionOrSubtractionOperatorsOnPointersQuery() + } +} diff --git a/c/misra/src/rules/RULE-18-4/standard-example.c b/c/misra/src/rules/RULE-18-4/standard-example.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/misra/src/rules/RULE-18-5/NoMoreThanTwoLevelsOfPointerNestingInDeclarations.ql b/c/misra/src/rules/RULE-18-5/NoMoreThanTwoLevelsOfPointerNestingInDeclarations.ql new file mode 100644 index 0000000000..c9d99469e0 --- /dev/null +++ b/c/misra/src/rules/RULE-18-5/NoMoreThanTwoLevelsOfPointerNestingInDeclarations.ql @@ -0,0 +1,22 @@ +/** + * @id c/misra/no-more-than-two-levels-of-pointer-nesting-in-declarations + * @name RULE-18-5: Declarations should contain no more than two levels of pointer nesting + * @description Declarations with more than two levels of pointer nesting can result in code that is + * difficult to read and understand. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-18-5 + * readability + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.rules.donotusemorethantwolevelsofpointerindirection.DoNotUseMoreThanTwoLevelsOfPointerIndirection + +class NoMoreThanTwoLevelsOfPointerNestingInDeclarationsQuery extends DoNotUseMoreThanTwoLevelsOfPointerIndirectionSharedQuery { + NoMoreThanTwoLevelsOfPointerNestingInDeclarationsQuery() { + this = Pointers1Package::noMoreThanTwoLevelsOfPointerNestingInDeclarationsQuery() + } +} diff --git a/c/misra/src/rules/RULE-18-5/standard-example.c b/c/misra/src/rules/RULE-18-5/standard-example.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/misra/src/rules/RULE-18-6/AutomaticStorageObjectAddressCopiedToOtherObject.ql b/c/misra/src/rules/RULE-18-6/AutomaticStorageObjectAddressCopiedToOtherObject.ql new file mode 100644 index 0000000000..499b730e2f --- /dev/null +++ b/c/misra/src/rules/RULE-18-6/AutomaticStorageObjectAddressCopiedToOtherObject.ql @@ -0,0 +1,23 @@ +/** + * @id c/misra/automatic-storage-object-address-copied-to-other-object + * @name RULE-18-6: The address of an object with automatic storage shall not be copied to another object that persists + * @description Storing the address of an object in a new object that persists past the original + * object's lifetime results in undefined behaviour if the address is subsequently + * accessed. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-18-6 + * correctness + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.rules.donotcopyaddressofautostorageobjecttootherobject.DoNotCopyAddressOfAutoStorageObjectToOtherObject + +class AutomaticStorageObjectAddressCopiedToOtherObjectQuery extends DoNotCopyAddressOfAutoStorageObjectToOtherObjectSharedQuery { + AutomaticStorageObjectAddressCopiedToOtherObjectQuery() { + this = Pointers1Package::automaticStorageObjectAddressCopiedToOtherObjectQuery() + } +} diff --git a/c/misra/src/rules/RULE-18-6/standard-example.c b/c/misra/src/rules/RULE-18-6/standard-example.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/misra/src/rules/RULE-20-8/ControllingExpressionIfDirective.ql b/c/misra/src/rules/RULE-20-8/ControllingExpressionIfDirective.ql new file mode 100644 index 0000000000..72495b5d5b --- /dev/null +++ b/c/misra/src/rules/RULE-20-8/ControllingExpressionIfDirective.ql @@ -0,0 +1,96 @@ +/** + * @id c/misra/controlling-expression-if-directive + * @name RULE-20-8: The controlling expression of a #if or #elif preprocessing directive shall evaluate to 0 or 1 + * @description A controlling expression of a #if or #elif preprocessing directive that does not + * evaluate to 0 or 1 makes code more difficult to understand. + * @kind problem + * @precision high + * @problem.severity warning + * @tags external/misra/id/rule-20-8 + * maintainability + * readability + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra + +/* A controlling expression is evaluated if it is not excluded (guarded by another controlling expression that is not taken). This translates to it either being taken or not taken. */ +predicate isEvaluated(PreprocessorBranch b) { b.wasTaken() or b.wasNotTaken() } + +class IfOrElifPreprocessorBranch extends PreprocessorBranch { + IfOrElifPreprocessorBranch() { + this instanceof PreprocessorIf or this instanceof PreprocessorElif + } +} + +/** + * Looks like it contains a single macro, which may be undefined + */ +class SimpleMacroPreprocessorBranch extends IfOrElifPreprocessorBranch { + SimpleMacroPreprocessorBranch() { this.getHead().regexpMatch("[a-zA-Z_][a-zA-Z0-9_]+") } +} + +class SimpleNumericPreprocessorBranch extends IfOrElifPreprocessorBranch { + SimpleNumericPreprocessorBranch() { this.getHead().regexpMatch("[0-9]+") } +} + +class ZeroOrOnePreprocessorBranch extends SimpleNumericPreprocessorBranch { + ZeroOrOnePreprocessorBranch() { this.getHead().regexpMatch("[0|1]") } +} + +predicate containsOnlySafeOperators(IfOrElifPreprocessorBranch b) { + containsOnlyDefinedOperator(b) + or + //logic: comparison operators eval last, so they make it safe? + b.getHead().regexpMatch(".*[\\&\\&|\\|\\||>|<|==].*") +} + +//all defined operators is definitely safe +predicate containsOnlyDefinedOperator(IfOrElifPreprocessorBranch b) { + forall(string portion | + portion = + b.getHead() + .replaceAll("\\", " ") + .replaceAll("(", " ") + .replaceAll(")", " ") + .splitAt("||") + .splitAt("&&") + | + portion.regexpMatch("^.*defined\\s[^(].*") + ) +} + +class BinaryValuedMacro extends Macro { + BinaryValuedMacro() { this.getBody().regexpMatch("\\(?(0|1)\\)?") } +} + +from IfOrElifPreprocessorBranch b, string msg +where + not isExcluded(b, Preprocessor3Package::controllingExpressionIfDirectiveQuery()) and + isEvaluated(b) and + //a catch all for anything that is not only comprised of defined operators + //after which the expression is guaranteed to eval to 0 or 1 + not containsOnlySafeOperators(b) and + //any single number, that is not 0|1 + ( + b instanceof SimpleNumericPreprocessorBranch and + not b instanceof ZeroOrOnePreprocessorBranch and + msg = " a simple number " + b.getHead() + ) + or + //contains exactly one instance of a macro name that is not representing 0|1 + b instanceof SimpleMacroPreprocessorBranch and + exists(Macro m | + m.getName() = b.getHead() and + not m instanceof BinaryValuedMacro and + not m.getBody().regexpMatch(".*[\\&\\&|\\|\\||>|<|==].*") and + msg = " a macro value " + m.getBody() + ) + or + //something that looks like an expression with arithmetic operators and numeric operands + //assume unless it it enclosed in not operator it does not evaluate to 0 or 1 + b.getHead().regexpMatch(".*!*[0-9]+\\s*[+|-|\\\\*|%|\\/]+\\s*!*[0-9]+.*") and + not b.getHead().regexpMatch("^!\\(.*") and + msg = " an arithmetic expression." +select b, "Directive expression " + b.getHead() + " evaluates to" + msg diff --git a/c/misra/src/rules/RULE-20-8/standard-example.c b/c/misra/src/rules/RULE-20-8/standard-example.c new file mode 100644 index 0000000000..21ad139e39 --- /dev/null +++ b/c/misra/src/rules/RULE-20-8/standard-example.c @@ -0,0 +1,11 @@ +#define FALSE 0 +#define TRUE 1 +#if FALSE /* Compliant */ +#endif +#if 10 /* Non-compliant */ +#endif +#if !defined(X) /* Compliant */ +#endif + +#if A > B /* Compliant assuming A and B are numeric */ +#endif \ No newline at end of file diff --git a/c/misra/src/rules/RULE-4-8/ObjectWithNoPointerDereferenceShouldBeOpaque.ql b/c/misra/src/rules/RULE-4-8/ObjectWithNoPointerDereferenceShouldBeOpaque.ql new file mode 100644 index 0000000000..20f91dca78 --- /dev/null +++ b/c/misra/src/rules/RULE-4-8/ObjectWithNoPointerDereferenceShouldBeOpaque.ql @@ -0,0 +1,47 @@ +/** + * @id c/misra/object-with-no-pointer-dereference-should-be-opaque + * @name RULE-4-8: The implementation of an object shall be hidden if a pointer to its structure or union is never dereferenced within a translation unit + * @description If a pointer to a structure or union is never dereferenced within a translation + * unit, then the implementation of the object should be hidden to prevent + * unintentional changes. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-4-8 + * readability + * maintainability + * readability + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.Scope + +TranslationUnit commonTranslationUnit(File a, File b) { + result.getAUserFile() = a and + result.getAUserFile() = b +} + +from Struct base, TranslationUnit tu +where + not isExcluded(base, Pointers1Package::objectWithNoPointerDereferenceShouldBeOpaqueQuery()) and + // exclude cases like `struct s1;` + base.getSize() > 0 and + exists(Expr e | + e.getType().(PointerType).getBaseType().stripType() = base and + tu = commonTranslationUnit(e.getFile(), base.getFile()) + ) and + not exists(FieldAccess fa | + inSameTranslationUnit(fa.getFile(), base.getFile()) and + fa.getQualifier().getType().stripType() = base + ) and + // exclude translation units where there exists a non-pointer variable of type `base` + not exists(Variable v | + v.getType().stripType() = base and + not v.getType().getUnderlyingType() instanceof PointerType and + inSameTranslationUnit(v.getFile(), base.getFile()) + ) +select base, + "$@ is not opaque but no pointer to it is dereferenced within the translation unit $@.", base, + base.getName(), tu, tu.getBaseName() diff --git a/c/misra/src/rules/RULE-4-8/standard-example.c b/c/misra/src/rules/RULE-4-8/standard-example.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/misra/src/rules/RULE-8-13/PointerShouldPointToConstTypeWhenPossible.ql b/c/misra/src/rules/RULE-8-13/PointerShouldPointToConstTypeWhenPossible.ql new file mode 100644 index 0000000000..f04721883b --- /dev/null +++ b/c/misra/src/rules/RULE-8-13/PointerShouldPointToConstTypeWhenPossible.ql @@ -0,0 +1,51 @@ +/** + * @id c/misra/pointer-should-point-to-const-type-when-possible + * @name RULE-8-13: A pointer should point to a const-qualified type whenever possible + * @description A pointer should point to a const-qualified type unless it is used to modify an + * object or the underlying object data is copied. + * @kind problem + * @precision high + * @problem.severity error + * @tags external/misra/id/rule-8-13 + * correctness + * maintainability + * readability + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.SideEffect + +class PointerOrArrayType extends DerivedType { + PointerOrArrayType() { + this.stripTopLevelSpecifiers() instanceof PointerType or + this.stripTopLevelSpecifiers() instanceof ArrayType + } +} + +from Variable ptr, PointerOrArrayType type +where + not isExcluded(ptr, Pointers1Package::pointerShouldPointToConstTypeWhenPossibleQuery()) and + // include only pointers which point to a const-qualified type + ptr.getType() = type and + not type.isDeeplyConstBelow() and + // exclude pointers passed as arguments to functions which take a + // parameter that points to a non-const-qualified type + not exists(FunctionCall fc, int i | + fc.getArgument(i) = ptr.getAnAccess() and + not fc.getTarget().getParameter(i).getType().isDeeplyConstBelow() + ) and + // exclude any pointers which have their underlying data modified + not exists(VariableEffect effect | + effect.getTarget() = ptr and + // but not pointers that are only themselves modified + not effect.(AssignExpr).getLValue() = effect.getAnAccess() and + not effect.(CrementOperation).getOperand() = effect.getAnAccess() + ) and + // exclude pointers assigned to another pointer to a non-const-qualified type + not exists(Variable a | + a.getAnAssignedValue() = ptr.getAnAccess() and + not a.getType().(PointerOrArrayType).isDeeplyConstBelow() + ) +select ptr, "$@ points to a non-const-qualified type.", ptr, ptr.getName() diff --git a/c/misra/src/rules/RULE-8-13/standard-example.c b/c/misra/src/rules/RULE-8-13/standard-example.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/misra/test/qlpack.yml b/c/misra/test/qlpack.yml index 2e9d46e7b1..2a121f8a63 100644 --- a/c/misra/test/qlpack.yml +++ b/c/misra/test/qlpack.yml @@ -1,4 +1,4 @@ name: misra-c-coding-standards-tests -version: 2.4.0 +version: 2.5.0 libraryPathDependencies: misra-c-coding-standards extractor: cpp \ No newline at end of file diff --git a/c/misra/test/rules/RULE-11-1/ConversionBetweenFunctionPointerAndOtherType.expected b/c/misra/test/rules/RULE-11-1/ConversionBetweenFunctionPointerAndOtherType.expected new file mode 100644 index 0000000000..05dace2c7d --- /dev/null +++ b/c/misra/test/rules/RULE-11-1/ConversionBetweenFunctionPointerAndOtherType.expected @@ -0,0 +1,5 @@ +| test.c:11:8:11:16 | (fp1 *)... | Cast performed between a function pointer and another type. | +| test.c:11:8:11:16 | (fp1)... | Cast performed between a function pointer and another type. | +| test.c:12:14:12:23 | (void *)... | Cast performed between a function pointer and another type. | +| test.c:14:8:14:15 | (fp2)... | Cast performed between a function pointer and another type. | +| test.c:15:8:15:15 | (fp2)... | Cast performed between a function pointer and another type. | diff --git a/c/misra/test/rules/RULE-11-1/ConversionBetweenFunctionPointerAndOtherType.qlref b/c/misra/test/rules/RULE-11-1/ConversionBetweenFunctionPointerAndOtherType.qlref new file mode 100644 index 0000000000..80f7e9093c --- /dev/null +++ b/c/misra/test/rules/RULE-11-1/ConversionBetweenFunctionPointerAndOtherType.qlref @@ -0,0 +1 @@ +rules/RULE-11-1/ConversionBetweenFunctionPointerAndOtherType.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-11-1/ConversionBetweenFunctionPointerAndOtherType.testref b/c/misra/test/rules/RULE-11-1/ConversionBetweenFunctionPointerAndOtherType.testref new file mode 100644 index 0000000000..68fdd74602 --- /dev/null +++ b/c/misra/test/rules/RULE-11-1/ConversionBetweenFunctionPointerAndOtherType.testref @@ -0,0 +1 @@ +c/common/test/rules/donotconvertbetweenfunctionpointerandothertype/DoNotConvertBetweenFunctionPointerAndOtherType.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-11-1/test.c b/c/misra/test/rules/RULE-11-1/test.c new file mode 100644 index 0000000000..0c87fab719 --- /dev/null +++ b/c/misra/test/rules/RULE-11-1/test.c @@ -0,0 +1,23 @@ +#include + +typedef void (*fp1)(void); +typedef void (*fp2)(int p1); +typedef fp2 (*pfp2)(void); + +void f1(void) { + fp1 v1 = NULL; // COMPLIANT + fp2 v2 = NULL; // COMPLIANT + + v1 = (fp1 *)v2; // NON_COMPLIANT + void *v3 = (void *)v1; // NON_COMPLIANT + + v2 = (fp2 *)0; // NON_COMPLIANT + v2 = (fp2 *)1; // NON_COMPLIANT + + pfp2 v4; + (void)(*v4()); // COMPLIANT + + extern void f2(int p1); + f2(0); // COMPLIANT + fp1 v5 = f2; // COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-11-2/ConversionBetweenIncompleteTypePointerAndOtherType.expected b/c/misra/test/rules/RULE-11-2/ConversionBetweenIncompleteTypePointerAndOtherType.expected new file mode 100644 index 0000000000..0d0a982f1a --- /dev/null +++ b/c/misra/test/rules/RULE-11-2/ConversionBetweenIncompleteTypePointerAndOtherType.expected @@ -0,0 +1,3 @@ +| test.c:14:8:14:22 | (s2 *)... | Cast performed between a pointer to incomplete type and another type. | +| test.c:15:8:15:17 | (void *)... | Cast performed between a pointer to incomplete type and another type. | +| test.c:19:8:19:21 | (s1 *)... | Cast performed between a pointer to incomplete type and another type. | diff --git a/c/misra/test/rules/RULE-11-2/ConversionBetweenIncompleteTypePointerAndOtherType.qlref b/c/misra/test/rules/RULE-11-2/ConversionBetweenIncompleteTypePointerAndOtherType.qlref new file mode 100644 index 0000000000..c26b798f36 --- /dev/null +++ b/c/misra/test/rules/RULE-11-2/ConversionBetweenIncompleteTypePointerAndOtherType.qlref @@ -0,0 +1 @@ +rules/RULE-11-2/ConversionBetweenIncompleteTypePointerAndOtherType.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-11-2/test.c b/c/misra/test/rules/RULE-11-2/test.c new file mode 100644 index 0000000000..e5b32bf8d5 --- /dev/null +++ b/c/misra/test/rules/RULE-11-2/test.c @@ -0,0 +1,21 @@ +#include + +void f1(void) { + struct s1; + struct s2; + + struct s1 *v1; + struct s1 *v2; + struct s2 *v3; + void *v4; + int *v5; + + v2 = (struct s1 *)v1; // COMPLIANT + v3 = (struct s2 *)v1; // NON_COMPLIANT + v4 = (void *)v1; // NON_COMPLIANT + v4 = (void *)v5; // COMPLIANT + v5 = (int *)v4; // COMPLIANT + v1 = NULL; // COMPLIANT + v1 = (struct s1 *)1; // NON_COMPLIANT + (void)v1; // COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-11-3/CastBetweenObjectPointerAndDifferentObjectType.expected b/c/misra/test/rules/RULE-11-3/CastBetweenObjectPointerAndDifferentObjectType.expected new file mode 100644 index 0000000000..91fd9f274a --- /dev/null +++ b/c/misra/test/rules/RULE-11-3/CastBetweenObjectPointerAndDifferentObjectType.expected @@ -0,0 +1,4 @@ +| test.c:12:17:12:28 | (int16_t *)... | Cast performed between a pointer to object type (int8_t) and a pointer to a different object type (int16_t). | +| test.c:14:8:14:9 | (int *)... | Cast performed between a pointer to object type (char) and a pointer to a different object type (int). | +| test.c:15:8:15:25 | (int *)... | Cast performed between a pointer to object type (short) and a pointer to a different object type (int). | +| test.c:15:15:15:25 | (short *)... | Cast performed between a pointer to object type (char) and a pointer to a different object type (short). | diff --git a/c/misra/test/rules/RULE-11-3/CastBetweenObjectPointerAndDifferentObjectType.qlref b/c/misra/test/rules/RULE-11-3/CastBetweenObjectPointerAndDifferentObjectType.qlref new file mode 100644 index 0000000000..f7ee843877 --- /dev/null +++ b/c/misra/test/rules/RULE-11-3/CastBetweenObjectPointerAndDifferentObjectType.qlref @@ -0,0 +1 @@ +rules/RULE-11-3/CastBetweenObjectPointerAndDifferentObjectType.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-11-3/test.c b/c/misra/test/rules/RULE-11-3/test.c new file mode 100644 index 0000000000..64ae688993 --- /dev/null +++ b/c/misra/test/rules/RULE-11-3/test.c @@ -0,0 +1,16 @@ +#include + +typedef struct s1 s1; + +void f1(void) { + int *v1 = (int *)(s1 *)0; // COMPLIANT + char *v2 = (char *)v1; // COMPLIANT + void *v3 = (void *)0; // COMPLIANT + s1 *v4 = (s1 *)v3; // COMPLIANT + s1 *v5 = (s1 *)v2; // COMPLIANT + void *v6 = (void *)v5; // COMPLIANT + int16_t *v7 = (int8_t *)v1; // NON_COMPLIANT + int *v8 = (int *)0; // COMPLIANT + v8 = v2; // NON_COMPLIANT + v8 = (int *)(short *)v2; // NON_COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-11-4/ConversionBetweenPointerToObjectAndIntegerType.expected b/c/misra/test/rules/RULE-11-4/ConversionBetweenPointerToObjectAndIntegerType.expected new file mode 100644 index 0000000000..5fedfdcce4 --- /dev/null +++ b/c/misra/test/rules/RULE-11-4/ConversionBetweenPointerToObjectAndIntegerType.expected @@ -0,0 +1,6 @@ +| test.c:5:21:5:42 | (unsigned int)... | Cast performed between a pointer to object type and a pointer to an integer type. | +| test.c:5:35:5:42 | (int *)... | Cast performed between a pointer to object type and a pointer to an integer type. | +| test.c:6:21:6:37 | (unsigned int)... | Cast performed between a pointer to object type and a pointer to an integer type. | +| test.c:8:8:8:24 | (unsigned int)... | Cast performed between a pointer to object type and a pointer to an integer type. | +| test.c:10:22:10:22 | (unsigned int *)... | Cast performed between a pointer to object type and a pointer to an integer type. | +| test.c:12:22:12:39 | (unsigned int *)... | Cast performed between a pointer to object type and a pointer to an integer type. | diff --git a/c/misra/test/rules/RULE-11-4/ConversionBetweenPointerToObjectAndIntegerType.qlref b/c/misra/test/rules/RULE-11-4/ConversionBetweenPointerToObjectAndIntegerType.qlref new file mode 100644 index 0000000000..f5648b25ac --- /dev/null +++ b/c/misra/test/rules/RULE-11-4/ConversionBetweenPointerToObjectAndIntegerType.qlref @@ -0,0 +1 @@ +rules/RULE-11-4/ConversionBetweenPointerToObjectAndIntegerType.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-11-4/test.c b/c/misra/test/rules/RULE-11-4/test.c new file mode 100644 index 0000000000..25e3f3c4b2 --- /dev/null +++ b/c/misra/test/rules/RULE-11-4/test.c @@ -0,0 +1,13 @@ +#include + +void f1(void) { + unsigned int v1 = (unsigned int)(void *)0; // COMPLIANT + unsigned int v2 = (unsigned int)(int *)0; // NON_COMPLIANT + unsigned int v3 = (unsigned int)&v2; // NON_COMPLIANT + v3 = v2; // COMPLIANT + v3 = (unsigned int)&v2; // NON_COMPLIANT + v3 = NULL; // COMPLIANT + unsigned int *v4 = 0; // NON_COMPLIANT + unsigned int *v5 = NULL; // COMPLIANT + unsigned int *v6 = (unsigned int *)v2; // NON_COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-11-5/ConversionFromPointerToVoidIntoPointerToObject.expected b/c/misra/test/rules/RULE-11-5/ConversionFromPointerToVoidIntoPointerToObject.expected new file mode 100644 index 0000000000..5b4eec8d15 --- /dev/null +++ b/c/misra/test/rules/RULE-11-5/ConversionFromPointerToVoidIntoPointerToObject.expected @@ -0,0 +1 @@ +| test.c:6:13:6:21 | (int *)... | Cast performed from a void pointer into a pointer to an object (int *). | diff --git a/c/misra/test/rules/RULE-11-5/ConversionFromPointerToVoidIntoPointerToObject.qlref b/c/misra/test/rules/RULE-11-5/ConversionFromPointerToVoidIntoPointerToObject.qlref new file mode 100644 index 0000000000..dc0fbf2978 --- /dev/null +++ b/c/misra/test/rules/RULE-11-5/ConversionFromPointerToVoidIntoPointerToObject.qlref @@ -0,0 +1 @@ +rules/RULE-11-5/ConversionFromPointerToVoidIntoPointerToObject.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-11-5/test.c b/c/misra/test/rules/RULE-11-5/test.c new file mode 100644 index 0000000000..a7ffa4822e --- /dev/null +++ b/c/misra/test/rules/RULE-11-5/test.c @@ -0,0 +1,10 @@ +#include + +void f1(void) { + void *v1 = (void *)0; // COMPLIANT + v1 = NULL; // COMPLIANT + int *v2 = (int *)v1; // NON_COMPLIANT + v2 = NULL; // COMPLIANT + void *v3 = (void *)v1; // COMPLIANT + v3 = (void *)v2; // COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-11-6/CastBetweenPointerToVoidAndArithmeticType.expected b/c/misra/test/rules/RULE-11-6/CastBetweenPointerToVoidAndArithmeticType.expected new file mode 100644 index 0000000000..ebafd39b8c --- /dev/null +++ b/c/misra/test/rules/RULE-11-6/CastBetweenPointerToVoidAndArithmeticType.expected @@ -0,0 +1,3 @@ +| test.c:3:14:3:23 | (void *)... | Cast performed between a pointer to void type and an arithmetic type. | +| test.c:5:8:5:17 | (void *)... | Cast performed between a pointer to void type and an arithmetic type. | +| test.c:7:8:7:14 | (int)... | Cast performed between a pointer to void type and an arithmetic type. | diff --git a/c/misra/test/rules/RULE-11-6/CastBetweenPointerToVoidAndArithmeticType.qlref b/c/misra/test/rules/RULE-11-6/CastBetweenPointerToVoidAndArithmeticType.qlref new file mode 100644 index 0000000000..20bbca7f98 --- /dev/null +++ b/c/misra/test/rules/RULE-11-6/CastBetweenPointerToVoidAndArithmeticType.qlref @@ -0,0 +1 @@ +rules/RULE-11-6/CastBetweenPointerToVoidAndArithmeticType.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-11-6/test.c b/c/misra/test/rules/RULE-11-6/test.c new file mode 100644 index 0000000000..fcbdd56881 --- /dev/null +++ b/c/misra/test/rules/RULE-11-6/test.c @@ -0,0 +1,9 @@ +void f1(void) { + int v1 = 0; + void *v2 = (void *)v1; // NON_COMPLIANT + unsigned char v3 = 0; + v2 = (void *)v3; // NON_COMPLIANT + v2 = (void *)&v3; // COMPLIANT + v1 = (int)v2; // NON_COMPLIANT + v1 = (int)v3; // COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-11-7/CastBetweenPointerToObjectAndNonIntArithmeticType.expected b/c/misra/test/rules/RULE-11-7/CastBetweenPointerToObjectAndNonIntArithmeticType.expected new file mode 100644 index 0000000000..0b96b3c747 --- /dev/null +++ b/c/misra/test/rules/RULE-11-7/CastBetweenPointerToObjectAndNonIntArithmeticType.expected @@ -0,0 +1,3 @@ +| test.c:5:13:5:20 | (bool)... | Cast performed between a pointer to void type and a non-integer arithmetic type. | +| test.c:7:21:7:28 | (bool)... | Cast performed between a pointer to void type and a non-integer arithmetic type. | +| test.c:8:8:8:16 | (int *)... | Cast performed between a pointer to void type and a non-integer arithmetic type. | diff --git a/c/misra/test/rules/RULE-11-7/CastBetweenPointerToObjectAndNonIntArithmeticType.qlref b/c/misra/test/rules/RULE-11-7/CastBetweenPointerToObjectAndNonIntArithmeticType.qlref new file mode 100644 index 0000000000..d071effc3e --- /dev/null +++ b/c/misra/test/rules/RULE-11-7/CastBetweenPointerToObjectAndNonIntArithmeticType.qlref @@ -0,0 +1 @@ +rules/RULE-11-7/CastBetweenPointerToObjectAndNonIntArithmeticType.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-11-7/test.c b/c/misra/test/rules/RULE-11-7/test.c new file mode 100644 index 0000000000..b7dd989b00 --- /dev/null +++ b/c/misra/test/rules/RULE-11-7/test.c @@ -0,0 +1,10 @@ +#include + +void f1(void) { + int *v1; + bool v2 = (bool)v1; // NON_COMPLIANT + bool v3 = 0; // COMPLIANT + float v4 = (float)(bool)v1; // NON_COMPLIANT + v1 = (int *)v2; // NON_COMPLIANT + v4 = (float)v3; // COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-11-8/CastRemovesConstOrVolatileQualification.expected b/c/misra/test/rules/RULE-11-8/CastRemovesConstOrVolatileQualification.expected new file mode 100644 index 0000000000..48658e2176 --- /dev/null +++ b/c/misra/test/rules/RULE-11-8/CastRemovesConstOrVolatileQualification.expected @@ -0,0 +1,2 @@ +| test.c:4:19:4:33 | (const char *)... | Cast of pointer removes volatile qualification from its base type. | +| test.c:6:13:6:21 | (char *)... | Cast of pointer removes const qualification from its base type. | diff --git a/c/misra/test/rules/RULE-11-8/CastRemovesConstOrVolatileQualification.qlref b/c/misra/test/rules/RULE-11-8/CastRemovesConstOrVolatileQualification.qlref new file mode 100644 index 0000000000..172c578989 --- /dev/null +++ b/c/misra/test/rules/RULE-11-8/CastRemovesConstOrVolatileQualification.qlref @@ -0,0 +1 @@ +rules/RULE-11-8/CastRemovesConstOrVolatileQualification.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-11-8/test.c b/c/misra/test/rules/RULE-11-8/test.c new file mode 100644 index 0000000000..75c7fc189a --- /dev/null +++ b/c/misra/test/rules/RULE-11-8/test.c @@ -0,0 +1,9 @@ +int f1(void) { + const volatile char *const a = 0; + const volatile char *b = (const volatile char *)a; // COMPLIANT + const char *c = (const char *)b; // NON_COMPLIANT + const char *c2 = (const char *)c; // COMPLIANT + char *d = (char *)c; // NON_COMPLIANT + const char *e = (const char *)d; // COMPLIANT + return 0; +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-11-9/MacroNullNotUsedAsIntegerNullPointerConstant.expected b/c/misra/test/rules/RULE-11-9/MacroNullNotUsedAsIntegerNullPointerConstant.expected new file mode 100644 index 0000000000..8cdd34edd1 --- /dev/null +++ b/c/misra/test/rules/RULE-11-9/MacroNullNotUsedAsIntegerNullPointerConstant.expected @@ -0,0 +1,4 @@ +| test.c:15:13:15:13 | 0 | $@ uses zero-value integer constant expression as null pointer constant. | test.c:15:7:15:13 | ... == ... | Equality operator | +| test.c:17:8:17:8 | 0 | $@ uses zero-value integer constant expression as null pointer constant. | test.c:17:3:17:8 | ... = ... | Assignment to pointer | +| test.c:25:20:25:20 | 0 | $@ uses zero-value integer constant expression as null pointer constant. | test.c:25:3:25:35 | ... ? ... : ... | Ternary operator | +| test.c:25:20:25:20 | 0 | $@ uses zero-value integer constant expression as null pointer constant. | test.c:25:15:25:20 | ... = ... | Assignment to pointer | diff --git a/c/misra/test/rules/RULE-11-9/MacroNullNotUsedAsIntegerNullPointerConstant.qlref b/c/misra/test/rules/RULE-11-9/MacroNullNotUsedAsIntegerNullPointerConstant.qlref new file mode 100644 index 0000000000..13235e33a3 --- /dev/null +++ b/c/misra/test/rules/RULE-11-9/MacroNullNotUsedAsIntegerNullPointerConstant.qlref @@ -0,0 +1 @@ +rules/RULE-11-9/MacroNullNotUsedAsIntegerNullPointerConstant.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-11-9/test.c b/c/misra/test/rules/RULE-11-9/test.c new file mode 100644 index 0000000000..216ea2b280 --- /dev/null +++ b/c/misra/test/rules/RULE-11-9/test.c @@ -0,0 +1,27 @@ +#include + +struct s1 { + void *v1; + void *v2; +}; + +struct s1 g_v1 = {0}; // COMPLIANT + +void *f1(void *p1, int p2) { + if (p1 == (void *)0) { // COMPLIANT + } + if (p1 == NULL) { // COMPLIANT + } + if (p1 == 0) { // NON_COMPLIANT + } + p1 = 0; // NON_COMPLIANT + p1 = (void *)0; // COMPLIANT + p1 = NULL; // COMPLIANT + if (p2 == 0) { // COMPLIANT + return NULL; + } // COMPLIANT + (p1) ? (p1 = NULL) : (p1 = NULL); // COMPLIANT + (p2 > 0) ? (p1 = NULL) : (p1 = NULL); // COMPLIANT + (p2 > 0) ? (p1 = 0) : (p1 = NULL); // NON_COMPLIANT + return 0; // COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-18-1/PointerAndDerivedPointerMustAddressSameArray.testref b/c/misra/test/rules/RULE-18-1/PointerAndDerivedPointerMustAddressSameArray.testref new file mode 100644 index 0000000000..cfca28a801 --- /dev/null +++ b/c/misra/test/rules/RULE-18-1/PointerAndDerivedPointerMustAddressSameArray.testref @@ -0,0 +1 @@ +c/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-18-2/SubtractionBetweenPointersMustAddressSameArray.testref b/c/misra/test/rules/RULE-18-2/SubtractionBetweenPointersMustAddressSameArray.testref new file mode 100644 index 0000000000..bbe3b3db8a --- /dev/null +++ b/c/misra/test/rules/RULE-18-2/SubtractionBetweenPointersMustAddressSameArray.testref @@ -0,0 +1 @@ +c/common/test/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-18-3/RelationalOperatorComparesPointerToDifferentArray.testref b/c/misra/test/rules/RULE-18-3/RelationalOperatorComparesPointerToDifferentArray.testref new file mode 100644 index 0000000000..067c1c5965 --- /dev/null +++ b/c/misra/test/rules/RULE-18-3/RelationalOperatorComparesPointerToDifferentArray.testref @@ -0,0 +1 @@ +c/common/test/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-18-4/DoNotUseAdditionOrSubtractionOperatorsOnPointers.testref b/c/misra/test/rules/RULE-18-4/DoNotUseAdditionOrSubtractionOperatorsOnPointers.testref new file mode 100644 index 0000000000..8a14a78a41 --- /dev/null +++ b/c/misra/test/rules/RULE-18-4/DoNotUseAdditionOrSubtractionOperatorsOnPointers.testref @@ -0,0 +1 @@ +c/common/test/rules/useonlyarrayindexingforpointerarithmetic/UseOnlyArrayIndexingForPointerArithmetic.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-18-5/NoMoreThanTwoLevelsOfPointerNestingInDeclarations.testref b/c/misra/test/rules/RULE-18-5/NoMoreThanTwoLevelsOfPointerNestingInDeclarations.testref new file mode 100644 index 0000000000..ead2715d27 --- /dev/null +++ b/c/misra/test/rules/RULE-18-5/NoMoreThanTwoLevelsOfPointerNestingInDeclarations.testref @@ -0,0 +1 @@ +c/common/test/rules/donotusemorethantwolevelsofpointerindirection/DoNotUseMoreThanTwoLevelsOfPointerIndirection.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-18-6/AutomaticStorageObjectAddressCopiedToOtherObject.testref b/c/misra/test/rules/RULE-18-6/AutomaticStorageObjectAddressCopiedToOtherObject.testref new file mode 100644 index 0000000000..e1ff9b5ae0 --- /dev/null +++ b/c/misra/test/rules/RULE-18-6/AutomaticStorageObjectAddressCopiedToOtherObject.testref @@ -0,0 +1 @@ +c/common/test/rules/donotcopyaddressofautostorageobjecttootherobject/DoNotCopyAddressOfAutoStorageObjectToOtherObject.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-20-8/ControllingExpressionIfDirective.expected b/c/misra/test/rules/RULE-20-8/ControllingExpressionIfDirective.expected new file mode 100644 index 0000000000..133273ae76 --- /dev/null +++ b/c/misra/test/rules/RULE-20-8/ControllingExpressionIfDirective.expected @@ -0,0 +1,7 @@ +| test.c:10:1:10:15 | #if falseAlsoOk | Directive expression falseAlsoOk evaluates to a macro value false + 1 | +| test.c:34:1:34:6 | #if 17 | Directive expression 17 evaluates to a simple number 17 | +| test.c:37:1:37:9 | #if extra | Directive expression extra evaluates to a macro value 17 | +| test.c:63:1:63:9 | #if 2 + 2 | Directive expression 2 + 2 evaluates to an arithmetic expression. | +| test.c:66:1:66:13 | #if !!2 + !!2 | Directive expression !!2 + !!2 evaluates to an arithmetic expression. | +| test.c:69:1:69:11 | #if !0 + !0 | Directive expression !0 + !0 evaluates to an arithmetic expression. | +| test.c:72:1:72:15 | #if (1 + 1 + 1) | Directive expression (1 + 1 + 1) evaluates to an arithmetic expression. | diff --git a/c/misra/test/rules/RULE-20-8/ControllingExpressionIfDirective.qlref b/c/misra/test/rules/RULE-20-8/ControllingExpressionIfDirective.qlref new file mode 100644 index 0000000000..a2e0273526 --- /dev/null +++ b/c/misra/test/rules/RULE-20-8/ControllingExpressionIfDirective.qlref @@ -0,0 +1 @@ +rules/RULE-20-8/ControllingExpressionIfDirective.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-20-8/test.c b/c/misra/test/rules/RULE-20-8/test.c new file mode 100644 index 0000000000..03995be331 --- /dev/null +++ b/c/misra/test/rules/RULE-20-8/test.c @@ -0,0 +1,76 @@ +#define false 0 +#define true 1 +#define extra 17 +#define falseAlsoOk false + 1 +#define tricky (1) + +#if false // COMPLIANT +#endif + +#if falseAlsoOk // COMPLIANT[FALSE_POSITIVE] +#endif + +#if true // COMPLIANT +#endif + +#if tricky // COMPLIANT +#endif + +#if extra == 1 // COMPLIANT +#endif + +#if defined(extra) // COMPLIANT +#endif + +#if defined(extra) && defined(notdefinedmacro) // COMPLIANT +#endif + +#if defined(extra) && 17 // COMPLIANT +#endif + +#if extra > 1 // COMPLIANT +#endif + +#if 17 // NON_COMPLIANT +#endif + +#if extra // NON_COMPLIANT +#endif + +#if extra + 1 // NON_COMPLIANT[FALSE_NEGATIVE] +#endif + +#if false + 1 // COMPLIANT +#endif + +#if undefinedmacro // COMPLIANT +#endif + +#if false // COMPLIANT +#if 17 // COMPLIANT - not evaluated +#endif +#endif + +#if !1 // COMPLIANT +#endif + +#if !2 // COMPLIANT +#endif + +#if !(2 + 2) // COMPLIANT +#endif + +#if 2 + 2 // NON_COMPLIANT +#endif + +#if !!2 + !!2 // NON_COMPLIANT +#endif + +#if !0 + !0 // NON_COMPLIANT +#endif + +#if (1 + 1 + 1) // NON_COMPLIANT +#endif + +#if !(1 + 1 + 1) // COMPLIANT +#endif diff --git a/c/misra/test/rules/RULE-4-8/ObjectWithNoPointerDereferenceShouldBeOpaque.expected b/c/misra/test/rules/RULE-4-8/ObjectWithNoPointerDereferenceShouldBeOpaque.expected new file mode 100644 index 0000000000..cdbef7ca60 --- /dev/null +++ b/c/misra/test/rules/RULE-4-8/ObjectWithNoPointerDereferenceShouldBeOpaque.expected @@ -0,0 +1,6 @@ +| test.c:10:8:10:9 | s4 | $@ is not opaque but no pointer to it is dereferenced within the translation unit $@. | test.c:10:8:10:9 | s4 | s4 | test.c:0:0:0:0 | test.c | test.c | +| test.h:3:8:3:9 | s1 | $@ is not opaque but no pointer to it is dereferenced within the translation unit $@. | test.h:3:8:3:9 | s1 | s1 | test.c:0:0:0:0 | test.c | test.c | +| test_2.c:7:8:7:9 | s2 | $@ is not opaque but no pointer to it is dereferenced within the translation unit $@. | test_2.c:7:8:7:9 | s2 | s2 | test_2.c:0:0:0:0 | test_2.c | test_2.c | +| test_shared.h:15:8:15:20 | only_test2_s2 | $@ is not opaque but no pointer to it is dereferenced within the translation unit $@. | test_shared.h:15:8:15:20 | only_test2_s2 | only_test2_s2 | test_2.c:0:0:0:0 | test_2.c | test_2.c | +| test_shared.h:19:7:19:15 | shared_u1 | $@ is not opaque but no pointer to it is dereferenced within the translation unit $@. | test_shared.h:19:7:19:15 | shared_u1 | shared_u1 | test.c:0:0:0:0 | test.c | test.c | +| test_shared.h:19:7:19:15 | shared_u1 | $@ is not opaque but no pointer to it is dereferenced within the translation unit $@. | test_shared.h:19:7:19:15 | shared_u1 | shared_u1 | test_2.c:0:0:0:0 | test_2.c | test_2.c | diff --git a/c/misra/test/rules/RULE-4-8/ObjectWithNoPointerDereferenceShouldBeOpaque.qlref b/c/misra/test/rules/RULE-4-8/ObjectWithNoPointerDereferenceShouldBeOpaque.qlref new file mode 100644 index 0000000000..4a5c410c38 --- /dev/null +++ b/c/misra/test/rules/RULE-4-8/ObjectWithNoPointerDereferenceShouldBeOpaque.qlref @@ -0,0 +1 @@ +rules/RULE-4-8/ObjectWithNoPointerDereferenceShouldBeOpaque.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-4-8/test.c b/c/misra/test/rules/RULE-4-8/test.c new file mode 100644 index 0000000000..0b5f4d6639 --- /dev/null +++ b/c/misra/test/rules/RULE-4-8/test.c @@ -0,0 +1,46 @@ +#include "test.h" +#include "test_shared.h" +struct s3 { + int v1; + struct s3_1 { + int a; + } v2; // COMPLIANT +}; // COMPLIANT + +struct s4 { + int v1; +}; // NON_COMPLIANT + +typedef struct s3 s3_t; +typedef struct s4 s4_t; + +void *f1(struct s1 *p1) { return (void *)p1; } + +void *f2(struct s2 *p1) { + int v1 = p1->v1; + return p1; +} + +s3_t *f3(s3_t *p1) { + int v1 = p1[0].v1; + return p1; +} + +void *f4(s4_t *p1) { return p1; } + +void *f5(struct only_test1_s1 *p1) { + int v1 = p1->v1; + return (void *)p1; +} + +void *f6(struct shared_s1 *p1) { + int v1 = p1->v1; + return (void *)p1; +} + +void *f7(union shared_u1 *p1) { return (void *)p1; } + +void *f8(union shared_u2 *p1) { + int v1 = p1->v1; + return (void *)p1; +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-4-8/test.h b/c/misra/test/rules/RULE-4-8/test.h new file mode 100644 index 0000000000..30ff6ca33e --- /dev/null +++ b/c/misra/test/rules/RULE-4-8/test.h @@ -0,0 +1,10 @@ +#ifndef TEST_H_ +#define TEST_H_ +struct s1 { + int v1; +}; // NON_COMPLIANT + +struct s2 { + int v1; +}; // COMPLIANT +#endif // TEST_H_ \ No newline at end of file diff --git a/c/misra/test/rules/RULE-4-8/test_2.c b/c/misra/test/rules/RULE-4-8/test_2.c new file mode 100644 index 0000000000..84328bb5f5 --- /dev/null +++ b/c/misra/test/rules/RULE-4-8/test_2.c @@ -0,0 +1,46 @@ +#include "test_shared.h" + +struct s1 { + float v1; +}; // COMPLIANT + +struct s2 { + float v1; +}; // NON_COMPLIANT + +struct s3 { + float v1; +}; // COMPLIANT + +void *f1(struct s1 *p1) { + int v1 = p1->v1; + return (void *)p1; +} + +void *f2(struct s2 *p1) { return (void *)p1; } + +void *f3(struct only_test2_s1 *p1) { + int v1 = (*p1).v1; + return (void *)p1; +} + +void *f4(struct only_test2_s1 *p1) { + int v1 = p1->v1; + return (void *)p1; +} + +void *f5(struct only_test2_s2 *p1) { return (void *)p1; } + +void *f6(union shared_u1 *p1) { return (void *)p1; } + +void *f7(union shared_u2 *p1) { + int v1 = p1->v1; + return (void *)p1; +} + +void *f8(void) { + struct s3 v1; + return (void *)0; +} + +void *f9(struct s3 *p1) { return (void *)p1; } \ No newline at end of file diff --git a/c/misra/test/rules/RULE-4-8/test_shared.h b/c/misra/test/rules/RULE-4-8/test_shared.h new file mode 100644 index 0000000000..c3c44fc43b --- /dev/null +++ b/c/misra/test/rules/RULE-4-8/test_shared.h @@ -0,0 +1,28 @@ +#ifndef TEST_SHARED_H_ +#define TEST_SHARED_H_ +struct shared_s1 { + int v1; +}; // COMPLIANT + +struct only_test1_s1 { + int v1; +}; // COMPLIANT + +struct only_test2_s1 { + int v1; +}; // COMPLIANT + +struct only_test2_s2 { + int v1; +}; // NON_COMPLIANT + +union shared_u1 { + int v1; + float v2; +}; // NON_COMPLIANT + +union shared_u2 { + int v1; + float v2; +}; // COMPLIANT +#endif // TEST_SHARED_H_ \ No newline at end of file diff --git a/c/misra/test/rules/RULE-8-13/PointerShouldPointToConstTypeWhenPossible.expected b/c/misra/test/rules/RULE-8-13/PointerShouldPointToConstTypeWhenPossible.expected new file mode 100644 index 0000000000..39dbf04763 --- /dev/null +++ b/c/misra/test/rules/RULE-8-13/PointerShouldPointToConstTypeWhenPossible.expected @@ -0,0 +1,14 @@ +| test.c:1:13:1:13 | p | $@ points to a non-const-qualified type. | test.c:1:13:1:13 | p | p | +| test.c:9:19:9:19 | p | $@ points to a non-const-qualified type. | test.c:9:19:9:19 | p | p | +| test.c:13:12:13:12 | a | $@ points to a non-const-qualified type. | test.c:13:12:13:12 | a | a | +| test.c:28:8:28:9 | v1 | $@ points to a non-const-qualified type. | test.c:28:8:28:9 | v1 | v1 | +| test.c:33:8:33:9 | v1 | $@ points to a non-const-qualified type. | test.c:33:8:33:9 | v1 | v1 | +| test.c:34:8:34:9 | v2 | $@ points to a non-const-qualified type. | test.c:34:8:34:9 | v2 | v2 | +| test.c:48:14:48:15 | p1 | $@ points to a non-const-qualified type. | test.c:48:14:48:15 | p1 | p1 | +| test.c:52:17:52:18 | p1 | $@ points to a non-const-qualified type. | test.c:52:17:52:18 | p1 | p1 | +| test.c:56:29:56:30 | p1 | $@ points to a non-const-qualified type. | test.c:56:29:56:30 | p1 | p1 | +| test.c:60:17:60:18 | p1 | $@ points to a non-const-qualified type. | test.c:60:17:60:18 | p1 | p1 | +| test.c:62:9:62:10 | v2 | $@ points to a non-const-qualified type. | test.c:62:9:62:10 | v2 | v2 | +| test.c:66:23:66:24 | p1 | $@ points to a non-const-qualified type. | test.c:66:23:66:24 | p1 | p1 | +| test.c:71:17:71:18 | p1 | $@ points to a non-const-qualified type. | test.c:71:17:71:18 | p1 | p1 | +| test.c:75:15:75:16 | p1 | $@ points to a non-const-qualified type. | test.c:75:15:75:16 | p1 | p1 | diff --git a/c/misra/test/rules/RULE-8-13/PointerShouldPointToConstTypeWhenPossible.qlref b/c/misra/test/rules/RULE-8-13/PointerShouldPointToConstTypeWhenPossible.qlref new file mode 100644 index 0000000000..999c9a826b --- /dev/null +++ b/c/misra/test/rules/RULE-8-13/PointerShouldPointToConstTypeWhenPossible.qlref @@ -0,0 +1 @@ +rules/RULE-8-13/PointerShouldPointToConstTypeWhenPossible.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-8-13/test.c b/c/misra/test/rules/RULE-8-13/test.c new file mode 100644 index 0000000000..1ac9e5028c --- /dev/null +++ b/c/misra/test/rules/RULE-8-13/test.c @@ -0,0 +1,78 @@ +int f1(int *p) { // NON_COMPLIANT + return *p; +} + +int f2(const int *p) { // COMPLIANT + return *p; +} + +int f3(int *const p) { // NON_COMPLIANT + return *p; +} + +int f4(int a[5]) { // NON_COMPLIANT + int b = a[0]; + return b; +} + +int f5(const int a[5]) { // COMPLIANT + return a[0]; +} + +int f6(int a[5]) { // COMPLIANT + a[2] = a[1]; + return a[0]; +} + +int f7(int *p1) { // COMPLIANT + int *v1 = p1; // NON_COMPLIANT + return v1[0]; +} + +int f8(int *p1) { // COMPLIANT + int *v1 = 0; // NON_COMPLIANT + int *v2 = p1; // NON_COMPLIANT + return v1[0]; +} + +int f9(int *p1) { // COMPLIANT + int *v1 = p1; // COMPLIANT + *v1 = 0; + return v1[0]; +} + +int f10(int *p1) { // COMPLIANT + return f8(p1); +} + +int f11(int *p1) { // NON_COMPLIANT + return f2(p1); +} + +char *f12(char *p1) { // NON_COMPLIANT + return p1; +} + +char *const f13(char *const p1) { // NON_COMPLIANT + return p1; +} + +char *f14(char *p1) { // NON_COMPLIANT + int v1 = p1[0] + 1; + char *v2 = 0; // NON_COMPLIANT + return v2; +} + +const char *f15(char *p1) { // NON_COMPLIANT + const char *v1 = p1; // COMPLIANT + return v1; +} + +char *f16(char *p1) { // NON_COMPLIANT + return ++p1; +} + +int f17(char *p1) { // NON_COMPLIANT + p1++; + return 0; +} \ No newline at end of file diff --git a/cpp/autosar/src/qlpack.yml b/cpp/autosar/src/qlpack.yml index 2d991b16e4..5dc89f303b 100644 --- a/cpp/autosar/src/qlpack.yml +++ b/cpp/autosar/src/qlpack.yml @@ -1,4 +1,4 @@ name: autosar-cpp-coding-standards -version: 2.4.0 +version: 2.5.0 suites: codeql-suites libraryPathDependencies: common-cpp-coding-standards diff --git a/cpp/autosar/src/rules/A5-0-3/DeclarationContainLessThanTwoLevelsOfIndirection.ql b/cpp/autosar/src/rules/A5-0-3/DeclarationContainLessThanTwoLevelsOfIndirection.ql index 993621c9ee..ddd996db5a 100644 --- a/cpp/autosar/src/rules/A5-0-3/DeclarationContainLessThanTwoLevelsOfIndirection.ql +++ b/cpp/autosar/src/rules/A5-0-3/DeclarationContainLessThanTwoLevelsOfIndirection.ql @@ -17,29 +17,10 @@ import cpp import codingstandards.cpp.autosar +import codingstandards.cpp.rules.donotusemorethantwolevelsofpointerindirection.DoNotUseMoreThanTwoLevelsOfPointerIndirection -Type getBaseType(DerivedType t) { result = t.getBaseType() } - -int levelsOfIndirection(Type t) { - if t instanceof FunctionPointerType - then result = t.(FunctionPointerType).getReturnType().getPointerIndirectionLevel() - else result = t.getPointerIndirectionLevel() -} - -int paramLevelsOfIndirection(Type t) { - if t instanceof ArrayType - then result = 1 + levelsOfIndirection(t.(ArrayType).getBaseType()) - else result = levelsOfIndirection(t) +class DeclarationContainLessThanTwoLevelsOfIndirectionQuery extends DoNotUseMoreThanTwoLevelsOfPointerIndirectionSharedQuery { + DeclarationContainLessThanTwoLevelsOfIndirectionQuery() { + this = PointersPackage::declarationContainLessThanTwoLevelsOfIndirectionQuery() + } } - -from Variable v, Type type -where - not isExcluded(v, PointersPackage::declarationContainLessThanTwoLevelsOfIndirectionQuery()) and - type = getBaseType*(v.getType()) and - ( - if v instanceof Parameter - then paramLevelsOfIndirection(type) > 2 - else levelsOfIndirection(type) > 2 - ) -select v, - "The declaration of " + v.getName() + " contain more than two levels of pointer indirection." diff --git a/cpp/autosar/src/rules/M5-0-15/IndexingNotTheOnlyFormOfPointerArithmetic.ql b/cpp/autosar/src/rules/M5-0-15/IndexingNotTheOnlyFormOfPointerArithmetic.ql index d6a7f7f20e..ab545a5225 100644 --- a/cpp/autosar/src/rules/M5-0-15/IndexingNotTheOnlyFormOfPointerArithmetic.ql +++ b/cpp/autosar/src/rules/M5-0-15/IndexingNotTheOnlyFormOfPointerArithmetic.ql @@ -16,49 +16,10 @@ import cpp import codingstandards.cpp.autosar -import semmle.code.cpp.dataflow.DataFlow +import codingstandards.cpp.rules.useonlyarrayindexingforpointerarithmetic.UseOnlyArrayIndexingForPointerArithmetic -class ArrayToArrayBaseConfig extends DataFlow::Configuration { - ArrayToArrayBaseConfig() { this = "ArrayToArrayBaseConfig" } - - override 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()) +class IndexingNotTheOnlyFormOfPointerArithmeticQuery extends UseOnlyArrayIndexingForPointerArithmeticSharedQuery { + IndexingNotTheOnlyFormOfPointerArithmeticQuery() { + this = PointersPackage::indexingNotTheOnlyFormOfPointerArithmeticQuery() } } - -predicate hasPointerResult(PointerArithmeticOperation op) { - op instanceof PointerAddExpr - or - op instanceof PointerSubExpr -} - -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())) - ) and - not exists(Variable v | - v.getAnAssignedValue().getType() instanceof ArrayType and - arrayExpr.getArrayBase() = v.getAnAccess() - ) -} - -from Expr e -where - not isExcluded(e, PointersPackage::indexingNotTheOnlyFormOfPointerArithmeticQuery()) and - ( - hasPointerResult(e) - or - shouldBeArray(e) - ) and - not e.isAffectedByMacro() -select e, - "Use of pointer arithmetic other than array indexing or indexing pointer not declared as an array." diff --git a/cpp/autosar/src/rules/M5-0-16/PointerAndDerivedPointerAccessDifferentArray.ql b/cpp/autosar/src/rules/M5-0-16/PointerAndDerivedPointerAccessDifferentArray.ql index f7361d9edb..8cbacf949f 100644 --- a/cpp/autosar/src/rules/M5-0-16/PointerAndDerivedPointerAccessDifferentArray.ql +++ b/cpp/autosar/src/rules/M5-0-16/PointerAndDerivedPointerAccessDifferentArray.ql @@ -15,170 +15,10 @@ import cpp import codingstandards.cpp.autosar -import semmle.code.cpp.dataflow.DataFlow -import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis +import codingstandards.cpp.rules.donotusepointerarithmetictoaddressdifferentarrays.DoNotUsePointerArithmeticToAddressDifferentArrays -/** - * 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) { - source.asExpr().(VariableAccess).getType() instanceof ArrayType - } - - override predicate isSink(DataFlow::Node sink) { - exists(ArrayExpr c | c.getArrayBase() = sink.asExpr()) - } -} - -/** 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 - index = lowerBound(ae.getArrayOffset().getFullyConverted()) and - addressOf.getOperand() = ae - ) -} - -/** A variable that points to an element of an array. */ -class PointerOperand extends Variable { - Variable array; - int arraySize; - int index; - AddressOfExpr source; - - PointerOperand() { - pointerOperandCreation(source, array, arraySize, index) and - this.getAnAssignedValue() = source - } - - Variable getArray() { result = array } - - int getArraySize() { result = arraySize } - - int getIndex() { result = index } - - AddressOfExpr getSource() { result = source } -} - -/** An derivation of a new pointer that differs by a constant amount. */ -class ConstantPointerAdjustment extends Expr { - int delta; - - ConstantPointerAdjustment() { - delta = this.(PointerAddExpr).getAnOperand().getValue().toInt() - or - delta = -this.(PointerSubExpr).getAnOperand().getValue().toInt() - or - this.(Operation).getAnOperand().getUnderlyingType() instanceof PointerType and - ( - delta = 0 and this instanceof PostfixCrementOperation - or - delta = 1 and this instanceof PrefixIncrExpr - or - delta = -1 and this instanceof PrefixDecrExpr - ) - or - this.(VariableAccess).getUnderlyingType() instanceof PointerType and delta = 0 - } - - int getDelta() { result = delta } - - VariableAccess getAdjusted() { - result = this - or - result = this.(Operation).getAnOperand() +class PointerAndDerivedPointerAccessDifferentArrayQuery extends DoNotUsePointerArithmeticToAddressDifferentArraysSharedQuery { + PointerAndDerivedPointerAccessDifferentArrayQuery() { + this = PointersPackage::pointerAndDerivedPointerAccessDifferentArrayQuery() } } - -/** Holds if `derivedPointer` is a new pointer created via an `adjustment` on `pointerOperand`. */ -predicate derivedPointer( - Variable derivedPointer, ConstantPointerAdjustment adjustment, - DerivedArrayPointerOrPointerOperand pointerOperand, int index -) { - adjustment.getAdjusted().getTarget() = pointerOperand and - index = pointerOperand.getIndex() + adjustment.getDelta() and - derivedPointer.getAnAssignedValue() = adjustment -} - -/** - * A pointer to an array that is derived from another pointer to an array through a constant adjustment. - * The new pointer may or may not point to the same array. - */ -class DerivedArrayPointer extends Variable { - DerivedArrayPointerOrPointerOperand operand; - int index; - ConstantPointerAdjustment source; - - DerivedArrayPointer() { derivedPointer(this, source, operand, index) } - - Variable getArray() { result = operand.getArray() } - - int getArraySize() { result = operand.getArraySize() } - - int getIndex() { result = index } - - ConstantPointerAdjustment getSource() { result = source } -} - -/** - * A pointer to an element of array created by taking the address of an array element or - * created through a constant adjustment of a pointer to an array. - */ -class DerivedArrayPointerOrPointerOperand extends Variable { - DerivedArrayPointerOrPointerOperand() { - this instanceof DerivedArrayPointer - or - this instanceof PointerOperand - } - - Variable getArray() { - result = this.(DerivedArrayPointer).getArray() or result = this.(PointerOperand).getArray() - } - - int getArraySize() { - result = this.(DerivedArrayPointer).getArraySize() or - result = this.(PointerOperand).getArraySize() - } - - int getIndex() { - result = this.(DerivedArrayPointer).getIndex() or result = this.(PointerOperand).getIndex() - } - - Expr getSource() { - result = this.(DerivedArrayPointer).getSource() or result = this.(PointerOperand).getSource() - } -} - -from - Expr arrayPointerCreation, - DerivedArrayPointerOrPointerOperand derivedArrayPointerOrPointerOperand, Variable array, - int index, int arraySize, int difference, string denomination -where - not isExcluded(arrayPointerCreation, - PointersPackage::pointerAndDerivedPointerAccessDifferentArrayQuery()) and - array = derivedArrayPointerOrPointerOperand.getArray() and - arraySize = derivedArrayPointerOrPointerOperand.getArraySize() and - index = derivedArrayPointerOrPointerOperand.getIndex() and - arrayPointerCreation = derivedArrayPointerOrPointerOperand.getSource() and - difference = index - arraySize and - ( - difference = 1 and denomination = "element" - or - difference > 1 and denomination = "elements" - ) and - // Exclude the creation of pointers to an element of an array in loops. - // Our range analysis will typically resort to widening resulting in - // possible false positives. - not exists(Loop loop | - arrayPointerCreation.getEnclosingBlock().getEnclosingBlock*() = loop.getStmt() - ) -select arrayPointerCreation, - "Array pointer " + derivedArrayPointerOrPointerOperand.getName() + " points " + - (index - arraySize).toString() + " " + denomination + " passed the end of $@.", array, - array.getName() diff --git a/cpp/autosar/src/rules/M5-0-18/AppliedToObjectsOfPointerType.ql b/cpp/autosar/src/rules/M5-0-18/AppliedToObjectsOfPointerType.ql index 1feac7770b..da6f82dd48 100644 --- a/cpp/autosar/src/rules/M5-0-18/AppliedToObjectsOfPointerType.ql +++ b/cpp/autosar/src/rules/M5-0-18/AppliedToObjectsOfPointerType.ql @@ -15,76 +15,10 @@ import cpp import codingstandards.cpp.autosar -import semmle.code.cpp.dataflow.DataFlow -import DataFlow::PathGraph +import codingstandards.cpp.rules.donotuserelationaloperatorswithdifferingarrays.DoNotUseRelationalOperatorsWithDifferingArrays -/** A source of arrays that can be used to start tracking data flow originating from an array. */ -abstract class ArraySource extends DataFlow::Node { } - -/** An access of an object of array type. */ -class ArrayAccess extends ArraySource { - ArrayAccess() { this.asExpr().(VariableAccess).getType() instanceof ArrayType } -} - -/** An access of an object of array type through a pointer that is the result of an array to pointer decay. */ -class DecayedArrayAccess extends ArraySource { - DecayedArrayAccess() { - exists(VariableAccess va | va = this.asExpr() | - va.getType() instanceof PointerType and - va.getTarget().(Parameter).getType() instanceof ArrayType - ) +class AppliedToObjectsOfPointerTypeQuery extends DoNotUseRelationalOperatorsWithDifferingArraysSharedQuery { + AppliedToObjectsOfPointerTypeQuery() { + this = PointersPackage::appliedToObjectsOfPointerTypeQuery() } } - -class ArrayToRelationalOperationOperandConfig extends DataFlow::Configuration { - ArrayToRelationalOperationOperandConfig() { this = "ArrayToRelationalOperationOperandConfig" } - - override predicate isSource(DataFlow::Node source) { source instanceof ArraySource } - - override predicate isSink(DataFlow::Node sink) { - exists(RelationalOperation op | op.getAnOperand() = sink.asExpr()) - } - - override 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()) - } -} - -predicate isComparingPointers(RelationalOperation op) { - forall(Expr operand | operand = op.getAnOperand() | - operand.getType() instanceof PointerType or operand.getType() instanceof ArrayType - ) -} - -from - RelationalOperation compare, DataFlow::PathNode source, DataFlow::PathNode sink, - Variable selectedOperandPointee, Variable otherOperandPointee, string side -where - not isExcluded(compare, PointersPackage::appliedToObjectsOfPointerTypeQuery()) and - exists(ArrayToRelationalOperationOperandConfig c, Variable sourceLeft, Variable sourceRight | - c.hasFlow(DataFlow::exprNode(sourceLeft.getAnAccess()), - DataFlow::exprNode(compare.getLeftOperand())) and - c.hasFlow(DataFlow::exprNode(sourceRight.getAnAccess()), - DataFlow::exprNode(compare.getRightOperand())) and - not sourceLeft = sourceRight and - isComparingPointers(compare) and - c.hasFlowPath(source, sink) and - ( - source.getNode().asExpr() = sourceLeft.getAnAccess() and - sink.getNode().asExpr() = compare.getLeftOperand() and - selectedOperandPointee = sourceLeft and - otherOperandPointee = sourceRight and - side = "left" - or - source.getNode().asExpr() = sourceRight.getAnAccess() and - sink.getNode().asExpr() = compare.getRightOperand() and - selectedOperandPointee = sourceRight and - otherOperandPointee = sourceLeft and - side = "right" - ) - ) -select compare, source, sink, - "Compare operation " + compare.getOperator() + " comparing " + side + - " operand pointing to array $@ and other operand pointing to array $@.", selectedOperandPointee, - selectedOperandPointee.getName(), otherOperandPointee, otherOperandPointee.getName() diff --git a/cpp/autosar/src/rules/M7-5-2/AssignmentOfEscapingAutoStorage.ql b/cpp/autosar/src/rules/M7-5-2/AssignmentOfEscapingAutoStorage.ql index a7cffc2c1c..def439ebae 100644 --- a/cpp/autosar/src/rules/M7-5-2/AssignmentOfEscapingAutoStorage.ql +++ b/cpp/autosar/src/rules/M7-5-2/AssignmentOfEscapingAutoStorage.ql @@ -15,47 +15,10 @@ import cpp import codingstandards.cpp.autosar -import semmle.code.cpp.dataflow.StackAddress +import codingstandards.cpp.rules.donotcopyaddressofautostorageobjecttootherobject.DoNotCopyAddressOfAutoStorageObjectToOtherObject -/* - * This is a variant of the `cpp/stack-address-escape` query, provided in the CodeQL C++ default - * query set, which enforces the stricter version of the rule required by MISRA. In particular, - * MISRA requires that stack addresses are never assigned to other stack variables with a wider - * scope, even if the address never leaks from the function itself. - */ - -/** - * Find assignments where the rhs might be a stack pointer and the lhs is - * not a stack variable. Such assignments might allow a stack address to - * escape. - */ -predicate stackAddressEscapes(AssignExpr assignExpr, Expr source, boolean isLocal) { - stackPointerFlowsToUse(assignExpr.getRValue(), _, source, isLocal) and - ( - // Not assigned to a StackVariable - not stackReferenceFlowsToUse(assignExpr.getLValue(), _, _, _) - or - // Assigned to a StackVariable with wider scope - exists(StackVariable rvalueVar, StackVariable lvalueVar, Expr lvalueSource | - // Restrict to local variables - stackReferenceFlowsToUse(assignExpr.getLValue(), _, lvalueSource, true) and - lvalueSource = lvalueVar.getAnAccess() and - source = rvalueVar.getAnAccess() and - lvalueVar.getParentScope() = rvalueVar.getParentScope().getParentScope+() - ) - ) +class AssignmentOfEscapingAutoStorageQuery extends DoNotCopyAddressOfAutoStorageObjectToOtherObjectSharedQuery { + AssignmentOfEscapingAutoStorageQuery() { + this = FreedPackage::assignmentOfEscapingAutoStorageQuery() + } } - -from Expr use, Expr source, boolean isLocal, string msg, string srcStr -where - not isExcluded(use, FreedPackage::assignmentOfEscapingAutoStorageQuery()) and - stackAddressEscapes(use, source, isLocal) and - if isLocal = true - then ( - msg = "A stack address ($@) may be assigned to a non-local variable." and - srcStr = "source" - ) else ( - msg = "A stack address which arrived via a $@ may be assigned to a non-local variable." and - srcStr = "parameter" - ) -select use, msg, source, srcStr diff --git a/cpp/autosar/test/qlpack.yml b/cpp/autosar/test/qlpack.yml index 1c37efaa14..3c06034525 100644 --- a/cpp/autosar/test/qlpack.yml +++ b/cpp/autosar/test/qlpack.yml @@ -1,4 +1,4 @@ name: autosar-cpp-coding-standards-tests -version: 2.4.0 +version: 2.5.0 libraryPathDependencies: autosar-cpp-coding-standards extractor: cpp diff --git a/cpp/autosar/test/rules/A5-0-3/DeclarationContainLessThanTwoLevelsOfIndirection.qlref b/cpp/autosar/test/rules/A5-0-3/DeclarationContainLessThanTwoLevelsOfIndirection.qlref deleted file mode 100644 index 4a111ea67c..0000000000 --- a/cpp/autosar/test/rules/A5-0-3/DeclarationContainLessThanTwoLevelsOfIndirection.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/A5-0-3/DeclarationContainLessThanTwoLevelsOfIndirection.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A5-0-3/DeclarationContainLessThanTwoLevelsOfIndirection.testref b/cpp/autosar/test/rules/A5-0-3/DeclarationContainLessThanTwoLevelsOfIndirection.testref new file mode 100644 index 0000000000..3b46dca736 --- /dev/null +++ b/cpp/autosar/test/rules/A5-0-3/DeclarationContainLessThanTwoLevelsOfIndirection.testref @@ -0,0 +1 @@ +cpp/common/test/rules/donotusemorethantwolevelsofpointerindirection/DoNotUseMoreThanTwoLevelsOfPointerIndirection.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M5-0-15/IndexingNotTheOnlyFormOfPointerArithmetic.qlref b/cpp/autosar/test/rules/M5-0-15/IndexingNotTheOnlyFormOfPointerArithmetic.qlref deleted file mode 100644 index 9f82907969..0000000000 --- a/cpp/autosar/test/rules/M5-0-15/IndexingNotTheOnlyFormOfPointerArithmetic.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/M5-0-15/IndexingNotTheOnlyFormOfPointerArithmetic.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M5-0-15/IndexingNotTheOnlyFormOfPointerArithmetic.testref b/cpp/autosar/test/rules/M5-0-15/IndexingNotTheOnlyFormOfPointerArithmetic.testref new file mode 100644 index 0000000000..7028093516 --- /dev/null +++ b/cpp/autosar/test/rules/M5-0-15/IndexingNotTheOnlyFormOfPointerArithmetic.testref @@ -0,0 +1 @@ +cpp/common/test/rules/useonlyarrayindexingforpointerarithmetic/UseOnlyArrayIndexingForPointerArithmetic.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M5-0-16/PointerAndDerivedPointerAccessDifferentArray.qlref b/cpp/autosar/test/rules/M5-0-16/PointerAndDerivedPointerAccessDifferentArray.qlref deleted file mode 100644 index 67d173065d..0000000000 --- a/cpp/autosar/test/rules/M5-0-16/PointerAndDerivedPointerAccessDifferentArray.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/M5-0-16/PointerAndDerivedPointerAccessDifferentArray.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M5-0-16/PointerAndDerivedPointerAccessDifferentArray.testref b/cpp/autosar/test/rules/M5-0-16/PointerAndDerivedPointerAccessDifferentArray.testref new file mode 100644 index 0000000000..d1fb78cb6d --- /dev/null +++ b/cpp/autosar/test/rules/M5-0-16/PointerAndDerivedPointerAccessDifferentArray.testref @@ -0,0 +1 @@ +cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M5-0-17/PointerSubtractionOnDifferentArrays.qlref b/cpp/autosar/test/rules/M5-0-17/PointerSubtractionOnDifferentArrays.qlref deleted file mode 100644 index bccc5af6d5..0000000000 --- a/cpp/autosar/test/rules/M5-0-17/PointerSubtractionOnDifferentArrays.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/M5-0-17/PointerSubtractionOnDifferentArrays.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M5-0-17/PointerSubtractionOnDifferentArrays.testref b/cpp/autosar/test/rules/M5-0-17/PointerSubtractionOnDifferentArrays.testref new file mode 100644 index 0000000000..6506d7bed1 --- /dev/null +++ b/cpp/autosar/test/rules/M5-0-17/PointerSubtractionOnDifferentArrays.testref @@ -0,0 +1 @@ +cpp/common/test/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M5-0-18/AppliedToObjectsOfPointerType.qlref b/cpp/autosar/test/rules/M5-0-18/AppliedToObjectsOfPointerType.qlref deleted file mode 100644 index e7b3d467fb..0000000000 --- a/cpp/autosar/test/rules/M5-0-18/AppliedToObjectsOfPointerType.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/M5-0-18/AppliedToObjectsOfPointerType.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M5-0-18/AppliedToObjectsOfPointerType.testref b/cpp/autosar/test/rules/M5-0-18/AppliedToObjectsOfPointerType.testref new file mode 100644 index 0000000000..5ca71e38c8 --- /dev/null +++ b/cpp/autosar/test/rules/M5-0-18/AppliedToObjectsOfPointerType.testref @@ -0,0 +1 @@ +cpp/common/test/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M7-5-2/AssignmentOfEscapingAutoStorage.qlref b/cpp/autosar/test/rules/M7-5-2/AssignmentOfEscapingAutoStorage.qlref deleted file mode 100644 index 01e3863eab..0000000000 --- a/cpp/autosar/test/rules/M7-5-2/AssignmentOfEscapingAutoStorage.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/M7-5-2/AssignmentOfEscapingAutoStorage.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M7-5-2/AssignmentOfEscapingAutoStorage.testref b/cpp/autosar/test/rules/M7-5-2/AssignmentOfEscapingAutoStorage.testref new file mode 100644 index 0000000000..fc0808753a --- /dev/null +++ b/cpp/autosar/test/rules/M7-5-2/AssignmentOfEscapingAutoStorage.testref @@ -0,0 +1 @@ +cpp/common/test/rules/donotcopyaddressofautostorageobjecttootherobject/DoNotCopyAddressOfAutoStorageObjectToOtherObject.ql \ No newline at end of file diff --git a/cpp/cert/src/qlpack.yml b/cpp/cert/src/qlpack.yml index b7f113b391..5bb13a8d4e 100644 --- a/cpp/cert/src/qlpack.yml +++ b/cpp/cert/src/qlpack.yml @@ -1,4 +1,4 @@ name: cert-cpp-coding-standards -version: 2.4.0 +version: 2.5.0 suites: codeql-suites libraryPathDependencies: common-cpp-coding-standards diff --git a/cpp/cert/src/rules/CON52-CPP/PreventBitFieldAccessFromMultipleThreads-standard.qhelp b/cpp/cert/src/rules/CON52-CPP/PreventBitFieldAccessFromMultipleThreads-standard.qhelp new file mode 100644 index 0000000000..ba5eaadab1 --- /dev/null +++ b/cpp/cert/src/rules/CON52-CPP/PreventBitFieldAccessFromMultipleThreads-standard.qhelp @@ -0,0 +1,33 @@ + + +
    +
      +
    • required
    • +
    • implementation
    • +
    • automated
    • +
    +
    + +
    +

    + ... +

    + +
    + +
    +

    + ... +

    +
    + + + + + +
    +
      +
    • ...
    • +
    +
    +
    \ No newline at end of file diff --git a/cpp/cert/src/rules/CON52-CPP/PreventDataRacesWhenAccessingBitFieldsFromMultipleThreads.qhelp b/cpp/cert/src/rules/CON52-CPP/PreventBitFieldAccessFromMultipleThreads.qhelp similarity index 86% rename from cpp/cert/src/rules/CON52-CPP/PreventDataRacesWhenAccessingBitFieldsFromMultipleThreads.qhelp rename to cpp/cert/src/rules/CON52-CPP/PreventBitFieldAccessFromMultipleThreads.qhelp index ba85c19d8d..6d31f23026 100644 --- a/cpp/cert/src/rules/CON52-CPP/PreventDataRacesWhenAccessingBitFieldsFromMultipleThreads.qhelp +++ b/cpp/cert/src/rules/CON52-CPP/PreventBitFieldAccessFromMultipleThreads.qhelp @@ -7,7 +7,7 @@

    Prevent data races when accessing bit-fields from multiple threads

    - +
  • CERT-C++: diff --git a/cpp/cert/src/rules/CON52-CPP/PreventBitFieldAccessFromMultipleThreads.ql b/cpp/cert/src/rules/CON52-CPP/PreventBitFieldAccessFromMultipleThreads.ql new file mode 100644 index 0000000000..49d5309113 --- /dev/null +++ b/cpp/cert/src/rules/CON52-CPP/PreventBitFieldAccessFromMultipleThreads.ql @@ -0,0 +1,23 @@ +/** + * @id cpp/cert/prevent-bit-field-access-from-multiple-threads + * @name CON52-CPP: Prevent data races when accessing bit-fields from multiple threads + * @description Accesses to bit fields without proper concurrency protection can result in data + * races. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/cert/id/con52-cpp + * correctness + * concurrency + * external/cert/obligation/rule + */ + +import cpp +import codingstandards.cpp.cert +import codingstandards.cpp.rules.guardaccesstobitfields.GuardAccessToBitFields + +class PreventBitFieldAccessFromMultipleThreadsQuery extends GuardAccessToBitFieldsSharedQuery { + PreventBitFieldAccessFromMultipleThreadsQuery() { + this = ConcurrencyPackage::preventBitFieldAccessFromMultipleThreadsQuery() + } +} diff --git a/cpp/cert/src/rules/CON52-CPP/PreventDataRacesWhenAccessingBitFieldsFromMultipleThreads-standard.qhelp b/cpp/cert/src/rules/CON52-CPP/PreventDataRacesWhenAccessingBitFieldsFromMultipleThreads-standard.qhelp deleted file mode 100644 index 742e22be15..0000000000 --- a/cpp/cert/src/rules/CON52-CPP/PreventDataRacesWhenAccessingBitFieldsFromMultipleThreads-standard.qhelp +++ /dev/null @@ -1,302 +0,0 @@ - - -
    -

    When accessing a bit-field, a thread may inadvertently access a separate bit-field in adjacent memory. This is because compilers are required to store multiple adjacent bit-fields in one storage unit whenever they fit. Consequently, data races may exist not just on a bit-field accessed by multiple threads but also on other bit-fields sharing the same byte or word. The problem is difficult to diagnose because it may not be obvious that the same memory location is being modified by multiple threads.

    -

    One approach for preventing data races in concurrent programming is to use a mutex. When properly observed by all threads, a mutex can provide safe and secure access to a shared object. However, mutexes provide no guarantees with regard to other objects that might be accessed when the mutex is not controlled by the accessing thread. Unfortunately, there is no portable way to determine which adjacent bit-fields may be stored along with the desired bit-field.

    -

    Another approach is to insert a non-bit-field member between any two bit-fields to ensure that each bit-field is the only one accessed within its storage unit. This technique effectively guarantees that no two bit-fields are accessed simultaneously.

    -
    -
    -

    Adjacent bit-fields may be stored in a single memory location. Consequently, modifying adjacent bit-fields in different threads is undefined behavior, as shown in this noncompliant code example.

    - struct MultiThreadedFlags { - unsigned int flag1 : 2; - unsigned int flag2 : 2; -}; - -MultiThreadedFlags flags; - -void thread1() { - flags.flag1 = 1; -} - -void thread2() { - flags.flag2 = 2; -} - -

    For example, the following instruction sequence is possible.

    - Thread 1: register 0 = flags -Thread 1: register 0 &= ~mask(flag1) -Thread 2: register 0 = flags -Thread 2: register 0 &= ~mask(flag2) -Thread 1: register 0 |= 1 << shift(flag1) -Thread 1: flags = register 0 -Thread 2: register 0 |= 2 << shift(flag2) -Thread 2: flags = register 0 -
    -
    -

    This compliant solution protects all accesses of the flags with a mutex, thereby preventing any data races.

    - #include <mutex> - -struct MultiThreadedFlags { - unsigned int flag1 : 2; - unsigned int flag2 : 2; -}; - -struct MtfMutex { - MultiThreadedFlags s; - std::mutex mutex; -}; - -MtfMutex flags; - -void thread1() { - std::lock_guard<std::mutex> lk(flags.mutex); - flags.s.flag1 = 1; -} - -void thread2() { - std::lock_guard<std::mutex> lk(flags.mutex); - flags.s.flag2 = 2; -} - -
    -
    -

    In this compliant solution, two threads simultaneously modify two distinct non-bit-field members of a structure. Because the members occupy different bytes in memory, no concurrency protection is required.

    - struct MultiThreadedFlags { - unsigned char flag1; - unsigned char flag2; -}; - -MultiThreadedFlags flags; - -void thread1() { - flags.flag1 = 1; -} - -void thread2() { - flags.flag2 = 2; -} -

    Unlike earlier versions of the standard, C++11 and later explicitly define a memory location and provide the following note in [intro.memory] paragraph 4 [ISO/IEC 14882-2014]:

    -
    -

    [Note: Thus a bit-field and an adjacent non-bit-field are in separate memory locations, and therefore can be concurrently updated by two threads of execution without interference. The same applies to two bit-fields, if one is declared inside a nested struct declaration and the other is not, or if the two are separated by a zero-length bit-field declaration, or if they are separated by a non-bit-field declaration. It is not safe to concurrently update two bit-fields in the same struct if all fields between them are also bit-fields of non-zero width. – end note]

    -
    -

    It is almost certain that flag1 and flag2 are stored in the same word. Using a compiler that conforms to earlier versions of the standard, if both assignments occur on a thread-scheduling interleaving that ends with both stores occurring after one another, it is possible that only one of the flags will be set as intended, and the other flag will contain its previous value because both members are represented by the same word, which is the smallest unit the processor can work on. Before the changes made to the C++ Standard for C++11, there were no guarantees that these flags could be modified concurrently.

    -
    -
    -

    Although the race window is narrow, an assignment or an expression can evaluate improperly because of misinterpreted data resulting in a corrupted running state or unintended information disclosure.

    - - - - - - - - - - - - - - - - - - - -
    - Rule - - Severity - - Likelihood - - Remediation Cost - - Priority - - Level -
    - CON52-CPP - - Medium - - Probable - - Medium - - P8 - - L2 -
    -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - Tool - - Version - - Checker - - Description -
    - - Astrée - - - 20.10 - - read_write_data_racewrite_write_data_race - - Supported -
    - - Axivion Bauhaus Suite - - - 7.2.0 - - CertC++-CON52 - -
    - - Coverity - - - 6.5 - - RACE_CONDITION - - Fully implemented -
    - - Helix QAC - - - 2021.2 - - C++1774, C++1775 - -
    - - Parasoft C/C++test - - - 2021.2 - - CERT_CPP-CON52-a - - Use locks to prevent race conditions when modifying bit fields -
    - - Polyspace Bug Finder - - - R2021b - - - CERT C++: CON52-CPP - - - Checks for data races (rule partially covered) -
    - - PRQA QA-C++ - - - 4.4 - - 1774, 1775 - - Enforced by MTA -
    -
    -
    -

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    -
    -
    - - - - - - - -
    - - SEI CERT C Coding Standard - - - - CON32-C. Prevent data races when accessing bit-fields from multiple threads - -
    -
    -
    - - - - - - - -
    - [ - - ISO/IEC 14882-2014 - - ] - - Subclause 1.7, "The C++ memory model" -
    -
    -
    \ No newline at end of file diff --git a/cpp/cert/src/rules/CON52-CPP/standard-example.cpp b/cpp/cert/src/rules/CON52-CPP/standard-example.cpp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/cpp/cert/src/rules/CTR56-CPP/standard-example.cpp b/cpp/cert/src/rules/CTR56-CPP/standard-example.cpp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/cpp/cert/src/rules/EXP51-CPP/standard-example.cpp b/cpp/cert/src/rules/EXP51-CPP/standard-example.cpp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/cpp/cert/src/rules/EXP54-CPP/standard-example.cpp b/cpp/cert/src/rules/EXP54-CPP/standard-example.cpp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/cpp/cert/src/rules/EXP57-CPP/standard-example.cpp b/cpp/cert/src/rules/EXP57-CPP/standard-example.cpp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/cpp/cert/src/rules/MEM50-CPP/standard-example.cpp b/cpp/cert/src/rules/MEM50-CPP/standard-example.cpp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/cpp/cert/src/rules/OOP55-CPP/standard-example.cpp b/cpp/cert/src/rules/OOP55-CPP/standard-example.cpp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/cpp/cert/test/qlpack.yml b/cpp/cert/test/qlpack.yml index f212d1000d..eec77e3e7b 100644 --- a/cpp/cert/test/qlpack.yml +++ b/cpp/cert/test/qlpack.yml @@ -1,4 +1,4 @@ name: cert-cpp-coding-standards-tests -version: 2.4.0 +version: 2.5.0 libraryPathDependencies: cert-cpp-coding-standards extractor: cpp diff --git a/cpp/cert/test/rules/CON52-CPP/PreventBitFieldAccessFromMultipleThreads.testref b/cpp/cert/test/rules/CON52-CPP/PreventBitFieldAccessFromMultipleThreads.testref new file mode 100644 index 0000000000..493486ecb2 --- /dev/null +++ b/cpp/cert/test/rules/CON52-CPP/PreventBitFieldAccessFromMultipleThreads.testref @@ -0,0 +1 @@ +cpp/common/test/rules/guardaccesstobitfields/GuardAccessToBitFields.ql \ No newline at end of file diff --git a/cpp/cert/test/rules/CON52-CPP/PreventDataRacesWhenAccessingBitFieldsFromMultipleThreads.qlref b/cpp/cert/test/rules/CON52-CPP/PreventDataRacesWhenAccessingBitFieldsFromMultipleThreads.qlref deleted file mode 100644 index 8bddb1ca72..0000000000 --- a/cpp/cert/test/rules/CON52-CPP/PreventDataRacesWhenAccessingBitFieldsFromMultipleThreads.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/CON52-CPP/PreventDataRacesWhenAccessingBitFieldsFromMultipleThreads.ql \ 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 0f76960661..a7234d601e 100644 --- a/cpp/common/src/codingstandards/cpp/Concurrency.qll +++ b/cpp/common/src/codingstandards/cpp/Concurrency.qll @@ -1,9 +1,37 @@ import cpp +import semmle.code.cpp.dataflow.TaintTracking + +/** + * Models CFG nodes which should be added to a thread context. + */ +abstract class ThreadedCFGPathExtension extends ControlFlowNode { + /** + * Returns the next `ControlFlowNode` in this thread context. + */ + abstract ControlFlowNode getNext(); +} + +/** + * Models a `FunctionCall` invoked from a threaded context. + */ +class ThreadContextFunctionCall extends FunctionCall, ThreadedCFGPathExtension { + override ControlFlowNode getNext() { getTarget().getEntryPoint() = result } +} + +/** + * Models a specialized `FunctionCall` that may create a thread. + */ +abstract class ThreadCreationFunction extends FunctionCall, ThreadedCFGPathExtension { + /** + * Returns the function that will be invoked. + */ + abstract Function getFunction(); +} /** * Models a call to a thread constructor via `std::thread`. */ -class ThreadConstructorCall extends ConstructorCall { +class ThreadConstructorCall extends ConstructorCall, ThreadCreationFunction { Function f; ThreadConstructorCall() { @@ -14,21 +42,58 @@ class ThreadConstructorCall extends ConstructorCall { /** * Returns the function that will be invoked by this `std::thread`. */ - Function getFunction() { result = f } + override Function getFunction() { result = f } + + override ControlFlowNode getNext() { result = getFunction().getEntryPoint() } +} + +/** + * Models a call to a thread constructor via `std::thread`. + */ +class C11ThreadCreateCall extends ThreadCreationFunction { + Function f; + + C11ThreadCreateCall() { + getTarget().getName() = "thrd_create" and + ( + f = getArgument(1).(FunctionAccess).getTarget() or + f = getArgument(1).(AddressOfExpr).getOperand().(FunctionAccess).getTarget() + ) + } + + /** + * Returns the function that will be invoked by this thread. + */ + override Function getFunction() { result = f } + + override ControlFlowNode getNext() { result = getFunction().getEntryPoint() } } /** - * Models calls to various mutex types. + * Common base class providing an interface into function call + * based mutex locks. */ -class MutexFunctionCall extends LockingOperation { +abstract class MutexFunctionCall extends LockingOperation { + abstract predicate isRecursive(); + + abstract predicate isSpeculativeLock(); + + abstract predicate unlocks(MutexFunctionCall fc); +} + +/** + * Models calls to various mutex types found in CPP. + */ +class CPPMutexFunctionCall extends MutexFunctionCall { VariableAccess var; - MutexFunctionCall() { - // the non recursive kinds + CPPMutexFunctionCall() { ( + // the non recursive kinds getTarget().(MemberFunction).getDeclaringType().hasQualifiedName("std", "mutex") or getTarget().(MemberFunction).getDeclaringType().hasQualifiedName("std", "timed_mutex") or getTarget().(MemberFunction).getDeclaringType().hasQualifiedName("std", "shared_timed_mutex") or + // the recursive ones getTarget().(MemberFunction).getDeclaringType().hasQualifiedName("std", "recursive_mutex") or getTarget() .(MemberFunction) @@ -41,40 +106,41 @@ class MutexFunctionCall extends LockingOperation { /** * Holds if this mutex is a recursive mutex. */ - predicate isRecursive() { + override predicate isRecursive() { getTarget().(MemberFunction).getDeclaringType().hasQualifiedName("std", "recursive_mutex") or getTarget().(MemberFunction).getDeclaringType().hasQualifiedName("std", "recursive_timed_mutex") } /** - * Holds if this `MutexFunctionCall` is a lock. + * Holds if this `CPPMutexFunctionCall` is a lock. */ override predicate isLock() { getTarget().getName() = "lock" } /** - * Holds if this `MutexFunctionCall` is a speculative lock, defined as calling + * Holds if this `CPPMutexFunctionCall` is a speculative lock, defined as calling * one of the speculative locking functions such as `try_lock`. */ - predicate isSpeculativeLock() { + override predicate isSpeculativeLock() { getTarget().getName() in [ "try_lock", "try_lock_for", "try_lock_until", "try_lock_shared_for", "try_lock_shared_until" ] } /** - * Returns the lock to which this `MutexFunctionCall` refers to. + * Returns the lock to which this `CPPMutexFunctionCall` refers to. */ override Variable getLock() { result = getQualifier().(VariableAccess).getTarget() } /** - * Returns the qualifier for this `MutexFunctionCall`. + * Returns the qualifier for this `CPPMutexFunctionCall`. */ override Expr getLockExpr() { result = var } /** - * Holds if this is a `unlock` and it unlocks the previously locked `MutexFunctionCall`. + * Holds if this is a `unlock` and *may* unlock the previously locked `MutexFunctionCall`. + * This predicate does not check that the mutex is currently locked. */ - predicate unlocks(MutexFunctionCall fc) { + override predicate unlocks(MutexFunctionCall fc) { isUnlock() and fc.getQualifier().(VariableAccess).getTarget() = getQualifier().(VariableAccess).getTarget() } @@ -85,6 +151,69 @@ class MutexFunctionCall extends LockingOperation { override predicate isUnlock() { getTarget().getName() = "unlock" } } +/** + * Models calls to various mutex types specialized to C code. + */ +class CMutexFunctionCall extends MutexFunctionCall { + Expr arg; + + CMutexFunctionCall() { + // the non recursive kinds + getTarget().getName() = ["mtx_lock", "mtx_unlock", "mtx_timedlock", "mtx_trylock"] and + arg = getArgument(0) + } + + /** + * Holds if this mutex is a recursive mutex. + */ + override predicate isRecursive() { none() } + + /** + * Holds if this `CMutexFunctionCall` is a lock. + */ + override predicate isLock() { + getTarget().getName() = ["mtx_lock", "mtx_timedlock", "mtx_trylock"] + } + + /** + * Holds if this `CMutexFunctionCall` is a speculative lock, defined as calling + * one of the speculative locking functions such as `try_lock`. + */ + override predicate isSpeculativeLock() { + getTarget().getName() in ["mtx_timedlock", "mtx_trylock"] + } + + /** + * Returns the `Variable` to which this `CMutexFunctionCall` refers to. For this + * style of lock it can reference a number of different variables. + */ + override Variable getLock() { + exists(VariableAccess va | + TaintTracking::localTaint(DataFlow::exprNode(va), DataFlow::exprNode(getLockExpr())) and + result = va.getTarget() + ) + } + + /** + * Returns the expression for this `CMutexFunctionCall`. + */ + override Expr getLockExpr() { result = arg } + + /** + * Holds if this is a `unlock` and *may* unlock the previously locked `CMutexFunctionCall`. + * This predicate does not check that the mutex is currently locked. + */ + override predicate unlocks(MutexFunctionCall fc) { + isUnlock() and + fc.getLock() = getLock() + } + + /** + * Holds if this is an unlock call. + */ + override predicate isUnlock() { getTarget().getName() = "mtx_unlock" } +} + /** * The thread-aware predecessor function is defined in terms of the thread aware * successor function. This is because it is simpler to construct the forward @@ -113,11 +242,7 @@ ControlFlowNode getAThreadContextAwarePredecessor(ControlFlowNode start, Control ControlFlowNode getAThreadContextAwareSuccessorR(ControlFlowNode cfn) { result = cfn.getASuccessor() or - cfn instanceof FunctionCall and - result = cfn.(FunctionCall).getTarget().getEntryPoint() - or - cfn instanceof ThreadConstructorCall and - result = cfn.(ThreadConstructorCall).getFunction().getEntryPoint() + result = cfn.(ThreadedCFGPathExtension).getNext() } ControlFlowNode getAThreadContextAwareSuccessor(ControlFlowNode m) { @@ -224,8 +349,22 @@ class RAIIStyleLock extends LockingOperation { /** * Models a function that may be executed by some thread. */ -class ThreadedFunction extends Function { - ThreadedFunction() { exists(ThreadConstructorCall tcc | tcc.getFunction() = this) } +abstract class ThreadedFunction extends Function { } + +/** + * Models a function that may be executed by some thread via + * C++ standard classes. + */ +class CPPThreadedFunction extends ThreadedFunction { + CPPThreadedFunction() { exists(ThreadConstructorCall tcc | tcc.getFunction() = this) } +} + +/** + * Models a function that may be executed by some thread via + * C11 standard functions. + */ +class C11ThreadedFunction extends ThreadedFunction { + C11ThreadedFunction() { exists(C11ThreadCreateCall cc | cc.getFunction() = this) } } /** diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Concurrency1.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Concurrency1.qll new file mode 100644 index 0000000000..7d49962781 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Concurrency1.qll @@ -0,0 +1,58 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype Concurrency1Query = + TPreventDataRacesWithMultipleThreadsQuery() or + TRaceConditionsWhenUsingLibraryFunctionsQuery() or + TDoNotCallSignalInMultithreadedProgramQuery() + +predicate isConcurrency1QueryMetadata(Query query, string queryId, string ruleId) { + query = + // `Query` instance for the `preventDataRacesWithMultipleThreads` query + Concurrency1Package::preventDataRacesWithMultipleThreadsQuery() and + queryId = + // `@id` for the `preventDataRacesWithMultipleThreads` query + "c/cert/prevent-data-races-with-multiple-threads" and + ruleId = "CON32-C" + or + query = + // `Query` instance for the `raceConditionsWhenUsingLibraryFunctions` query + Concurrency1Package::raceConditionsWhenUsingLibraryFunctionsQuery() and + queryId = + // `@id` for the `raceConditionsWhenUsingLibraryFunctions` query + "c/cert/race-conditions-when-using-library-functions" and + ruleId = "CON33-C" + or + query = + // `Query` instance for the `doNotCallSignalInMultithreadedProgram` query + Concurrency1Package::doNotCallSignalInMultithreadedProgramQuery() and + queryId = + // `@id` for the `doNotCallSignalInMultithreadedProgram` query + "c/cert/do-not-call-signal-in-multithreaded-program" and + ruleId = "CON37-C" +} + +module Concurrency1Package { + Query preventDataRacesWithMultipleThreadsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `preventDataRacesWithMultipleThreads` query + TQueryC(TConcurrency1PackageQuery(TPreventDataRacesWithMultipleThreadsQuery())) + } + + Query raceConditionsWhenUsingLibraryFunctionsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `raceConditionsWhenUsingLibraryFunctions` query + TQueryC(TConcurrency1PackageQuery(TRaceConditionsWhenUsingLibraryFunctionsQuery())) + } + + Query doNotCallSignalInMultithreadedProgramQuery() { + //autogenerate `Query` type + result = + // `Query` type for `doNotCallSignalInMultithreadedProgram` query + TQueryC(TConcurrency1PackageQuery(TDoNotCallSignalInMultithreadedProgramQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Pointers1.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Pointers1.qll new file mode 100644 index 0000000000..506e3a5fba --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Pointers1.qll @@ -0,0 +1,282 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype Pointers1Query = + TConversionBetweenFunctionPointerAndOtherTypeQuery() or + TConversionBetweenIncompleteTypePointerAndOtherTypeQuery() or + TCastBetweenObjectPointerAndDifferentObjectTypeQuery() or + TConversionBetweenPointerToObjectAndIntegerTypeQuery() or + TConversionFromPointerToVoidIntoPointerToObjectQuery() or + TCastBetweenPointerToVoidAndArithmeticTypeQuery() or + TCastBetweenPointerToObjectAndNonIntArithmeticTypeQuery() or + TCastRemovesConstOrVolatileQualificationQuery() or + TMacroNullNotUsedAsIntegerNullPointerConstantQuery() or + TPointerAndDerivedPointerMustAddressSameArrayQuery() or + TSubtractionBetweenPointersMustAddressSameArrayQuery() or + TRelationalOperatorComparesPointerToDifferentArrayQuery() or + TDoNotUseAdditionOrSubtractionOperatorsOnPointersQuery() or + TNoMoreThanTwoLevelsOfPointerNestingInDeclarationsQuery() or + TAutomaticStorageObjectAddressCopiedToOtherObjectQuery() or + TObjectWithNoPointerDereferenceShouldBeOpaqueQuery() or + TPointerShouldPointToConstTypeWhenPossibleQuery() + +predicate isPointers1QueryMetadata(Query query, string queryId, string ruleId) { + query = + // `Query` instance for the `conversionBetweenFunctionPointerAndOtherType` query + Pointers1Package::conversionBetweenFunctionPointerAndOtherTypeQuery() and + queryId = + // `@id` for the `conversionBetweenFunctionPointerAndOtherType` query + "c/misra/conversion-between-function-pointer-and-other-type" and + ruleId = "RULE-11-1" + or + query = + // `Query` instance for the `conversionBetweenIncompleteTypePointerAndOtherType` query + Pointers1Package::conversionBetweenIncompleteTypePointerAndOtherTypeQuery() and + queryId = + // `@id` for the `conversionBetweenIncompleteTypePointerAndOtherType` query + "c/misra/conversion-between-incomplete-type-pointer-and-other-type" and + ruleId = "RULE-11-2" + or + query = + // `Query` instance for the `castBetweenObjectPointerAndDifferentObjectType` query + Pointers1Package::castBetweenObjectPointerAndDifferentObjectTypeQuery() and + queryId = + // `@id` for the `castBetweenObjectPointerAndDifferentObjectType` query + "c/misra/cast-between-object-pointer-and-different-object-type" and + ruleId = "RULE-11-3" + or + query = + // `Query` instance for the `conversionBetweenPointerToObjectAndIntegerType` query + Pointers1Package::conversionBetweenPointerToObjectAndIntegerTypeQuery() and + queryId = + // `@id` for the `conversionBetweenPointerToObjectAndIntegerType` query + "c/misra/conversion-between-pointer-to-object-and-integer-type" and + ruleId = "RULE-11-4" + or + query = + // `Query` instance for the `conversionFromPointerToVoidIntoPointerToObject` query + Pointers1Package::conversionFromPointerToVoidIntoPointerToObjectQuery() and + queryId = + // `@id` for the `conversionFromPointerToVoidIntoPointerToObject` query + "c/misra/conversion-from-pointer-to-void-into-pointer-to-object" and + ruleId = "RULE-11-5" + or + query = + // `Query` instance for the `castBetweenPointerToVoidAndArithmeticType` query + Pointers1Package::castBetweenPointerToVoidAndArithmeticTypeQuery() and + queryId = + // `@id` for the `castBetweenPointerToVoidAndArithmeticType` query + "c/misra/cast-between-pointer-to-void-and-arithmetic-type" and + ruleId = "RULE-11-6" + or + query = + // `Query` instance for the `castBetweenPointerToObjectAndNonIntArithmeticType` query + Pointers1Package::castBetweenPointerToObjectAndNonIntArithmeticTypeQuery() and + queryId = + // `@id` for the `castBetweenPointerToObjectAndNonIntArithmeticType` query + "c/misra/cast-between-pointer-to-object-and-non-int-arithmetic-type" and + ruleId = "RULE-11-7" + or + query = + // `Query` instance for the `castRemovesConstOrVolatileQualification` query + Pointers1Package::castRemovesConstOrVolatileQualificationQuery() and + queryId = + // `@id` for the `castRemovesConstOrVolatileQualification` query + "c/misra/cast-removes-const-or-volatile-qualification" and + ruleId = "RULE-11-8" + or + query = + // `Query` instance for the `macroNullNotUsedAsIntegerNullPointerConstant` query + Pointers1Package::macroNullNotUsedAsIntegerNullPointerConstantQuery() and + queryId = + // `@id` for the `macroNullNotUsedAsIntegerNullPointerConstant` query + "c/misra/macro-null-not-used-as-integer-null-pointer-constant" and + ruleId = "RULE-11-9" + or + query = + // `Query` instance for the `pointerAndDerivedPointerMustAddressSameArray` query + Pointers1Package::pointerAndDerivedPointerMustAddressSameArrayQuery() and + queryId = + // `@id` for the `pointerAndDerivedPointerMustAddressSameArray` query + "c/misra/pointer-and-derived-pointer-must-address-same-array" and + ruleId = "RULE-18-1" + or + query = + // `Query` instance for the `subtractionBetweenPointersMustAddressSameArray` query + Pointers1Package::subtractionBetweenPointersMustAddressSameArrayQuery() and + queryId = + // `@id` for the `subtractionBetweenPointersMustAddressSameArray` query + "c/misra/subtraction-between-pointers-must-address-same-array" and + ruleId = "RULE-18-2" + or + query = + // `Query` instance for the `relationalOperatorComparesPointerToDifferentArray` query + Pointers1Package::relationalOperatorComparesPointerToDifferentArrayQuery() and + queryId = + // `@id` for the `relationalOperatorComparesPointerToDifferentArray` query + "c/misra/relational-operator-compares-pointer-to-different-array" and + ruleId = "RULE-18-3" + or + query = + // `Query` instance for the `doNotUseAdditionOrSubtractionOperatorsOnPointers` query + Pointers1Package::doNotUseAdditionOrSubtractionOperatorsOnPointersQuery() and + queryId = + // `@id` for the `doNotUseAdditionOrSubtractionOperatorsOnPointers` query + "c/misra/do-not-use-addition-or-subtraction-operators-on-pointers" and + ruleId = "RULE-18-4" + or + query = + // `Query` instance for the `noMoreThanTwoLevelsOfPointerNestingInDeclarations` query + Pointers1Package::noMoreThanTwoLevelsOfPointerNestingInDeclarationsQuery() and + queryId = + // `@id` for the `noMoreThanTwoLevelsOfPointerNestingInDeclarations` query + "c/misra/no-more-than-two-levels-of-pointer-nesting-in-declarations" and + ruleId = "RULE-18-5" + or + query = + // `Query` instance for the `automaticStorageObjectAddressCopiedToOtherObject` query + Pointers1Package::automaticStorageObjectAddressCopiedToOtherObjectQuery() and + queryId = + // `@id` for the `automaticStorageObjectAddressCopiedToOtherObject` query + "c/misra/automatic-storage-object-address-copied-to-other-object" and + ruleId = "RULE-18-6" + or + query = + // `Query` instance for the `objectWithNoPointerDereferenceShouldBeOpaque` query + Pointers1Package::objectWithNoPointerDereferenceShouldBeOpaqueQuery() and + queryId = + // `@id` for the `objectWithNoPointerDereferenceShouldBeOpaque` query + "c/misra/object-with-no-pointer-dereference-should-be-opaque" and + ruleId = "RULE-4-8" + or + query = + // `Query` instance for the `pointerShouldPointToConstTypeWhenPossible` query + Pointers1Package::pointerShouldPointToConstTypeWhenPossibleQuery() and + queryId = + // `@id` for the `pointerShouldPointToConstTypeWhenPossible` query + "c/misra/pointer-should-point-to-const-type-when-possible" and + ruleId = "RULE-8-13" +} + +module Pointers1Package { + Query conversionBetweenFunctionPointerAndOtherTypeQuery() { + //autogenerate `Query` type + result = + // `Query` type for `conversionBetweenFunctionPointerAndOtherType` query + TQueryC(TPointers1PackageQuery(TConversionBetweenFunctionPointerAndOtherTypeQuery())) + } + + Query conversionBetweenIncompleteTypePointerAndOtherTypeQuery() { + //autogenerate `Query` type + result = + // `Query` type for `conversionBetweenIncompleteTypePointerAndOtherType` query + TQueryC(TPointers1PackageQuery(TConversionBetweenIncompleteTypePointerAndOtherTypeQuery())) + } + + Query castBetweenObjectPointerAndDifferentObjectTypeQuery() { + //autogenerate `Query` type + result = + // `Query` type for `castBetweenObjectPointerAndDifferentObjectType` query + TQueryC(TPointers1PackageQuery(TCastBetweenObjectPointerAndDifferentObjectTypeQuery())) + } + + Query conversionBetweenPointerToObjectAndIntegerTypeQuery() { + //autogenerate `Query` type + result = + // `Query` type for `conversionBetweenPointerToObjectAndIntegerType` query + TQueryC(TPointers1PackageQuery(TConversionBetweenPointerToObjectAndIntegerTypeQuery())) + } + + Query conversionFromPointerToVoidIntoPointerToObjectQuery() { + //autogenerate `Query` type + result = + // `Query` type for `conversionFromPointerToVoidIntoPointerToObject` query + TQueryC(TPointers1PackageQuery(TConversionFromPointerToVoidIntoPointerToObjectQuery())) + } + + Query castBetweenPointerToVoidAndArithmeticTypeQuery() { + //autogenerate `Query` type + result = + // `Query` type for `castBetweenPointerToVoidAndArithmeticType` query + TQueryC(TPointers1PackageQuery(TCastBetweenPointerToVoidAndArithmeticTypeQuery())) + } + + Query castBetweenPointerToObjectAndNonIntArithmeticTypeQuery() { + //autogenerate `Query` type + result = + // `Query` type for `castBetweenPointerToObjectAndNonIntArithmeticType` query + TQueryC(TPointers1PackageQuery(TCastBetweenPointerToObjectAndNonIntArithmeticTypeQuery())) + } + + Query castRemovesConstOrVolatileQualificationQuery() { + //autogenerate `Query` type + result = + // `Query` type for `castRemovesConstOrVolatileQualification` query + TQueryC(TPointers1PackageQuery(TCastRemovesConstOrVolatileQualificationQuery())) + } + + Query macroNullNotUsedAsIntegerNullPointerConstantQuery() { + //autogenerate `Query` type + result = + // `Query` type for `macroNullNotUsedAsIntegerNullPointerConstant` query + TQueryC(TPointers1PackageQuery(TMacroNullNotUsedAsIntegerNullPointerConstantQuery())) + } + + Query pointerAndDerivedPointerMustAddressSameArrayQuery() { + //autogenerate `Query` type + result = + // `Query` type for `pointerAndDerivedPointerMustAddressSameArray` query + TQueryC(TPointers1PackageQuery(TPointerAndDerivedPointerMustAddressSameArrayQuery())) + } + + Query subtractionBetweenPointersMustAddressSameArrayQuery() { + //autogenerate `Query` type + result = + // `Query` type for `subtractionBetweenPointersMustAddressSameArray` query + TQueryC(TPointers1PackageQuery(TSubtractionBetweenPointersMustAddressSameArrayQuery())) + } + + Query relationalOperatorComparesPointerToDifferentArrayQuery() { + //autogenerate `Query` type + result = + // `Query` type for `relationalOperatorComparesPointerToDifferentArray` query + TQueryC(TPointers1PackageQuery(TRelationalOperatorComparesPointerToDifferentArrayQuery())) + } + + Query doNotUseAdditionOrSubtractionOperatorsOnPointersQuery() { + //autogenerate `Query` type + result = + // `Query` type for `doNotUseAdditionOrSubtractionOperatorsOnPointers` query + TQueryC(TPointers1PackageQuery(TDoNotUseAdditionOrSubtractionOperatorsOnPointersQuery())) + } + + Query noMoreThanTwoLevelsOfPointerNestingInDeclarationsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `noMoreThanTwoLevelsOfPointerNestingInDeclarations` query + TQueryC(TPointers1PackageQuery(TNoMoreThanTwoLevelsOfPointerNestingInDeclarationsQuery())) + } + + Query automaticStorageObjectAddressCopiedToOtherObjectQuery() { + //autogenerate `Query` type + result = + // `Query` type for `automaticStorageObjectAddressCopiedToOtherObject` query + TQueryC(TPointers1PackageQuery(TAutomaticStorageObjectAddressCopiedToOtherObjectQuery())) + } + + Query objectWithNoPointerDereferenceShouldBeOpaqueQuery() { + //autogenerate `Query` type + result = + // `Query` type for `objectWithNoPointerDereferenceShouldBeOpaque` query + TQueryC(TPointers1PackageQuery(TObjectWithNoPointerDereferenceShouldBeOpaqueQuery())) + } + + Query pointerShouldPointToConstTypeWhenPossibleQuery() { + //autogenerate `Query` type + result = + // `Query` type for `pointerShouldPointToConstTypeWhenPossible` query + TQueryC(TPointers1PackageQuery(TPointerShouldPointToConstTypeWhenPossibleQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Preprocessor3.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Preprocessor3.qll new file mode 100644 index 0000000000..5894975f2d --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Preprocessor3.qll @@ -0,0 +1,25 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype Preprocessor3Query = TControllingExpressionIfDirectiveQuery() + +predicate isPreprocessor3QueryMetadata(Query query, string queryId, string ruleId) { + query = + // `Query` instance for the `controllingExpressionIfDirective` query + Preprocessor3Package::controllingExpressionIfDirectiveQuery() and + queryId = + // `@id` for the `controllingExpressionIfDirective` query + "c/misra/controlling-expression-if-directive" and + ruleId = "RULE-20-8" +} + +module Preprocessor3Package { + Query controllingExpressionIfDirectiveQuery() { + //autogenerate `Query` type + result = + // `Query` type for `controllingExpressionIfDirective` query + TQueryC(TPreprocessor3PackageQuery(TControllingExpressionIfDirectiveQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll index c03fc8dd84..321a86d7bd 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll @@ -2,43 +2,55 @@ import cpp import codingstandards.cpp.exclusions.RuleMetadata //** Import packages for this language **/ +import Concurrency1 import IO1 import IO2 import IO3 import Misc +import Pointers1 import Preprocessor1 import Preprocessor2 +import Preprocessor3 import SideEffects1 import SideEffects2 import Strings1 import Strings2 +import Strings3 import Syntax /** The TQuery type representing this language * */ newtype TCQuery = + TConcurrency1PackageQuery(Concurrency1Query q) or TIO1PackageQuery(IO1Query q) or TIO2PackageQuery(IO2Query q) or TIO3PackageQuery(IO3Query q) or TMiscPackageQuery(MiscQuery q) or + TPointers1PackageQuery(Pointers1Query q) or TPreprocessor1PackageQuery(Preprocessor1Query q) or TPreprocessor2PackageQuery(Preprocessor2Query q) or + TPreprocessor3PackageQuery(Preprocessor3Query q) or TSideEffects1PackageQuery(SideEffects1Query q) or TSideEffects2PackageQuery(SideEffects2Query q) or TStrings1PackageQuery(Strings1Query q) or TStrings2PackageQuery(Strings2Query q) or + TStrings3PackageQuery(Strings3Query q) or TSyntaxPackageQuery(SyntaxQuery q) /** The metadata predicate * */ predicate isQueryMetadata(Query query, string queryId, string ruleId) { + isConcurrency1QueryMetadata(query, queryId, ruleId) or isIO1QueryMetadata(query, queryId, ruleId) or isIO2QueryMetadata(query, queryId, ruleId) or isIO3QueryMetadata(query, queryId, ruleId) or isMiscQueryMetadata(query, queryId, ruleId) or + isPointers1QueryMetadata(query, queryId, ruleId) or isPreprocessor1QueryMetadata(query, queryId, ruleId) or isPreprocessor2QueryMetadata(query, queryId, ruleId) or + isPreprocessor3QueryMetadata(query, queryId, ruleId) or isSideEffects1QueryMetadata(query, queryId, ruleId) or isSideEffects2QueryMetadata(query, queryId, ruleId) or isStrings1QueryMetadata(query, queryId, ruleId) or isStrings2QueryMetadata(query, queryId, ruleId) or + isStrings3QueryMetadata(query, queryId, ruleId) or isSyntaxQueryMetadata(query, queryId, ruleId) } diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Strings3.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Strings3.qll new file mode 100644 index 0000000000..ab837108c9 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Strings3.qll @@ -0,0 +1,42 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype Strings3Query = + TCastCharBeforeConvertingToLargerSizesQuery() or + TDoNotConfuseNarrowAndWideFunctionsQuery() + +predicate isStrings3QueryMetadata(Query query, string queryId, string ruleId) { + query = + // `Query` instance for the `castCharBeforeConvertingToLargerSizes` query + Strings3Package::castCharBeforeConvertingToLargerSizesQuery() and + queryId = + // `@id` for the `castCharBeforeConvertingToLargerSizes` query + "c/cert/cast-char-before-converting-to-larger-sizes" and + ruleId = "STR34-C" + or + query = + // `Query` instance for the `doNotConfuseNarrowAndWideFunctions` query + Strings3Package::doNotConfuseNarrowAndWideFunctionsQuery() and + queryId = + // `@id` for the `doNotConfuseNarrowAndWideFunctions` query + "c/cert/do-not-confuse-narrow-and-wide-functions" and + ruleId = "STR38-C" +} + +module Strings3Package { + Query castCharBeforeConvertingToLargerSizesQuery() { + //autogenerate `Query` type + result = + // `Query` type for `castCharBeforeConvertingToLargerSizes` query + TQueryC(TStrings3PackageQuery(TCastCharBeforeConvertingToLargerSizesQuery())) + } + + Query doNotConfuseNarrowAndWideFunctionsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `doNotConfuseNarrowAndWideFunctions` query + TQueryC(TStrings3PackageQuery(TDoNotConfuseNarrowAndWideFunctionsQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/Concurrency.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Concurrency.qll index 4c67e654a4..3ae8b37cca 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/cpp/Concurrency.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Concurrency.qll @@ -7,7 +7,7 @@ newtype ConcurrencyQuery = TDoNotAllowAMutexToGoOutOfScopeWhileLockedQuery() or TDoNotDestroyAMutexWhileItIsLockedQuery() or TEnsureActivelyHeldLocksAreReleasedOnExceptionalConditionsQuery() or - TPreventDataRacesWhenAccessingBitFieldsFromMultipleThreadsQuery() or + TPreventBitFieldAccessFromMultipleThreadsQuery() or TDeadlockByLockingInPredefinedOrderQuery() or TWrapFunctionsThatCanSpuriouslyWakeUpInLoopQuery() or TPreserveThreadSafetyAndLivenessWhenUsingConditionVariablesQuery() or @@ -40,11 +40,11 @@ predicate isConcurrencyQueryMetadata(Query query, string queryId, string ruleId) ruleId = "CON51-CPP" or query = - // `Query` instance for the `preventDataRacesWhenAccessingBitFieldsFromMultipleThreads` query - ConcurrencyPackage::preventDataRacesWhenAccessingBitFieldsFromMultipleThreadsQuery() and + // `Query` instance for the `preventBitFieldAccessFromMultipleThreads` query + ConcurrencyPackage::preventBitFieldAccessFromMultipleThreadsQuery() and queryId = - // `@id` for the `preventDataRacesWhenAccessingBitFieldsFromMultipleThreads` query - "cpp/cert/prevent-data-races-when-accessing-bit-fields-from-multiple-threads" and + // `@id` for the `preventBitFieldAccessFromMultipleThreads` query + "cpp/cert/prevent-bit-field-access-from-multiple-threads" and ruleId = "CON52-CPP" or query = @@ -110,11 +110,11 @@ module ConcurrencyPackage { TQueryCPP(TConcurrencyPackageQuery(TEnsureActivelyHeldLocksAreReleasedOnExceptionalConditionsQuery())) } - Query preventDataRacesWhenAccessingBitFieldsFromMultipleThreadsQuery() { + Query preventBitFieldAccessFromMultipleThreadsQuery() { //autogenerate `Query` type result = - // `Query` type for `preventDataRacesWhenAccessingBitFieldsFromMultipleThreads` query - TQueryCPP(TConcurrencyPackageQuery(TPreventDataRacesWhenAccessingBitFieldsFromMultipleThreadsQuery())) + // `Query` type for `preventBitFieldAccessFromMultipleThreads` query + TQueryCPP(TConcurrencyPackageQuery(TPreventBitFieldAccessFromMultipleThreadsQuery())) } Query deadlockByLockingInPredefinedOrderQuery() { diff --git a/cpp/common/src/codingstandards/cpp/rules/donotcopyaddressofautostorageobjecttootherobject/DoNotCopyAddressOfAutoStorageObjectToOtherObject.qll b/cpp/common/src/codingstandards/cpp/rules/donotcopyaddressofautostorageobjecttootherobject/DoNotCopyAddressOfAutoStorageObjectToOtherObject.qll new file mode 100644 index 0000000000..1b22fd5c3b --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/donotcopyaddressofautostorageobjecttootherobject/DoNotCopyAddressOfAutoStorageObjectToOtherObject.qll @@ -0,0 +1,57 @@ +/** + * Provides a library which includes a `problems` predicate for reporting instances of + * assignment of stack addresses to other variables with a wider scope. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import semmle.code.cpp.dataflow.StackAddress + +abstract class DoNotCopyAddressOfAutoStorageObjectToOtherObjectSharedQuery extends Query { } + +/* + * This is a variant of the `cpp/stack-address-escape` query, provided in the CodeQL C++ default + * query set, which enforces the stricter version of the rule required by MISRA. In particular, + * MISRA requires that stack addresses are never assigned to other stack variables with a wider + * scope, even if the address never leaks from the function itself. + */ + +/** + * Find assignments where the rhs might be a stack pointer and the lhs is + * not a stack variable. Such assignments might allow a stack address to + * escape. + */ +predicate stackAddressEscapes(AssignExpr assignExpr, Expr source, boolean isLocal) { + stackPointerFlowsToUse(assignExpr.getRValue(), _, source, isLocal) and + ( + // Not assigned to a StackVariable + not stackReferenceFlowsToUse(assignExpr.getLValue(), _, _, _) + or + // Assigned to a StackVariable with wider scope + exists(StackVariable rvalueVar, StackVariable lvalueVar, Expr lvalueSource | + // Restrict to local variables + stackReferenceFlowsToUse(assignExpr.getLValue(), _, lvalueSource, true) and + lvalueSource = lvalueVar.getAnAccess() and + source = rvalueVar.getAnAccess() and + lvalueVar.getParentScope() = rvalueVar.getParentScope().getParentScope+() + ) + ) +} + +Query getQuery() { result instanceof DoNotCopyAddressOfAutoStorageObjectToOtherObjectSharedQuery } + +query predicate problems(Expr use, string message, Expr source, string srcStr) { + not isExcluded(use, getQuery()) and + exists(boolean isLocal | + stackAddressEscapes(use, source, isLocal) and + if isLocal = true + then ( + message = "A stack address ($@) may be assigned to a non-local variable." and + srcStr = "source" + ) else ( + message = "A stack address which arrived via a $@ may be assigned to a non-local variable." and + srcStr = "parameter" + ) + ) +} diff --git a/cpp/common/src/codingstandards/cpp/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.qll b/cpp/common/src/codingstandards/cpp/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.qll new file mode 100644 index 0000000000..40dac2d027 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.qll @@ -0,0 +1,72 @@ +/** + * Provides a library which includes a `problems` predicate for reporting + * subtraction between operands pointing to differing arrays. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import semmle.code.cpp.dataflow.DataFlow +import DataFlow::PathGraph + +class ArrayToPointerDiffOperandConfig extends DataFlow::Configuration { + ArrayToPointerDiffOperandConfig() { this = "ArrayToPointerDiffOperandConfig" } + + override 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(PointerDiffExpr e | e.getAnOperand() = sink.asExpr()) + } + + override 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()) + } +} + +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 +) { + exists( + PointerDiffExpr pointerSubtraction, string side, ArrayToPointerDiffOperandConfig c, + Variable sourceLeft, Variable sourceRight + | + not isExcluded(pointerSubtraction, getQuery()) and + c.hasFlow(DataFlow::exprNode(sourceLeft.getAnAccess()), + DataFlow::exprNode(pointerSubtraction.getLeftOperand())) and + c.hasFlow(DataFlow::exprNode(sourceRight.getAnAccess()), + DataFlow::exprNode(pointerSubtraction.getRightOperand())) and + not sourceLeft = sourceRight and + c.hasFlowPath(source, sink) and + ( + source.getNode().asExpr() = sourceLeft.getAnAccess() and + sink.getNode().asExpr() = pointerSubtraction.getLeftOperand() and + side = "left" and + currentOperandPointee = sourceLeft and + otherOperandPointee = sourceRight + or + source.getNode().asExpr() = sourceRight.getAnAccess() and + sink.getNode().asExpr() = pointerSubtraction.getRightOperand() and + side = "right" and + currentOperandPointee = sourceRight and + otherOperandPointee = sourceLeft + ) and + sinkNode = sink.getNode() and + currentOperandPointeeName = currentOperandPointee.getName() and + otherOperandPointeeName = otherOperandPointee.getName() and + message = + "Subtraction between " + side + + " operand pointing to array $@ and other operand pointing to array $@." + ) +} diff --git a/cpp/common/src/codingstandards/cpp/rules/donotusemorethantwolevelsofpointerindirection/DoNotUseMoreThanTwoLevelsOfPointerIndirection.qll b/cpp/common/src/codingstandards/cpp/rules/donotusemorethantwolevelsofpointerindirection/DoNotUseMoreThanTwoLevelsOfPointerIndirection.qll new file mode 100644 index 0000000000..66fc57e7aa --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/donotusemorethantwolevelsofpointerindirection/DoNotUseMoreThanTwoLevelsOfPointerIndirection.qll @@ -0,0 +1,40 @@ +/** + * Provides a library which includes a `problems` predicate for reporting + * variables declared with more than two levels of pointer indirection. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class DoNotUseMoreThanTwoLevelsOfPointerIndirectionSharedQuery extends Query { } + +Query getQuery() { result instanceof DoNotUseMoreThanTwoLevelsOfPointerIndirectionSharedQuery } + +Type getBaseType(DerivedType t) { result = t.getBaseType() } + +int levelsOfIndirection(Type t) { + if t instanceof FunctionPointerType + then result = t.(FunctionPointerType).getReturnType().getPointerIndirectionLevel() + else result = t.getPointerIndirectionLevel() +} + +int paramLevelsOfIndirection(Type t) { + if t instanceof ArrayType + then result = 1 + levelsOfIndirection(t.(ArrayType).getBaseType()) + else result = levelsOfIndirection(t) +} + +query predicate problems(Variable v, string message) { + not isExcluded(v, getQuery()) and + exists(Type type | + type = getBaseType*(v.getType()) and + ( + if v instanceof Parameter + then paramLevelsOfIndirection(type) > 2 + else levelsOfIndirection(type) > 2 + ) + ) and + message = + "The declaration of " + v.getName() + " contain more than two levels of pointer indirection." +} diff --git a/cpp/common/src/codingstandards/cpp/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.qll b/cpp/common/src/codingstandards/cpp/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.qll new file mode 100644 index 0000000000..758dcc0157 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.qll @@ -0,0 +1,181 @@ +/** + * Provides a library which includes a `problems` predicate for reporting + * pointer arithmetic expressions in which the resulting pointer addresses an array + * other than the array which the original pointer operand addressed. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import semmle.code.cpp.dataflow.DataFlow +import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis + +abstract class DoNotUsePointerArithmeticToAddressDifferentArraysSharedQuery extends Query { } + +Query getQuery() { result instanceof DoNotUsePointerArithmeticToAddressDifferentArraysSharedQuery } + +/** + * 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) { + source.asExpr().(VariableAccess).getType() instanceof ArrayType + } + + override predicate isSink(DataFlow::Node sink) { + exists(ArrayExpr c | c.getArrayBase() = sink.asExpr()) + } +} + +/** 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 + index = lowerBound(ae.getArrayOffset().getFullyConverted()) and + addressOf.getOperand() = ae + ) +} + +/** A variable that points to an element of an array. */ +class PointerOperand extends Variable { + Variable array; + int arraySize; + int index; + AddressOfExpr source; + + PointerOperand() { + pointerOperandCreation(source, array, arraySize, index) and + this.getAnAssignedValue() = source + } + + Variable getArray() { result = array } + + int getArraySize() { result = arraySize } + + int getIndex() { result = index } + + AddressOfExpr getSource() { result = source } +} + +/** An derivation of a new pointer that differs by a constant amount. */ +class ConstantPointerAdjustment extends Expr { + int delta; + + ConstantPointerAdjustment() { + delta = this.(PointerAddExpr).getAnOperand().getValue().toInt() + or + delta = -this.(PointerSubExpr).getAnOperand().getValue().toInt() + or + this.(Operation).getAnOperand().getUnderlyingType() instanceof PointerType and + ( + delta = 0 and this instanceof PostfixCrementOperation + or + delta = 1 and this instanceof PrefixIncrExpr + or + delta = -1 and this instanceof PrefixDecrExpr + ) + or + this.(VariableAccess).getUnderlyingType() instanceof PointerType and delta = 0 + } + + int getDelta() { result = delta } + + VariableAccess getAdjusted() { + result = this + or + result = this.(Operation).getAnOperand() + } +} + +/** Holds if `derivedPointer` is a new pointer created via an `adjustment` on `pointerOperand`. */ +predicate derivedPointer( + Variable derivedPointer, ConstantPointerAdjustment adjustment, + DerivedArrayPointerOrPointerOperand pointerOperand, int index +) { + adjustment.getAdjusted().getTarget() = pointerOperand and + index = pointerOperand.getIndex() + adjustment.getDelta() and + derivedPointer.getAnAssignedValue() = adjustment +} + +/** + * A pointer to an array that is derived from another pointer to an array through a constant adjustment. + * The new pointer may or may not point to the same array. + */ +class DerivedArrayPointer extends Variable { + DerivedArrayPointerOrPointerOperand operand; + int index; + ConstantPointerAdjustment source; + + DerivedArrayPointer() { derivedPointer(this, source, operand, index) } + + Variable getArray() { result = operand.getArray() } + + int getArraySize() { result = operand.getArraySize() } + + int getIndex() { result = index } + + ConstantPointerAdjustment getSource() { result = source } +} + +/** + * A pointer to an element of array created by taking the address of an array element or + * created through a constant adjustment of a pointer to an array. + */ +class DerivedArrayPointerOrPointerOperand extends Variable { + DerivedArrayPointerOrPointerOperand() { + this instanceof DerivedArrayPointer + or + this instanceof PointerOperand + } + + Variable getArray() { + result = this.(DerivedArrayPointer).getArray() or result = this.(PointerOperand).getArray() + } + + int getArraySize() { + result = this.(DerivedArrayPointer).getArraySize() or + result = this.(PointerOperand).getArraySize() + } + + int getIndex() { + result = this.(DerivedArrayPointer).getIndex() or result = this.(PointerOperand).getIndex() + } + + Expr getSource() { + result = this.(DerivedArrayPointer).getSource() or result = this.(PointerOperand).getSource() + } +} + +query predicate problems(Expr arrayPointerCreation, string message, Variable array, string arrayName) { + not isExcluded(arrayPointerCreation, getQuery()) and + exists( + DerivedArrayPointerOrPointerOperand derivedArrayPointerOrPointerOperand, int index, + int arraySize, int difference, string denomination + | + array = derivedArrayPointerOrPointerOperand.getArray() and + arraySize = derivedArrayPointerOrPointerOperand.getArraySize() and + index = derivedArrayPointerOrPointerOperand.getIndex() and + arrayPointerCreation = derivedArrayPointerOrPointerOperand.getSource() and + difference = index - arraySize and + ( + difference = 1 and denomination = "element" + or + difference > 1 and denomination = "elements" + ) and + // Exclude the creation of pointers to an element of an array in loops. + // Our range analysis will typically resort to widening resulting in + // possible false positives. + not exists(Loop loop | + arrayPointerCreation.getEnclosingBlock().getEnclosingBlock*() = loop.getStmt() + ) and + message = + "Array pointer " + derivedArrayPointerOrPointerOperand.getName() + " points " + + (index - arraySize).toString() + " " + denomination + " passed the end of $@." + ) and + arrayName = array.getName() +} diff --git a/cpp/common/src/codingstandards/cpp/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.qll b/cpp/common/src/codingstandards/cpp/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.qll new file mode 100644 index 0000000000..15f1fa4057 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.qll @@ -0,0 +1,92 @@ +/** + * Provides a library which includes a `problems` predicate for reporting + * instances of the >, >=, <, and <= operators being applied to pointers + * which address different arrays. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import semmle.code.cpp.dataflow.DataFlow +import DataFlow::PathGraph + +abstract class DoNotUseRelationalOperatorsWithDifferingArraysSharedQuery extends Query { } + +Query getQuery() { result instanceof DoNotUseRelationalOperatorsWithDifferingArraysSharedQuery } + +/** A source of arrays that can be used to start tracking data flow originating from an array. */ +abstract class ArraySource extends DataFlow::Node { } + +/** An access of an object of array type. */ +class ArrayAccess extends ArraySource { + ArrayAccess() { this.asExpr().(VariableAccess).getType() instanceof ArrayType } +} + +/** An access of an object of array type through a pointer that is the result of an array to pointer decay. */ +class DecayedArrayAccess extends ArraySource { + DecayedArrayAccess() { + exists(VariableAccess va | va = this.asExpr() | + va.getType() instanceof PointerType and + va.getTarget().(Parameter).getType() instanceof ArrayType + ) + } +} + +class ArrayToRelationalOperationOperandConfig extends DataFlow::Configuration { + ArrayToRelationalOperationOperandConfig() { this = "ArrayToRelationalOperationOperandConfig" } + + override predicate isSource(DataFlow::Node source) { source instanceof ArraySource } + + override predicate isSink(DataFlow::Node sink) { + exists(RelationalOperation op | op.getAnOperand() = sink.asExpr()) + } + + override 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()) + } +} + +predicate isComparingPointers(RelationalOperation op) { + forall(Expr operand | operand = op.getAnOperand() | + operand.getType() instanceof PointerType or operand.getType() instanceof ArrayType + ) +} + +query predicate problems( + RelationalOperation compare, DataFlow::PathNode source, DataFlow::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()), + DataFlow::exprNode(compare.getLeftOperand())) and + c.hasFlow(DataFlow::exprNode(sourceRight.getAnAccess()), + DataFlow::exprNode(compare.getRightOperand())) and + not sourceLeft = sourceRight and + isComparingPointers(compare) and + c.hasFlowPath(source, sink) and + ( + source.getNode().asExpr() = sourceLeft.getAnAccess() and + sink.getNode().asExpr() = compare.getLeftOperand() and + selectedOperandPointee = sourceLeft and + otherOperandPointee = sourceRight and + side = "left" + or + source.getNode().asExpr() = sourceRight.getAnAccess() and + sink.getNode().asExpr() = compare.getRightOperand() and + selectedOperandPointee = sourceRight and + otherOperandPointee = sourceLeft and + side = "right" + ) and + selectedOperandPointeeName = selectedOperandPointee.getName() and + otherOperandPointeeName = otherOperandPointee.getName() and + message = + "Compare operation " + compare.getOperator() + " comparing " + side + + " operand pointing to array $@ and other operand pointing to array $@." + ) +} diff --git a/cpp/cert/src/rules/CON52-CPP/PreventDataRacesWhenAccessingBitFieldsFromMultipleThreads.ql b/cpp/common/src/codingstandards/cpp/rules/guardaccesstobitfields/GuardAccessToBitFields.qll similarity index 59% rename from cpp/cert/src/rules/CON52-CPP/PreventDataRacesWhenAccessingBitFieldsFromMultipleThreads.ql rename to cpp/common/src/codingstandards/cpp/rules/guardaccesstobitfields/GuardAccessToBitFields.qll index ba4682899c..f07d9d94bd 100644 --- a/cpp/cert/src/rules/CON52-CPP/PreventDataRacesWhenAccessingBitFieldsFromMultipleThreads.ql +++ b/cpp/common/src/codingstandards/cpp/rules/guardaccesstobitfields/GuardAccessToBitFields.qll @@ -1,21 +1,17 @@ /** - * @id cpp/cert/prevent-data-races-when-accessing-bit-fields-from-multiple-threads - * @name CON52-CPP: Prevent data races when accessing bit-fields from multiple threads - * @description Accesses to bit fields without proper concurrency protection can result in data - * races. - * @kind problem - * @precision very-high - * @problem.severity error - * @tags external/cert/id/con52-cpp - * correctness - * concurrency - * external/cert/obligation/rule + * Provides a library which includes a `problems` predicate for data races while accessing + * bit fields. */ import cpp -import codingstandards.cpp.cert +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions import codingstandards.cpp.Concurrency +abstract class GuardAccessToBitFieldsSharedQuery extends Query { } + +Query getQuery() { result instanceof GuardAccessToBitFieldsSharedQuery } + class BitFieldAccess extends VariableAccess { BitFieldAccess() { this.getTarget() instanceof BitField } } @@ -43,10 +39,9 @@ ControlFlowNode getAReachableLockCFN(MutexFunctionCall mfc) { // point where the bit field access happens that either a) a RAII-style lock is // in scope or b) a lock is held manually. One issue with this query is that it // has no way of determining that code is indeed multi-threaded. -from BitFieldAccess ba -where - not isExcluded(ba, - ConcurrencyPackage::preventDataRacesWhenAccessingBitFieldsFromMultipleThreadsQuery()) and +query predicate problems(BitFieldAccess ba, string message) { + not isExcluded(ba, getQuery()) and ba instanceof ThreadedCFN and - not ba instanceof LockProtectedControlFlowNode -select ba, "Access to a bit-field without a concurrency guard." + not ba instanceof LockProtectedControlFlowNode and + message = "Access to a bit-field without a concurrency guard." +} diff --git a/cpp/common/src/codingstandards/cpp/rules/useonlyarrayindexingforpointerarithmetic/UseOnlyArrayIndexingForPointerArithmetic.qll b/cpp/common/src/codingstandards/cpp/rules/useonlyarrayindexingforpointerarithmetic/UseOnlyArrayIndexingForPointerArithmetic.qll new file mode 100644 index 0000000000..faa4442ba3 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/useonlyarrayindexingforpointerarithmetic/UseOnlyArrayIndexingForPointerArithmetic.qll @@ -0,0 +1,58 @@ +/** + * Provides a library which includes a `problems` predicate for reporting + * instances of pointer arithmetic using means other than array indexing. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import semmle.code.cpp.dataflow.DataFlow + +abstract class UseOnlyArrayIndexingForPointerArithmeticSharedQuery extends Query { } + +class ArrayToArrayBaseConfig extends DataFlow::Configuration { + ArrayToArrayBaseConfig() { this = "ArrayToArrayBaseConfig" } + + override 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 hasPointerResult(PointerArithmeticOperation op) { + op instanceof PointerAddExpr + or + op instanceof PointerSubExpr +} + +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())) + ) and + not exists(Variable v | + v.getAnAssignedValue().getType() instanceof ArrayType and + arrayExpr.getArrayBase() = v.getAnAccess() + ) +} + +Query getQuery() { result instanceof UseOnlyArrayIndexingForPointerArithmeticSharedQuery } + +query predicate problems(Expr e, string message) { + not isExcluded(e, getQuery()) and + ( + hasPointerResult(e) + or + shouldBeArray(e) + ) and + not e.isAffectedByMacro() and + message = + "Use of pointer arithmetic other than array indexing or indexing pointer not declared as an array." +} diff --git a/cpp/common/src/qlpack.yml b/cpp/common/src/qlpack.yml index e95f43b81b..079e9fcf0a 100644 --- a/cpp/common/src/qlpack.yml +++ b/cpp/common/src/qlpack.yml @@ -1,3 +1,3 @@ name: common-cpp-coding-standards -version: 2.4.0 +version: 2.5.0 libraryPathDependencies: codeql-cpp diff --git a/cpp/common/test/qlpack.yml b/cpp/common/test/qlpack.yml index fefbebc149..0acd040fb3 100644 --- a/cpp/common/test/qlpack.yml +++ b/cpp/common/test/qlpack.yml @@ -1,4 +1,4 @@ name: common-cpp-coding-standards-tests -version: 2.4.0 +version: 2.5.0 libraryPathDependencies: common-cpp-coding-standards extractor: cpp diff --git a/cpp/autosar/test/rules/M7-5-2/AssignmentOfEscapingAutoStorage.expected b/cpp/common/test/rules/donotcopyaddressofautostorageobjecttootherobject/DoNotCopyAddressOfAutoStorageObjectToOtherObject.expected similarity index 100% rename from cpp/autosar/test/rules/M7-5-2/AssignmentOfEscapingAutoStorage.expected rename to cpp/common/test/rules/donotcopyaddressofautostorageobjecttootherobject/DoNotCopyAddressOfAutoStorageObjectToOtherObject.expected diff --git a/cpp/common/test/rules/donotcopyaddressofautostorageobjecttootherobject/DoNotCopyAddressOfAutoStorageObjectToOtherObject.ql b/cpp/common/test/rules/donotcopyaddressofautostorageobjecttootherobject/DoNotCopyAddressOfAutoStorageObjectToOtherObject.ql new file mode 100644 index 0000000000..9f0c40ef4c --- /dev/null +++ b/cpp/common/test/rules/donotcopyaddressofautostorageobjecttootherobject/DoNotCopyAddressOfAutoStorageObjectToOtherObject.ql @@ -0,0 +1,2 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.donotcopyaddressofautostorageobjecttootherobject.DoNotCopyAddressOfAutoStorageObjectToOtherObject diff --git a/cpp/autosar/test/rules/M7-5-2/manager.cpp b/cpp/common/test/rules/donotcopyaddressofautostorageobjecttootherobject/manager.cpp similarity index 100% rename from cpp/autosar/test/rules/M7-5-2/manager.cpp rename to cpp/common/test/rules/donotcopyaddressofautostorageobjecttootherobject/manager.cpp diff --git a/cpp/autosar/test/rules/M7-5-2/stack_escapes_test.cpp b/cpp/common/test/rules/donotcopyaddressofautostorageobjecttootherobject/stack_escapes_test.cpp similarity index 100% rename from cpp/autosar/test/rules/M7-5-2/stack_escapes_test.cpp rename to cpp/common/test/rules/donotcopyaddressofautostorageobjecttootherobject/stack_escapes_test.cpp diff --git a/cpp/common/test/rules/donotcopyaddressofautostorageobjecttootherobject/test.cpp b/cpp/common/test/rules/donotcopyaddressofautostorageobjecttootherobject/test.cpp new file mode 100644 index 0000000000..0cd3970c7e --- /dev/null +++ b/cpp/common/test/rules/donotcopyaddressofautostorageobjecttootherobject/test.cpp @@ -0,0 +1,9 @@ +void test_simple_aliasing() { + int *a; + int b; + a = &b; // COMPLIANT - same scope + { + int c; + a = &c; // NON_COMPLIANT - different scope + } +} \ No newline at end of file diff --git a/cpp/autosar/test/rules/M5-0-17/PointerSubtractionOnDifferentArrays.expected b/cpp/common/test/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.expected similarity index 99% rename from cpp/autosar/test/rules/M5-0-17/PointerSubtractionOnDifferentArrays.expected rename to cpp/common/test/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.expected index 02e1a4f56b..21fe1e3ccd 100644 --- a/cpp/autosar/test/rules/M5-0-17/PointerSubtractionOnDifferentArrays.expected +++ b/cpp/common/test/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.expected @@ -1,3 +1,8 @@ +problems +| test.cpp:12:10:12:11 | p1 | test.cpp:4:14:4:15 | l1 | test.cpp:12:10:12:11 | p1 | Subtraction between left 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 | +| test.cpp:12:15:12:16 | p2 | test.cpp:5:14:5:15 | l2 | test.cpp:12:15:12:16 | p2 | Subtraction between right 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: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 | @@ -19,8 +24,3 @@ nodes | test.cpp:14:10:14:11 | p4 | semmle.label | p4 | | test.cpp:14:15:14:16 | l2 | semmle.label | l2 | subpaths -#select -| test.cpp:12:10:12:11 | p1 | test.cpp:4:14:4:15 | l1 | test.cpp:12:10:12:11 | p1 | Subtraction between left 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 | -| test.cpp:12:15:12:16 | p2 | test.cpp:5:14:5:15 | l2 | test.cpp:12:15:12:16 | p2 | Subtraction between right 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: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 | diff --git a/cpp/common/test/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.ql b/cpp/common/test/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.ql new file mode 100644 index 0000000000..bf47bf28f1 --- /dev/null +++ b/cpp/common/test/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.ql @@ -0,0 +1,2 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.donotsubtractpointersaddressingdifferentarrays.DoNotSubtractPointersAddressingDifferentArrays diff --git a/cpp/common/test/rules/donotsubtractpointersaddressingdifferentarrays/test.cpp b/cpp/common/test/rules/donotsubtractpointersaddressingdifferentarrays/test.cpp new file mode 100644 index 0000000000..b91074e3bc --- /dev/null +++ b/cpp/common/test/rules/donotsubtractpointersaddressingdifferentarrays/test.cpp @@ -0,0 +1,15 @@ +void f1() { + int l1[10]; + int l2[10]; + int *p1 = &l1[9]; + int *p2 = &l2[10]; + int *p3 = p2; + int *p4 = p3; + int diff; + + diff = p1 - l1; // COMPLIANT + diff = p2 - l2; // COMPLIANT + diff = p1 - p2; // NON_COMPLIANT + diff = p4 - l1; // NON_COMPLIANT + diff = p4 - l2; // COMPLIANT +} diff --git a/cpp/autosar/test/rules/A5-0-3/DeclarationContainLessThanTwoLevelsOfIndirection.expected b/cpp/common/test/rules/donotusemorethantwolevelsofpointerindirection/DoNotUseMoreThanTwoLevelsOfPointerIndirection.expected similarity index 100% rename from cpp/autosar/test/rules/A5-0-3/DeclarationContainLessThanTwoLevelsOfIndirection.expected rename to cpp/common/test/rules/donotusemorethantwolevelsofpointerindirection/DoNotUseMoreThanTwoLevelsOfPointerIndirection.expected diff --git a/cpp/common/test/rules/donotusemorethantwolevelsofpointerindirection/DoNotUseMoreThanTwoLevelsOfPointerIndirection.ql b/cpp/common/test/rules/donotusemorethantwolevelsofpointerindirection/DoNotUseMoreThanTwoLevelsOfPointerIndirection.ql new file mode 100644 index 0000000000..6fdfb9c928 --- /dev/null +++ b/cpp/common/test/rules/donotusemorethantwolevelsofpointerindirection/DoNotUseMoreThanTwoLevelsOfPointerIndirection.ql @@ -0,0 +1,2 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.donotusemorethantwolevelsofpointerindirection.DoNotUseMoreThanTwoLevelsOfPointerIndirection diff --git a/cpp/autosar/test/rules/A5-0-3/test.cpp b/cpp/common/test/rules/donotusemorethantwolevelsofpointerindirection/test.cpp similarity index 100% rename from cpp/autosar/test/rules/A5-0-3/test.cpp rename to cpp/common/test/rules/donotusemorethantwolevelsofpointerindirection/test.cpp diff --git a/cpp/autosar/test/rules/M5-0-16/PointerAndDerivedPointerAccessDifferentArray.expected b/cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.expected similarity index 100% rename from cpp/autosar/test/rules/M5-0-16/PointerAndDerivedPointerAccessDifferentArray.expected rename to cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.expected diff --git a/cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.ql b/cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.ql new file mode 100644 index 0000000000..b06daa52b7 --- /dev/null +++ b/cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.ql @@ -0,0 +1,2 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.donotusepointerarithmetictoaddressdifferentarrays.DoNotUsePointerArithmeticToAddressDifferentArrays diff --git a/cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/test.cpp b/cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/test.cpp new file mode 100644 index 0000000000..c1032ee735 --- /dev/null +++ b/cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/test.cpp @@ -0,0 +1,20 @@ +void f1() { + int l1[3]; + int *p1 = &l1[0]; + int *p2 = p1 + 4; // NON_COMPLIANT + int *p3 = 4 + p1; // NON_COMPLIANT + int *p4 = &l1[4]; // NON_COMPLIANT + int *p5, *p6, *p7, *p8; + + p5 = p2 - 1; // COMPLIANT + p6 = --p2; // COMPLIANT + p7 = p3--; // NON_COMPLIANT + p8 = p3; // COMPLIANT[FALSE_POSITIVE] + + int *p9 = + p1 + 3; // COMPLIANT - points to an element on beyond the end of the array + int *p10 = + 3 + p1; // COMPLIANT - points to an element on beyond the end of the array + int *p11 = + &l1[3]; // COMPLIANT - points to an element on beyond the end of the array +} \ No newline at end of file diff --git a/cpp/autosar/test/rules/M5-0-18/AppliedToObjectsOfPointerType.expected b/cpp/common/test/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.expected similarity index 99% rename from cpp/autosar/test/rules/M5-0-18/AppliedToObjectsOfPointerType.expected rename to cpp/common/test/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.expected index 743035b553..1b31174b2f 100644 --- a/cpp/autosar/test/rules/M5-0-18/AppliedToObjectsOfPointerType.expected +++ b/cpp/common/test/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.expected @@ -1,3 +1,14 @@ +problems +| test.cpp:17:7:17:13 | ... < ... | test.cpp:7:14:7:15 | l1 | test.cpp:17:7:17:8 | p1 | Compare operation < comparing left 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 | +| test.cpp:17:7:17:13 | ... < ... | test.cpp:17:12:17:13 | l2 | test.cpp:17:12:17:13 | l2 | Compare operation < comparing right 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:19:7:19:13 | ... < ... | test.cpp:19:7:19:8 | l1 | test.cpp:19:7:19:8 | l1 | Compare operation < comparing left 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 | +| test.cpp:19:7:19:13 | ... < ... | test.cpp:19:12:19:13 | l2 | test.cpp:19:12:19:13 | l2 | Compare operation < comparing right 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:21:7:21:13 | ... < ... | test.cpp:8:14:8:15 | l1 | test.cpp:21:7:21:8 | p2 | Compare operation < comparing left 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 | +| test.cpp:21:7:21:13 | ... < ... | test.cpp:9:14:9:15 | l2 | test.cpp:21:12:21:13 | p3 | Compare operation < comparing right 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:23:7:23:14 | ... <= ... | test.cpp:7:14:7:15 | l1 | test.cpp:23:13:23:14 | p1 | Compare operation <= comparing 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 | +| test.cpp:23:7:23:14 | ... <= ... | test.cpp:23:7:23:8 | l2 | test.cpp:23:7:23:8 | l2 | Compare operation <= comparing 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:25:7:25:14 | ... >= ... | test.cpp:7:14:7:15 | l1 | test.cpp:25:7:25:8 | p1 | Compare operation >= comparing left operand pointing to array $@ and other operand pointing to array $@. | test.cpp:2:7:2:8 | l1 | l1 | test.cpp:4:7:4:8 | l3 | l3 | +| 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 | @@ -31,14 +42,3 @@ nodes | test.cpp:25:7:25:8 | p1 | semmle.label | p1 | | test.cpp:25:13:25:14 | l3 | semmle.label | l3 | subpaths -#select -| test.cpp:17:7:17:13 | ... < ... | test.cpp:7:14:7:15 | l1 | test.cpp:17:7:17:8 | p1 | Compare operation < comparing left 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 | -| test.cpp:17:7:17:13 | ... < ... | test.cpp:17:12:17:13 | l2 | test.cpp:17:12:17:13 | l2 | Compare operation < comparing right 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:19:7:19:13 | ... < ... | test.cpp:19:7:19:8 | l1 | test.cpp:19:7:19:8 | l1 | Compare operation < comparing left 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 | -| test.cpp:19:7:19:13 | ... < ... | test.cpp:19:12:19:13 | l2 | test.cpp:19:12:19:13 | l2 | Compare operation < comparing right 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:21:7:21:13 | ... < ... | test.cpp:8:14:8:15 | l1 | test.cpp:21:7:21:8 | p2 | Compare operation < comparing left 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 | -| test.cpp:21:7:21:13 | ... < ... | test.cpp:9:14:9:15 | l2 | test.cpp:21:12:21:13 | p3 | Compare operation < comparing right 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:23:7:23:14 | ... <= ... | test.cpp:7:14:7:15 | l1 | test.cpp:23:13:23:14 | p1 | Compare operation <= comparing 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 | -| test.cpp:23:7:23:14 | ... <= ... | test.cpp:23:7:23:8 | l2 | test.cpp:23:7:23:8 | l2 | Compare operation <= comparing 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:25:7:25:14 | ... >= ... | test.cpp:7:14:7:15 | l1 | test.cpp:25:7:25:8 | p1 | Compare operation >= comparing left operand pointing to array $@ and other operand pointing to array $@. | test.cpp:2:7:2:8 | l1 | l1 | test.cpp:4:7:4:8 | l3 | l3 | -| 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 | diff --git a/cpp/common/test/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.ql b/cpp/common/test/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.ql new file mode 100644 index 0000000000..c6cca37aa2 --- /dev/null +++ b/cpp/common/test/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.ql @@ -0,0 +1,2 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.donotuserelationaloperatorswithdifferingarrays.DoNotUseRelationalOperatorsWithDifferingArrays diff --git a/cpp/common/test/rules/donotuserelationaloperatorswithdifferingarrays/test.cpp b/cpp/common/test/rules/donotuserelationaloperatorswithdifferingarrays/test.cpp new file mode 100644 index 0000000000..97c89408e9 --- /dev/null +++ b/cpp/common/test/rules/donotuserelationaloperatorswithdifferingarrays/test.cpp @@ -0,0 +1,27 @@ +void f1() { + int l1[10]; + int l2[10]; + int l3[7]; + + int *p0 = l1; + int *p1 = &l1[0]; + int *p2 = &l1[1]; + int *p3 = &l2[2]; + + if (p1 < p2) { // COMPLIANT + } + if (p1 < p0) { // COMPLIANT + } + if (l1 <= p1) { // COMPLIANT + } + if (p1 < l2) { // NON_COMPLIANT + } + if (l1 < l2) { // NON_COMPLIANT + } + if (p2 < p3) { // NON_COMPLIANT + } + if (l2 <= p1) { // NON_COMPLIANT + } + if (p1 >= l3) { // NON_COMPLIANT + } +} \ No newline at end of file diff --git a/cpp/cert/test/rules/CON52-CPP/PreventDataRacesWhenAccessingBitFieldsFromMultipleThreads.expected b/cpp/common/test/rules/guardaccesstobitfields/GuardAccessToBitFields.expected similarity index 100% rename from cpp/cert/test/rules/CON52-CPP/PreventDataRacesWhenAccessingBitFieldsFromMultipleThreads.expected rename to cpp/common/test/rules/guardaccesstobitfields/GuardAccessToBitFields.expected diff --git a/cpp/common/test/rules/guardaccesstobitfields/GuardAccessToBitFields.ql b/cpp/common/test/rules/guardaccesstobitfields/GuardAccessToBitFields.ql new file mode 100644 index 0000000000..693dae8f57 --- /dev/null +++ b/cpp/common/test/rules/guardaccesstobitfields/GuardAccessToBitFields.ql @@ -0,0 +1,2 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.guardaccesstobitfields.GuardAccessToBitFields diff --git a/cpp/cert/test/rules/CON52-CPP/test.cpp b/cpp/common/test/rules/guardaccesstobitfields/test.cpp similarity index 100% rename from cpp/cert/test/rules/CON52-CPP/test.cpp rename to cpp/common/test/rules/guardaccesstobitfields/test.cpp diff --git a/cpp/autosar/test/rules/M5-0-15/IndexingNotTheOnlyFormOfPointerArithmetic.expected b/cpp/common/test/rules/useonlyarrayindexingforpointerarithmetic/UseOnlyArrayIndexingForPointerArithmetic.expected similarity index 100% rename from cpp/autosar/test/rules/M5-0-15/IndexingNotTheOnlyFormOfPointerArithmetic.expected rename to cpp/common/test/rules/useonlyarrayindexingforpointerarithmetic/UseOnlyArrayIndexingForPointerArithmetic.expected diff --git a/cpp/common/test/rules/useonlyarrayindexingforpointerarithmetic/UseOnlyArrayIndexingForPointerArithmetic.ql b/cpp/common/test/rules/useonlyarrayindexingforpointerarithmetic/UseOnlyArrayIndexingForPointerArithmetic.ql new file mode 100644 index 0000000000..819d12c4e8 --- /dev/null +++ b/cpp/common/test/rules/useonlyarrayindexingforpointerarithmetic/UseOnlyArrayIndexingForPointerArithmetic.ql @@ -0,0 +1,2 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.useonlyarrayindexingforpointerarithmetic.UseOnlyArrayIndexingForPointerArithmetic diff --git a/cpp/autosar/test/rules/M5-0-15/test.cpp b/cpp/common/test/rules/useonlyarrayindexingforpointerarithmetic/test.cpp similarity index 100% rename from cpp/autosar/test/rules/M5-0-15/test.cpp rename to cpp/common/test/rules/useonlyarrayindexingforpointerarithmetic/test.cpp diff --git a/cpp/misra/src/qlpack.yml b/cpp/misra/src/qlpack.yml index 2b092a00d6..1d7556c45f 100644 --- a/cpp/misra/src/qlpack.yml +++ b/cpp/misra/src/qlpack.yml @@ -1,3 +1,3 @@ name: misra-cpp-coding-standards -version: 2.4.0 +version: 2.5.0 libraryPathDependencies: common-cpp-coding-standards diff --git a/cpp/misra/test/qlpack.yml b/cpp/misra/test/qlpack.yml index 089408a7cf..886b211c97 100644 --- a/cpp/misra/test/qlpack.yml +++ b/cpp/misra/test/qlpack.yml @@ -1,4 +1,4 @@ name: misra-cpp-coding-standards-tests -version: 2.4.0 +version: 2.5.0 libraryPathDependencies: misra-cpp-coding-standards extractor: cpp diff --git a/cpp/report/src/qlpack.yml b/cpp/report/src/qlpack.yml index b4a8a6f37a..41b02cdb85 100644 --- a/cpp/report/src/qlpack.yml +++ b/cpp/report/src/qlpack.yml @@ -1,3 +1,3 @@ name: report-cpp-coding-standards -version: 2.4.0 +version: 2.5.0 libraryPathDependencies: codeql-cpp diff --git a/rule_packages/c/Concurrency1.json b/rule_packages/c/Concurrency1.json new file mode 100644 index 0000000000..2dde41e511 --- /dev/null +++ b/rule_packages/c/Concurrency1.json @@ -0,0 +1,66 @@ +{ + "CERT-C": { + "CON32-C": { + "properties": { + "obligation": "rule" + }, + "queries": [ + { + "description": "Accesses to bit fields without proper concurrency protection can result in data races.", + "kind": "problem", + "name": "Prevent data races when accessing bit-fields from multiple threads", + "precision": "very-high", + "severity": "error", + "short_name": "PreventDataRacesWithMultipleThreads", + "shared_implementation_short_name": "GuardAccessToBitFields", + "tags": [ + "correctness", + "concurrency" + ] + } + ], + "title": "Prevent data races when accessing bit-fields from multiple threads" + }, + "CON33-C": { + "properties": { + "obligation": "rule" + }, + "queries": [ + { + "description": "Certain functions may cause race conditions when used from a threaded context.", + "kind": "problem", + "name": "Avoid race conditions when using library functions", + "precision": "very-high", + "severity": "error", + "short_name": "RaceConditionsWhenUsingLibraryFunctions", + "tags": [ + "correctness", + "concurrency" + ] + } + ], + "title": "Avoid race conditions when using library functions" + }, + "CON37-C": { + "properties": { + "obligation": "rule" + }, + "queries": [ + { + "description": "Calling signal() from within a multithreaded program can result in unpredictable program behavior.", + "kind": "problem", + "name": "Do not call signal() in a multithreaded program", + "precision": "very-high", + "severity": "error", + "short_name": "DoNotCallSignalInMultithreadedProgram", + "implementation_scope" : "This implementation does not consider threads created function pointers.", + "tags": [ + "correctness", + "concurrency" + ] + } + ], + "title": "Do not call signal() in a multithreaded program" + } + } +} \ No newline at end of file diff --git a/rule_packages/c/Pointers1.json b/rule_packages/c/Pointers1.json new file mode 100644 index 0000000000..1b1b94c9c3 --- /dev/null +++ b/rule_packages/c/Pointers1.json @@ -0,0 +1,388 @@ +{ + "MISRA-C-2012": { + "RULE-11-1": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Converting between a function pointer into an incompatible type results in undefined behaviour.", + "kind": "problem", + "name": "Conversions shall not be performed between a pointer to a function and any other type", + "precision": "very-high", + "severity": "error", + "short_name": "ConversionBetweenFunctionPointerAndOtherType", + "tags": [ + "correctness" + ] + } + ], + "title": "Conversions shall not be performed between a pointer to a function and any other type", + "implementation_scope": { + "description": "None." + } + }, + "RULE-11-2": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Converting between a pointer to an incomplete type to another type can result in undefined behaviour or violate encapsulation.", + "kind": "problem", + "name": "Conversions shall not be performed between a pointer to an incomplete type and any other type", + "precision": "very-high", + "severity": "error", + "short_name": "ConversionBetweenIncompleteTypePointerAndOtherType", + "tags": [ + "correctness" + ] + } + ], + "title": "Conversions shall not be performed between a pointer to an incomplete type and any other type", + "implementation_scope": { + "description": "None." + } + }, + "RULE-11-3": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Casting between an object pointer and a pointer to a different object type can result in a pointer that is incorrectly aligned or that results in undefined behaviour if accessed.", + "kind": "problem", + "name": "A cast shall not be performed between a pointer to object type and a pointer to a different object", + "precision": "very-high", + "severity": "error", + "short_name": "CastBetweenObjectPointerAndDifferentObjectType", + "tags": [ + "correctness" + ] + } + ], + "title": "A cast shall not be performed between a pointer to object type and a pointer to a different object type", + "implementation_scope": { + "description": "None." + } + }, + "RULE-11-4": { + "properties": { + "obligation": "advisory" + }, + "queries": [ + { + "description": "Converting between a pointer to an object and an integer type may result in undefined behaviour.", + "kind": "problem", + "name": "A conversion should not be performed between a pointer to object and an integer type", + "precision": "very-high", + "severity": "error", + "short_name": "ConversionBetweenPointerToObjectAndIntegerType", + "tags": [ + "correctness" + ] + } + ], + "title": "A conversion should not be performed between a pointer to object and an integer type", + "implementation_scope": { + "description": "None." + } + }, + "RULE-11-5": { + "properties": { + "obligation": "advisory" + }, + "queries": [ + { + "description": "Converting from a pointer to void into a pointer to an object may result in an incorrectly aligned pointer and undefined behaviour.", + "kind": "problem", + "name": "A conversion should not be performed from pointer to void into pointer to object", + "precision": "very-high", + "severity": "error", + "short_name": "ConversionFromPointerToVoidIntoPointerToObject", + "tags": [ + "correctness" + ] + } + ], + "title": "A conversion should not be performed from pointer to void into pointer to object", + "implementation_scope": { + "description": "None." + } + }, + "RULE-11-6": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Converting from an integer into a pointer to void may result in an incorrectly aligned pointer and undefined behaviour.", + "kind": "problem", + "name": "A cast shall not be performed between pointer to void and an arithmetic type", + "precision": "very-high", + "severity": "error", + "short_name": "CastBetweenPointerToVoidAndArithmeticType", + "tags": [ + "correctness" + ] + } + ], + "title": "A cast shall not be performed between pointer to void and an arithmetic type", + "implementation_scope": { + "description": "None." + } + }, + "RULE-11-7": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Converting between a pointer to an object and a pointer to a non-integer arithmetic type can result in undefined behaviour.", + "kind": "problem", + "name": "A cast shall not be performed between pointer to object and a non-integer arithmetic type", + "precision": "very-high", + "severity": "error", + "short_name": "CastBetweenPointerToObjectAndNonIntArithmeticType", + "tags": [ + "correctness" + ] + } + ], + "title": "A cast shall not be performed between pointer to object and a non-integer arithmetic type", + "implementation_scope": { + "description": "None." + } + }, + "RULE-11-8": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Casting away const or volatile qualifications violates the principle of type qualification and can result in unpredictable behaviour.", + "kind": "problem", + "name": "A cast shall not remove any const or volatile qualification from the type pointed to by a pointer", + "precision": "very-high", + "severity": "error", + "short_name": "CastRemovesConstOrVolatileQualification", + "tags": [ + "correctness" + ] + } + ], + "title": "A cast shall not remove any const or volatile qualification from the type pointed to by a pointer", + "implementation_scope": { + "description": "None." + } + }, + "RULE-11-9": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "The macro NULL unambiguously signifies the intended use of a null pointer constant.", + "kind": "problem", + "name": "The macro NULL shall be the only permitted form of integer null pointer constant", + "precision": "very-high", + "severity": "error", + "short_name": "MacroNullNotUsedAsIntegerNullPointerConstant", + "tags": [ + "readability" + ] + } + ], + "title": "The macro NULL shall be the only permitted form of integer null pointer constant", + "implementation_scope": { + "description": "This rule allows two forms of null-pointer constants: a Zero literal created by the NULL macro or a Zero literal cast to a void pointer." + } + }, + "RULE-18-1": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "A pointer resulting from arithmetic on a pointer operand shall address an element of the same array as that pointer operand.", + "kind": "problem", + "name": "A pointer resulting from arithmetic on a pointer operand shall address an element of the same array", + "precision": "medium", + "severity": "error", + "short_name": "PointerAndDerivedPointerMustAddressSameArray", + "shared_implementation_short_name": "DoNotUsePointerArithmeticToAddressDifferentArrays", + "tags": [ + "correctness" + ] + } + ], + "title": "A pointer resulting from arithmetic on a pointer operand shall address an element of the same array as that pointer operand", + "implementation_scope": { + "description": "None." + } + }, + "RULE-18-2": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Subtraction between pointers which do not both point to elements of the same array results in undefined behavior.", + "kind": "path-problem", + "name": "Subtraction between pointers shall only be applied to pointers that address elements of the same array", + "precision": "high", + "severity": "error", + "short_name": "SubtractionBetweenPointersMustAddressSameArray", + "shared_implementation_short_name": "DoNotSubtractPointersAddressingDifferentArrays", + "tags": [ + "correctness" + ] + } + ], + "title": "Subtraction between pointers shall only be applied to pointers that address elements of the same array", + "implementation_scope": { + "description": "None." + } + }, + "RULE-18-3": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "The relational operators >, >=, <, <= applied to pointers produces undefined behavior, except where they point to the same object.", + "kind": "path-problem", + "name": "The relational operators >, >=, < and <= shall not be applied to pointers unless they point to the same object", + "precision": "high", + "severity": "error", + "short_name": "RelationalOperatorComparesPointerToDifferentArray", + "shared_implementation_short_name": "DoNotUseRelationalOperatorsWithDifferingArrays", + "tags": [ + "correctness" + ] + } + ], + "title": "The relational operators >, >=, < and <= shall not be applied to objects of pointer type except where they point into the same object", + "implementation_scope": { + "description": "None." + } + }, + "RULE-18-4": { + "properties": { + "obligation": "advisory" + }, + "queries": [ + { + "description": "Array indexing should be used to perform pointer arithmetic as it is less prone to errors and undefined behaviour.", + "kind": "problem", + "name": "The +, -, += and -= operators should not be applied to an expression of pointer type", + "precision": "high", + "severity": "error", + "short_name": "DoNotUseAdditionOrSubtractionOperatorsOnPointers", + "shared_implementation_short_name": "UseOnlyArrayIndexingForPointerArithmetic", + "tags": [ + "correctness" + ] + } + ], + "title": "The +, -, += and -= operators should not be applied to an expression of pointer type", + "implementation_scope": { + "description": "None." + } + }, + "RULE-18-5": { + "properties": { + "obligation": "advisory" + }, + "queries": [ + { + "description": "Declarations with more than two levels of pointer nesting can result in code that is difficult to read and understand.", + "kind": "problem", + "name": "Declarations should contain no more than two levels of pointer nesting", + "precision": "very-high", + "severity": "error", + "short_name": "NoMoreThanTwoLevelsOfPointerNestingInDeclarations", + "shared_implementation_short_name": "DoNotUseMoreThanTwoLevelsOfPointerIndirection", + "tags": [ + "readability" + ] + } + ], + "title": "Declarations should contain no more than two levels of pointer nesting", + "implementation_scope": { + "description": "None." + } + }, + "RULE-18-6": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Storing the address of an object in a new object that persists past the original object's lifetime results in undefined behaviour if the address is subsequently accessed.", + "kind": "problem", + "name": "The address of an object with automatic storage shall not be copied to another object that persists", + "precision": "very-high", + "severity": "error", + "short_name": "AutomaticStorageObjectAddressCopiedToOtherObject", + "shared_implementation_short_name": "DoNotCopyAddressOfAutoStorageObjectToOtherObject", + "tags": [ + "correctness" + ] + } + ], + "title": "The address of an object with automatic storage shall not be copied to another object that persists after the first object has ceased to exist", + "implementation_scope": { + "description": "None." + } + }, + "RULE-4-8": { + "properties": { + "obligation": "advisory" + }, + "queries": [ + { + "description": "If a pointer to a structure or union is never dereferenced within a translation unit, then the implementation of the object should be hidden to prevent unintentional changes.", + "kind": "problem", + "name": "The implementation of an object shall be hidden if a pointer to its structure or union is never dereferenced within a translation unit", + "precision": "very-high", + "severity": "error", + "short_name": "ObjectWithNoPointerDereferenceShouldBeOpaque", + "tags": [ + "readability", + "maintainability", + "readability" + ] + } + ], + "title": "If a pointer to a structure or union is never dereferenced within a translation unit, then the implementation of the object should be hidden", + "implementation_scope": { + "description": "This rule considers all cases where a structure or union is referenced as a pointer but has no FieldAccess within a translation unit. Further excluded from this rule are translation units in which the structure or union is declared as a non-pointer variable." + } + }, + "RULE-8-13": { + "properties": { + "obligation": "advisory" + }, + "queries": [ + { + "description": "A pointer should point to a const-qualified type unless it is used to modify an object or the underlying object data is copied.", + "kind": "problem", + "name": "A pointer should point to a const-qualified type whenever possible", + "precision": "high", + "severity": "error", + "short_name": "PointerShouldPointToConstTypeWhenPossible", + "tags": [ + "correctness", + "maintainability", + "readability" + ] + } + ], + "title": "A pointer should point to a const-qualified type whenever possible", + "implementation_scope": { + "description": "To exclude compliant exceptions, this rule only excludes direct assignments of pointers to non-const-qualified types in the context of a single function and does not cover memory-copying functions. This rule also excludes pointers passed to other functions without conversion." + } + } + } +} \ No newline at end of file diff --git a/rule_packages/c/Preprocessor3.json b/rule_packages/c/Preprocessor3.json new file mode 100644 index 0000000000..0b0c735a04 --- /dev/null +++ b/rule_packages/c/Preprocessor3.json @@ -0,0 +1,24 @@ +{ + "MISRA-C-2012": { + "RULE-20-8": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "A controlling expression of a #if or #elif preprocessing directive that does not evaluate to 0 or 1 makes code more difficult to understand.", + "kind": "problem", + "name": "The controlling expression of a #if or #elif preprocessing directive shall evaluate to 0 or 1", + "precision": "high", + "severity": "warning", + "short_name": "ControllingExpressionIfDirective", + "tags": [ + "maintainability", + "readability" + ] + } + ], + "title": "The controlling expression of a #if or #elif preprocessing directive shall evaluate to 0 or 1" + } + } +} \ No newline at end of file diff --git a/rule_packages/c/Strings3.json b/rule_packages/c/Strings3.json new file mode 100644 index 0000000000..dff9744cdd --- /dev/null +++ b/rule_packages/c/Strings3.json @@ -0,0 +1,44 @@ +{ + "CERT-C": { + "STR34-C": { + "properties": { + "obligation": "rule" + }, + "queries": [ + { + "description": "Not casting smaller char sizes to unsigned char before converting to lager integer sizes may lead to unpredictable program behavior.", + "kind": "problem", + "name": "Cast characters to unsigned char before converting to larger integer sizes", + "precision": "very-high", + "severity": "error", + "short_name": "CastCharBeforeConvertingToLargerSizes", + "tags": [ + "correctness", + "security" + ] + } + ], + "title": "Cast characters to unsigned char before converting to larger integer sizes" + }, + "STR38-C": { + "properties": { + "obligation": "rule" + }, + "queries": [ + { + "description": "Mixing narrow and wide character strings may cause unpredictable program behavior.", + "kind": "problem", + "name": "Do not confuse narrow and wide character strings and functions", + "precision": "very-high", + "severity": "error", + "short_name": "DoNotConfuseNarrowAndWideFunctions", + "tags": [ + "correctness", + "security" + ] + } + ], + "title": "Do not confuse narrow and wide character strings and functions" + } + } +} \ No newline at end of file diff --git a/rule_packages/cpp/Concurrency.json b/rule_packages/cpp/Concurrency.json index 5bf391c164..c79c7dc777 100644 --- a/rule_packages/cpp/Concurrency.json +++ b/rule_packages/cpp/Concurrency.json @@ -63,7 +63,8 @@ "name": "Prevent data races when accessing bit-fields from multiple threads", "precision": "very-high", "severity": "error", - "short_name": "PreventDataRacesWhenAccessingBitFieldsFromMultipleThreads", + "short_name": "PreventBitFieldAccessFromMultipleThreads", + "shared_implementation_short_name": "GuardAccessToBitFields", "tags": [ "correctness", "concurrency" diff --git a/rule_packages/cpp/Freed.json b/rule_packages/cpp/Freed.json index bc3946b1da..3e435c2b89 100644 --- a/rule_packages/cpp/Freed.json +++ b/rule_packages/cpp/Freed.json @@ -90,6 +90,7 @@ "precision": "very-high", "severity": "warning", "short_name": "AssignmentOfEscapingAutoStorage", + "shared_implementation_short_name": "DoNotCopyAddressOfAutoStorageObjectToOtherObject", "tags": [ "correctness" ] diff --git a/rule_packages/cpp/Pointers.json b/rule_packages/cpp/Pointers.json index 7a568a9a68..6a862e057c 100644 --- a/rule_packages/cpp/Pointers.json +++ b/rule_packages/cpp/Pointers.json @@ -39,6 +39,7 @@ "precision": "very-high", "severity": "warning", "short_name": "DeclarationContainLessThanTwoLevelsOfIndirection", + "shared_implementation_short_name": "DoNotUseMoreThanTwoLevelsOfPointerIndirection", "tags": [ "readability", "maintainability" @@ -181,6 +182,7 @@ "precision": "high", "severity": "recommendation", "short_name": "IndexingNotTheOnlyFormOfPointerArithmetic", + "shared_implementation_short_name": "UseOnlyArrayIndexingForPointerArithmetic", "tags": [ "correctness", "external/autosar/strict" @@ -205,6 +207,7 @@ "precision": "medium", "severity": "error", "short_name": "PointerAndDerivedPointerAccessDifferentArray", + "shared_implementation_short_name": "DoNotUsePointerArithmeticToAddressDifferentArrays", "tags": [ "correctness" ] @@ -228,6 +231,7 @@ "precision": "high", "severity": "error", "short_name": "PointerSubtractionOnDifferentArrays", + "shared_implementation_short_name": "DoNotSubtractPointersAddressingDifferentArrays", "tags": [ "correctness" ] @@ -251,6 +255,7 @@ "precision": "high", "severity": "error", "short_name": "AppliedToObjectsOfPointerType", + "shared_implementation_short_name": "DoNotUseRelationalOperatorsWithDifferingArrays", "tags": [ "correctness" ] diff --git a/rules.csv b/rules.csv index 4a77637191..891cbefd8d 100755 --- a/rules.csv +++ b/rules.csv @@ -483,20 +483,20 @@ c,CERT-C,ARR30-C,Yes,Rule,,,Do not form or use out-of-bounds pointers or array s c,CERT-C,ARR32-C,Yes,Rule,,,Ensure size arguments for variable length arrays are in a valid range,,InvalidMemory,Medium, c,CERT-C,ARR36-C,Yes,Rule,,,Do not subtract or compare two pointers that do not refer to the same array,,Memory,Medium, c,CERT-C,ARR37-C,Yes,Rule,,,Do not add or subtract an integer to a pointer to a non-array object,,InvalidMemory,Medium, -c,CERT-C,ARR38-C,Yes,Rule,,,Guarantee that library functions do not form invalid pointers,,Pointers,Medium, -c,CERT-C,ARR39-C,Yes,Rule,,,Do not add or subtract a scaled integer to a pointer,,Pointers,Medium, -c,CERT-C,CON30-C,Yes,Rule,,,Clean up thread-specific storage,,Concurrency,Very Hard, -c,CERT-C,CON31-C,Yes,Rule,,,Do not destroy a mutex while it is locked,CON50-CPP,Concurrency,Very Hard, -c,CERT-C,CON32-C,Yes,Rule,,,Prevent data races when accessing bit-fields from multiple threads,,Concurrency,Easy, -c,CERT-C,CON33-C,Yes,Rule,,,Avoid race conditions when using library functions,,Concurrency,Easy, -c,CERT-C,CON34-C,Yes,Rule,,,Declare objects shared between threads with appropriate storage durations,,Concurrency,Hard, -c,CERT-C,CON35-C,Yes,Rule,,,Avoid deadlock by locking in a predefined order,CON53-CPP,Concurrency,Medium, -c,CERT-C,CON36-C,Yes,Rule,,,Wrap functions that can spuriously wake up in a loop,CON54-CPP,Concurrency,Medium, -c,CERT-C,CON37-C,Yes,Rule,,,Do not call signal() in a multithreaded program,,Concurrency,Easy, -c,CERT-C,CON38-C,Yes,Rule,,,Preserve thread safety and liveness when using condition variables,CON55-CPP,Concurrency,Medium, -c,CERT-C,CON39-C,Yes,Rule,,,Do not join or detach a thread that was previously joined or detached,,Concurrency,Hard, -c,CERT-C,CON40-C,Yes,Rule,,,Do not refer to an atomic variable twice in an expression,,Concurrency,Medium, -c,CERT-C,CON41-C,Yes,Rule,,,Wrap functions that can fail spuriously in a loop,CON53-CPP,Concurrency,Medium, +c,CERT-C,ARR38-C,Yes,Rule,,,Guarantee that library functions do not form invalid pointers,,Pointers2,Very Hard, +c,CERT-C,ARR39-C,Yes,Rule,,,Do not add or subtract a scaled integer to a pointer,,Pointers2,Medium, +c,CERT-C,CON30-C,Yes,Rule,,,Clean up thread-specific storage,,Concurrency2,Very Hard, +c,CERT-C,CON31-C,Yes,Rule,,,Do not destroy a mutex while it is locked,CON50-CPP,Concurrency2,Very Hard, +c,CERT-C,CON32-C,Yes,Rule,,,Prevent data races when accessing bit-fields from multiple threads,,Concurrency1,Easy, +c,CERT-C,CON33-C,Yes,Rule,,,Avoid race conditions when using library functions,,Concurrency1,Easy, +c,CERT-C,CON34-C,Yes,Rule,,,Declare objects shared between threads with appropriate storage durations,,Concurrency2,Hard, +c,CERT-C,CON35-C,Yes,Rule,,,Avoid deadlock by locking in a predefined order,CON53-CPP,Concurrency2,Medium, +c,CERT-C,CON36-C,Yes,Rule,,,Wrap functions that can spuriously wake up in a loop,CON54-CPP,Concurrency2,Medium, +c,CERT-C,CON37-C,Yes,Rule,,,Do not call signal() in a multithreaded program,,Concurrency1,Easy, +c,CERT-C,CON38-C,Yes,Rule,,,Preserve thread safety and liveness when using condition variables,CON55-CPP,Concurrency2,Medium, +c,CERT-C,CON39-C,Yes,Rule,,,Do not join or detach a thread that was previously joined or detached,,Concurrency2,Hard, +c,CERT-C,CON40-C,Yes,Rule,,,Do not refer to an atomic variable twice in an expression,,Concurrency2,Medium, +c,CERT-C,CON41-C,Yes,Rule,,,Wrap functions that can fail spuriously in a loop,CON53-CPP,Concurrency2,Medium, c,CERT-C,CON43-C,OutOfScope,Rule,,,Do not allow data races in multithreaded code,,,, c,CERT-C,DCL30-C,Yes,Rule,,,Declare objects with appropriate storage durations,,Declarations,Hard, c,CERT-C,DCL31-C,Yes,Rule,,,Declare identifiers before using them,,Declarations,Medium, @@ -516,16 +516,16 @@ c,CERT-C,ERR32-C,Yes,Rule,,,Do not rely on indeterminate values of errno,,Contra c,CERT-C,ERR33-C,Yes,Rule,,,Detect and handle standard library errors,MEM52-CPP,Contracts,Hard, c,CERT-C,ERR34-C,OutOfScope,Rule,,,Detect errors when converting a string to a number,,,, c,CERT-C,EXP30-C,Yes,Rule,,,Do not depend on the order of evaluation for side effects,EXP50-CPP,SideEffects1,Easy, -c,CERT-C,EXP32-C,Yes,Rule,,,Do not access a volatile object through a nonvolatile reference,,Pointers,Easy, +c,CERT-C,EXP32-C,Yes,Rule,,,Do not access a volatile object through a nonvolatile reference,,Pointers2,Easy, c,CERT-C,EXP33-C,Yes,Rule,,,Do not read uninitialized memory,EXP53-CPP,InvalidMemory,Easy, c,CERT-C,EXP34-C,Yes,Rule,,,Do not dereference null pointers,A5-3-2,InvalidMemory,Medium, c,CERT-C,EXP35-C,Yes,Rule,,,Do not modify objects with temporary lifetime,,InvalidMemory,Hard, -c,CERT-C,EXP36-C,Yes,Rule,,,Do not cast pointers into more strictly aligned pointer types,,Pointers,Medium, +c,CERT-C,EXP36-C,Yes,Rule,,,Do not cast pointers into more strictly aligned pointer types,,Pointers2,Medium, c,CERT-C,EXP37-C,Yes,Rule,,,Call functions with the correct number and type of arguments,,Expressions,Easy, -c,CERT-C,EXP39-C,Yes,Rule,,,Do not access a variable through a pointer of an incompatible type,,Pointers,Medium, +c,CERT-C,EXP39-C,Yes,Rule,,,Do not access a variable through a pointer of an incompatible type,,Pointers2,Medium, c,CERT-C,EXP40-C,Yes,Rule,,,Do not modify constant objects,,Contracts,Medium, c,CERT-C,EXP42-C,Yes,Rule,,,Do not compare padding data,,Memory,Medium, -c,CERT-C,EXP43-C,Yes,Rule,,,Avoid undefined behavior when using restrict-qualified pointers,,Pointers,Medium, +c,CERT-C,EXP43-C,Yes,Rule,,,Avoid undefined behavior when using restrict-qualified pointers,,Pointers2,Medium, c,CERT-C,EXP44-C,Yes,Rule,,,"Do not rely on side effects in operands to sizeof, _Alignof, or _Generic",M5-3-4,SideEffects1,Medium, c,CERT-C,EXP45-C,Yes,Rule,,,Do not perform assignments in selection statements,M6-2-1,SideEffects1,Medium, c,CERT-C,EXP46-C,Yes,Rule,,,Do not use a bitwise operator with a Boolean-like operand,,Expressions,Easy, @@ -609,7 +609,7 @@ c,MISRA-C-2012,RULE-4-4,Yes,Advisory,,,Sections of code should not be commented c,MISRA-C-2012,DIR-4-5,Yes,Advisory,,,Identifiers in the same name space with overlapping visibility should be typographically unambiguous,M2-10-1,Syntax,Easy, c,MISRA-C-2012,RULE-4-6,Yes,Advisory,,,typedefs that indicate size and signedness should be used in place of the basic numerical types,,Types,Hard, c,MISRA-C-2012,RULE-4-7,Yes,Required,,,"If a function returns error information, then that error information shall be tested",M0-3-2,Contracts,Import, -c,MISRA-C-2012,RULE-4-8,Yes,Advisory,,,"If a pointer to a structure or union is never dereferenced within a translation unit, then the implementation of the object should be hidden",,Pointers,Medium, +c,MISRA-C-2012,RULE-4-8,Yes,Advisory,,,"If a pointer to a structure or union is never dereferenced within a translation unit, then the implementation of the object should be hidden",,Pointers1,Medium, c,MISRA-C-2012,RULE-4-9,Yes,Advisory,,,A function should be used in preference to a function-like macro where they are interchangeable,,Preprocessor,Medium, c,MISRA-C-2012,RULE-4-10,Yes,Required,,,Precautions shall be taken in order to prevent the contents of a header file being included more than once,M16-2-3,Preprocessor2,Medium, c,MISRA-C-2012,RULE-4-11,Yes,Required,,,The validity of values passed to library functions shall be checked,,Contracts,Hard, @@ -658,7 +658,7 @@ c,MISRA-C-2012,RULE-8-9,Yes,Advisory,,,An object should be defined at block scop c,MISRA-C-2012,RULE-8-10,Yes,Required,,,An inline function shall be declared with the static storage class,,Declarations,Medium, c,MISRA-C-2012,RULE-8-11,Yes,Advisory,,,"When an array with external linkage is declared, its size should be explicitly specified",,Declarations,Medium, c,MISRA-C-2012,RULE-8-12,Yes,Required,,,"Within an enumerator list, the value of an implicitly-specified enumeration constant shall be unique",,Declarations,Medium, -c,MISRA-C-2012,RULE-8-13,Yes,Advisory,,,A pointer should point to a const-qualified type whenever possible,,Pointers,Medium, +c,MISRA-C-2012,RULE-8-13,Yes,Advisory,,,A pointer should point to a const-qualified type whenever possible,,Pointers1,Medium, c,MISRA-C-2012,RULE-8-14,Yes,Required,,,The restrict type qualifier shall not be used,,Banned,Easy, c,MISRA-C-2012,RULE-9-1,Yes,Mandatory,,,The value of an object with automatic storage duration shall not be read before it has been set,,InvalidMemory,Medium, c,MISRA-C-2012,RULE-9-2,Yes,Required,,,The initializer for an aggregate or union shall be enclosed in braces,,Memory,Easy, @@ -673,15 +673,15 @@ c,MISRA-C-2012,RULE-10-5,Yes,Advisory,,,The value of an expression should not be c,MISRA-C-2012,RULE-10-6,Yes,Required,,,The value of a composite expression shall not be assigned to an object with wider essential type,,Types,Medium, c,MISRA-C-2012,RULE-10-7,Yes,Required,,,If a composite expression is used as one operand of an operator in which the usual arithmetic conversions are performed then the other operand shall not have wider essential type,,Types,Medium, c,MISRA-C-2012,RULE-10-8,Yes,Required,,,The value of a composite expression shall not be cast to a different essential type category or a wider essential type,,Types,Medium, -c,MISRA-C-2012,RULE-11-1,Yes,Required,,,Conversions shall not be performed between a pointer to a function and any other type,M5-2-6,Pointers,Import, -c,MISRA-C-2012,RULE-11-2,Yes,Required,,,Conversions shall not be performed between a pointer to an incomplete type and any other type,,Pointers,Easy, -c,MISRA-C-2012,RULE-11-3,Yes,Required,,,A cast shall not be performed between a pointer to object type and a pointer to a different object type,,Pointers,Easy, -c,MISRA-C-2012,RULE-11-4,Yes,Advisory,,,A conversion should not be performed between a pointer to object and an integer type,M-2-9,Pointers,Import, -c,MISRA-C-2012,RULE-11-5,Yes,Advisory,,,A conversion should not be performed from pointer to void into pointer to object,,Pointers,Easy, -c,MISRA-C-2012,RULE-11-6,Yes,Required,,,A cast shall not be performed between pointer to void and an arithmetic type,,Pointers,Easy, -c,MISRA-C-2012,RULE-11-7,Yes,Required,,,A cast shall not be performed between pointer to object and a non- integer arithmetic type,,Pointers,Easy, -c,MISRA-C-2012,RULE-11-8,Yes,Required,,,A cast shall not remove any const or volatile qualification from the type pointed to by a pointer,,Pointers,Easy, -c,MISRA-C-2012,RULE-11-9,Yes,Required,,,The macro NULL shall be the only permitted form of integer null pointer constant,,Pointers,Easy, +c,MISRA-C-2012,RULE-11-1,Yes,Required,,,Conversions shall not be performed between a pointer to a function and any other type,M5-2-6,Pointers1,Import, +c,MISRA-C-2012,RULE-11-2,Yes,Required,,,Conversions shall not be performed between a pointer to an incomplete type and any other type,,Pointers1,Easy, +c,MISRA-C-2012,RULE-11-3,Yes,Required,,,A cast shall not be performed between a pointer to object type and a pointer to a different object type,,Pointers1,Easy, +c,MISRA-C-2012,RULE-11-4,Yes,Advisory,,,A conversion should not be performed between a pointer to object and an integer type,M-2-9,Pointers1,Easy, +c,MISRA-C-2012,RULE-11-5,Yes,Advisory,,,A conversion should not be performed from pointer to void into pointer to object,,Pointers1,Easy, +c,MISRA-C-2012,RULE-11-6,Yes,Required,,,A cast shall not be performed between pointer to void and an arithmetic type,,Pointers1,Easy, +c,MISRA-C-2012,RULE-11-7,Yes,Required,,,A cast shall not be performed between pointer to object and a non- integer arithmetic type,,Pointers1,Easy, +c,MISRA-C-2012,RULE-11-8,Yes,Required,,,A cast shall not remove any const or volatile qualification from the type pointed to by a pointer,,Pointers1,Easy, +c,MISRA-C-2012,RULE-11-9,Yes,Required,,,The macro NULL shall be the only permitted form of integer null pointer constant,,Pointers1,Easy, c,MISRA-C-2012,RULE-12-1,Yes,Advisory,,,The precedence of operators within expressions should be made explicit,,SideEffects1,Medium, c,MISRA-C-2012,RULE-12-2,Yes,Required,,,The right hand operand of a shift operator shall lie in the range zero to one less than the width in bits of the essential type of the left hand operand,,Contracts,Hard, c,MISRA-C-2012,RULE-12-3,Yes,Advisory,,,The comma operator should not be used,M5-18-1,Banned,Import, @@ -719,12 +719,12 @@ c,MISRA-C-2012,RULE-17-5,Yes,Advisory,,,The function argument corresponding to a c,MISRA-C-2012,RULE-17-6,Yes,Mandatory,,,The declaration of an array parameter shall not contain the static keyword between the [ ],,Declarations,Easy, c,MISRA-C-2012,RULE-17-7,Yes,Required,,,The value returned by a function having non-void return type shall be used,A0-1-2,Contracts,Import, c,MISRA-C-2012,RULE-17-8,Yes,Advisory,,,A function parameter should not be modified,,SideEffects2,Medium, -c,MISRA-C-2012,RULE-18-1,Yes,Required,,,A pointer resulting from arithmetic on a pointer operand shall address an element of the same array as that pointer operand,M5-0-16,Pointers,Import, -c,MISRA-C-2012,RULE-18-2,Yes,Required,,,Subtraction between pointers shall only be applied to pointers that address elements of the same array,M5-0-17,Pointers,Import, -c,MISRA-C-2012,RULE-18-3,Yes,Required,,,"The relational operators >, >=, < and <= shall not be applied to objects of pointer type except where they point into the same object",M5-0-18,Pointers,Import, -c,MISRA-C-2012,RULE-18-4,Yes,Advisory,,,"The +, -, += and -= operators should not be applied to an expression of pointer type",,Pointers,Medium, -c,MISRA-C-2012,RULE-18-5,Yes,Advisory,,,Declarations should contain no more than two levels of pointer nesting,,Pointers,Medium, -c,MISRA-C-2012,RULE-18-6,Yes,Required,,,The address of an object with automatic storage shall not be copied to another object that persists after the first object has ceased to exist,M7-5-2,Pointers,Import, +c,MISRA-C-2012,RULE-18-1,Yes,Required,,,A pointer resulting from arithmetic on a pointer operand shall address an element of the same array as that pointer operand,M5-0-16,Pointers1,Import, +c,MISRA-C-2012,RULE-18-2,Yes,Required,,,Subtraction between pointers shall only be applied to pointers that address elements of the same array,M5-0-17,Pointers1,Import, +c,MISRA-C-2012,RULE-18-3,Yes,Required,,,"The relational operators >, >=, < and <= shall not be applied to objects of pointer type except where they point into the same object",M5-0-18,Pointers1,Import, +c,MISRA-C-2012,RULE-18-4,Yes,Advisory,,,"The +, -, += and -= operators should not be applied to an expression of pointer type",M5-0-15,Pointers1,Medium, +c,MISRA-C-2012,RULE-18-5,Yes,Advisory,,,Declarations should contain no more than two levels of pointer nesting,A5-0-3,Pointers1,Import, +c,MISRA-C-2012,RULE-18-6,Yes,Required,,,The address of an object with automatic storage shall not be copied to another object that persists after the first object has ceased to exist,M7-5-2,Pointers1,Import, c,MISRA-C-2012,RULE-18-7,Yes,Required,,,Flexible array members shall not be declared,,Declarations,Medium, c,MISRA-C-2012,RULE-18-8,Yes,Required,,,Variable-length array types shall not be used,,Declarations,Medium, c,MISRA-C-2012,RULE-19-1,Yes,Mandatory,,,An object shall not be assigned or copied to an overlapping object,M0-2-1,Contracts,Hard, @@ -736,7 +736,7 @@ c,MISRA-C-2012,RULE-20-4,Yes,Required,,,A macro shall not be defined with the sa c,MISRA-C-2012,RULE-20-5,Yes,Advisory,,,#undef should not be used,,Preprocessor2,Easy, c,MISRA-C-2012,RULE-20-6,Yes,Required,,,Tokens that look like a preprocessing directive shall not occur within a macro argument,M16-0-5,Preprocessor,Import, c,MISRA-C-2012,RULE-20-7,Yes,Required,,,Expressions resulting from the expansion of macro parameters shall be enclosed in parentheses,M16-0-6,Preprocessor,Easy, -c,MISRA-C-2012,RULE-20-8,Yes,Required,,,The controlling expression of a #if or #elif preprocessing directive shall evaluate to 0 or 1,,,Hard, +c,MISRA-C-2012,RULE-20-8,Yes,Required,,,The controlling expression of a #if or #elif preprocessing directive shall evaluate to 0 or 1,,Preprocessor3,Hard, c,MISRA-C-2012,RULE-20-9,Yes,Required,,,All identifiers used in the controlling expression of #if or #elif preprocessing directives shall be #defined before evaluation,M16-0-7,Preprocessor1,Import, c,MISRA-C-2012,RULE-20-10,Yes,Advisory,,,The # and ## preprocessor operators should not be used,M16-3-2,Preprocessor1,Import, c,MISRA-C-2012,RULE-20-11,Yes,Required,,,A macro parameter immediately following a # operator shall not immediately be followed by a ## operator,M16-3-1,Preprocessor2,Easy, From 77bf4a7ebd13529ae223dc713b6004140cbae157 Mon Sep 17 00:00:00 2001 From: Remco Vermeulen Date: Wed, 13 Jul 2022 12:17:50 +0200 Subject: [PATCH 0006/2973] Open sourcing CodeQL Coding Standards --- .github/pull_request_template.md | 6 +- .github/workflows/code-scanning-pack-gen.yml | 60 +- .github/workflows/codeql_unit_tests.yml | 7 +- .github/workflows/create-draft-release.yml | 5 + .github/workflows/generate-html-docs.yml | 7 + .../standard_library_upgrade_tests.yml | 7 +- .../workflows/validate-coding-standards.yml | 71 +- CODE_OF_CONDUCT.md | 126 +++ CONTRIBUTING.md | 55 ++ LICENSE.md | 21 + README.md | 35 +- SECURITY.md | 3 + c/cert/src/qlpack.yml | 2 +- ...ataRacesWithMultipleThreads-standard.qhelp | 33 - .../PreventDataRacesWithMultipleThreads.md | 156 ++++ .../PreventDataRacesWithMultipleThreads.qhelp | 18 - c/cert/src/rules/CON32-C/standard-example.c | 0 ...nsWhenUsingLibraryFunctions-standard.qhelp | 33 - ...RaceConditionsWhenUsingLibraryFunctions.md | 159 ++++ ...eConditionsWhenUsingLibraryFunctions.qhelp | 18 - c/cert/src/rules/CON33-C/standard-example.c | 0 ...ignalInMultithreadedProgram-standard.qhelp | 33 - .../DoNotCallSignalInMultithreadedProgram.md | 110 +++ ...oNotCallSignalInMultithreadedProgram.qhelp | 21 - c/cert/src/rules/CON37-C/standard-example.c | 0 ...tionArgumentsForSideEffects-standard.qhelp | 679 -------------- ...nOrderOfFunctionArgumentsForSideEffects.md | 224 +++++ ...derOfFunctionArgumentsForSideEffects.qhelp | 18 - ...larEvaluationForSideEffects-standard.qhelp | 679 -------------- ...OnOrderOfScalarEvaluationForSideEffects.md | 224 +++++ ...rderOfScalarEvaluationForSideEffects.qhelp | 18 - c/cert/src/rules/EXP30-C/standard-example.c | 0 ...luatedOperandWithSideEffect-standard.qhelp | 481 ---------- .../UnevaluatedOperandWithSideEffect.md | 195 ++++ .../UnevaluatedOperandWithSideEffect.qhelp | 18 - c/cert/src/rules/EXP44-C/standard-example.c | 0 ...nmentsInSelectionStatements-standard.qhelp | 688 -------------- .../AssignmentsInSelectionStatements.md | 212 +++++ .../AssignmentsInSelectionStatements.qhelp | 18 - c/cert/src/rules/EXP45-C/standard-example.c | 0 ...eUserInputFromFormatStrings-standard.qhelp | 585 ------------ .../ExcludeUserInputFromFormatStrings.md | 169 ++++ .../ExcludeUserInputFromFormatStrings.qhelp | 18 - c/cert/src/rules/FIO30-C/standard-example.c | 0 ...formFileOperationsOnDevices-standard.qhelp | 594 ------------ .../DoNotPerformFileOperationsOnDevices.md | 252 ++++++ .../DoNotPerformFileOperationsOnDevices.qhelp | 18 - ...arReadFromAFileAndEofOrWeof-standard.qhelp | 547 ------------ ...ishBetweenCharReadFromAFileAndEofOrWeof.md | 202 +++++ ...BetweenCharReadFromAFileAndEofOrWeof.qhelp | 18 - .../EndOfFileCheckPortability-standard.qhelp | 547 ------------ .../FIO34-C/EndOfFileCheckPortability.md | 202 +++++ .../FIO34-C/EndOfFileCheckPortability.qhelp | 18 - c/cert/src/rules/FIO34-C/standard-example.c | 0 ...getwsMayReturnAnEmptyString-standard.qhelp | 392 -------- ...sfulFgetsOrFgetwsMayReturnAnEmptyString.md | 105 +++ ...lFgetsOrFgetwsMayReturnAnEmptyString.qhelp | 18 - .../DoNotCopyAFileObject-standard.qhelp | 368 -------- .../src/rules/FIO38-C/DoNotCopyAFileObject.md | 82 ++ .../rules/FIO38-C/DoNotCopyAFileObject.qhelp | 18 - c/cert/src/rules/FIO38-C/standard-example.c | 0 ...omAStreamWithoutPositioning-standard.qhelp | 384 -------- ...ernatelyIOFromAStreamWithoutPositioning.md | 138 +++ ...atelyIOFromAStreamWithoutPositioning.qhelp | 18 - ...ringsOnFgetsOrFgetwsFailure-standard.qhelp | 219 ----- .../ResetStringsOnFgetsOrFgetwsFailure.md | 70 ++ .../ResetStringsOnFgetsOrFgetwsFailure.qhelp | 18 - c/cert/src/rules/FIO40-C/standard-example.c | 0 ...lGetcAndPutcWithSideEffects-standard.qhelp | 363 -------- .../DoNotCallGetcAndPutcWithSideEffects.md | 143 +++ .../DoNotCallGetcAndPutcWithSideEffects.qhelp | 18 - c/cert/src/rules/FIO41-C/standard-example.c | 0 ...esWhenTheyAreNoLongerNeeded-standard.qhelp | 604 ------------- .../CloseFilesWhenTheyAreNoLongerNeeded.md | 232 +++++ .../CloseFilesWhenTheyAreNoLongerNeeded.qhelp | 18 - c/cert/src/rules/FIO42-C/standard-example.c | 0 ...sThatAreReturnedFromFgetpos-standard.qhelp | 331 ------- ...uesForFsetposThatAreReturnedFromFgetpos.md | 111 +++ ...ForFsetposThatAreReturnedFromFgetpos.qhelp | 18 - c/cert/src/rules/FIO44-C/standard-example.c | 0 ...ehaviorAccessingAClosedFile-standard.qhelp | 339 ------- .../UndefinedBehaviorAccessingAClosedFile.md | 71 ++ ...ndefinedBehaviorAccessingAClosedFile.qhelp | 18 - c/cert/src/rules/FIO46-C/standard-example.c | 0 ...neratingPseudorandomNumbers-standard.qhelp | 597 ------------- ...andUsedForGeneratingPseudorandomNumbers.md | 170 ++++ ...UsedForGeneratingPseudorandomNumbers.qhelp | 18 - ...seudorandomNumberGenerators-standard.qhelp | 425 --------- ...roperlySeedPseudorandomNumberGenerators.md | 165 ++++ ...erlySeedPseudorandomNumberGenerators.qhelp | 18 - ...hesTheEndOfANonVoidFunction-standard.qhelp | 524 ----------- ...trolFlowReachesTheEndOfANonVoidFunction.md | 219 +++++ ...lFlowReachesTheEndOfANonVoidFunction.qhelp | 18 - ...temptToModifyStringLiterals-standard.qhelp | 33 - .../DoNotAttemptToModifyStringLiterals.md | 160 ++++ .../DoNotAttemptToModifyStringLiterals.qhelp | 18 - c/cert/src/rules/STR30-C/standard-example.c | 0 ...ntSpaceForTheNullTerminator-standard.qhelp | 33 - ...sHasSufficientSpaceForTheNullTerminator.md | 581 ++++++++++++ ...sSufficientSpaceForTheNullTerminator.qhelp | 18 - c/cert/src/rules/STR31-C/standard-example.c | 0 ...oFunctionThatExpectsAString-standard.qhelp | 33 - ...lTerminatedToFunctionThatExpectsAString.md | 278 ++++++ ...rminatedToFunctionThatExpectsAString.qhelp | 18 - c/cert/src/rules/STR32-C/standard-example.c | 0 ...foreConvertingToLargerSizes-standard.qhelp | 33 - .../CastCharBeforeConvertingToLargerSizes.md | 162 ++++ ...astCharBeforeConvertingToLargerSizes.qhelp | 18 - c/cert/src/rules/STR34-C/standard-example.c | 0 ...nctionsRepresentableAsUChar-standard.qhelp | 33 - ...erHandlingFunctionsRepresentableAsUChar.md | 118 +++ ...andlingFunctionsRepresentableAsUChar.qhelp | 18 - c/cert/src/rules/STR37-C/standard-example.c | 0 ...nfuseNarrowAndWideFunctions-standard.qhelp | 33 - .../DoNotConfuseNarrowAndWideFunctions.md | 138 +++ .../DoNotConfuseNarrowAndWideFunctions.qhelp | 18 - c/cert/src/rules/STR38-C/standard-example.c | 0 c/cert/test/qlpack.yml | 2 +- c/common/src/qlpack.yml | 2 +- .../test/includes/standard-library/LICENSE | 193 ++++ c/common/test/qlpack.yml | 2 +- c/misra/src/qlpack.yml | 2 +- .../src/rules/DIR-4-5/standard-example.cpp | 18 - .../src/rules/RULE-11-1/standard-example.c | 0 .../src/rules/RULE-11-2/standard-example.c | 0 .../src/rules/RULE-11-3/standard-example.c | 0 .../src/rules/RULE-11-4/standard-example.c | 0 .../src/rules/RULE-11-5/standard-example.c | 0 .../src/rules/RULE-11-6/standard-example.c | 0 .../src/rules/RULE-11-7/standard-example.c | 0 .../src/rules/RULE-11-8/standard-example.c | 0 .../src/rules/RULE-11-9/standard-example.c | 0 .../src/rules/RULE-12-1/standard-example.c | 0 .../src/rules/RULE-13-1/standard-example.c | 0 .../src/rules/RULE-13-3/standard-example.c | 0 .../src/rules/RULE-13-4/standard-example.c | 0 .../src/rules/RULE-13-5/standard-example.c | 0 .../src/rules/RULE-13-6/standard-example.c | 0 .../src/rules/RULE-17-8/standard-example.c | 0 .../src/rules/RULE-18-1/standard-example.c | 0 .../src/rules/RULE-18-2/standard-example.c | 0 .../src/rules/RULE-18-3/standard-example.c | 0 .../src/rules/RULE-18-4/standard-example.c | 0 .../src/rules/RULE-18-5/standard-example.c | 0 .../src/rules/RULE-18-6/standard-example.c | 0 .../src/rules/RULE-20-1/standard-example.c | 5 - .../src/rules/RULE-20-11/standard-example.c | 3 - .../src/rules/RULE-20-12/standard-example.c | 7 - .../src/rules/RULE-20-2/standard-example.c | 1 - .../src/rules/RULE-20-5/standard-example.c | 7 - .../src/rules/RULE-20-8/standard-example.c | 11 - .../src/rules/RULE-20-9/standard-example.c | 11 - .../src/rules/RULE-22-3/standard-example.c | 5 - .../src/rules/RULE-22-4/standard-example.c | 6 - .../src/rules/RULE-22-5/standard-example.c | 8 - .../src/rules/RULE-22-6/standard-example.c | 15 - .../src/rules/RULE-22-7/standard-example1.c | 10 - .../src/rules/RULE-22-7/standard-example2.c | 19 - .../src/rules/RULE-4-10/standard-example.c | 12 - c/misra/src/rules/RULE-4-8/standard-example.c | 0 .../src/rules/RULE-8-13/standard-example.c | 0 c/misra/test/qlpack.yml | 2 +- .../2021-10-26-enable-lifetime-profile.md | 2 + change_notes/2022-03-04-address-fp-m7-3-4.md | 1 + change_notes/2022-03-16-fix-placeholders.md | 4 + change_notes/2022-03-18 | 1 + change_notes/2022-03-18-address-fp-A3-3-1.md | 1 + ...06-24-use-variable-entry-type-in-M3-2-1.md | 2 + cpp/autosar/src/qlpack.yml | 2 +- .../src/rules/A0-1-1/standard-example.cpp | 57 -- .../src/rules/A0-1-2/standard-example.cpp | 15 - .../src/rules/A0-1-3/standard-example.cpp | 43 - .../src/rules/A0-1-4/standard-example.cpp | 48 - .../src/rules/A0-1-5/standard-example.cpp | 42 - .../src/rules/A0-1-6/standard-example.cpp | 6 - .../src/rules/A0-4-1/standard-example.cpp | 14 - .../src/rules/A0-4-2/standard-example.cpp | 7 - .../src/rules/A0-4-4/standard-example.cpp | 23 - .../src/rules/A1-1-1/standard-example.cpp | 24 - .../src/rules/A10-1-1/standard-example.cpp | 44 - .../src/rules/A10-2-1/standard-example.cpp | 31 - .../src/rules/A10-3-1/standard-example.cpp | 60 -- .../src/rules/A10-3-2/standard-example.cpp | 46 - .../src/rules/A10-3-3/standard-example.cpp | 22 - .../src/rules/A10-3-5/standard-example.cpp | 76 -- .../src/rules/A11-0-1/standard-example.cpp | 50 -- .../src/rules/A11-0-2/standard-example.cpp | 41 - .../src/rules/A11-3-1/standard-example.cpp | 21 - .../src/rules/A12-0-1/standard-example.cpp | 109 --- .../src/rules/A12-0-2/standard-example.cpp | 109 --- .../src/rules/A12-1-1/standard-example.cpp | 27 - .../src/rules/A12-1-2/standard-example.cpp | 45 - .../src/rules/A12-1-3/standard-example.cpp | 25 - .../src/rules/A12-1-4/standard-example.cpp | 40 - .../src/rules/A12-1-5/standard-example.cpp | 18 - .../src/rules/A12-1-6/standard-example.cpp | 26 - .../src/rules/A12-4-1/standard-example.cpp | 41 - .../src/rules/A12-4-2/standard-example.cpp | 55 -- .../src/rules/A12-6-1/standard-example.cpp | 43 - .../src/rules/A12-7-1/standard-example.cpp | 78 -- .../src/rules/A12-8-1/standard-example.cpp | 62 -- .../src/rules/A12-8-2/standard-example.cpp | 66 -- .../src/rules/A12-8-3/standard-example.cpp | 22 - .../src/rules/A12-8-4/standard-example.cpp | 46 - .../src/rules/A12-8-5/standard-example.cpp | 63 -- .../src/rules/A12-8-6/standard-example.cpp | 128 --- .../src/rules/A12-8-7/standard-example.cpp | 43 - .../src/rules/A13-1-2/standard-example.cpp | 27 - .../src/rules/A13-1-3/standard-example.cpp | 42 - .../src/rules/A13-2-1/standard-example.cpp | 44 - .../src/rules/A13-2-2/standard-example.cpp | 26 - .../src/rules/A13-2-3/standard-example.cpp | 30 - .../src/rules/A13-3-1/standard-example.cpp | 36 - .../src/rules/A13-5-1/standard-example.cpp | 38 - .../src/rules/A13-5-2/standard-example.cpp | 18 - .../src/rules/A13-5-3/standard-example.cpp | 21 - .../src/rules/A13-5-4/standard-example.cpp | 37 - .../src/rules/A13-5-5/standard-example.cpp | 55 -- .../src/rules/A13-6-1/standard-example.cpp | 14 - .../src/rules/A14-1-1/standard-example.cpp | 88 -- .../src/rules/A14-5-1/standard-example.cpp | 61 -- .../src/rules/A14-5-2/standard-example.cpp | 31 - .../src/rules/A14-5-3/standard-example.cpp | 32 - .../src/rules/A14-7-1/standard-example.cpp | 53 -- .../src/rules/A14-7-2/standard-example.cpp | 53 -- .../src/rules/A14-8-2/standard-example.cpp | 54 -- .../src/rules/A15-0-1/standard-example.cpp | 127 --- .../src/rules/A15-0-2/standard-example.cpp | 96 -- .../src/rules/A15-0-3/standard-example.cpp | 66 -- .../src/rules/A15-0-4/standard-example.cpp | 82 -- .../src/rules/A15-0-5/standard-example.cpp | 102 --- .../src/rules/A15-1-1/standard-example.cpp | 51 -- .../src/rules/A15-1-2/standard-example.cpp | 36 - .../src/rules/A15-1-3/standard-example.cpp | 67 -- .../src/rules/A15-1-4/standard-example.cpp | 156 ---- .../src/rules/A15-1-5/standard-example.cpp | 0 .../src/rules/A15-2-1/standard-example.cpp | 40 - .../src/rules/A15-2-2/standard-example.cpp | 98 -- .../src/rules/A15-3-3/standard-example.cpp | 64 -- .../src/rules/A15-3-4/standard-example.cpp | 110 --- .../src/rules/A15-3-5/standard-example.cpp | 38 - .../src/rules/A15-4-1/standard-example.cpp | 12 - .../src/rules/A15-4-2/standard-example.cpp | 29 - .../src/rules/A15-4-3/standard-example.cpp | 50 -- .../src/rules/A15-4-4/standard-example.cpp | 66 -- .../src/rules/A15-4-5/standard-example.cpp | 68 -- .../src/rules/A15-5-1/standard-example.cpp | 130 --- .../src/rules/A15-5-2/standard-example.cpp | 42 - .../src/rules/A15-5-3/standard-example.cpp | 58 -- .../src/rules/A16-0-1/standard-example.cpp | 51 -- .../src/rules/A16-2-1/standard-example.cpp | 10 - .../src/rules/A16-2-2/standard-example.cpp | 23 - .../src/rules/A16-6-1/standard-example.cpp | 19 - .../src/rules/A16-7-1/standard-example.cpp | 6 - .../src/rules/A17-0-1/standard-example.cpp | 3 - .../src/rules/A17-1-1/standard-example.cpp | 54 -- .../src/rules/A17-6-1/standard-example.cpp | 52 -- .../src/rules/A18-0-2/standard-example.cpp | 34 - .../src/rules/A18-1-1/standard-example.cpp | 19 - .../src/rules/A18-1-2/standard-example.cpp | 20 - .../src/rules/A18-1-3/standard-example.cpp | 11 - .../src/rules/A18-1-4/standard-example.cpp | 42 - .../src/rules/A18-1-6/standard-example.cpp | 73 -- .../src/rules/A18-5-1/standard-example.cpp | 51 -- .../src/rules/A18-5-10/standard-example.cpp | 14 - .../src/rules/A18-5-11/standard-example.cpp | 17 - .../src/rules/A18-5-2/standard-example.cpp | 63 -- .../src/rules/A18-5-3/standard-example.cpp | 30 - .../src/rules/A18-5-4/standard-example.cpp | 12 - .../src/rules/A18-5-5/standard-example.cpp | 31 - .../src/rules/A18-5-8/standard-example.cpp | 32 - .../src/rules/A18-5-9/standard-example.cpp | 8 - .../src/rules/A18-9-1/standard-example.cpp | 29 - .../src/rules/A18-9-2/standard-example.cpp | 45 - .../src/rules/A18-9-3/standard-example.cpp | 13 - .../src/rules/A18-9-4/standard-example.cpp | 14 - .../src/rules/A2-10-1/standard-example.cpp | 51 -- .../src/rules/A2-10-4/standard-example.cpp | 23 - .../src/rules/A2-10-5/standard-example.cpp | 22 - .../src/rules/A2-10-6/standard-example.cpp | 35 - .../src/rules/A2-13-1/standard-example.cpp | 8 - .../src/rules/A2-13-3/standard-example.cpp | 4 - .../src/rules/A2-13-4/standard-example.cpp | 17 - .../src/rules/A2-13-5/standard-example.cpp | 11 - .../src/rules/A2-13-6/standard-example.cpp | 12 - .../src/rules/A2-3-1/standard-example.cpp | 9 - .../src/rules/A2-7-1/standard-example.cpp | 13 - .../src/rules/A2-7-2/standard-example.cpp | 34 - .../src/rules/A2-7-3/standard-example.cpp | 39 - .../src/rules/A20-8-1/standard-example.cpp | 14 - .../src/rules/A20-8-2/standard-example.cpp | 32 - .../src/rules/A20-8-3/standard-example.cpp | 39 - .../src/rules/A20-8-4/standard-example.cpp | 40 - .../src/rules/A20-8-5/standard-example.cpp | 32 - .../src/rules/A20-8-6/standard-example.cpp | 32 - .../src/rules/A20-8-7/standard-example.cpp | 50 -- .../src/rules/A21-8-1/standard-example.cpp | 19 - .../src/rules/A23-0-1/standard-example.cpp | 31 - .../src/rules/A23-0-2/standard-example.cpp | 29 - .../src/rules/A25-1-1/standard-example.cpp | 87 -- .../src/rules/A25-4-1/standard-example.cpp | 22 - .../src/rules/A26-5-1/standard-example.cpp | 18 - .../src/rules/A26-5-2/standard-example.cpp | 20 - .../src/rules/A27-0-1/standard-example.cpp | 46 - .../src/rules/A27-0-2/standard-example.cpp | 45 - .../src/rules/A27-0-3/standard-example.cpp | 18 - .../src/rules/A27-0-4/standard-example.cpp | 21 - .../src/rules/A3-1-1/standard-example.cpp | 16 - .../src/rules/A3-1-2/standard-example.cpp | 8 - .../src/rules/A3-1-4/standard-example.cpp | 4 - .../src/rules/A3-1-5/standard-example.cpp | 80 -- .../src/rules/A3-1-6/standard-example.cpp | 25 - .../ExternalLinkageNotDeclaredInHeaderFile.ql | 4 +- .../src/rules/A3-3-1/standard-example.cpp | 54 -- .../src/rules/A3-3-2/standard-example.cpp | 53 -- .../ObjectAccessedAfterLifetimeAutosar.ql | 1 - .../ObjectAccessedBeforeLifetimeAutosar.ql | 1 - .../src/rules/A3-8-1/standard-example.cpp | 86 -- .../src/rules/A3-9-1/standard-example.cpp | 10 - .../src/rules/A4-10-1/standard-example.cpp | 28 - .../src/rules/A4-5-1/standard-example.cpp | 81 -- .../src/rules/A4-7-1/standard-example.cpp | 58 -- .../src/rules/A5-0-1/standard-example.cpp | 140 --- .../src/rules/A5-0-2/standard-example.cpp | 67 -- .../src/rules/A5-0-3/standard-example.cpp | 55 -- .../src/rules/A5-0-4/standard-example.cpp | 73 -- .../src/rules/A5-1-1/standard-example.cpp | 65 -- .../src/rules/A5-1-2/standard-example.cpp | 25 - .../src/rules/A5-1-3/standard-example.cpp | 12 - .../src/rules/A5-1-4/standard-example.cpp | 23 - .../src/rules/A5-1-6/standard-example.cpp | 16 - .../src/rules/A5-1-7/standard-example.cpp | 42 - .../src/rules/A5-1-8/standard-example.cpp | 19 - .../src/rules/A5-1-9/standard-example.cpp | 19 - .../src/rules/A5-10-1/standard-example.cpp | 16 - .../src/rules/A5-16-1/standard-example.cpp | 18 - .../src/rules/A5-2-1/standard-example.cpp | 25 - .../src/rules/A5-2-2/standard-example.cpp | 38 - .../src/rules/A5-2-3/standard-example.cpp | 29 - .../src/rules/A5-2-4/standard-example.cpp | 40 - .../src/rules/A5-2-5/standard-example.cpp | 66 -- .../src/rules/A5-2-6/standard-example.cpp | 18 - .../src/rules/A5-3-1/standard-example.cpp | 23 - .../rules/A5-3-2/NullPointersDereferenced.ql | 1 - .../src/rules/A5-3-2/standard-example.cpp | 31 - .../src/rules/A5-3-3/standard-example.cpp | 61 -- .../src/rules/A5-5-1/standard-example.cpp | 34 - .../src/rules/A5-6-1/standard-example.cpp | 23 - .../src/rules/A6-2-1/standard-example.cpp | 89 -- .../src/rules/A6-2-2/standard-example.cpp | 29 - .../src/rules/A6-4-1/standard-example.cpp | 44 - .../src/rules/A6-5-1/standard-example.cpp | 44 - .../src/rules/A6-5-2/standard-example.cpp | 35 - .../src/rules/A6-5-3/standard-example.cpp | 38 - .../src/rules/A6-5-4/standard-example.cpp | 10 - .../src/rules/A6-6-1/standard-example.cpp | 37 - .../src/rules/A7-1-1/standard-example.cpp | 11 - .../src/rules/A7-1-2/standard-example.cpp | 42 - .../src/rules/A7-1-3/standard-example.cpp | 33 - .../src/rules/A7-1-4/standard-example.cpp | 12 - .../src/rules/A7-1-5/standard-example.cpp | 44 - .../src/rules/A7-1-6/standard-example.cpp | 13 - .../src/rules/A7-1-7/standard-example.cpp | 31 - .../src/rules/A7-1-9/standard-example.cpp | 26 - .../src/rules/A7-2-1/standard-example.cpp | 63 -- .../src/rules/A7-2-2/standard-example.cpp | 27 - .../src/rules/A7-2-3/standard-example.cpp | 29 - .../src/rules/A7-2-4/standard-example.cpp | 19 - .../src/rules/A7-2-5/standard-example.cpp | 16 - .../src/rules/A7-3-1/standard-example.cpp | 77 -- .../src/rules/A7-4-1/standard-example.cpp | 22 - .../src/rules/A7-5-1/standard-example.cpp | 69 -- .../src/rules/A7-5-2/standard-example.cpp | 54 -- .../src/rules/A7-6-1/standard-example.cpp | 23 - .../src/rules/A8-4-1/standard-example.cpp | 11 - .../src/rules/A8-4-10/standard-example.cpp | 16 - .../src/rules/A8-4-11/standard-example.cpp | 52 -- .../src/rules/A8-4-12/standard-example.cpp | 41 - .../src/rules/A8-4-13/standard-example.cpp | 38 - .../src/rules/A8-4-2/standard-example.cpp | 21 - .../src/rules/A8-4-4/standard-example.cpp | 28 - .../src/rules/A8-4-5/standard-example.cpp | 24 - .../src/rules/A8-4-6/standard-example.cpp | 26 - .../src/rules/A8-4-7/standard-example.cpp | 28 - .../src/rules/A8-4-8/standard-example.cpp | 42 - .../src/rules/A8-4-9/standard-example.cpp | 23 - .../src/rules/A8-5-0/standard-example.cpp | 68 -- .../src/rules/A8-5-1/standard-example.cpp | 37 - .../src/rules/A8-5-2/standard-example.cpp | 66 -- .../src/rules/A8-5-3/standard-example.cpp | 16 - .../src/rules/A8-5-4/standard-example.cpp | 42 - .../src/rules/A9-3-1/standard-example.cpp | 77 -- .../src/rules/A9-5-1/standard-example.cpp | 29 - .../src/rules/A9-6-1/standard-example.cpp | 60 -- .../src/rules/M0-1-1/standard-example.cpp | 15 - .../src/rules/M0-1-10/standard-example.cpp | 7 - .../src/rules/M0-1-2/standard-example.cpp | 43 - .../src/rules/M0-1-3/standard-example.cpp | 17 - .../src/rules/M0-1-4/standard-example.cpp | 7 - .../src/rules/M0-1-8/standard-example.cpp | 5 - .../src/rules/M0-1-9/standard-example.cpp | 9 - .../src/rules/M0-2-1/standard-example.cpp | 18 - .../src/rules/M0-3-2/standard-example.cpp | 19 - .../src/rules/M10-1-1/standard-example.cpp | 2 - .../src/rules/M10-1-2/standard-example.cpp | 5 - .../src/rules/M10-1-3/standard-example.cpp | 6 - .../src/rules/M10-2-1/standard-example.cpp | 23 - .../src/rules/M10-3-3/standard-example.cpp | 13 - .../src/rules/M11-0-1/standard-example.cpp | 9 - .../src/rules/M12-1-1/standard-example.cpp | 21 - .../src/rules/M14-5-3/standard-example.cpp | 26 - .../src/rules/M14-6-1/standard-example.cpp | 29 - .../src/rules/M15-0-3/standard-example.cpp | 32 - .../src/rules/M15-1-1/standard-example.cpp | 21 - .../src/rules/M15-1-2/standard-example.cpp | 23 - .../src/rules/M15-1-3/standard-example.cpp | 31 - .../src/rules/M15-3-1/standard-example.cpp | 28 - .../src/rules/M15-3-3/standard-example.cpp | 20 - .../src/rules/M15-3-4/standard-example.cpp | 12 - .../src/rules/M15-3-6/standard-example.cpp | 26 - .../src/rules/M15-3-7/standard-example.cpp | 22 - .../src/rules/M16-0-1/standard-example.cpp | 3 - .../src/rules/M16-0-2/standard-example.cpp | 8 - .../src/rules/M16-0-5/standard-example1.cpp | 11 - .../src/rules/M16-0-5/standard-example2.cpp | 1 - .../src/rules/M16-0-5/standard-example3.cpp | 1 - .../src/rules/M16-0-6/standard-example1.cpp | 1 - .../src/rules/M16-0-6/standard-example2.cpp | 1 - .../src/rules/M16-0-6/standard-example3.cpp | 1 - .../src/rules/M16-0-6/standard-example4.cpp | 1 - .../src/rules/M16-0-6/standard-example5.cpp | 1 - .../src/rules/M16-0-7/standard-example.cpp | 1 - .../src/rules/M16-1-1/standard-example1.cpp | 1 - .../src/rules/M16-1-1/standard-example2.cpp | 2 - .../src/rules/M16-2-3/standard-example.cpp | 6 - .../src/rules/M16-3-1/standard-example1.cpp | 3 - .../src/rules/M16-3-1/standard-example2.cpp | 1 - .../src/rules/M16-3-2/standard-example.cpp | 2 - .../src/rules/M17-0-2/standard-example.cpp | 1 - .../src/rules/M17-0-3/standard-example.cpp | 4 - .../src/rules/M17-0-5/standard-example.cpp | 17 - .../src/rules/M18-0-3/standard-example.cpp | 5 - .../src/rules/M18-0-4/standard-example.cpp | 5 - .../src/rules/M18-0-5/standard-example.cpp | 6 - .../src/rules/M18-2-1/standard-example.cpp | 9 - .../src/rules/M18-7-1/standard-example.cpp | 6 - .../src/rules/M19-3-1/standard-example.cpp | 11 - .../src/rules/M2-10-1/standard-example.cpp | 18 - .../src/rules/M2-13-2/standard-example1.cpp | 4 - .../src/rules/M2-13-2/standard-example2.cpp | 3 - .../src/rules/M2-13-3/standard-example.cpp | 12 - .../src/rules/M2-13-4/standard-example.cpp | 12 - .../src/rules/M2-7-1/standard-example.cpp | 3 - .../src/rules/M27-0-1/standard-example.cpp | 6 - .../src/rules/M3-1-2/standard-example.cpp | 9 - ...tionsOfAnObjectShallHaveCompatibleTypes.ql | 4 +- .../src/rules/M3-2-1/standard-example.cpp | 13 - .../src/rules/M3-2-2/standard-example.cpp | 19 - .../src/rules/M3-2-3/standard-example.cpp | 9 - .../src/rules/M3-2-4/standard-example.cpp | 4 - .../src/rules/M3-3-2/standard-example.cpp | 4 - .../src/rules/M3-4-1/standard-example.cpp | 8 - .../src/rules/M3-9-1/standard-example.cpp | 11 - .../src/rules/M3-9-3/standard-example.cpp | 7 - .../src/rules/M4-10-1/standard-example.cpp | 8 - .../src/rules/M4-10-2/standard-example.cpp | 8 - .../src/rules/M4-5-1/standard-example.cpp | 14 - .../src/rules/M4-5-3/standard-example.cpp | 17 - .../src/rules/M5-0-11/standard-example.cpp | 4 - .../src/rules/M5-0-12/standard-example.cpp | 5 - .../src/rules/M5-0-14/standard-example.cpp | 3 - .../src/rules/M5-0-15/standard-example.cpp | 34 - .../src/rules/M5-0-16/standard-example.cpp | 12 - .../src/rules/M5-0-17/standard-example.cpp | 10 - .../src/rules/M5-0-18/standard-example.cpp | 11 - .../src/rules/M5-0-20/standard-example.cpp | 3 - .../src/rules/M5-0-21/standard-example.cpp | 4 - .../src/rules/M5-0-3/standard-example.cpp | 8 - .../src/rules/M5-0-4/standard-example.cpp | 7 - .../src/rules/M5-0-5/standard-example.cpp | 7 - .../src/rules/M5-0-6/standard-example.cpp | 6 - .../src/rules/M5-0-7/standard-example.cpp | 14 - .../src/rules/M5-0-7/standard-example2.cpp | 14 - .../src/rules/M5-0-8/standard-example.cpp | 6 - .../src/rules/M5-0-9/standard-example.cpp | 6 - .../src/rules/M5-14-1/standard-example.cpp | 4 - .../src/rules/M5-17-1/standard-example.cpp | 16 - .../src/rules/M5-18-1/standard-example.cpp | 1 - .../src/rules/M5-19-1/standard-example.cpp | 20 - .../src/rules/M5-2-11/standard-example.cpp | 17 - .../src/rules/M5-2-12/standard-example.cpp | 11 - .../src/rules/M5-2-2/standard-example.cpp | 11 - .../src/rules/M5-2-3/standard-example.cpp | 38 - .../src/rules/M5-2-6/standard-example.cpp | 4 - .../src/rules/M5-2-8/standard-example.cpp | 8 - .../src/rules/M5-2-9/standard-example.cpp | 7 - .../src/rules/M5-3-1/standard-example.cpp | 9 - .../src/rules/M5-3-2/standard-example.cpp | 4 - .../src/rules/M5-3-3/standard-example.cpp | 18 - .../src/rules/M5-3-4/standard-example.cpp | 7 - .../src/rules/M5-8-1/standard-example.cpp | 3 - .../src/rules/M6-2-1/standard-example.cpp | 20 - .../src/rules/M6-2-2/standard-example1.cpp | 3 - .../src/rules/M6-2-2/standard-example2.cpp | 2 - .../src/rules/M6-2-2/standard-example3.cpp | 2 - .../src/rules/M6-2-3/standard-example.cpp | 6 - .../src/rules/M6-3-1/standard-example.cpp | 17 - .../src/rules/M6-4-1/standard-example.cpp | 17 - .../src/rules/M6-4-2/standard-example1.cpp | 6 - .../src/rules/M6-4-2/standard-example2.cpp | 13 - .../src/rules/M6-4-3/standard-example.cpp | 12 - .../src/rules/M6-4-4/standard-example.cpp | 12 - .../src/rules/M6-4-5/standard-example.cpp | 16 - .../src/rules/M6-4-6/standard-example.cpp | 28 - .../src/rules/M6-4-7/standard-example.cpp | 4 - .../src/rules/M6-5-2/standard-example.cpp | 3 - .../src/rules/M6-5-3/standard-example.cpp | 14 - .../src/rules/M6-5-4/standard-example.cpp | 8 - .../src/rules/M6-5-5/standard-example.cpp | 18 - .../src/rules/M6-5-6/standard-example.cpp | 9 - .../src/rules/M6-6-1/standard-example.cpp | 22 - .../src/rules/M6-6-2/standard-example.cpp | 13 - .../src/rules/M6-6-3/standard-example.cpp | 21 - .../src/rules/M7-1-2/standard-example.cpp | 12 - .../src/rules/M7-3-1/standard-example.cpp | 15 - .../src/rules/M7-3-2/standard-example.cpp | 15 - .../src/rules/M7-3-3/standard-example.cpp | 28 - .../src/rules/M7-3-4/UsingDirectivesUsed.ql | 5 +- .../src/rules/M7-3-4/standard-example.cpp | 26 - .../src/rules/M7-3-6/standard-example.cpp | 29 - .../src/rules/M7-4-1/standard-example.cpp | 0 .../src/rules/M7-4-2/standard-example.cpp | 8 - .../src/rules/M7-4-3/standard-example.cpp | 10 - .../src/rules/M7-5-1/standard-example.cpp | 18 - .../src/rules/M7-5-2/standard-example.cpp | 8 - .../src/rules/M8-0-1/standard-example.cpp | 4 - .../src/rules/M8-3-1/standard-example.cpp | 25 - .../src/rules/M8-4-2/standard-example.cpp | 13 - .../src/rules/M8-4-4/standard-example.cpp | 11 - .../src/rules/M8-5-2/standard-example1.cpp | 2 - .../src/rules/M8-5-2/standard-example2.cpp | 8 - .../src/rules/M9-3-1/standard-example.cpp | 33 - .../src/rules/M9-3-3/standard-example.cpp | 21 - .../src/rules/M9-6-4/standard-example.cpp | 8 - cpp/autosar/test/qlpack.yml | 2 +- ...alFunctionsIntroducedInFinalClass.expected | 2 +- ...ExternalOrInternalLinkageIsReused.expected | 4 +- ...fierNameOfAStaticFunctionIsReused.expected | 4 +- cpp/autosar/test/rules/A2-10-5/test1a.cpp | 6 +- cpp/autosar/test/rules/A2-10-5/test1b.cpp | 7 +- cpp/autosar/test/rules/A3-3-1/test.cpp | 8 +- cpp/autosar/test/rules/A3-3-1/test.hpp | 4 +- cpp/autosar/test/rules/M7-3-4/test.cpp | 4 + cpp/cert/src/qlpack.yml | 2 +- ...exToGoOutOfScopeWhileLocked-standard.qhelp | 282 ------ ...NotAllowAMutexToGoOutOfScopeWhileLocked.md | 137 +++ ...AllowAMutexToGoOutOfScopeWhileLocked.qhelp | 18 - ...estroyAMutexWhileItIsLocked-standard.qhelp | 282 ------ .../DoNotDestroyAMutexWhileItIsLocked.md | 137 +++ .../DoNotDestroyAMutexWhileItIsLocked.qhelp | 18 - ...asedOnExceptionalConditions-standard.qhelp | 212 ----- ...LocksAreReleasedOnExceptionalConditions.md | 101 +++ ...ksAreReleasedOnExceptionalConditions.qhelp | 18 - ...ldAccessFromMultipleThreads-standard.qhelp | 33 - ...entBitFieldAccessFromMultipleThreads.qhelp | 18 - ...enAccessingBitFieldsFromMultipleThreads.md | 140 +++ .../src/rules/CON52-CPP/standard-example.cpp | 0 ...kByLockingInPredefinedOrder-standard.qhelp | 376 -------- .../DeadlockByLockingInPredefinedOrder.md | 196 ++++ .../DeadlockByLockingInPredefinedOrder.qhelp | 18 - ...atCanSpuriouslyWakeUpInLoop-standard.qhelp | 320 ------- ...pFunctionsThatCanSpuriouslyWakeUpInLoop.md | 153 ++++ ...nctionsThatCanSpuriouslyWakeUpInLoop.qhelp | 18 - ...WhenUsingConditionVariables-standard.qhelp | 472 ---------- ...yAndLivenessWhenUsingConditionVariables.md | 201 +++++ ...dLivenessWhenUsingConditionVariables.qhelp | 18 - ...ockALockedNonRecursiveMutex-standard.qhelp | 236 ----- ...eculativelyLockALockedNonRecursiveMutex.md | 148 +++ ...lativelyLockALockedNonRecursiveMutex.qhelp | 18 - ...ockedNonRecursiveMutexAudit-standard.qhelp | 236 ----- .../LockedALockedNonRecursiveMutexAudit.md | 148 +++ .../LockedALockedNonRecursiveMutexAudit.qhelp | 18 - ...AccessWithoutRangeCheckCert-standard.qhelp | 435 --------- .../ContainerAccessWithoutRangeCheckCert.md | 197 ++++ ...ContainerAccessWithoutRangeCheckCert.qhelp | 18 - ...ValidContainerElementAccess-standard.qhelp | 783 ---------------- .../UsesValidContainerElementAccess.md | 107 +++ .../UsesValidContainerElementAccess.qhelp | 18 - ...braryFunctionsDoNotOverflow-standard.qhelp | 309 ------- ...GenericCppLibraryFunctionsDoNotOverflow.md | 152 ++++ ...ericCppLibraryFunctionsDoNotOverflow.qhelp | 18 - .../UseValidIteratorRanges-standard.qhelp | 280 ------ .../rules/CTR53-CPP/UseValidIteratorRanges.md | 114 +++ .../CTR53-CPP/UseValidIteratorRanges.qhelp | 18 - ...atorsForDifferentContainers-standard.qhelp | 347 ------- ...SubtractIteratorsForDifferentContainers.md | 174 ++++ ...tractIteratorsForDifferentContainers.qhelp | 18 - ...dditiveOperatorOnAnIterator-standard.qhelp | 227 ----- .../DoNotUseAnAdditiveOperatorOnAnIterator.md | 85 ++ ...NotUseAnAdditiveOperatorOnAnIterator.qhelp | 18 - ...thmeticOnPolymorphicObjects-standard.qhelp | 359 -------- ...sePointerArithmeticOnPolymorphicObjects.md | 170 ++++ ...ointerArithmeticOnPolymorphicObjects.qhelp | 18 - .../src/rules/CTR56-CPP/standard-example.cpp | 0 ...videAValidOrderingPredicate-standard.qhelp | 257 ------ .../ProvideAValidOrderingPredicate.md | 149 +++ .../ProvideAValidOrderingPredicate.qhelp | 18 - ...onObjectsShouldNotBeMutable-standard.qhelp | 283 ------ ...dicateFunctionObjectsShouldNotBeMutable.md | 193 ++++ ...ateFunctionObjectsShouldNotBeMutable.qhelp | 18 - ...fineACStyleVariadicFunction-standard.qhelp | 351 -------- .../DoNotDefineACStyleVariadicFunction.md | 125 +++ .../DoNotDefineACStyleVariadicFunction.qhelp | 18 - ...numeratorReusesReservedName-standard.qhelp | 488 ---------- .../DCL51-CPP/EnumeratorReusesReservedName.md | 193 ++++ .../EnumeratorReusesReservedName.qhelp | 18 - .../FunctionReusesReservedName-standard.qhelp | 488 ---------- .../DCL51-CPP/FunctionReusesReservedName.md | 193 ++++ .../FunctionReusesReservedName.qhelp | 18 - .../ObjectReusesReservedName-standard.qhelp | 488 ---------- .../DCL51-CPP/ObjectReusesReservedName.md | 193 ++++ .../DCL51-CPP/ObjectReusesReservedName.qhelp | 18 - ...finingOfStandardLibraryName-standard.qhelp | 488 ---------- .../RedefiningOfStandardLibraryName.md | 193 ++++ .../RedefiningOfStandardLibraryName.qhelp | 18 - .../ReuseOfReservedIdentifier-standard.qhelp | 488 ---------- .../DCL51-CPP/ReuseOfReservedIdentifier.md | 193 ++++ .../DCL51-CPP/ReuseOfReservedIdentifier.qhelp | 18 - ...bleUnderscoreReservedPrefix-standard.qhelp | 488 ---------- .../UseOfDoubleUnderscoreReservedPrefix.md | 193 ++++ .../UseOfDoubleUnderscoreReservedPrefix.qhelp | 18 - ...rvedLiteralSuffixIdentifier-standard.qhelp | 488 ---------- .../UseOfReservedLiteralSuffixIdentifier.md | 193 ++++ ...UseOfReservedLiteralSuffixIdentifier.qhelp | 18 - .../UseOfReservedNamePrefix-standard.qhelp | 488 ---------- ...gleUnderscoreReservedPrefix-standard.qhelp | 488 ---------- .../UseOfSingleUnderscoreReservedPrefix.md | 193 ++++ .../UseOfSingleUnderscoreReservedPrefix.qhelp | 18 - ...alizedObjectHidesIdentifier-standard.qhelp | 347 ------- ...tructorInitializedObjectHidesIdentifier.md | 181 ++++ ...ctorInitializedObjectHidesIdentifier.qhelp | 18 - .../LocalFunctionDeclaration-standard.qhelp | 347 ------- .../DCL53-CPP/LocalFunctionDeclaration.md | 181 ++++ .../DCL53-CPP/LocalFunctionDeclaration.qhelp | 18 - ...larOverloadOfMemoryFunction-standard.qhelp | 367 -------- .../SingularOverloadOfMemoryFunction.md | 158 ++++ .../SingularOverloadOfMemoryFunction.qhelp | 18 - ...eakageAcrossTrustBoundaries-standard.qhelp | 603 ------------- ...InformationLeakageAcrossTrustBoundaries.md | 317 +++++++ ...ormationLeakageAcrossTrustBoundaries.qhelp | 18 - ...yclesDuringStaticObjectInit-standard.qhelp | 308 ------- .../DCL56-CPP/CyclesDuringStaticObjectInit.md | 196 ++++ .../CyclesDuringStaticObjectInit.qhelp | 18 - ...torsOrDeallocationFunctions-standard.qhelp | 431 --------- ...eFromDestructorsOrDeallocationFunctions.md | 200 +++++ ...omDestructorsOrDeallocationFunctions.qhelp | 18 - ...tionOfTheStandardNamespaces-standard.qhelp | 388 -------- .../ModificationOfTheStandardNamespaces.md | 203 +++++ .../ModificationOfTheStandardNamespaces.qhelp | 18 - ...nnamedNamespaceInHeaderFile-standard.qhelp | 534 ----------- .../DCL59-CPP/UnnamedNamespaceInHeaderFile.md | 296 ++++++ .../UnnamedNamespaceInHeaderFile.qhelp | 18 - .../OneDefinitionRuleNotObeyed-standard.qhelp | 381 -------- .../DCL60-CPP/OneDefinitionRuleNotObeyed.md | 223 +++++ .../OneDefinitionRuleNotObeyed.qhelp | 18 - ...ablePostConditionFailedCert-standard.qhelp | 454 ---------- ...onditionVariablePostConditionFailedCert.md | 152 ++++ ...itionVariablePostConditionFailedCert.qhelp | 18 - ...tHandlerThrowsExceptionCert-standard.qhelp | 454 ---------- .../ExitHandlerThrowsExceptionCert.md | 152 ++++ .../ExitHandlerThrowsExceptionCert.qhelp | 18 - ...plicitAbruptTerminationCert-standard.qhelp | 454 ---------- .../ExplicitAbruptTerminationCert.md | 152 ++++ .../ExplicitAbruptTerminationCert.qhelp | 18 - ...ThreadCopiedOrDestroyedCert-standard.qhelp | 454 ---------- .../JoinableThreadCopiedOrDestroyedCert.md | 152 ++++ .../JoinableThreadCopiedOrDestroyedCert.qhelp | 18 - ...rowNestedWithoutCaptureCert-standard.qhelp | 454 ---------- .../RethrowNestedWithoutCaptureCert.md | 152 ++++ .../RethrowNestedWithoutCaptureCert.qhelp | 18 - .../HandleAllExceptions-standard.qhelp | 342 ------- .../rules/ERR51-CPP/HandleAllExceptions.md | 133 +++ .../rules/ERR51-CPP/HandleAllExceptions.qhelp | 18 - .../DoNotUseSetjmpOrLongjmp-standard.qhelp | 380 -------- .../ERR52-CPP/DoNotUseSetjmpOrLongjmp.md | 134 +++ .../ERR52-CPP/DoNotUseSetjmpOrLongjmp.qhelp | 18 - ...tructorDestructorCatchBlock-standard.qhelp | 308 ------- ...rencedInConstructorDestructorCatchBlock.md | 92 ++ ...cedInConstructorDestructorCatchBlock.qhelp | 18 - .../CatchBlockShadowingCert-standard.qhelp | 371 -------- .../ERR54-CPP/CatchBlockShadowingCert.md | 89 ++ .../ERR54-CPP/CatchBlockShadowingCert.qhelp | 18 - ...onorExceptionSpecifications-standard.qhelp | 344 ------- .../ERR55-CPP/HonorExceptionSpecifications.md | 149 +++ .../HonorExceptionSpecifications.qhelp | 18 - .../GuaranteeExceptionSafety-standard.qhelp | 393 -------- .../ERR56-CPP/GuaranteeExceptionSafety.md | 127 +++ .../ERR56-CPP/GuaranteeExceptionSafety.qhelp | 18 - ...urcesWhenHandlingExceptions-standard.qhelp | 404 --------- ...oNotLeakResourcesWhenHandlingExceptions.md | 217 +++++ ...tLeakResourcesWhenHandlingExceptions.qhelp | 18 - ...wnBeforeMainBeginsExecuting-standard.qhelp | 363 -------- ...ceptionsThrownBeforeMainBeginsExecuting.md | 184 ++++ ...tionsThrownBeforeMainBeginsExecuting.qhelp | 18 - ...onAcrossExecutionBoundaries-standard.qhelp | 195 ---- ...rowAnExceptionAcrossExecutionBoundaries.md | 107 +++ ...AnExceptionAcrossExecutionBoundaries.qhelp | 18 - ...tBeNothrowCopyConstructible-standard.qhelp | 285 ------ ...onObjectsMustBeNothrowCopyConstructible.md | 149 +++ ...bjectsMustBeNothrowCopyConstructible.qhelp | 18 - ...ExceptionsByLvalueReference-standard.qhelp | 375 -------- .../CatchExceptionsByLvalueReference.md | 107 +++ .../CatchExceptionsByLvalueReference.qhelp | 18 - ...nConvertingAStringToANumber-standard.qhelp | 298 ------ ...ectErrorsWhenConvertingAStringToANumber.md | 116 +++ ...ErrorsWhenConvertingAStringToANumber.qhelp | 18 - ...ionCallsAsFunctionArguments-standard.qhelp | 523 ----------- ...fectsInFunctionCallsAsFunctionArguments.md | 237 +++++ ...tsInFunctionCallsAsFunctionArguments.qhelp | 18 - ...ectEvaluationForSideEffects-standard.qhelp | 523 ----------- ...rOfScalarObjectEvaluationForSideEffects.md | 237 +++++ ...ScalarObjectEvaluationForSideEffects.qhelp | 18 - ...hAPointerOfTheIncorrectType-standard.qhelp | 226 ----- ...nArrayThroughAPointerOfTheIncorrectType.md | 85 ++ ...rayThroughAPointerOfTheIncorrectType.qhelp | 18 - .../src/rules/EXP51-CPP/standard-example.cpp | 0 ...ideEffectsInDeclTypeOperand-standard.qhelp | 370 -------- ...DoNotRelyOnSideEffectsInDeclTypeOperand.md | 168 ++++ ...otRelyOnSideEffectsInDeclTypeOperand.qhelp | 18 - ...eEffectsInDeclValExpression-standard.qhelp | 370 -------- ...NotRelyOnSideEffectsInDeclValExpression.md | 168 ++++ ...RelyOnSideEffectsInDeclValExpression.qhelp | 18 - ...ideEffectsInNoExceptOperand-standard.qhelp | 370 -------- ...DoNotRelyOnSideEffectsInNoExceptOperand.md | 168 ++++ ...otRelyOnSideEffectsInNoExceptOperand.qhelp | 18 - ...nSideEffectsInSizeOfOperand-standard.qhelp | 370 -------- .../DoNotRelyOnSideEffectsInSizeOfOperand.md | 168 ++++ ...oNotRelyOnSideEffectsInSizeOfOperand.qhelp | 18 - ...nSideEffectsInTypeIdOperand-standard.qhelp | 370 -------- .../DoNotRelyOnSideEffectsInTypeIdOperand.md | 168 ++++ ...oNotRelyOnSideEffectsInTypeIdOperand.qhelp | 18 - ...oNotReadUninitializedMemory-standard.qhelp | 424 --------- .../EXP53-CPP/DoNotReadUninitializedMemory.md | 159 ++++ .../DoNotReadUninitializedMemory.qhelp | 18 - ...ctAccessedAfterLifetimeCert-standard.qhelp | 620 ------------- .../ObjectAccessedAfterLifetimeCert.md | 393 ++++++++ .../ObjectAccessedAfterLifetimeCert.qhelp | 18 - .../ObjectAccessedAfterLifetimeCert.ql | 1 - ...tAccessedBeforeLifetimeCert-standard.qhelp | 620 ------------- .../ObjectAccessedBeforeLifetimeCert.md | 393 ++++++++ .../ObjectAccessedBeforeLifetimeCert.qhelp | 18 - .../ObjectAccessedBeforeLifetimeCert.ql | 1 - .../src/rules/EXP54-CPP/standard-example.cpp | 0 ...OrVolatileQualificationCert-standard.qhelp | 420 --------- .../RemoveConstOrVolatileQualificationCert.md | 205 +++++ ...moveConstOrVolatileQualificationCert.qhelp | 18 - ...thMismatchedLanguageLinkage-standard.qhelp | 207 ----- .../FunctionWithMismatchedLanguageLinkage.md | 104 +++ ...unctionWithMismatchedLanguageLinkage.qhelp | 18 - ...tOfPointerToIncompleteClass-standard.qhelp | 426 --------- .../CastOfPointerToIncompleteClass.md | 198 ++++ .../CastOfPointerToIncompleteClass.qhelp | 18 - ...ingPointerToIncompleteClass-standard.qhelp | 426 --------- .../DeletingPointerToIncompleteClass.md | 198 ++++ .../DeletingPointerToIncompleteClass.qhelp | 18 - .../src/rules/EXP57-CPP/standard-example.cpp | 0 ...ssNonTrivialObjectToVaStart-standard.qhelp | 287 ------ .../PassNonTrivialObjectToVaStart.md | 162 ++++ .../PassNonTrivialObjectToVaStart.qhelp | 18 - ...tablePrimitiveTypeToVaStart-standard.qhelp | 287 ------ .../PassPromotablePrimitiveTypeToVaStart.md | 162 ++++ ...PassPromotablePrimitiveTypeToVaStart.qhelp | 18 - .../PassReferenceTypeToVaStart-standard.qhelp | 287 ------ .../EXP58-CPP/PassReferenceTypeToVaStart.md | 162 ++++ .../PassReferenceTypeToVaStart.qhelp | 18 - ...etUsedOnInvalidTypeOrMember-standard.qhelp | 279 ------ .../OffsetUsedOnInvalidTypeOrMember.md | 134 +++ .../OffsetUsedOnInvalidTypeOrMember.qhelp | 18 - ...ndardObjectAcrossBoundaries-standard.qhelp | 250 ------ ...tPassANonstandardObjectAcrossBoundaries.md | 152 ++++ ...ssANonstandardObjectAcrossBoundaries.qhelp | 18 - ...bjectWithCaptureByReference-standard.qhelp | 262 ------ ...apingLambdaObjectWithCaptureByReference.md | 129 +++ ...ngLambdaObjectWithCaptureByReference.qhelp | 18 - ...bjectWithCaptureByReference-standard.qhelp | 262 ------ ...rningLambdaObjectWithCaptureByReference.md | 129 +++ ...ngLambdaObjectWithCaptureByReference.qhelp | 18 - ...oAccessObjectRepresentation-standard.qhelp | 304 ------- .../MemcmpUsedToAccessObjectRepresentation.md | 162 ++++ ...mcmpUsedToAccessObjectRepresentation.qhelp | 18 - ...oAccessObjectRepresentation-standard.qhelp | 304 ------- .../MemcpyUsedToAccessObjectRepresentation.md | 162 ++++ ...mcpyUsedToAccessObjectRepresentation.qhelp | 18 - ...oAccessObjectRepresentation-standard.qhelp | 304 ------- .../MemsetUsedToAccessObjectRepresentation.md | 162 ++++ ...msetUsedToAccessObjectRepresentation.qhelp | 18 - ...nTheValueOfAMovedFromObject-standard.qhelp | 475 ---------- .../DoNotRelyOnTheValueOfAMovedFromObject.md | 164 ++++ ...oNotRelyOnTheValueOfAMovedFromObject.qhelp | 18 - ...dInputOutputWithoutPosition-standard.qhelp | 255 ------ .../InterleavedInputOutputWithoutPosition.md | 108 +++ ...nterleavedInputOutputWithoutPosition.qhelp | 18 - ...esWhenTheyAreNoLongerNeeded-standard.qhelp | 263 ------ .../CloseFilesWhenTheyAreNoLongerNeeded.md | 115 +++ .../CloseFilesWhenTheyAreNoLongerNeeded.qhelp | 18 - ...nOutOfRangeEnumerationValue-standard.qhelp | 266 ------ ...DoNotCastToAnOutOfRangeEnumerationValue.md | 122 +++ ...otCastToAnOutOfRangeEnumerationValue.qhelp | 18 - .../MEM50-CPP/UseAfterFree-standard.qhelp | 566 ------------ cpp/cert/src/rules/MEM50-CPP/UseAfterFree.md | 258 ++++++ .../src/rules/MEM50-CPP/UseAfterFree.qhelp | 18 - .../src/rules/MEM50-CPP/standard-example.cpp | 0 ...namicallyAllocatedResources-standard.qhelp | 845 ------------------ ...DeallocateDynamicallyAllocatedResources.md | 409 +++++++++ ...llocateDynamicallyAllocatedResources.qhelp | 18 - ...andleMemoryAllocationErrors-standard.qhelp | 453 ---------- .../DetectAndHandleMemoryAllocationErrors.md | 184 ++++ ...etectAndHandleMemoryAllocationErrors.qhelp | 18 - ...allForManuallyManagedObject-standard.qhelp | 276 ------ ...ConstructorCallForManuallyManagedObject.md | 185 ++++ ...structorCallForManuallyManagedObject.qhelp | 18 - ...allForManuallyManagedObject-standard.qhelp | 276 ------ ...gDestructorCallForManuallyManagedObject.md | 185 ++++ ...structorCallForManuallyManagedObject.qhelp | 18 - ...tNewInsufficientStorageCert-standard.qhelp | 323 ------- .../PlacementNewInsufficientStorageCert.md | 187 ++++ .../PlacementNewInsufficientStorageCert.qhelp | 18 - ...ntNewNotProperlyAlignedCert-standard.qhelp | 323 ------- .../PlacementNewNotProperlyAlignedCert.md | 187 ++++ .../PlacementNewNotProperlyAlignedCert.qhelp | 18 - ...torDeleteMissingPartnerCert-standard.qhelp | 255 ------ .../OperatorDeleteMissingPartnerCert.md | 90 ++ .../OperatorDeleteMissingPartnerCert.qhelp | 18 - ...oThrowOperatorNewDeleteCert-standard.qhelp | 255 ------ .../ThrowingNoThrowOperatorNewDeleteCert.md | 90 ++ ...ThrowingNoThrowOperatorNewDeleteCert.qhelp | 18 - ...gOperatorNewReturnsNullCert-standard.qhelp | 255 ------ .../ThrowingOperatorNewReturnsNullCert.md | 90 ++ .../ThrowingOperatorNewReturnsNullCert.qhelp | 18 - ...wThrowsInvalidExceptionCert-standard.qhelp | 255 ------ ...ngOperatorNewThrowsInvalidExceptionCert.md | 90 ++ ...peratorNewThrowsInvalidExceptionCert.qhelp | 18 - ...InUnrelatedSmartPointerCert-standard.qhelp | 317 ------- ...rValueStoredInUnrelatedSmartPointerCert.md | 158 ++++ ...lueStoredInUnrelatedSmartPointerCert.qhelp | 18 - ...ratorNewForOverAlignedTypes-standard.qhelp | 223 ----- ...ngDefaultOperatorNewForOverAlignedTypes.md | 90 ++ ...efaultOperatorNewForOverAlignedTypes.qhelp | 18 - ...neratingPseudorandomNumbers-standard.qhelp | 400 --------- ...UseRandForGeneratingPseudorandomNumbers.md | 83 ++ ...RandForGeneratingPseudorandomNumbers.qhelp | 18 - ...SeededRandomNumberGenerator-standard.qhelp | 314 ------- .../BadlySeededRandomNumberGenerator.md | 122 +++ .../BadlySeededRandomNumberGenerator.qhelp | 18 - ...idFunctionDoesNotReturnCert-standard.qhelp | 376 -------- .../NonVoidFunctionDoesNotReturnCert.md | 132 +++ .../NonVoidFunctionDoesNotReturnCert.qhelp | 18 - ...eturnAttributeConditionCert-standard.qhelp | 280 ------ .../FunctionNoReturnAttributeConditionCert.md | 73 ++ ...nctionNoReturnAttributeConditionCert.qhelp | 18 - ...dlerMustBeAPlainOldFunction-standard.qhelp | 268 ------ .../SignalHandlerMustBeAPlainOldFunction.md | 158 ++++ ...SignalHandlerMustBeAPlainOldFunction.qhelp | 18 - ...omConstructorsOrDestructors-standard.qhelp | 430 --------- ...lFunctionsFromConstructorsOrDestructors.md | 161 ++++ ...nctionsFromConstructorsOrDestructors.qhelp | 18 - .../DoNotSliceDerivedObjects-standard.qhelp | 448 ---------- .../OOP51-CPP/DoNotSliceDerivedObjects.md | 277 ++++++ .../OOP51-CPP/DoNotSliceDerivedObjects.qhelp | 18 - ...ctWithoutAVirtualDestructor-standard.qhelp | 442 --------- ...ymorphicObjectWithoutAVirtualDestructor.md | 178 ++++ ...rphicObjectWithoutAVirtualDestructor.qhelp | 18 - .../src/rules/OOP52-CPP/standard-example.cpp | 0 ...CanonicalOrderForMemberInit-standard.qhelp | 365 -------- .../UseCanonicalOrderForMemberInit.md | 129 +++ .../UseCanonicalOrderForMemberInit.qhelp | 18 - ...llyHandleSelfCopyAssignment-standard.qhelp | 361 -------- .../GracefullyHandleSelfCopyAssignment.md | 181 ++++ .../GracefullyHandleSelfCopyAssignment.qhelp | 18 - ...alizedStaticPointerToMember-standard.qhelp | 310 ------- ...sWithUninitializedStaticPointerToMember.md | 173 ++++ ...thUninitializedStaticPointerToMember.qhelp | 18 - ...erToAccessNonexistentMember-standard.qhelp | 310 ------- ...ointerToMemberToAccessNonexistentMember.md | 173 ++++ ...terToMemberToAccessNonexistentMember.qhelp | 18 - ...mberToAccessUndefinedMember-standard.qhelp | 310 ------- ...fPointerToMemberToAccessUndefinedMember.md | 173 ++++ ...interToMemberToAccessUndefinedMember.qhelp | 18 - .../src/rules/OOP55-CPP/standard-example.cpp | 0 ...lacementHandlerRequirements-standard.qhelp | 214 ----- .../HonorNewReplacementHandlerRequirements.md | 119 +++ ...norNewReplacementHandlerRequirements.qhelp | 18 - ...lacementHandlerRequirements-standard.qhelp | 214 ----- ...rminationReplacementHandlerRequirements.md | 119 +++ ...nationReplacementHandlerRequirements.qhelp | 18 - ...ToCStandardLibraryFunctions-standard.qhelp | 501 ----------- ...dedOperatorsToCStandardLibraryFunctions.md | 252 ++++++ ...OperatorsToCStandardLibraryFunctions.qhelp | 18 - ...ustNotMutateTheSourceObject-standard.qhelp | 319 ------- ...yOperationsMustNotMutateTheSourceObject.md | 149 +++ ...erationsMustNotMutateTheSourceObject.qhelp | 18 - ...gMayNotBeNullTerminatedCert-standard.qhelp | 323 ------- .../BasicStringMayNotBeNullTerminatedCert.md | 135 +++ ...asicStringMayNotBeNullTerminatedCert.qhelp | 18 - ...llTerminateCStyleStringCert-standard.qhelp | 323 ------- ...tionMayNotNullTerminateCStyleStringCert.md | 135 +++ ...nMayNotNullTerminateCStyleStringCert.qhelp | 18 - ...eateAStringFromANullPointer-standard.qhelp | 285 ------ ...tAttemptToCreateAStringFromANullPointer.md | 120 +++ ...temptToCreateAStringFromANullPointer.qhelp | 18 - ...tAttemptToCreateAStringFromANullPointer.ql | 1 - ...ferencesForElementsOfString-standard.qhelp | 249 ------ .../UseValidReferencesForElementsOfString.md | 141 +++ ...seValidReferencesForElementsOfString.qhelp | 18 - ...ngeCheckStringElementAccess-standard.qhelp | 284 ------ .../RangeCheckStringElementAccess.md | 134 +++ .../RangeCheckStringElementAccess.qhelp | 18 - cpp/cert/test/qlpack.yml | 2 +- cpp/common/src/qlpack.yml | 2 +- cpp/common/test/qlpack.yml | 2 +- cpp/misra/src/qlpack.yml | 2 +- cpp/misra/test/qlpack.yml | 2 +- cpp/report/src/qlpack.yml | 2 +- .../development_handbook.md | 248 +++-- docs/iso_26262_tool_qualification.md | 28 +- docs/user_manual.md | 126 ++- rule_packages/cpp/DeadCode.json | 5 +- rule_packages/cpp/Exceptions1.json | 5 +- rule_packages/cpp/Exceptions2.json | 5 +- rule_packages/cpp/Freed.json | 12 +- rule_packages/cpp/Literals.json | 5 +- rule_packages/cpp/Null.json | 6 +- schemas/rule-package.schema.json | 17 + scripts/create_language_matrix.py | 2 - .../process_coding_standards_config.py | 2 +- .../documentation/generate_iso26262_docs.py | 81 +- .../generate_rules/coding_standards_utils.py | 76 +- .../generate_rules/generate_package_files.py | 79 +- .../templates/autosar-help.md.template | 49 + .../templates/cert-c++-help.md.template | 28 + .../templates/cert-c-help.md.template | 28 + .../templates/misra-c-2012-help.md.template | 49 + scripts/help/cert-help-extraction.py | 135 +-- .../matrix_testing/CreateMatrixTestReport.ps1 | 47 +- .../ExecuteQueryAndDecodeAsJson.ps1 | 27 + scripts/release/create_draft_release.sh | 22 +- scripts/reports/codeql.py | 138 +-- scripts/requirements.txt | 3 +- scripts/shared/codeql.py | 133 +++ scripts/shared/markdown_helpers.py | 108 +++ scripts/verify_rule_package_consistency.py | 2 +- 951 files changed, 25950 insertions(+), 66296 deletions(-) create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.md create mode 100644 LICENSE.md create mode 100644 SECURITY.md delete mode 100644 c/cert/src/rules/CON32-C/PreventDataRacesWithMultipleThreads-standard.qhelp create mode 100644 c/cert/src/rules/CON32-C/PreventDataRacesWithMultipleThreads.md delete mode 100644 c/cert/src/rules/CON32-C/PreventDataRacesWithMultipleThreads.qhelp delete mode 100644 c/cert/src/rules/CON32-C/standard-example.c delete mode 100644 c/cert/src/rules/CON33-C/RaceConditionsWhenUsingLibraryFunctions-standard.qhelp create mode 100644 c/cert/src/rules/CON33-C/RaceConditionsWhenUsingLibraryFunctions.md delete mode 100644 c/cert/src/rules/CON33-C/RaceConditionsWhenUsingLibraryFunctions.qhelp delete mode 100644 c/cert/src/rules/CON33-C/standard-example.c delete mode 100644 c/cert/src/rules/CON37-C/DoNotCallSignalInMultithreadedProgram-standard.qhelp create mode 100644 c/cert/src/rules/CON37-C/DoNotCallSignalInMultithreadedProgram.md delete mode 100644 c/cert/src/rules/CON37-C/DoNotCallSignalInMultithreadedProgram.qhelp delete mode 100644 c/cert/src/rules/CON37-C/standard-example.c delete mode 100644 c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects-standard.qhelp create mode 100644 c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.md delete mode 100644 c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.qhelp delete mode 100644 c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects-standard.qhelp create mode 100644 c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects.md delete mode 100644 c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects.qhelp delete mode 100644 c/cert/src/rules/EXP30-C/standard-example.c delete mode 100644 c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect-standard.qhelp create mode 100644 c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect.md delete mode 100644 c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect.qhelp delete mode 100644 c/cert/src/rules/EXP44-C/standard-example.c delete mode 100644 c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements-standard.qhelp create mode 100644 c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements.md delete mode 100644 c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements.qhelp delete mode 100644 c/cert/src/rules/EXP45-C/standard-example.c delete mode 100644 c/cert/src/rules/FIO30-C/ExcludeUserInputFromFormatStrings-standard.qhelp create mode 100644 c/cert/src/rules/FIO30-C/ExcludeUserInputFromFormatStrings.md delete mode 100644 c/cert/src/rules/FIO30-C/ExcludeUserInputFromFormatStrings.qhelp delete mode 100644 c/cert/src/rules/FIO30-C/standard-example.c delete mode 100644 c/cert/src/rules/FIO32-C/DoNotPerformFileOperationsOnDevices-standard.qhelp create mode 100644 c/cert/src/rules/FIO32-C/DoNotPerformFileOperationsOnDevices.md delete mode 100644 c/cert/src/rules/FIO32-C/DoNotPerformFileOperationsOnDevices.qhelp delete mode 100644 c/cert/src/rules/FIO34-C/DistinguishBetweenCharReadFromAFileAndEofOrWeof-standard.qhelp create mode 100644 c/cert/src/rules/FIO34-C/DistinguishBetweenCharReadFromAFileAndEofOrWeof.md delete mode 100644 c/cert/src/rules/FIO34-C/DistinguishBetweenCharReadFromAFileAndEofOrWeof.qhelp delete mode 100644 c/cert/src/rules/FIO34-C/EndOfFileCheckPortability-standard.qhelp create mode 100644 c/cert/src/rules/FIO34-C/EndOfFileCheckPortability.md delete mode 100644 c/cert/src/rules/FIO34-C/EndOfFileCheckPortability.qhelp delete mode 100644 c/cert/src/rules/FIO34-C/standard-example.c delete mode 100644 c/cert/src/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString-standard.qhelp create mode 100644 c/cert/src/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString.md delete mode 100644 c/cert/src/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString.qhelp delete mode 100644 c/cert/src/rules/FIO38-C/DoNotCopyAFileObject-standard.qhelp create mode 100644 c/cert/src/rules/FIO38-C/DoNotCopyAFileObject.md delete mode 100644 c/cert/src/rules/FIO38-C/DoNotCopyAFileObject.qhelp delete mode 100644 c/cert/src/rules/FIO38-C/standard-example.c delete mode 100644 c/cert/src/rules/FIO39-C/DoNotAlternatelyIOFromAStreamWithoutPositioning-standard.qhelp create mode 100644 c/cert/src/rules/FIO39-C/DoNotAlternatelyIOFromAStreamWithoutPositioning.md delete mode 100644 c/cert/src/rules/FIO39-C/DoNotAlternatelyIOFromAStreamWithoutPositioning.qhelp delete mode 100644 c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure-standard.qhelp create mode 100644 c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.md delete mode 100644 c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.qhelp delete mode 100644 c/cert/src/rules/FIO40-C/standard-example.c delete mode 100644 c/cert/src/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects-standard.qhelp create mode 100644 c/cert/src/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects.md delete mode 100644 c/cert/src/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects.qhelp delete mode 100644 c/cert/src/rules/FIO41-C/standard-example.c delete mode 100644 c/cert/src/rules/FIO42-C/CloseFilesWhenTheyAreNoLongerNeeded-standard.qhelp create mode 100644 c/cert/src/rules/FIO42-C/CloseFilesWhenTheyAreNoLongerNeeded.md delete mode 100644 c/cert/src/rules/FIO42-C/CloseFilesWhenTheyAreNoLongerNeeded.qhelp delete mode 100644 c/cert/src/rules/FIO42-C/standard-example.c delete mode 100644 c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos-standard.qhelp create mode 100644 c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.md delete mode 100644 c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.qhelp delete mode 100644 c/cert/src/rules/FIO44-C/standard-example.c delete mode 100644 c/cert/src/rules/FIO46-C/UndefinedBehaviorAccessingAClosedFile-standard.qhelp create mode 100644 c/cert/src/rules/FIO46-C/UndefinedBehaviorAccessingAClosedFile.md delete mode 100644 c/cert/src/rules/FIO46-C/UndefinedBehaviorAccessingAClosedFile.qhelp delete mode 100644 c/cert/src/rules/FIO46-C/standard-example.c delete mode 100644 c/cert/src/rules/MSC30-C/RandUsedForGeneratingPseudorandomNumbers-standard.qhelp create mode 100644 c/cert/src/rules/MSC30-C/RandUsedForGeneratingPseudorandomNumbers.md delete mode 100644 c/cert/src/rules/MSC30-C/RandUsedForGeneratingPseudorandomNumbers.qhelp delete mode 100644 c/cert/src/rules/MSC32-C/ProperlySeedPseudorandomNumberGenerators-standard.qhelp create mode 100644 c/cert/src/rules/MSC32-C/ProperlySeedPseudorandomNumberGenerators.md delete mode 100644 c/cert/src/rules/MSC32-C/ProperlySeedPseudorandomNumberGenerators.qhelp delete mode 100644 c/cert/src/rules/MSC37-C/ControlFlowReachesTheEndOfANonVoidFunction-standard.qhelp create mode 100644 c/cert/src/rules/MSC37-C/ControlFlowReachesTheEndOfANonVoidFunction.md delete mode 100644 c/cert/src/rules/MSC37-C/ControlFlowReachesTheEndOfANonVoidFunction.qhelp delete mode 100644 c/cert/src/rules/STR30-C/DoNotAttemptToModifyStringLiterals-standard.qhelp create mode 100644 c/cert/src/rules/STR30-C/DoNotAttemptToModifyStringLiterals.md delete mode 100644 c/cert/src/rules/STR30-C/DoNotAttemptToModifyStringLiterals.qhelp delete mode 100644 c/cert/src/rules/STR30-C/standard-example.c delete mode 100644 c/cert/src/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator-standard.qhelp create mode 100644 c/cert/src/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.md delete mode 100644 c/cert/src/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.qhelp delete mode 100644 c/cert/src/rules/STR31-C/standard-example.c delete mode 100644 c/cert/src/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString-standard.qhelp create mode 100644 c/cert/src/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.md delete mode 100644 c/cert/src/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.qhelp delete mode 100644 c/cert/src/rules/STR32-C/standard-example.c delete mode 100644 c/cert/src/rules/STR34-C/CastCharBeforeConvertingToLargerSizes-standard.qhelp create mode 100644 c/cert/src/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.md delete mode 100644 c/cert/src/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.qhelp delete mode 100644 c/cert/src/rules/STR34-C/standard-example.c delete mode 100644 c/cert/src/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar-standard.qhelp create mode 100644 c/cert/src/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar.md delete mode 100644 c/cert/src/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar.qhelp delete mode 100644 c/cert/src/rules/STR37-C/standard-example.c delete mode 100644 c/cert/src/rules/STR38-C/DoNotConfuseNarrowAndWideFunctions-standard.qhelp create mode 100644 c/cert/src/rules/STR38-C/DoNotConfuseNarrowAndWideFunctions.md delete mode 100644 c/cert/src/rules/STR38-C/DoNotConfuseNarrowAndWideFunctions.qhelp delete mode 100644 c/cert/src/rules/STR38-C/standard-example.c create mode 100644 c/common/test/includes/standard-library/LICENSE delete mode 100644 c/misra/src/rules/DIR-4-5/standard-example.cpp delete mode 100644 c/misra/src/rules/RULE-11-1/standard-example.c delete mode 100644 c/misra/src/rules/RULE-11-2/standard-example.c delete mode 100644 c/misra/src/rules/RULE-11-3/standard-example.c delete mode 100644 c/misra/src/rules/RULE-11-4/standard-example.c delete mode 100644 c/misra/src/rules/RULE-11-5/standard-example.c delete mode 100644 c/misra/src/rules/RULE-11-6/standard-example.c delete mode 100644 c/misra/src/rules/RULE-11-7/standard-example.c delete mode 100644 c/misra/src/rules/RULE-11-8/standard-example.c delete mode 100644 c/misra/src/rules/RULE-11-9/standard-example.c delete mode 100644 c/misra/src/rules/RULE-12-1/standard-example.c delete mode 100644 c/misra/src/rules/RULE-13-1/standard-example.c delete mode 100644 c/misra/src/rules/RULE-13-3/standard-example.c delete mode 100644 c/misra/src/rules/RULE-13-4/standard-example.c delete mode 100644 c/misra/src/rules/RULE-13-5/standard-example.c delete mode 100644 c/misra/src/rules/RULE-13-6/standard-example.c delete mode 100644 c/misra/src/rules/RULE-17-8/standard-example.c delete mode 100644 c/misra/src/rules/RULE-18-1/standard-example.c delete mode 100644 c/misra/src/rules/RULE-18-2/standard-example.c delete mode 100644 c/misra/src/rules/RULE-18-3/standard-example.c delete mode 100644 c/misra/src/rules/RULE-18-4/standard-example.c delete mode 100644 c/misra/src/rules/RULE-18-5/standard-example.c delete mode 100644 c/misra/src/rules/RULE-18-6/standard-example.c delete mode 100644 c/misra/src/rules/RULE-20-1/standard-example.c delete mode 100644 c/misra/src/rules/RULE-20-11/standard-example.c delete mode 100644 c/misra/src/rules/RULE-20-12/standard-example.c delete mode 100644 c/misra/src/rules/RULE-20-2/standard-example.c delete mode 100644 c/misra/src/rules/RULE-20-5/standard-example.c delete mode 100644 c/misra/src/rules/RULE-20-8/standard-example.c delete mode 100644 c/misra/src/rules/RULE-20-9/standard-example.c delete mode 100644 c/misra/src/rules/RULE-22-3/standard-example.c delete mode 100644 c/misra/src/rules/RULE-22-4/standard-example.c delete mode 100644 c/misra/src/rules/RULE-22-5/standard-example.c delete mode 100644 c/misra/src/rules/RULE-22-6/standard-example.c delete mode 100644 c/misra/src/rules/RULE-22-7/standard-example1.c delete mode 100644 c/misra/src/rules/RULE-22-7/standard-example2.c delete mode 100644 c/misra/src/rules/RULE-4-10/standard-example.c delete mode 100644 c/misra/src/rules/RULE-4-8/standard-example.c delete mode 100644 c/misra/src/rules/RULE-8-13/standard-example.c create mode 100644 change_notes/2021-10-26-enable-lifetime-profile.md create mode 100644 change_notes/2022-03-04-address-fp-m7-3-4.md create mode 100644 change_notes/2022-03-16-fix-placeholders.md create mode 100644 change_notes/2022-03-18 create mode 100644 change_notes/2022-03-18-address-fp-A3-3-1.md create mode 100644 change_notes/2022-06-24-use-variable-entry-type-in-M3-2-1.md delete mode 100644 cpp/autosar/src/rules/A0-1-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A0-1-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A0-1-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A0-1-4/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A0-1-5/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A0-1-6/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A0-4-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A0-4-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A0-4-4/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A1-1-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A10-1-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A10-2-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A10-3-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A10-3-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A10-3-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A10-3-5/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A11-0-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A11-0-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A11-3-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A12-0-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A12-0-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A12-1-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A12-1-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A12-1-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A12-1-4/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A12-1-5/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A12-1-6/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A12-4-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A12-4-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A12-6-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A12-7-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A12-8-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A12-8-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A12-8-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A12-8-4/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A12-8-5/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A12-8-6/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A12-8-7/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A13-1-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A13-1-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A13-2-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A13-2-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A13-2-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A13-3-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A13-5-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A13-5-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A13-5-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A13-5-4/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A13-5-5/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A13-6-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A14-1-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A14-5-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A14-5-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A14-5-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A14-7-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A14-7-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A14-8-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A15-0-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A15-0-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A15-0-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A15-0-4/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A15-0-5/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A15-1-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A15-1-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A15-1-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A15-1-4/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A15-1-5/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A15-2-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A15-2-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A15-3-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A15-3-4/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A15-3-5/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A15-4-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A15-4-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A15-4-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A15-4-4/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A15-4-5/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A15-5-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A15-5-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A15-5-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A16-0-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A16-2-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A16-2-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A16-6-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A16-7-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A17-0-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A17-1-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A17-6-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A18-0-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A18-1-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A18-1-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A18-1-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A18-1-4/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A18-1-6/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A18-5-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A18-5-10/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A18-5-11/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A18-5-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A18-5-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A18-5-4/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A18-5-5/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A18-5-8/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A18-5-9/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A18-9-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A18-9-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A18-9-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A18-9-4/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A2-10-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A2-10-4/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A2-10-5/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A2-10-6/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A2-13-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A2-13-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A2-13-4/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A2-13-5/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A2-13-6/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A2-3-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A2-7-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A2-7-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A2-7-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A20-8-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A20-8-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A20-8-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A20-8-4/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A20-8-5/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A20-8-6/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A20-8-7/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A21-8-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A23-0-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A23-0-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A25-1-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A25-4-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A26-5-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A26-5-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A27-0-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A27-0-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A27-0-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A27-0-4/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A3-1-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A3-1-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A3-1-4/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A3-1-5/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A3-1-6/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A3-3-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A3-3-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A3-8-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A3-9-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A4-10-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A4-5-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A4-7-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A5-0-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A5-0-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A5-0-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A5-0-4/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A5-1-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A5-1-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A5-1-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A5-1-4/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A5-1-6/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A5-1-7/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A5-1-8/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A5-1-9/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A5-10-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A5-16-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A5-2-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A5-2-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A5-2-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A5-2-4/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A5-2-5/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A5-2-6/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A5-3-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A5-3-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A5-3-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A5-5-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A5-6-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A6-2-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A6-2-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A6-4-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A6-5-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A6-5-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A6-5-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A6-5-4/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A6-6-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A7-1-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A7-1-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A7-1-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A7-1-4/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A7-1-5/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A7-1-6/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A7-1-7/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A7-1-9/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A7-2-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A7-2-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A7-2-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A7-2-4/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A7-2-5/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A7-3-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A7-4-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A7-5-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A7-5-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A7-6-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A8-4-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A8-4-10/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A8-4-11/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A8-4-12/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A8-4-13/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A8-4-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A8-4-4/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A8-4-5/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A8-4-6/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A8-4-7/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A8-4-8/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A8-4-9/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A8-5-0/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A8-5-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A8-5-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A8-5-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A8-5-4/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A9-3-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A9-5-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/A9-6-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M0-1-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M0-1-10/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M0-1-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M0-1-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M0-1-4/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M0-1-8/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M0-1-9/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M0-2-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M0-3-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M10-1-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M10-1-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M10-1-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M10-2-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M10-3-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M11-0-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M12-1-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M14-5-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M14-6-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M15-0-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M15-1-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M15-1-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M15-1-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M15-3-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M15-3-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M15-3-4/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M15-3-6/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M15-3-7/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M16-0-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M16-0-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M16-0-5/standard-example1.cpp delete mode 100644 cpp/autosar/src/rules/M16-0-5/standard-example2.cpp delete mode 100644 cpp/autosar/src/rules/M16-0-5/standard-example3.cpp delete mode 100644 cpp/autosar/src/rules/M16-0-6/standard-example1.cpp delete mode 100644 cpp/autosar/src/rules/M16-0-6/standard-example2.cpp delete mode 100644 cpp/autosar/src/rules/M16-0-6/standard-example3.cpp delete mode 100644 cpp/autosar/src/rules/M16-0-6/standard-example4.cpp delete mode 100644 cpp/autosar/src/rules/M16-0-6/standard-example5.cpp delete mode 100644 cpp/autosar/src/rules/M16-0-7/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M16-1-1/standard-example1.cpp delete mode 100644 cpp/autosar/src/rules/M16-1-1/standard-example2.cpp delete mode 100644 cpp/autosar/src/rules/M16-2-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M16-3-1/standard-example1.cpp delete mode 100644 cpp/autosar/src/rules/M16-3-1/standard-example2.cpp delete mode 100644 cpp/autosar/src/rules/M16-3-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M17-0-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M17-0-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M17-0-5/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M18-0-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M18-0-4/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M18-0-5/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M18-2-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M18-7-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M19-3-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M2-10-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M2-13-2/standard-example1.cpp delete mode 100644 cpp/autosar/src/rules/M2-13-2/standard-example2.cpp delete mode 100644 cpp/autosar/src/rules/M2-13-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M2-13-4/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M2-7-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M27-0-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M3-1-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M3-2-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M3-2-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M3-2-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M3-2-4/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M3-3-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M3-4-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M3-9-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M3-9-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M4-10-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M4-10-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M4-5-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M4-5-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M5-0-11/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M5-0-12/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M5-0-14/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M5-0-15/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M5-0-16/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M5-0-17/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M5-0-18/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M5-0-20/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M5-0-21/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M5-0-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M5-0-4/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M5-0-5/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M5-0-6/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M5-0-7/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M5-0-7/standard-example2.cpp delete mode 100644 cpp/autosar/src/rules/M5-0-8/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M5-0-9/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M5-14-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M5-17-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M5-18-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M5-19-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M5-2-11/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M5-2-12/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M5-2-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M5-2-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M5-2-6/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M5-2-8/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M5-2-9/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M5-3-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M5-3-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M5-3-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M5-3-4/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M5-8-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M6-2-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M6-2-2/standard-example1.cpp delete mode 100644 cpp/autosar/src/rules/M6-2-2/standard-example2.cpp delete mode 100644 cpp/autosar/src/rules/M6-2-2/standard-example3.cpp delete mode 100644 cpp/autosar/src/rules/M6-2-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M6-3-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M6-4-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M6-4-2/standard-example1.cpp delete mode 100644 cpp/autosar/src/rules/M6-4-2/standard-example2.cpp delete mode 100644 cpp/autosar/src/rules/M6-4-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M6-4-4/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M6-4-5/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M6-4-6/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M6-4-7/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M6-5-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M6-5-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M6-5-4/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M6-5-5/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M6-5-6/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M6-6-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M6-6-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M6-6-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M7-1-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M7-3-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M7-3-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M7-3-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M7-3-4/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M7-3-6/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M7-4-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M7-4-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M7-4-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M7-5-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M7-5-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M8-0-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M8-3-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M8-4-2/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M8-4-4/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M8-5-2/standard-example1.cpp delete mode 100644 cpp/autosar/src/rules/M8-5-2/standard-example2.cpp delete mode 100644 cpp/autosar/src/rules/M9-3-1/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M9-3-3/standard-example.cpp delete mode 100644 cpp/autosar/src/rules/M9-6-4/standard-example.cpp delete mode 100644 cpp/cert/src/rules/CON50-CPP/DoNotAllowAMutexToGoOutOfScopeWhileLocked-standard.qhelp create mode 100644 cpp/cert/src/rules/CON50-CPP/DoNotAllowAMutexToGoOutOfScopeWhileLocked.md delete mode 100644 cpp/cert/src/rules/CON50-CPP/DoNotAllowAMutexToGoOutOfScopeWhileLocked.qhelp delete mode 100644 cpp/cert/src/rules/CON50-CPP/DoNotDestroyAMutexWhileItIsLocked-standard.qhelp create mode 100644 cpp/cert/src/rules/CON50-CPP/DoNotDestroyAMutexWhileItIsLocked.md delete mode 100644 cpp/cert/src/rules/CON50-CPP/DoNotDestroyAMutexWhileItIsLocked.qhelp delete mode 100644 cpp/cert/src/rules/CON51-CPP/EnsureActivelyHeldLocksAreReleasedOnExceptionalConditions-standard.qhelp create mode 100644 cpp/cert/src/rules/CON51-CPP/EnsureActivelyHeldLocksAreReleasedOnExceptionalConditions.md delete mode 100644 cpp/cert/src/rules/CON51-CPP/EnsureActivelyHeldLocksAreReleasedOnExceptionalConditions.qhelp delete mode 100644 cpp/cert/src/rules/CON52-CPP/PreventBitFieldAccessFromMultipleThreads-standard.qhelp delete mode 100644 cpp/cert/src/rules/CON52-CPP/PreventBitFieldAccessFromMultipleThreads.qhelp create mode 100644 cpp/cert/src/rules/CON52-CPP/PreventDataRacesWhenAccessingBitFieldsFromMultipleThreads.md delete mode 100644 cpp/cert/src/rules/CON52-CPP/standard-example.cpp delete mode 100644 cpp/cert/src/rules/CON53-CPP/DeadlockByLockingInPredefinedOrder-standard.qhelp create mode 100644 cpp/cert/src/rules/CON53-CPP/DeadlockByLockingInPredefinedOrder.md delete mode 100644 cpp/cert/src/rules/CON53-CPP/DeadlockByLockingInPredefinedOrder.qhelp delete mode 100644 cpp/cert/src/rules/CON54-CPP/WrapFunctionsThatCanSpuriouslyWakeUpInLoop-standard.qhelp create mode 100644 cpp/cert/src/rules/CON54-CPP/WrapFunctionsThatCanSpuriouslyWakeUpInLoop.md delete mode 100644 cpp/cert/src/rules/CON54-CPP/WrapFunctionsThatCanSpuriouslyWakeUpInLoop.qhelp delete mode 100644 cpp/cert/src/rules/CON55-CPP/PreserveThreadSafetyAndLivenessWhenUsingConditionVariables-standard.qhelp create mode 100644 cpp/cert/src/rules/CON55-CPP/PreserveThreadSafetyAndLivenessWhenUsingConditionVariables.md delete mode 100644 cpp/cert/src/rules/CON55-CPP/PreserveThreadSafetyAndLivenessWhenUsingConditionVariables.qhelp delete mode 100644 cpp/cert/src/rules/CON56-CPP/DoNotSpeculativelyLockALockedNonRecursiveMutex-standard.qhelp create mode 100644 cpp/cert/src/rules/CON56-CPP/DoNotSpeculativelyLockALockedNonRecursiveMutex.md delete mode 100644 cpp/cert/src/rules/CON56-CPP/DoNotSpeculativelyLockALockedNonRecursiveMutex.qhelp delete mode 100644 cpp/cert/src/rules/CON56-CPP/LockedALockedNonRecursiveMutexAudit-standard.qhelp create mode 100644 cpp/cert/src/rules/CON56-CPP/LockedALockedNonRecursiveMutexAudit.md delete mode 100644 cpp/cert/src/rules/CON56-CPP/LockedALockedNonRecursiveMutexAudit.qhelp delete mode 100644 cpp/cert/src/rules/CTR50-CPP/ContainerAccessWithoutRangeCheckCert-standard.qhelp create mode 100644 cpp/cert/src/rules/CTR50-CPP/ContainerAccessWithoutRangeCheckCert.md delete mode 100644 cpp/cert/src/rules/CTR50-CPP/ContainerAccessWithoutRangeCheckCert.qhelp delete mode 100644 cpp/cert/src/rules/CTR51-CPP/UsesValidContainerElementAccess-standard.qhelp create mode 100644 cpp/cert/src/rules/CTR51-CPP/UsesValidContainerElementAccess.md delete mode 100644 cpp/cert/src/rules/CTR51-CPP/UsesValidContainerElementAccess.qhelp delete mode 100644 cpp/cert/src/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow-standard.qhelp create mode 100644 cpp/cert/src/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow.md delete mode 100644 cpp/cert/src/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow.qhelp delete mode 100644 cpp/cert/src/rules/CTR53-CPP/UseValidIteratorRanges-standard.qhelp create mode 100644 cpp/cert/src/rules/CTR53-CPP/UseValidIteratorRanges.md delete mode 100644 cpp/cert/src/rules/CTR53-CPP/UseValidIteratorRanges.qhelp delete mode 100644 cpp/cert/src/rules/CTR54-CPP/DoNotSubtractIteratorsForDifferentContainers-standard.qhelp create mode 100644 cpp/cert/src/rules/CTR54-CPP/DoNotSubtractIteratorsForDifferentContainers.md delete mode 100644 cpp/cert/src/rules/CTR54-CPP/DoNotSubtractIteratorsForDifferentContainers.qhelp delete mode 100644 cpp/cert/src/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator-standard.qhelp create mode 100644 cpp/cert/src/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator.md delete mode 100644 cpp/cert/src/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator.qhelp delete mode 100644 cpp/cert/src/rules/CTR56-CPP/DoNotUsePointerArithmeticOnPolymorphicObjects-standard.qhelp create mode 100644 cpp/cert/src/rules/CTR56-CPP/DoNotUsePointerArithmeticOnPolymorphicObjects.md delete mode 100644 cpp/cert/src/rules/CTR56-CPP/DoNotUsePointerArithmeticOnPolymorphicObjects.qhelp delete mode 100644 cpp/cert/src/rules/CTR56-CPP/standard-example.cpp delete mode 100644 cpp/cert/src/rules/CTR57-CPP/ProvideAValidOrderingPredicate-standard.qhelp create mode 100644 cpp/cert/src/rules/CTR57-CPP/ProvideAValidOrderingPredicate.md delete mode 100644 cpp/cert/src/rules/CTR57-CPP/ProvideAValidOrderingPredicate.qhelp delete mode 100644 cpp/cert/src/rules/CTR58-CPP/PredicateFunctionObjectsShouldNotBeMutable-standard.qhelp create mode 100644 cpp/cert/src/rules/CTR58-CPP/PredicateFunctionObjectsShouldNotBeMutable.md delete mode 100644 cpp/cert/src/rules/CTR58-CPP/PredicateFunctionObjectsShouldNotBeMutable.qhelp delete mode 100644 cpp/cert/src/rules/DCL50-CPP/DoNotDefineACStyleVariadicFunction-standard.qhelp create mode 100644 cpp/cert/src/rules/DCL50-CPP/DoNotDefineACStyleVariadicFunction.md delete mode 100644 cpp/cert/src/rules/DCL50-CPP/DoNotDefineACStyleVariadicFunction.qhelp delete mode 100644 cpp/cert/src/rules/DCL51-CPP/EnumeratorReusesReservedName-standard.qhelp create mode 100644 cpp/cert/src/rules/DCL51-CPP/EnumeratorReusesReservedName.md delete mode 100644 cpp/cert/src/rules/DCL51-CPP/EnumeratorReusesReservedName.qhelp delete mode 100644 cpp/cert/src/rules/DCL51-CPP/FunctionReusesReservedName-standard.qhelp create mode 100644 cpp/cert/src/rules/DCL51-CPP/FunctionReusesReservedName.md delete mode 100644 cpp/cert/src/rules/DCL51-CPP/FunctionReusesReservedName.qhelp delete mode 100644 cpp/cert/src/rules/DCL51-CPP/ObjectReusesReservedName-standard.qhelp create mode 100644 cpp/cert/src/rules/DCL51-CPP/ObjectReusesReservedName.md delete mode 100644 cpp/cert/src/rules/DCL51-CPP/ObjectReusesReservedName.qhelp delete mode 100644 cpp/cert/src/rules/DCL51-CPP/RedefiningOfStandardLibraryName-standard.qhelp create mode 100644 cpp/cert/src/rules/DCL51-CPP/RedefiningOfStandardLibraryName.md delete mode 100644 cpp/cert/src/rules/DCL51-CPP/RedefiningOfStandardLibraryName.qhelp delete mode 100644 cpp/cert/src/rules/DCL51-CPP/ReuseOfReservedIdentifier-standard.qhelp create mode 100644 cpp/cert/src/rules/DCL51-CPP/ReuseOfReservedIdentifier.md delete mode 100644 cpp/cert/src/rules/DCL51-CPP/ReuseOfReservedIdentifier.qhelp delete mode 100644 cpp/cert/src/rules/DCL51-CPP/UseOfDoubleUnderscoreReservedPrefix-standard.qhelp create mode 100644 cpp/cert/src/rules/DCL51-CPP/UseOfDoubleUnderscoreReservedPrefix.md delete mode 100644 cpp/cert/src/rules/DCL51-CPP/UseOfDoubleUnderscoreReservedPrefix.qhelp delete mode 100644 cpp/cert/src/rules/DCL51-CPP/UseOfReservedLiteralSuffixIdentifier-standard.qhelp create mode 100644 cpp/cert/src/rules/DCL51-CPP/UseOfReservedLiteralSuffixIdentifier.md delete mode 100644 cpp/cert/src/rules/DCL51-CPP/UseOfReservedLiteralSuffixIdentifier.qhelp delete mode 100644 cpp/cert/src/rules/DCL51-CPP/UseOfReservedNamePrefix-standard.qhelp delete mode 100644 cpp/cert/src/rules/DCL51-CPP/UseOfSingleUnderscoreReservedPrefix-standard.qhelp create mode 100644 cpp/cert/src/rules/DCL51-CPP/UseOfSingleUnderscoreReservedPrefix.md delete mode 100644 cpp/cert/src/rules/DCL51-CPP/UseOfSingleUnderscoreReservedPrefix.qhelp delete mode 100644 cpp/cert/src/rules/DCL53-CPP/LocalConstructorInitializedObjectHidesIdentifier-standard.qhelp create mode 100644 cpp/cert/src/rules/DCL53-CPP/LocalConstructorInitializedObjectHidesIdentifier.md delete mode 100644 cpp/cert/src/rules/DCL53-CPP/LocalConstructorInitializedObjectHidesIdentifier.qhelp delete mode 100644 cpp/cert/src/rules/DCL53-CPP/LocalFunctionDeclaration-standard.qhelp create mode 100644 cpp/cert/src/rules/DCL53-CPP/LocalFunctionDeclaration.md delete mode 100644 cpp/cert/src/rules/DCL53-CPP/LocalFunctionDeclaration.qhelp delete mode 100644 cpp/cert/src/rules/DCL54-CPP/SingularOverloadOfMemoryFunction-standard.qhelp create mode 100644 cpp/cert/src/rules/DCL54-CPP/SingularOverloadOfMemoryFunction.md delete mode 100644 cpp/cert/src/rules/DCL54-CPP/SingularOverloadOfMemoryFunction.qhelp delete mode 100644 cpp/cert/src/rules/DCL55-CPP/InformationLeakageAcrossTrustBoundaries-standard.qhelp create mode 100644 cpp/cert/src/rules/DCL55-CPP/InformationLeakageAcrossTrustBoundaries.md delete mode 100644 cpp/cert/src/rules/DCL55-CPP/InformationLeakageAcrossTrustBoundaries.qhelp delete mode 100644 cpp/cert/src/rules/DCL56-CPP/CyclesDuringStaticObjectInit-standard.qhelp create mode 100644 cpp/cert/src/rules/DCL56-CPP/CyclesDuringStaticObjectInit.md delete mode 100644 cpp/cert/src/rules/DCL56-CPP/CyclesDuringStaticObjectInit.qhelp delete mode 100644 cpp/cert/src/rules/DCL57-CPP/DoNotLetExceptionsEscapeFromDestructorsOrDeallocationFunctions-standard.qhelp create mode 100644 cpp/cert/src/rules/DCL57-CPP/DoNotLetExceptionsEscapeFromDestructorsOrDeallocationFunctions.md delete mode 100644 cpp/cert/src/rules/DCL57-CPP/DoNotLetExceptionsEscapeFromDestructorsOrDeallocationFunctions.qhelp delete mode 100644 cpp/cert/src/rules/DCL58-CPP/ModificationOfTheStandardNamespaces-standard.qhelp create mode 100644 cpp/cert/src/rules/DCL58-CPP/ModificationOfTheStandardNamespaces.md delete mode 100644 cpp/cert/src/rules/DCL58-CPP/ModificationOfTheStandardNamespaces.qhelp delete mode 100644 cpp/cert/src/rules/DCL59-CPP/UnnamedNamespaceInHeaderFile-standard.qhelp create mode 100644 cpp/cert/src/rules/DCL59-CPP/UnnamedNamespaceInHeaderFile.md delete mode 100644 cpp/cert/src/rules/DCL59-CPP/UnnamedNamespaceInHeaderFile.qhelp delete mode 100644 cpp/cert/src/rules/DCL60-CPP/OneDefinitionRuleNotObeyed-standard.qhelp create mode 100644 cpp/cert/src/rules/DCL60-CPP/OneDefinitionRuleNotObeyed.md delete mode 100644 cpp/cert/src/rules/DCL60-CPP/OneDefinitionRuleNotObeyed.qhelp delete mode 100644 cpp/cert/src/rules/ERR50-CPP/ConditionVariablePostConditionFailedCert-standard.qhelp create mode 100644 cpp/cert/src/rules/ERR50-CPP/ConditionVariablePostConditionFailedCert.md delete mode 100644 cpp/cert/src/rules/ERR50-CPP/ConditionVariablePostConditionFailedCert.qhelp delete mode 100644 cpp/cert/src/rules/ERR50-CPP/ExitHandlerThrowsExceptionCert-standard.qhelp create mode 100644 cpp/cert/src/rules/ERR50-CPP/ExitHandlerThrowsExceptionCert.md delete mode 100644 cpp/cert/src/rules/ERR50-CPP/ExitHandlerThrowsExceptionCert.qhelp delete mode 100644 cpp/cert/src/rules/ERR50-CPP/ExplicitAbruptTerminationCert-standard.qhelp create mode 100644 cpp/cert/src/rules/ERR50-CPP/ExplicitAbruptTerminationCert.md delete mode 100644 cpp/cert/src/rules/ERR50-CPP/ExplicitAbruptTerminationCert.qhelp delete mode 100644 cpp/cert/src/rules/ERR50-CPP/JoinableThreadCopiedOrDestroyedCert-standard.qhelp create mode 100644 cpp/cert/src/rules/ERR50-CPP/JoinableThreadCopiedOrDestroyedCert.md delete mode 100644 cpp/cert/src/rules/ERR50-CPP/JoinableThreadCopiedOrDestroyedCert.qhelp delete mode 100644 cpp/cert/src/rules/ERR50-CPP/RethrowNestedWithoutCaptureCert-standard.qhelp create mode 100644 cpp/cert/src/rules/ERR50-CPP/RethrowNestedWithoutCaptureCert.md delete mode 100644 cpp/cert/src/rules/ERR50-CPP/RethrowNestedWithoutCaptureCert.qhelp delete mode 100644 cpp/cert/src/rules/ERR51-CPP/HandleAllExceptions-standard.qhelp create mode 100644 cpp/cert/src/rules/ERR51-CPP/HandleAllExceptions.md delete mode 100644 cpp/cert/src/rules/ERR51-CPP/HandleAllExceptions.qhelp delete mode 100644 cpp/cert/src/rules/ERR52-CPP/DoNotUseSetjmpOrLongjmp-standard.qhelp create mode 100644 cpp/cert/src/rules/ERR52-CPP/DoNotUseSetjmpOrLongjmp.md delete mode 100644 cpp/cert/src/rules/ERR52-CPP/DoNotUseSetjmpOrLongjmp.qhelp delete mode 100644 cpp/cert/src/rules/ERR53-CPP/DestroyedValueReferencedInConstructorDestructorCatchBlock-standard.qhelp create mode 100644 cpp/cert/src/rules/ERR53-CPP/DestroyedValueReferencedInConstructorDestructorCatchBlock.md delete mode 100644 cpp/cert/src/rules/ERR53-CPP/DestroyedValueReferencedInConstructorDestructorCatchBlock.qhelp delete mode 100644 cpp/cert/src/rules/ERR54-CPP/CatchBlockShadowingCert-standard.qhelp create mode 100644 cpp/cert/src/rules/ERR54-CPP/CatchBlockShadowingCert.md delete mode 100644 cpp/cert/src/rules/ERR54-CPP/CatchBlockShadowingCert.qhelp delete mode 100644 cpp/cert/src/rules/ERR55-CPP/HonorExceptionSpecifications-standard.qhelp create mode 100644 cpp/cert/src/rules/ERR55-CPP/HonorExceptionSpecifications.md delete mode 100644 cpp/cert/src/rules/ERR55-CPP/HonorExceptionSpecifications.qhelp delete mode 100644 cpp/cert/src/rules/ERR56-CPP/GuaranteeExceptionSafety-standard.qhelp create mode 100644 cpp/cert/src/rules/ERR56-CPP/GuaranteeExceptionSafety.md delete mode 100644 cpp/cert/src/rules/ERR56-CPP/GuaranteeExceptionSafety.qhelp delete mode 100644 cpp/cert/src/rules/ERR57-CPP/DoNotLeakResourcesWhenHandlingExceptions-standard.qhelp create mode 100644 cpp/cert/src/rules/ERR57-CPP/DoNotLeakResourcesWhenHandlingExceptions.md delete mode 100644 cpp/cert/src/rules/ERR57-CPP/DoNotLeakResourcesWhenHandlingExceptions.qhelp delete mode 100644 cpp/cert/src/rules/ERR58-CPP/HandleAllExceptionsThrownBeforeMainBeginsExecuting-standard.qhelp create mode 100644 cpp/cert/src/rules/ERR58-CPP/HandleAllExceptionsThrownBeforeMainBeginsExecuting.md delete mode 100644 cpp/cert/src/rules/ERR58-CPP/HandleAllExceptionsThrownBeforeMainBeginsExecuting.qhelp delete mode 100644 cpp/cert/src/rules/ERR59-CPP/DoNotThrowAnExceptionAcrossExecutionBoundaries-standard.qhelp create mode 100644 cpp/cert/src/rules/ERR59-CPP/DoNotThrowAnExceptionAcrossExecutionBoundaries.md delete mode 100644 cpp/cert/src/rules/ERR59-CPP/DoNotThrowAnExceptionAcrossExecutionBoundaries.qhelp delete mode 100644 cpp/cert/src/rules/ERR60-CPP/ExceptionObjectsMustBeNothrowCopyConstructible-standard.qhelp create mode 100644 cpp/cert/src/rules/ERR60-CPP/ExceptionObjectsMustBeNothrowCopyConstructible.md delete mode 100644 cpp/cert/src/rules/ERR60-CPP/ExceptionObjectsMustBeNothrowCopyConstructible.qhelp delete mode 100644 cpp/cert/src/rules/ERR61-CPP/CatchExceptionsByLvalueReference-standard.qhelp create mode 100644 cpp/cert/src/rules/ERR61-CPP/CatchExceptionsByLvalueReference.md delete mode 100644 cpp/cert/src/rules/ERR61-CPP/CatchExceptionsByLvalueReference.qhelp delete mode 100644 cpp/cert/src/rules/ERR62-CPP/DetectErrorsWhenConvertingAStringToANumber-standard.qhelp create mode 100644 cpp/cert/src/rules/ERR62-CPP/DetectErrorsWhenConvertingAStringToANumber.md delete mode 100644 cpp/cert/src/rules/ERR62-CPP/DetectErrorsWhenConvertingAStringToANumber.qhelp delete mode 100644 cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments-standard.qhelp create mode 100644 cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.md delete mode 100644 cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.qhelp delete mode 100644 cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfScalarObjectEvaluationForSideEffects-standard.qhelp create mode 100644 cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfScalarObjectEvaluationForSideEffects.md delete mode 100644 cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfScalarObjectEvaluationForSideEffects.qhelp delete mode 100644 cpp/cert/src/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType-standard.qhelp create mode 100644 cpp/cert/src/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.md delete mode 100644 cpp/cert/src/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.qhelp delete mode 100644 cpp/cert/src/rules/EXP51-CPP/standard-example.cpp delete mode 100644 cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclTypeOperand-standard.qhelp create mode 100644 cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclTypeOperand.md delete mode 100644 cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclTypeOperand.qhelp delete mode 100644 cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclValExpression-standard.qhelp create mode 100644 cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclValExpression.md delete mode 100644 cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclValExpression.qhelp delete mode 100644 cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInNoExceptOperand-standard.qhelp create mode 100644 cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInNoExceptOperand.md delete mode 100644 cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInNoExceptOperand.qhelp delete mode 100644 cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInSizeOfOperand-standard.qhelp create mode 100644 cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInSizeOfOperand.md delete mode 100644 cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInSizeOfOperand.qhelp delete mode 100644 cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInTypeIdOperand-standard.qhelp create mode 100644 cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInTypeIdOperand.md delete mode 100644 cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInTypeIdOperand.qhelp delete mode 100644 cpp/cert/src/rules/EXP53-CPP/DoNotReadUninitializedMemory-standard.qhelp create mode 100644 cpp/cert/src/rules/EXP53-CPP/DoNotReadUninitializedMemory.md delete mode 100644 cpp/cert/src/rules/EXP53-CPP/DoNotReadUninitializedMemory.qhelp delete mode 100644 cpp/cert/src/rules/EXP54-CPP/ObjectAccessedAfterLifetimeCert-standard.qhelp create mode 100644 cpp/cert/src/rules/EXP54-CPP/ObjectAccessedAfterLifetimeCert.md delete mode 100644 cpp/cert/src/rules/EXP54-CPP/ObjectAccessedAfterLifetimeCert.qhelp delete mode 100644 cpp/cert/src/rules/EXP54-CPP/ObjectAccessedBeforeLifetimeCert-standard.qhelp create mode 100644 cpp/cert/src/rules/EXP54-CPP/ObjectAccessedBeforeLifetimeCert.md delete mode 100644 cpp/cert/src/rules/EXP54-CPP/ObjectAccessedBeforeLifetimeCert.qhelp delete mode 100644 cpp/cert/src/rules/EXP54-CPP/standard-example.cpp delete mode 100644 cpp/cert/src/rules/EXP55-CPP/RemoveConstOrVolatileQualificationCert-standard.qhelp create mode 100644 cpp/cert/src/rules/EXP55-CPP/RemoveConstOrVolatileQualificationCert.md delete mode 100644 cpp/cert/src/rules/EXP55-CPP/RemoveConstOrVolatileQualificationCert.qhelp delete mode 100644 cpp/cert/src/rules/EXP56-CPP/FunctionWithMismatchedLanguageLinkage-standard.qhelp create mode 100644 cpp/cert/src/rules/EXP56-CPP/FunctionWithMismatchedLanguageLinkage.md delete mode 100644 cpp/cert/src/rules/EXP56-CPP/FunctionWithMismatchedLanguageLinkage.qhelp delete mode 100644 cpp/cert/src/rules/EXP57-CPP/CastOfPointerToIncompleteClass-standard.qhelp create mode 100644 cpp/cert/src/rules/EXP57-CPP/CastOfPointerToIncompleteClass.md delete mode 100644 cpp/cert/src/rules/EXP57-CPP/CastOfPointerToIncompleteClass.qhelp delete mode 100644 cpp/cert/src/rules/EXP57-CPP/DeletingPointerToIncompleteClass-standard.qhelp create mode 100644 cpp/cert/src/rules/EXP57-CPP/DeletingPointerToIncompleteClass.md delete mode 100644 cpp/cert/src/rules/EXP57-CPP/DeletingPointerToIncompleteClass.qhelp delete mode 100644 cpp/cert/src/rules/EXP57-CPP/standard-example.cpp delete mode 100644 cpp/cert/src/rules/EXP58-CPP/PassNonTrivialObjectToVaStart-standard.qhelp create mode 100644 cpp/cert/src/rules/EXP58-CPP/PassNonTrivialObjectToVaStart.md delete mode 100644 cpp/cert/src/rules/EXP58-CPP/PassNonTrivialObjectToVaStart.qhelp delete mode 100644 cpp/cert/src/rules/EXP58-CPP/PassPromotablePrimitiveTypeToVaStart-standard.qhelp create mode 100644 cpp/cert/src/rules/EXP58-CPP/PassPromotablePrimitiveTypeToVaStart.md delete mode 100644 cpp/cert/src/rules/EXP58-CPP/PassPromotablePrimitiveTypeToVaStart.qhelp delete mode 100644 cpp/cert/src/rules/EXP58-CPP/PassReferenceTypeToVaStart-standard.qhelp create mode 100644 cpp/cert/src/rules/EXP58-CPP/PassReferenceTypeToVaStart.md delete mode 100644 cpp/cert/src/rules/EXP58-CPP/PassReferenceTypeToVaStart.qhelp delete mode 100644 cpp/cert/src/rules/EXP59-CPP/OffsetUsedOnInvalidTypeOrMember-standard.qhelp create mode 100644 cpp/cert/src/rules/EXP59-CPP/OffsetUsedOnInvalidTypeOrMember.md delete mode 100644 cpp/cert/src/rules/EXP59-CPP/OffsetUsedOnInvalidTypeOrMember.qhelp delete mode 100644 cpp/cert/src/rules/EXP60-CPP/DoNotPassANonstandardObjectAcrossBoundaries-standard.qhelp create mode 100644 cpp/cert/src/rules/EXP60-CPP/DoNotPassANonstandardObjectAcrossBoundaries.md delete mode 100644 cpp/cert/src/rules/EXP60-CPP/DoNotPassANonstandardObjectAcrossBoundaries.qhelp delete mode 100644 cpp/cert/src/rules/EXP61-CPP/EscapingLambdaObjectWithCaptureByReference-standard.qhelp create mode 100644 cpp/cert/src/rules/EXP61-CPP/EscapingLambdaObjectWithCaptureByReference.md delete mode 100644 cpp/cert/src/rules/EXP61-CPP/EscapingLambdaObjectWithCaptureByReference.qhelp delete mode 100644 cpp/cert/src/rules/EXP61-CPP/ReturningLambdaObjectWithCaptureByReference-standard.qhelp create mode 100644 cpp/cert/src/rules/EXP61-CPP/ReturningLambdaObjectWithCaptureByReference.md delete mode 100644 cpp/cert/src/rules/EXP61-CPP/ReturningLambdaObjectWithCaptureByReference.qhelp delete mode 100644 cpp/cert/src/rules/EXP62-CPP/MemcmpUsedToAccessObjectRepresentation-standard.qhelp create mode 100644 cpp/cert/src/rules/EXP62-CPP/MemcmpUsedToAccessObjectRepresentation.md delete mode 100644 cpp/cert/src/rules/EXP62-CPP/MemcmpUsedToAccessObjectRepresentation.qhelp delete mode 100644 cpp/cert/src/rules/EXP62-CPP/MemcpyUsedToAccessObjectRepresentation-standard.qhelp create mode 100644 cpp/cert/src/rules/EXP62-CPP/MemcpyUsedToAccessObjectRepresentation.md delete mode 100644 cpp/cert/src/rules/EXP62-CPP/MemcpyUsedToAccessObjectRepresentation.qhelp delete mode 100644 cpp/cert/src/rules/EXP62-CPP/MemsetUsedToAccessObjectRepresentation-standard.qhelp create mode 100644 cpp/cert/src/rules/EXP62-CPP/MemsetUsedToAccessObjectRepresentation.md delete mode 100644 cpp/cert/src/rules/EXP62-CPP/MemsetUsedToAccessObjectRepresentation.qhelp delete mode 100644 cpp/cert/src/rules/EXP63-CPP/DoNotRelyOnTheValueOfAMovedFromObject-standard.qhelp create mode 100644 cpp/cert/src/rules/EXP63-CPP/DoNotRelyOnTheValueOfAMovedFromObject.md delete mode 100644 cpp/cert/src/rules/EXP63-CPP/DoNotRelyOnTheValueOfAMovedFromObject.qhelp delete mode 100644 cpp/cert/src/rules/FIO50-CPP/InterleavedInputOutputWithoutPosition-standard.qhelp create mode 100644 cpp/cert/src/rules/FIO50-CPP/InterleavedInputOutputWithoutPosition.md delete mode 100644 cpp/cert/src/rules/FIO50-CPP/InterleavedInputOutputWithoutPosition.qhelp delete mode 100644 cpp/cert/src/rules/FIO51-CPP/CloseFilesWhenTheyAreNoLongerNeeded-standard.qhelp create mode 100644 cpp/cert/src/rules/FIO51-CPP/CloseFilesWhenTheyAreNoLongerNeeded.md delete mode 100644 cpp/cert/src/rules/FIO51-CPP/CloseFilesWhenTheyAreNoLongerNeeded.qhelp delete mode 100644 cpp/cert/src/rules/INT50-CPP/DoNotCastToAnOutOfRangeEnumerationValue-standard.qhelp create mode 100644 cpp/cert/src/rules/INT50-CPP/DoNotCastToAnOutOfRangeEnumerationValue.md delete mode 100644 cpp/cert/src/rules/INT50-CPP/DoNotCastToAnOutOfRangeEnumerationValue.qhelp delete mode 100644 cpp/cert/src/rules/MEM50-CPP/UseAfterFree-standard.qhelp create mode 100644 cpp/cert/src/rules/MEM50-CPP/UseAfterFree.md delete mode 100644 cpp/cert/src/rules/MEM50-CPP/UseAfterFree.qhelp delete mode 100644 cpp/cert/src/rules/MEM50-CPP/standard-example.cpp delete mode 100644 cpp/cert/src/rules/MEM51-CPP/ProperlyDeallocateDynamicallyAllocatedResources-standard.qhelp create mode 100644 cpp/cert/src/rules/MEM51-CPP/ProperlyDeallocateDynamicallyAllocatedResources.md delete mode 100644 cpp/cert/src/rules/MEM51-CPP/ProperlyDeallocateDynamicallyAllocatedResources.qhelp delete mode 100644 cpp/cert/src/rules/MEM52-CPP/DetectAndHandleMemoryAllocationErrors-standard.qhelp create mode 100644 cpp/cert/src/rules/MEM52-CPP/DetectAndHandleMemoryAllocationErrors.md delete mode 100644 cpp/cert/src/rules/MEM52-CPP/DetectAndHandleMemoryAllocationErrors.qhelp delete mode 100644 cpp/cert/src/rules/MEM53-CPP/MissingConstructorCallForManuallyManagedObject-standard.qhelp create mode 100644 cpp/cert/src/rules/MEM53-CPP/MissingConstructorCallForManuallyManagedObject.md delete mode 100644 cpp/cert/src/rules/MEM53-CPP/MissingConstructorCallForManuallyManagedObject.qhelp delete mode 100644 cpp/cert/src/rules/MEM53-CPP/MissingDestructorCallForManuallyManagedObject-standard.qhelp create mode 100644 cpp/cert/src/rules/MEM53-CPP/MissingDestructorCallForManuallyManagedObject.md delete mode 100644 cpp/cert/src/rules/MEM53-CPP/MissingDestructorCallForManuallyManagedObject.qhelp delete mode 100644 cpp/cert/src/rules/MEM54-CPP/PlacementNewInsufficientStorageCert-standard.qhelp create mode 100644 cpp/cert/src/rules/MEM54-CPP/PlacementNewInsufficientStorageCert.md delete mode 100644 cpp/cert/src/rules/MEM54-CPP/PlacementNewInsufficientStorageCert.qhelp delete mode 100644 cpp/cert/src/rules/MEM54-CPP/PlacementNewNotProperlyAlignedCert-standard.qhelp create mode 100644 cpp/cert/src/rules/MEM54-CPP/PlacementNewNotProperlyAlignedCert.md delete mode 100644 cpp/cert/src/rules/MEM54-CPP/PlacementNewNotProperlyAlignedCert.qhelp delete mode 100644 cpp/cert/src/rules/MEM55-CPP/OperatorDeleteMissingPartnerCert-standard.qhelp create mode 100644 cpp/cert/src/rules/MEM55-CPP/OperatorDeleteMissingPartnerCert.md delete mode 100644 cpp/cert/src/rules/MEM55-CPP/OperatorDeleteMissingPartnerCert.qhelp delete mode 100644 cpp/cert/src/rules/MEM55-CPP/ThrowingNoThrowOperatorNewDeleteCert-standard.qhelp create mode 100644 cpp/cert/src/rules/MEM55-CPP/ThrowingNoThrowOperatorNewDeleteCert.md delete mode 100644 cpp/cert/src/rules/MEM55-CPP/ThrowingNoThrowOperatorNewDeleteCert.qhelp delete mode 100644 cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewReturnsNullCert-standard.qhelp create mode 100644 cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewReturnsNullCert.md delete mode 100644 cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewReturnsNullCert.qhelp delete mode 100644 cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewThrowsInvalidExceptionCert-standard.qhelp create mode 100644 cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewThrowsInvalidExceptionCert.md delete mode 100644 cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewThrowsInvalidExceptionCert.qhelp delete mode 100644 cpp/cert/src/rules/MEM56-CPP/OwnedPointerValueStoredInUnrelatedSmartPointerCert-standard.qhelp create mode 100644 cpp/cert/src/rules/MEM56-CPP/OwnedPointerValueStoredInUnrelatedSmartPointerCert.md delete mode 100644 cpp/cert/src/rules/MEM56-CPP/OwnedPointerValueStoredInUnrelatedSmartPointerCert.qhelp delete mode 100644 cpp/cert/src/rules/MEM57-CPP/UsingDefaultOperatorNewForOverAlignedTypes-standard.qhelp create mode 100644 cpp/cert/src/rules/MEM57-CPP/UsingDefaultOperatorNewForOverAlignedTypes.md delete mode 100644 cpp/cert/src/rules/MEM57-CPP/UsingDefaultOperatorNewForOverAlignedTypes.qhelp delete mode 100644 cpp/cert/src/rules/MSC50-CPP/DoNotUseRandForGeneratingPseudorandomNumbers-standard.qhelp create mode 100644 cpp/cert/src/rules/MSC50-CPP/DoNotUseRandForGeneratingPseudorandomNumbers.md delete mode 100644 cpp/cert/src/rules/MSC50-CPP/DoNotUseRandForGeneratingPseudorandomNumbers.qhelp delete mode 100644 cpp/cert/src/rules/MSC51-CPP/BadlySeededRandomNumberGenerator-standard.qhelp create mode 100644 cpp/cert/src/rules/MSC51-CPP/BadlySeededRandomNumberGenerator.md delete mode 100644 cpp/cert/src/rules/MSC51-CPP/BadlySeededRandomNumberGenerator.qhelp delete mode 100644 cpp/cert/src/rules/MSC52-CPP/NonVoidFunctionDoesNotReturnCert-standard.qhelp create mode 100644 cpp/cert/src/rules/MSC52-CPP/NonVoidFunctionDoesNotReturnCert.md delete mode 100644 cpp/cert/src/rules/MSC52-CPP/NonVoidFunctionDoesNotReturnCert.qhelp delete mode 100644 cpp/cert/src/rules/MSC53-CPP/FunctionNoReturnAttributeConditionCert-standard.qhelp create mode 100644 cpp/cert/src/rules/MSC53-CPP/FunctionNoReturnAttributeConditionCert.md delete mode 100644 cpp/cert/src/rules/MSC53-CPP/FunctionNoReturnAttributeConditionCert.qhelp delete mode 100644 cpp/cert/src/rules/MSC54-CPP/SignalHandlerMustBeAPlainOldFunction-standard.qhelp create mode 100644 cpp/cert/src/rules/MSC54-CPP/SignalHandlerMustBeAPlainOldFunction.md delete mode 100644 cpp/cert/src/rules/MSC54-CPP/SignalHandlerMustBeAPlainOldFunction.qhelp delete mode 100644 cpp/cert/src/rules/OOP50-CPP/DoNotInvokeVirtualFunctionsFromConstructorsOrDestructors-standard.qhelp create mode 100644 cpp/cert/src/rules/OOP50-CPP/DoNotInvokeVirtualFunctionsFromConstructorsOrDestructors.md delete mode 100644 cpp/cert/src/rules/OOP50-CPP/DoNotInvokeVirtualFunctionsFromConstructorsOrDestructors.qhelp delete mode 100644 cpp/cert/src/rules/OOP51-CPP/DoNotSliceDerivedObjects-standard.qhelp create mode 100644 cpp/cert/src/rules/OOP51-CPP/DoNotSliceDerivedObjects.md delete mode 100644 cpp/cert/src/rules/OOP51-CPP/DoNotSliceDerivedObjects.qhelp delete mode 100644 cpp/cert/src/rules/OOP52-CPP/DoNotDeleteAPolymorphicObjectWithoutAVirtualDestructor-standard.qhelp create mode 100644 cpp/cert/src/rules/OOP52-CPP/DoNotDeleteAPolymorphicObjectWithoutAVirtualDestructor.md delete mode 100644 cpp/cert/src/rules/OOP52-CPP/DoNotDeleteAPolymorphicObjectWithoutAVirtualDestructor.qhelp delete mode 100644 cpp/cert/src/rules/OOP52-CPP/standard-example.cpp delete mode 100644 cpp/cert/src/rules/OOP53-CPP/UseCanonicalOrderForMemberInit-standard.qhelp create mode 100644 cpp/cert/src/rules/OOP53-CPP/UseCanonicalOrderForMemberInit.md delete mode 100644 cpp/cert/src/rules/OOP53-CPP/UseCanonicalOrderForMemberInit.qhelp delete mode 100644 cpp/cert/src/rules/OOP54-CPP/GracefullyHandleSelfCopyAssignment-standard.qhelp create mode 100644 cpp/cert/src/rules/OOP54-CPP/GracefullyHandleSelfCopyAssignment.md delete mode 100644 cpp/cert/src/rules/OOP54-CPP/GracefullyHandleSelfCopyAssignment.qhelp delete mode 100644 cpp/cert/src/rules/OOP55-CPP/MemberAccessWithUninitializedStaticPointerToMember-standard.qhelp create mode 100644 cpp/cert/src/rules/OOP55-CPP/MemberAccessWithUninitializedStaticPointerToMember.md delete mode 100644 cpp/cert/src/rules/OOP55-CPP/MemberAccessWithUninitializedStaticPointerToMember.qhelp delete mode 100644 cpp/cert/src/rules/OOP55-CPP/UseOfPointerToMemberToAccessNonexistentMember-standard.qhelp create mode 100644 cpp/cert/src/rules/OOP55-CPP/UseOfPointerToMemberToAccessNonexistentMember.md delete mode 100644 cpp/cert/src/rules/OOP55-CPP/UseOfPointerToMemberToAccessNonexistentMember.qhelp delete mode 100644 cpp/cert/src/rules/OOP55-CPP/UseOfPointerToMemberToAccessUndefinedMember-standard.qhelp create mode 100644 cpp/cert/src/rules/OOP55-CPP/UseOfPointerToMemberToAccessUndefinedMember.md delete mode 100644 cpp/cert/src/rules/OOP55-CPP/UseOfPointerToMemberToAccessUndefinedMember.qhelp delete mode 100644 cpp/cert/src/rules/OOP55-CPP/standard-example.cpp delete mode 100644 cpp/cert/src/rules/OOP56-CPP/HonorNewReplacementHandlerRequirements-standard.qhelp create mode 100644 cpp/cert/src/rules/OOP56-CPP/HonorNewReplacementHandlerRequirements.md delete mode 100644 cpp/cert/src/rules/OOP56-CPP/HonorNewReplacementHandlerRequirements.qhelp delete mode 100644 cpp/cert/src/rules/OOP56-CPP/HonorTerminationReplacementHandlerRequirements-standard.qhelp create mode 100644 cpp/cert/src/rules/OOP56-CPP/HonorTerminationReplacementHandlerRequirements.md delete mode 100644 cpp/cert/src/rules/OOP56-CPP/HonorTerminationReplacementHandlerRequirements.qhelp delete mode 100644 cpp/cert/src/rules/OOP57-CPP/PreferSpecialMemberFunctionsAndOverloadedOperatorsToCStandardLibraryFunctions-standard.qhelp create mode 100644 cpp/cert/src/rules/OOP57-CPP/PreferSpecialMemberFunctionsAndOverloadedOperatorsToCStandardLibraryFunctions.md delete mode 100644 cpp/cert/src/rules/OOP57-CPP/PreferSpecialMemberFunctionsAndOverloadedOperatorsToCStandardLibraryFunctions.qhelp delete mode 100644 cpp/cert/src/rules/OOP58-CPP/CopyOperationsMustNotMutateTheSourceObject-standard.qhelp create mode 100644 cpp/cert/src/rules/OOP58-CPP/CopyOperationsMustNotMutateTheSourceObject.md delete mode 100644 cpp/cert/src/rules/OOP58-CPP/CopyOperationsMustNotMutateTheSourceObject.qhelp delete mode 100644 cpp/cert/src/rules/STR50-CPP/BasicStringMayNotBeNullTerminatedCert-standard.qhelp create mode 100644 cpp/cert/src/rules/STR50-CPP/BasicStringMayNotBeNullTerminatedCert.md delete mode 100644 cpp/cert/src/rules/STR50-CPP/BasicStringMayNotBeNullTerminatedCert.qhelp delete mode 100644 cpp/cert/src/rules/STR50-CPP/OperationMayNotNullTerminateCStyleStringCert-standard.qhelp create mode 100644 cpp/cert/src/rules/STR50-CPP/OperationMayNotNullTerminateCStyleStringCert.md delete mode 100644 cpp/cert/src/rules/STR50-CPP/OperationMayNotNullTerminateCStyleStringCert.qhelp delete mode 100644 cpp/cert/src/rules/STR51-CPP/DoNotAttemptToCreateAStringFromANullPointer-standard.qhelp create mode 100644 cpp/cert/src/rules/STR51-CPP/DoNotAttemptToCreateAStringFromANullPointer.md delete mode 100644 cpp/cert/src/rules/STR51-CPP/DoNotAttemptToCreateAStringFromANullPointer.qhelp delete mode 100644 cpp/cert/src/rules/STR52-CPP/UseValidReferencesForElementsOfString-standard.qhelp create mode 100644 cpp/cert/src/rules/STR52-CPP/UseValidReferencesForElementsOfString.md delete mode 100644 cpp/cert/src/rules/STR52-CPP/UseValidReferencesForElementsOfString.qhelp delete mode 100644 cpp/cert/src/rules/STR53-CPP/RangeCheckStringElementAccess-standard.qhelp create mode 100644 cpp/cert/src/rules/STR53-CPP/RangeCheckStringElementAccess.md delete mode 100644 cpp/cert/src/rules/STR53-CPP/RangeCheckStringElementAccess.qhelp rename development_handbook.md => docs/development_handbook.md (58%) create mode 100644 scripts/generate_rules/templates/autosar-help.md.template create mode 100644 scripts/generate_rules/templates/cert-c++-help.md.template create mode 100644 scripts/generate_rules/templates/cert-c-help.md.template create mode 100644 scripts/generate_rules/templates/misra-c-2012-help.md.template create mode 100644 scripts/matrix_testing/ExecuteQueryAndDecodeAsJson.ps1 create mode 100644 scripts/shared/codeql.py create mode 100644 scripts/shared/markdown_helpers.py diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 49968618f5..ae14ef5b59 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -20,7 +20,7 @@ _please enter the description of your change here_ ## Release change checklist -A change note ([development_handbook.md#change-notes](https://github.com/github/codeql-coding-standards/blob/main/development_handbook.md#change-notes)) is required for any pull request which modifies: +A change note ([development_handbook.md#change-notes](https://github.com/github/codeql-coding-standards/blob/main/docs/development_handbook.md#change-notes)) is required for any pull request which modifies: - The structure or layout of the release artifacts. - The evaluation performance (memory, execution time) of an existing query. @@ -44,7 +44,7 @@ For PRs that add new queries or modify existing queries, the following checklist - [ ] Have all the relevant rule package description files been checked in? - [ ] Have you verified that the metadata properties of each new query is set appropriately? - [ ] Do all the unit tests contain both "COMPLIANT" and "NON_COMPLIANT" cases? - - [ ] Are the alert messages properly formatted and consistent with the [style guide](https://github.com/github/codeql-coding-standards/blob/main/development_handbook.md#query-style-guide)? + - [ ] Are the alert messages properly formatted and consistent with the [style guide](https://github.com/github/codeql-coding-standards/blob/main/docs/development_handbook.md#query-style-guide)? - [ ] Have you run the queries on OpenPilot and verified that the performance and results are acceptable?
    _As a rule of thumb, predicates specific to the query should take no more than 1 minute, and for simple queries be under 10 seconds. If this is not the case, this should be highlighted and agreed in the code review process._ - [ ] Does the query have an appropriate level of in-query comments/documentation? - [ ] Have you considered/identified possible edge cases? @@ -56,7 +56,7 @@ For PRs that add new queries or modify existing queries, the following checklist - [ ] Have all the relevant rule package description files been checked in? - [ ] Have you verified that the metadata properties of each new query is set appropriately? - [ ] Do all the unit tests contain both "COMPLIANT" and "NON_COMPLIANT" cases? - - [ ] Are the alert messages properly formatted and consistent with the [style guide](https://github.com/github/codeql-coding-standards/blob/main/development_handbook.md#query-style-guide)? + - [ ] Are the alert messages properly formatted and consistent with the [style guide](https://github.com/github/codeql-coding-standards/blob/main/docs/development_handbook.md#query-style-guide)? - [ ] Have you run the queries on OpenPilot and verified that the performance and results are acceptable?
    _As a rule of thumb, predicates specific to the query should take no more than 1 minute, and for simple queries be under 10 seconds. If this is not the case, this should be highlighted and agreed in the code review process._ - [ ] Does the query have an appropriate level of in-query comments/documentation? - [ ] Have you considered/identified possible edge cases? diff --git a/.github/workflows/code-scanning-pack-gen.yml b/.github/workflows/code-scanning-pack-gen.yml index b734cdd5ef..4a122a23fb 100644 --- a/.github/workflows/code-scanning-pack-gen.yml +++ b/.github/workflows/code-scanning-pack-gen.yml @@ -5,13 +5,13 @@ on: branches: - main - "rc/**" - - "c-coding-standards" + - next push: branches: - main - "rc/**" - - "c-coding-standards" + - next env: XARGS_MAX_PROCS: 4 @@ -59,25 +59,23 @@ jobs: codeql-home: ${{ github.workspace }}/codeql_home add-to-path: false - - name: Install latest CodeQL for docs generation - id: install-latest-codeql - uses: ./.github/actions/install-codeql + - name: Install Python + uses: actions/setup-python@v4 with: - add-to-path: false + python-version: "3.9" - name: Anonymising and pre-compiling queries env: CODEQL_HOME: ${{ github.workspace }}/codeql_home - CODEQL_LATEST_HOME: ${{ steps.install-latest-codeql.outputs.codeql-home}} run: | PATH=$PATH:$CODEQL_HOME/codeql pip install -r scripts/requirements.txt - find rule_packages/cpp -name '*.json' -exec basename {} .json \; | xargs --max-procs "$XARGS_MAX_PROCS" --max-args 1 python3 scripts/generate_rules/generate_package_files.py -a cpp - find rule_packages/c -name '*.json' -exec basename {} .json \; | xargs --max-procs "$XARGS_MAX_PROCS" --max-args 1 python3 scripts/generate_rules/generate_package_files.py --skip-shared-test-generation -a c + find rule_packages/cpp -name '*.json' -exec basename {} .json \; | xargs --max-procs "$XARGS_MAX_PROCS" --max-args 1 python scripts/generate_rules/generate_package_files.py -a cpp + find rule_packages/c -name '*.json' -exec basename {} .json \; | xargs --max-procs "$XARGS_MAX_PROCS" --max-args 1 python scripts/generate_rules/generate_package_files.py --skip-shared-test-generation -a c - echo "Generating help markdown file for cert" - $CODEQL_LATEST_HOME/codeql/codeql generate query-help -vvv --format=markdown -o cpp/cert/src/ cpp/cert/src/rules - $CODEQL_LATEST_HOME/codeql/codeql generate query-help -vvv --format=markdown -o c/cert/src/ c/cert/src/rules + echo "Remove help files that cannot be freely distributed" + find cpp/autosar/src/rules -name "*.md" -delete + find c/misra/src/rules -name "*.md" -delete codeql query compile --search-path cpp --threads 0 cpp codeql query compile --search-path c --search-path cpp --threads 0 c @@ -103,12 +101,11 @@ jobs: copy_to_root_name=$(realpath --relative-to "./$2/$1/src/" "$copy_from_root_name") query_dir=$(dirname "lgtm-cpp-query-pack/$copy_to_root_name") mkdir -p "$query_dir" - # Copy each selected ql file, plus the related files (qhelp, qhelp implementation) + # Copy each selected ql file cp "$copy_from_root_name.ql" "lgtm-cpp-query-pack/$copy_to_root_name.ql" - cp "$copy_from_root_name.qhelp" "lgtm-cpp-query-pack/$copy_to_root_name.qhelp" done } - + echo "Copying autosar-default queries (CPP)" copy_queries_for_pack "autosar" "cpp" echo "Copying cert-default queries (CPP)" @@ -186,30 +183,25 @@ jobs: codeql-home: ${{ github.workspace }}/codeql_home add-to-path: false - - name: Install latest CodeQL for docs generation - id: install-latest-codeql - uses: ./.github/actions/install-codeql + - name: Checkout external help files + uses: actions/checkout@v2 with: - add-to-path: false + ssh-key: ${{ secrets.CODEQL_CODING_STANDARDS_HELP_KEY }} + repository: "github/codeql-coding-standards-help" + ref: ${{ github.head_ref }} + path: external-help-files + + - name: Include external help files + run: | + pushd external-help-files + find . -name '*.md' -exec rsync -av --relative {} "$GITHUB_WORKSPACE" \; + popd - name: Pre-compiling queries env: CODEQL_HOME: ${{ github.workspace }}/codeql_home - CODEQL_LATEST_HOME: ${{ steps.install-latest-codeql.outputs.codeql-home}} run: | PATH=$PATH:$CODEQL_HOME/codeql - for s in "autosar" "cert" - do - echo "Generating help markdown file for $s" - $CODEQL_LATEST_HOME/codeql/codeql generate query-help -vvv --format=markdown -o cpp/$s/src/ cpp/$s/src/rules - done - - for s in "misra" "cert" - do - echo "Generating help markdown file for $s" - $CODEQL_LATEST_HOME/codeql/codeql generate query-help -vvv --format=markdown -o c/$s/src/ c/$s/src/rules - done - codeql query compile --search-path cpp --threads 0 cpp codeql query compile --search-path c --search-path cpp --threads 0 c @@ -234,8 +226,8 @@ jobs: do copy_to_root="lgtm-cpp-query-pack/$(realpath --relative-to "./$2/$1/src/" "$rule_dir")" mkdir -p "$copy_to_root" - # Copy each selected ql file, plus the related files (qhelp, qhelp implementation) - find "$rule_dir" -name '*.ql' -o -name '*.qhelp' -o -name '*.c' -name '*.cpp' -o -name '*.png' -exec cp -n {} "$copy_to_root" \; + # Copy each selected ql file, plus the related files + find "$rule_dir" -name '*.ql' -o -name '*.c' -name '*.cpp' -o -name '*.png' -exec cp -n {} "$copy_to_root" \; done } echo "Copying autosar-default queries (CPP)" diff --git a/.github/workflows/codeql_unit_tests.yml b/.github/workflows/codeql_unit_tests.yml index c4e26abc08..1a2374d19d 100644 --- a/.github/workflows/codeql_unit_tests.yml +++ b/.github/workflows/codeql_unit_tests.yml @@ -5,6 +5,7 @@ on: branches: - main - "rc/**" + - next pull_request: branches: - "**" @@ -42,10 +43,10 @@ jobs: - name: Checkout repository uses: actions/checkout@v2 - - name: Setup Python 3 - uses: actions/setup-python@v2 + - name: Install Python + uses: actions/setup-python@v4 with: - python-version: "3.x" + python-version: "3.9" - name: Cache CodeQL id: cache-codeql diff --git a/.github/workflows/create-draft-release.yml b/.github/workflows/create-draft-release.yml index ef4ae708b0..43bf8cac06 100644 --- a/.github/workflows/create-draft-release.yml +++ b/.github/workflows/create-draft-release.yml @@ -41,6 +41,11 @@ jobs: with: fetch-depth: 0 + - name: Install Python + uses: actions/setup-python@v4 + with: + python-version: "3.9" + - name: Install generate_release_notes.py dependencies run: pip install -r scripts/requirements.txt diff --git a/.github/workflows/generate-html-docs.yml b/.github/workflows/generate-html-docs.yml index dda1ae4a47..0142c2feed 100644 --- a/.github/workflows/generate-html-docs.yml +++ b/.github/workflows/generate-html-docs.yml @@ -5,10 +5,12 @@ on: branches: - main - 'rc/**' + - next pull_request: branches: - main - 'rc/**' + - next jobs: generate-html-doc: @@ -18,6 +20,11 @@ jobs: - name: Checkout uses: actions/checkout@v2 + - name: Install Python + uses: actions/setup-python@v4 + with: + python-version: "3.9" + - name: Install generate_iso26262_docs.py dependencies run: pip install -r scripts/requirements.txt diff --git a/.github/workflows/standard_library_upgrade_tests.yml b/.github/workflows/standard_library_upgrade_tests.yml index ac55233a11..0a4e58dbd3 100644 --- a/.github/workflows/standard_library_upgrade_tests.yml +++ b/.github/workflows/standard_library_upgrade_tests.yml @@ -6,6 +6,7 @@ on: branches: - main - "rc/**" + - next paths: - "supported_codeql_configs.json" workflow_dispatch: @@ -155,10 +156,10 @@ jobs: needs: [run-test-suites] runs-on: ubuntu-latest steps: - - name: Setup Python 3 - uses: actions/setup-python@v2 + - name: Install Python + uses: actions/setup-python@v4 with: - python-version: "3.x" + python-version: "3.9" - name: Collect test results uses: actions/download-artifact@v2 diff --git a/.github/workflows/validate-coding-standards.yml b/.github/workflows/validate-coding-standards.yml index 4e1bb0f95b..f7fc7563a1 100644 --- a/.github/workflows/validate-coding-standards.yml +++ b/.github/workflows/validate-coding-standards.yml @@ -4,12 +4,13 @@ on: push: branches: - main - - 'rc/**' + - "rc/**" + - next pull_request: branches: - main - - 'rc/**' - - 'c-coding-standards' + - "rc/**" + - next env: XARGS_MAX_PROCS: 4 @@ -22,6 +23,11 @@ jobs: - name: Checkout uses: actions/checkout@v2 + - name: Install Python + uses: actions/setup-python@v4 + with: + python-version: "3.9" + - name: Install generate_package_files.py dependencies run: pip install -r scripts/requirements.txt @@ -43,19 +49,18 @@ jobs: - name: Validate Package Files (CPP) run: | - find rule_packages/cpp -name \*.json -exec basename {} .json \; | xargs --max-procs "$XARGS_MAX_PROCS" --max-args 1 python3 scripts/generate_rules/generate_package_files.py cpp + find rule_packages/cpp -name \*.json -exec basename {} .json \; | xargs --max-procs "$XARGS_MAX_PROCS" --max-args 1 python scripts/generate_rules/generate_package_files.py cpp git diff git diff --compact-summary git diff --quiet - name: Validate Package Files (C) run: | - find rule_packages/c -name \*.json -exec basename {} .json \; | xargs --max-procs "$XARGS_MAX_PROCS" --max-args 1 python3 scripts/generate_rules/generate_package_files.py c + find rule_packages/c -name \*.json -exec basename {} .json \; | xargs --max-procs "$XARGS_MAX_PROCS" --max-args 1 python scripts/generate_rules/generate_package_files.py c git diff git diff --compact-summary git diff --quiet - validate-codeql-format: name: "Validate CodeQL Format" runs-on: ubuntu-latest @@ -90,41 +95,37 @@ jobs: validate-query-help-files: name: Validate Query Help Files runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - language: ['cpp', 'c'] steps: - name: Checkout uses: actions/checkout@v2 - - name: Fetch CodeQL + - name: Validate CPP Query Help Files run: | - gh release download --repo https://github.com/github/codeql-cli-binaries --pattern codeql-linux64.zip - unzip -q codeql-linux64.zip - env: - GITHUB_TOKEN: ${{ github.token }} + exit_code=0 + for help_file in `find cpp -name '*.md'` + do + if grep -F -q 'REPLACE THIS' "$help_file" > /dev/null + then + echo "Help file $help_file contains placeholders that are not replaced or removed!" + exit_code=1 + fi + done + + exit $exit_code - - name: Validate Query Help Files + - name: Validate C Query Help Files run: | - qhelp_output=$(( codeql/codeql generate query-help --format=markdown --output=${{ matrix.language }}/qhelp-markdown-dump ${{ matrix.language }} ) 2>&1 ) - qhelp_count=$(find ${{ matrix.language }} -name \*.ql -or -name \*.qhelp | wc -l) - - if [[ $qhelp_output ]]; then - errors=$( echo "$qhelp_output" | grep -v '/test/' || [[ $? == 1 ]] ) - if [[ $errors ]]; then - echo "There are errors with the qhelp files: " - echo "$errors" - exit 1 - else - echo "Disregarding tests..." - echo "Query help files look good." + exit_code=0 + for help_file in `find c -name '*.md'` + do + if grep -F -q 'REPLACE THIS' "$help_file" > /dev/null + then + echo "Help file $help_file contains placeholders that are not replaced or removed!" + exit_code=1 fi - elif [[ ! $qhelp_output && qhelp_count -gt 0 ]]; then - echo "Query help files look good." - else - echo "There are no query help files to analyze." - fi + done + + exit $exit_code validate-cpp-test-files: name: Validate C++ Test Files @@ -143,7 +144,7 @@ jobs: if ! test -f .clang-format; then echo "Cannot find .clang-format in '$PWD'. Exiting..." fi - + find cpp/*/test -name \*.cpp -print0 | xargs -0 --max-procs "$XARGS_MAX_PROCS" clang-format --style=file -i --verbose git diff git diff --compact-summary @@ -166,7 +167,7 @@ jobs: if ! test -f .clang-format; then echo "Cannot find .clang-format in '$PWD'. Exiting..." fi - + find c/*/test -name \*.c -print0 | xargs -0 --max-procs "$XARGS_MAX_PROCS" clang-format --style=file -i --verbose git diff git diff --compact-summary diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000..1d74b7bef7 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,126 @@ +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, religion, or sexual identity +and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the + overall community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or + advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email + address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +opensource@github.com. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series +of actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or +permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within +the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.0, available at +https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. + +Community Impact Guidelines were inspired by [Mozilla's code of conduct +enforcement ladder](https://github.com/mozilla/diversity). + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see the FAQ at +https://www.contributor-covenant.org/faq. Translations are available at +https://www.contributor-covenant.org/translations. \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000..25c919d090 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,55 @@ +## Contributing + +[fork]: https://github.com/github/REPO/fork +[pr]: https://github.com/github/REPO/compare +[style]: https://github.com/styleguide/ruby +[code-of-conduct]: CODE_OF_CONDUCT.md + +Hi there! We're thrilled that you'd like to contribute to this project. Your help is essential for keeping it great. + +Contributions to this project are [released](https://help.github.com/articles/github-terms-of-service/#6-contributions-under-repository-license) to the public under the [project's open source license](LICENSE.md). + +Please note that this project is released with a [Contributor Code of Conduct](CODE_OF_CONDUCT.md). By participating in this project you agree to abide by its terms. + +## Scope + +The CodeQL Coding Standards project **only** considers external contributions that improve an existing query. +Proposals for additional standards or guidelines are out of scope for this project. + +If you are interested in adding a query that is outside the scope of this project then consider contributing to the [CodeQL standard library and queries](https://github.com/github/codeql). + +## First step in contributing + +The CodeQL Coding Standards is subject to strict software development processes in accordance with the ISO 26262 standard. +For more information on the tool qualification process refer to our [tool qualification document](docs/iso_26262_tool_qualification.md). + +To ensure the that we adhere to the requirements we must first start with an [issue](https://github.com/github/codeql-coding-standards/issues/new/choose) to register and discuss the proposed improvement. + +## Submitting a pull request + +The next step, after registering and discussing your improvement, is proposing the improvement in a pull request. + +1. [Fork](fork) and clone the repository +2. Configure and install the [CodeQL CLI](https://github.com/github/codeql-cli-binaries/releases) specified in the `supported_codeql_configs.json` and [ClangFormat](https://clang.llvm.org/docs/ClangFormat.html) +3. Create a new branch: `git checkout -b my-branch-name` +4. Make your change according to process described in the [development handbook](docs/development_handbook.md) +5. Ensure the files are appropriately formatted. + - QL files should be formatted with `codeql query format` + - C/C++ files should be formatted with `clang-format` using the format specification [.clang-format](.clang-format) +6. Push to your fork and [submit a draft pull request](https://github.com/github/codeql-coding-standards/compare). Make sure to select **Create Draft Pull Request**. +7. Address failed checks, if any. +8. Mark the [pull request ready for review](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/changing-the-stage-of-a-pull-request#marking-a-pull-request-as-ready-for-review). +9. Pat your self on the back and wait for your pull request to be reviewed and merged. + +Here are a few things you can do that will increase the likelihood of your pull request being accepted: + +- Follow the [development handbook](docs/development_handbook.md). +- Ensure all PR checks succeed. +- Keep your change as focused as possible. If there are multiple changes you would like to make that are not dependent upon each other, consider submitting them as separate pull requests. +- Write a [good commit message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html). + +## Resources + +- [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/) +- [Using Pull Requests](https://help.github.com/articles/about-pull-requests/) +- [GitHub Help](https://help.github.com) diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000000..32c3074c05 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 GitHub + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index 564e8d552a..f4edcb2254 100644 --- a/README.md +++ b/README.md @@ -4,22 +4,43 @@ This repository contains CodeQL queries and libraries which support various Codi ## Supported standards -This repository includes queries which support the following standards: - - SEI CERT® C++ Coding Standard1. +Carnegie Mellon and CERT are registered trademarks of Carnegie Mellon University. +This repository contains CodeQL queries and libraries which support various Coding Standards for the [C++14](https://www.iso.org/standard/64029.html) programming language. + +The following coding standards are included: +- [AUTOSAR - Guidelines for the use of C++14 language in critical and safety-related systems Release 18-10](https://www.autosar.org/fileadmin/user_upload/standards/adaptive/18-10/AUTOSAR_RS_CPP14Guidelines.pdf) +- [MISRA C++:2008](https://www.misra.org.uk) +- [SEI CERT C++ Coding Standard: Rules for Developing Safe, Reliable, and Secure Systems (2016 Edition)](https://resources.sei.cmu.edu/library/asset-view.cfm?assetID=494932) + +## How do I use the CodeQL Coding Standards Queries? + +The use of the CodeQL Coding Standards is extensively documented in the [user manual](docs/user_manual.md). + +### Use in a functional safety environment + +The CodeQL Coding Standards is qualified as a "software tool" under "Part 8: Supporting processes" of ISO 26262 ("Road vehicles - Functional Safety") as described in our [tool qualification documents](docs/iso_26262_tool_qualification.md). +Use of the CodeQL Coding Standards is only compliant with the qualification if it is used as distributed by GitHub and according to the requirements described in the [user manual](docs/user_manual.md). + +Any changes to the CodeQL Coding Standards distribution and/or deviations from the requirements and steps described in the [user manual](docs/user_manual.md) runs the risk of non compliance. + + +## Contributing + +We welcome contributions to our standard library and standard checks. Do you have an idea for a new check, or how to improve an existing query? Then please go ahead and open a pull request! Before you do, though, please take the time to read our [contributing guidelines](CONTRIBUTING.md). You can also consult our [development handbook](docs/development_handbook.md) to learn about the requirements for a contribution. ## License -Unless otherwise noted below, the code in this repository is licensed under the [MIT License](LICENSE) by [GitHub](https://github.com). +Unless otherwise noted below, the code in this repository is licensed under the [MIT License](LICENSE.md) by [GitHub](https://github.com). -Parts of certain query help files (`.qhelp` extension) are reproduced under the following licenses: +Parts of certain query help files (`.md` extension) are reproduced under the following licenses: - [SEI CERT® Coding Standards](thirdparty/cert/LICENSE) (_reproduced as of 15th March 2021_). These licenses are directly referenced where applicable. -All code in the `thirdparty` directory is licensed according to the files present in those sub directories. +All code in the [thirdparty](./thirdparty) directory is licensed according to the files present in those sub directories. + +All header files in [c/common/test/includes/standard-library](./c/common/test/includes/standard-library) are licensed according to [LICENSE](c/common/test/includes/standard-library/LICENSE) --- 1This repository incorporates portions of the SEI CERT® Coding Standards available at https://wiki.sei.cmu.edu/confluence/display/seccode/SEI+CERT+Coding+Standards; however, such use does not necessarily constitute or imply an endorsement, recommendation, or favoring by Carnegie Mellon University or its Software Engineering Institute. - -Carnegie Mellon and CERT are registered trademarks of Carnegie Mellon University. \ No newline at end of file diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000000..fc3f6d19ad --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,3 @@ +If you discover a security issue in this repo, please submit it through the [GitHub Security Bug Bounty](https://hackerone.com/github) + +Thanks for helping make GitHub Actions safe for everyone. \ No newline at end of file diff --git a/c/cert/src/qlpack.yml b/c/cert/src/qlpack.yml index 2feb43f3b8..910d4d2636 100644 --- a/c/cert/src/qlpack.yml +++ b/c/cert/src/qlpack.yml @@ -1,4 +1,4 @@ name: cert-c-coding-standards -version: 2.5.0 +version: 2.6.0-dev suites: codeql-suites libraryPathDependencies: common-c-coding-standards \ No newline at end of file diff --git a/c/cert/src/rules/CON32-C/PreventDataRacesWithMultipleThreads-standard.qhelp b/c/cert/src/rules/CON32-C/PreventDataRacesWithMultipleThreads-standard.qhelp deleted file mode 100644 index 458fbe3f7d..0000000000 --- a/c/cert/src/rules/CON32-C/PreventDataRacesWithMultipleThreads-standard.qhelp +++ /dev/null @@ -1,33 +0,0 @@ - - -
    -
      -
    • required
    • -
    • implementation
    • -
    • automated
    • -
    -
    - -
    -

    - ... -

    - -
    - -
    -

    - ... -

    -
    - - - - - -
    -
      -
    • ...
    • -
    -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/CON32-C/PreventDataRacesWithMultipleThreads.md b/c/cert/src/rules/CON32-C/PreventDataRacesWithMultipleThreads.md new file mode 100644 index 0000000000..8ff7750348 --- /dev/null +++ b/c/cert/src/rules/CON32-C/PreventDataRacesWithMultipleThreads.md @@ -0,0 +1,156 @@ +# CON32-C: Prevent data races when accessing bit-fields from multiple threads + +This query implements the CERT-C rule CON32-C: + +> Prevent data races when accessing bit-fields from multiple threads + + +## Description + +When accessing a bit-field, a thread may inadvertently access a separate bit-field in adjacent memory. This is because compilers are required to store multiple adjacent bit-fields in one storage unit whenever they fit. Consequently, data races may exist not just on a bit-field accessed by multiple threads but also on other bit-fields sharing the same byte or word. A similar problem is discussed in [CON43-C. Do not allow data races in multithreaded code](https://wiki.sei.cmu.edu/confluence/display/c/CON43-C.+Do+not+allow+data+races+in+multithreaded+code), but the issue described by this rule can be harder to diagnose because it may not be obvious that the same memory location is being modified by multiple threads. + +One approach for preventing data races in concurrent programming is to use a mutex. When properly observed by all threads, a mutex can provide safe and secure access to a shared object. However, mutexes provide no guarantees with regard to other objects that might be accessed when the mutex is not controlled by the accessing thread. Unfortunately, there is no portable way to determine which adjacent bit-fields may be stored along with the desired bit-field. + +Another approach is to insert a non-bit-field member between any two bit-fields to ensure that each bit-field is the only one accessed within its storage unit. This technique effectively guarantees that no two bit-fields are accessed simultaneously. + +## Noncompliant Code Example (Bit-field) + +Adjacent bit-fields may be stored in a single memory location. Consequently, modifying adjacent bit-fields in different threads is [undefined behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior), as shown in this noncompliant code example: + +```cpp +struct multi_threaded_flags { + unsigned int flag1 : 2; + unsigned int flag2 : 2; +}; + +struct multi_threaded_flags flags; + +int thread1(void *arg) { + flags.flag1 = 1; + return 0; +} + +int thread2(void *arg) { + flags.flag2 = 2; + return 0; +} + +``` +The C Standard, 3.14, paragraph 3 \[[ISO/IEC 9899:2011](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO-IEC9899-2011)\], states + +> NOTE 2 A bit-field and an adjacent non-bit-field member are in separate memory locations. The same applies to two bit-fields, if one is declared inside a nested structure declaration and the other is not, or if the two are separated by a zero-length bit-field declaration, or if they are separated by a non-bit-field member declaration. It is not safe to concurrently update two non-atomic bit-fields in the same structure if all members declared between them are also (non-zero-length) bit-fields, no matter what the sizes of those intervening bit-fields happen to be. + + +For example, the following instruction sequence is possible: + +```cpp +Thread 1: register 0 = flags +Thread 1: register 0 &= ~mask(flag1) +Thread 2: register 0 = flags +Thread 2: register 0 &= ~mask(flag2) +Thread 1: register 0 |= 1 << shift(flag1) +Thread 1: flags = register 0 +Thread 2: register 0 |= 2 << shift(flag2) +Thread 2: flags = register 0 +``` + +## Compliant Solution (Bit-field, C11, Mutex) + +This compliant solution protects all accesses of the flags with a mutex, thereby preventing any data races: + +```cpp +#include + +struct multi_threaded_flags { + unsigned int flag1 : 2; + unsigned int flag2 : 2; +}; + +struct mtf_mutex { + struct multi_threaded_flags s; + mtx_t mutex; +}; + +struct mtf_mutex flags; + +int thread1(void *arg) { + if (thrd_success != mtx_lock(&flags.mutex)) { + /* Handle error */ + } + flags.s.flag1 = 1; + if (thrd_success != mtx_unlock(&flags.mutex)) { + /* Handle error */ + } + return 0; +} + +int thread2(void *arg) { + if (thrd_success != mtx_lock(&flags.mutex)) { + /* Handle error */ + } + flags.s.flag2 = 2; + if (thrd_success != mtx_unlock(&flags.mutex)) { + /* Handle error */ + } + return 0; +} + +``` + +## Compliant Solution (C11) + +In this compliant solution, two threads simultaneously modify two distinct non-bit-field members of a structure. Because the members occupy different bytes in memory, no concurrency protection is required. + +```cpp +struct multi_threaded_flags { + unsigned char flag1; + unsigned char flag2; +}; + +struct multi_threaded_flags flags; + +int thread1(void *arg) { + flags.flag1 = 1; + return 0; +} + +int thread2(void *arg) { + flags.flag2 = 2; + return 0; +} +``` +Unlike C99, C11 explicitly defines a memory location and provides the following note in subclause 3.14.2 \[[ISO/IEC 9899:2011](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO-IEC9899-2011)\]: + +> NOTE 1 Two threads of execution can update and access separate memory locations without interfering with each other. + + +It is almost certain that `flag1` and `flag2` are stored in the same word. Using a compiler that conforms to C99 or earlier, if both assignments occur on a thread-scheduling interleaving that ends with both stores occurring after one another, it is possible that only one of the flags will be set as intended. The other flag will contain its previous value because both members are represented by the same word, which is the smallest unit the processor can work on. Before the changes were made to the C Standard for C11, there were no guarantees that these flags could be modified concurrently. + +## Risk Assessment + +Although the race window is narrow, an assignment or an expression can evaluate improperly because of misinterpreted data resulting in a corrupted running state or unintended information disclosure. + +
    Rule Severity Likelihood Remediation Cost Priority Level
    CON32-C Medium Probable Medium P8 L2
    + + +## Automated Detection + +
    Tool Version Checker Description
    Astrée 22.04 read_data_race write_data_race Supported by sound analysis (data race alarm)
    Axivion Bauhaus Suite 7.2.0 CertC-CON32
    CodeSonar 7.0p0 CONCURRENCY.DATARACECONCURRENCY.MAA Data race Multiple Accesses of Atomic
    Coverity 2017.07 MISSING_LOCK Partially implemented
    Helix QAC 2022.2 C1774, C1775
    Parasoft C/C++test 2022.1 CERT_C-CON32-a Use locks to prevent race conditions when modifying bit fields
    PC-lint Plus 1.4 457 Partially supported: access is detected at the object level (not at the field level)
    Polyspace Bug Finder R2022a CERT C: Rule CON32-C Checks for data race (rule fully covered)
    PRQA QA-C 9.7 1774, 1775 Enforced by MTA
    + + +## Related Vulnerabilities + +Search for [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) resulting from the violation of this rule on the [CERT website](https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+CON32-C). + +## Bibliography + +
    \[ ISO/IEC 9899:2011 \] 3.14, "Memory Location"
    + + +## Implementation notes + +None + +## References + +* CERT-C: [CON32-C: Prevent data races when accessing bit-fields from multiple threads](https://wiki.sei.cmu.edu/confluence/display/c) diff --git a/c/cert/src/rules/CON32-C/PreventDataRacesWithMultipleThreads.qhelp b/c/cert/src/rules/CON32-C/PreventDataRacesWithMultipleThreads.qhelp deleted file mode 100644 index 3100741c68..0000000000 --- a/c/cert/src/rules/CON32-C/PreventDataRacesWithMultipleThreads.qhelp +++ /dev/null @@ -1,18 +0,0 @@ - - - - -

    This query implements the CERT-C rule CON32-C:

    -
    -

    Prevent data races when accessing bit-fields from multiple threads

    -
    -
    - - -
  • - CERT-C: - CON32-C: Prevent data races when accessing bit-fields from multiple threads - . -
  • -
    - \ No newline at end of file diff --git a/c/cert/src/rules/CON32-C/standard-example.c b/c/cert/src/rules/CON32-C/standard-example.c deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/c/cert/src/rules/CON33-C/RaceConditionsWhenUsingLibraryFunctions-standard.qhelp b/c/cert/src/rules/CON33-C/RaceConditionsWhenUsingLibraryFunctions-standard.qhelp deleted file mode 100644 index 458fbe3f7d..0000000000 --- a/c/cert/src/rules/CON33-C/RaceConditionsWhenUsingLibraryFunctions-standard.qhelp +++ /dev/null @@ -1,33 +0,0 @@ - - -
    -
      -
    • required
    • -
    • implementation
    • -
    • automated
    • -
    -
    - -
    -

    - ... -

    - -
    - -
    -

    - ... -

    -
    - - - - - -
    -
      -
    • ...
    • -
    -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/CON33-C/RaceConditionsWhenUsingLibraryFunctions.md b/c/cert/src/rules/CON33-C/RaceConditionsWhenUsingLibraryFunctions.md new file mode 100644 index 0000000000..542f5390fe --- /dev/null +++ b/c/cert/src/rules/CON33-C/RaceConditionsWhenUsingLibraryFunctions.md @@ -0,0 +1,159 @@ +# CON33-C: Avoid race conditions when using library functions + +This query implements the CERT-C rule CON33-C: + +> Avoid race conditions when using library functions + + +## Description + +Some C standard library functions are not guaranteed to be [reentrant](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-reentrant) with respect to threads. Functions such as `strtok()` and `asctime()` return a pointer to the result stored in function-allocated memory on a per-process basis. Other functions such as `rand()` store state information in function-allocated memory on a per-process basis. Multiple threads invoking the same function can cause concurrency problems, which often result in abnormal behavior and can cause more serious [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability), such as [abnormal termination](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-abnormaltermination), [denial-of-service attack](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-denial-of-service), and data integrity violations. + +According to the C Standard, the library functions listed in the following table may contain data races when invoked by multiple threads. + +
    Functions Remediation
    rand() , srand() MSC30-C. Do not use the rand() function for generating pseudorandom numbers
    getenv() , getenv_s() ENV34-C. Do not store pointers returned by certain functions
    strtok() strtok_s() in C11 Annex K strtok_r() in POSIX
    strerror() strerror_s() in C11 Annex K strerror_r() in POSIX
    asctime() , ctime() , localtime() , gmtime() asctime_s() , ctime_s() , localtime_s() , gmtime_s() in C11 Annex K
    setlocale() Protect multithreaded access to locale-specific functions with a mutex
    ATOMIC_VAR_INIT , atomic_init() Do not attempt to initialize an atomic variable from multiple threads
    tmpnam() tmpnam_s() in C11 Annex K tmpnam_r() in POSIX
    mbrtoc16() , c16rtomb() , mbrtoc32() , c32rtomb() Do not call with a null mbstate_t \* argument
    +Section 2.9.1 of the *Portable Operating System Interface (POSIX®), Base Specifications, Issue 7* \[[IEEE Std 1003.1:2013](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-IEEEStd1003.1-2013)\] extends the list of functions that are not required to be thread-safe. + + +## Noncompliant Code Example + +In this noncompliant code example, the function `f()` is called from within a multithreaded application but encounters an error while calling a system function. The `strerror()` function returns a human-readable error string given an error number. The C Standard, 7.24.6.2 \[[ISO/IEC 9899:2011](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO-IEC9899-2011)\], specifically states that `strerror()` is not required to avoid data races. An [implementation](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-implementation) could write the error string into a static array and return a pointer to it, and that array might be accessible and modifiable by other threads. + +```cpp +#include +#include +#include + +void f(FILE *fp) { + fpos_t pos; + errno = 0; + + if (0 != fgetpos(fp, &pos)) { + char *errmsg = strerror(errno); + printf("Could not get the file position: %s\n", errmsg); + } +} +``` +This code first sets `errno` to 0 to comply with [ERR30-C. Take care when reading errno](https://wiki.sei.cmu.edu/confluence/display/c/ERR30-C.+Take+care+when+reading+errno). + +## Compliant Solution (Annex K, strerror_s()) + +This compliant solution uses the `strerror_s()` function from Annex K of the C Standard, which has the same functionality as `strerror()` but guarantees thread-safety: + +```cpp +#define __STDC_WANT_LIB_EXT1__ 1 +#include +#include +#include +  +enum { BUFFERSIZE = 64 }; +void f(FILE *fp) { + fpos_t pos; + errno = 0; + + if (0 != fgetpos(fp, &pos)) { + char errmsg[BUFFERSIZE]; + if (strerror_s(errmsg, BUFFERSIZE, errno) != 0) { + /* Handle error */ + } + printf("Could not get the file position: %s\n", errmsg); + } +} +``` +Because Annex K is optional, `strerror_s()` may not be available in all implementations.  + +## Compliant Solution (POSIX, strerror_r()) + +This compliant solution uses the POSIX `strerror_r()` function, which has the same functionality as `strerror()` but guarantees thread safety: + +```cpp +#include +#include +#include + +enum { BUFFERSIZE = 64 }; +  +void f(FILE *fp) { + fpos_t pos; + errno = 0; + + if (0 != fgetpos(fp, &pos)) { + char errmsg[BUFFERSIZE]; + if (strerror_r(errno, errmsg, BUFFERSIZE) != 0) { + /* Handle error */ + } + printf("Could not get the file position: %s\n", errmsg); + } +} +``` +Linux provides two versions of `strerror_r()`, known as the *XSI-compliant version* and the *GNU-specific version*. This compliant solution assumes the XSI-compliant version, which is the default when an application is compiled as required by POSIX (that is, by defining `_POSIX_C_SOURCE` or `_XOPEN_SOURCE` appropriately). The` strerror_r()` manual page lists versions that are available on a particular system. + +## Risk Assessment + +Race conditions caused by multiple threads invoking the same library function can lead to [abnormal termination](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-abnormaltermination) of the application, data integrity violations, or a [denial-of-service attack](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-denial-of-service). + +
    Rule Severity Likelihood Remediation Cost Priority Level
    CON33-C Medium Probable High P4 L3
    + + +## Related Vulnerabilities + +Search for [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) resulting from the violation of this rule on the [CERT website](https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+CON33-C). + +## Automated Detection + +
    Tool Version Checker Description
    Astrée 22.04 Supported, but no explicit checker
    CodeSonar 7.0p0 BADFUNC.RANDOM.RAND BADFUNC.TEMP.TMPNAM BADFUNC.TTYNAME Use of rand (includes check for uses of srand() ) Use of tmpnam (includes check for uses of tmpnam_r() ) Use of ttyname
    Compass/ROSE A module written in Compass/ROSE can detect violations of this rule
    Helix QAC 2022.2 C4976, C4977,C5037 C++4976, C++4977, C++5021
    Klocwork 2022.2 CERT.CONC.LIB_FUNC_USE
    LDRA tool suite 9.7.1 44 S Partially Implemented
    Parasoft C/C++test 2022.1 CERT_C-CON33-a Avoid using thread-unsafe functions
    PC-lint Plus 1.4 586 Fully supported
    Polyspace Bug Finder R2022a CERT C: Rule CON33-C Checks for data race through standard library function call (rule fully covered)
    PRQA QA-C 9.7 5037, 4976, 4977
    PRQA QA-C++ 4.4 4976, 4977, 5021
    + + +## Related Guidelines + +[Key here](https://wiki.sei.cmu.edu/confluence/display/c/How+this+Coding+Standard+is+Organized#HowthisCodingStandardisOrganized-RelatedGuidelines) (explains table format and definitions) + +
    Taxonomy Taxonomy item Relationship
    CERT C Secure Coding Standard ERR30-C. Set errno to zero before calling a library function known to set errno, and check errno only after the function returns a value indicating failure Prior to 2018-01-12: CERT: Unspecified Relationship
    CERT C CON00-CPP. Avoid assuming functions are thread safe unless otherwise specified Prior to 2018-01-12: CERT: Unspecified Relationship
    CWE 2.11 CWE-330 2017-06-28: CERT: Partial overlap
    CWE 2.11 CWE-377 2017-06-28: CERT: Partial overlap
    CWE 2.11 CWE-676 2017-05-18: CERT: Rule subset of CWE
    + + +## CERT-CWE Mapping Notes + +[Key here](https://wiki.sei.cmu.edu/confluence/pages/viewpage.action?pageId=87152408#HowthisCodingStandardisOrganized-CERT-CWEMappingNotes) for mapping notes + +**CWE-330 and CON33-C** + +Independent( MSC30-C, MSC32-C, CON33-C) + +Intersection( CWE-330, CON33-C) = + +* Use of rand() or srand() from multiple threads, introducing a race condition. +CWE-330 – CON33-C = +* Use of rand() or srand() without introducing race conditions +* Use of other dangerous functions +CON33-C – CWE-330 = +* Use of other global functions (besides rand() and srand()) introducing race conditions +**CWE-377 and CON33-C** + +Intersection( CWE-377, CON33-C) = + +* Use of tmpnam() from multiple threads, introducing a race condition. +CWE-377 – CON33-C = +* Insecure usage of tmpnam() without introducing race conditions +* Insecure usage of other functions for creating temporary files (see CERT recommendation FIO21-C for details) +CON33-C – CWE-377 = +* Use of other global functions (besides tmpnam()) introducing race conditions +**CWE-676 and CON33-C** +* Independent( ENV33-C, CON33-C, STR31-C, EXP33-C, MSC30-C, ERR34-C) +* CON33-C lists standard C library functions that manipulate global data (e.g., locale()), that can be dangerous to use in a multithreaded context. +* CWE-676 = Union( CON33-C, list) where list = +* Invocation of the following functions without introducing a race condition: +* rand(), srand(, getenv(), getenv_s(), strtok(), strerror(), asctime(), ctime(), localtime(), gmtime(), setlocale(), ATOMIC_VAR_INIT, atomic_init(), tmpnam(), mbrtoc16(), c16rtomb(), mbrtoc32(), c32rtomb() +* Invocation of other dangerous functions + +## Bibliography + +
    \[ IEEE Std 1003.1:2013 \] Section 2.9.1, "Thread Safety"
    \[ ISO/IEC 9899:2011 \] Subclause 7.24.6.2, "The strerror Function"
    \[ Open Group 1997b \] Section 10.12, "Thread-Safe POSIX.1 and C-Language Functions"
    + + +## Implementation notes + +None + +## References + +* CERT-C: [CON33-C: Avoid race conditions when using library functions](https://wiki.sei.cmu.edu/confluence/display/c) diff --git a/c/cert/src/rules/CON33-C/RaceConditionsWhenUsingLibraryFunctions.qhelp b/c/cert/src/rules/CON33-C/RaceConditionsWhenUsingLibraryFunctions.qhelp deleted file mode 100644 index e15b789b7d..0000000000 --- a/c/cert/src/rules/CON33-C/RaceConditionsWhenUsingLibraryFunctions.qhelp +++ /dev/null @@ -1,18 +0,0 @@ - - - - -

    This query implements the CERT-C rule CON33-C:

    -
    -

    Avoid race conditions when using library functions

    -
    -
    - - -
  • - CERT-C: - CON33-C: Avoid race conditions when using library functions - . -
  • -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/CON33-C/standard-example.c b/c/cert/src/rules/CON33-C/standard-example.c deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/c/cert/src/rules/CON37-C/DoNotCallSignalInMultithreadedProgram-standard.qhelp b/c/cert/src/rules/CON37-C/DoNotCallSignalInMultithreadedProgram-standard.qhelp deleted file mode 100644 index 458fbe3f7d..0000000000 --- a/c/cert/src/rules/CON37-C/DoNotCallSignalInMultithreadedProgram-standard.qhelp +++ /dev/null @@ -1,33 +0,0 @@ - - -
    -
      -
    • required
    • -
    • implementation
    • -
    • automated
    • -
    -
    - -
    -

    - ... -

    - -
    - -
    -

    - ... -

    -
    - - - - - -
    -
      -
    • ...
    • -
    -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/CON37-C/DoNotCallSignalInMultithreadedProgram.md b/c/cert/src/rules/CON37-C/DoNotCallSignalInMultithreadedProgram.md new file mode 100644 index 0000000000..5cf6747dff --- /dev/null +++ b/c/cert/src/rules/CON37-C/DoNotCallSignalInMultithreadedProgram.md @@ -0,0 +1,110 @@ +# CON37-C: Do not call signal() in a multithreaded program + +This query implements the CERT-C rule CON37-C: + +> Do not call signal() in a multithreaded program + + +## Description + +Calling the `signal()` function in a multithreaded program is [undefined behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior). (See [undefined behavior 135](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_135).) + +## Noncompliant Code Example + +This noncompliant code example invokes the `signal()` function from a multithreaded program: + +```cpp +#include +#include +#include + +volatile sig_atomic_t flag = 0; + +void handler(int signum) { + flag = 1; +} + +/* Runs until user sends SIGUSR1 */ +int func(void *data) { + while (!flag) { + /* ... */ + } + return 0; +} + +int main(void) { + signal(SIGUSR1, handler); /* Undefined behavior */ + thrd_t tid; + + if (thrd_success != thrd_create(&tid, func, NULL)) { + /* Handle error */ + } + /* ... */ + return 0; +} +``` +NOTE: The `SIGUSR1` signal value is not defined in the C Standard; consequently, this is not a C-compliant code example. + +## Compliant Solution + +This compliant solution uses an object of type `atomic_bool` to indicate when the child thread should terminate its loop: + +```cpp +#include +#include +#include +#include + +atomic_bool flag = ATOMIC_VAR_INIT(false); + +int func(void *data) { + while (!flag) { + /* ... */ + } + return 0; +} + +int main(void) { + thrd_t tid; + + if (thrd_success != thrd_create(&tid, func, NULL)) { + /* Handle error */ + } + /* ... */ + /* Set flag when done */ + flag = true; + + return 0; +} +``` + +## Exceptions + +**CON37-C-EX1:** Implementations such as POSIX that provide defined behavior when multithreaded programs use custom signal handlers are exempt from this rule \[[IEEE Std 1003.1-2013](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-IEEEStd1003.1-2013)\]. + +## Risk Assessment + +Mixing signals and threads causes [undefined behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior). + +
    Rule Severity Likelihood Remediation Cost Priority Level
    CON37-C Low Probable Low P6 L2
    + + +## Related Vulnerabilities + +Search for [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) resulting from the violation of this rule on the [CERT website](https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+CON37-C). + +## Automated Detection + +
    Tool Version Checker Description
    Astrée 22.04 stdlib-use-signal Fully checked
    CodeSonar 7.0p0 BADFUNC.SIGNAL Use of signal
    Coverity 2017.07 MISRA C 2012 Rule 21.5 Over-constraining
    Helix QAC 2022.2 C5021 C++5022
    Klocwork 2022.2 MISRA.STDLIB.SIGNAL
    LDRA tool suite 9.7.1 44 S Enhanced enforcement
    Parasoft C/C++test 2022.1 CERT_C-CON37-a The signal handling facilities of <signal.h> shall not be used
    PC-lint Plus 1.4 586 Fully supported
    Polyspace Bug Finder R2022a CERT C: Rule CON37-C Checks for signal call in multithreaded program (rule fully covered)
    RuleChecker 22.04 stdlib-use-signal Fully checked
    PRQA QA-C 9.7 5021
    PRQA QA-C++ 4.4 5022
    + + +## Bibliography + +
    \[ IEEE Std 1003.1-2013 \] XSH 2.9.1, "Thread Safety"
    + + +## Implementation notes + +## References + +* CERT-C: [CON37-C: Do not call signal() in a multithreaded program](https://wiki.sei.cmu.edu/confluence/display/c) diff --git a/c/cert/src/rules/CON37-C/DoNotCallSignalInMultithreadedProgram.qhelp b/c/cert/src/rules/CON37-C/DoNotCallSignalInMultithreadedProgram.qhelp deleted file mode 100644 index 3aa2f3347e..0000000000 --- a/c/cert/src/rules/CON37-C/DoNotCallSignalInMultithreadedProgram.qhelp +++ /dev/null @@ -1,21 +0,0 @@ - - - - -

    This query implements the CERT-C rule CON37-C:

    -
    -

    Do not call signal() in a multithreaded program

    -
    -
    - -
    -

    -
    - -
  • - CERT-C: - CON37-C: Do not call signal() in a multithreaded program - . -
  • -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/CON37-C/standard-example.c b/c/cert/src/rules/CON37-C/standard-example.c deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects-standard.qhelp b/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects-standard.qhelp deleted file mode 100644 index 628d8290fb..0000000000 --- a/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects-standard.qhelp +++ /dev/null @@ -1,679 +0,0 @@ - - -
    -

    Evaluation of an expression may produce side effects. At specific points during execution, known as sequence points, all side effects of previous evaluations are complete, and no side effects of subsequent evaluations have yet taken place. Do not depend on the order of evaluation for side effects unless there is an intervening sequence point.

    -

    The C Standard, 6.5, paragraph 2 [ISO/IEC 9899:2011], states

    -
    -

    If a side effect on a scalar object is unsequenced relative to either a different side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined. If there are multiple allowable orderings of the subexpressions of an expression, the behavior is undefined if such an unsequenced side effect occurs in any of the orderings.

    -
    -

    This requirement must be met for each allowable ordering of the subexpressions of a full expression; otherwise, the behavior is undefined. (See undefined behavior 35.)

    -

    The following sequence points are defined in the C Standard, Annex C [ISO/IEC 9899:2011]:

    -
      -
    • Between the evaluations of the function designator and actual arguments in a function call and the actual call
    • -
    • Between the evaluations of the first and second operands of the following operators:Logical AND: &&Logical OR: ||Comma: ,
    • -
    • Between the evaluations of the first operand of the conditional ?: operator and whichever of the second and third operands is evaluated
    • -
    • The end of a full declarator
    • -
    • Between the evaluation of a full expression and the next full expression to be evaluated; the following are full expressions:An initializer that is not part of a compound literalThe expression in an expression statementThe controlling expression of a selection statement (if or switch)The controlling expression of a while or do statementEach of the (optional) expressions of a for statementThe (optional) expression in a return statement
    • -
    • Immediately before a library function returns
    • -
    • After the actions associated with each formatted input/output function conversion specifier
    • -
    • Immediately before and immediately after each call to a comparison function, and also between any call to a comparison function and any movement of the objects passed as arguments to that call
    • -
    -

    Furthermore, Section 6.5.16, paragraph 3 says (regarding assignment operations):

    -
    -

    The side effect of updating the stored value of the left operand is sequenced after the value computations of the left and right operands.

    -
    -

    This rule means that statements such as

    - i = i + 1; -a[i] = i; - -

    have defined behavior, and statements such as the following do not:

    - /* i is modified twice between sequence points */ -i = ++i + 1; - -/* i is read other than to determine the value to be stored */ -a[i++] = i; - -

    Not all instances of a comma in C code denote a usage of the comma operator. For example, the comma between arguments in a function call is not a sequence point. However, according to the C Standard, 6.5.2.2, paragraph 10 [ISO/IEC 9899:2011]

    -
    -

    Every evaluation in the calling function (including other function calls) that is not otherwise specifically sequenced before or after the execution of the body of the called function is indeterminately sequenced with respect to the execution of the called function.

    -
    -

    This rule means that the order of evaluation for function call arguments is unspecified and can happen in any order.

    -
    -
    -

    Programs cannot safely rely on the order of evaluation of operands between sequence points. In this noncompliant code example, i is evaluated twice without an intervening sequence point, so the behavior of the expression is undefined:

    - #include <stdio.h> - -void func(int i, int *b) { - int a = i + b[++i]; - printf("%d, %d", a, i); -} -
    -
    -

    These examples are independent of the order of evaluation of the operands and can be interpreted in only one way:

    - #include <stdio.h> - -void func(int i, int *b) { - int a; - ++i; - a = i + b[i]; - printf("%d, %d", a, i); -} -

    Alternatively:

    - #include <stdio.h> - -void func(int i, int *b) { - int a = i + b[i + 1]; - ++i; - printf("%d, %d", a, i); -} -
    -
    -

    The call to func() in this noncompliant code example has undefined behavior because there is no sequence point between the argument expressions:

    - extern void func(int i, int j); - -void f(int i) { - func(i++, i); -} -

    The first (left) argument expression reads the value of i (to determine the value to be stored) and then modifies i. The second (right) argument expression reads the value of i between the same pair of sequence points as the first argument, but not to determine the value to be stored in i. This additional attempt to read the value of i has undefined behavior.

    -
    -
    -

    This compliant solution is appropriate when the programmer intends for both arguments to func() to be equivalent:

    - extern void func(int i, int j); - -void f(int i) { - i++; - func(i, i); -} -

    This compliant solution is appropriate when the programmer intends for the second argument to be 1 greater than the first:

    - extern void func(int i, int j); - -void f(int i) { - int j = i++; - func(j, i); -} -
    -
    -

    The order of evaluation for function arguments is unspecified. This noncompliant code example exhibits unspecified behavior but not undefined behavior:

    - extern void c(int i, int j); -int glob; - -int a(void) { - return glob + 10; -} - -int b(void) { - glob = 42; - return glob; -} - -void func(void) { - c(a(), b()); -} -

    It is unspecified what order a() and b() are called in; the only guarantee is that both a() and b() will be called before c() is called. If a() or b() rely on shared state when calculating their return value, as they do in this example, the resulting arguments passed to c() may differ between compilers or architectures.

    -
    -
    -

    In this compliant solution, the order of evaluation for a() and b() is fixed, and so no unspecified behavior occurs:

    - extern void c(int i, int j); -int glob; - -int a(void) { - return glob + 10; -} -int b(void) { - glob = 42; - return glob; -} - -void func(void) { - int a_val, b_val; - - a_val = a(); - b_val = b(); - - c(a_val, b_val); -} -
    -
    -

    Attempting to modify an object multiple times between sequence points may cause that object to take on an unexpected value, which can lead to unexpected program behavior.

    - - - - - - - - - - - - - - - - - - - -
    - Rule - - Severity - - Likelihood - - Remediation Cost - - Priority - - Level -
    - EXP30-C - - Medium - - Probable - - Medium - - P8 - - L2 -
    -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - Tool - - Version - - Checker - - Description -
    - - Astrée - - - 20.10 - - evaluation-order - multiple-volatile-accesses - - Fully checked -
    - - Axivion Bauhaus Suite - - - 7.2.0 - - CertC-EXP30 - -
    - - Clang - - - 3.9 - - -Wunsequenced - - Detects simple violations of this rule, but does not diagnose unsequenced function call arguments. -
    - - Compass/ROSE - - - - - Can detect simple violations of this rule. It needs to examine each expression and make sure that no variable is modified twice in the expression. It also must check that no variable is modified once, then read elsewhere, with the single exception that a variable may appear on both the left and right of an assignment operator -
    - - Coverity - - - 2017.07 - - EVALUATION_ORDER - - Can detect the specific instance where a statement contains multiple side effects on the same value with an undefined evaluation order because, with different compiler flags or different compilers or platforms, the statement may behave differently -
    - - ECLAIR - - - 1.2 - - CC2.EXP30 - - Fully implemented -
    - - GCC - - - 4.3.5 - - - Can detect violations of this rule when the - -Wsequence-point - flag is used -
    - - Helix QAC - - - 2022.1 - - C0400, C0401, C0402, C0403, C0404, C0405 - -
    - - Klocwork - - - 2022.1 - - PORTING.VAR.EFFECTS - MISRA.INCR_DECR.OTHER - -
    - - LDRA tool suite - - - 9.7.1 - - 35 D, 1 Q, 9 S, 30 S, 134 S - - Partially implemented -
    - - Parasoft C/C++test - - - 2021.2 - - CERT_C-EXP30-a - CERT_C-EXP30-b - CERT_C-EXP30-c - CERT_C-EXP30-d - - The value of an expression shall be the same under any order of evaluation that the standard permits - Don't write code that depends on the order of evaluation of function arguments - Don't write code that depends on the order of evaluation of function designator and function arguments - Don't write code that depends on the order of evaluation of expression that involves a function call -
    - - PC-lint Plus - - - 1.4 - - 564 - - Partially supported -
    - - Polyspace Bug Finder - - - R2021a - - - CERT C: Rule EXP30-C - - - Checks for situations when expression value depends on order of evaluation or of side effects (rule partially covered) -
    - - PRQA QA-C - - - 9.7 - - 0400, 0401, 0402, - 0403, 0404, 0405 - - Fully implemented -
    - - PVS-Studio - - - 7.18 - - V532 - - , - - V567 - -
    - - RuleChecker - - - 20.10 - - evaluation-order - multiple-volatile-accesses - - Fully checked -
    - - Splint - - - 3.1.1 - - -
    - - SonarQube C/C++ Plugin - - - 3.11 - - IncAndDecMixedWithOtherOperators - -
    - - TrustInSoft Analyzer - - - 1.38 - - separated - - Exhaustively verified (see - - one compliant and one non-compliant example - - ). -
    -
    -
    -

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    -
    -
    -

    Key here (explains table format and definitions)

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - Taxonomy - - Taxonomy item - - Relationship -
    - - CERT C - - - - EXP50-CPP. Do not depend on the order of evaluation for side effects - - - Prior to 2018-01-12: CERT: Unspecified Relationship -
    - - CERT Oracle Secure Coding Standard for Java - - - - EXP05-J. Do not follow a write by a subsequent write or read of the same object within an expression - - - Prior to 2018-01-12: CERT: Unspecified Relationship -
    - - ISO/IEC TR 24772:2013 - - - Operator Precedence/Order of Evaluation [JCW] - - Prior to 2018-01-12: CERT: Unspecified Relationship -
    - - ISO/IEC TR 24772:2013 - - - Side-effects and Order of Evaluation [SAM] - - Prior to 2018-01-12: CERT: Unspecified Relationship -
    - - MISRA C:2012 - - - Rule 13.2 (required) - - CERT cross-reference in - - MISRA C:2012 – Addendum 3 - -
    - - CWE 2.11 - - - - CWE-758 - - - 2017-07-07: CERT: Rule subset of CWE -
    -
    -
    -

    Key here for mapping notes

    -

    CWE-758 and EXP30-C

    -

    Independent( INT34-C, INT36-C, MEM30-C, MSC37-C, FLP32-C, EXP33-C, EXP30-C, ERR34-C, ARR32-C)

    -

    CWE-758 = Union( EXP30-C, list) where list =

    -
      -
    • Undefined behavior that results from anything other than reading and writing to a variable twice without an intervening sequence point.
    • -
    -
    -
    - - - - - - - - - - - - - - - -
    - [ - - ISO/IEC 9899:2011 - - ] - - 6.5, "Expressions" - 6.5.2.2, "Function Calls" - Annex C, "Sequence Points" -
    - [ - - Saks 2007 - - ] - -
    - [ - - Summit 2005 - - ] - - Questions 3.1, 3.2, 3.3, 3.3b, 3.7, 3.8, 3.9, 3.10a, 3.10b, and 3.11 -
    -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.md b/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.md new file mode 100644 index 0000000000..bbe3105708 --- /dev/null +++ b/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.md @@ -0,0 +1,224 @@ +# EXP30-C: Do not depend on the order of evaluation of function call arguments for side effects + +This query implements the CERT-C rule EXP30-C: + +> Do not depend on the order of evaluation for side effects + + +## Description + +Evaluation of an expression may produce [side effects](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-sideeffect). At specific points during execution, known as [sequence points](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-sequencepoint), all side effects of previous evaluations are complete, and no side effects of subsequent evaluations have yet taken place. Do not depend on the order of evaluation for side effects unless there is an intervening sequence point. + +The C Standard, 6.5, paragraph 2 \[[ISO/IEC 9899:2011](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO-IEC9899-2011)\], states + +> If a side effect on a scalar object is unsequenced relative to either a different side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined. If there are multiple allowable orderings of the subexpressions of an expression, the behavior is undefined if such an unsequenced side effect occurs in any of the orderings. + + +This requirement must be met for each allowable ordering of the subexpressions of a full expression; otherwise, the behavior is [undefined](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior). (See [undefined behavior 35](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_35).) + +The following sequence points are defined in the C Standard, Annex C \[[ISO/IEC 9899:2011](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO-IEC9899-2011)\]: + +* Between the evaluations of the function designator and actual arguments in a function call and the actual call +* Between the evaluations of the first and second operands of the following operators:Logical AND: `&&`Logical OR: `||`Comma: `**,**` +* Between the evaluations of the first operand of the conditional `?:` operator and whichever of the second and third operands is evaluated +* The end of a full declarator +* Between the evaluation of a full expression and the next full expression to be evaluated; the following are full expressions:An initializer that is not part of a compound literalThe expression in an expression statementThe controlling expression of a selection statement (`if `or `switch`)The controlling expression of a `while` or `do` statementEach of the (optional) expressions of a `for` statementThe (optional) expression in a `return` statement +* Immediately before a library function returns +* After the actions associated with each formatted input/output function conversion specifier +* Immediately before and immediately after each call to a comparison function, and also between any call to a comparison function and any movement of the objects passed as arguments to that call +Furthermore, Section 6.5.16, paragraph 3 says (regarding assignment operations): + +> The side effect of updating the stored value of the left operand is sequenced after the value computations of the left and right operands. + + +This rule means that statements such as + +```cpp +i = i + 1; +a[i] = i; + +``` +have defined behavior, and statements such as the following do not: + +```cpp +/* i is modified twice between sequence points */ +i = ++i + 1; + +/* i is read other than to determine the value to be stored */ +a[i++] = i; + +``` +Not all instances of a comma in C code denote a usage of the comma operator. For example, the comma between arguments in a function call is not a sequence point. However, according to the C Standard, 6.5.2.2, paragraph 10 \[[ISO/IEC 9899:2011](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO-IEC9899-2011)\] + +> Every evaluation in the calling function (including other function calls) that is not otherwise specifically sequenced before or after the execution of the body of the called function is indeterminately sequenced with respect to the execution of the called function. + + +This rule means that the order of evaluation for function call arguments is unspecified and can happen in any order. + +## Noncompliant Code Example + +Programs cannot safely rely on the order of evaluation of operands between sequence points. In this noncompliant code example, `i` is evaluated twice without an intervening sequence point, so the behavior of the expression is [undefined](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior): + +```cpp +#include + +void func(int i, int *b) { + int a = i + b[++i]; + printf("%d, %d", a, i); +} +``` + +## Compliant Solution + +These examples are independent of the order of evaluation of the operands and can be interpreted in only one way: + +```cpp +#include + +void func(int i, int *b) { + int a; + ++i; + a = i + b[i]; + printf("%d, %d", a, i); +} +``` +Alternatively: + +```cpp +#include + +void func(int i, int *b) { + int a = i + b[i + 1]; + ++i; + printf("%d, %d", a, i); +} +``` + +## Noncompliant Code Example + +The call to `func()` in this noncompliant code example has [undefined behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior) because there is no sequence point between the argument expressions: + +```cpp +extern void func(int i, int j); + +void f(int i) { + func(i++, i); +} +``` +The first (left) argument expression reads the value of `i` (to determine the value to be stored) and then modifies `i`. The second (right) argument expression reads the value of `i` between the same pair of sequence points as the first argument, but not to determine the value to be stored in `i`. This additional attempt to read the value of `i` has undefined behavior. + +## Compliant Solution + +This compliant solution is appropriate when the programmer intends for both arguments to `func()` to be equivalent: + +```cpp +extern void func(int i, int j); + +void f(int i) { + i++; + func(i, i); +} +``` +This compliant solution is appropriate when the programmer intends for the second argument to be 1 greater than the first: + +```cpp +extern void func(int i, int j); + +void f(int i) { + int j = i++; + func(j, i); +} +``` + +## Noncompliant Code Example + +The order of evaluation for function arguments is unspecified. This noncompliant code example exhibits [unspecified behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-unspecifiedbehavior) but not [undefined behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior): + +```cpp +extern void c(int i, int j); +int glob; + +int a(void) { + return glob + 10; +} + +int b(void) { + glob = 42; + return glob; +} + +void func(void) { + c(a(), b()); +} +``` +It is unspecified what order `a()` and `b()` are called in; the only guarantee is that both `a()` and `b()` will be called before `c()` is called. If `a()` or `b()` rely on shared state when calculating their return value, as they do in this example, the resulting arguments passed to `c()` may differ between compilers or architectures. + +## Compliant Solution + +In this compliant solution, the order of evaluation for `a()` and `b()` is fixed, and so no unspecified behavior occurs: + +```cpp +extern void c(int i, int j); +int glob; + +int a(void) { + return glob + 10; +} +int b(void) { + glob = 42; + return glob; +} + +void func(void) { + int a_val, b_val; + + a_val = a(); + b_val = b(); + + c(a_val, b_val); +} +``` + +## Risk Assessment + +Attempting to modify an object multiple times between sequence points may cause that object to take on an unexpected value, which can lead to [unexpected program behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-unexpectedbehavior). + +
    Rule Severity Likelihood Remediation Cost Priority Level
    EXP30-C Medium Probable Medium P8 L2
    + + +## Automated Detection + +
    Tool Version Checker Description
    Astrée 20.10 evaluation-order multiple-volatile-accesses Fully checked
    Axivion Bauhaus Suite 7.2.0 CertC-EXP30
    Clang 3.9 -Wunsequenced Detects simple violations of this rule, but does not diagnose unsequenced function call arguments.
    Compass/ROSE Can detect simple violations of this rule. It needs to examine each expression and make sure that no variable is modified twice in the expression. It also must check that no variable is modified once, then read elsewhere, with the single exception that a variable may appear on both the left and right of an assignment operator
    Coverity 2017.07 EVALUATION_ORDER Can detect the specific instance where a statement contains multiple side effects on the same value with an undefined evaluation order because, with different compiler flags or different compilers or platforms, the statement may behave differently
    ECLAIR 1.2 CC2.EXP30 Fully implemented
    GCC 4.3.5 Can detect violations of this rule when the -Wsequence-point flag is used
    Helix QAC 2022.1 C0400, C0401, C0402, C0403, C0404, C0405
    Klocwork 2022.1 PORTING.VAR.EFFECTS MISRA.INCR_DECR.OTHER
    LDRA tool suite 9.7.1 35 D, 1 Q, 9 S, 30 S, 134 S Partially implemented
    Parasoft C/C++test 2021.2 CERT_C-EXP30-a CERT_C-EXP30-b CERT_C-EXP30-c CERT_C-EXP30-d The value of an expression shall be the same under any order of evaluation that the standard permits Don't write code that depends on the order of evaluation of function arguments Don't write code that depends on the order of evaluation of function designator and function arguments Don't write code that depends on the order of evaluation of expression that involves a function call
    PC-lint Plus 1.4 564 Partially supported
    Polyspace Bug Finder R2021a CERT C: Rule EXP30-C Checks for situations when expression value depends on order of evaluation or of side effects (rule partially covered)
    PRQA QA-C 9.7 0400, 0401, 0402, 0403, 0404, 0405 Fully implemented
    PVS-Studio 7.18 V532 , V567
    RuleChecker 20.10 evaluation-order multiple-volatile-accesses Fully checked
    Splint 3.1.1
    SonarQube C/C++ Plugin 3.11 IncAndDecMixedWithOtherOperators
    TrustInSoft Analyzer 1.38 separated Exhaustively verified (see one compliant and one non-compliant example ).
    + + +## Related Vulnerabilities + +Search for [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) resulting from the violation of this rule on the [CERT website](https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+EXP30-C). + +## Related Guidelines + +[Key here](https://wiki.sei.cmu.edu/confluence/display/c/How+this+Coding+Standard+is+Organized#HowthisCodingStandardisOrganized-RelatedGuidelines) (explains table format and definitions) + +
    Taxonomy Taxonomy item Relationship
    CERT C EXP50-CPP. Do not depend on the order of evaluation for side effects Prior to 2018-01-12: CERT: Unspecified Relationship
    CERT Oracle Secure Coding Standard for Java EXP05-J. Do not follow a write by a subsequent write or read of the same object within an expression Prior to 2018-01-12: CERT: Unspecified Relationship
    ISO/IEC TR 24772:2013 Operator Precedence/Order of Evaluation \[JCW\] Prior to 2018-01-12: CERT: Unspecified Relationship
    ISO/IEC TR 24772:2013 Side-effects and Order of Evaluation \[SAM\] Prior to 2018-01-12: CERT: Unspecified Relationship
    MISRA C:2012 Rule 13.2 (required) CERT cross-reference in MISRA C:2012 – Addendum 3
    CWE 2.11 CWE-758 2017-07-07: CERT: Rule subset of CWE
    + + +## CERT-CWE Mapping Notes + +[Key here](https://wiki.sei.cmu.edu/confluence/pages/viewpage.action?pageId=87152408#HowthisCodingStandardisOrganized-CERT-CWEMappingNotes) for mapping notes + +**CWE-758 and EXP30-C** + +Independent( INT34-C, INT36-C, MEM30-C, MSC37-C, FLP32-C, EXP33-C, EXP30-C, ERR34-C, ARR32-C) + +CWE-758 = Union( EXP30-C, list) where list = + +* Undefined behavior that results from anything other than reading and writing to a variable twice without an intervening sequence point. + +## Bibliography + +
    \[ ISO/IEC 9899:2011 \] 6.5, "Expressions" 6.5.2.2, "Function Calls" Annex C, "Sequence Points"
    \[ Saks 2007 \]
    \[ Summit 2005 \] Questions 3.1, 3.2, 3.3, 3.3b, 3.7, 3.8, 3.9, 3.10a, 3.10b, and 3.11
    + + +## References + +* CERT-C: [EXP30-C: Do not depend on the order of evaluation for side effects](https://wiki.sei.cmu.edu/confluence/display/c) diff --git a/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.qhelp b/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.qhelp deleted file mode 100644 index 0ad32f85e2..0000000000 --- a/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.qhelp +++ /dev/null @@ -1,18 +0,0 @@ - - - - -

    This query implements the CERT-C rule EXP30-C:

    -
    -

    Do not depend on the order of evaluation for side effects

    -
    -
    - - -
  • - CERT-C: - EXP30-C: Do not depend on the order of evaluation for side effects - . -
  • -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects-standard.qhelp b/c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects-standard.qhelp deleted file mode 100644 index 628d8290fb..0000000000 --- a/c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects-standard.qhelp +++ /dev/null @@ -1,679 +0,0 @@ - - -
    -

    Evaluation of an expression may produce side effects. At specific points during execution, known as sequence points, all side effects of previous evaluations are complete, and no side effects of subsequent evaluations have yet taken place. Do not depend on the order of evaluation for side effects unless there is an intervening sequence point.

    -

    The C Standard, 6.5, paragraph 2 [ISO/IEC 9899:2011], states

    -
    -

    If a side effect on a scalar object is unsequenced relative to either a different side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined. If there are multiple allowable orderings of the subexpressions of an expression, the behavior is undefined if such an unsequenced side effect occurs in any of the orderings.

    -
    -

    This requirement must be met for each allowable ordering of the subexpressions of a full expression; otherwise, the behavior is undefined. (See undefined behavior 35.)

    -

    The following sequence points are defined in the C Standard, Annex C [ISO/IEC 9899:2011]:

    -
      -
    • Between the evaluations of the function designator and actual arguments in a function call and the actual call
    • -
    • Between the evaluations of the first and second operands of the following operators:Logical AND: &&Logical OR: ||Comma: ,
    • -
    • Between the evaluations of the first operand of the conditional ?: operator and whichever of the second and third operands is evaluated
    • -
    • The end of a full declarator
    • -
    • Between the evaluation of a full expression and the next full expression to be evaluated; the following are full expressions:An initializer that is not part of a compound literalThe expression in an expression statementThe controlling expression of a selection statement (if or switch)The controlling expression of a while or do statementEach of the (optional) expressions of a for statementThe (optional) expression in a return statement
    • -
    • Immediately before a library function returns
    • -
    • After the actions associated with each formatted input/output function conversion specifier
    • -
    • Immediately before and immediately after each call to a comparison function, and also between any call to a comparison function and any movement of the objects passed as arguments to that call
    • -
    -

    Furthermore, Section 6.5.16, paragraph 3 says (regarding assignment operations):

    -
    -

    The side effect of updating the stored value of the left operand is sequenced after the value computations of the left and right operands.

    -
    -

    This rule means that statements such as

    - i = i + 1; -a[i] = i; - -

    have defined behavior, and statements such as the following do not:

    - /* i is modified twice between sequence points */ -i = ++i + 1; - -/* i is read other than to determine the value to be stored */ -a[i++] = i; - -

    Not all instances of a comma in C code denote a usage of the comma operator. For example, the comma between arguments in a function call is not a sequence point. However, according to the C Standard, 6.5.2.2, paragraph 10 [ISO/IEC 9899:2011]

    -
    -

    Every evaluation in the calling function (including other function calls) that is not otherwise specifically sequenced before or after the execution of the body of the called function is indeterminately sequenced with respect to the execution of the called function.

    -
    -

    This rule means that the order of evaluation for function call arguments is unspecified and can happen in any order.

    -
    -
    -

    Programs cannot safely rely on the order of evaluation of operands between sequence points. In this noncompliant code example, i is evaluated twice without an intervening sequence point, so the behavior of the expression is undefined:

    - #include <stdio.h> - -void func(int i, int *b) { - int a = i + b[++i]; - printf("%d, %d", a, i); -} -
    -
    -

    These examples are independent of the order of evaluation of the operands and can be interpreted in only one way:

    - #include <stdio.h> - -void func(int i, int *b) { - int a; - ++i; - a = i + b[i]; - printf("%d, %d", a, i); -} -

    Alternatively:

    - #include <stdio.h> - -void func(int i, int *b) { - int a = i + b[i + 1]; - ++i; - printf("%d, %d", a, i); -} -
    -
    -

    The call to func() in this noncompliant code example has undefined behavior because there is no sequence point between the argument expressions:

    - extern void func(int i, int j); - -void f(int i) { - func(i++, i); -} -

    The first (left) argument expression reads the value of i (to determine the value to be stored) and then modifies i. The second (right) argument expression reads the value of i between the same pair of sequence points as the first argument, but not to determine the value to be stored in i. This additional attempt to read the value of i has undefined behavior.

    -
    -
    -

    This compliant solution is appropriate when the programmer intends for both arguments to func() to be equivalent:

    - extern void func(int i, int j); - -void f(int i) { - i++; - func(i, i); -} -

    This compliant solution is appropriate when the programmer intends for the second argument to be 1 greater than the first:

    - extern void func(int i, int j); - -void f(int i) { - int j = i++; - func(j, i); -} -
    -
    -

    The order of evaluation for function arguments is unspecified. This noncompliant code example exhibits unspecified behavior but not undefined behavior:

    - extern void c(int i, int j); -int glob; - -int a(void) { - return glob + 10; -} - -int b(void) { - glob = 42; - return glob; -} - -void func(void) { - c(a(), b()); -} -

    It is unspecified what order a() and b() are called in; the only guarantee is that both a() and b() will be called before c() is called. If a() or b() rely on shared state when calculating their return value, as they do in this example, the resulting arguments passed to c() may differ between compilers or architectures.

    -
    -
    -

    In this compliant solution, the order of evaluation for a() and b() is fixed, and so no unspecified behavior occurs:

    - extern void c(int i, int j); -int glob; - -int a(void) { - return glob + 10; -} -int b(void) { - glob = 42; - return glob; -} - -void func(void) { - int a_val, b_val; - - a_val = a(); - b_val = b(); - - c(a_val, b_val); -} -
    -
    -

    Attempting to modify an object multiple times between sequence points may cause that object to take on an unexpected value, which can lead to unexpected program behavior.

    - - - - - - - - - - - - - - - - - - - -
    - Rule - - Severity - - Likelihood - - Remediation Cost - - Priority - - Level -
    - EXP30-C - - Medium - - Probable - - Medium - - P8 - - L2 -
    -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - Tool - - Version - - Checker - - Description -
    - - Astrée - - - 20.10 - - evaluation-order - multiple-volatile-accesses - - Fully checked -
    - - Axivion Bauhaus Suite - - - 7.2.0 - - CertC-EXP30 - -
    - - Clang - - - 3.9 - - -Wunsequenced - - Detects simple violations of this rule, but does not diagnose unsequenced function call arguments. -
    - - Compass/ROSE - - - - - Can detect simple violations of this rule. It needs to examine each expression and make sure that no variable is modified twice in the expression. It also must check that no variable is modified once, then read elsewhere, with the single exception that a variable may appear on both the left and right of an assignment operator -
    - - Coverity - - - 2017.07 - - EVALUATION_ORDER - - Can detect the specific instance where a statement contains multiple side effects on the same value with an undefined evaluation order because, with different compiler flags or different compilers or platforms, the statement may behave differently -
    - - ECLAIR - - - 1.2 - - CC2.EXP30 - - Fully implemented -
    - - GCC - - - 4.3.5 - - - Can detect violations of this rule when the - -Wsequence-point - flag is used -
    - - Helix QAC - - - 2022.1 - - C0400, C0401, C0402, C0403, C0404, C0405 - -
    - - Klocwork - - - 2022.1 - - PORTING.VAR.EFFECTS - MISRA.INCR_DECR.OTHER - -
    - - LDRA tool suite - - - 9.7.1 - - 35 D, 1 Q, 9 S, 30 S, 134 S - - Partially implemented -
    - - Parasoft C/C++test - - - 2021.2 - - CERT_C-EXP30-a - CERT_C-EXP30-b - CERT_C-EXP30-c - CERT_C-EXP30-d - - The value of an expression shall be the same under any order of evaluation that the standard permits - Don't write code that depends on the order of evaluation of function arguments - Don't write code that depends on the order of evaluation of function designator and function arguments - Don't write code that depends on the order of evaluation of expression that involves a function call -
    - - PC-lint Plus - - - 1.4 - - 564 - - Partially supported -
    - - Polyspace Bug Finder - - - R2021a - - - CERT C: Rule EXP30-C - - - Checks for situations when expression value depends on order of evaluation or of side effects (rule partially covered) -
    - - PRQA QA-C - - - 9.7 - - 0400, 0401, 0402, - 0403, 0404, 0405 - - Fully implemented -
    - - PVS-Studio - - - 7.18 - - V532 - - , - - V567 - -
    - - RuleChecker - - - 20.10 - - evaluation-order - multiple-volatile-accesses - - Fully checked -
    - - Splint - - - 3.1.1 - - -
    - - SonarQube C/C++ Plugin - - - 3.11 - - IncAndDecMixedWithOtherOperators - -
    - - TrustInSoft Analyzer - - - 1.38 - - separated - - Exhaustively verified (see - - one compliant and one non-compliant example - - ). -
    -
    -
    -

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    -
    -
    -

    Key here (explains table format and definitions)

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - Taxonomy - - Taxonomy item - - Relationship -
    - - CERT C - - - - EXP50-CPP. Do not depend on the order of evaluation for side effects - - - Prior to 2018-01-12: CERT: Unspecified Relationship -
    - - CERT Oracle Secure Coding Standard for Java - - - - EXP05-J. Do not follow a write by a subsequent write or read of the same object within an expression - - - Prior to 2018-01-12: CERT: Unspecified Relationship -
    - - ISO/IEC TR 24772:2013 - - - Operator Precedence/Order of Evaluation [JCW] - - Prior to 2018-01-12: CERT: Unspecified Relationship -
    - - ISO/IEC TR 24772:2013 - - - Side-effects and Order of Evaluation [SAM] - - Prior to 2018-01-12: CERT: Unspecified Relationship -
    - - MISRA C:2012 - - - Rule 13.2 (required) - - CERT cross-reference in - - MISRA C:2012 – Addendum 3 - -
    - - CWE 2.11 - - - - CWE-758 - - - 2017-07-07: CERT: Rule subset of CWE -
    -
    -
    -

    Key here for mapping notes

    -

    CWE-758 and EXP30-C

    -

    Independent( INT34-C, INT36-C, MEM30-C, MSC37-C, FLP32-C, EXP33-C, EXP30-C, ERR34-C, ARR32-C)

    -

    CWE-758 = Union( EXP30-C, list) where list =

    -
      -
    • Undefined behavior that results from anything other than reading and writing to a variable twice without an intervening sequence point.
    • -
    -
    -
    - - - - - - - - - - - - - - - -
    - [ - - ISO/IEC 9899:2011 - - ] - - 6.5, "Expressions" - 6.5.2.2, "Function Calls" - Annex C, "Sequence Points" -
    - [ - - Saks 2007 - - ] - -
    - [ - - Summit 2005 - - ] - - Questions 3.1, 3.2, 3.3, 3.3b, 3.7, 3.8, 3.9, 3.10a, 3.10b, and 3.11 -
    -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects.md b/c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects.md new file mode 100644 index 0000000000..d68012d99d --- /dev/null +++ b/c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects.md @@ -0,0 +1,224 @@ +# EXP30-C: Do not depend on the order of scalar object evaluation for side effects + +This query implements the CERT-C rule EXP30-C: + +> Do not depend on the order of evaluation for side effects + + +## Description + +Evaluation of an expression may produce [side effects](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-sideeffect). At specific points during execution, known as [sequence points](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-sequencepoint), all side effects of previous evaluations are complete, and no side effects of subsequent evaluations have yet taken place. Do not depend on the order of evaluation for side effects unless there is an intervening sequence point. + +The C Standard, 6.5, paragraph 2 \[[ISO/IEC 9899:2011](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO-IEC9899-2011)\], states + +> If a side effect on a scalar object is unsequenced relative to either a different side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined. If there are multiple allowable orderings of the subexpressions of an expression, the behavior is undefined if such an unsequenced side effect occurs in any of the orderings. + + +This requirement must be met for each allowable ordering of the subexpressions of a full expression; otherwise, the behavior is [undefined](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior). (See [undefined behavior 35](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_35).) + +The following sequence points are defined in the C Standard, Annex C \[[ISO/IEC 9899:2011](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO-IEC9899-2011)\]: + +* Between the evaluations of the function designator and actual arguments in a function call and the actual call +* Between the evaluations of the first and second operands of the following operators:Logical AND: `&&`Logical OR: `||`Comma: `**,**` +* Between the evaluations of the first operand of the conditional `?:` operator and whichever of the second and third operands is evaluated +* The end of a full declarator +* Between the evaluation of a full expression and the next full expression to be evaluated; the following are full expressions:An initializer that is not part of a compound literalThe expression in an expression statementThe controlling expression of a selection statement (`if `or `switch`)The controlling expression of a `while` or `do` statementEach of the (optional) expressions of a `for` statementThe (optional) expression in a `return` statement +* Immediately before a library function returns +* After the actions associated with each formatted input/output function conversion specifier +* Immediately before and immediately after each call to a comparison function, and also between any call to a comparison function and any movement of the objects passed as arguments to that call +Furthermore, Section 6.5.16, paragraph 3 says (regarding assignment operations): + +> The side effect of updating the stored value of the left operand is sequenced after the value computations of the left and right operands. + + +This rule means that statements such as + +```cpp +i = i + 1; +a[i] = i; + +``` +have defined behavior, and statements such as the following do not: + +```cpp +/* i is modified twice between sequence points */ +i = ++i + 1; + +/* i is read other than to determine the value to be stored */ +a[i++] = i; + +``` +Not all instances of a comma in C code denote a usage of the comma operator. For example, the comma between arguments in a function call is not a sequence point. However, according to the C Standard, 6.5.2.2, paragraph 10 \[[ISO/IEC 9899:2011](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO-IEC9899-2011)\] + +> Every evaluation in the calling function (including other function calls) that is not otherwise specifically sequenced before or after the execution of the body of the called function is indeterminately sequenced with respect to the execution of the called function. + + +This rule means that the order of evaluation for function call arguments is unspecified and can happen in any order. + +## Noncompliant Code Example + +Programs cannot safely rely on the order of evaluation of operands between sequence points. In this noncompliant code example, `i` is evaluated twice without an intervening sequence point, so the behavior of the expression is [undefined](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior): + +```cpp +#include + +void func(int i, int *b) { + int a = i + b[++i]; + printf("%d, %d", a, i); +} +``` + +## Compliant Solution + +These examples are independent of the order of evaluation of the operands and can be interpreted in only one way: + +```cpp +#include + +void func(int i, int *b) { + int a; + ++i; + a = i + b[i]; + printf("%d, %d", a, i); +} +``` +Alternatively: + +```cpp +#include + +void func(int i, int *b) { + int a = i + b[i + 1]; + ++i; + printf("%d, %d", a, i); +} +``` + +## Noncompliant Code Example + +The call to `func()` in this noncompliant code example has [undefined behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior) because there is no sequence point between the argument expressions: + +```cpp +extern void func(int i, int j); + +void f(int i) { + func(i++, i); +} +``` +The first (left) argument expression reads the value of `i` (to determine the value to be stored) and then modifies `i`. The second (right) argument expression reads the value of `i` between the same pair of sequence points as the first argument, but not to determine the value to be stored in `i`. This additional attempt to read the value of `i` has undefined behavior. + +## Compliant Solution + +This compliant solution is appropriate when the programmer intends for both arguments to `func()` to be equivalent: + +```cpp +extern void func(int i, int j); + +void f(int i) { + i++; + func(i, i); +} +``` +This compliant solution is appropriate when the programmer intends for the second argument to be 1 greater than the first: + +```cpp +extern void func(int i, int j); + +void f(int i) { + int j = i++; + func(j, i); +} +``` + +## Noncompliant Code Example + +The order of evaluation for function arguments is unspecified. This noncompliant code example exhibits [unspecified behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-unspecifiedbehavior) but not [undefined behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior): + +```cpp +extern void c(int i, int j); +int glob; + +int a(void) { + return glob + 10; +} + +int b(void) { + glob = 42; + return glob; +} + +void func(void) { + c(a(), b()); +} +``` +It is unspecified what order `a()` and `b()` are called in; the only guarantee is that both `a()` and `b()` will be called before `c()` is called. If `a()` or `b()` rely on shared state when calculating their return value, as they do in this example, the resulting arguments passed to `c()` may differ between compilers or architectures. + +## Compliant Solution + +In this compliant solution, the order of evaluation for `a()` and `b()` is fixed, and so no unspecified behavior occurs: + +```cpp +extern void c(int i, int j); +int glob; + +int a(void) { + return glob + 10; +} +int b(void) { + glob = 42; + return glob; +} + +void func(void) { + int a_val, b_val; + + a_val = a(); + b_val = b(); + + c(a_val, b_val); +} +``` + +## Risk Assessment + +Attempting to modify an object multiple times between sequence points may cause that object to take on an unexpected value, which can lead to [unexpected program behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-unexpectedbehavior). + +
    Rule Severity Likelihood Remediation Cost Priority Level
    EXP30-C Medium Probable Medium P8 L2
    + + +## Automated Detection + +
    Tool Version Checker Description
    Astrée 20.10 evaluation-order multiple-volatile-accesses Fully checked
    Axivion Bauhaus Suite 7.2.0 CertC-EXP30
    Clang 3.9 -Wunsequenced Detects simple violations of this rule, but does not diagnose unsequenced function call arguments.
    Compass/ROSE Can detect simple violations of this rule. It needs to examine each expression and make sure that no variable is modified twice in the expression. It also must check that no variable is modified once, then read elsewhere, with the single exception that a variable may appear on both the left and right of an assignment operator
    Coverity 2017.07 EVALUATION_ORDER Can detect the specific instance where a statement contains multiple side effects on the same value with an undefined evaluation order because, with different compiler flags or different compilers or platforms, the statement may behave differently
    ECLAIR 1.2 CC2.EXP30 Fully implemented
    GCC 4.3.5 Can detect violations of this rule when the -Wsequence-point flag is used
    Helix QAC 2022.1 C0400, C0401, C0402, C0403, C0404, C0405
    Klocwork 2022.1 PORTING.VAR.EFFECTS MISRA.INCR_DECR.OTHER
    LDRA tool suite 9.7.1 35 D, 1 Q, 9 S, 30 S, 134 S Partially implemented
    Parasoft C/C++test 2021.2 CERT_C-EXP30-a CERT_C-EXP30-b CERT_C-EXP30-c CERT_C-EXP30-d The value of an expression shall be the same under any order of evaluation that the standard permits Don't write code that depends on the order of evaluation of function arguments Don't write code that depends on the order of evaluation of function designator and function arguments Don't write code that depends on the order of evaluation of expression that involves a function call
    PC-lint Plus 1.4 564 Partially supported
    Polyspace Bug Finder R2021a CERT C: Rule EXP30-C Checks for situations when expression value depends on order of evaluation or of side effects (rule partially covered)
    PRQA QA-C 9.7 0400, 0401, 0402, 0403, 0404, 0405 Fully implemented
    PVS-Studio 7.18 V532 , V567
    RuleChecker 20.10 evaluation-order multiple-volatile-accesses Fully checked
    Splint 3.1.1
    SonarQube C/C++ Plugin 3.11 IncAndDecMixedWithOtherOperators
    TrustInSoft Analyzer 1.38 separated Exhaustively verified (see one compliant and one non-compliant example ).
    + + +## Related Vulnerabilities + +Search for [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) resulting from the violation of this rule on the [CERT website](https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+EXP30-C). + +## Related Guidelines + +[Key here](https://wiki.sei.cmu.edu/confluence/display/c/How+this+Coding+Standard+is+Organized#HowthisCodingStandardisOrganized-RelatedGuidelines) (explains table format and definitions) + +
    Taxonomy Taxonomy item Relationship
    CERT C EXP50-CPP. Do not depend on the order of evaluation for side effects Prior to 2018-01-12: CERT: Unspecified Relationship
    CERT Oracle Secure Coding Standard for Java EXP05-J. Do not follow a write by a subsequent write or read of the same object within an expression Prior to 2018-01-12: CERT: Unspecified Relationship
    ISO/IEC TR 24772:2013 Operator Precedence/Order of Evaluation \[JCW\] Prior to 2018-01-12: CERT: Unspecified Relationship
    ISO/IEC TR 24772:2013 Side-effects and Order of Evaluation \[SAM\] Prior to 2018-01-12: CERT: Unspecified Relationship
    MISRA C:2012 Rule 13.2 (required) CERT cross-reference in MISRA C:2012 – Addendum 3
    CWE 2.11 CWE-758 2017-07-07: CERT: Rule subset of CWE
    + + +## CERT-CWE Mapping Notes + +[Key here](https://wiki.sei.cmu.edu/confluence/pages/viewpage.action?pageId=87152408#HowthisCodingStandardisOrganized-CERT-CWEMappingNotes) for mapping notes + +**CWE-758 and EXP30-C** + +Independent( INT34-C, INT36-C, MEM30-C, MSC37-C, FLP32-C, EXP33-C, EXP30-C, ERR34-C, ARR32-C) + +CWE-758 = Union( EXP30-C, list) where list = + +* Undefined behavior that results from anything other than reading and writing to a variable twice without an intervening sequence point. + +## Bibliography + +
    \[ ISO/IEC 9899:2011 \] 6.5, "Expressions" 6.5.2.2, "Function Calls" Annex C, "Sequence Points"
    \[ Saks 2007 \]
    \[ Summit 2005 \] Questions 3.1, 3.2, 3.3, 3.3b, 3.7, 3.8, 3.9, 3.10a, 3.10b, and 3.11
    + + +## References + +* CERT-C: [EXP30-C: Do not depend on the order of evaluation for side effects](https://wiki.sei.cmu.edu/confluence/display/c) diff --git a/c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects.qhelp b/c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects.qhelp deleted file mode 100644 index b1a3a347d1..0000000000 --- a/c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects.qhelp +++ /dev/null @@ -1,18 +0,0 @@ - - - - -

    This query implements the CERT-C rule EXP30-C:

    -
    -

    Do not depend on the order of evaluation for side effects

    -
    -
    - - -
  • - CERT-C: - EXP30-C: Do not depend on the order of evaluation for side effects - . -
  • -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/EXP30-C/standard-example.c b/c/cert/src/rules/EXP30-C/standard-example.c deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect-standard.qhelp b/c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect-standard.qhelp deleted file mode 100644 index f439c63755..0000000000 --- a/c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect-standard.qhelp +++ /dev/null @@ -1,481 +0,0 @@ - - -
    -

    Some operators do not evaluate their operands beyond the type information the operands provide. When using one of these operators, do not pass an operand that would otherwise yield a side effect since the side effect will not be generated.

    -

    The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. In most cases, the operand is not evaluated. A possible exception is when the type of the operand is a variable length array type (VLA); then the expression is evaluated. When part of the operand of the sizeof operator is a VLA type and when changing the value of the VLA's size expression would not affect the result of the operator, it is unspecified whether or not the size expression is evaluated. (See unspecified behavior 22.)

    -

    The operand passed to_Alignof is never evaluated, despite not being an expression. For instance, if the operand is a VLA type and the VLA's size expression contains a side effect, that side effect is never evaluated.

    -

    The operand used in the controlling expression of a _Generic selection expression is never evaluated.

    -

    Providing an expression that appears to produce side effects may be misleading to programmers who are not aware that these expressions are not evaluated, and in the case of a VLA used in sizeof, have unspecified results. As a result, programmers may make invalid assumptions about program state, leading to errors and possible software vulnerabilities.

    -

    This rule is similar to PRE31-C. Avoid side effects in arguments to unsafe macros.

    -
    -
    -

    In this noncompliant code example, the expression a++ is not evaluated:

    - #include <stdio.h> - -void func(void) { - int a = 14; - int b = sizeof(a++); - printf("%d, %d\n", a, b); -} -

    Consequently, the value of a after b has been initialized is 14.

    -
    -
    -

    In this compliant solution, the variable a is incremented outside of the sizeof operation:

    - #include <stdio.h> - -void func(void) { - int a = 14; - int b = sizeof(a); - ++a; - printf("%d, %d\n", a, b); -} -
    -
    -

    In this noncompliant code example, the expression ++n in the initialization expression of a must be evaluated because its value affects the size of the VLA operand of the sizeof operator. However, in the initialization expression of b, the expression ++n % 1 evaluates to 0. This means that the value of n does not affect the result of the sizeof operator. Consequently, it is unspecified whether or not n will be incremented when initializing b.

    - #include <stddef.h> -#include <stdio.h> - -void f(size_t n) { - /* n must be incremented */ - size_t a = sizeof(int[++n]); - - /* n need not be incremented */ - size_t b = sizeof(int[++n % 1 + 1]); - - printf("%zu, %zu, %zu\n", a, b, n); - /* ... */ -} -
    -
    -

    This compliant solution avoids changing the value of the variable n used in each sizeof expression and instead increments n safely afterwards:

    - #include <stddef.h> -#include <stdio.h> - -void f(size_t n) { - size_t a = sizeof(int[n + 1]); - ++n; - - size_t b = sizeof(int[n % 1 + 1]); - ++n; - printf("%zu, %zu, %zu\n", a, b, n); - /* ... */ -} - -
    -
    -

    This noncompliant code example attempts to modify a variable's value as part of the _Generic selection control expression. The programmer may expect that a is incremented, but because _Generic does not evaluate its control expression, the value of a is not modified.

    - #include <stdio.h> - -#define S(val) _Generic(val, int : 2, \ - short : 3, \ - default : 1) -void func(void) { - int a = 0; - int b = S(a++); - printf("%d, %d\n", a, b); -} -
    -
    -

    In this compliant solution, a is incremented outside of the _Generic selection expression:

    - #include <stdio.h> - -#define S(val) _Generic(val, int : 2, \ - short : 3, \ - default : 1) -void func(void) { - int a = 0; - int b = S(a); - ++a; - printf("%d, %d\n", a, b); -} -
    -
    -

    This noncompliant code example attempts to modify a variable while getting its default alignment value. The user may have expected val to be incremented as part of the _Alignof expression, but because _Alignof does not evaluate its operand, val is unchanged.

    - #include <stdio.h> - -void func(void) { - int val = 0; - /* ... */ - size_t align = _Alignof(int[++val]); - printf("%zu, %d\n", align, val); - /* ... */ -} -
    -
    -

    This compliant solution moves the expression out of the _Alignof operator:

    - #include <stdio.h> -void func(void) { - int val = 0; - /* ... */ - ++val; - size_t align = _Alignof(int[val]); - printf("%zu, %d\n", align, val); - /* ... */ -} -
    -
    -

    EXP44-C-EX1: Reading a volatile-qualified value is a side-effecting operation. However, accessing a value through a volatile-qualified type does not guarantee side effects will happen on the read of the value unless the underlying object is also volatile-qualified. Idiomatic reads of a volatile-qualified object are permissible as an operand to a sizeof(), _Alignof(), or _Generic expression, as in the following example:

    - void f(void) { - int * volatile v; - (void)sizeof(*v); -} -
    -
    -

    If expressions that appear to produce side effects are supplied to an operator that does not evaluate its operands, the results may be different than expected. Depending on how this result is used, it can lead to unintended program behavior.

    - - - - - - - - - - - - - - - - - - - -
    - Rule - - Severity - - Likelihood - - Remediation Cost - - Priority - - Level -
    - EXP44-C - - Low - - Unlikely - - Low - - P3 - - L3 -
    -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - Tool - - Version - - Checker - - Description -
    - - Astrée - - - 20.10 - - alignof-side-effectgeneric-selection-side-effectsizeof - - Fully checked -
    - - Axivion Bauhaus Suite - - - 7.2.0 - - CertC-EXP44 - -
    - - Clang - - - 3.9 - - -Wunevaluated-expression - - Can diagnose some instance of this rule, but not all (such as the - _Alignof - NCCE). -
    - - CodeSonar - - - 6.2p0 - - LANG.STRUCT.SE.SIZEOF - - Side effects in sizeof -
    - - Compass/ROSE - - - - -
    - - Coverity - - - 2017.07 - - MISRA C 2004 Rule 12.3 - - Partially implemented -
    - - ECLAIR - - - 1.2 - - CC2.EXP06 - - Fully implemented -
    - - Helix QAC - - - 2022.1 - - C3307 - -
    - - Klocwork - - - 2022.1 - - MISRA.SIZEOF.SIDE_EFFECT - -
    - - LDRA tool suite - - - 9.7.1 - - 54 S, 653 S - - Fully implemented -
    - - Parasoft C/C++test - - - 2021.2 - - CERT_C-EXP44-a - CERT_C-EXP44-b - - Object designated by a volatile lvalue should not be accessed in the operand of the sizeof operator - The function call that causes the side effect shall not be the operand of the sizeof operator -
    - - PC-lint Plus - - - 1.4 - - 9006 - - Partially supported: reports use of sizeof with an expression that would have side effects -
    - - Polyspace Bug Finder - - - R2021a - - - CERT C: Rule EXP44-C - - - Checks for situations when side effects of specified expressions are ignored (rule fully covered) -
    - - PRQA QA-C - - - 9.7 - - 3307 - - Fully implemented -
    - - PVS-Studio - - - 7.18 - - V568 - -
    - - RuleChecker - - - 20.10 - - alignof-side-effectgeneric-selection-side-effectsizeof - - Fully checked -
    -
    -
    -

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    -
    -
    -

    Key here (explains table format and definitions)

    - - - - - - - - - - - - - -
    - Taxonomy - - Taxonomy item - - Relationship -
    - - CERT C - - - - EXP52-CPP. Do not rely on side effects in unevaluated operands - - - Prior to 2018-01-12: CERT: Unspecified Relationship -
    -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect.md b/c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect.md new file mode 100644 index 0000000000..94727fe63a --- /dev/null +++ b/c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect.md @@ -0,0 +1,195 @@ +# EXP44-C: Do not rely on side effects in operands to sizeof, _Alignof, or _Generic + +This query implements the CERT-C rule EXP44-C: + +> Do not rely on side effects in operands to sizeof, _Alignof, or _Generic + + +## Description + +Some operators do not evaluate their operands beyond the type information the operands provide. When using one of these operators, do not pass an operand that would otherwise yield a side effect since the side effect will not be generated. + +The `sizeof` operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. In most cases, the operand is not evaluated. A possible exception is when the type of the operand is a variable length array type (VLA); then the expression is evaluated. When part of the operand of the sizeof operator is a VLA type and when changing the value of the VLA's size expression would not affect the result of the operator, it is [unspecified](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-unspecifiedbehavior) whether or not the size expression is evaluated. (See [unspecified behavior 22](https://wiki.sei.cmu.edu/confluence/display/c/DD.+Unspecified+Behavior#DD.UnspecifiedBehavior-usb_22).) + +The operand passed to`_Alignof` is never evaluated, despite not being an expression. For instance, if the operand is a VLA type and the VLA's size expression contains a side effect, that side effect is never evaluated. + +The operand used in the controlling expression of a `_Generic` selection expression is never evaluated. + +Providing an expression that appears to produce side effects may be misleading to programmers who are not aware that these expressions are not evaluated, and in the case of a VLA used in `sizeof`, have unspecified results. As a result, programmers may make invalid assumptions about program state, leading to errors and possible software [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability). + +This rule is similar to [PRE31-C. Avoid side effects in arguments to unsafe macros](https://wiki.sei.cmu.edu/confluence/display/c/PRE31-C.+Avoid+side+effects+in+arguments+to+unsafe+macros). + +## Noncompliant Code Example (sizeof) + +In this noncompliant code example, the expression `a++` is not evaluated: + +```cpp +#include + +void func(void) { + int a = 14; + int b = sizeof(a++); + printf("%d, %d\n", a, b); +} +``` +Consequently, the value of `a` after `b` has been initialized is 14. + +## Compliant Solution (sizeof) + +In this compliant solution, the variable `a` is incremented outside of the `sizeof` operation: + +```cpp +#include + +void func(void) { + int a = 14; + int b = sizeof(a); + ++a; + printf("%d, %d\n", a, b); +} +``` + +## Noncompliant Code Example (sizeof, VLA) + +In this noncompliant code example, the expression `++n` in the initialization expression of `a` must be evaluated because its value affects the size of the VLA operand of the `sizeof` operator. However, in the initialization expression of `b`, the expression `++n % 1` evaluates to `0.` This means that the value of `n` does not affect the result of the `sizeof` operator. Consequently, it is unspecified whether or not `n` will be incremented when initializing `b`. + +```cpp +#include +#include + +void f(size_t n) { + /* n must be incremented */ + size_t a = sizeof(int[++n]); + + /* n need not be incremented */ + size_t b = sizeof(int[++n % 1 + 1]); + + printf("%zu, %zu, %zu\n", a, b, n); + /* ... */ +} +``` + +## Compliant Solution (sizeof, VLA) + +This compliant solution avoids changing the value of the variable `n` used in each `sizeof` expression and instead increments `n` safely afterwards: + +```cpp +#include +#include + +void f(size_t n) { + size_t a = sizeof(int[n + 1]); + ++n; + + size_t b = sizeof(int[n % 1 + 1]); + ++n; + printf("%zu, %zu, %zu\n", a, b, n); + /* ... */ +} + +``` + +## Noncompliant Code Example (_Generic) + +This noncompliant code example attempts to modify a variable's value as part of the `_Generic` selection control expression. The programmer may expect that `a` is incremented, but because `_Generic` does not evaluate its control expression, the value of `a` is not modified. + +```cpp +#include + +#define S(val) _Generic(val, int : 2, \ + short : 3, \ + default : 1) +void func(void) { + int a = 0; + int b = S(a++); + printf("%d, %d\n", a, b); +} +``` + +## Compliant Solution (_Generic) + +In this compliant solution, a is incremented outside of the `_Generic` selection expression: + +```cpp +#include + +#define S(val) _Generic(val, int : 2, \ + short : 3, \ + default : 1) +void func(void) { + int a = 0; + int b = S(a); + ++a; + printf("%d, %d\n", a, b); +} +``` + +## Noncompliant Code Example (_Alignof) + +This noncompliant code example attempts to modify a variable while getting its default alignment value. The user may have expected `val` to be incremented as part of the `_Alignof` expression, but because `_Alignof` does not evaluate its operand, `val` is unchanged. + +```cpp +#include + +void func(void) { + int val = 0; + /* ... */ + size_t align = _Alignof(int[++val]); + printf("%zu, %d\n", align, val); + /* ... */ +} +``` + +## Compliant Solution (_Alignof) + +This compliant solution moves the expression out of the `_Alignof` operator: + +```cpp +#include +void func(void) { + int val = 0; + /* ... */ + ++val; + size_t align = _Alignof(int[val]); + printf("%zu, %d\n", align, val); + /* ... */ +} +``` + +## Exceptions + +**EXP44-C-EX1**: Reading a `volatile`-qualified value is a side-effecting operation. However, accessing a value through a `volatile`-qualified type does not guarantee side effects will happen on the read of the value unless the underlying object is also `volatile`-qualified. Idiomatic reads of a `volatile`-qualified object are permissible as an operand to a `sizeof()`, `_Alignof()`, or `_Generic` expression, as in the following example: + +```cpp +void f(void) { + int * volatile v; + (void)sizeof(*v); +} +``` + +## Risk Assessment + +If expressions that appear to produce side effects are supplied to an operator that does not evaluate its operands, the results may be different than expected. Depending on how this result is used, it can lead to unintended program behavior. + +
    Rule Severity Likelihood Remediation Cost Priority Level
    EXP44-C Low Unlikely Low P3 L3
    + + +## Automated Detection + +
    Tool Version Checker Description
    Astrée 20.10 alignof-side-effectgeneric-selection-side-effectsizeof Fully checked
    Axivion Bauhaus Suite 7.2.0 CertC-EXP44
    Clang 3.9 -Wunevaluated-expression Can diagnose some instance of this rule, but not all (such as the _Alignof NCCE).
    CodeSonar 6.2p0 LANG.STRUCT.SE.SIZEOF Side effects in sizeof
    Compass/ROSE
    Coverity 2017.07 MISRA C 2004 Rule 12.3 Partially implemented
    ECLAIR 1.2 CC2.EXP06 Fully implemented
    Helix QAC 2022.1 C3307
    Klocwork 2022.1 MISRA.SIZEOF.SIDE_EFFECT
    LDRA tool suite 9.7.1 54 S, 653 S Fully implemented
    Parasoft C/C++test 2021.2 CERT_C-EXP44-a CERT_C-EXP44-b Object designated by a volatile lvalue should not be accessed in the operand of the sizeof operator The function call that causes the side effect shall not be the operand of the sizeof operator
    PC-lint Plus 1.4 9006 Partially supported: reports use of sizeof with an expression that would have side effects
    Polyspace Bug Finder R2021a CERT C: Rule EXP44-C Checks for situations when side effects of specified expressions are ignored (rule fully covered)
    PRQA QA-C 9.7 3307 Fully implemented
    PVS-Studio 7.18 V568
    RuleChecker 20.10 alignof-side-effectgeneric-selection-side-effectsizeof Fully checked
    + + +## Related Vulnerabilities + +Search for [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) resulting from the violation of this rule on the [CERT website](https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+EXP44-C). + +## Related Guidelines + +[Key here](https://wiki.sei.cmu.edu/confluence/display/c/How+this+Coding+Standard+is+Organized#HowthisCodingStandardisOrganized-RelatedGuidelines) (explains table format and definitions) + +
    Taxonomy Taxonomy item Relationship
    CERT C EXP52-CPP. Do not rely on side effects in unevaluated operands Prior to 2018-01-12: CERT: Unspecified Relationship
    + + +## References + +* CERT-C: [EXP44-C: Do not rely on side effects in operands to sizeof, _Alignof, or _Generic](https://wiki.sei.cmu.edu/confluence/display/c) diff --git a/c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect.qhelp b/c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect.qhelp deleted file mode 100644 index b33510d090..0000000000 --- a/c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect.qhelp +++ /dev/null @@ -1,18 +0,0 @@ - - - - -

    This query implements the CERT-C rule EXP44-C:

    -
    -

    Do not rely on side effects in operands to sizeof, _Alignof, or _Generic

    -
    -
    - - -
  • - CERT-C: - EXP44-C: Do not rely on side effects in operands to sizeof, _Alignof, or _Generic - . -
  • -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/EXP44-C/standard-example.c b/c/cert/src/rules/EXP44-C/standard-example.c deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements-standard.qhelp b/c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements-standard.qhelp deleted file mode 100644 index 01036cbe97..0000000000 --- a/c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements-standard.qhelp +++ /dev/null @@ -1,688 +0,0 @@ - - -
    -

    Do not use the assignment operator in the contexts listed in the following table because doing so typically indicates programmer error and can result in unexpected behavior.

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - Operator - - Context -
    - if - - Controlling expression -
    - while - - Controlling expression -
    - do ... while - - Controlling expression -
    - for - - Second operand -
    - ?: - - First operand -
    - ?: - - Second or third operands, where the ternary expression is used in any of these contexts -
    - && - - Either operand -
    - || - - either operand -
    - , - - Second operand, when the comma expression is used in any of these contexts -
    -

    Performing assignment statements in other contexts do not violate this rule. However, they may violate other rules, such as EXP30-C. Do not depend on the order of evaluation for side effects.

    -

    Noncompliant Code Example

    -

    In this noncompliant code example, an assignment expression is the outermost expression in an if statement:

    - if (a = b) { - /* ... */ -} - -

    Although the intent of the code may be to assign b to a and test the value of the result for equality to 0, it is frequently a case of the programmer mistakenly using the assignment operator = instead of the equals operator ==. Consequently, many compilers will warn about this condition, making this coding error detectable by adhering to MSC00-C. Compile cleanly at high warning levels.

    -
    -
    -

    When the assignment of b to a is not intended, the conditional block is now executed when a is equal to b:

    - if (a == b) { - /* ... */ -} - -
    -
    -

    When the assignment is intended, this compliant solution explicitly uses inequality as the outermost expression while performing the assignment in the inner expression:

    - if ((a = b) != 0) { - /* ... */ -} - -

    It is less desirable in general, depending on what was intended, because it mixes the assignment in the condition, but it is clear that the programmer intended the assignment to occur.

    -
    -
    -

    In this noncompliant code example, the expression x = y is used as the controlling expression of the while statement:

    - do { /* ... */ } while (foo(), x = y); -
    -
    -

    When the assignment of y to x is not intended, the conditional block should be executed only when x is equal to y, as in this compliant solution:

    - do { /* ... */ } while (foo(), x == y); - -
    -
    -

    When the assignment is intended, this compliant solution can be used:

    - do { /* ... */ } while (foo(), (x = y) != 0); - -
    -
    -

    The same result can be obtained using the for statement, which is specifically designed to evaluate an expression on each iteration of the loop, just before performing the test in its controlling expression. Remember that its controlling expression is the second operand, where the assignment occurs in its third operand:

    - for (; x; foo(), x = y) { /* ... */ } -
    -
    -

    In this noncompliant example, the expression p = q is used as the controlling expression of the while statement:

    - do { /* ... */ } while (x = y, p = q); -
    -
    -

    In this compliant solution, the expression x = y is not used as the controlling expression of the while statement:

    - do { /* ... */ } while (x = y, p == q); - -
    -
    -

    This noncompliant code example has a typo that results in an assignment rather than a comparison.

    - while (ch = '\t' || ch == ' ' || ch == '\n') { - /* ... */ -} - -

    Many compilers will warn about this condition. This coding error would typically be eliminated by adherence to MSC00-C. Compile cleanly at high warning levels. Although this code compiles, it will cause unexpected behavior to an unsuspecting programmer. If the intent was to verify a string such as a password, user name, or group user ID, the code may produce significant vulnerabilities and require significant debugging.

    -
    -
    -

    When comparisons are made between a variable and a literal or const-qualified variable, placing the variable on the right of the comparison operation can prevent a spurious assignment.

    -

    In this code example, the literals are placed on the left-hand side of each comparison. If the programmer were to inadvertently use an assignment operator, the statement would assign ch to '\t', which is invalid and produces a diagnostic message.

    - while ('\t' = ch || ' ' == ch || '\n' == ch) { - /* ... */ -} -

    Due to the diagnostic, the typo will be easily spotted and fixed.

    - while ('\t' == ch || ' ' == ch || '\n' == ch) { - /* ... */ -} -

    As a result, any mistaken use of the assignment operator that could otherwise create a vulnerability for operations such as string verification will result in a compiler diagnostic regardless of compiler, warning level, or implementation.

    -
    -
    -

    EXP45-C-EX1: Assignment can be used where the result of the assignment is itself an operand to a comparison expression or relational expression. In this compliant example, the expression x = y is itself an operand to a comparison operation:

    - if ((x = y) != 0) { /* ... */ } -

    EXP45-C-EX2: Assignment can be used where the expression consists of a single primary expression. The following code is compliant because the expression x = y is a single primary expression:

    - if ((x = y)) { /* ... */ } -

    The following controlling expression is noncompliant because && is not a comparison or relational operator and the entire expression is not primary:

    - if ((v = w) && flag) { /* ... */ } -

    When the assignment of v to w is not intended, the following controlling expression can be used to execute the conditional block when v is equal to w:

    - if ((v == w) && flag) { /* ... */ }; -

    When the assignment is intended, the following controlling expression can be used:

    - if (((v = w) != 0) && flag) { /* ... */ }; -

    EXP45-C-EX3: Assignment can be used in a function argument or array index. In this compliant solution, the expression x = y is used in a function argument:

    - if (foo(x = y)) { /* ... */ } -
    -
    -

    Errors of omission can result in unintended program flow.

    - - - - - - - - - - - - - - - - - - - -
    - Recommendation - - Severity - - Likelihood - - Remediation Cost - - Priority - - Level -
    - EXP45-C - - Low - - Likely - - Medium - - P6 - - L2 -
    -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - Tool - - Version - - Checker - - Description -
    - - Astrée - - - 20.10 - - assignment-conditional - - Fully checked -
    - - Axivion Bauhaus Suite - - - 7.2.0 - - CertC-EXP45 - -
    - - Clang - - - 3.9 - - -Wparentheses - - Can detect some instances of this rule, but does not detect all -
    - - CodeSonar - - - 6.2p0 - - LANG.STRUCT.CONDASSIGLANG.STRUCT.SE.CONDLANG.STRUCT.USEASSIGN - - Assignment in conditional - Condition contains side effects - Assignment result in expression -
    - - Compass/ROSE - - - - - Could detect violations of this recommendation by identifying any assignment expression as the top-level expression in an - if - or - while - statement -
    - - ECLAIR - - - 1.2 - - CC2.EXP18 - CC2.EXP21 - - Fully implemented -
    - - GCC - - - 4.3.5 - - - Can detect violations of this recommendation when the - -Wall - flag is used -
    - - Helix QAC - - - 2022.1 - - C3314, C3326, C3344, C3416 - C++4071, C++4074 - -
    - - Klocwork - - - 2022.1 - - ASSIGCOND.CALL - ASSIGCOND.GENMISRA.ASSIGN.COND - -
    - - LDRA tool suite - - - 9.7.1 - - 114 S, 132 S - - Enhanced Enforcement -
    - - Parasoft C/C++test - - - 2021.2 - - CERT_C-EXP45-b - CERT_C-EXP45-d - - Assignment operators shall not be used in conditions without brackets - Assignment operators shall not be used in expressions that yield a Boolean value -
    - - PC-lint Plus - - - 1.4 - - 720 - - Partially supported: reports Boolean test of unparenthesized assignment -
    - - Polyspace Bug Finder - - - R2021a - - - CERT C: Rule EXP45-C - - - Checks for invalid use of = (assignment) operator (rule fully covered) -
    - - PRQA QA-C - - - 9.7 - - 3314, 3326, 3344, 3416 - - Partially implemented -
    - - PRQA QA-C++ - - - 4.4 - - 4071, 4074 - -
    - - PVS-Studio - - - 7.18 - - V559 - , - V633 - , - V699 - -
    - - RuleChecker - - - 20.10 - - assignment-conditional - - Fully checked -
    - - SonarQube C/C++ Plugin - - - 3.11 - - AssignmentInSubExpression - -
    -
    -
    -

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    -
    -
    -

    Key here (explains table format and definitions)

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - Taxonomy - - Taxonomy item - - Relationship -
    - - CERT C - - - - EXP19-CPP. Do not perform assignments in conditional expressions - - - Prior to 2018-01-12: CERT: Unspecified Relationship -
    - - CERT Oracle Secure Coding Standard for Java - - - - EXP51-J. Do not perform assignments in conditional expressions - - - Prior to 2018-01-12: CERT: Unspecified Relationship -
    - - ISO/IEC TR 24772:2013 - - - Likely Incorrect Expression [KOA] - - Prior to 2018-01-12: CERT: Unspecified Relationship -
    - - ISO/IEC TS 17961 - - - No assignment in conditional expressions [boolasgn] - - Prior to 2018-01-12: CERT: Unspecified Relationship -
    - - CWE 2.11 - - - - CWE-480 - - , Use of Incorrect Operator - - 2017-07-05: CERT: Rule subset of CWE -
    - - CWE 2.11 - - - - CWE-481 - - - 2017-07-05: CERT: Rule subset of CWE -
    -
    -
    -

    Key here for mapping notes

    -

    CWE-480 and EXP45-C

    -

    Intersection( EXP45-C, EXP46-C) = Ø

    -

    CWE-480 = Union( EXP45-C, list) where list =

    -
      -
    • Usage of incorrect operator besides s/=/==/
    • -
    -

    CWE-569 and EXP45-C

    -

    CWE-480 = Subset( CWE-569)

    -
    -
    - - - - - - - - - - - -
    - [ - - Dutta 03 - - ] - - "Best Practices for Programming in C" -
    - [ - - Hatton 1995 - - ] - - Section 2.7.2, "Errors of Omission and Addition" -
    -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements.md b/c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements.md new file mode 100644 index 0000000000..7576bc7a61 --- /dev/null +++ b/c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements.md @@ -0,0 +1,212 @@ +# EXP45-C: Do not perform assignments in selection statements + +This query implements the CERT-C rule EXP45-C: + +> Do not perform assignments in selection statements + + +## Description + +Do not use the assignment operator in the contexts listed in the following table because doing so typically indicates programmer error and can result in [unexpected behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-unexpectedbehavior). + +
    Operator Context
    if Controlling expression
    while Controlling expression
    do ... while Controlling expression
    for Second operand
    ?: First operand
    ?: Second or third operands, where the ternary expression is used in any of these contexts
    && Either operand
    || either operand
    , Second operand, when the comma expression is used in any of these contexts
    +Performing assignment statements in other contexts do not violate this rule. However, they may violate other rules, such as [EXP30-C. Do not depend on the order of evaluation for side effects](https://wiki.sei.cmu.edu/confluence/display/c/EXP30-C.+Do+not+depend+on+the+order+of+evaluation+for+side+effects). + + +Noncompliant Code Example + +In this noncompliant code example, an assignment expression is the outermost expression in an `if` statement: + +```cpp +if (a = b) { + /* ... */ +} + +``` +Although the intent of the code may be to assign `b` to `a` and test the value of the result for equality to 0, it is frequently a case of the programmer mistakenly using the assignment operator `=` instead of the equals operator `==`. Consequently, many compilers will warn about this condition, making this coding error detectable by adhering to [MSC00-C. Compile cleanly at high warning levels](https://wiki.sei.cmu.edu/confluence/display/c/MSC00-C.+Compile+cleanly+at+high+warning+levels). + +## Compliant Solution (Unintentional Assignment) + +When the assignment of `b` to `a` is not intended, the conditional block is now executed when `a` is equal to `b`: + +```cpp +if (a == b) { + /* ... */ +} + +``` + +## Compliant Solution (Intentional Assignment) + +When the assignment is intended, this compliant solution explicitly uses inequality as the outermost expression while performing the assignment in the inner expression: + +```cpp +if ((a = b) != 0) { + /* ... */ +} + +``` +It is less desirable in general, depending on what was intended, because it mixes the assignment in the condition, but it is clear that the programmer intended the assignment to occur. + +## Noncompliant Code Example + +In this noncompliant code example, the expression `x = y` is used as the controlling expression of the `while` statement: + +```cpp + do { /* ... */ } while (foo(), x = y); +``` + +## Compliant Solution (Unintentional Assignment) + +When the assignment of y to x is not intended, the conditional block should be executed only when x is equal to y, as in this compliant solution: + +```cpp +do { /* ... */ } while (foo(), x == y); + +``` + +## Compliant Solution (Intentional Assignment) + +When the assignment is intended, this compliant solution can be used: + +```cpp +do { /* ... */ } while (foo(), (x = y) != 0); + +``` + +## Compliant Solution (for statement) + +The same result can be obtained using the `for` statement, which is specifically designed to evaluate an expression on each iteration of the loop, just before performing the test in its controlling expression. Remember that its controlling expression is the second operand, where the assignment occurs in its third operand: + +```cpp + for (; x; foo(), x = y) { /* ... */ } +``` + +## Noncompliant Code Example + +In this noncompliant example, the expression `p = q` is used as the controlling expression of the `while` statement: + +```cpp + do { /* ... */ } while (x = y, p = q); +``` + +## Compliant Solution + +In this compliant solution, the expression `x = y` is not used as the controlling expression of the `while` statement: + +```cpp +do { /* ... */ } while (x = y, p == q); + +``` + +## Noncompliant Code Example + +This noncompliant code example has a typo that results in an assignment rather than a comparison. + +```cpp +while (ch = '\t' || ch == ' ' || ch == '\n') { + /* ... */ +} + +``` +Many compilers will warn about this condition. This coding error would typically be eliminated by adherence to [MSC00-C. Compile cleanly at high warning levels](https://wiki.sei.cmu.edu/confluence/display/c/MSC00-C.+Compile+cleanly+at+high+warning+levels). Although this code compiles, it will cause [unexpected behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-unexpectedbehavior) to an unsuspecting programmer. If the intent was to verify a string such as a password, user name, or group user ID, the code may produce significant [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) and require significant debugging. + +## Compliant Solution (RHS Variable) + +When comparisons are made between a variable and a literal or const-qualified variable, placing the variable on the right of the comparison operation can prevent a spurious assignment. + +In this code example, the literals are placed on the left-hand side of each comparison. If the programmer were to inadvertently use an assignment operator, the statement would assign `ch` to `'\t'`, which is invalid and produces a diagnostic message. + +```cpp +while ('\t' = ch || ' ' == ch || '\n' == ch) { + /* ... */ +} +``` +Due to the diagnostic, the typo will be easily spotted and fixed. + +```cpp +while ('\t' == ch || ' ' == ch || '\n' == ch) { + /* ... */ +} +``` +As a result, any mistaken use of the assignment operator that could otherwise create a [vulnerability](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) for operations such as string verification will result in a compiler diagnostic regardless of compiler, warning level, or [implementation](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-implementation). + +## Exceptions + +**EXP45-C-EX1**:****Assignment can be used where the result of the assignment is itself an operand to a comparison expression or relational expression. In this compliant example, the expression `x = y` is itself an operand to a comparison operation: + +```cpp +if ((x = y) != 0) { /* ... */ } +``` +**EXP45-C-EX2**:****Assignment can be used where the expression consists of a single primary expression. The following code is compliant because the expression `x = y` is a single primary expression: + +```cpp +if ((x = y)) { /* ... */ } +``` +The following controlling expression is noncompliant because `&&` is not a comparison or relational operator and the entire expression is not primary: + +```cpp +if ((v = w) && flag) { /* ... */ } +``` +When the assignment of `v` to `w` is not intended, the following controlling expression can be used to execute the conditional block when `v` is equal to `w`: + +```cpp +if ((v == w) && flag) { /* ... */ }; +``` +When the assignment is intended, the following controlling expression can be used: + +```cpp +if (((v = w) != 0) && flag) { /* ... */ }; +``` +**EXP45-C-EX3**:****Assignment can be used in a function argument or array index. In this compliant solution, the expression `x = y` is used in a function argument: + +```cpp +if (foo(x = y)) { /* ... */ } +``` + +## Risk Assessment + +Errors of omission can result in unintended program flow. + +
    Recommendation Severity Likelihood Remediation Cost Priority Level
    EXP45-C Low Likely Medium P6 L2
    + + +## Automated Detection + +
    Tool Version Checker Description
    Astrée 20.10 assignment-conditional Fully checked
    Axivion Bauhaus Suite 7.2.0 CertC-EXP45
    Clang 3.9 -Wparentheses Can detect some instances of this rule, but does not detect all
    CodeSonar 6.2p0 LANG.STRUCT.CONDASSIGLANG.STRUCT.SE.CONDLANG.STRUCT.USEASSIGN Assignment in conditional Condition contains side effects Assignment result in expression
    Compass/ROSE Could detect violations of this recommendation by identifying any assignment expression as the top-level expression in an if or while statement
    ECLAIR 1.2 CC2.EXP18 CC2.EXP21 Fully implemented
    GCC 4.3.5 Can detect violations of this recommendation when the -Wall flag is used
    Helix QAC 2022.1 C3314, C3326, C3344, C3416 C++4071, C++4074
    Klocwork 2022.1 ASSIGCOND.CALL ASSIGCOND.GENMISRA.ASSIGN.COND
    LDRA tool suite 9.7.1 114 S, 132 S Enhanced Enforcement
    Parasoft C/C++test 2021.2 CERT_C-EXP45-b CERT_C-EXP45-d Assignment operators shall not be used in conditions without brackets Assignment operators shall not be used in expressions that yield a Boolean value
    PC-lint Plus 1.4 720 Partially supported: reports Boolean test of unparenthesized assignment
    Polyspace Bug Finder R2021a CERT C: Rule EXP45-C Checks for invalid use of = (assignment) operator (rule fully covered)
    PRQA QA-C 9.7 3314, 3326, 3344, 3416 Partially implemented
    PRQA QA-C++ 4.4 4071, 4074
    PVS-Studio 7.18 V559 , V633 , V699
    RuleChecker 20.10 assignment-conditional Fully checked
    SonarQube C/C++ Plugin 3.11 AssignmentInSubExpression
    + + +## Related Vulnerabilities + +Search for [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) resulting from the violation of this rule on the [CERT website](https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+EXP45-C). + +## Related Guidelines + +[Key here](https://wiki.sei.cmu.edu/confluence/display/c/How+this+Coding+Standard+is+Organized#HowthisCodingStandardisOrganized-RelatedGuidelines) (explains table format and definitions) + +
    Taxonomy Taxonomy item Relationship
    CERT C EXP19-CPP. Do not perform assignments in conditional expressions Prior to 2018-01-12: CERT: Unspecified Relationship
    CERT Oracle Secure Coding Standard for Java EXP51-J. Do not perform assignments in conditional expressions Prior to 2018-01-12: CERT: Unspecified Relationship
    ISO/IEC TR 24772:2013 Likely Incorrect Expression \[KOA\] Prior to 2018-01-12: CERT: Unspecified Relationship
    ISO/IEC TS 17961 No assignment in conditional expressions \[boolasgn\] Prior to 2018-01-12: CERT: Unspecified Relationship
    CWE 2.11 CWE-480 , Use of Incorrect Operator 2017-07-05: CERT: Rule subset of CWE
    CWE 2.11 CWE-481 2017-07-05: CERT: Rule subset of CWE
    + + +## CERT-CWE Mapping Notes + +[Key here](https://wiki.sei.cmu.edu/confluence/pages/viewpage.action?pageId=87152408#HowthisCodingStandardisOrganized-CERT-CWEMappingNotes) for mapping notes + +**CWE-480 and EXP45-C** + +Intersection( EXP45-C, EXP46-C) = Ø + +CWE-480 = Union( EXP45-C, list) where list = + +* Usage of incorrect operator besides s/=/==/ +**CWE-569 and EXP45-C** + +CWE-480 = Subset( CWE-569) + +## Bibliography + +
    \[ Dutta 03 \] "Best Practices for Programming in C"
    \[ Hatton 1995 \] Section 2.7.2, "Errors of Omission and Addition"
    + + +## References + +* CERT-C: [EXP45-C: Do not perform assignments in selection statements](https://wiki.sei.cmu.edu/confluence/display/c) diff --git a/c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements.qhelp b/c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements.qhelp deleted file mode 100644 index 82c72bc417..0000000000 --- a/c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements.qhelp +++ /dev/null @@ -1,18 +0,0 @@ - - - - -

    This query implements the CERT-C rule EXP45-C:

    -
    -

    Do not perform assignments in selection statements

    -
    -
    - - -
  • - CERT-C: - EXP45-C: Do not perform assignments in selection statements - . -
  • -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/EXP45-C/standard-example.c b/c/cert/src/rules/EXP45-C/standard-example.c deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/c/cert/src/rules/FIO30-C/ExcludeUserInputFromFormatStrings-standard.qhelp b/c/cert/src/rules/FIO30-C/ExcludeUserInputFromFormatStrings-standard.qhelp deleted file mode 100644 index 53396c7e5b..0000000000 --- a/c/cert/src/rules/FIO30-C/ExcludeUserInputFromFormatStrings-standard.qhelp +++ /dev/null @@ -1,585 +0,0 @@ - - -
    -

    Never call a formatted I/O function with a format string containing a tainted value . An attacker who can fully or partially control the contents of a format string can crash a vulnerable process, view the contents of the stack, view memory content, or write to an arbitrary memory location. Consequently, the attacker can execute arbitrary code with the permissions of the vulnerable process [Seacord 2013b]. Formatted output functions are particularly dangerous because many programmers are unaware of their capabilities. For example, formatted output functions can be used to write an integer value to a specified address using the %n conversion specifier.

    -
    -
    -

    The incorrect_password() function in this noncompliant code example is called during identification and authentication to display an error message if the specified user is not found or the password is incorrect. The function accepts the name of the user as a string referenced by user. This is an exemplar of untrusted data that originates from an unauthenticated user. The function constructs an error message that is then output to stderr using the C Standard fprintf() function.

    - #include <stdio.h> -#include <stdlib.h> -#include <string.h> - -void incorrect_password(const char *user) { - int ret; - /* User names are restricted to 256 or fewer characters */ - static const char msg_format[] = "%s cannot be authenticated.\n"; - size_t len = strlen(user) + sizeof(msg_format); - char *msg = (char *)malloc(len); - if (msg == NULL) { - /* Handle error */ - } - ret = snprintf(msg, len, msg_format, user); - if (ret < 0) { - /* Handle error */ - } else if (ret >= len) { - /* Handle truncated output */ - } - fprintf(stderr, msg); - free(msg); -} - -

    The incorrect_password() function calculates the size of the message, allocates dynamic storage, and then constructs the message in the allocated memory using the snprintf() function. The addition operations are not checked for integer overflow because the string referenced by user is known to have a length of 256 or less. Because the %s characters are replaced by the string referenced by user in the call to snprintf(), the resulting string needs 1 byte less than is allocated. The snprintf() function is commonly used for messages that are displayed in multiple locations or messages that are difficult to build. However, the resulting code contains a format-string vulnerability because the msg includes untrusted user input and is passed as the format-string argument in the call to fprintf().

    -
    -
    -

    This compliant solution fixes the problem by replacing the fprintf() call with a call to fputs(), which outputs msg directly to stderr without evaluating its contents:

    - #include <stdio.h> -#include <stdlib.h> -#include <string.h> - -void incorrect_password(const char *user) { - int ret; - /* User names are restricted to 256 or fewer characters */ - static const char msg_format[] = "%s cannot be authenticated.\n"; - size_t len = strlen(user) + sizeof(msg_format); - char *msg = (char *)malloc(len); - if (msg == NULL) { - /* Handle error */ - } - ret = snprintf(msg, len, msg_format, user); - if (ret < 0) { - /* Handle error */ - } else if (ret >= len) { - /* Handle truncated output */ - } - fputs(msg, stderr); - free(msg); -} - -
    -
    -

    This compliant solution passes the untrusted user input as one of the variadic arguments to fprintf() and not as part of the format string, eliminating the possibility of a format-string vulnerability:

    - #include <stdio.h> - -void incorrect_password(const char *user) { - static const char msg_format[] = "%s cannot be authenticated.\n"; - fprintf(stderr, msg_format, user); -} - -
    -
    -

    This noncompliant code example is similar to the first noncompliant code example but uses the POSIX function syslog() [IEEE Std 1003.1:2013] instead of the fprintf() function. The syslog() function is also susceptible to format-string vulnerabilities.

    - #include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <syslog.h> - -void incorrect_password(const char *user) { - int ret; - /* User names are restricted to 256 or fewer characters */ - static const char msg_format[] = "%s cannot be authenticated.\n"; - size_t len = strlen(user) + sizeof(msg_format); - char *msg = (char *)malloc(len); - if (msg == NULL) { - /* Handle error */ - } - ret = snprintf(msg, len, msg_format, user); - if (ret < 0) { - /* Handle error */ - } else if (ret >= len) { - /* Handle truncated output */ - } - syslog(LOG_INFO, msg); - free(msg); -} - -

    The syslog() function first appeared in BSD 4.2 and is supported by Linux and other modern UNIX implementations. It is not available on Windows systems.

    -
    -
    -

    This compliant solution passes the untrusted user input as one of the variadic arguments to syslog() instead of including it in the format string:

    - #include <syslog.h> - -void incorrect_password(const char *user) { - static const char msg_format[] = "%s cannot be authenticated.\n"; - syslog(LOG_INFO, msg_format, user); -} - -
    -
    -

    Failing to exclude user input from format specifiers may allow an attacker to crash a vulnerable process, view the contents of the stack, view memory content, or write to an arbitrary memory location and consequently execute arbitrary code with the permissions of the vulnerable process.

    - - - - - - - - - - - - - - - - - - - -
    - Rule - - Severity - - Likelihood - - Remediation Cost - - Priority - - Level -
    - FIO30-C - - High - - Likely - - Medium - - P18 - - L1 -
    -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - Tool - - Version - - Checker - - Description -
    - - Astrée - - - 20.10 - - - Supported via stubbing/taint analysis -
    - - Axivion Bauhaus Suite - - - 7.2.0 - - CertC-FIO30 - - Partially implemented -
    - - CodeSonar - - - 6.2p0 - - IO.INJ.FMT - MISC.FMT - - Format string injection - Format string -
    - - Compass/ROSE - - - - -
    - - Coverity - - - 2017.07 - - TAINTED_STRING - - Implemented -
    - - GCC - - - 4.3.5 - - - Can detect violations of this rule when the - -Wformat-security - flag is used -
    - - Helix QAC - - - 2021.3 - - C4916, C4917, C4918 - C++4916, C++4917, C++4918 - -
    - - Klocwork - - - 2021.4 - - SV.FMTSTR.GENERIC - SV.TAINTED.FMTSTR - -
    - - LDRA tool suite - - - 9.7.1 - - 86 D - - Partially Implemented -
    - - Parasoft C/C++test - - - 2021.2 - - CERT_C-FIO30-a - CERT_C-FIO30-b - CERT_C-FIO30-c - - Avoid calling functions printf/wprintf with only one argument other than string constant - Avoid using functions fprintf/fwprintf with only two parameters, when second parameter is a variable - Never use unfiltered data from an untrusted user as the format parameter -
    - - PC-lint Plus - - - 1.4 - - 592 - - Partially supported: reports non-literal format strings -
    - - Polyspace Bug Finder - - - R2021a - - - CERT C: Rule FIO30-C - - - Checks for tainted string format (rule partially covered) -
    - - PRQA QA-C - - - 9.7 - - 4916, 4917, 4918 - -
    - - PRQA QA-C++ - - - 4.4 - - 4916, 4917, 4918 - -
    - - PVS-Studio - - - 7.17 - - V618 - -
    - - Splint - - - 3.1.1 - - -
    -
    -
    -

    Two examples of format-string vulnerabilities resulting from a violation of this rule include Ettercap and Samba.

    -

    In Ettercap v.NG-0.7.2, the ncurses user interface suffers from a format-string defect. The curses_msg() function in ec_curses.c calls wdg_scroll_print(), which takes a format string and its parameters and passes it to vw_printw(). The curses_msg() function uses one of its parameters as the format string. This input can include user data, allowing for a format-string vulnerability.

    -

    The Samba AFS ACL mapping VFS plug-in fails to properly sanitize user-controlled file names that are used in a format specifier supplied to snprintf(). This security flaw becomes exploitable when a user can write to a share that uses Samba's afsacl.so library for setting Windows NT access control lists on files residing on an AFS file system.

    -

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    -
    -
    -

    Key here (explains table format and definitions)

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - Taxonomy - - Taxonomy item - - Relationship -
    - - CERT Oracle Secure Coding Standard for Java - - - - IDS06-J. Exclude unsanitized user input from format strings - - - Prior to 2018-01-12: CERT: Unspecified Relationship -
    - - CERT Perl Secure Coding Standard - - - - IDS30-PL. Exclude user input from format strings - - - Prior to 2018-01-12: CERT: Unspecified Relationship -
    - - ISO/IEC TR 24772:2013 - - - Injection [RST] - - Prior to 2018-01-12: CERT: Unspecified Relationship -
    - - ISO/IEC TS 17961:2013 - - - Including tainted or out-of-domain input in a format string [usrfmt] - - Prior to 2018-01-12: CERT: Unspecified Relationship -
    - - CWE 2.11 - - - - CWE-134 - - , Uncontrolled Format String - - 2017-05-16: CERT: Exact -
    - - CWE 2.11 - - - - CWE-20 - - , Improper Input Validation - - 2017-05-17: CERT: Rule subset of CWE -
    -
    -
    - - - - - - - - - - - - - - - -
    - [ - - IEEE Std 1003.1:2013 - - ] - - XSH, System Interfaces, - syslog -
    - [ - - Seacord 2013b - - ] - - Chapter 6, "Formatted Output" -
    - [ - - Viega 2005 - - ] - - Section 5.2.23, "Format String Problem" -
    -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO30-C/ExcludeUserInputFromFormatStrings.md b/c/cert/src/rules/FIO30-C/ExcludeUserInputFromFormatStrings.md new file mode 100644 index 0000000000..1d72ebd079 --- /dev/null +++ b/c/cert/src/rules/FIO30-C/ExcludeUserInputFromFormatStrings.md @@ -0,0 +1,169 @@ +# FIO30-C: Exclude user input from format strings + +This query implements the CERT-C rule FIO30-C: + +> Exclude user input from format strings + + +## Description + +Never call a formatted I/O function with a format string containing a [tainted value ](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-taintedvalue). An attacker who can fully or partially control the contents of a format string can crash a vulnerable process, view the contents of the stack, view memory content, or write to an arbitrary memory location. Consequently, the attacker can execute arbitrary code with the permissions of the vulnerable process \[[Seacord 2013b](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-Seacord2013)\]. Formatted output functions are particularly dangerous because many programmers are unaware of their capabilities. For example, formatted output functions can be used to write an integer value to a specified address using the `%n` conversion specifier. + +## Noncompliant Code Example + +The `incorrect_password()` function in this noncompliant code example is called during identification and authentication to display an error message if the specified user is not found or the password is incorrect. The function accepts the name of the user as a string referenced by `user`. This is an exemplar of [untrusted data](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-untrusteddata) that originates from an unauthenticated user. The function constructs an error message that is then output to `stderr` using the C Standard `fprintf()` function. + +```cpp +#include +#include +#include + +void incorrect_password(const char *user) { + int ret; + /* User names are restricted to 256 or fewer characters */ + static const char msg_format[] = "%s cannot be authenticated.\n"; + size_t len = strlen(user) + sizeof(msg_format); + char *msg = (char *)malloc(len); + if (msg == NULL) { + /* Handle error */ + } + ret = snprintf(msg, len, msg_format, user); + if (ret < 0) { + /* Handle error */ + } else if (ret >= len) { + /* Handle truncated output */ + } + fprintf(stderr, msg); + free(msg); +} + +``` +The `incorrect_password()` function calculates the size of the message, allocates dynamic storage, and then constructs the message in the allocated memory using the `snprintf()` function. The addition operations are not checked for integer overflow because the string referenced by `user` is known to have a length of 256 or less. Because the `%s` characters are replaced by the string referenced by `user` in the call to `snprintf()`, the resulting string needs 1 byte less than is allocated. The `snprintf()` function is commonly used for messages that are displayed in multiple locations or messages that are difficult to build. However, the resulting code contains a format-string [vulnerability](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) because the `msg` includes untrusted user input and is passed as the format-string argument in the call to `fprintf()`. + +## Compliant Solution (fputs()) + +This compliant solution fixes the problem by replacing the `fprintf()` call with a call to `fputs()`, which outputs `msg` directly to `stderr` without evaluating its contents: + +```cpp +#include +#include +#include + +void incorrect_password(const char *user) { + int ret; + /* User names are restricted to 256 or fewer characters */ + static const char msg_format[] = "%s cannot be authenticated.\n"; + size_t len = strlen(user) + sizeof(msg_format); + char *msg = (char *)malloc(len); + if (msg == NULL) { + /* Handle error */ + } + ret = snprintf(msg, len, msg_format, user); + if (ret < 0) { + /* Handle error */ + } else if (ret >= len) { + /* Handle truncated output */ + } + fputs(msg, stderr); + free(msg); +} + +``` + +## Compliant Solution (fprintf()) + +This compliant solution passes the untrusted user input as one of the variadic arguments to `fprintf()` and not as part of the format string, eliminating the possibility of a format-string vulnerability: + +```cpp +#include + +void incorrect_password(const char *user) { + static const char msg_format[] = "%s cannot be authenticated.\n"; + fprintf(stderr, msg_format, user); +} + +``` + +## Noncompliant Code Example (POSIX) + +This noncompliant code example is similar to the first noncompliant code example but uses the POSIX function `syslog()` \[[IEEE Std 1003.1:2013](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-IEEEStd1003.1-2013)\] instead of the `fprintf()` function. The `syslog()` function is also susceptible to format-string vulnerabilities. + +```cpp +#include +#include +#include +#include + +void incorrect_password(const char *user) { + int ret; + /* User names are restricted to 256 or fewer characters */ + static const char msg_format[] = "%s cannot be authenticated.\n"; + size_t len = strlen(user) + sizeof(msg_format); + char *msg = (char *)malloc(len); + if (msg == NULL) { + /* Handle error */ + } + ret = snprintf(msg, len, msg_format, user); + if (ret < 0) { + /* Handle error */ + } else if (ret >= len) { + /* Handle truncated output */ + } + syslog(LOG_INFO, msg); + free(msg); +} + +``` +The `syslog()` function first appeared in BSD 4.2 and is supported by Linux and other modern UNIX implementations. It is not available on Windows systems. + +## Compliant Solution (POSIX) + +This compliant solution passes the untrusted user input as one of the variadic arguments to `syslog()` instead of including it in the format string: + +```cpp +#include + +void incorrect_password(const char *user) { + static const char msg_format[] = "%s cannot be authenticated.\n"; + syslog(LOG_INFO, msg_format, user); +} + +``` + +## Risk Assessment + +Failing to exclude user input from format specifiers may allow an attacker to crash a vulnerable process, view the contents of the stack, view memory content, or write to an arbitrary memory location and consequently execute arbitrary code with the permissions of the vulnerable process. + +
    Rule Severity Likelihood Remediation Cost Priority Level
    FIO30-C High Likely Medium P18 L1
    + + +## Automated Detection + +
    Tool Version Checker Description
    Astrée 20.10 Supported via stubbing/taint analysis
    Axivion Bauhaus Suite 7.2.0 CertC-FIO30 Partially implemented
    CodeSonar 6.2p0 IO.INJ.FMT MISC.FMT Format string injection Format string
    Compass/ROSE
    Coverity 2017.07 TAINTED_STRING Implemented
    GCC 4.3.5 Can detect violations of this rule when the -Wformat-security flag is used
    Helix QAC 2021.3 C4916, C4917, C4918 C++4916, C++4917, C++4918
    Klocwork 2021.4 SV.FMTSTR.GENERIC SV.TAINTED.FMTSTR
    LDRA tool suite 9.7.1 86 D Partially Implemented
    Parasoft C/C++test 2021.2 CERT_C-FIO30-a CERT_C-FIO30-b CERT_C-FIO30-c Avoid calling functions printf/wprintf with only one argument other than string constant Avoid using functions fprintf/fwprintf with only two parameters, when second parameter is a variable Never use unfiltered data from an untrusted user as the format parameter
    PC-lint Plus 1.4 592 Partially supported: reports non-literal format strings
    Polyspace Bug Finder R2021a CERT C: Rule FIO30-C Checks for tainted string format (rule partially covered)
    PRQA QA-C 9.7 4916, 4917, 4918
    PRQA QA-C++ 4.4 4916, 4917, 4918
    PVS-Studio 7.17 V618
    Splint 3.1.1
    + + +## Related Vulnerabilities + +Two examples of format-string vulnerabilities resulting from a violation of this rule include [Ettercap](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-VU286468) and [Samba](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-VU649732). + +In Ettercap v.NG-0.7.2, the `ncurses` user interface suffers from a format-string defect. The `curses_msg()` function in `ec_curses.c` calls `wdg_scroll_print()`, which takes a format string and its parameters and passes it to `vw_printw()`. The `curses_msg()` function uses one of its parameters as the format string. This input can include user data, allowing for a format-string vulnerability. + +The Samba AFS ACL mapping VFS plug-in fails to properly [sanitize](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-sanitize) user-controlled file names that are used in a format specifier supplied to `snprintf()`. This [security flaw](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-securityflaw) becomes exploitable when a user can write to a share that uses Samba's `afsacl.so` library for setting Windows NT access control lists on files residing on an AFS file system. + +Search for [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) resulting from the violation of this rule on the [CERT website](https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+FIO30-C). + +## Related Guidelines + +[Key here](https://wiki.sei.cmu.edu/confluence/display/c/How+this+Coding+Standard+is+Organized#HowthisCodingStandardisOrganized-RelatedGuidelines) (explains table format and definitions) + +
    Taxonomy Taxonomy item Relationship
    CERT Oracle Secure Coding Standard for Java IDS06-J. Exclude unsanitized user input from format strings Prior to 2018-01-12: CERT: Unspecified Relationship
    CERT Perl Secure Coding Standard IDS30-PL. Exclude user input from format strings Prior to 2018-01-12: CERT: Unspecified Relationship
    ISO/IEC TR 24772:2013 Injection \[RST\] Prior to 2018-01-12: CERT: Unspecified Relationship
    ISO/IEC TS 17961:2013 Including tainted or out-of-domain input in a format string \[usrfmt\] Prior to 2018-01-12: CERT: Unspecified Relationship
    CWE 2.11 CWE-134 , Uncontrolled Format String 2017-05-16: CERT: Exact
    CWE 2.11 CWE-20 , Improper Input Validation 2017-05-17: CERT: Rule subset of CWE
    + + +## Bibliography + +
    \[ IEEE Std 1003.1:2013 \] XSH, System Interfaces, syslog
    \[ Seacord 2013b \] Chapter 6, "Formatted Output"
    \[ Viega 2005 \] Section 5.2.23, "Format String Problem"
    + + +## References + +* CERT-C: [FIO30-C: Exclude user input from format strings](https://wiki.sei.cmu.edu/confluence/display/c) diff --git a/c/cert/src/rules/FIO30-C/ExcludeUserInputFromFormatStrings.qhelp b/c/cert/src/rules/FIO30-C/ExcludeUserInputFromFormatStrings.qhelp deleted file mode 100644 index c289d0a58b..0000000000 --- a/c/cert/src/rules/FIO30-C/ExcludeUserInputFromFormatStrings.qhelp +++ /dev/null @@ -1,18 +0,0 @@ - - - - -

    This query implements the CERT-C rule FIO30-C:

    -
    -

    Exclude user input from format strings

    -
    -
    - - -
  • - CERT-C: - FIO30-C: Exclude user input from format strings - . -
  • -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO30-C/standard-example.c b/c/cert/src/rules/FIO30-C/standard-example.c deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/c/cert/src/rules/FIO32-C/DoNotPerformFileOperationsOnDevices-standard.qhelp b/c/cert/src/rules/FIO32-C/DoNotPerformFileOperationsOnDevices-standard.qhelp deleted file mode 100644 index 44fd54fffd..0000000000 --- a/c/cert/src/rules/FIO32-C/DoNotPerformFileOperationsOnDevices-standard.qhelp +++ /dev/null @@ -1,594 +0,0 @@ - - -
    -

    File names on many operating systems, including Windows and UNIX, may be used to access special files, which are actually devices. Reserved Microsoft Windows device names include AUX, CON, PRN, COM1, and LPT1 or paths using the \\.\ device namespace. Device files on UNIX systems are used to apply access rights and to direct operations on the files to the appropriate device drivers.

    -

    Performing operations on device files that are intended for ordinary character or binary files can result in crashes and denial-of-service attacks. For example, when Windows attempts to interpret the device name as a file resource, it performs an invalid resource access that usually results in a crash [Howard 2002].

    -

    Device files in UNIX can be a security risk when an attacker can access them in an unauthorized way. For example, if attackers can read or write to the /dev/kmem device, they may be able to alter the priority, UID, or other attributes of their process or simply crash the system. Similarly, access to disk devices, tape devices, network devices, and terminals being used by other processes can lead to problems [Garfinkel 1996].

    -

    On Linux, it is possible to lock certain applications by attempting to open devices rather than files. Consider the following example:

    - /dev/mouse -/dev/console -/dev/tty0 -/dev/zero - -

    A Web browser that failed to check for these devices would allow an attacker to create a website with image tags such as <IMG src="file:///dev/mouse"> that would lock the user's mouse [Howard 2002].

    -
    -
    -

    In this noncompliant code example, the user can specify a locked device or a FIFO (first-in, first-out) file name, which can cause the program to hang on the call to fopen():

    - #include <stdio.h> -  -void func(const char *file_name) { - FILE *file; - if ((file = fopen(file_name, "wb")) == NULL) { - /* Handle error */ - } - - /* Operate on the file */ - - if (fclose(file) == EOF) { - /* Handle error */ - } -} -
    -
    -

    POSIX defines the O_NONBLOCK flag to open(), which ensures that delayed operations on a file do not hang the program [IEEE Std 1003.1:2013].

    -
    -

    When opening a FIFO with O_RDONLY or O_WRONLY set:

    -
      -
    • If O_NONBLOCK is set, an open() for reading-only returns without delay. An open() for writing-only returns an error if no process currently has the file open for reading.
    • -
    • If O_NONBLOCK is clear, an open() for reading-only blocks the calling thread until a thread opens the file for writing. An open() for writing-only blocks the calling thread until a thread opens the file for reading.
    • -
    -

    When opening a block special or character special file that supports nonblocking opens:

    -
      -
    • If O_NONBLOCK is set, the open() function returns without blocking for the device to be ready or available; subsequent behavior is device-specific.
    • -
    • If O_NONBLOCK is clear, the open() function blocks the calling thread until the device is ready or available before returning.
    • -
    -

    Otherwise, the behavior of O_NONBLOCK is unspecified.

    -
    -

    Once the file is open, programmers can use the POSIX lstat() and fstat() functions to obtain information about a file and the S_ISREG() macro to determine if the file is a regular file. 

    -

    Because the behavior of O_NONBLOCK on subsequent calls to read() or write() is unspecified, it is advisable to disable the flag after it has been determined that the file in question is not a special device.

    -

    When available (Linux 2.1.126+, FreeBSD, Solaris 10, POSIX.1-2008), the O_NOFOLLOW flag should also be used. (See POS01-C. Check for the existence of links when dealing with files.) When O_NOFOLLOW is not available, symbolic link checks should use the method from POS35-C. Avoid race conditions while checking for the existence of a symbolic link.

    - #include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <unistd.h> - -#ifdef O_NOFOLLOW - #define OPEN_FLAGS O_NOFOLLOW | O_NONBLOCK -#else - #define OPEN_FLAGS O_NONBLOCK -#endif - -void func(const char *file_name) { - struct stat orig_st; - struct stat open_st; - int fd; - int flags; - - if ((lstat(file_name, &orig_st) != 0) || - (!S_ISREG(orig_st.st_mode))) { - /* Handle error */ - } - - /* Race window */ - - fd = open(file_name, OPEN_FLAGS | O_WRONLY); - if (fd == -1) { - /* Handle error */ - } - - if (fstat(fd, &open_st) != 0) { - /* Handle error */ - } - - if ((orig_st.st_mode != open_st.st_mode) || - (orig_st.st_ino != open_st.st_ino) || - (orig_st.st_dev != open_st.st_dev)) { - /* The file was tampered with */ - } - - /* - * Optional: drop the O_NONBLOCK now that we are sure - * this is a good file. -  */ - if ((flags = fcntl(fd, F_GETFL)) == -1) { - /* Handle error */ - } - - if (fcntl(fd, F_SETFL, flags & ~O_NONBLOCK) == -1) { - /* Handle error */ - } - - /* Operate on the file */ - - if (close(fd) == -1) { - /* Handle error */ - } -} -

    This code contains an intractable TOCTOU (time-of-check, time-of-use) race condition under which an attacker can alter the file referenced by file_name following the call to lstat() but before the call to open(). The switch will be discovered after the file is opened, but opening the file cannot be prevented in the case where this action itself causes undesired behavior. (See FIO45-C. Avoid TOCTOU race conditions while accessing files for more information about TOCTOU race conditions.)

    -

    Essentially, an attacker can switch out a file for one of the file types shown in the following table with the specified effect.

    -

    File Types and Effects

    - - - - - - - - - - - - - - - - - - - - - - - -
    - Type - - Note on Effect -
    - Another regular file - - The - fstat() - verification fails. -
    - FIFO - - Either - open() - returns - -1 - and sets - errno - to - ENXIO - , or - open() - succeeds and the - fstat() - verification fails. -
    - Symbolic link - - open() - returns - -1 - if - O_NOFOLLOW - is available; otherwise, the - fstat() - verification fails. -
    - Special device - - Usually the - fstat() - verification fails on - st_mode - . This can still be a problem if the device is one for which just opening (or closing) it causes a side effect. If - st_mode - compares equal, then the device is one that, after opening, appears to be a regular file. It would then fail the - fstat() - verification on - st_dev - and - st_ino - (unless it happens to be the - - same - - file, as can happen with - /dev/fd/* - on Solaris, but this would not be a problem). -
    -

    To be compliant with this rule and to prevent this TOCTOU race condition, file_name must refer to a file in a secure directory. (See FIO15-C. Ensure that file operations are performed in a secure directory.)

    -
    -
    -

    This noncompliant code example uses the GetFileType() function to attempt to prevent opening a special file: 

    - #include <Windows.h> - -void func(const TCHAR *file_name) { - HANDLE hFile = CreateFile( - file_name, - GENERIC_READ | GENERIC_WRITE, 0, - NULL, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, NULL - ); - if (hFile == INVALID_HANDLE_VALUE) { - /* Handle error */ - } else if (GetFileType(hFile) != FILE_TYPE_DISK) { - /* Handle error */ - CloseHandle(hFile); - } else { - /* Operate on the file */ - CloseHandle(hFile); - } -} -

    Although tempting, the Win32 GetFileType() function is dangerous in this case. If the file name given identifies a named pipe that is currently blocking on a read request, the call to GetFileType() will block until the read request completes. This provides an effective attack vector for a denial-of-service attack on the application. Furthermore, the act of opening a file handle may cause side effects, such as line states being set to their default voltage when opening a serial device.

    -
    -
    -

    Microsoft documents a list of reserved identifiers that represent devices and have a device namespace to be used specifically by devices [MSDN]. In this compliant solution, the isReservedName() function can be used to determine if a specified path refers to a device. Care must be taken to avoid a TOCTOU race condition when first testing a path name using the isReservedName() function and then later operating on that path name.

    - #include <ctype.h> -#include <stdbool.h> -#include <stdlib.h> -#include <string.h> -#include <stdio.h> - -static bool isReservedName(const char *path) { - /* This list of reserved names comes from MSDN */ - static const char *reserved[] = { - "nul", "con", "prn", "aux", "com1", "com2", "com3", - "com4", "com5", "com6", "com7", "com8", "com9", - "lpt1", "lpt2", "lpt3", "lpt4", "lpt5", "lpt6", - "lpt7", "lpt8", "lpt9" - }; - bool ret = false; - -/* - * First, check to see if this is a device namespace, which - * always starts with \\.\, because device namespaces are not - * valid file paths. - */ - -  if (!path || 0 == strncmp(path, "\\\\.\\", 4)) { - return true; - } - - /* Compare against the list of ancient reserved names */ - for (size_t i = 0; !ret && - i < sizeof(reserved) / sizeof(*reserved); ++i) { - /* - * Because Windows uses a case-insensitive file system, operate on - * a lowercase version of the given filename. Note: This ignores - * globalization issues and assumes ASCII characters. - */ - if (0 == _stricmp(path, reserved[i])) { - ret = true; - } - } - return ret; -} -
    -
    -

    Allowing operations that are appropriate only for regular files to be performed on devices can result in denial-of-service attacks or more serious exploits depending on the platform.

    - - - - - - - - - - - - - - - - - - - -
    - Rule - - Severity - - Likelihood - - Remediation Cost - - Priority - - Level -
    - FIO32-C - - Medium - - Unlikely - - Medium - - P4 - - L3 -
    -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - Tool - - Version - - Checker - - Description -
    - - Compass/ROSE - - - - - Could detect some violations of this rule. This rule applies only to untrusted file name strings, and ROSE cannot tell which strings are trusted and which are not. The best heuristic is to note if there is any verification of the file name before or after the - fopen() - call. If there is any verification, then the file opening should be preceded by an - lstat() - call and succeeded by an - fstat() - call. Although that does not enforce the rule completely, it does indicate that the coder is aware of the - lstat-fopen - - - fstat - idiom -
    - - Helix QAC - - - 2022.1 - - C4921, C4922, C4923 - C++4921, C++4922, C++4923 - -
    - - Parasoft C/C++test - - - 2021.2 - - CERT_C-FIO32-a - - Protect against file name injection -
    - - Polyspace Bug Finder - - - R2022a - - - CERT C: Rule FIO32-C - - - Checks for inappropriate I/O operation on device files (rule fully covered) -
    - - PRQA QA-C - - - 9.7 - - 4921, 4922, 4923 - - Enforced by QAC -
    - - PRQA QA-C++ - - - 4.4 - - 4921, 4922, 4923 - -
    -
    -
    -

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    -
    -
    -

    Key here (explains table format and definitions)

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - Taxonomy - - Taxonomy item - - Relationship -
    - - CERT C Secure Coding Standard - - - - FIO05-C. Identify files using multiple file attributes - - - Prior to 2018-01-12: CERT: Unspecified Relationship -
    - - CERT C Secure Coding Standard - - - - FIO15-C. Ensure that file operations are performed in a secure directory - - - Prior to 2018-01-12: CERT: Unspecified Relationship -
    - - CERT C Secure Coding Standard - - - - POS01-C. Check for the existence of links when dealing with files - - - Prior to 2018-01-12: CERT: Unspecified Relationship -
    - - CERT C Secure Coding Standard - - - - POS35-C. Avoid race conditions while checking for the existence of a symbolic link - - - Prior to 2018-01-12: CERT: Unspecified Relationship -
    - - CERT Oracle Secure Coding Standard for Java - - - - FIO00-J. Do not operate on files in shared directories - - - Prior to 2018-01-12: CERT: Unspecified Relationship -
    -
    -
    -

    Key here for mapping notes

    -

    CWE-67 and FIO32-C

    -

    FIO32-C = Union( CWE-67, list) where list =

    -
      -
    • Treating trusted device names like regular files in Windows.
    • -
    -
      -
    • Treating device names (both trusted and untrusted) like regular files in POSIX
    • -
    -
    -
    - - - - - - - - - - - - - - - - - - - -
    - [ - - Garfinkel 1996 - - ] - - Section 5.6, "Device Files" -
    - [ - - Howard 2002 - - ] - - Chapter 11, "Canonical Representation Issues" -
    - [ - - IEEE Std 1003.1:2013 - - ] - - XSH, System Interfaces, - open -
    - [ - - MSDN - - ] - -
    -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO32-C/DoNotPerformFileOperationsOnDevices.md b/c/cert/src/rules/FIO32-C/DoNotPerformFileOperationsOnDevices.md new file mode 100644 index 0000000000..a52395981d --- /dev/null +++ b/c/cert/src/rules/FIO32-C/DoNotPerformFileOperationsOnDevices.md @@ -0,0 +1,252 @@ +# FIO32-C: Do not perform operations on devices that are only appropriate for files + +This query implements the CERT-C rule FIO32-C: + +> Do not perform operations on devices that are only appropriate for files + + +## Description + +File names on many operating systems, including Windows and UNIX, may be used to access *special files*, which are actually devices. Reserved Microsoft Windows device names include `AUX`, `CON`, `PRN`, `COM1`, and `LPT1` or paths using the `\\.\` device namespace. Device files on UNIX systems are used to apply access rights and to direct operations on the files to the appropriate device drivers. + +Performing operations on device files that are intended for ordinary character or binary files can result in crashes and [denial-of-service attacks](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-denial-of-service). For example, when Windows attempts to interpret the device name as a file resource, it performs an invalid resource access that usually results in a crash \[[Howard 2002](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-Howard02)\]. + +Device files in UNIX can be a security risk when an attacker can access them in an unauthorized way. For example, if attackers can read or write to the `/dev/kmem` device, they may be able to alter the priority, UID, or other attributes of their process or simply crash the system. Similarly, access to disk devices, tape devices, network devices, and terminals being used by other processes can lead to problems \[[Garfinkel 1996](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-Garfinkel96)\]. + +On Linux, it is possible to lock certain applications by attempting to open devices rather than files. Consider the following example: + +```cpp +/dev/mouse +/dev/console +/dev/tty0 +/dev/zero + +``` +A Web browser that failed to check for these devices would allow an attacker to create a website with image tags such as `` that would lock the user's mouse \[[Howard 2002](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-Howard02)\]. + +## Noncompliant Code Example + +In this noncompliant code example, the user can specify a locked device or a FIFO (first-in, first-out) file name, which can cause the program to hang on the call to `fopen()`: + +```cpp +#include +  +void func(const char *file_name) { + FILE *file; + if ((file = fopen(file_name, "wb")) == NULL) { + /* Handle error */ + } + + /* Operate on the file */ + + if (fclose(file) == EOF) { + /* Handle error */ + } +} +``` + +## Compliant Solution (POSIX) + +POSIX defines the `O_NONBLOCK` flag to `open()`, which ensures that delayed operations on a file do not hang the program \[[IEEE Std 1003.1:2013](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-IEEEStd1003.1-2013)\]. + +> When opening a FIFO with `O_RDONLY` or `O_WRONLY` set: + + +* If `O_NONBLOCK` is set, an `open()` for reading-only returns without delay. An `open()` for writing-only returns an error if no process currently has the file open for reading. +* If `O_NONBLOCK` is clear, an `open()` for reading-only blocks the calling thread until a thread opens the file for writing. An `open()` for writing-only blocks the calling thread until a thread opens the file for reading. +When opening a block special or character special file that supports nonblocking opens: +* If `O_NONBLOCK` is set, the `open()` function returns without blocking for the device to be ready or available; subsequent behavior is device-specific. +* If `O_NONBLOCK` is clear, the `open()` function blocks the calling thread until the device is ready or available before returning. +Otherwise, the behavior of `O_NONBLOCK` is unspecified. + +Once the file is open, programmers can use the POSIX `lstat()` and `fstat()` functions to obtain information about a file and the `S_ISREG()` macro to determine if the file is a regular file.  + +Because the behavior of `O_NONBLOCK` on subsequent calls to `read()` or `write()` is [unspecified](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-unspecifiedbehavior), it is advisable to disable the flag after it has been determined that the file in question is not a special device. + +When available (Linux 2.1.126+, FreeBSD, Solaris 10, POSIX.1-2008), the `O_NOFOLLOW` flag should also be used. (See [POS01-C. Check for the existence of links when dealing with files](https://wiki.sei.cmu.edu/confluence/display/c/POS01-C.+Check+for+the+existence+of+links+when+dealing+with+files).) When `O_NOFOLLOW` is not available, symbolic link checks should use the method from [POS35-C. Avoid race conditions while checking for the existence of a symbolic link](https://wiki.sei.cmu.edu/confluence/display/c/POS35-C.+Avoid+race+conditions+while+checking+for+the+existence+of+a+symbolic+link). + +```cpp +#include +#include +#include +#include + +#ifdef O_NOFOLLOW + #define OPEN_FLAGS O_NOFOLLOW | O_NONBLOCK +#else + #define OPEN_FLAGS O_NONBLOCK +#endif + +void func(const char *file_name) { + struct stat orig_st; + struct stat open_st; + int fd; + int flags; + + if ((lstat(file_name, &orig_st) != 0) || + (!S_ISREG(orig_st.st_mode))) { + /* Handle error */ + } + + /* Race window */ + + fd = open(file_name, OPEN_FLAGS | O_WRONLY); + if (fd == -1) { + /* Handle error */ + } + + if (fstat(fd, &open_st) != 0) { + /* Handle error */ + } + + if ((orig_st.st_mode != open_st.st_mode) || + (orig_st.st_ino != open_st.st_ino) || + (orig_st.st_dev != open_st.st_dev)) { + /* The file was tampered with */ + } + + /* + * Optional: drop the O_NONBLOCK now that we are sure + * this is a good file. +  */ + if ((flags = fcntl(fd, F_GETFL)) == -1) { + /* Handle error */ + } + + if (fcntl(fd, F_SETFL, flags & ~O_NONBLOCK) == -1) { + /* Handle error */ + } + + /* Operate on the file */ + + if (close(fd) == -1) { + /* Handle error */ + } +} +``` +This code contains an intractable [TOCTOU (time-of-check, time-of-use)](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-TOCTOU) race condition under which an attacker can alter the file referenced by `file_name` following the call to `lstat()` but before the call to `open()`. The switch will be discovered after the file is opened, but opening the file cannot be prevented in the case where this action itself causes undesired behavior. (See [FIO45-C. Avoid TOCTOU race conditions while accessing files](https://wiki.sei.cmu.edu/confluence/display/c/FIO45-C.+Avoid+TOCTOU+race+conditions+while+accessing+files) for more information about TOCTOU race conditions.) + +Essentially, an attacker can switch out a file for one of the file types shown in the following table with the specified effect. + +File Types and Effects + +
    Type Note on Effect
    Another regular file The fstat() verification fails.
    FIFO Either open() returns -1 and sets errno to ENXIO , or open() succeeds and the fstat() verification fails.
    Symbolic link open() returns -1 if O_NOFOLLOW is available; otherwise, the fstat() verification fails.
    Special device Usually the fstat() verification fails on st_mode . This can still be a problem if the device is one for which just opening (or closing) it causes a side effect. If st_mode compares equal, then the device is one that, after opening, appears to be a regular file. It would then fail the fstat() verification on st_dev and st_ino (unless it happens to be the same file, as can happen with /dev/fd/\* on Solaris, but this would not be a problem).
    +To be compliant with this rule and to prevent this TOCTOU race condition, `file_name` must refer to a file in a secure directory. (See [FIO15-C. Ensure that file operations are performed in a secure directory](https://wiki.sei.cmu.edu/confluence/display/c/FIO15-C.+Ensure+that+file+operations+are+performed+in+a+secure+directory).) + + +## Noncompliant Code Example (Windows) + +This noncompliant code example uses the `GetFileType()` function to attempt to prevent opening a special file:  + +```cpp +#include + +void func(const TCHAR *file_name) { + HANDLE hFile = CreateFile( + file_name, + GENERIC_READ | GENERIC_WRITE, 0, + NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL + ); + if (hFile == INVALID_HANDLE_VALUE) { + /* Handle error */ + } else if (GetFileType(hFile) != FILE_TYPE_DISK) { + /* Handle error */ + CloseHandle(hFile); + } else { + /* Operate on the file */ + CloseHandle(hFile); + } +} +``` +Although tempting, the Win32 `GetFileType()` function is dangerous in this case. If the file name given identifies a named pipe that is currently blocking on a read request, the call to `GetFileType()` will block until the read request completes. This provides an effective attack vector for a [denial-of-service attack](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-denial-of-service) on the application. Furthermore, the act of opening a file handle may cause side effects, such as line states being set to their default voltage when opening a serial device. + +## Compliant Solution (Windows) + +Microsoft documents a list of reserved identifiers that represent devices and have a device namespace to be used specifically by devices \[[MSDN](http://msdn.microsoft.com/en-us/library/aa365247%28v=vs.85%29.aspx)\]. In this compliant solution, the `isReservedName()` function can be used to determine if a specified path refers to a device. Care must be taken to avoid a TOCTOU race condition when first testing a path name using the `isReservedName()` function and then later operating on that path name. + +```cpp +#include +#include +#include +#include +#include + +static bool isReservedName(const char *path) { + /* This list of reserved names comes from MSDN */ + static const char *reserved[] = { + "nul", "con", "prn", "aux", "com1", "com2", "com3", + "com4", "com5", "com6", "com7", "com8", "com9", + "lpt1", "lpt2", "lpt3", "lpt4", "lpt5", "lpt6", + "lpt7", "lpt8", "lpt9" + }; + bool ret = false; + +/* + * First, check to see if this is a device namespace, which + * always starts with \\.\, because device namespaces are not + * valid file paths. + */ + +  if (!path || 0 == strncmp(path, "\\\\.\\", 4)) { + return true; + } + + /* Compare against the list of ancient reserved names */ + for (size_t i = 0; !ret && + i < sizeof(reserved) / sizeof(*reserved); ++i) { + /* + * Because Windows uses a case-insensitive file system, operate on + * a lowercase version of the given filename. Note: This ignores + * globalization issues and assumes ASCII characters. + */ + if (0 == _stricmp(path, reserved[i])) { + ret = true; + } + } + return ret; +} +``` + +## Risk Assessment + +Allowing operations that are appropriate only for regular files to be performed on devices can result in [denial-of-service attacks](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-denial-of-service) or more serious [exploits](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-exploit) depending on the platform. + +
    Rule Severity Likelihood Remediation Cost Priority Level
    FIO32-C Medium Unlikely Medium P4 L3
    + + +## Automated Detection + +
    Tool Version Checker Description
    Compass/ROSE Could detect some violations of this rule. This rule applies only to untrusted file name strings, and ROSE cannot tell which strings are trusted and which are not. The best heuristic is to note if there is any verification of the file name before or after the fopen() call. If there is any verification, then the file opening should be preceded by an lstat() call and succeeded by an fstat() call. Although that does not enforce the rule completely, it does indicate that the coder is aware of the lstat-fopen - fstat idiom
    Helix QAC 2022.1 C4921, C4922, C4923 C++4921, C++4922, C++4923
    Parasoft C/C++test 2021.2 CERT_C-FIO32-a Protect against file name injection
    Polyspace Bug Finder R2022a CERT C: Rule FIO32-C Checks for inappropriate I/O operation on device files (rule fully covered)
    PRQA QA-C 9.7 4921, 4922, 4923 Enforced by QAC
    PRQA QA-C++ 4.4 4921, 4922, 4923
    + + +## Related Vulnerabilities + +Search for [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) resulting from the violation of this rule on the [CERT website](https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+FIO32-C). + +## Related Guidelines + +[Key here](https://wiki.sei.cmu.edu/confluence/display/c/How+this+Coding+Standard+is+Organized#HowthisCodingStandardisOrganized-RelatedGuidelines) (explains table format and definitions) + +
    Taxonomy Taxonomy item Relationship
    CERT C Secure Coding Standard FIO05-C. Identify files using multiple file attributes Prior to 2018-01-12: CERT: Unspecified Relationship
    CERT C Secure Coding Standard FIO15-C. Ensure that file operations are performed in a secure directory Prior to 2018-01-12: CERT: Unspecified Relationship
    CERT C Secure Coding Standard POS01-C. Check for the existence of links when dealing with files Prior to 2018-01-12: CERT: Unspecified Relationship
    CERT C Secure Coding Standard POS35-C. Avoid race conditions while checking for the existence of a symbolic link Prior to 2018-01-12: CERT: Unspecified Relationship
    CERT Oracle Secure Coding Standard for Java FIO00-J. Do not operate on files in shared directories Prior to 2018-01-12: CERT: Unspecified Relationship
    + + +## CERT-CWE Mapping Notes + +[Key here](https://wiki.sei.cmu.edu/confluence/pages/viewpage.action?pageId=87152408#HowthisCodingStandardisOrganized-CERT-CWEMappingNotes) for mapping notes + +**CWE-67 and FIO32-C** + +FIO32-C = Union( CWE-67, list) where list = + +* Treating trusted device names like regular files in Windows. +* Treating device names (both trusted and untrusted) like regular files in POSIX + +## Bibliography + +
    \[ Garfinkel 1996 \] Section 5.6, "Device Files"
    \[ Howard 2002 \] Chapter 11, "Canonical Representation Issues"
    \[ IEEE Std 1003.1:2013 \] XSH, System Interfaces, open
    \[ MSDN \]
    + + +## References + +* CERT-C: [FIO32-C: Do not perform operations on devices that are only appropriate for files](https://wiki.sei.cmu.edu/confluence/display/c) diff --git a/c/cert/src/rules/FIO32-C/DoNotPerformFileOperationsOnDevices.qhelp b/c/cert/src/rules/FIO32-C/DoNotPerformFileOperationsOnDevices.qhelp deleted file mode 100644 index 439daed07c..0000000000 --- a/c/cert/src/rules/FIO32-C/DoNotPerformFileOperationsOnDevices.qhelp +++ /dev/null @@ -1,18 +0,0 @@ - - - - -

    This query implements the CERT-C rule FIO32-C:

    -
    -

    Do not perform operations on devices that are only appropriate for files

    -
    -
    - - -
  • - CERT-C: - FIO32-C: Do not perform operations on devices that are only appropriate for files - . -
  • -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO34-C/DistinguishBetweenCharReadFromAFileAndEofOrWeof-standard.qhelp b/c/cert/src/rules/FIO34-C/DistinguishBetweenCharReadFromAFileAndEofOrWeof-standard.qhelp deleted file mode 100644 index ea25476294..0000000000 --- a/c/cert/src/rules/FIO34-C/DistinguishBetweenCharReadFromAFileAndEofOrWeof-standard.qhelp +++ /dev/null @@ -1,547 +0,0 @@ - - -
    -

    The EOF macro represents a negative value that is used to indicate that the file is exhausted and no data remains when reading data from a file. EOF is an example of an in-band error indicator. In-band error indicators are problematic to work with, and the creation of new in-band-error indicators is discouraged by ERR02-C. Avoid in-band error indicators.

    -

    The byte I/O functions fgetc(), getc(), and getchar() all read a character from a stream and return it as an int. (See STR00-C. Represent characters using an appropriate type.) If the stream is at the end of the file, the end-of-file indicator for the stream is set and the function returns EOF. If a read error occurs, the error indicator for the stream is set and the function returns EOF. If these functions succeed, they cast the character returned into an unsigned char.

    -

    Because EOF is negative, it should not match any unsigned character value. However, this is only true for implementations where the int type is wider than char. On an implementation where int and char have the same width, a character-reading function can read and return a valid character that has the same bit-pattern as EOF. This could occur, for example, if an attacker inserted a value that looked like EOF into the file or data stream to alter the behavior of the program.

    -

    The C Standard requires only that the int type be able to represent a maximum value of +32767 and that a char type be no larger than an int. Although uncommon, this situation can result in the integer constant expression EOF being indistinguishable from a valid character; that is, (int)(unsigned char)65535 == -1. Consequently, failing to use feof() and ferror() to detect end-of-file and file errors can result in incorrectly identifying the EOF character on rare implementations where sizeof(int) == sizeof(char).

    -

    This problem is much more common when reading wide characters. The fgetwc(), getwc(), and getwchar() functions return a value of type wint_t. This value can represent the next wide character read, or it can represent WEOF, which indicates end-of-file for wide character streams. On most implementations, the wchar_t type has the same width as wint_t, and these functions can return a character indistinguishable from WEOF.

    -

    In the UTF-16 character set, 0xFFFF is guaranteed not to be a character, which allows WEOF to be represented as the value -1. Similarly, all UTF-32 characters are positive when viewed as a signed 32-bit integer. All widely used character sets are designed with at least one value that does not represent a character. Consequently, it would require a custom character set designed without consideration of the C programming language for this problem to occur with wide characters or with ordinary characters that are as wide as int.

    -

    The C Standard feof() and ferror() functions are not subject to the problems associated with character and integer sizes and should be used to verify end-of-file and file errors for susceptible implementations [Kettlewell 2002]. Calling both functions on each iteration of a loop adds significant overhead, so a good strategy is to temporarily trust EOF and WEOF within the loop but verify them with feof() and ferror() following the loop.

    -
    -
    -

    This noncompliant code example loops while the character c is not EOF:

    - #include <stdio.h> - -void func(void) { - int c; - - do { - c = getchar(); - } while (c != EOF); -} - -

    Although EOF is guaranteed to be negative and distinct from the value of any unsigned character, it is not guaranteed to be different from any such value when converted to an int. Consequently, when int has the same width as char, this loop may terminate prematurely.

    -
    -
    -

    This compliant solution uses feof() and ferror() to test whether the EOF was an actual character or a real EOF because of end-of-file or errors:

    - #include <stdio.h> - -void func(void) { - int c; - - do { - c = getchar(); - } while (c != EOF || (!feof(stdin) && !ferror(stdin))); -} - -
    -
    -

    This noncompliant code example uses an assertion to ensure that the code is executed only on architectures where int is wider than char and EOF is guaranteed not to be a valid character value. However, this code example is noncompliant because the variable c is declared as a char rather than an int, making it possible for a valid character value to compare equal to the value of the EOF macro when char is signed because of sign extension:

    - #include <assert.h> -#include <limits.h> -#include <stdio.h> - -void func(void) { - char c; - static_assert(UCHAR_MAX < UINT_MAX, "FIO34-C violation"); - - do { - c = getchar(); - } while (c != EOF); -} - -

    Assuming that a char is a signed 8-bit type and an int is a 32-bit type, if getchar() returns the character value '\xff (decimal 255), it will be interpreted as EOF because this value is sign-extended to 0xFFFFFFFF (the value of EOF) to perform the comparison. (See STR34-C. Cast characters to unsigned char before converting to larger integer sizes.)

    -
    -
    -

    This compliant solution declares c to be an int. Consequently, the loop will terminate only when the file is exhausted.

    - #include <assert.h> -#include <stdio.h> -#include <limits.h> - -void func(void) { - int c; - static_assert(UCHAR_MAX < UINT_MAX, "FIO34-C violation"); - - do { - c = getchar(); - } while (c != EOF); -} - -
    -
    -

    In this noncompliant example, the result of the call to the C standard library function getwc() is stored into a variable of type wchar_t and is subsequently compared with WEOF:

    - #include <stddef.h> -#include <stdio.h> -#include <wchar.h> - -enum { BUFFER_SIZE = 32 }; - -void g(void) { - wchar_t buf[BUFFER_SIZE]; - wchar_t wc; - size_t i = 0; - - while ((wc = getwc(stdin)) != L'\n' && wc != WEOF) { - if (i < (BUFFER_SIZE - 1)) { - buf[i++] = wc; - } - } - buf[i] = L'\0'; -} - -

    This code suffers from two problems. First, the value returned by getwc() is immediately converted to wchar_t before being compared with WEOF. Second, there is no check to ensure that wint_t is wider than wchar_t. Both of these problems make it possible for an attacker to terminate the loop prematurely by supplying the wide-character value matching WEOF in the file.

    -
    -
    -

    This compliant solution declares c to be a wint_t to match the integer type returned by getwc(). Furthermore, it does not rely on WEOF to determine end-of-file definitively.

    - #include <stddef.h> -#include <stdio.h> -#include <wchar.h> - -enum {BUFFER_SIZE = 32 } - -void g(void) { - wchar_t buf[BUFFER_SIZE]; - wint_t wc; - size_t i = 0; - - while ((wc = getwc(stdin)) != L'\n' && wc != WEOF) { - if (i < BUFFER_SIZE - 1) { - buf[i++] = wc; - } - } - - if (feof(stdin) || ferror(stdin)) { - buf[i] = L'\0'; - } else { - /* Received a wide character that resembles WEOF; handle error */ - } -} - -
    -
    -

    FIO34-C-EX1: A number of C functions do not return characters but can return EOF as a status code. These functions include fclose(), fflush(), fputs(), fscanf(), puts(), scanf(), sscanf(), vfscanf(), and vscanf(). These return values can be compared to EOF without validating the result.

    -
    -
    -

    Incorrectly assuming characters from a file cannot match EOF or WEOF has resulted in significant vulnerabilities, including command injection attacks. (See the *CA-1996-22 advisory.)

    - - - - - - - - - - - - - - - - - - - -
    - Rule - - Severity - - Likelihood - - Remediation Cost - - Priority - - Level -
    - FIO34-C - - High - - Probable - - Medium - - P12 - - L1 -
    -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - Tool - - Version - - Checker - - Description -
    - - Axivion Bauhaus Suite - - - 7.2.0 - - CertC-FIO34 - -
    - - CodeSonar - - - 6.2p0 - - LANG.CAST.COERCE - - Coercion alters value -
    - - Compass/ROSE - - - - -
    - - Coverity - - - 2017.07 - - CHAR_IO - - Identifies defects when the return value of - fgetc() - , - getc() - , or - getchar() - is incorrectly assigned to a - char - instead of an - int - . Coverity Prevent cannot discover all violations of this rule, so further verification is necessary -
    - - ECLAIR - - - 1.2 - - CC2.FIO34 - - Partially implemented -
    - - Helix QAC - - - 2021.3 - - C2676, C2678 - C++2676, C++2678, C++3001, C++3010, C++3051, C++3137, C++3717 - -
    - - Klocwork - - - 2021.4 - - CWARN.CMPCHR.EOF - -
    - - LDRA tool suite - - - 9.7.1 - - 662 S - - Fully implemented -
    - - Parasoft C/C++test - - - 2021.2 - - CERT_C-FIO34-a - - The macro EOF should be compared with the unmodified return value from the Standard Library function -
    - - Polyspace Bug Finder - - - R2021a - - - CERT C: Rule FIO34-C - - - Checks for character values absorbed into EOF (rule partially covered) -
    - - PRQA QA-C - - - 9.7 - - 2676, 2678 - -
    - - PRQA QA-C++ - - - 4.4 - - 2676, 2678, 3001, 3010, 3051, 3137, 3717 - -
    - - Splint - - - 3.1.1 - - -
    -
    -
    -

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    -
    -
    -

    Key here (explains table format and definitions)

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - Taxonomy - - Taxonomy item - - Relationship -
    - - CERT C Secure Coding Standard - - - - STR00-C. Represent characters using an appropriate type - - - Prior to 2018-01-12: CERT: Unspecified Relationship -
    - - CERT C Secure Coding Standard - - - - INT31-C. Ensure that integer conversions do not result in lost or misinterpreted data - - - Prior to 2018-01-12: CERT: Unspecified Relationship -
    - - CERT Oracle Secure Coding Standard for Java - - - - FIO08-J. Use an int to capture the return value of methods that read a character or byte - - - Prior to 2018-01-12: CERT: Unspecified Relationship -
    - - ISO/IEC TS 17961:2013 - - - Using character values that are indistinguishable from EOF [chreof] - - Prior to 2018-01-12: CERT: Unspecified Relationship -
    - - CWE 2.11 - - - - CWE-197 - - - 2017-06-14: CERT: Rule subset of CWE -
    -
    -
    -

    Key here for mapping notes

    -

    CWE-197 and FIO34-C

    -

    Independent( FLP34-C, INT31-C) FIO34-C = Subset( INT31-C)

    -

    Therefore: FIO34-C = Subset( CWE-197)

    -
    -
    - - - - - - - - - - - - - - - -
    - [ - - Kettlewell 2002 - - ] - - Section 1.2, "< - stdio.h - > and Character Types" -
    - [ - - NIST 2006 - - ] - - SAMATE Reference Dataset Test Case ID 000-000-088 -
    - [ - - Summit 2005 - - ] - - Question 12.2 -
    -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO34-C/DistinguishBetweenCharReadFromAFileAndEofOrWeof.md b/c/cert/src/rules/FIO34-C/DistinguishBetweenCharReadFromAFileAndEofOrWeof.md new file mode 100644 index 0000000000..8f44752d1a --- /dev/null +++ b/c/cert/src/rules/FIO34-C/DistinguishBetweenCharReadFromAFileAndEofOrWeof.md @@ -0,0 +1,202 @@ +# FIO34-C: Distinguish between characters read from a file and EOF or WEOF + +This query implements the CERT-C rule FIO34-C: + +> Distinguish between characters read from a file and EOF or WEOF + + +## Description + +The `EOF` macro represents a negative value that is used to indicate that the file is exhausted and no data remains when reading data from a file. `EOF` is an example of an [in-band error indicator](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-in-banderrorindicator). In-band error indicators are problematic to work with, and the creation of new in-band-error indicators is discouraged by [ERR02-C. Avoid in-band error indicators](https://wiki.sei.cmu.edu/confluence/display/c/ERR02-C.+Avoid+in-band+error+indicators). + +The byte I/O functions `fgetc()`, `getc()`, and `getchar()` all read a character from a stream and return it as an `int.` (See [STR00-C. Represent characters using an appropriate type](https://wiki.sei.cmu.edu/confluence/display/c/STR00-C.+Represent+characters+using+an+appropriate+type).) If the stream is at the end of the file, the end-of-file indicator for the stream is set and the function returns `EOF`. If a read error occurs, the error indicator for the stream is set and the function returns `EOF`. If these functions succeed, they cast the character returned into an `unsigned char`. + +Because `EOF` is negative, it should not match any unsigned character value. However, this is only true for [implementations](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-implementation) where the `int` type is wider than `char`. On an implementation where `int` and `char` have the same width, a character-reading function can read and return a valid character that has the same bit-pattern as `EOF`. This could occur, for example, if an attacker inserted a value that looked like `EOF` into the file or data stream to alter the behavior of the program. + +The C Standard requires only that the `int` type be able to represent a maximum value of +32767 and that a `char` type be no larger than an `int`. Although uncommon, this situation can result in the integer constant expression `EOF` being indistinguishable from a valid character; that is, `(int)(unsigned char)65535 == -1`. Consequently, failing to use `feof()` and `ferror()` to detect end-of-file and file errors can result in incorrectly identifying the `EOF` character on rare implementations where `sizeof(int) == sizeof(char)`. + +This problem is much more common when reading wide characters. The `fgetwc()`, `getwc()`, and `getwchar()` functions return a value of type `wint_t`. This value can represent the next wide character read, or it can represent `WEOF`, which indicates end-of-file for wide character streams. On most implementations, the `wchar_t` type has the same width as `wint_t`, and these functions can return a character indistinguishable from `WEOF`. + +In the UTF-16 character set, `0xFFFF` is guaranteed not to be a character, which allows `WEOF` to be represented as the value `-1`. Similarly, all UTF-32 characters are positive when viewed as a signed 32-bit integer. All widely used character sets are designed with at least one value that does not represent a character. Consequently, it would require a custom character set designed without consideration of the C programming language for this problem to occur with wide characters or with ordinary characters that are as wide as `int`. + +The C Standard `feof()` and `ferror()` functions are not subject to the problems associated with character and integer sizes and should be used to verify end-of-file and file errors for susceptible implementations \[[Kettlewell 2002](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-Kettle02)\]. Calling both functions on each iteration of a loop adds significant overhead, so a good strategy is to temporarily trust `EOF` and `WEOF` within the loop but verify them with `feof()` and `ferror()` following the loop. + +## Noncompliant Code Example + +This noncompliant code example loops while the character `c` is not `EOF`: + +```cpp +#include + +void func(void) { + int c; + + do { + c = getchar(); + } while (c != EOF); +} + +``` +Although `EOF` is guaranteed to be negative and distinct from the value of any unsigned character, it is not guaranteed to be different from any such value when converted to an `int`. Consequently, when `int` has the same width as `char`, this loop may terminate prematurely. + +## Compliant Solution (Portable) + +This compliant solution uses `feof()` and `ferror()` to test whether the `EOF` was an actual character or a real `EOF` because of end-of-file or errors: + +```cpp +#include + +void func(void) { + int c; + + do { + c = getchar(); + } while (c != EOF || (!feof(stdin) && !ferror(stdin))); +} + +``` + +## Noncompliant Code Example (Nonportable) + +This noncompliant code example uses an assertion to ensure that the code is executed only on architectures where `int` is wider than `char` and `EOF` is guaranteed not to be a valid character value. However, this code example is noncompliant because the variable `c` is declared as a `char` rather than an `int`, making it possible for a valid character value to compare equal to the value of the `EOF` macro when `char` is signed because of sign extension: + +```cpp +#include +#include +#include + +void func(void) { + char c; + static_assert(UCHAR_MAX < UINT_MAX, "FIO34-C violation"); + + do { + c = getchar(); + } while (c != EOF); +} + +``` +Assuming that a `char` is a signed 8-bit type and an int is a 32-bit type, if `getchar()` returns the character value `'\xff` (decimal 255), it will be interpreted as `EOF` because this value is sign-extended to `0xFFFFFFFF` (the value of `EOF`) to perform the comparison. (See [STR34-C. Cast characters to unsigned char before converting to larger integer sizes](https://wiki.sei.cmu.edu/confluence/display/c/STR34-C.+Cast+characters+to+unsigned+char+before+converting+to+larger+integer+sizes).) + +## Compliant Solution (Nonportable) + +This compliant solution declares `c` to be an `int`. Consequently, the loop will terminate only when the file is exhausted. + +```cpp +#include +#include +#include + +void func(void) { + int c; + static_assert(UCHAR_MAX < UINT_MAX, "FIO34-C violation"); + + do { + c = getchar(); + } while (c != EOF); +} + +``` + +## Noncompliant Code Example (Wide Characters) + +In this noncompliant example, the result of the call to the C standard library function `getwc()` is stored into a variable of type `wchar_t` and is subsequently compared with `WEOF`: + +```cpp +#include +#include +#include + +enum { BUFFER_SIZE = 32 }; + +void g(void) { + wchar_t buf[BUFFER_SIZE]; + wchar_t wc; + size_t i = 0; + + while ((wc = getwc(stdin)) != L'\n' && wc != WEOF) { + if (i < (BUFFER_SIZE - 1)) { + buf[i++] = wc; + } + } + buf[i] = L'\0'; +} + +``` +This code suffers from two problems. First, the value returned by `getwc()` is immediately converted to `wchar_t` before being compared with `WEOF`. Second, there is no check to ensure that `wint_t` is wider than `wchar_t`. Both of these problems make it possible for an attacker to terminate the loop prematurely by supplying the wide-character value matching `WEOF` in the file. + +## Compliant Solution (Portable) + +This compliant solution declares `c` to be a `wint_t` to match the integer type returned by `getwc()`. Furthermore, it does not rely on `WEOF` to determine end-of-file definitively. + +```cpp +#include +#include +#include + +enum {BUFFER_SIZE = 32 } + +void g(void) { + wchar_t buf[BUFFER_SIZE]; + wint_t wc; + size_t i = 0; + + while ((wc = getwc(stdin)) != L'\n' && wc != WEOF) { + if (i < BUFFER_SIZE - 1) { + buf[i++] = wc; + } + } + + if (feof(stdin) || ferror(stdin)) { + buf[i] = L'\0'; + } else { + /* Received a wide character that resembles WEOF; handle error */ + } +} + +``` + +## Exceptions + +**FIO34-C-EX1:** A number of C functions do not return characters but can return `EOF` as a status code. These functions include `fclose()`, `fflush()`, `fputs()`, `fscanf()`, `puts()`, `scanf()`, `sscanf()`, `vfscanf()`, and `vscanf()`. These return values can be compared to `EOF` without validating the result. + +## Risk Assessment + +Incorrectly assuming characters from a file cannot match `EOF` or `WEOF` has resulted in significant vulnerabilities, including command injection attacks. (See the [\*CA-1996-22](http://www.cert.org/historical/advisories/CA-1996-22.cfm) advisory.) + +
    Rule Severity Likelihood Remediation Cost Priority Level
    FIO34-C High Probable Medium P12 L1
    + + +## Automated Detection + +
    Tool Version Checker Description
    Axivion Bauhaus Suite 7.2.0 CertC-FIO34
    CodeSonar 6.2p0 LANG.CAST.COERCE Coercion alters value
    Compass/ROSE
    Coverity 2017.07 CHAR_IO Identifies defects when the return value of fgetc() , getc() , or getchar() is incorrectly assigned to a char instead of an int . Coverity Prevent cannot discover all violations of this rule, so further verification is necessary
    ECLAIR 1.2 CC2.FIO34 Partially implemented
    Helix QAC 2021.3 C2676, C2678 C++2676, C++2678, C++3001, C++3010, C++3051, C++3137, C++3717
    Klocwork 2021.4 CWARN.CMPCHR.EOF
    LDRA tool suite 9.7.1 662 S Fully implemented
    Parasoft C/C++test 2021.2 CERT_C-FIO34-a The macro EOF should be compared with the unmodified return value from the Standard Library function
    Polyspace Bug Finder R2021a CERT C: Rule FIO34-C Checks for character values absorbed into EOF (rule partially covered)
    PRQA QA-C 9.7 2676, 2678
    PRQA QA-C++ 4.4 2676, 2678, 3001, 3010, 3051, 3137, 3717
    Splint 3.1.1
    + + +## Related Vulnerabilities + +Search for [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) resulting from the violation of this rule on the [CERT website](https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+FIO34-C). + +## Related Guidelines + +[Key here](https://wiki.sei.cmu.edu/confluence/display/c/How+this+Coding+Standard+is+Organized#HowthisCodingStandardisOrganized-RelatedGuidelines) (explains table format and definitions) + +
    Taxonomy Taxonomy item Relationship
    CERT C Secure Coding Standard STR00-C. Represent characters using an appropriate type Prior to 2018-01-12: CERT: Unspecified Relationship
    CERT C Secure Coding Standard INT31-C. Ensure that integer conversions do not result in lost or misinterpreted data Prior to 2018-01-12: CERT: Unspecified Relationship
    CERT Oracle Secure Coding Standard for Java FIO08-J. Use an int to capture the return value of methods that read a character or byte Prior to 2018-01-12: CERT: Unspecified Relationship
    ISO/IEC TS 17961:2013 Using character values that are indistinguishable from EOF \[chreof\] Prior to 2018-01-12: CERT: Unspecified Relationship
    CWE 2.11 CWE-197 2017-06-14: CERT: Rule subset of CWE
    + + +## CERT-CWE Mapping Notes + +[Key here](https://wiki.sei.cmu.edu/confluence/pages/viewpage.action?pageId=87152408#HowthisCodingStandardisOrganized-CERT-CWEMappingNotes) for mapping notes + +**CWE-197 and FIO34-C** + +Independent( FLP34-C, INT31-C) FIO34-C = Subset( INT31-C) + +Therefore: FIO34-C = Subset( CWE-197) + +## Bibliography + +
    \[ Kettlewell 2002 \] Section 1.2, "< stdio.h > and Character Types"
    \[ NIST 2006 \] SAMATE Reference Dataset Test Case ID 000-000-088
    \[ Summit 2005 \] Question 12.2
    + + +## References + +* CERT-C: [FIO34-C: Distinguish between characters read from a file and EOF or WEOF](https://wiki.sei.cmu.edu/confluence/display/c) diff --git a/c/cert/src/rules/FIO34-C/DistinguishBetweenCharReadFromAFileAndEofOrWeof.qhelp b/c/cert/src/rules/FIO34-C/DistinguishBetweenCharReadFromAFileAndEofOrWeof.qhelp deleted file mode 100644 index ddb42c3df5..0000000000 --- a/c/cert/src/rules/FIO34-C/DistinguishBetweenCharReadFromAFileAndEofOrWeof.qhelp +++ /dev/null @@ -1,18 +0,0 @@ - - - - -

    This query implements the CERT-C rule FIO34-C:

    -
    -

    Distinguish between characters read from a file and EOF or WEOF

    -
    -
    - - -
  • - CERT-C: - FIO34-C: Distinguish between characters read from a file and EOF or WEOF - . -
  • -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO34-C/EndOfFileCheckPortability-standard.qhelp b/c/cert/src/rules/FIO34-C/EndOfFileCheckPortability-standard.qhelp deleted file mode 100644 index ea25476294..0000000000 --- a/c/cert/src/rules/FIO34-C/EndOfFileCheckPortability-standard.qhelp +++ /dev/null @@ -1,547 +0,0 @@ - - -
    -

    The EOF macro represents a negative value that is used to indicate that the file is exhausted and no data remains when reading data from a file. EOF is an example of an in-band error indicator. In-band error indicators are problematic to work with, and the creation of new in-band-error indicators is discouraged by ERR02-C. Avoid in-band error indicators.

    -

    The byte I/O functions fgetc(), getc(), and getchar() all read a character from a stream and return it as an int. (See STR00-C. Represent characters using an appropriate type.) If the stream is at the end of the file, the end-of-file indicator for the stream is set and the function returns EOF. If a read error occurs, the error indicator for the stream is set and the function returns EOF. If these functions succeed, they cast the character returned into an unsigned char.

    -

    Because EOF is negative, it should not match any unsigned character value. However, this is only true for implementations where the int type is wider than char. On an implementation where int and char have the same width, a character-reading function can read and return a valid character that has the same bit-pattern as EOF. This could occur, for example, if an attacker inserted a value that looked like EOF into the file or data stream to alter the behavior of the program.

    -

    The C Standard requires only that the int type be able to represent a maximum value of +32767 and that a char type be no larger than an int. Although uncommon, this situation can result in the integer constant expression EOF being indistinguishable from a valid character; that is, (int)(unsigned char)65535 == -1. Consequently, failing to use feof() and ferror() to detect end-of-file and file errors can result in incorrectly identifying the EOF character on rare implementations where sizeof(int) == sizeof(char).

    -

    This problem is much more common when reading wide characters. The fgetwc(), getwc(), and getwchar() functions return a value of type wint_t. This value can represent the next wide character read, or it can represent WEOF, which indicates end-of-file for wide character streams. On most implementations, the wchar_t type has the same width as wint_t, and these functions can return a character indistinguishable from WEOF.

    -

    In the UTF-16 character set, 0xFFFF is guaranteed not to be a character, which allows WEOF to be represented as the value -1. Similarly, all UTF-32 characters are positive when viewed as a signed 32-bit integer. All widely used character sets are designed with at least one value that does not represent a character. Consequently, it would require a custom character set designed without consideration of the C programming language for this problem to occur with wide characters or with ordinary characters that are as wide as int.

    -

    The C Standard feof() and ferror() functions are not subject to the problems associated with character and integer sizes and should be used to verify end-of-file and file errors for susceptible implementations [Kettlewell 2002]. Calling both functions on each iteration of a loop adds significant overhead, so a good strategy is to temporarily trust EOF and WEOF within the loop but verify them with feof() and ferror() following the loop.

    -
    -
    -

    This noncompliant code example loops while the character c is not EOF:

    - #include <stdio.h> - -void func(void) { - int c; - - do { - c = getchar(); - } while (c != EOF); -} - -

    Although EOF is guaranteed to be negative and distinct from the value of any unsigned character, it is not guaranteed to be different from any such value when converted to an int. Consequently, when int has the same width as char, this loop may terminate prematurely.

    -
    -
    -

    This compliant solution uses feof() and ferror() to test whether the EOF was an actual character or a real EOF because of end-of-file or errors:

    - #include <stdio.h> - -void func(void) { - int c; - - do { - c = getchar(); - } while (c != EOF || (!feof(stdin) && !ferror(stdin))); -} - -
    -
    -

    This noncompliant code example uses an assertion to ensure that the code is executed only on architectures where int is wider than char and EOF is guaranteed not to be a valid character value. However, this code example is noncompliant because the variable c is declared as a char rather than an int, making it possible for a valid character value to compare equal to the value of the EOF macro when char is signed because of sign extension:

    - #include <assert.h> -#include <limits.h> -#include <stdio.h> - -void func(void) { - char c; - static_assert(UCHAR_MAX < UINT_MAX, "FIO34-C violation"); - - do { - c = getchar(); - } while (c != EOF); -} - -

    Assuming that a char is a signed 8-bit type and an int is a 32-bit type, if getchar() returns the character value '\xff (decimal 255), it will be interpreted as EOF because this value is sign-extended to 0xFFFFFFFF (the value of EOF) to perform the comparison. (See STR34-C. Cast characters to unsigned char before converting to larger integer sizes.)

    -
    -
    -

    This compliant solution declares c to be an int. Consequently, the loop will terminate only when the file is exhausted.

    - #include <assert.h> -#include <stdio.h> -#include <limits.h> - -void func(void) { - int c; - static_assert(UCHAR_MAX < UINT_MAX, "FIO34-C violation"); - - do { - c = getchar(); - } while (c != EOF); -} - -
    -
    -

    In this noncompliant example, the result of the call to the C standard library function getwc() is stored into a variable of type wchar_t and is subsequently compared with WEOF:

    - #include <stddef.h> -#include <stdio.h> -#include <wchar.h> - -enum { BUFFER_SIZE = 32 }; - -void g(void) { - wchar_t buf[BUFFER_SIZE]; - wchar_t wc; - size_t i = 0; - - while ((wc = getwc(stdin)) != L'\n' && wc != WEOF) { - if (i < (BUFFER_SIZE - 1)) { - buf[i++] = wc; - } - } - buf[i] = L'\0'; -} - -

    This code suffers from two problems. First, the value returned by getwc() is immediately converted to wchar_t before being compared with WEOF. Second, there is no check to ensure that wint_t is wider than wchar_t. Both of these problems make it possible for an attacker to terminate the loop prematurely by supplying the wide-character value matching WEOF in the file.

    -
    -
    -

    This compliant solution declares c to be a wint_t to match the integer type returned by getwc(). Furthermore, it does not rely on WEOF to determine end-of-file definitively.

    - #include <stddef.h> -#include <stdio.h> -#include <wchar.h> - -enum {BUFFER_SIZE = 32 } - -void g(void) { - wchar_t buf[BUFFER_SIZE]; - wint_t wc; - size_t i = 0; - - while ((wc = getwc(stdin)) != L'\n' && wc != WEOF) { - if (i < BUFFER_SIZE - 1) { - buf[i++] = wc; - } - } - - if (feof(stdin) || ferror(stdin)) { - buf[i] = L'\0'; - } else { - /* Received a wide character that resembles WEOF; handle error */ - } -} - -
    -
    -

    FIO34-C-EX1: A number of C functions do not return characters but can return EOF as a status code. These functions include fclose(), fflush(), fputs(), fscanf(), puts(), scanf(), sscanf(), vfscanf(), and vscanf(). These return values can be compared to EOF without validating the result.

    -
    -
    -

    Incorrectly assuming characters from a file cannot match EOF or WEOF has resulted in significant vulnerabilities, including command injection attacks. (See the *CA-1996-22 advisory.)

    - - - - - - - - - - - - - - - - - - - -
    - Rule - - Severity - - Likelihood - - Remediation Cost - - Priority - - Level -
    - FIO34-C - - High - - Probable - - Medium - - P12 - - L1 -
    -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - Tool - - Version - - Checker - - Description -
    - - Axivion Bauhaus Suite - - - 7.2.0 - - CertC-FIO34 - -
    - - CodeSonar - - - 6.2p0 - - LANG.CAST.COERCE - - Coercion alters value -
    - - Compass/ROSE - - - - -
    - - Coverity - - - 2017.07 - - CHAR_IO - - Identifies defects when the return value of - fgetc() - , - getc() - , or - getchar() - is incorrectly assigned to a - char - instead of an - int - . Coverity Prevent cannot discover all violations of this rule, so further verification is necessary -
    - - ECLAIR - - - 1.2 - - CC2.FIO34 - - Partially implemented -
    - - Helix QAC - - - 2021.3 - - C2676, C2678 - C++2676, C++2678, C++3001, C++3010, C++3051, C++3137, C++3717 - -
    - - Klocwork - - - 2021.4 - - CWARN.CMPCHR.EOF - -
    - - LDRA tool suite - - - 9.7.1 - - 662 S - - Fully implemented -
    - - Parasoft C/C++test - - - 2021.2 - - CERT_C-FIO34-a - - The macro EOF should be compared with the unmodified return value from the Standard Library function -
    - - Polyspace Bug Finder - - - R2021a - - - CERT C: Rule FIO34-C - - - Checks for character values absorbed into EOF (rule partially covered) -
    - - PRQA QA-C - - - 9.7 - - 2676, 2678 - -
    - - PRQA QA-C++ - - - 4.4 - - 2676, 2678, 3001, 3010, 3051, 3137, 3717 - -
    - - Splint - - - 3.1.1 - - -
    -
    -
    -

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    -
    -
    -

    Key here (explains table format and definitions)

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - Taxonomy - - Taxonomy item - - Relationship -
    - - CERT C Secure Coding Standard - - - - STR00-C. Represent characters using an appropriate type - - - Prior to 2018-01-12: CERT: Unspecified Relationship -
    - - CERT C Secure Coding Standard - - - - INT31-C. Ensure that integer conversions do not result in lost or misinterpreted data - - - Prior to 2018-01-12: CERT: Unspecified Relationship -
    - - CERT Oracle Secure Coding Standard for Java - - - - FIO08-J. Use an int to capture the return value of methods that read a character or byte - - - Prior to 2018-01-12: CERT: Unspecified Relationship -
    - - ISO/IEC TS 17961:2013 - - - Using character values that are indistinguishable from EOF [chreof] - - Prior to 2018-01-12: CERT: Unspecified Relationship -
    - - CWE 2.11 - - - - CWE-197 - - - 2017-06-14: CERT: Rule subset of CWE -
    -
    -
    -

    Key here for mapping notes

    -

    CWE-197 and FIO34-C

    -

    Independent( FLP34-C, INT31-C) FIO34-C = Subset( INT31-C)

    -

    Therefore: FIO34-C = Subset( CWE-197)

    -
    -
    - - - - - - - - - - - - - - - -
    - [ - - Kettlewell 2002 - - ] - - Section 1.2, "< - stdio.h - > and Character Types" -
    - [ - - NIST 2006 - - ] - - SAMATE Reference Dataset Test Case ID 000-000-088 -
    - [ - - Summit 2005 - - ] - - Question 12.2 -
    -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO34-C/EndOfFileCheckPortability.md b/c/cert/src/rules/FIO34-C/EndOfFileCheckPortability.md new file mode 100644 index 0000000000..8c204a36f3 --- /dev/null +++ b/c/cert/src/rules/FIO34-C/EndOfFileCheckPortability.md @@ -0,0 +1,202 @@ +# FIO34-C: Checks against EOF and WEOF are not portable + +This query implements the CERT-C rule FIO34-C: + +> Distinguish between characters read from a file and EOF or WEOF + + +## Description + +The `EOF` macro represents a negative value that is used to indicate that the file is exhausted and no data remains when reading data from a file. `EOF` is an example of an [in-band error indicator](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-in-banderrorindicator). In-band error indicators are problematic to work with, and the creation of new in-band-error indicators is discouraged by [ERR02-C. Avoid in-band error indicators](https://wiki.sei.cmu.edu/confluence/display/c/ERR02-C.+Avoid+in-band+error+indicators). + +The byte I/O functions `fgetc()`, `getc()`, and `getchar()` all read a character from a stream and return it as an `int.` (See [STR00-C. Represent characters using an appropriate type](https://wiki.sei.cmu.edu/confluence/display/c/STR00-C.+Represent+characters+using+an+appropriate+type).) If the stream is at the end of the file, the end-of-file indicator for the stream is set and the function returns `EOF`. If a read error occurs, the error indicator for the stream is set and the function returns `EOF`. If these functions succeed, they cast the character returned into an `unsigned char`. + +Because `EOF` is negative, it should not match any unsigned character value. However, this is only true for [implementations](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-implementation) where the `int` type is wider than `char`. On an implementation where `int` and `char` have the same width, a character-reading function can read and return a valid character that has the same bit-pattern as `EOF`. This could occur, for example, if an attacker inserted a value that looked like `EOF` into the file or data stream to alter the behavior of the program. + +The C Standard requires only that the `int` type be able to represent a maximum value of +32767 and that a `char` type be no larger than an `int`. Although uncommon, this situation can result in the integer constant expression `EOF` being indistinguishable from a valid character; that is, `(int)(unsigned char)65535 == -1`. Consequently, failing to use `feof()` and `ferror()` to detect end-of-file and file errors can result in incorrectly identifying the `EOF` character on rare implementations where `sizeof(int) == sizeof(char)`. + +This problem is much more common when reading wide characters. The `fgetwc()`, `getwc()`, and `getwchar()` functions return a value of type `wint_t`. This value can represent the next wide character read, or it can represent `WEOF`, which indicates end-of-file for wide character streams. On most implementations, the `wchar_t` type has the same width as `wint_t`, and these functions can return a character indistinguishable from `WEOF`. + +In the UTF-16 character set, `0xFFFF` is guaranteed not to be a character, which allows `WEOF` to be represented as the value `-1`. Similarly, all UTF-32 characters are positive when viewed as a signed 32-bit integer. All widely used character sets are designed with at least one value that does not represent a character. Consequently, it would require a custom character set designed without consideration of the C programming language for this problem to occur with wide characters or with ordinary characters that are as wide as `int`. + +The C Standard `feof()` and `ferror()` functions are not subject to the problems associated with character and integer sizes and should be used to verify end-of-file and file errors for susceptible implementations \[[Kettlewell 2002](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-Kettle02)\]. Calling both functions on each iteration of a loop adds significant overhead, so a good strategy is to temporarily trust `EOF` and `WEOF` within the loop but verify them with `feof()` and `ferror()` following the loop. + +## Noncompliant Code Example + +This noncompliant code example loops while the character `c` is not `EOF`: + +```cpp +#include + +void func(void) { + int c; + + do { + c = getchar(); + } while (c != EOF); +} + +``` +Although `EOF` is guaranteed to be negative and distinct from the value of any unsigned character, it is not guaranteed to be different from any such value when converted to an `int`. Consequently, when `int` has the same width as `char`, this loop may terminate prematurely. + +## Compliant Solution (Portable) + +This compliant solution uses `feof()` and `ferror()` to test whether the `EOF` was an actual character or a real `EOF` because of end-of-file or errors: + +```cpp +#include + +void func(void) { + int c; + + do { + c = getchar(); + } while (c != EOF || (!feof(stdin) && !ferror(stdin))); +} + +``` + +## Noncompliant Code Example (Nonportable) + +This noncompliant code example uses an assertion to ensure that the code is executed only on architectures where `int` is wider than `char` and `EOF` is guaranteed not to be a valid character value. However, this code example is noncompliant because the variable `c` is declared as a `char` rather than an `int`, making it possible for a valid character value to compare equal to the value of the `EOF` macro when `char` is signed because of sign extension: + +```cpp +#include +#include +#include + +void func(void) { + char c; + static_assert(UCHAR_MAX < UINT_MAX, "FIO34-C violation"); + + do { + c = getchar(); + } while (c != EOF); +} + +``` +Assuming that a `char` is a signed 8-bit type and an int is a 32-bit type, if `getchar()` returns the character value `'\xff` (decimal 255), it will be interpreted as `EOF` because this value is sign-extended to `0xFFFFFFFF` (the value of `EOF`) to perform the comparison. (See [STR34-C. Cast characters to unsigned char before converting to larger integer sizes](https://wiki.sei.cmu.edu/confluence/display/c/STR34-C.+Cast+characters+to+unsigned+char+before+converting+to+larger+integer+sizes).) + +## Compliant Solution (Nonportable) + +This compliant solution declares `c` to be an `int`. Consequently, the loop will terminate only when the file is exhausted. + +```cpp +#include +#include +#include + +void func(void) { + int c; + static_assert(UCHAR_MAX < UINT_MAX, "FIO34-C violation"); + + do { + c = getchar(); + } while (c != EOF); +} + +``` + +## Noncompliant Code Example (Wide Characters) + +In this noncompliant example, the result of the call to the C standard library function `getwc()` is stored into a variable of type `wchar_t` and is subsequently compared with `WEOF`: + +```cpp +#include +#include +#include + +enum { BUFFER_SIZE = 32 }; + +void g(void) { + wchar_t buf[BUFFER_SIZE]; + wchar_t wc; + size_t i = 0; + + while ((wc = getwc(stdin)) != L'\n' && wc != WEOF) { + if (i < (BUFFER_SIZE - 1)) { + buf[i++] = wc; + } + } + buf[i] = L'\0'; +} + +``` +This code suffers from two problems. First, the value returned by `getwc()` is immediately converted to `wchar_t` before being compared with `WEOF`. Second, there is no check to ensure that `wint_t` is wider than `wchar_t`. Both of these problems make it possible for an attacker to terminate the loop prematurely by supplying the wide-character value matching `WEOF` in the file. + +## Compliant Solution (Portable) + +This compliant solution declares `c` to be a `wint_t` to match the integer type returned by `getwc()`. Furthermore, it does not rely on `WEOF` to determine end-of-file definitively. + +```cpp +#include +#include +#include + +enum {BUFFER_SIZE = 32 } + +void g(void) { + wchar_t buf[BUFFER_SIZE]; + wint_t wc; + size_t i = 0; + + while ((wc = getwc(stdin)) != L'\n' && wc != WEOF) { + if (i < BUFFER_SIZE - 1) { + buf[i++] = wc; + } + } + + if (feof(stdin) || ferror(stdin)) { + buf[i] = L'\0'; + } else { + /* Received a wide character that resembles WEOF; handle error */ + } +} + +``` + +## Exceptions + +**FIO34-C-EX1:** A number of C functions do not return characters but can return `EOF` as a status code. These functions include `fclose()`, `fflush()`, `fputs()`, `fscanf()`, `puts()`, `scanf()`, `sscanf()`, `vfscanf()`, and `vscanf()`. These return values can be compared to `EOF` without validating the result. + +## Risk Assessment + +Incorrectly assuming characters from a file cannot match `EOF` or `WEOF` has resulted in significant vulnerabilities, including command injection attacks. (See the [\*CA-1996-22](http://www.cert.org/historical/advisories/CA-1996-22.cfm) advisory.) + +
    Rule Severity Likelihood Remediation Cost Priority Level
    FIO34-C High Probable Medium P12 L1
    + + +## Automated Detection + +
    Tool Version Checker Description
    Axivion Bauhaus Suite 7.2.0 CertC-FIO34
    CodeSonar 6.2p0 LANG.CAST.COERCE Coercion alters value
    Compass/ROSE
    Coverity 2017.07 CHAR_IO Identifies defects when the return value of fgetc() , getc() , or getchar() is incorrectly assigned to a char instead of an int . Coverity Prevent cannot discover all violations of this rule, so further verification is necessary
    ECLAIR 1.2 CC2.FIO34 Partially implemented
    Helix QAC 2021.3 C2676, C2678 C++2676, C++2678, C++3001, C++3010, C++3051, C++3137, C++3717
    Klocwork 2021.4 CWARN.CMPCHR.EOF
    LDRA tool suite 9.7.1 662 S Fully implemented
    Parasoft C/C++test 2021.2 CERT_C-FIO34-a The macro EOF should be compared with the unmodified return value from the Standard Library function
    Polyspace Bug Finder R2021a CERT C: Rule FIO34-C Checks for character values absorbed into EOF (rule partially covered)
    PRQA QA-C 9.7 2676, 2678
    PRQA QA-C++ 4.4 2676, 2678, 3001, 3010, 3051, 3137, 3717
    Splint 3.1.1
    + + +## Related Vulnerabilities + +Search for [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) resulting from the violation of this rule on the [CERT website](https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+FIO34-C). + +## Related Guidelines + +[Key here](https://wiki.sei.cmu.edu/confluence/display/c/How+this+Coding+Standard+is+Organized#HowthisCodingStandardisOrganized-RelatedGuidelines) (explains table format and definitions) + +
    Taxonomy Taxonomy item Relationship
    CERT C Secure Coding Standard STR00-C. Represent characters using an appropriate type Prior to 2018-01-12: CERT: Unspecified Relationship
    CERT C Secure Coding Standard INT31-C. Ensure that integer conversions do not result in lost or misinterpreted data Prior to 2018-01-12: CERT: Unspecified Relationship
    CERT Oracle Secure Coding Standard for Java FIO08-J. Use an int to capture the return value of methods that read a character or byte Prior to 2018-01-12: CERT: Unspecified Relationship
    ISO/IEC TS 17961:2013 Using character values that are indistinguishable from EOF \[chreof\] Prior to 2018-01-12: CERT: Unspecified Relationship
    CWE 2.11 CWE-197 2017-06-14: CERT: Rule subset of CWE
    + + +## CERT-CWE Mapping Notes + +[Key here](https://wiki.sei.cmu.edu/confluence/pages/viewpage.action?pageId=87152408#HowthisCodingStandardisOrganized-CERT-CWEMappingNotes) for mapping notes + +**CWE-197 and FIO34-C** + +Independent( FLP34-C, INT31-C) FIO34-C = Subset( INT31-C) + +Therefore: FIO34-C = Subset( CWE-197) + +## Bibliography + +
    \[ Kettlewell 2002 \] Section 1.2, "< stdio.h > and Character Types"
    \[ NIST 2006 \] SAMATE Reference Dataset Test Case ID 000-000-088
    \[ Summit 2005 \] Question 12.2
    + + +## References + +* CERT-C: [FIO34-C: Distinguish between characters read from a file and EOF or WEOF](https://wiki.sei.cmu.edu/confluence/display/c) diff --git a/c/cert/src/rules/FIO34-C/EndOfFileCheckPortability.qhelp b/c/cert/src/rules/FIO34-C/EndOfFileCheckPortability.qhelp deleted file mode 100644 index 980ea8be38..0000000000 --- a/c/cert/src/rules/FIO34-C/EndOfFileCheckPortability.qhelp +++ /dev/null @@ -1,18 +0,0 @@ - - - - -

    This query implements the CERT-C rule FIO34-C:

    -
    -

    Distinguish between characters read from a file and EOF or WEOF

    -
    -
    - - -
  • - CERT-C: - FIO34-C: Distinguish between characters read from a file and EOF or WEOF - . -
  • -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO34-C/standard-example.c b/c/cert/src/rules/FIO34-C/standard-example.c deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/c/cert/src/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString-standard.qhelp b/c/cert/src/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString-standard.qhelp deleted file mode 100644 index e4ce1eaf65..0000000000 --- a/c/cert/src/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString-standard.qhelp +++ /dev/null @@ -1,392 +0,0 @@ - - -
    -

    Errors can occur when incorrect assumptions are made about the type of data being read. These assumptions may be violated, for example, when binary data has been read from a file instead of text from a user's terminal or the output of a process is piped to stdin. (See FIO14-C. Understand the difference between text mode and binary mode with file streams.) On some systems, it may also be possible to input a null byte (as well as other binary codes) from the keyboard.

    -

    Subclause 7.21.7.2 of the C Standard [ISO/IEC 9899:2011] says,

    -
    -

    The fgets function returns s if successful. If end-of-file is encountered and no characters have been read into the array, the contents of the array remain unchanged and a null pointer is returned.

    -
    -

    The wide-character function fgetws() has the same behavior. Therefore, if fgets() or fgetws() returns a non-null pointer, it is safe to assume that the array contains data. However, it is erroneous to assume that the array contains a nonempty string because the data may contain null characters.

    -
    -
    -

    This noncompliant code example attempts to remove the trailing newline (\n) from an input line. The fgets() function is typically used to read a newline-terminated line of input from a stream. It takes a size parameter for the destination buffer and copies, at most, size - 1 characters from a stream to a character array.

    - #include <stdio.h> -#include <string.h> - -enum { BUFFER_SIZE = 1024 }; - -void func(void) { - char buf[BUFFER_SIZE]; - - if (fgets(buf, sizeof(buf), stdin) == NULL) { - /* Handle error */ - } - buf[strlen(buf) - 1] = '\0'; -} -

    The strlen() function computes the length of a string by determining the number of characters that precede the terminating null character. A problem occurs if the first character read from the input by fgets() happens to be a null character. This may occur, for example, if a binary data file is read by the fgets() call [Lai 2006]. If the first character in buf is a null character, strlen(buf) returns 0, the expression strlen(buf) - 1 wraps around to a large positive value, and a write-outside-array-bounds error occurs.

    -
    -
    -

    This compliant solution uses strchr() to replace the newline character in the string if it exists:

    - #include <stdio.h> -#include <string.h> - -enum { BUFFER_SIZE = 1024 }; - -void func(void) { - char buf[BUFFER_SIZE]; - char *p; - - if (fgets(buf, sizeof(buf), stdin)) { - p = strchr(buf, '\n'); - if (p) { - *p = '\0'; - } - } else { - /* Handle error */ - } -} -
    -
    -

    Incorrectly assuming that character data has been read can result in an out-of-bounds memory write or other flawed logic.

    - - - - - - - - - - - - - - - - - - - -
    - Rule - - Severity - - Likelihood - - Remediation Cost - - Priority - - Level -
    - FIO37-C - - High - - Probable - - Medium - - P12 - - L1 -
    -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - Tool - - Version - - Checker - - Description -
    - - Astrée - - - 20.10 - - - Supported: Astrée reports defects due to returned (empty) strings. -
    - - Axivion Bauhaus Suite - - - 7.2.0 - - CertC-FIO37 - -
    - - CodeSonar - - - 6.2p0 - - (general) - - Considers the possibility that - fgets() - and - fgetws() - may return empty strings (Warnings of various classes may be triggered depending on subsequent operations on those strings. For example, the noncompliant code example cited above would trigger a buffer underrun warning.) -
    - - Compass/ROSE - - - - - Could detect some violations of this rule (In particular, it could detect the noncompliant code example by searching for - fgets() - , followed by - strlen() - 1 - , which could be −1. The crux of this rule is that a string returned by - fgets() - could still be empty, because the first - char - is ' - \0 - '. There are probably other code examples that violate this guideline; they would need to be enumerated before ROSE could detect them.) -
    - - Helix QAC - - - 2022.1 - - C4911, C4912, C4913 - C++4911, C++4912, C++4913 - -
    - - LDRA tool suite - - - 9.7.1 - - 44 S - - Enhanced enforcement -
    - - Parasoft C/C++test - - - 2021.2 - - CERT_C-FIO37-a - - Avoid accessing arrays out of bounds -
    - - Polyspace Bug Finder - - - R2022a - - - CERT C: Rule FIO37-C - - - Checks for use of indeterminate string (rule fully covered) -
    - - PRQA QA-C++ - - - 4.4 - - 2844 - -
    -
    -
    -

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    -
    -
    -

    Key here (explains table format and definitions)

    - - - - - - - - - - - - - - - - - - - - - - - -
    - Taxonomy - - Taxonomy item - - Relationship -
    - - CERT C Secure Coding Standard - - - - FIO14-C. Understand the difference between text mode and binary mode with file streams - - - Prior to 2018-01-12: CERT: Unspecified Relationship -
    - - CERT C Secure Coding Standard - - - - FIO20-C. Avoid unintentional truncation when using fgets() or fgetws() - - - Prior to 2018-01-12: CERT: Unspecified Relationship -
    - - CWE 2.11 - - - - CWE-241 - - , Improper Handling of Unexpected Data Type - - 2017-07-05: CERT: Rule subset of CWE -
    -
    -
    -

    Key here for mapping notes

    -

    CWE-241 and FIO37-C

    -

    CWE-241 = Union( FIO37-C, list) where list =

    -
      -
    • Improper handling of unexpected data type that does not come from the fgets() function.
    • -
    -
    -
    - - - - - - - - - - - - - - - -
    - [ - - ISO/IEC 9899:2011 - - ] - - Subclause 7.21.7.2, "The - fgets - Function" - Subclause 7.29.3.2, "The - fgetws - Function" -
    - [ - - Lai 2006 - - ] - -
    - [ - - Seacord 2013 - - ] - - Chapter 2, "Strings" -
    -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString.md b/c/cert/src/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString.md new file mode 100644 index 0000000000..f6eb194bf0 --- /dev/null +++ b/c/cert/src/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString.md @@ -0,0 +1,105 @@ +# FIO37-C: Do not assume that fgets() or fgetws() returns a nonempty string when successful + +This query implements the CERT-C rule FIO37-C: + +> Do not assume that fgets() or fgetws() returns a nonempty string when successful + + +## Description + +Errors can occur when incorrect assumptions are made about the type of data being read. These assumptions may be violated, for example, when binary data has been read from a file instead of text from a user's terminal or the output of a process is piped to `stdin.` (See [FIO14-C. Understand the difference between text mode and binary mode with file streams](https://wiki.sei.cmu.edu/confluence/display/c/FIO14-C.+Understand+the+difference+between+text+mode+and+binary+mode+with+file+streams).) On some systems, it may also be possible to input a null byte (as well as other binary codes) from the keyboard. + +Subclause 7.21.7.2 of the C Standard \[[ISO/IEC 9899:2011](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO-IEC9899-2011)\] says, + +> The `fgets` function returns `s` if successful. If end-of-file is encountered and no characters have been read into the array, the contents of the array remain unchanged and a null pointer is returned. + + +The wide-character function `fgetws()` has the same behavior. Therefore, if `fgets()` or `fgetws()` returns a non-null pointer, it is safe to assume that the array contains data. However, it is erroneous to assume that the array contains a nonempty string because the data may contain null characters. + +## Noncompliant Code Example + +This noncompliant code example attempts to remove the trailing newline (`\n`) from an input line. The `fgets()` function is typically used to read a newline-terminated line of input from a stream. It takes a size parameter for the destination buffer and copies, at most, `size - 1` characters from a stream to a character array. + +```cpp +#include +#include + +enum { BUFFER_SIZE = 1024 }; + +void func(void) { + char buf[BUFFER_SIZE]; + + if (fgets(buf, sizeof(buf), stdin) == NULL) { + /* Handle error */ + } + buf[strlen(buf) - 1] = '\0'; +} +``` +The `strlen()` function computes the length of a string by determining the number of characters that precede the terminating null character. A problem occurs if the first character read from the input by `fgets()` happens to be a null character. This may occur, for example, if a binary data file is read by the `fgets()` call \[[Lai 2006](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-Lai06)\]. If the first character in `buf` is a null character, `strlen(buf)` returns 0, the expression `strlen(buf) - 1` wraps around to a large positive value, and a write-outside-array-bounds error occurs. + +## Compliant Solution + +This compliant solution uses `strchr()` to replace the newline character in the string if it exists: + +```cpp +#include +#include + +enum { BUFFER_SIZE = 1024 }; + +void func(void) { + char buf[BUFFER_SIZE]; + char *p; + + if (fgets(buf, sizeof(buf), stdin)) { + p = strchr(buf, '\n'); + if (p) { + *p = '\0'; + } + } else { + /* Handle error */ + } +} +``` + +## Risk Assessment + +Incorrectly assuming that character data has been read can result in an out-of-bounds memory write or other flawed logic. + +
    Rule Severity Likelihood Remediation Cost Priority Level
    FIO37-C High Probable Medium P12 L1
    + + +## Automated Detection + +
    Tool Version Checker Description
    Astrée 20.10 Supported: Astrée reports defects due to returned (empty) strings.
    Axivion Bauhaus Suite 7.2.0 CertC-FIO37
    CodeSonar 6.2p0 (general) Considers the possibility that fgets() and fgetws() may return empty strings (Warnings of various classes may be triggered depending on subsequent operations on those strings. For example, the noncompliant code example cited above would trigger a buffer underrun warning.)
    Compass/ROSE Could detect some violations of this rule (In particular, it could detect the noncompliant code example by searching for fgets() , followed by strlen() - 1 , which could be −1. The crux of this rule is that a string returned by fgets() could still be empty, because the first char is ' \\0 '. There are probably other code examples that violate this guideline; they would need to be enumerated before ROSE could detect them.)
    Helix QAC 2022.1 C4911, C4912, C4913 C++4911, C++4912, C++4913
    LDRA tool suite 9.7.1 44 S Enhanced enforcement
    Parasoft C/C++test 2021.2 CERT_C-FIO37-a Avoid accessing arrays out of bounds
    Polyspace Bug Finder R2022a CERT C: Rule FIO37-C Checks for use of indeterminate string (rule fully covered)
    PRQA QA-C++ 4.4 2844
    + + +## Related Vulnerabilities + +Search for [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) resulting from the violation of this rule on the [CERT website](https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+FIO37-C). + +## Related Guidelines + +[Key here](https://wiki.sei.cmu.edu/confluence/display/c/How+this+Coding+Standard+is+Organized#HowthisCodingStandardisOrganized-RelatedGuidelines) (explains table format and definitions) + +
    Taxonomy Taxonomy item Relationship
    CERT C Secure Coding Standard FIO14-C. Understand the difference between text mode and binary mode with file streams Prior to 2018-01-12: CERT: Unspecified Relationship
    CERT C Secure Coding Standard FIO20-C. Avoid unintentional truncation when using fgets() or fgetws() Prior to 2018-01-12: CERT: Unspecified Relationship
    CWE 2.11 CWE-241 , Improper Handling of Unexpected Data Type 2017-07-05: CERT: Rule subset of CWE
    + + +## CERT-CWE Mapping Notes + +[Key here](https://wiki.sei.cmu.edu/confluence/pages/viewpage.action?pageId=87152408#HowthisCodingStandardisOrganized-CERT-CWEMappingNotes) for mapping notes + +**CWE-241 and FIO37-C** + +CWE-241 = Union( FIO37-C, list) where list = + +* Improper handling of unexpected data type that does not come from the fgets() function. + +## Bibliography + +
    \[ ISO/IEC 9899:2011 \] Subclause 7.21.7.2, "The fgets Function" Subclause 7.29.3.2, "The fgetws Function"
    \[ Lai 2006 \]
    \[ Seacord 2013 \] Chapter 2, "Strings"
    + + +## References + +* CERT-C: [FIO37-C: Do not assume that fgets() or fgetws() returns a nonempty string when successful](https://wiki.sei.cmu.edu/confluence/display/c) diff --git a/c/cert/src/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString.qhelp b/c/cert/src/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString.qhelp deleted file mode 100644 index 0ef132869f..0000000000 --- a/c/cert/src/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString.qhelp +++ /dev/null @@ -1,18 +0,0 @@ - - - - -

    This query implements the CERT-C rule FIO37-C:

    -
    -

    Do not assume that fgets() or fgetws() returns a nonempty string when successful

    -
    -
    - - -
  • - CERT-C: - FIO37-C: Do not assume that fgets() or fgetws() returns a nonempty string when successful - . -
  • -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO38-C/DoNotCopyAFileObject-standard.qhelp b/c/cert/src/rules/FIO38-C/DoNotCopyAFileObject-standard.qhelp deleted file mode 100644 index 64fabbc606..0000000000 --- a/c/cert/src/rules/FIO38-C/DoNotCopyAFileObject-standard.qhelp +++ /dev/null @@ -1,368 +0,0 @@ - - -
    -

    According to the C Standard, 7.21.3, paragraph 6 [ISO/IEC 9899:2011],

    -
    -

    The address of the FILE object used to control a stream may be significant; a copy of a FILE object need not serve in place of the original.

    -
    -

    Consequently, do not copy a FILE object.

    -
    -
    -

    This noncompliant code example can fail because a by-value copy of stdout is being used in the call to fputs():

    - #include <stdio.h> - -int main(void) { - FILE my_stdout = *stdout; - if (fputs("Hello, World!\n", &my_stdout) == EOF) { - /* Handle error */ - } - return 0; -} - -

    When compiled under Microsoft Visual Studio 2013 and run on Windows, this noncompliant example results in an "access violation" at runtime.

    -
    -
    -

    In this compliant solution, a copy of the stdout pointer to the FILE object is used in the call to fputs():

    - #include <stdio.h> - -int main(void) { - FILE *my_stdout = stdout; - if (fputs("Hello, World!\n", my_stdout) == EOF) { - /* Handle error */ - } - return 0; -} - -
    -
    -

    Using a copy of a FILE object in place of the original may result in a crash, which can be used in a denial-of-service attack.

    - - - - - - - - - - - - - - - - - - - -
    - Rule - - Severity - - Likelihood - - Remediation Cost - - Priority - - Level -
    - FIO38-C - - Low - - Probable - - Medium - - P4 - - L3 -
    -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - Tool - - Version - - Checker - - Description -
    - - Astrée - - - 20.10 - - file-dereference - - Partially checked -
    - - Axivion Bauhaus Suite - - - 7.2.0 - - CertC-FIO38 - - Fully implemented -
    - - Clang - - - 3.9 - - misc-non-copyable-objects - - Checked with - clang-tidy -
    - - Compass/ROSE - - - - - Can detect simple violations of this rule -
    - - Coverity - - - 2017.07 - - MISRA C 2012 Rule 22.5 - - Partially implemented -
    - - Helix QAC - - - 2021.3 - - C1485, C5028 - C++3113, C++3114 - -
    - - Klocwork - - - 2021.4 - - MISRA.FILE_PTR.DEREF.2012 - MISRA.FILE_PTR.DEREF.CAST.2012 - MISRA.FILE_PTR.DEREF.INDIRECT.2012 - MISRA.FILE_PTR.DEREF.RETURN.2012 - -
    - - LDRA tool suite - - - 9.7.1 - - 591 S - - Fully implemented -
    - - Parasoft C/C++test - - - 2021.2 - - CERT_C-FIO38-a - - A pointer to a FILE object shall not be dereferenced -
    - - PC-lint Plus - - - 1.4 - - 9047 - - Partially supported: reports when a FILE pointer is dereferenced -
    - - Polyspace Bug Finder - - - R2021a - - - CERT C: Rule FIO38-C - - - Checks for misuse of a FILE object (rule fully covered) -
    - - PRQA QA-C - - - 9.7 - - 1485, 5028 - -
    - - RuleChecker - - - 20.10 - - file-dereference - - Partially checked -
    -
    -
    -

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    -
    -
    -

    Key here (explains table format and definitions)

    - - - - - - - - - - - - - -
    - Taxonomy - - Taxonomy item - - Relationship -
    - - ISO/IEC TS 17961:2013 - - - Copying a - FILE - object [filecpy] - - Prior to 2018-01-12: CERT: Unspecified Relationship -
    -
    -
    - - - - - - - -
    - [ - - ISO/IEC 9899:2011 - - ] - - 7.21.3, "Files" -
    -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO38-C/DoNotCopyAFileObject.md b/c/cert/src/rules/FIO38-C/DoNotCopyAFileObject.md new file mode 100644 index 0000000000..88ce59d0ef --- /dev/null +++ b/c/cert/src/rules/FIO38-C/DoNotCopyAFileObject.md @@ -0,0 +1,82 @@ +# FIO38-C: Do not copy a FILE object + +This query implements the CERT-C rule FIO38-C: + +> Do not copy a FILE object + + +## Description + +According to the C Standard, 7.21.3, paragraph 6 \[[ISO/IEC 9899:2011](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO-IEC9899-2011)\], + +> The address of the `FILE` object used to control a stream may be significant; a copy of a `FILE` object need not serve in place of the original. + + +Consequently, do not copy a `FILE` object. + +## Noncompliant Code Example + +This noncompliant code example can fail because a by-value copy of `stdout` is being used in the call to `fputs()`: + +```cpp +#include + +int main(void) { + FILE my_stdout = *stdout; + if (fputs("Hello, World!\n", &my_stdout) == EOF) { + /* Handle error */ + } + return 0; +} + +``` +When compiled under Microsoft Visual Studio 2013 and run on Windows, this noncompliant example results in an "access violation" at runtime. + +## Compliant Solution + +In this compliant solution, a copy of the `stdout` pointer to the `FILE` object is used in the call to `fputs()`: + +```cpp +#include + +int main(void) { + FILE *my_stdout = stdout; + if (fputs("Hello, World!\n", my_stdout) == EOF) { + /* Handle error */ + } + return 0; +} + +``` + +## Risk Assessment + +Using a copy of a `FILE` object in place of the original may result in a crash, which can be used in a [denial-of-service attack](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-denial-of-service). + +
    Rule Severity Likelihood Remediation Cost Priority Level
    FIO38-C Low Probable Medium P4 L3
    + + +## Automated Detection + +
    Tool Version Checker Description
    Astrée 20.10 file-dereference Partially checked
    Axivion Bauhaus Suite 7.2.0 CertC-FIO38 Fully implemented
    Clang 3.9 misc-non-copyable-objects Checked with clang-tidy
    Compass/ROSE Can detect simple violations of this rule
    Coverity 2017.07 MISRA C 2012 Rule 22.5 Partially implemented
    Helix QAC 2021.3 C1485, C5028 C++3113, C++3114
    Klocwork 2021.4 MISRA.FILE_PTR.DEREF.2012 MISRA.FILE_PTR.DEREF.CAST.2012 MISRA.FILE_PTR.DEREF.INDIRECT.2012 MISRA.FILE_PTR.DEREF.RETURN.2012
    LDRA tool suite 9.7.1 591 S Fully implemented
    Parasoft C/C++test 2021.2 CERT_C-FIO38-a A pointer to a FILE object shall not be dereferenced
    PC-lint Plus 1.4 9047 Partially supported: reports when a FILE pointer is dereferenced
    Polyspace Bug Finder R2021a CERT C: Rule FIO38-C Checks for misuse of a FILE object (rule fully covered)
    PRQA QA-C 9.7 1485, 5028
    RuleChecker 20.10 file-dereference Partially checked
    + + +## Related Vulnerabilities + +Search for [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) resulting from the violation of this rule on the [CERT website](https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+FIO38-C). + +## Related Guidelines + +[Key here](https://wiki.sei.cmu.edu/confluence/display/c/How+this+Coding+Standard+is+Organized#HowthisCodingStandardisOrganized-RelatedGuidelines) (explains table format and definitions) + +
    Taxonomy Taxonomy item Relationship
    ISO/IEC TS 17961:2013 Copying a FILE object \[filecpy\] Prior to 2018-01-12: CERT: Unspecified Relationship
    + + +## Bibliography + +
    \[ ISO/IEC 9899:2011 \] 7.21.3, "Files"
    + + +## References + +* CERT-C: [FIO38-C: Do not copy a FILE object](https://wiki.sei.cmu.edu/confluence/display/c) diff --git a/c/cert/src/rules/FIO38-C/DoNotCopyAFileObject.qhelp b/c/cert/src/rules/FIO38-C/DoNotCopyAFileObject.qhelp deleted file mode 100644 index 88766992b3..0000000000 --- a/c/cert/src/rules/FIO38-C/DoNotCopyAFileObject.qhelp +++ /dev/null @@ -1,18 +0,0 @@ - - - - -

    This query implements the CERT-C rule FIO38-C:

    -
    -

    Do not copy a FILE object

    -
    -
    - - -
  • - CERT-C: - FIO38-C: Do not copy a FILE object - . -
  • -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO38-C/standard-example.c b/c/cert/src/rules/FIO38-C/standard-example.c deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/c/cert/src/rules/FIO39-C/DoNotAlternatelyIOFromAStreamWithoutPositioning-standard.qhelp b/c/cert/src/rules/FIO39-C/DoNotAlternatelyIOFromAStreamWithoutPositioning-standard.qhelp deleted file mode 100644 index b4bf574812..0000000000 --- a/c/cert/src/rules/FIO39-C/DoNotAlternatelyIOFromAStreamWithoutPositioning-standard.qhelp +++ /dev/null @@ -1,384 +0,0 @@ - - -
    -

    The C Standard, 7.21.5.3, paragraph 7 [ISO/IEC 9899:2011], places the following restrictions on update streams:

    -
    -

    When a file is opened with update mode . . ., both input and output may be performed on the associated stream. However, output shall not be directly followed by input without an intervening call to the fflush function or to a file positioning function (fseek, fsetpos, or rewind), and input shall not be directly followed by output without an intervening call to a file positioning function, unless the input operation encounters end-of-file. Opening (or creating) a text file with update mode may instead open (or create) a binary stream in some implementations.

    -
    -

    The following scenarios can result in undefined behavior. (See undefined behavior 151.)

    -
      -
    • Receiving input from a stream directly following an output to that stream without an intervening call to fflush(), fseek(), fsetpos(), or rewind() if the file is not at end-of-file
    • -
    • Outputting to a stream after receiving input from that stream without a call to fseek(), fsetpos(), or rewind() if the file is not at end-of-file
    • -
    -

    Consequently, a call to fseek(), fflush(), or fsetpos() is necessary between input and output to the same stream. See ERR07-C. Prefer functions that support error checking over equivalent functions that don't for more information on why fseek() is preferred over rewind().

    -
    -
    -

    This noncompliant code example appends data to a file and then reads from the same file:

    - #include <stdio.h> - -enum { BUFFERSIZE = 32 }; - -extern void initialize_data(char *data, size_t size); - -void func(const char *file_name) { - char data[BUFFERSIZE]; - char append_data[BUFFERSIZE]; - FILE *file; - - file = fopen(file_name, "a+"); - if (file == NULL) { - /* Handle error */ - } - - initialize_data(append_data, BUFFERSIZE); - - if (fwrite(append_data, 1, BUFFERSIZE, file) != BUFFERSIZE) { - /* Handle error */ - } - if (fread(data, 1, BUFFERSIZE, file) < BUFFERSIZE) { - /* Handle there not being data */ - } - - if (fclose(file) == EOF) { - /* Handle error */ - } -} -

    Because there is no intervening flush or positioning call between the calls to fread() and fwrite(), the behavior is undefined.

    -
    -
    -

    In this compliant solution, fseek() is called between the output and input, eliminating the undefined behavior:

    - #include <stdio.h> - -enum { BUFFERSIZE = 32 }; -extern void initialize_data(char *data, size_t size); - -void func(const char *file_name) { - char data[BUFFERSIZE]; - char append_data[BUFFERSIZE]; - FILE *file; - - file = fopen(file_name, "a+"); - if (file == NULL) { - /* Handle error */ - } - - initialize_data(append_data, BUFFERSIZE); - if (fwrite(append_data, BUFFERSIZE, 1, file) != BUFFERSIZE) { - /* Handle error */ - } - - if (fseek(file, 0L, SEEK_SET) != 0) { - /* Handle error */ - } - - if (fread(data, BUFFERSIZE, 1, file) != 0) { - /* Handle there not being data */ - } - - if (fclose(file) == EOF) { - /* Handle error */ - } -} -
    -
    -

    Alternately inputting and outputting from a stream without an intervening flush or positioning call is undefined behavior.

    - - - - - - - - - - - - - - - - - - - -
    - Rule - - Severity - - Likelihood - - Remediation Cost - - Priority - - Level -
    - FIO39-C - - Low - - Likely - - Medium - - P6 - - L2 -
    -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - Tool - - Version - - Checker - - Description -
    - - Astrée - - - 20.10 - - - Supported, but no explicit checker -
    - - Axivion Bauhaus Suite - - - 7.2.0 - - CertC-FIO39 - -
    - - Compass/ROSE - - - - - Can detect simple violations of this rule -
    - - Helix QAC - - - 2021.3 - - C4711, C4712, C4713 - C++4711, C++4712, C++4713 - -
    - - LDRA tool suite - - - 9.7.1 - - 84 D - - Fully implemented -
    - - Parasoft C/C++test - - - 2021.2 - - CERT_C-FIO39-a - - Do not alternately input and output from a stream without an intervening flush or positioning call -
    - - PC-lint Plus - - - 1.4 - - 2478, 2479 - - Fully supported -
    - - Polyspace Bug Finder - - - R2021a - - - CERT C: Rule FIO39-C - - - Checks for alternating input and output from a stream without flush or positioning call (rule fully covered) -
    - - PRQA QA-C - - - 9.7 - - 5029 - -
    -
    -
    -

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    -
    -
    -

    Key here (explains table format and definitions)

    - - - - - - - - - - - - - - - - - - - - - - - -
    - Taxonomy - - Taxonomy item - - Relationship -
    - - CERT C - - - - FIO50-CPP. Do not alternately input and output from a file stream without an intervening positioning call - - - Prior to 2018-01-12: CERT: Unspecified Relationship -
    - - ISO/IEC TS 17961:2013 - - - Interleaving stream inputs and outputs without a flush or positioning call [ioileave] - - Prior to 2018-01-12: CERT: Unspecified Relationship -
    - - CWE 2.11 - - - - CWE-664 - - - 2017-07-10: CERT: Rule subset of CWE -
    -
    -
    -

    Key here for mapping notes

    -

    CWE-664 and FIO39-C

    -

    CWE-664 = Union( FIO39-C, list) where list =

    -
      -
    • Improper use of an object (besides alternating reading/writing a file stream without an intervening flush
    • -
    -

    This CWE is vague on what constitutes “improper control of a resource”. It could include any violation of an object’s method constraints (whether they are documented or not). Or it could be narrowly interpreted to mean object creation and object destruction (which are covered by other CWEs).

    -
    -
    - - - - - - - -
    - [ - - ISO/IEC 9899:2011 - - ] - - 7.21.5.3, "The - fopen - Function" -
    -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO39-C/DoNotAlternatelyIOFromAStreamWithoutPositioning.md b/c/cert/src/rules/FIO39-C/DoNotAlternatelyIOFromAStreamWithoutPositioning.md new file mode 100644 index 0000000000..92c0d48669 --- /dev/null +++ b/c/cert/src/rules/FIO39-C/DoNotAlternatelyIOFromAStreamWithoutPositioning.md @@ -0,0 +1,138 @@ +# FIO39-C: Do not alternately input and output from a stream without an intervening flush or positioning call + +This query implements the CERT-C rule FIO39-C: + +> Do not alternately input and output from a stream without an intervening flush or positioning call + + +## Description + +The C Standard, 7.21.5.3, paragraph 7 \[[ISO/IEC 9899:2011](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO-IEC9899-2011)\], places the following restrictions on update streams: + +> When a file is opened with update mode . . ., both input and output may be performed on the associated stream. However, output shall not be directly followed by input without an intervening call to the `fflush` function or to a file positioning function (`fseek`, `fsetpos`, or `rewind`), and input shall not be directly followed by output without an intervening call to a file positioning function, unless the input operation encounters end-of-file. Opening (or creating) a text file with update mode may instead open (or create) a binary stream in some implementations. + + +The following scenarios can result in [undefined behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior). (See [undefined behavior 151](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_151).) + +* Receiving input from a stream directly following an output to that stream without an intervening call to `fflush()`, `fseek()`, `fsetpos()`, or `rewind()` if the file is not at end-of-file +* Outputting to a stream after receiving input from that stream without a call to `fseek()`, `fsetpos()`, or `rewind()` if the file is not at end-of-file +Consequently, a call to `fseek()`, `fflush()`, or `fsetpos()` is necessary between input and output to the same stream. See [ERR07-C. Prefer functions that support error checking over equivalent functions that don't](https://wiki.sei.cmu.edu/confluence/display/c/ERR07-C.+Prefer+functions+that+support+error+checking+over+equivalent+functions+that+don%27t) for more information on why `fseek()` is preferred over `rewind()`. + +## Noncompliant Code Example + +This noncompliant code example appends data to a file and then reads from the same file: + +```cpp +#include + +enum { BUFFERSIZE = 32 }; + +extern void initialize_data(char *data, size_t size); + +void func(const char *file_name) { + char data[BUFFERSIZE]; + char append_data[BUFFERSIZE]; + FILE *file; + + file = fopen(file_name, "a+"); + if (file == NULL) { + /* Handle error */ + } + + initialize_data(append_data, BUFFERSIZE); + + if (fwrite(append_data, 1, BUFFERSIZE, file) != BUFFERSIZE) { + /* Handle error */ + } + if (fread(data, 1, BUFFERSIZE, file) < BUFFERSIZE) { + /* Handle there not being data */ + } + + if (fclose(file) == EOF) { + /* Handle error */ + } +} +``` +Because there is no intervening flush or positioning call between the calls to `fread()` and `fwrite()`, the behavior is [undefined](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior). + +## Compliant Solution + +In this compliant solution, `fseek()` is called between the output and input, eliminating the undefined behavior: + +```cpp +#include + +enum { BUFFERSIZE = 32 }; +extern void initialize_data(char *data, size_t size); + +void func(const char *file_name) { + char data[BUFFERSIZE]; + char append_data[BUFFERSIZE]; + FILE *file; + + file = fopen(file_name, "a+"); + if (file == NULL) { + /* Handle error */ + } + + initialize_data(append_data, BUFFERSIZE); + if (fwrite(append_data, BUFFERSIZE, 1, file) != BUFFERSIZE) { + /* Handle error */ + } + + if (fseek(file, 0L, SEEK_SET) != 0) { + /* Handle error */ + } + + if (fread(data, BUFFERSIZE, 1, file) != 0) { + /* Handle there not being data */ + } + + if (fclose(file) == EOF) { + /* Handle error */ + } +} +``` + +## Risk Assessment + +Alternately inputting and outputting from a stream without an intervening flush or positioning call is [undefined behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior). + +
    Rule Severity Likelihood Remediation Cost Priority Level
    FIO39-C Low Likely Medium P6 L2
    + + +## Automated Detection + +
    Tool Version Checker Description
    Astrée 20.10 Supported, but no explicit checker
    Axivion Bauhaus Suite 7.2.0 CertC-FIO39
    Compass/ROSE Can detect simple violations of this rule
    Helix QAC 2021.3 C4711, C4712, C4713 C++4711, C++4712, C++4713
    LDRA tool suite 9.7.1 84 D Fully implemented
    Parasoft C/C++test 2021.2 CERT_C-FIO39-a Do not alternately input and output from a stream without an intervening flush or positioning call
    PC-lint Plus 1.4 2478, 2479 Fully supported
    Polyspace Bug Finder R2021a CERT C: Rule FIO39-C Checks for alternating input and output from a stream without flush or positioning call (rule fully covered)
    PRQA QA-C 9.7 5029
    + + +## Related Vulnerabilities + +Search for [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) resulting from the violation of this rule on the [CERT website](https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+FIO39-C). + +## Related Guidelines + +[Key here](https://wiki.sei.cmu.edu/confluence/display/c/How+this+Coding+Standard+is+Organized#HowthisCodingStandardisOrganized-RelatedGuidelines) (explains table format and definitions) + +
    Taxonomy Taxonomy item Relationship
    CERT C FIO50-CPP. Do not alternately input and output from a file stream without an intervening positioning call Prior to 2018-01-12: CERT: Unspecified Relationship
    ISO/IEC TS 17961:2013 Interleaving stream inputs and outputs without a flush or positioning call \[ioileave\] Prior to 2018-01-12: CERT: Unspecified Relationship
    CWE 2.11 CWE-664 2017-07-10: CERT: Rule subset of CWE
    + + +## CERT-CWE Mapping Notes + +[Key here](https://wiki.sei.cmu.edu/confluence/pages/viewpage.action?pageId=87152408#HowthisCodingStandardisOrganized-CERT-CWEMappingNotes) for mapping notes + +**CWE-664 and FIO39-C** + +CWE-664 = Union( FIO39-C, list) where list = + +* Improper use of an object (besides alternating reading/writing a file stream without an intervening flush +This CWE is vague on what constitutes “improper control of a resource”. It could include any violation of an object’s method constraints (whether they are documented or not). Or it could be narrowly interpreted to mean object creation and object destruction (which are covered by other CWEs). + +## Bibliography + +
    \[ ISO/IEC 9899:2011 \] 7.21.5.3, "The fopen Function"
    + + +## References + +* CERT-C: [FIO39-C: Do not alternately input and output from a stream without an intervening flush or positioning call](https://wiki.sei.cmu.edu/confluence/display/c) diff --git a/c/cert/src/rules/FIO39-C/DoNotAlternatelyIOFromAStreamWithoutPositioning.qhelp b/c/cert/src/rules/FIO39-C/DoNotAlternatelyIOFromAStreamWithoutPositioning.qhelp deleted file mode 100644 index 333b34b2f1..0000000000 --- a/c/cert/src/rules/FIO39-C/DoNotAlternatelyIOFromAStreamWithoutPositioning.qhelp +++ /dev/null @@ -1,18 +0,0 @@ - - - - -

    This query implements the CERT-C rule FIO39-C:

    -
    -

    Do not alternately input and output from a stream without an intervening flush or positioning call

    -
    -
    - - -
  • - CERT-C: - FIO39-C: Do not alternately input and output from a stream without an intervening flush or positioning call - . -
  • -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure-standard.qhelp b/c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure-standard.qhelp deleted file mode 100644 index 85898e6966..0000000000 --- a/c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure-standard.qhelp +++ /dev/null @@ -1,219 +0,0 @@ - - -
    -

    If either of the C Standard fgets() or fgetws() functions fail, the contents of the array being written is indeterminate. (See undefined behavior 170.) It is necessary to reset the string to a known value to avoid errors on subsequent string manipulation functions.

    -
    -
    -

    In this noncompliant code example, an error flag is set if fgets() fails. However, buf is not reset and has indeterminate contents:

    - #include <stdio.h> - -enum { BUFFER_SIZE = 1024 }; -void func(FILE *file) { - char buf[BUFFER_SIZE]; - - if (fgets(buf, sizeof(buf), file) == NULL) { - /* Set error flag and continue */ - } -} -
    -
    -

    In this compliant solution, buf is set to an empty string if fgets() fails. The equivalent solution for fgetws() would set buf to an empty wide string.

    - #include <stdio.h> - -enum { BUFFER_SIZE = 1024 }; - -void func(FILE *file) { - char buf[BUFFER_SIZE]; - - if (fgets(buf, sizeof(buf), file) == NULL) { - /* Set error flag and continue */ - *buf = '\0'; - } -} -
    -
    -

    FIO40-C-EX1: If the string goes out of scope immediately following the call to fgets() or fgetws() or is not referenced in the case of a failure, it need not be reset.

    -
    -
    -

    Making invalid assumptions about the contents of an array modified by fgets() or fgetws() can result in undefined behavior and abnormal program termination.

    - - - - - - - - - - - - - - - - - - - -
    - Rule - - Severity - - Likelihood - - Remediation Cost - - Priority - - Level -
    - FIO40-C - - Low - - Probable - - Medium - - P4 - - L3 -
    -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - Tool - - Version - - Checker - - Description -
    - - CodeSonar - - - 6.2p0 - - LANG.MEM.UVAR - - Uninitialized Variable -
    - - Helix QAC - - - 2021.3 - - C4861, C4862, C4863 - C++4861, C++4862, C++4863 - -
    - - LDRA tool suite - - - 9.7.1 - - 44 S - - Enhanced enforcement -
    - - Parasoft C/C++test - - - 2021.2 - - CERT_C-FIO40-a - - Reset strings on fgets() or fgetws() failure -
    - - Polyspace Bug Finder - - - R2021a - - - CERT C: Rule FIO40-C - - - Checks for use of indeterminate string (rule partially covered) -
    - - PRQA QA-C++ - - - 4.4 - - 2956 - -
    - - PVS-Studio - - - 7.17 - - V1024 - -
    -
    -
    -

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.md b/c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.md new file mode 100644 index 0000000000..85429afbdf --- /dev/null +++ b/c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.md @@ -0,0 +1,70 @@ +# FIO40-C: Reset strings on fgets() or fgetws() failure + +This query implements the CERT-C rule FIO40-C: + +> Reset strings on fgets() or fgetws() failure + + +## Description + +If either of the C Standard `fgets()` or `fgetws()` functions fail, the contents of the array being written is [indeterminate](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-indeterminatevalue). (See [undefined behavior 170](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_170).) It is necessary to reset the string to a known value to avoid errors on subsequent string manipulation functions. + +## Noncompliant Code Example + +In this noncompliant code example, an error flag is set if `fgets()` fails. However, `buf` is not reset and has indeterminate contents: + +```cpp +#include + +enum { BUFFER_SIZE = 1024 }; +void func(FILE *file) { + char buf[BUFFER_SIZE]; + + if (fgets(buf, sizeof(buf), file) == NULL) { + /* Set error flag and continue */ + } +} +``` + +## Compliant Solution + +In this compliant solution, `buf` is set to an empty string if `fgets()` fails. The equivalent solution for `fgetws()` would set `buf` to an empty wide string. + +```cpp +#include + +enum { BUFFER_SIZE = 1024 }; + +void func(FILE *file) { + char buf[BUFFER_SIZE]; + + if (fgets(buf, sizeof(buf), file) == NULL) { + /* Set error flag and continue */ + *buf = '\0'; + } +} +``` + +## Exceptions + +**FIO40-C-EX1:** If the string goes out of scope immediately following the call to `fgets()` or `fgetws()` or is not referenced in the case of a failure, it need not be reset. + +## Risk Assessment + +Making invalid assumptions about the contents of an array modified by `fgets()` or `fgetws()` can result in [undefined behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior) and [abnormal program termination](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-abnormaltermination). + +
    Rule Severity Likelihood Remediation Cost Priority Level
    FIO40-C Low Probable Medium P4 L3
    + + +## Automated Detection + +
    Tool Version Checker Description
    CodeSonar 6.2p0 LANG.MEM.UVAR Uninitialized Variable
    Helix QAC 2021.3 C4861, C4862, C4863 C++4861, C++4862, C++4863
    LDRA tool suite 9.7.1 44 S Enhanced enforcement
    Parasoft C/C++test 2021.2 CERT_C-FIO40-a Reset strings on fgets() or fgetws() failure
    Polyspace Bug Finder R2021a CERT C: Rule FIO40-C Checks for use of indeterminate string (rule partially covered)
    PRQA QA-C++ 4.4 2956
    PVS-Studio 7.17 V1024
    + + +## Related Vulnerabilities + +Search for [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) resulting from the violation of this rule on the [CERT website](https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+FIO40-C). + +## References + +* CERT-C: [FIO40-C: Reset strings on fgets() or fgetws() failure](https://wiki.sei.cmu.edu/confluence/display/c) diff --git a/c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.qhelp b/c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.qhelp deleted file mode 100644 index 753fc0162f..0000000000 --- a/c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.qhelp +++ /dev/null @@ -1,18 +0,0 @@ - - - - -

    This query implements the CERT-C rule FIO40-C:

    -
    -

    Reset strings on fgets() or fgetws() failure

    -
    -
    - - -
  • - CERT-C: - FIO40-C: Reset strings on fgets() or fgetws() failure - . -
  • -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO40-C/standard-example.c b/c/cert/src/rules/FIO40-C/standard-example.c deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/c/cert/src/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects-standard.qhelp b/c/cert/src/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects-standard.qhelp deleted file mode 100644 index 12049ae1c2..0000000000 --- a/c/cert/src/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects-standard.qhelp +++ /dev/null @@ -1,363 +0,0 @@ - - -
    -

    Do not invoke getc() or putc() or their wide-character analogues getwc() and putwc() with a stream argument that has side effects. The stream argument passed to these macros may be evaluated more than once if these functions are implemented as unsafe macros. (See PRE31-C. Avoid side effects in arguments to unsafe macros for more information.)

    -

    This rule does not apply to the character argument in putc() or the wide-character argument in putwc(), which is guaranteed to be evaluated exactly once.

    -
    -
    -

    This noncompliant code example calls the getc() function with an expression as the stream argument. If getc() is implemented as a macro, the file may be opened multiple times. (See FIO24-C. Do not open a file that is already open.)

    - #include <stdio.h> - -void func(const char *file_name) { - FILE *fptr; - - int c = getc(fptr = fopen(file_name, "r")); - if (feof(fptr) || ferror(fptr)) { - /* Handle error */ - } - - if (fclose(fptr) == EOF) { - /* Handle error */ - } -} -

    This noncompliant code example also violates ERR33-C. Detect and handle standard library errors because the value returned by fopen() is not checked for errors.

    -
    -
    -

    In this compliant solution, fopen() is called before getc() and its return value is checked for errors:

    - #include <stdio.h> - -void func(const char *file_name) { - int c; - FILE *fptr; - - fptr = fopen(file_name, "r"); - if (fptr == NULL) { - /* Handle error */ - } - - c = getc(fptr); - if (c == EOF) { - /* Handle error */ - } - - if (fclose(fptr) == EOF) { - /* Handle error */ - } -} -
    -
    -

    In this noncompliant example, putc() is called with an expression as the stream argument. If putc() is implemented as a macro, this expression might be evaluated multiple times.

    - #include <stdio.h> - -void func(const char *file_name) { - FILE *fptr = NULL; - int c = 'a'; - - while (c <= 'z') { - if (putc(c++, fptr ? fptr : - (fptr = fopen(file_name, "w"))) == EOF) { - /* Handle error */ - } - } - - if (fclose(fptr) == EOF) { - /* Handle error */ - } -} -

    This noncompliant code example might appear safe even if the putc() macro evaluates its stream argument multiple times, as the ternary conditional expression ostensibly prevents multiple calls to fopen(). However, the assignment to fptr and the evaluation of fptr as the controlling expression of the ternary conditional expression can take place between the same sequence points, resulting in undefined behavior (a violation of EXP30-C. Do not depend on the order of evaluation for side effects). This code also violates ERR33-C. Detect and handle standard library errors because it fails to check the return value from fopen().

    -
    -
    -

    In this compliant solution, the stream argument to putc() no longer has side effects:

    - #include <stdio.h> - -void func(const char *file_name) { - int c = 'a'; - FILE *fptr = fopen(file_name, "w"); - - if (fptr == NULL) { - /* Handle error */ - } - - while (c <= 'z') { - if (putc(c++, fptr) == EOF) { - /* Handle error */ - } - } - - if (fclose(fptr) == EOF) { - /* Handle error */ - } -} -

    The expression c++ is perfectly safe because putc() guarantees to evaluate its character argument exactly once.

    -

    NOTE: The output of this compliant solution differs depending on the character set. For example, when run on a machine using an ASCII-derived code set such as ISO-8859 or Unicode, this solution will print out the 26 lowercase letters of the English alphabet. However, if run with an EBCDIC-based code set, such as Codepage 037 or Codepage 285, punctuation marks or symbols may be output between the letters.

    -
    -
    -

    Using an expression that has side effects as the stream argument to getc(), putc(), or getwc() can result in unexpected behavior and abnormal program termination.

    - - - - - - - - - - - - - - - - - - - -
    - Rule - - Severity - - Likelihood - - Remediation Cost - - Priority - - Level -
    - FIO41-C - - Low - - Unlikely - - Medium - - P2 - - L3 -
    -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - Tool - - Version - - Checker - - Description -
    - - Astrée - - - 20.10 - - stream-argument-with-side-effects - - Fully checked -
    - - Axivion Bauhaus Suite - - - 7.2.0 - - CertC-FIO41 - -
    - - Helix QAC - - - 2021.3 - - C5036 - C++3225, C++3229 - -
    - - LDRA tool suite - - - 9.7.1 - - 35 D, 1 Q, 9 S,30 S, 134 S - - Fully implemented -
    - - Parasoft C/C++test - - - 2021.2 - - CERT_C-FIO41-a - CERT_C-FIO41-b - CERT_C-FIO41-c - CERT_C-FIO41-d - CERT_C-FIO41-e - - The value of an expression shall be the same under any order of evaluation that the standard permits - Don't write code that depends on the order of evaluation of function arguments - Don't write code that depends on the order of evaluation of function designator and function arguments - Don't write code that depends on the order of evaluation of expression that involves a function call - A full expression containing an increment (++) or decrement (--) operator should have no other potential side effects -
    - - Polyspace Bug Finder - - - R2021a - - - CERT C: Rule FIO41-C - - - Checks for stream arguments with possibly unintended side effects (rule fully covered) -
    - - PRQA QA-C - - - 9.7 - - 5036 - -
    - - PRQA QA-C++ - - - 4.4 - - 3225, 3229 - -
    - - RuleChecker - - - 20.10 - - stream-argument-with-side-effects - - Fully checked -
    -
    -
    -

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    -
    -
    -

    Key here (explains table format and definitions)

    - - - - - - - - - - - - - - - - - - -
    - Taxonomy - - Taxonomy item - - Relationship -
    - - CERT C Secure Coding Standard - - - - FIO24-C. Do not open a file that is already open - - - Prior to 2018-01-12: CERT: Unspecified Relationship -
    - - CERT C Secure Coding Standard - - - - EXP30-C. Do not depend on the order of evaluation for side effects - - - Prior to 2018-01-12: CERT: Unspecified Relationship -
    -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects.md b/c/cert/src/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects.md new file mode 100644 index 0000000000..2bb65dee2e --- /dev/null +++ b/c/cert/src/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects.md @@ -0,0 +1,143 @@ +# FIO41-C: Do not call getc(), putc(), getwc(), or putwc() with a stream argument that has side effects + +This query implements the CERT-C rule FIO41-C: + +> Do not call getc(), putc(), getwc(), or putwc() with a stream argument that has side effects + + +## Description + +Do not invoke `getc()` or `putc()` or their wide-character analogues `getwc()` and `putwc()` with a stream argument that has side effects. The stream argument passed to these macros may be evaluated more than once if these functions are implemented as unsafe macros. (See [PRE31-C. Avoid side effects in arguments to unsafe macros](https://wiki.sei.cmu.edu/confluence/display/c/PRE31-C.+Avoid+side+effects+in+arguments+to+unsafe+macros) for more information.) + +This rule does not apply to the character argument in `putc()` or the wide-character argument in `putwc()`, which is guaranteed to be evaluated exactly once. + +## Noncompliant Code Example (getc()) + +This noncompliant code example calls the `getc()` function with an expression as the stream argument. If `getc()` is implemented as a macro, the file may be opened multiple times. (See [FIO24-C. Do not open a file that is already open](https://wiki.sei.cmu.edu/confluence/display/c/FIO24-C.+Do+not+open+a+file+that+is+already+open).) + +```cpp +#include + +void func(const char *file_name) { + FILE *fptr; + + int c = getc(fptr = fopen(file_name, "r")); + if (feof(fptr) || ferror(fptr)) { + /* Handle error */ + } + + if (fclose(fptr) == EOF) { + /* Handle error */ + } +} +``` +This noncompliant code example also violates [ERR33-C. Detect and handle standard library errors](https://wiki.sei.cmu.edu/confluence/display/c/ERR33-C.+Detect+and+handle+standard+library+errors) because the value returned by `fopen()` is not checked for errors. + +## Compliant Solution (getc()) + +In this compliant solution, `fopen()` is called before `getc()` and its return value is checked for errors: + +```cpp +#include + +void func(const char *file_name) { + int c; + FILE *fptr; + + fptr = fopen(file_name, "r"); + if (fptr == NULL) { + /* Handle error */ + } + + c = getc(fptr); + if (c == EOF) { + /* Handle error */ + } + + if (fclose(fptr) == EOF) { + /* Handle error */ + } +} +``` + +## Noncompliant Code Example (putc()) + +In this noncompliant example, `putc()` is called with an expression as the stream argument. If `putc()` is implemented as a macro, this expression might be evaluated multiple times. + +```cpp +#include + +void func(const char *file_name) { + FILE *fptr = NULL; + int c = 'a'; + + while (c <= 'z') { + if (putc(c++, fptr ? fptr : + (fptr = fopen(file_name, "w"))) == EOF) { + /* Handle error */ + } + } + + if (fclose(fptr) == EOF) { + /* Handle error */ + } +} +``` +This noncompliant code example might appear safe even if the `putc()` macro evaluates its stream argument multiple times, as the ternary conditional expression ostensibly prevents multiple calls to `fopen()`. However, the assignment to `fptr` and the evaluation of `fptr` as the controlling expression of the ternary conditional expression can take place between the same sequence points, resulting in [undefined behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior) (a violation of [EXP30-C. Do not depend on the order of evaluation for side effects](https://wiki.sei.cmu.edu/confluence/display/c/EXP30-C.+Do+not+depend+on+the+order+of+evaluation+for+side+effects)). This code also violates [ERR33-C. Detect and handle standard library errors](https://wiki.sei.cmu.edu/confluence/display/c/ERR33-C.+Detect+and+handle+standard+library+errors) because it fails to check the return value from `fopen()`. + +## Compliant Solution (putc()) + +In this compliant solution, the stream argument to `putc()` no longer has side effects: + +```cpp +#include + +void func(const char *file_name) { + int c = 'a'; + FILE *fptr = fopen(file_name, "w"); + + if (fptr == NULL) { + /* Handle error */ + } + + while (c <= 'z') { + if (putc(c++, fptr) == EOF) { + /* Handle error */ + } + } + + if (fclose(fptr) == EOF) { + /* Handle error */ + } +} +``` +The expression `c++` is perfectly safe because `putc()` guarantees to evaluate its character argument exactly once. + +NOTE: The output of this compliant solution differs depending on the character set. For example, when run on a machine using an ASCII-derived code set such as ISO-8859 or Unicode, this solution will print out the 26 lowercase letters of the English alphabet. However, if run with an EBCDIC-based code set, such as Codepage 037 or Codepage 285, punctuation marks or symbols may be output between the letters. + +## Risk Assessment + +Using an expression that has side effects as the stream argument to `getc()`, `putc()`, or `getwc()` can result in [unexpected behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-unexpectedbehavior) and [abnormal program termination](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-abnormaltermination). + +
    Rule Severity Likelihood Remediation Cost Priority Level
    FIO41-C Low Unlikely Medium P2 L3
    + + +## Automated Detection + +
    Tool Version Checker Description
    Astrée 20.10 stream-argument-with-side-effects Fully checked
    Axivion Bauhaus Suite 7.2.0 CertC-FIO41
    Helix QAC 2021.3 C5036 C++3225, C++3229
    LDRA tool suite 9.7.1 35 D, 1 Q, 9 S,30 S, 134 S Fully implemented
    Parasoft C/C++test 2021.2 CERT_C-FIO41-a CERT_C-FIO41-b CERT_C-FIO41-c CERT_C-FIO41-d CERT_C-FIO41-e The value of an expression shall be the same under any order of evaluation that the standard permits Don't write code that depends on the order of evaluation of function arguments Don't write code that depends on the order of evaluation of function designator and function arguments Don't write code that depends on the order of evaluation of expression that involves a function call A full expression containing an increment (++) or decrement (--) operator should have no other potential side effects
    Polyspace Bug Finder R2021a CERT C: Rule FIO41-C Checks for stream arguments with possibly unintended side effects (rule fully covered)
    PRQA QA-C 9.7 5036
    PRQA QA-C++ 4.4 3225, 3229
    RuleChecker 20.10 stream-argument-with-side-effects Fully checked
    + + +## Related Vulnerabilities + +Search for [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) resulting from the violation of this rule on the [CERT website](https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+FIO41-C). + +## Related Guidelines + +[Key here](https://wiki.sei.cmu.edu/confluence/display/c/How+this+Coding+Standard+is+Organized#HowthisCodingStandardisOrganized-RelatedGuidelines) (explains table format and definitions) + +
    Taxonomy Taxonomy item Relationship
    CERT C Secure Coding Standard FIO24-C. Do not open a file that is already open Prior to 2018-01-12: CERT: Unspecified Relationship
    CERT C Secure Coding Standard EXP30-C. Do not depend on the order of evaluation for side effects Prior to 2018-01-12: CERT: Unspecified Relationship
    + + +## References + +* CERT-C: [FIO41-C: Do not call getc(), putc(), getwc(), or putwc() with a stream argument that has side effects](https://wiki.sei.cmu.edu/confluence/display/c) diff --git a/c/cert/src/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects.qhelp b/c/cert/src/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects.qhelp deleted file mode 100644 index 9555b25cf1..0000000000 --- a/c/cert/src/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects.qhelp +++ /dev/null @@ -1,18 +0,0 @@ - - - - -

    This query implements the CERT-C rule FIO41-C:

    -
    -

    Do not call getc(), putc(), getwc(), or putwc() with a stream argument that has side effects

    -
    -
    - - -
  • - CERT-C: - FIO41-C: Do not call getc(), putc(), getwc(), or putwc() with a stream argument that has side effects - . -
  • -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO41-C/standard-example.c b/c/cert/src/rules/FIO41-C/standard-example.c deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/c/cert/src/rules/FIO42-C/CloseFilesWhenTheyAreNoLongerNeeded-standard.qhelp b/c/cert/src/rules/FIO42-C/CloseFilesWhenTheyAreNoLongerNeeded-standard.qhelp deleted file mode 100644 index 6343d9015a..0000000000 --- a/c/cert/src/rules/FIO42-C/CloseFilesWhenTheyAreNoLongerNeeded-standard.qhelp +++ /dev/null @@ -1,604 +0,0 @@ - - -
    -

    A call to the fopen() or freopen() function must be matched with a call to fclose() before the lifetime of the last pointer that stores the return value of the call has ended or before normal program termination, whichever occurs first.

    -

    In general, this rule should also be applied to other functions with open and close resources, such as the POSIX open() and close() functions, or the Microsoft Windows CreateFile() and CloseHandle() functions.

    -
    -
    -

    This code example is noncompliant because the file opened by the call to fopen() is not closed before function func() returns:

    - #include <stdio.h> - -int func(const char *filename) { - FILE *f = fopen(filename, "r"); - if (NULL == f) { - return -1; - } - /* ... */ - return 0; -} -
    -
    -

    In this compliant solution, the file pointed to by f is closed before returning to the caller:

    - #include <stdio.h> - -int func(const char *filename) { - FILE *f = fopen(filename, "r"); - if (NULL == f) { - return -1; - } - /* ... */ - if (fclose(f) == EOF) { - return -1; - } - return 0; -} -
    -
    -

    This code example is noncompliant because the resource allocated by the call to fopen() is not closed before the program terminates. Although exit() closes the file, the program has no way of determining if an error occurs while flushing or closing the file.

    - #include <stdio.h> -#include <stdlib.h> - -int main(void) { - FILE *f = fopen(filename, "w"); - if (NULL == f) { - exit(EXIT_FAILURE); - } - /* ... */ - exit(EXIT_SUCCESS); -} -
    -
    -

    In this compliant solution, the program closes f explicitly before calling exit(), allowing any error that occurs when flushing or closing the file to be handled appropriately:

    - #include <stdio.h> -#include <stdlib.h> - -int main(void) { - FILE *f = fopen(filename, "w"); - if (NULL == f) { - /* Handle error */ - } - /* ... */ - if (fclose(f) == EOF) { - /* Handle error */ - } - exit(EXIT_SUCCESS); -} -
    -
    -

    This code example is noncompliant because the resource allocated by the call to open() is not closed before function func() returns:

    - #include <stdio.h> -#include <fcntl.h> - -int func(const char *filename) { - int fd = open(filename, O_RDONLY, S_IRUSR); - if (-1 == fd) { - return -1; - } - /* ... */ - return 0; -} -
    -
    -

    In this compliant solution, fd is closed before returning to the caller:

    - #include <stdio.h> -#include <fcntl.h> -#include <unistd.h> - -int func(const char *filename) { - int fd = open(filename, O_RDONLY, S_IRUSR); - if (-1 == fd) { - return -1 - } - /* ... */ - if (-1 == close(fd)) { - return -1; - } - return 0; -} -
    -
    -

    In this noncompliant code example, the file opened by the Microsoft Windows CreateFile() function is not closed before func() returns:

    - #include <Windows.h> - -int func(LPCTSTR filename) { - HANDLE hFile = CreateFile(filename, GENERIC_READ, 0, NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, NULL); - if (INVALID_HANDLE_VALUE == hFile) { - return -1; - } - /* ... */ - return 0; -} -
    -
    -

    In this compliant solution, hFile is closed by invoking the CloseHandle() function before returning to the caller:

    - #include <Windows.h> - -int func(LPCTSTR filename) { - HANDLE hFile = CreateFile(filename, GENERIC_READ, 0, NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, NULL); - if (INVALID_HANDLE_VALUE == hFile) { - return -1; - } - /* ... */ - if (!CloseHandle(hFile)) { - return -1; - } - - return 0; -} -
    -
    -

    Failing to properly close files may allow an attacker to exhaust system resources and can increase the risk that data written into in-memory file buffers will not be flushed in the event of abnormal program termination.

    - - - - - - - - - - - - - - - - - - - -
    - Rule - - Severity - - Likelihood - - Remediation Cost - - Priority - - Level -
    - FIO42-C - - Medium - - Unlikely - - Medium - - P4 - - L3 -
    -
    -
    -

    This rule is stricter than rule [fileclose] in ISO/IEC TS 17961:2013. Analyzers that conform to the technical standard may not detect all violations of this rule.

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - Tool - - Version - - Checker - - Description -
    - - Astrée - - - 20.10 - - - Supported, but no explicit checker -
    - - CodeSonar - - - 6.2p0 - - ALLOC.LEAK - - Leak -
    - - Compass/ROSE - - - - -
    - - Coverity - - - 2017.07 - - RESOURCE_LEAK (partial) - - Partially implemented -
    - - Helix QAC - - - 2021.3 - - C2701, C2702, C2703 - C++2701, C++2702, C++2703 - -
    - - Klocwork - - - 2021.4 - - RH.LEAK - -
    - - LDRA tool suite - - - 9.7.1 - - 49 D - - Partially implemented -
    - - Parasoft C/C++test - - - 2021.2 - - CERT_C-FIO42-a - - Ensure resources are freed -
    - - PC-lint Plus - - - 1.4 - - 429 - - Partially supported -
    - - Polyspace Bug Finder - - - R2021a - - - CERT C: Rule FIO42-C - - - Checks for resource leak (rule partially covered) -
    - - PRQA QA-C - - - 9.7 - - 2701, 2702, 2703 - -
    - - PRQA QA-C++ - - - 4.4 - - 2701, 2702, 2703 - -
    - - SonarQube C/C++ Plugin - - - 3.11 - - S2095 - -
    -
    -
    -

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    -
    -
    -

    Key here (explains table format and definitions)

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - Taxonomy - - Taxonomy item - - Relationship -
    - - CERT C - - - - FIO51-CPP. Close files when they are no longer needed - - - Prior to 2018-01-12: CERT: Unspecified Relationship -
    - - CERT Oracle Secure Coding Standard for Java - - - - FIO04-J. Release resources when they are no longer needed - - - Prior to 2018-01-12: CERT: Unspecified Relationship -
    - - ISO/IEC TS 17961:2013 - - - Failing to close files or free dynamic memory when they are no longer needed [fileclose] - - Prior to 2018-01-12: CERT: Unspecified Relationship -
    - - CWE 2.11 - - - - CWE-404 - - , Improper Resource Shutdown or Release - - 2017-07-06: CERT: Rule subset of CWE -
    - - CWE 2.11 - - - - CWE-459 - - - 2017-07-06: CERT: Rule subset of CWE -
    - - CWE 2.11 - - - - CWE-772 - - - 2017-07-06: CERT: Rule subset of CWE -
    - - CWE 2.11 - - - - CWE-773 - - - 2017-07-06: CERT: Rule subset of CWE -
    - - CWE 2.11 - - - - CWE-775 - - - 2017-07-06: CERT: Rule subset of CWE -
    - - CWE 2.11 - - - - CWE-403 - - - 2017-10-30:MITRE:Unspecified Relationship - 2018-10-18:CERT: - Partial overlap -
    -
    -
    -

    Key here for mapping notes

    -

    CWE-773/CWE-775 and FIO42-C

    -

    CWE-773 = CWE-775

    -

    CWE-773 = Union( FIO42-C, list) where list =

    -
      -
    • Failure to free resource handles besides files
    • -
    -

    CWE-404/CWE-459/CWE-771/CWE-772 and FIO42-C/MEM31-C

    -

    Intersection( FIO42-C, MEM31-C) = Ø

    -

    CWE-404 = CWE-459 = CWE-771 = CWE-772

    -

    CWE-404 = Union( FIO42-C, MEM31-C list) where list =

    -
      -
    • Failure to free resources besides files or memory chunks, such as mutexes)
    • -
    -

    CWE-403 and FIO42-C

    -

    CWE-403 - FIO42-C = list, where list =

    -
      -
    • A process opens and closes a sensitive file descriptor, but also executes a child process while the file descriptor is open.
    • -
    -

    FIO42-C - CWE-403 = SPECIAL_CASES, where SPECIAL_CASES =

    -
      -
    • A program opens a file descriptor and fails to close it, but does not invoke any child processes while the file descriptor is open.
    • -
    -
    -
    - - - - - - - -
    - [ - - IEEE Std 1003.1:2013 - - ] - - XSH, System Interfaces, - open -
    -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO42-C/CloseFilesWhenTheyAreNoLongerNeeded.md b/c/cert/src/rules/FIO42-C/CloseFilesWhenTheyAreNoLongerNeeded.md new file mode 100644 index 0000000000..f4d720d307 --- /dev/null +++ b/c/cert/src/rules/FIO42-C/CloseFilesWhenTheyAreNoLongerNeeded.md @@ -0,0 +1,232 @@ +# FIO42-C: Close files when they are no longer needed + +This query implements the CERT-C rule FIO42-C: + +> Close files when they are no longer needed + + +## Description + +A call to the `fopen()` or `freopen()` function must be matched with a call to `fclose()` before the lifetime of the last pointer that stores the return value of the call has ended or before normal program termination, whichever occurs first. + +In general, this rule should also be applied to other functions with open and close resources, such as the POSIX `open()` and `close()` functions, or the Microsoft Windows `CreateFile()` and `CloseHandle()` functions. + +## Noncompliant Code Example + +This code example is noncompliant because the file opened by the call to `fopen()` is not closed before function `func()` returns: + +```cpp +#include + +int func(const char *filename) { + FILE *f = fopen(filename, "r"); + if (NULL == f) { + return -1; + } + /* ... */ + return 0; +} +``` + +## Compliant Solution + +In this compliant solution, the file pointed to by `f` is closed before returning to the caller: + +```cpp +#include + +int func(const char *filename) { + FILE *f = fopen(filename, "r"); + if (NULL == f) { + return -1; + } + /* ... */ + if (fclose(f) == EOF) { + return -1; + } + return 0; +} +``` + +## Noncompliant Code Example (exit()) + +This code example is noncompliant because the resource allocated by the call to `fopen()` is not closed before the program terminates. Although `exit()` closes the file, the program has no way of determining if an error occurs while flushing or closing the file. + +```cpp +#include +#include + +int main(void) { + FILE *f = fopen(filename, "w"); + if (NULL == f) { + exit(EXIT_FAILURE); + } + /* ... */ + exit(EXIT_SUCCESS); +} +``` + +## Compliant Solution (exit()) + +In this compliant solution, the program closes `f` explicitly before calling `exit()`, allowing any error that occurs when flushing or closing the file to be handled appropriately: + +```cpp +#include +#include + +int main(void) { + FILE *f = fopen(filename, "w"); + if (NULL == f) { + /* Handle error */ + } + /* ... */ + if (fclose(f) == EOF) { + /* Handle error */ + } + exit(EXIT_SUCCESS); +} +``` + +## Noncompliant Code Example (POSIX) + +This code example is noncompliant because the resource allocated by the call to `open()` is not closed before function `func()` returns: + +```cpp +#include +#include + +int func(const char *filename) { + int fd = open(filename, O_RDONLY, S_IRUSR); + if (-1 == fd) { + return -1; + } + /* ... */ + return 0; +} +``` + +## Compliant Solution (POSIX) + +In this compliant solution, `fd` is closed before returning to the caller: + +```cpp +#include +#include +#include + +int func(const char *filename) { + int fd = open(filename, O_RDONLY, S_IRUSR); + if (-1 == fd) { + return -1 + } + /* ... */ + if (-1 == close(fd)) { + return -1; + } + return 0; +} +``` + +## Noncompliant Code Example (Windows) + +In this noncompliant code example, the file opened by the Microsoft Windows `[CreateFile()](http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx)` function is not closed before `func()` returns: + +```cpp +#include + +int func(LPCTSTR filename) { + HANDLE hFile = CreateFile(filename, GENERIC_READ, 0, NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + if (INVALID_HANDLE_VALUE == hFile) { + return -1; + } + /* ... */ + return 0; +} +``` + +## Compliant Solution (Windows) + +In this compliant solution, `hFile` is closed by invoking the `[CloseHandle()](http://msdn.microsoft.com/en-us/library/windows/desktop/ms724211(v=vs.85).aspx)` function before returning to the caller: + +```cpp +#include + +int func(LPCTSTR filename) { + HANDLE hFile = CreateFile(filename, GENERIC_READ, 0, NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + if (INVALID_HANDLE_VALUE == hFile) { + return -1; + } + /* ... */ + if (!CloseHandle(hFile)) { + return -1; + } + + return 0; +} +``` + +## Risk Assessment + +Failing to properly close files may allow an attacker to exhaust system resources and can increase the risk that data written into in-memory file buffers will not be flushed in the event of [abnormal program termination](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-abnormaltermination). + +
    Rule Severity Likelihood Remediation Cost Priority Level
    FIO42-C Medium Unlikely Medium P4 L3
    + + +## Automated Detection + +This rule is stricter than rule \[fileclose\] in [ISO/IEC TS 17961:2013](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO-IECTS17961). Analyzers that conform to the technical standard may not detect all violations of this rule. + +
    Tool Version Checker Description
    Astrée 20.10 Supported, but no explicit checker
    CodeSonar 6.2p0 ALLOC.LEAK Leak
    Compass/ROSE
    Coverity 2017.07 RESOURCE_LEAK (partial) Partially implemented
    Helix QAC 2021.3 C2701, C2702, C2703 C++2701, C++2702, C++2703
    Klocwork 2021.4 RH.LEAK
    LDRA tool suite 9.7.1 49 D Partially implemented
    Parasoft C/C++test 2021.2 CERT_C-FIO42-a Ensure resources are freed
    PC-lint Plus 1.4 429 Partially supported
    Polyspace Bug Finder R2021a CERT C: Rule FIO42-C Checks for resource leak (rule partially covered)
    PRQA QA-C 9.7 2701, 2702, 2703
    PRQA QA-C++ 4.4 2701, 2702, 2703
    SonarQube C/C++ Plugin 3.11 S2095
    + + +## Related Vulnerabilities + +Search for [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) resulting from the violation of this rule on the [CERT website](https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+FIO42-C). + +## Related Guidelines + +[Key here](https://wiki.sei.cmu.edu/confluence/display/c/How+this+Coding+Standard+is+Organized#HowthisCodingStandardisOrganized-RelatedGuidelines) (explains table format and definitions) + +
    Taxonomy Taxonomy item Relationship
    CERT C FIO51-CPP. Close files when they are no longer needed Prior to 2018-01-12: CERT: Unspecified Relationship
    CERT Oracle Secure Coding Standard for Java FIO04-J. Release resources when they are no longer needed Prior to 2018-01-12: CERT: Unspecified Relationship
    ISO/IEC TS 17961:2013 Failing to close files or free dynamic memory when they are no longer needed \[fileclose\] Prior to 2018-01-12: CERT: Unspecified Relationship
    CWE 2.11 CWE-404 , Improper Resource Shutdown or Release 2017-07-06: CERT: Rule subset of CWE
    CWE 2.11 CWE-459 2017-07-06: CERT: Rule subset of CWE
    CWE 2.11 CWE-772 2017-07-06: CERT: Rule subset of CWE
    CWE 2.11 CWE-773 2017-07-06: CERT: Rule subset of CWE
    CWE 2.11 CWE-775 2017-07-06: CERT: Rule subset of CWE
    CWE 2.11 CWE-403 2017-10-30:MITRE:Unspecified Relationship 2018-10-18:CERT: Partial overlap
    + + +## CERT-CWE Mapping Notes + +[Key here](https://wiki.sei.cmu.edu/confluence/pages/viewpage.action?pageId=87152408#HowthisCodingStandardisOrganized-CERT-CWEMappingNotes) for mapping notes + +**CWE-773/CWE-775 and FIO42-C** + +CWE-773 = CWE-775 + +CWE-773 = Union( FIO42-C, list) where list = + +* Failure to free resource handles besides files +**CWE-404/CWE-459/CWE-771/CWE-772 and FIO42-C/MEM31-C** + +Intersection( FIO42-C, MEM31-C) = Ø + +CWE-404 = CWE-459 = CWE-771 = CWE-772 + +CWE-404 = Union( FIO42-C, MEM31-C list) where list = + +* Failure to free resources besides files or memory chunks, such as mutexes) +**CWE-403 and FIO42-C** + +CWE-403 - FIO42-C = list, where list = + +* A process opens and closes a sensitive file descriptor, but also executes a child process while the file descriptor is open. +FIO42-C - CWE-403 = SPECIAL_CASES, where SPECIAL_CASES = +* A program opens a file descriptor and fails to close it, but does not invoke any child processes while the file descriptor is open. + +## Bibliography + +
    \[ IEEE Std 1003.1:2013 \] XSH, System Interfaces, open
    + + +## References + +* CERT-C: [FIO42-C: Close files when they are no longer needed](https://wiki.sei.cmu.edu/confluence/display/c) diff --git a/c/cert/src/rules/FIO42-C/CloseFilesWhenTheyAreNoLongerNeeded.qhelp b/c/cert/src/rules/FIO42-C/CloseFilesWhenTheyAreNoLongerNeeded.qhelp deleted file mode 100644 index 8349d80e59..0000000000 --- a/c/cert/src/rules/FIO42-C/CloseFilesWhenTheyAreNoLongerNeeded.qhelp +++ /dev/null @@ -1,18 +0,0 @@ - - - - -

    This query implements the CERT-C rule FIO42-C:

    -
    -

    Close files when they are no longer needed

    -
    -
    - - -
  • - CERT-C: - FIO42-C: Close files when they are no longer needed - . -
  • -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO42-C/standard-example.c b/c/cert/src/rules/FIO42-C/standard-example.c deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos-standard.qhelp b/c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos-standard.qhelp deleted file mode 100644 index 2246be232f..0000000000 --- a/c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos-standard.qhelp +++ /dev/null @@ -1,331 +0,0 @@ - - -
    -

    The C Standard, 7.21.9.3 [ISO/IEC 9899:2011], defines the following behavior for fsetpos():

    -
    -

    The fsetpos function sets the mbstate_t object (if any) and file position indicator for the stream pointed to by stream according to the value of the object pointed to by pos, which shall be a value obtained from an earlier successful call to the fgetpos function on a stream associated with the same file.

    -
    -

    Invoking the fsetpos() function with any other values for pos is undefined behavior.

    -
    -
    -

    This noncompliant code example attempts to read three values from a file and then set the file position pointer back to the beginning of the file:

    - #include <stdio.h> -#include <string.h> - -int opener(FILE *file) { - int rc; - fpos_t offset; - - memset(&offset, 0, sizeof(offset)); - - if (file == NULL) { - return -1; - } - - /* Read in data from file */ - - rc = fsetpos(file, &offset); - if (rc != 0 ) { - return rc; - } - - return 0; -} - -

    Only the return value of an fgetpos() call is a valid argument to fsetpos(); passing a value of type fpos_t that was created in any other way is undefined behavior.

    -
    -
    -

    In this compliant solution, the initial file position indicator is stored by first calling fgetpos(), which is used to restore the state to the beginning of the file in the later call to fsetpos():

    - #include <stdio.h> -#include <string.h> - -int opener(FILE *file) { - int rc; - fpos_t offset; - - if (file == NULL) { - return -1; - } - - rc = fgetpos(file, &offset); - if (rc != 0 ) { - return rc; - } - - /* Read in data from file */ - - rc = fsetpos(file, &offset); - if (rc != 0 ) { - return rc; - } - - return 0; -} - -
    -
    -

    Misuse of the fsetpos() function can position a file position indicator to an unintended location in the file.

    - - - - - - - - - - - - - - - - - - - -
    - Rule - - Severity - - Likelihood - - Remediation Cost - - Priority - - Level -
    - FIO44-C - - Medium - - Unlikely - - Medium - - P4 - - L3 -
    -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - Tool - - Version - - Checker - - Description -
    - - CodeSonar - - - 6.2p0 - - (customization) - - Users can add a custom check for violations of this constraint. -
    - - Compass/ROSE - - - - - Can detect common violations of this rule. However, it cannot handle cases in which the value returned by - fgetpos() - is copied between several variables before being passed to - fsetpos() -
    - - Helix QAC - - - 2021.3 - - C4841, C4842, C4843 - C++4841, C++4842, C++4843 - -
    - - LDRA tool suite - - - 9.7.1 - - 82 D - - Fully implemented -
    - - Parasoft C/C++test - - - 2021.2 - - CERT_C-FIO44-a - - Only use values for fsetpos() that are returned from fgetpos() -
    - - Polyspace Bug Finder - - - - - CERT C: Rule FIO44-C - - - Checks for invalid file position (rule partially covered) -
    - - PRQA QA-C - - - 9.7 - - 4841, 4842, 4843 - - Enforced by QAC -
    - - PRQA QA-C++ - - - 4.4 - - 4841, 4842, 4843 - -
    - - PVS-Studio - - - 7.17 - - V1035 - -
    -
    -
    -

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    -
    -
    -

    Key here (explains table format and definitions)

    - - - - - - - - - - - - - -
    - Taxonomy - - Taxonomy item - - Relationship -
    - - ISO/IEC TS 17961:2013 - - - Using a value for fsetpos other than a value returned from fgetpos [xfilepos] - - Prior to 2018-01-12: CERT: Unspecified Relationship -
    -
    -
    - - - - - - - -
    - [ - - ISO/IEC 9899:2011 - - ] - - 7.21.9.3, "The - fsetpos - Function" -
    -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.md b/c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.md new file mode 100644 index 0000000000..8b05eb8b02 --- /dev/null +++ b/c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.md @@ -0,0 +1,111 @@ +# FIO44-C: Only use values for fsetpos() that are returned from fgetpos() + +This query implements the CERT-C rule FIO44-C: + +> Only use values for fsetpos() that are returned from fgetpos() + + +## Description + +The C Standard, 7.21.9.3 \[[ISO/IEC 9899:2011](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO-IEC9899-2011)\], defines the following behavior for `fsetpos()`: + +> The `fsetpos` function sets the `mbstate_t` object (if any) and file position indicator for the stream pointed to by `stream` according to the value of the object pointed to by `pos`, which shall be a value obtained from an earlier successful call to the `fgetpos` function on a stream associated with the same file. + + +Invoking the `fsetpos()` function with any other values for `pos` is [undefined behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior). + +## Noncompliant Code Example + +This noncompliant code example attempts to read three values from a file and then set the file position pointer back to the beginning of the file: + +```cpp +#include +#include + +int opener(FILE *file) { + int rc; + fpos_t offset; + + memset(&offset, 0, sizeof(offset)); + + if (file == NULL) { + return -1; + } + + /* Read in data from file */ + + rc = fsetpos(file, &offset); + if (rc != 0 ) { + return rc; + } + + return 0; +} + +``` +Only the return value of an `fgetpos()` call is a valid argument to `fsetpos()`; passing a value of type `fpos_t` that was created in any other way is [undefined behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior). + +## Compliant Solution + +In this compliant solution, the initial file position indicator is stored by first calling `fgetpos()`, which is used to restore the state to the beginning of the file in the later call to `fsetpos()`: + +```cpp +#include +#include + +int opener(FILE *file) { + int rc; + fpos_t offset; + + if (file == NULL) { + return -1; + } + + rc = fgetpos(file, &offset); + if (rc != 0 ) { + return rc; + } + + /* Read in data from file */ + + rc = fsetpos(file, &offset); + if (rc != 0 ) { + return rc; + } + + return 0; +} + +``` + +## Risk Assessment + +Misuse of the `fsetpos()` function can position a file position indicator to an unintended location in the file. + +
    Rule Severity Likelihood Remediation Cost Priority Level
    FIO44-C Medium Unlikely Medium P4 L3
    + + +## Automated Detection + +
    Tool Version Checker Description
    CodeSonar 6.2p0 (customization) Users can add a custom check for violations of this constraint.
    Compass/ROSE Can detect common violations of this rule. However, it cannot handle cases in which the value returned by fgetpos() is copied between several variables before being passed to fsetpos()
    Helix QAC 2021.3 C4841, C4842, C4843 C++4841, C++4842, C++4843
    LDRA tool suite 9.7.1 82 D Fully implemented
    Parasoft C/C++test 2021.2 CERT_C-FIO44-a Only use values for fsetpos() that are returned from fgetpos()
    Polyspace Bug Finder CERT C: Rule FIO44-C Checks for invalid file position (rule partially covered)
    PRQA QA-C 9.7 4841, 4842, 4843 Enforced by QAC
    PRQA QA-C++ 4.4 4841, 4842, 4843
    PVS-Studio 7.17 V1035
    + + +## Related Vulnerabilities + +Search for [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) resulting from the violation of this rule on the [CERT website](https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+FIO44-C). + +## Related Guidelines + +[Key here](https://wiki.sei.cmu.edu/confluence/display/c/How+this+Coding+Standard+is+Organized#HowthisCodingStandardisOrganized-RelatedGuidelines) (explains table format and definitions) + +
    Taxonomy Taxonomy item Relationship
    ISO/IEC TS 17961:2013 Using a value for fsetpos other than a value returned from fgetpos \[xfilepos\] Prior to 2018-01-12: CERT: Unspecified Relationship
    + + +## Bibliography + +
    \[ ISO/IEC 9899:2011 \] 7.21.9.3, "The fsetpos Function"
    + + +## References + +* CERT-C: [FIO44-C: Only use values for fsetpos() that are returned from fgetpos()](https://wiki.sei.cmu.edu/confluence/display/c) diff --git a/c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.qhelp b/c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.qhelp deleted file mode 100644 index 9bd681d3f1..0000000000 --- a/c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.qhelp +++ /dev/null @@ -1,18 +0,0 @@ - - - - -

    This query implements the CERT-C rule FIO44-C:

    -
    -

    Only use values for fsetpos() that are returned from fgetpos()

    -
    -
    - - -
  • - CERT-C: - FIO44-C: Only use values for fsetpos() that are returned from fgetpos() - . -
  • -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO44-C/standard-example.c b/c/cert/src/rules/FIO44-C/standard-example.c deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/c/cert/src/rules/FIO46-C/UndefinedBehaviorAccessingAClosedFile-standard.qhelp b/c/cert/src/rules/FIO46-C/UndefinedBehaviorAccessingAClosedFile-standard.qhelp deleted file mode 100644 index 1f54ed624e..0000000000 --- a/c/cert/src/rules/FIO46-C/UndefinedBehaviorAccessingAClosedFile-standard.qhelp +++ /dev/null @@ -1,339 +0,0 @@ - - -
    -

    Using the value of a pointer to a FILE object after the associated file is closed is undefined behavior. (See undefined behavior 148.) Programs that close the standard streams (especially stdout but also stderr and stdin) must be careful not to use these streams in subsequent function calls, particularly those that implicitly operate on them (such as printf(), perror(), and getc()).

    -

    This rule can be generalized to other file representations.

    -
    -
    -

    In this noncompliant code example, the stdout stream is used after it is closed:

    - #include <stdio.h> - -int close_stdout(void) { - if (fclose(stdout) == EOF) { - return -1; - } - - printf("stdout successfully closed.\n"); - return 0; -} -
    -
    -

    In this compliant solution, stdout is not used again after it is closed. This must remain true for the remainder of the program, or stdout must be assigned the address of an open file object.

    - #include <stdio.h> - -int close_stdout(void) { - if (fclose(stdout) == EOF) { - return -1; - } - - fputs("stdout successfully closed.", stderr); - return 0; -} -
    -
    -

    Using the value of a pointer to a FILE object after the associated file is closed is undefined behavior.

    - - - - - - - - - - - - - - - - - - - -
    - Rule - - Severity - - Likelihood - - Remediation Cost - - Priority - - Level -
    - FIO46-C - - Medium - - Unlikely - - Medium - - P4 - - L3 -
    -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - Tool - - Version - - Checker - - Description -
    - - Astrée - - - 20.10 - - - Supported -
    - - CodeSonar - - - 6.2p0 - - IO.UAC - - Use after close -
    - - Compass/ROSE - - - - -
    - - Coverity - - - 2017.07 - - USE_AFTER_FREE - - Implemented -
    - - Helix QAC - - - 2021.3 - - C2696, C2697, C2698 - C++2696, C++2697, C++2698 - -
    - - Klocwork - - - 2021.4 - - SV.INCORRECT_RESOURCE_HANDLING.URH - -
    - - LDRA tool suite - - - 9.7.1 - - 48 D - - Partially implemented -
    - - Parasoft C/C++test - - - 2021.2 - - CERT_C-FIO46-a - - Do not use resources that have been freed -
    - - PC-lint Plus - - - 1.4 - - 2471 - - Fully supported -
    - - Polyspace Bug Finder - - - R2021a - - - CERT C: Rule FIO46-C - - - Checks for use of previously closed resource (rule partially covered) -
    - - PRQA QA-C - - - 9.7 - - 2696, 2697, 2698 - -
    - - PRQA QA-C++ - - - 4.4 - - 2696, 2697, 2698 - -
    - - SonarQube C/C++ Plugin - - - 3.11 - - S3588 - -
    -
    -
    -

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    -
    -
    - - - - - - - - - - - -
    - [ - - IEEE Std 1003.1:2013 - - ] - - XSH, System Interfaces, - open -
    - [ - - ISO/IEC 9899:2011 - - ] - - Subclause 7.21.3, "Files" - Subclause 7.21.5.1, "The - fclose - Function" -
    -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO46-C/UndefinedBehaviorAccessingAClosedFile.md b/c/cert/src/rules/FIO46-C/UndefinedBehaviorAccessingAClosedFile.md new file mode 100644 index 0000000000..607e494a9c --- /dev/null +++ b/c/cert/src/rules/FIO46-C/UndefinedBehaviorAccessingAClosedFile.md @@ -0,0 +1,71 @@ +# FIO46-C: Do not access a closed file + +This query implements the CERT-C rule FIO46-C: + +> Do not access a closed file + + +## Description + +Using the value of a pointer to a `FILE` object after the associated file is closed is [undefined behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior). (See [undefined behavior 148](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_148).) Programs that close the standard streams (especially `stdout` but also `stderr` and `stdin`) must be careful not to use these streams in subsequent function calls, particularly those that implicitly operate on them (such as `printf()`, `perror()`, and `getc()`). + +This rule can be generalized to other file representations. + +## Noncompliant Code Example + +In this noncompliant code example, the `stdout` stream is used after it is closed: + +```cpp +#include + +int close_stdout(void) { + if (fclose(stdout) == EOF) { + return -1; + } + + printf("stdout successfully closed.\n"); + return 0; +} +``` + +## Compliant Solution + +In this compliant solution, `stdout` is not used again after it is closed. This must remain true for the remainder of the program, or `stdout` must be assigned the address of an open file object. + +```cpp +#include + +int close_stdout(void) { + if (fclose(stdout) == EOF) { + return -1; + } + + fputs("stdout successfully closed.", stderr); + return 0; +} +``` + +## Risk Assessment + +Using the value of a pointer to a `FILE` object after the associated file is closed is [undefined behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior). + +
    Rule Severity Likelihood Remediation Cost Priority Level
    FIO46-C Medium Unlikely Medium P4 L3
    + + +## Automated Detection + +
    Tool Version Checker Description
    Astrée 20.10 Supported
    CodeSonar 6.2p0 IO.UAC Use after close
    Compass/ROSE
    Coverity 2017.07 USE_AFTER_FREE Implemented
    Helix QAC 2021.3 C2696, C2697, C2698 C++2696, C++2697, C++2698
    Klocwork 2021.4 SV.INCORRECT_RESOURCE_HANDLING.URH
    LDRA tool suite 9.7.1 48 D Partially implemented
    Parasoft C/C++test 2021.2 CERT_C-FIO46-a Do not use resources that have been freed
    PC-lint Plus 1.4 2471 Fully supported
    Polyspace Bug Finder R2021a CERT C: Rule FIO46-C Checks for use of previously closed resource (rule partially covered)
    PRQA QA-C 9.7 2696, 2697, 2698
    PRQA QA-C++ 4.4 2696, 2697, 2698
    SonarQube C/C++ Plugin 3.11 S3588
    + + +## Related Vulnerabilities + +Search for [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) resulting from the violation of this rule on the [CERT website](https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+FIO46-C). + +## Bibliography + +
    \[ IEEE Std 1003.1:2013 \] XSH, System Interfaces, open
    \[ ISO/IEC 9899:2011 \] Subclause 7.21.3, "Files" Subclause 7.21.5.1, "The fclose Function"
    + + +## References + +* CERT-C: [FIO46-C: Do not access a closed file](https://wiki.sei.cmu.edu/confluence/display/c) diff --git a/c/cert/src/rules/FIO46-C/UndefinedBehaviorAccessingAClosedFile.qhelp b/c/cert/src/rules/FIO46-C/UndefinedBehaviorAccessingAClosedFile.qhelp deleted file mode 100644 index 7858cad959..0000000000 --- a/c/cert/src/rules/FIO46-C/UndefinedBehaviorAccessingAClosedFile.qhelp +++ /dev/null @@ -1,18 +0,0 @@ - - - - -

    This query implements the CERT-C rule FIO46-C:

    -
    -

    Do not access a closed file

    -
    -
    - - -
  • - CERT-C: - FIO46-C: Do not access a closed file - . -
  • -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/FIO46-C/standard-example.c b/c/cert/src/rules/FIO46-C/standard-example.c deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/c/cert/src/rules/MSC30-C/RandUsedForGeneratingPseudorandomNumbers-standard.qhelp b/c/cert/src/rules/MSC30-C/RandUsedForGeneratingPseudorandomNumbers-standard.qhelp deleted file mode 100644 index 7d0bdffbc0..0000000000 --- a/c/cert/src/rules/MSC30-C/RandUsedForGeneratingPseudorandomNumbers-standard.qhelp +++ /dev/null @@ -1,597 +0,0 @@ - - -
    -

    Pseudorandom number generators use mathematical algorithms to produce a sequence of numbers with good statistical properties, but the numbers produced are not genuinely random.

    -

    The C Standard rand() function makes no guarantees as to the quality of the random sequence produced. The numbers generated by some implementations of rand() have a comparatively short cycle and the numbers can be predictable. Applications that have strong pseudorandom number requirements must use a generator that is known to be sufficient for their needs.

    -
    -
    -

    The following noncompliant code generates an ID with a numeric part produced by calling the rand() function. The IDs produced are predictable and have limited randomness.

    - #include <stdio.h> -#include <stdlib.h> -  -enum { len = 12 }; -  -void func(void) { - /* - * id will hold the ID, starting with the characters - * "ID" followed by a random integer. - */ -  char id[len]; - int r; - int num; - /* ... */ - r = rand(); /* Generate a random integer */ - num = snprintf(id, len, "ID%-d", r); /* Generate the ID */ - /* ... */ -} -
    -
    -

    This compliant solution replaces the rand() function with the POSIX random() function:

    - #include <stdio.h> -#include <stdlib.h> -#include <time.h> - -enum { len = 12 };  - -void func(void) { - /* - * id will hold the ID, starting with the characters - * "ID" followed by a random integer. - */ -  char id[len]; - int r; - int num; - /* ... */ - struct timespec ts; - if (timespec_get(&ts, TIME_UTC) == 0) { -  /* Handle error */ - } - srandom(ts.tv_nsec ^ ts.tv_sec); /* Seed the PRNG */ - /* ... */ - r = random(); /* Generate a random integer */ - num = snprintf(id, len, "ID%-d", r); /* Generate the ID */ - /* ... */ -} -

    The POSIX random() function is a better pseudorandom number generator. Although on some platforms the low dozen bits generated by rand() go through a cyclic pattern, all the bits generated by random() are usable. The rand48 family of functions provides another alternative for pseudorandom numbers.

    -

    Although not specified by POSIX, arc4random() is another possibility for systems that support it. The arc4random(3) manual page [OpenBSD] states

    -
    -

    ... provides higher quality of data than those described in rand(3), random(3), and drand48(3).

    -
    -

    To achieve the best random numbers possible, an implementation-specific function must be used. When unpredictability is crucial and speed is not an issue, as in the creation of strong cryptographic keys, use a true entropy source, such as /dev/random, or a hardware device capable of generating random numbers. The /dev/random device can block for a long time if there are not enough events going on to generate sufficient entropy.

    -
    -
    -

    On Windows platforms, the BCryptGenRandom() function can be used to generate cryptographically strong random numbers. The Microsoft Developer Network BCryptGenRandom() reference [MSDN] states:

    -
    -

    The default random number provider implements an algorithm for generating random numbers that complies with the NIST SP800-90 standard, specifically the CTR_DRBG portion of that standard.

    -
    - #include <Windows.h> -#include <bcrypt.h> -#include <stdio.h> - -#pragma comment(lib, "Bcrypt") - -void func(void) { - BCRYPT_ALG_HANDLE Prov; - int Buffer; - if (!BCRYPT_SUCCESS( - BCryptOpenAlgorithmProvider(&Prov, BCRYPT_RNG_ALGORITHM, - NULL, 0))) { - /* handle error */ - } - if (!BCRYPT_SUCCESS(BCryptGenRandom(Prov, (PUCHAR) (&Buffer), - sizeof(Buffer), 0))) { - /* handle error */ - } - printf("Random number: %d\n", Buffer); - BCryptCloseAlgorithmProvider(Prov, 0); -} -
    -
    -

    The use of the rand() function can result in predictable random numbers.

    - - - - - - - - - - - - - - - - - - - -
    - Rule - - Severity - - Likelihood - - Remediation Cost - - Priority - - Level -
    - MSC30-C - - Medium - - Unlikely - - Low - - P6 - - L2 -
    -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - Tool - - Version - - Checker - - Description -
    - - Astrée - - - 20.10 - - stdlib-use-rand - - Fully checked -
    - - Axivion Bauhaus Suite - - - 7.2.0 - - CertC-MSC30 - -
    - - Clang - - - 4.0 (prerelease) - - cert-msc30-c - - Checked by - clang-tidy -
    - - CodeSonar - - - 6.2p0 - - BADFUNC.RANDOM.RAND - - Use of rand -
    - - Compass/ROSE - - - - -
    - - Coverity - - - 2017.07 - - DONTCALL - - Implemented - weak support -
    - - ECLAIR - - - 1.2 - - CC2.MSC30 - - Fully implemented -
    - - Helix QAC - - - 2022.1 - - C5022 - C++5029 - -
    - - Klocwork - - - 2022.1 - - CERT.MSC.STD_RAND_CALL - -
    - - LDRA tool suite - - - 9.7.1 - - 44 S - - Enhanced enforcement -
    - - Parasoft C/C++test - - - 2021.2 - - CERT_C-MSC30-a - - Do not use the rand() function for generating pseudorandom numbers -
    - - PC-lint Plus - - - 1.4 - - 586 - - Fully supported -
    - - Polyspace Bug Finder - - - R2021a - - - CERT C: Rule MSC30-C - - - Checks for vulnerable pseudo-random number generator (rule fully covered) -
    - - PRQA QA-C - - - 9.7 - - 5022 - - Fully implemented -
    - - PRQA QA-C++ - - - 4.4 - - 5029 - -
    - - RuleChecker - - - 20.10 - - stdlib-use-rand - - Fully checked -
    -
    -
    -

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    -
    -
    -

    Key here (explains table format and definitions)

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - Taxonomy - - Taxonomy item - - Relationship -
    - - CERT C - - - - MSC50-CPP. Do not use std::rand() for generating pseudorandom numbers - - - Prior to 2018-01-12: CERT: Unspecified Relationship -
    - - CERT Oracle Secure Coding Standard for Java - - - - MSC02-J. Generate strong random numbers - - - Prior to 2018-01-12: CERT: Unspecified Relationship -
    - - CWE 2.11 - - - - CWE-327 - - , Use of a Broken or Risky Cryptographic Algorithm - - 2017-05-16: CERT: Rule subset of CWE -
    - - CWE 2.11 - - - - CWE-330 - - , Use of Insufficiently Random Values - - 2017-06-28: CERT: Rule subset of CWE -
    - - CWE 2.11 - - - - CWE-338 - - , Use of Cryptographically Weak Pseudo-Random Number Generator (PRNG) - - 2017-06-28: CERT: Rule subset of CWE -
    - - CWE 2.11 - - - - CWE-676 - - - 2017-05-18: CERT: Rule subset of CWE -
    -
    -
    -

    Key here for mapping notes

    -

    CWE-327 and MSC30-C

    -
      -
    • CWE-327 forbids “broken or risky cryptographic algorithms” but does not specify what constitutes such an algo.
    • -
    -
      -
    • Per CERT judgement, rand() qualifies, so:
    • -
    -
      -
    • CWE-327 = Union( MSC30-C, list) where list =
    • -
    -
      -
    • Invocation of broken/risky crypto algorithms besides rand()
    • -
    -

    CWE-338 and MSC30-C

    -

    CWE-338 = Union( MSC30-C, list) where list =

    -
      -
    • Use of a weak PRNG besides standard C rand().
    • -
    -

    CWE-330 and MSC30-C

    -

    Independent( MSC30-C, MSC32-C, CON33-C)

    -

    CWE-330 = Union( MSC30-C, MSC32-C, CON33-C, list) where list = other improper use or creation of random values. (EG the would qualify)

    -

    MSC30-C, MSC32-C and CON33-C are independent, they have no intersections. They each specify distinct errors regarding PRNGs.

    -

    CWE-676 and MSC30-C

    -
      -
    • Independent( ENV33-C, CON33-C, STR31-C, EXP33-C, MSC30-C, ERR34-C)
    • -
    -
      -
    • MSC30-C implies that rand() is dangerous.
    • -
    -
      -
    • CWE-676 = Union( MSC30-C, list) where list =
    • -
    -
      -
    • Invocation of other dangerous functions, besides rand().
    • -
    -
    -
    - - - - - - - - - - - -
    - [ - - MSDN - - ] - - " - - BCryptGenRandom() Function - - " -
    - [ - - OpenBSD - - ] - - - arc4random() - -
    -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/MSC30-C/RandUsedForGeneratingPseudorandomNumbers.md b/c/cert/src/rules/MSC30-C/RandUsedForGeneratingPseudorandomNumbers.md new file mode 100644 index 0000000000..cc79159963 --- /dev/null +++ b/c/cert/src/rules/MSC30-C/RandUsedForGeneratingPseudorandomNumbers.md @@ -0,0 +1,170 @@ +# MSC30-C: Do not use the rand() function for generating pseudorandom numbers + +This query implements the CERT-C rule MSC30-C: + +> Do not use the rand() function for generating pseudorandom numbers + + +## Description + +Pseudorandom number generators use mathematical algorithms to produce a sequence of numbers with good statistical properties, but the numbers produced are not genuinely random. + +The C Standard `rand()` function makes no guarantees as to the quality of the random sequence produced. The numbers generated by some implementations of `rand()` have a comparatively short cycle and the numbers can be predictable. Applications that have strong pseudorandom number requirements must use a generator that is known to be sufficient for their needs. + +## Noncompliant Code Example + +The following noncompliant code generates an ID with a numeric part produced by calling the `rand()` function. The IDs produced are predictable and have limited randomness. + +```cpp +#include +#include +  +enum { len = 12 }; +  +void func(void) { + /* + * id will hold the ID, starting with the characters + * "ID" followed by a random integer. + */ +  char id[len]; + int r; + int num; + /* ... */ + r = rand(); /* Generate a random integer */ + num = snprintf(id, len, "ID%-d", r); /* Generate the ID */ + /* ... */ +} +``` + +## Compliant Solution (POSIX) + +This compliant solution replaces the `rand()` function with the POSIX `random()` function: + +```cpp +#include +#include +#include + +enum { len = 12 };  + +void func(void) { + /* + * id will hold the ID, starting with the characters + * "ID" followed by a random integer. + */ +  char id[len]; + int r; + int num; + /* ... */ + struct timespec ts; + if (timespec_get(&ts, TIME_UTC) == 0) { +  /* Handle error */ + } + srandom(ts.tv_nsec ^ ts.tv_sec); /* Seed the PRNG */ + /* ... */ + r = random(); /* Generate a random integer */ + num = snprintf(id, len, "ID%-d", r); /* Generate the ID */ + /* ... */ +} +``` +The POSIX `random()` function is a better pseudorandom number generator. Although on some platforms the low dozen bits generated by `rand()` go through a cyclic pattern, all the bits generated by `random()` are usable. The `rand48` family of functions provides another alternative for pseudorandom numbers. + +Although not specified by POSIX, [arc4random()](http://www.openbsd.org/cgi-bin/man.cgi?query=arc4random) is another possibility for systems that support it. The `arc4random(3)` manual page \[[OpenBSD](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-OpenBSD)\] states + +> ... provides higher quality of data than those described in rand(3), random(3), and drand48(3). + + +To achieve the best random numbers possible, an [implementation](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-implementation)-specific function must be used. When unpredictability is crucial and speed is not an issue, as in the creation of strong cryptographic keys, use a true entropy source, such as `/dev/random`, or a hardware device capable of generating random numbers. The `/dev/random` device can block for a long time if there are not enough events going on to generate sufficient entropy. + +## Compliant Solution (Windows) + +On Windows platforms, the [BCryptGenRandom()](https://docs.microsoft.com/en-us/windows/desktop/api/bcrypt/nf-bcrypt-bcryptgenrandom) function can be used to generate cryptographically strong random numbers. The Microsoft Developer Network `BCryptGenRandom()` reference \[[MSDN](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-MSDN)\] states: + +> The default random number provider implements an algorithm for generating random numbers that complies with the NIST SP800-90 standard, specifically the CTR_DRBG portion of that standard. + + +```cpp +#include +#include +#include + +#pragma comment(lib, "Bcrypt") + +void func(void) { + BCRYPT_ALG_HANDLE Prov; + int Buffer; + if (!BCRYPT_SUCCESS( + BCryptOpenAlgorithmProvider(&Prov, BCRYPT_RNG_ALGORITHM, + NULL, 0))) { + /* handle error */ + } + if (!BCRYPT_SUCCESS(BCryptGenRandom(Prov, (PUCHAR) (&Buffer), + sizeof(Buffer), 0))) { + /* handle error */ + } + printf("Random number: %d\n", Buffer); + BCryptCloseAlgorithmProvider(Prov, 0); +} +``` + +## Risk Assessment + +The use of the `rand()` function can result in predictable random numbers. + +
    Rule Severity Likelihood Remediation Cost Priority Level
    MSC30-C Medium Unlikely Low P6 L2
    + + +## Automated Detection + +
    Tool Version Checker Description
    Astrée 20.10 stdlib-use-rand Fully checked
    Axivion Bauhaus Suite 7.2.0 CertC-MSC30
    Clang 4.0 (prerelease) cert-msc30-c Checked by clang-tidy
    CodeSonar 6.2p0 BADFUNC.RANDOM.RAND Use of rand
    Compass/ROSE
    Coverity 2017.07 DONTCALL Implemented - weak support
    ECLAIR 1.2 CC2.MSC30 Fully implemented
    Helix QAC 2022.1 C5022 C++5029
    Klocwork 2022.1 CERT.MSC.STD_RAND_CALL
    LDRA tool suite 9.7.1 44 S Enhanced enforcement
    Parasoft C/C++test 2021.2 CERT_C-MSC30-a Do not use the rand() function for generating pseudorandom numbers
    PC-lint Plus 1.4 586 Fully supported
    Polyspace Bug Finder R2021a CERT C: Rule MSC30-C Checks for vulnerable pseudo-random number generator (rule fully covered)
    PRQA QA-C 9.7 5022 Fully implemented
    PRQA QA-C++ 4.4 5029
    RuleChecker 20.10 stdlib-use-rand Fully checked
    + + +## Related Vulnerabilities + +Search for [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) resulting from the violation of this rule on the [CERT website](https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+MSC30-C). + +## Related Guidelines + +[Key here](https://wiki.sei.cmu.edu/confluence/display/c/How+this+Coding+Standard+is+Organized#HowthisCodingStandardisOrganized-RelatedGuidelines) (explains table format and definitions) + +
    Taxonomy Taxonomy item Relationship
    CERT C MSC50-CPP. Do not use std::rand() for generating pseudorandom numbers Prior to 2018-01-12: CERT: Unspecified Relationship
    CERT Oracle Secure Coding Standard for Java MSC02-J. Generate strong random numbers Prior to 2018-01-12: CERT: Unspecified Relationship
    CWE 2.11 CWE-327 , Use of a Broken or Risky Cryptographic Algorithm 2017-05-16: CERT: Rule subset of CWE
    CWE 2.11 CWE-330 , Use of Insufficiently Random Values 2017-06-28: CERT: Rule subset of CWE
    CWE 2.11 CWE-338 , Use of Cryptographically Weak Pseudo-Random Number Generator (PRNG) 2017-06-28: CERT: Rule subset of CWE
    CWE 2.11 CWE-676 2017-05-18: CERT: Rule subset of CWE
    + + +## CERT-CWE Mapping Notes + +[Key here](https://wiki.sei.cmu.edu/confluence/pages/viewpage.action?pageId=87152408#HowthisCodingStandardisOrganized-CERT-CWEMappingNotes) for mapping notes + +**CWE-327 and MSC30-C** + +* CWE-327 forbids “broken or risky cryptographic algorithms” but does not specify what constitutes such an algo. +* Per CERT judgement, rand() qualifies, so: +* CWE-327 = Union( MSC30-C, list) where list = +* Invocation of broken/risky crypto algorithms besides rand() +**CWE-338 and MSC30-C** + +CWE-338 = Union( MSC30-C, list) where list = + +* Use of a weak PRNG besides standard C rand(). +**CWE-330 and MSC30-C** + +Independent( MSC30-C, MSC32-C, CON33-C) + +CWE-330 = Union( MSC30-C, MSC32-C, CON33-C, list) where list = other improper use or creation of random values. (EG the would qualify) + +MSC30-C, MSC32-C and CON33-C are independent, they have no intersections. They each specify distinct errors regarding PRNGs. + +**CWE-676 and MSC30-C** + +* Independent( ENV33-C, CON33-C, STR31-C, EXP33-C, MSC30-C, ERR34-C) +* MSC30-C implies that rand() is dangerous. +* CWE-676 = Union( MSC30-C, list) where list = +* Invocation of other dangerous functions, besides rand(). + +## Bibliography + +
    \[ MSDN \] " BCryptGenRandom() Function "
    \[ OpenBSD \] arc4random()
    + + +## References + +* CERT-C: [MSC30-C: Do not use the rand() function for generating pseudorandom numbers](https://wiki.sei.cmu.edu/confluence/display/c) diff --git a/c/cert/src/rules/MSC30-C/RandUsedForGeneratingPseudorandomNumbers.qhelp b/c/cert/src/rules/MSC30-C/RandUsedForGeneratingPseudorandomNumbers.qhelp deleted file mode 100644 index fa84110011..0000000000 --- a/c/cert/src/rules/MSC30-C/RandUsedForGeneratingPseudorandomNumbers.qhelp +++ /dev/null @@ -1,18 +0,0 @@ - - - - -

    This query implements the CERT-C rule MSC30-C:

    -
    -

    Do not use the rand() function for generating pseudorandom numbers

    -
    -
    - - -
  • - CERT-C: - MSC30-C: Do not use the rand() function for generating pseudorandom numbers - . -
  • -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/MSC32-C/ProperlySeedPseudorandomNumberGenerators-standard.qhelp b/c/cert/src/rules/MSC32-C/ProperlySeedPseudorandomNumberGenerators-standard.qhelp deleted file mode 100644 index ee66852ba9..0000000000 --- a/c/cert/src/rules/MSC32-C/ProperlySeedPseudorandomNumberGenerators-standard.qhelp +++ /dev/null @@ -1,425 +0,0 @@ - - -
    -

    A pseudorandom number generator (PRNG) is a deterministic algorithm capable of generating sequences of numbers that approximate the properties of random numbers. Each sequence is completely determined by the initial state of the PRNG and the algorithm for changing the state. Most PRNGs make it possible to set the initial state, also called the seed state. Setting the initial state is called seeding the PRNG.

    -

    Calling a PRNG in the same initial state, either without seeding it explicitly or by seeding it with the same value, results in generating the same sequence of random numbers in different runs of the program. Consider a PRNG function that is seeded with some initial seed value and is consecutively called to produce a sequence of random numbers, S. If the PRNG is subsequently seeded with the same initial seed value, then it will generate the same sequence S.

    -

    As a result, after the first run of an improperly seeded PRNG, an attacker can predict the sequence of random numbers that will be generated in the future runs. Improperly seeding or failing to seed the PRNG can lead to vulnerabilities, especially in security protocols.

    -

    The solution is to ensure that the PRNG is always properly seeded. A properly seeded PRNG will generate a different sequence of random numbers each time it is run.

    -

    Not all random number generators can be seeded. True random number generators that rely on hardware to produce completely unpredictable results do not need to be and cannot be seeded. Some high-quality PRNGs, such as the /dev/random device on some UNIX systems, also cannot be seeded. This rule applies only to algorithmic pseudorandom number generators that can be seeded.

    -
    -
    -

    This noncompliant code example generates a sequence of 10 pseudorandom numbers using the random() function. When random() is not seeded, it behaves like rand(), producing the same sequence of random numbers each time any program that uses it is run.

    - #include <stdio.h> -#include <stdlib.h> -  -void func(void) { - for (unsigned int i = 0; i < 10; ++i) { - /* Always generates the same sequence */ - printf("%ld, ", random()); - } -} -

    The output is as follows:

    - 1st run: 1804289383, 846930886, 1681692777, 1714636915, 1957747793, 424238335, 719885386, 1649760492, 596516649, - 1189641421, -2nd run: 1804289383, 846930886, 1681692777, 1714636915, 1957747793, 424238335, 719885386, 1649760492, 596516649, - 1189641421, -... -nth run: 1804289383, 846930886, 1681692777, 1714636915, 1957747793, 424238335, 719885386, 1649760492, 596516649, - 1189641421, -
    -
    -

    Call srandom() before invoking random() to seed the random sequence generated by random(). This compliant solution produces different random number sequences each time the function is called, depending on the resolution of the system clock:

    - #include <stdio.h> -#include <stdlib.h> -#include <time.h> -  -void func(void) { - struct timespec ts; - if (timespec_get(&ts, TIME_UTC) == 0) { - /* Handle error */ - } else { - srandom(ts.tv_nsec ^ ts.tv_sec); - for (unsigned int i = 0; i < 10; ++i) { - /* Generates different sequences at different runs */ -  printf("%ld, ", random()); - } - } -} - -

    The output is as follows:

    - 1st run: 198682410, 2076262355, 910374899, 428635843, 2084827500, 1558698420, 4459146, 733695321, 2044378618, 1649046624, -2nd run: 1127071427, 252907983, 1358798372, 2101446505, 1514711759, 229790273, 954268511, 1116446419, 368192457, - 1297948050, -3rd run: 2052868434, 1645663878, 731874735, 1624006793, 938447420, 1046134947, 1901136083, 418123888, 836428296, - 2017467418, -

    This may not be sufficiently random for concurrent execution, which may lead to correlated generated series in different threads. Depending on the application and the desired level of security, a programmer may choose alternative ways to seed PRNGs. In general, hardware is more capable than software of generating real random numbers (for example, by sampling the thermal noise of a diode).

    -
    -
    -

    The BCryptGenRandom() function does not run the risk of not being properly seeded because its arguments serve as seeders:

    - #include <stdio.h> -#include <Windows.h> -#include <Bcrypt.h> -#include <Ntstatus.h> -#include <Wincrypt.h> - -void func(void) { - BCRYPT_ALG_HANDLE hAlgorithm = NULL; - long rand_buf; - PUCHAR pbBuffer = (PUCHAR) &rand_buf; - ULONG cbBuffer = sizeof(rand_buf); - ULONG dwFlags = BCRYPT_USE_SYSTEM_PREFERRED_RNG; - NTSTATUS status; - for (unsigned int i = 0; i < 10; ++i) { - status = BCryptGenRandom(hAlgorithm, pbBuffer, cbBuffer, dwFlags); - if (status == STATUS_SUCCESS) { - printf("%ld, ", rand_buf); - } else { - /* Handle Error */ - } - } -} - -

    The output is as follows:

    - 1st run: -683378946, 1957231690, 1933176011, -1745403355, -883473417, 882992405, 169629816, 1824800038, 899851668, 1702784647, -2nd run: -58750553, -1921870721, -1973269161, 1512649964, -673518452, 234003619, -1622633366, 1312389688, -2125631172, 2067680022, -3rd run: -189899579, 1220698973, 752205360, -1826365616, 79310867, 1430950090, -283206168, -941773185, 129633665, 543448789, -
    -
    - - - - - - - - - - - - - - - - - - - -
    - Rule - - Severity - - Likelihood - - Remediation Cost - - Priority - - Level -
    - MSC32-C - - Medium - - Likely - - Low - - P18 - - L1 -
    -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - Tool - - Version - - Checker - - Description -
    - - Astrée - - - 20.10 - - - Supported, but no explicit checker -
    - - Axivion Bauhaus Suite - - - 7.2.0 - - CertC-MSC32 - -
    - - Helix QAC - - - 2022.1 - - C5031 - C++5036 - -
    - - Klocwork - - - 2022.1 - - CERT.MSC.SEED_RANDOM - -
    - - PC-lint Plus - - - 1.4 - - 2460, 2461, 2760 - - Fully supported -
    - - Polyspace Bug Finder - - - R2021a - - - CERT C: Rule MSC32-C - - - Checks for: - Deterministic random output from constant seedeterministic random output from constant seed, predictable random output from predictable seedredictable random output from predictable seed. - Rule fully covered. -
    - - Parasoft C/C++test - - - 2021.2 - - CERT_C-MSC32-d - - Properly seed pseudorandom number generators -
    - - PRQA QA-C - - - 9.7 - - 5031  - -
    -
    -
    -

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    -
    -
    -

    Key here (explains table format and definitions)

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - Taxonomy - - Taxonomy item - - Relationship -
    - - CERT C Secure Coding Standard - - - - MSC30-C. Do not use the rand() function for generating pseudorandom numbers - - - Prior to 2018-01-12: CERT: Unspecified Relationship -
    - - CERT C - - - - MSC51-CPP. Ensure your random number generator is properly seeded - - - Prior to 2018-01-12: CERT: Unspecified Relationship -
    - - CWE 2.11 - - - - CWE-327 - - , Use of a Broken or Risky Cryptographic Algorithm - - 2017-05-16: CERT: Rule subset of CWE -
    - - CWE 2.11 - - - - CWE-330 - - , Use of Insufficiently Random Values - - 2017-06-28: CERT: Rule subset of CWE -
    - - CWE 2.11 - - - - CWE-331 - - , Insufficient Entropy - - 2017-06-28: CERT: Exact -
    -
    -
    -

    Key here for mapping notes

    -

    CWE-327 and MSC32-C

    -
      -
    • Intersection( MSC30-C, MSC32-C) = Ø
    • -
    -
      -
    • MSC32-C says to properly seed pseudorandom number generators. For example, if you call rand(), make sure to seed it properly by calling srand() first. So far, we haven’t found any calls to rand().
    • -
    -
      -
    • Failure to seed a PRNG causes it to produce reproducible (hence insecure) series of random numbers.
    • -
    -
      -
    • CWE-327 = Union( MSC32-C, list) where list =
    • -
    -
      -
    • Invocation of broken/risky crypto algorithms that are not properly seeded
    • -
    -

    CWE-330 and MSC32-C

    -

    Independent( MSC30-C, MSC32-C, CON33-C)

    -

    CWE-330 = Union( MSC30-C, MSC32-C, CON33-C, list) where list = other improper use or creation of random values. (EG the would qualify)

    -

    MSC30-C, MSC32-C and CON33-C are independent, they have no intersections. They each specify distinct errors regarding PRNGs.

    -
    -
    - - - - - - - -
    - [ - - MSDN - - ] - - " - - BCryptGenRandom() Function - - " -
    -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/MSC32-C/ProperlySeedPseudorandomNumberGenerators.md b/c/cert/src/rules/MSC32-C/ProperlySeedPseudorandomNumberGenerators.md new file mode 100644 index 0000000000..22c999e410 --- /dev/null +++ b/c/cert/src/rules/MSC32-C/ProperlySeedPseudorandomNumberGenerators.md @@ -0,0 +1,165 @@ +# MSC32-C: Properly seed pseudorandom number generators + +This query implements the CERT-C rule MSC32-C: + +> Properly seed pseudorandom number generators + + +## Description + +A pseudorandom number generator (PRNG) is a deterministic algorithm capable of generating sequences of numbers that approximate the properties of random numbers. Each sequence is completely determined by the initial state of the PRNG and the algorithm for changing the state. Most PRNGs make it possible to set the initial state, also called the *seed state*. Setting the initial state is called *seeding* the PRNG. + +Calling a PRNG in the same initial state, either without seeding it explicitly or by seeding it with the same value, results in generating the same sequence of random numbers in different runs of the program. Consider a PRNG function that is seeded with some initial seed value and is consecutively called to produce a sequence of random numbers, `S`. If the PRNG is subsequently seeded with the same initial seed value, then it will generate the same sequence `S`. + +As a result, after the first run of an improperly seeded PRNG, an attacker can predict the sequence of random numbers that will be generated in the future runs. Improperly seeding or failing to seed the PRNG can lead to [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability), especially in security protocols. + +The solution is to ensure that the PRNG is always properly seeded. A properly seeded PRNG will generate a different sequence of random numbers each time it is run. + +Not all random number generators can be seeded. True random number generators that rely on hardware to produce completely unpredictable results do not need to be and cannot be seeded. Some high-quality PRNGs, such as the `/dev/random` device on some UNIX systems, also cannot be seeded. This rule applies only to algorithmic pseudorandom number generators that can be seeded. + +## Noncompliant Code Example (POSIX) + +This noncompliant code example generates a sequence of 10 pseudorandom numbers using the `random()` function. When `random()` is not seeded, it behaves like `rand()`, producing the same sequence of random numbers each time any program that uses it is run. + +```cpp +#include +#include +  +void func(void) { + for (unsigned int i = 0; i < 10; ++i) { + /* Always generates the same sequence */ + printf("%ld, ", random()); + } +} +``` +The output is as follows: + +```cpp +1st run: 1804289383, 846930886, 1681692777, 1714636915, 1957747793, 424238335, 719885386, 1649760492, 596516649, + 1189641421, +2nd run: 1804289383, 846930886, 1681692777, 1714636915, 1957747793, 424238335, 719885386, 1649760492, 596516649, + 1189641421, +... +nth run: 1804289383, 846930886, 1681692777, 1714636915, 1957747793, 424238335, 719885386, 1649760492, 596516649, + 1189641421, +``` + +## Compliant Solution (POSIX) + +Call `srandom()` before invoking `random()` to seed the random sequence generated by `random()`. This compliant solution produces different random number sequences each time the function is called, depending on the resolution of the system clock: + +```cpp +#include +#include +#include +  +void func(void) { + struct timespec ts; + if (timespec_get(&ts, TIME_UTC) == 0) { + /* Handle error */ + } else { + srandom(ts.tv_nsec ^ ts.tv_sec); + for (unsigned int i = 0; i < 10; ++i) { + /* Generates different sequences at different runs */ +  printf("%ld, ", random()); + } + } +} + +``` +The output is as follows: + +```cpp +1st run: 198682410, 2076262355, 910374899, 428635843, 2084827500, 1558698420, 4459146, 733695321, 2044378618, 1649046624, +2nd run: 1127071427, 252907983, 1358798372, 2101446505, 1514711759, 229790273, 954268511, 1116446419, 368192457, + 1297948050, +3rd run: 2052868434, 1645663878, 731874735, 1624006793, 938447420, 1046134947, 1901136083, 418123888, 836428296, + 2017467418, +``` +This may not be sufficiently random for concurrent execution, which may lead to correlated generated series in different threads. Depending on the application and the desired level of security, a programmer may choose alternative ways to seed PRNGs. In general, hardware is more capable than software of generating real random numbers (for example, by sampling the thermal noise of a diode). + +## Compliant Solution (Windows) + +The [BCryptGenRandom()](https://docs.microsoft.com/en-us/windows/desktop/api/bcrypt/nf-bcrypt-bcryptgenrandom) function does not run the risk of not being properly seeded because its arguments serve as seeders: + +```cpp +#include +#include +#include +#include +#include + +void func(void) { + BCRYPT_ALG_HANDLE hAlgorithm = NULL; + long rand_buf; + PUCHAR pbBuffer = (PUCHAR) &rand_buf; + ULONG cbBuffer = sizeof(rand_buf); + ULONG dwFlags = BCRYPT_USE_SYSTEM_PREFERRED_RNG; + NTSTATUS status; + for (unsigned int i = 0; i < 10; ++i) { + status = BCryptGenRandom(hAlgorithm, pbBuffer, cbBuffer, dwFlags); + if (status == STATUS_SUCCESS) { + printf("%ld, ", rand_buf); + } else { + /* Handle Error */ + } + } +} + +``` +The output is as follows: + +```cpp +1st run: -683378946, 1957231690, 1933176011, -1745403355, -883473417, 882992405, 169629816, 1824800038, 899851668, 1702784647, +2nd run: -58750553, -1921870721, -1973269161, 1512649964, -673518452, 234003619, -1622633366, 1312389688, -2125631172, 2067680022, +3rd run: -189899579, 1220698973, 752205360, -1826365616, 79310867, 1430950090, -283206168, -941773185, 129633665, 543448789, +``` + +## Risk Assessment + +
    Rule Severity Likelihood Remediation Cost Priority Level
    MSC32-C Medium Likely Low P18 L1
    + + +## Automated Detection + +
    Tool Version Checker Description
    Astrée 20.10 Supported, but no explicit checker
    Axivion Bauhaus Suite 7.2.0 CertC-MSC32
    Helix QAC 2022.1 C5031 C++5036
    Klocwork 2022.1 CERT.MSC.SEED_RANDOM
    PC-lint Plus 1.4 2460, 2461, 2760 Fully supported
    Polyspace Bug Finder R2021a CERT C: Rule MSC32-C Checks for: Deterministic random output from constant seedeterministic random output from constant seed, predictable random output from predictable seedredictable random output from predictable seed. Rule fully covered.
    Parasoft C/C++test 2021.2 CERT_C-MSC32-d Properly seed pseudorandom number generators
    PRQA QA-C 9.7 5031 
    + + +## Related Vulnerabilities + +Search for [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) resulting from the violation of this rule on the [CERT website](https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+MSC32-C). + +## Related Guidelines + +[Key here](https://wiki.sei.cmu.edu/confluence/display/c/How+this+Coding+Standard+is+Organized#HowthisCodingStandardisOrganized-RelatedGuidelines) (explains table format and definitions) + +
    Taxonomy Taxonomy item Relationship
    CERT C Secure Coding Standard MSC30-C. Do not use the rand() function for generating pseudorandom numbers Prior to 2018-01-12: CERT: Unspecified Relationship
    CERT C MSC51-CPP. Ensure your random number generator is properly seeded Prior to 2018-01-12: CERT: Unspecified Relationship
    CWE 2.11 CWE-327 , Use of a Broken or Risky Cryptographic Algorithm 2017-05-16: CERT: Rule subset of CWE
    CWE 2.11 CWE-330 , Use of Insufficiently Random Values 2017-06-28: CERT: Rule subset of CWE
    CWE 2.11 CWE-331 , Insufficient Entropy 2017-06-28: CERT: Exact
    + + +## CERT-CWE Mapping Notes + +[Key here](https://wiki.sei.cmu.edu/confluence/pages/viewpage.action?pageId=87152408#HowthisCodingStandardisOrganized-CERT-CWEMappingNotes) for mapping notes + +**CWE-327 and MSC32-C** + +* Intersection( MSC30-C, MSC32-C) = Ø +* MSC32-C says to properly seed pseudorandom number generators. For example, if you call rand(), make sure to seed it properly by calling srand() first. So far, we haven’t found any calls to rand(). +* Failure to seed a PRNG causes it to produce reproducible (hence insecure) series of random numbers. +* CWE-327 = Union( MSC32-C, list) where list = +* Invocation of broken/risky crypto algorithms that are not properly seeded +**CWE-330 and MSC32-C** + +Independent( MSC30-C, MSC32-C, CON33-C) + +CWE-330 = Union( MSC30-C, MSC32-C, CON33-C, list) where list = other improper use or creation of random values. (EG the would qualify) + +MSC30-C, MSC32-C and CON33-C are independent, they have no intersections. They each specify distinct errors regarding PRNGs. + +## Bibliography + +
    \[ MSDN \] " BCryptGenRandom() Function "
    + + +## References + +* CERT-C: [MSC32-C: Properly seed pseudorandom number generators](https://wiki.sei.cmu.edu/confluence/display/c) diff --git a/c/cert/src/rules/MSC32-C/ProperlySeedPseudorandomNumberGenerators.qhelp b/c/cert/src/rules/MSC32-C/ProperlySeedPseudorandomNumberGenerators.qhelp deleted file mode 100644 index 70be073e93..0000000000 --- a/c/cert/src/rules/MSC32-C/ProperlySeedPseudorandomNumberGenerators.qhelp +++ /dev/null @@ -1,18 +0,0 @@ - - - - -

    This query implements the CERT-C rule MSC32-C:

    -
    -

    Properly seed pseudorandom number generators

    -
    -
    - - -
  • - CERT-C: - MSC32-C: Properly seed pseudorandom number generators - . -
  • -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/MSC37-C/ControlFlowReachesTheEndOfANonVoidFunction-standard.qhelp b/c/cert/src/rules/MSC37-C/ControlFlowReachesTheEndOfANonVoidFunction-standard.qhelp deleted file mode 100644 index 08dadda262..0000000000 --- a/c/cert/src/rules/MSC37-C/ControlFlowReachesTheEndOfANonVoidFunction-standard.qhelp +++ /dev/null @@ -1,524 +0,0 @@ - - -
    -

    If control reaches the closing curly brace (}) of a non-void function without evaluating a return statement, using the return value of the function call is undefined behavior. (See undefined behavior 88.)

    -
    -
    -

    In this noncompliant code example, control reaches the end of the checkpass() function when the two strings passed to strcmp() are not equal, resulting in undefined behavior. Many compilers will generate code for the checkpass() function, returning various values along the execution path where no return statement is defined.

    - #include <string.h> -#include <stdio.h> -  -int checkpass(const char *password) { - if (strcmp(password, "pass") == 0) { - return 1; - } -} - -void func(const char *userinput) { - if (checkpass(userinput)) { - printf("Success\n"); - } -} -

    This error is frequently diagnosed by compilers. (See MSC00-C. Compile cleanly at high warning levels.)

    -
    -
    -

    This compliant solution ensures that the checkpass() function always returns a value:

    - #include <string.h> -#include <stdio.h> -  -int checkpass(const char *password) { - if (strcmp(password, "pass") == 0) { - return 1; - } - return 0; -} - -void func(const char *userinput) { - if (checkpass(userinput)) { - printf("Success!\n"); - } -} -
    -
    -

    In this noncompliant code example, control reaches the end of the getlen() function when input does not contain the integer delim. Because the potentially undefined return value of getlen() is later used as an index into an array, a buffer overflow may occur.

    - #include <stddef.h> -  -size_t getlen(const int *input, size_t maxlen, int delim) { - for (size_t i = 0; i < maxlen; ++i) { - if (input[i] == delim) { - return i; - } - } -} -  -void func(int userdata) { - size_t i; - int data[] = { 1, 1, 1 }; - i = getlen(data, sizeof(data), 0); - data[i] = userdata; -} -

    Implementation Details (GCC)

    -

    Violating this rule can have unexpected consequences, as in the following example:

    - #include <stdio.h> - -size_t getlen(const int *input, size_t maxlen, int delim) { - for (size_t i = 0; i < maxlen; ++i) { - if (input[i] == delim) { - return i; - } - } -} - -int main(int argc, char **argv) { - size_t i; - int data[] = { 1, 1, 1 }; - - i = getlen(data, sizeof(data), 0); - printf("Returned: %zu\n", i); - data[i] = 0; - - return 0; -} -

    When this program is compiled with -Wall on most versions of the GCC compiler, the following warning is generated:

    - example.c: In function 'getlen': -example.c:12: warning: control reaches end of non-void function - -

    None of the inputs to the function equal the delimiter, so when run with GCC 5.3 on Linux, control reaches the end of the getlen() function, which is undefined behavior and in this test returns 3, causing an out-of-bounds write to the data array.

    -
    -
    -

    This compliant solution changes the interface of getlen() to store the result in a user-provided pointer and returns a status indicator to report success or failure. The best method for handling this type of error is specific to the application and the type of error. (See ERR00-C. Adopt and implement a consistent and comprehensive error-handling policy for more on error handling.)

    - #include <stddef.h> -  -int getlen(const int *input, size_t maxlen, int delim, -  size_t *result) { - if (result == NULL) { - return -1; - } - for (size_t i = 0; i < maxlen; ++i) { - if (input[i] == delim) { - *result = i; - return 0; - } - } - return -1; -} - -void func(int userdata) { - size_t i; - int data[] = {1, 1, 1}; - if (getlen(data, sizeof(data), 0, &i) != 0) { - /* Handle error */ - } else { - data[i] = userdata; - } -} - -
    -
    -

    MSC37-C-EX1: According to the C Standard, 5.1.2.2.3, paragraph 1 [ISO/IEC 9899:2011], "Reaching the } that terminates the main function returns a value of 0." As a result, it is permissible for control to reach the end of the main() function without executing a return statement.

    -

    MSC37-C-EX2: It is permissible for a control path to not return a value if that code path is never taken and a function marked _Noreturn is called as part of that code path. For example:

    - #include <stdio.h> -#include <stdlib.h> - -_Noreturn void unreachable(const char *msg) { - printf("Unreachable code reached: %s\n", msg); - exit(1); -} - -enum E { - One, - Two, - Three -}; - -int f(enum E e) { - switch (e) { - case One: return 1; - case Two: return 2; - case Three: return 3; - } - unreachable("Can never get here"); -} -
    -
    -

    Using the return value from a non-void function where control reaches the end of the function without evaluating a return statement can lead to buffer overflow vulnerabilities as well as other unexpected program behaviors.

    - - - - - - - - - - - - - - - - - - - -
    - Rule - - Severity - - Likelihood - - Remediation Cost - - Priority - - Level -
    - MSC37-C - - High - - Unlikely - - Low - - P9 - - L2 -
    -
    -
    -

    Search for vulnerabilities resulting from the violation of this rule on the CERT website.

    -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - Tool - - Version - - Checker - - Description -
    - - Astrée - - - 20.10 - - return-implicit - - Fully checked -
    - - Axivion Bauhaus Suite - - - 7.2.0 - - CertC-MSC37 - -
    - - CodeSonar - - - 6.2p0 - - LANG.STRUCT.MRS - - Missing return statement -
    - - Coverity - - - 2017.07 - - MISSING_RETURN - - Implemented -
    - - Helix QAC - - - 2022.1 - - C2888 - C++2888, C++4022 - -
    - - Klocwork - - - 2022.1 - - FUNCRET.GEN - FUNCRET.IMPLICIT - -
    - - LDRA tool suite - - - 9.7.1 - - 2 D, 36 S, 66 S - - Fully implemented -
    - - Parasoft C/C++test - - - 2021.2 - - CERT_C-MSC37-a - - All exit paths from a function with non-void return type shall have an explicit return statement with an expression -
    - - PC-lint Plus - - - 1.4 - - 533 - - Fully supported -
    - - Polyspace Bug Finder - - - R2021a - - - CERT C: Rule MSC37-C - - - Checks for missing return statement (rule fully covered) -
    - - PRQA QA-C - - - 9.7 - - 2888 - -
    - - PRQA QA-C++ - - - 4.4 - - 2888, 4022  - -
    - - RuleChecker - - - 20.10 - - return-implicit - - Fully checked -
    - - SonarQube C/C++ Plugin - - - 3.11 - - S935 - -
    - - TrustInSoft Analyzer - - - 1.38 - - Body of function falls-through - - Exhaustively verified. -
    -
    -
    -

    Key here (explains table format and definitions)

    - - - - - - - - - - - - - - - - - - -
    - Taxonomy - - Taxonomy item - - Relationship -
    - - CERT C Secure Coding Standard - - - - MSC01-C. Strive for logical completeness - - - Prior to 2018-01-12: CERT: Unspecified Relationship -
    - - CWE 2.11 - - - - CWE-758 - - - 2017-07-07: CERT: Rule subset of CWE -
    -
    -
    -

    Key here for mapping notes

    -

    CWE-758 and MSC37-C

    -

    Independent( INT34-C, INT36-C, MEM30-C, MSC37-C, FLP32-C, EXP33-C, EXP30-C, ERR34-C, ARR32-C)

    -

    CWE-758 = Union( MSC37-C, list) where list =

    -

    Undefined behavior that results from anything other than failing to return a value from a function that expects one

    -
    -
    - - - - - - - -
    - [ - - ISO/IEC 9899:2011 - - ] - - 5.1.2.2.3, "Program Termination" -
    -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/MSC37-C/ControlFlowReachesTheEndOfANonVoidFunction.md b/c/cert/src/rules/MSC37-C/ControlFlowReachesTheEndOfANonVoidFunction.md new file mode 100644 index 0000000000..bd316db71c --- /dev/null +++ b/c/cert/src/rules/MSC37-C/ControlFlowReachesTheEndOfANonVoidFunction.md @@ -0,0 +1,219 @@ +# MSC37-C: Ensure that control never reaches the end of a non-void function + +This query implements the CERT-C rule MSC37-C: + +> Ensure that control never reaches the end of a non-void function + + +## Description + +If control reaches the closing curly brace (`}`) of a non-`void` function without evaluating a `return` statement, using the return value of the function call is [undefined behavior. ](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior)(See [undefined behavior 88](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_88).) + +## Noncompliant Code Example + +In this noncompliant code example, control reaches the end of the `checkpass()` function when the two strings passed to `strcmp()` are not equal, resulting in undefined behavior. Many compilers will generate code for the `checkpass()` function, returning various values along the execution path where no `return` statement is defined. + +```cpp +#include +#include +  +int checkpass(const char *password) { + if (strcmp(password, "pass") == 0) { + return 1; + } +} + +void func(const char *userinput) { + if (checkpass(userinput)) { + printf("Success\n"); + } +} +``` +This error is frequently diagnosed by compilers. (See [MSC00-C. Compile cleanly at high warning levels](https://wiki.sei.cmu.edu/confluence/display/c/MSC00-C.+Compile+cleanly+at+high+warning+levels).) + +## Compliant Solution + +This compliant solution ensures that the `checkpass()` function always returns a value: + +```cpp +#include +#include +  +int checkpass(const char *password) { + if (strcmp(password, "pass") == 0) { + return 1; + } + return 0; +} + +void func(const char *userinput) { + if (checkpass(userinput)) { + printf("Success!\n"); + } +} +``` + +## Noncompliant Code Example + +In this noncompliant code example, control reaches the end of the `getlen()` function when `input` does not contain the integer `delim`. Because the potentially undefined return value of `getlen()` is later used as an index into an array, a buffer overflow may occur. + +```cpp +#include +  +size_t getlen(const int *input, size_t maxlen, int delim) { + for (size_t i = 0; i < maxlen; ++i) { + if (input[i] == delim) { + return i; + } + } +} +  +void func(int userdata) { + size_t i; + int data[] = { 1, 1, 1 }; + i = getlen(data, sizeof(data), 0); + data[i] = userdata; +} +``` +**Implementation Details (GCC)** + +Violating this rule can have unexpected consequences, as in the following example: + +```cpp +#include + +size_t getlen(const int *input, size_t maxlen, int delim) { + for (size_t i = 0; i < maxlen; ++i) { + if (input[i] == delim) { + return i; + } + } +} + +int main(int argc, char **argv) { + size_t i; + int data[] = { 1, 1, 1 }; + + i = getlen(data, sizeof(data), 0); + printf("Returned: %zu\n", i); + data[i] = 0; + + return 0; +} +``` +When this program is compiled with `-Wall` on most versions of the GCC compiler, the following warning is generated: + +```cpp +example.c: In function 'getlen': +example.c:12: warning: control reaches end of non-void function + +``` +None of the inputs to the function equal the delimiter, so when run with GCC 5.3 on Linux, control reaches the end of the `getlen()` function, which is undefined behavior and in this test returns `3`, causing an out-of-bounds write to the `data` array. + +## Compliant Solution + +This compliant solution changes the interface of `getlen()` to store the result in a user-provided pointer and returns a status indicator to report success or failure. The best method for handling this type of error is specific to the application and the type of error. (See [ERR00-C. Adopt and implement a consistent and comprehensive error-handling policy](https://wiki.sei.cmu.edu/confluence/display/c/ERR00-C.+Adopt+and+implement+a+consistent+and+comprehensive+error-handling+policy) for more on error handling.) + +```cpp +#include +  +int getlen(const int *input, size_t maxlen, int delim, +  size_t *result) { + if (result == NULL) { + return -1; + } + for (size_t i = 0; i < maxlen; ++i) { + if (input[i] == delim) { + *result = i; + return 0; + } + } + return -1; +} + +void func(int userdata) { + size_t i; + int data[] = {1, 1, 1}; + if (getlen(data, sizeof(data), 0, &i) != 0) { + /* Handle error */ + } else { + data[i] = userdata; + } +} + +``` + +## Exceptions + +**MSC37-C-EX1:** According to the C Standard, 5.1.2.2.3, paragraph 1 \[[ISO/IEC 9899:2011](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO-IEC9899-2011)\], "Reaching the `}` that terminates the main function returns a value of 0." As a result, it is permissible for control to reach the end of the `main()` function without executing a return statement. + +**MSC37-C-EX2: **It is permissible for a control path to not return a value if that code path is never taken and a function marked `_Noreturn` is called as part of that code path. For example: + +```cpp +#include +#include + +_Noreturn void unreachable(const char *msg) { + printf("Unreachable code reached: %s\n", msg); + exit(1); +} + +enum E { + One, + Two, + Three +}; + +int f(enum E e) { + switch (e) { + case One: return 1; + case Two: return 2; + case Three: return 3; + } + unreachable("Can never get here"); +} +``` + +## Risk Assessment + +Using the return value from a non-`void` function where control reaches the end of the function without evaluating a `return` statement can lead to buffer overflow [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) as well as other [unexpected program behaviors](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-unexpectedbehavior). + +
    Rule Severity Likelihood Remediation Cost Priority Level
    MSC37-C High Unlikely Low P9 L2
    + + +## Related Vulnerabilities + +Search for [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) resulting from the violation of this rule on the [CERT website](https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+MSC37-C). + +## Automated Detection + +
    Tool Version Checker Description
    Astrée 20.10 return-implicit Fully checked
    Axivion Bauhaus Suite 7.2.0 CertC-MSC37
    CodeSonar 6.2p0 LANG.STRUCT.MRS Missing return statement
    Coverity 2017.07 MISSING_RETURN Implemented
    Helix QAC 2022.1 C2888 C++2888, C++4022
    Klocwork 2022.1 FUNCRET.GEN FUNCRET.IMPLICIT
    LDRA tool suite 9.7.1 2 D, 36 S, 66 S Fully implemented
    Parasoft C/C++test 2021.2 CERT_C-MSC37-a All exit paths from a function with non-void return type shall have an explicit return statement with an expression
    PC-lint Plus 1.4 533 Fully supported
    Polyspace Bug Finder R2021a CERT C: Rule MSC37-C Checks for missing return statement (rule fully covered)
    PRQA QA-C 9.7 2888
    PRQA QA-C++ 4.4 2888, 4022 
    RuleChecker 20.10 return-implicit Fully checked
    SonarQube C/C++ Plugin 3.11 S935
    TrustInSoft Analyzer 1.38 Body of function falls-through Exhaustively verified.
    + + +## Related Guidelines + +[Key here](https://wiki.sei.cmu.edu/confluence/display/c/How+this+Coding+Standard+is+Organized#HowthisCodingStandardisOrganized-RelatedGuidelines) (explains table format and definitions) + +
    Taxonomy Taxonomy item Relationship
    CERT C Secure Coding Standard MSC01-C. Strive for logical completeness Prior to 2018-01-12: CERT: Unspecified Relationship
    CWE 2.11 CWE-758 2017-07-07: CERT: Rule subset of CWE
    + + +## CERT-CWE Mapping Notes + +[Key here](https://wiki.sei.cmu.edu/confluence/pages/viewpage.action?pageId=87152408#HowthisCodingStandardisOrganized-CERT-CWEMappingNotes) for mapping notes + +**CWE-758 and MSC37-C** + +Independent( INT34-C, INT36-C, MEM30-C, MSC37-C, FLP32-C, EXP33-C, EXP30-C, ERR34-C, ARR32-C) + +CWE-758 = Union( MSC37-C, list) where list = + +Undefined behavior that results from anything other than failing to return a value from a function that expects one + +## Bibliography + +
    \[ ISO/IEC 9899:2011 \] 5.1.2.2.3, "Program Termination"
    + + +## References + +* CERT-C: [MSC37-C: Ensure that control never reaches the end of a non-void function](https://wiki.sei.cmu.edu/confluence/display/c) diff --git a/c/cert/src/rules/MSC37-C/ControlFlowReachesTheEndOfANonVoidFunction.qhelp b/c/cert/src/rules/MSC37-C/ControlFlowReachesTheEndOfANonVoidFunction.qhelp deleted file mode 100644 index 28a45a9317..0000000000 --- a/c/cert/src/rules/MSC37-C/ControlFlowReachesTheEndOfANonVoidFunction.qhelp +++ /dev/null @@ -1,18 +0,0 @@ - - - - -

    This query implements the CERT-C rule MSC37-C:

    -
    -

    Ensure that control never reaches the end of a non-void function

    -
    -
    - - -
  • - CERT-C: - MSC37-C: Ensure that control never reaches the end of a non-void function - . -
  • -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/STR30-C/DoNotAttemptToModifyStringLiterals-standard.qhelp b/c/cert/src/rules/STR30-C/DoNotAttemptToModifyStringLiterals-standard.qhelp deleted file mode 100644 index 458fbe3f7d..0000000000 --- a/c/cert/src/rules/STR30-C/DoNotAttemptToModifyStringLiterals-standard.qhelp +++ /dev/null @@ -1,33 +0,0 @@ - - -
    -
      -
    • required
    • -
    • implementation
    • -
    • automated
    • -
    -
    - -
    -

    - ... -

    - -
    - -
    -

    - ... -

    -
    - - - - - -
    -
      -
    • ...
    • -
    -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/STR30-C/DoNotAttemptToModifyStringLiterals.md b/c/cert/src/rules/STR30-C/DoNotAttemptToModifyStringLiterals.md new file mode 100644 index 0000000000..9360d59dfd --- /dev/null +++ b/c/cert/src/rules/STR30-C/DoNotAttemptToModifyStringLiterals.md @@ -0,0 +1,160 @@ +# STR30-C: Do not attempt to modify string literals + +This query implements the CERT-C rule STR30-C: + +> Do not attempt to modify string literals + + +## Description + +According to the C Standard, 6.4.5, paragraph 3 \[[ISO/IEC 9899:2011](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO-IEC9899-2011)\]: + +> A *character string literal* is a sequence of zero or more multibyte characters enclosed in double-quotes, as in `"xyz"`. A UTF−8 string literal is the same, except prefixed by `u8`. A wide string literal is the same, except prefixed by the letter `L`, `u`, or `U`. + + +At compile time, string literals are used to create an array of static storage duration of sufficient length to contain the character sequence and a terminating null character. String literals are usually referred to by a pointer to (or array of) characters. Ideally, they should be assigned only to pointers to (or arrays of) `const char` or `const wchar_t`. It is unspecified whether these arrays of string literals are distinct from each other. The behavior is [undefined](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior) if a program attempts to modify any portion of a string literal. Modifying a string literal frequently results in an access violation because string literals are typically stored in read-only memory. (See [undefined behavior 33](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_33).) + +Avoid assigning a string literal to a pointer to non-`const` or casting a string literal to a pointer to non-`const`. For the purposes of this rule, a pointer to (or array of) `const` characters must be treated as a string literal. Similarly, the returned value of the following library functions must be treated as a string literal if the first argument is a string literal: + +* `strpbrk(), strchr(), strrchr(), strstr()` +* `wcspbrk(), wcschr(), wcsrchr(), wcsstr()` +* `memchr(), wmemchr()` +This rule is a specific instance of [EXP40-C. Do not modify constant objects](https://wiki.sei.cmu.edu/confluence/display/c/EXP40-C.+Do+not+modify+constant+objects). + +## Noncompliant Code Example + +In this noncompliant code example, the `char` pointer `str` is initialized to the address of a string literal. Attempting to modify the string literal is [undefined behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior): + +```cpp +char *str = "string literal"; +str[0] = 'S'; + +``` + +## Compliant Solution + +As an array initializer, a string literal specifies the initial values of characters in an array as well as the size of the array. (See [STR11-C. Do not specify the bound of a character array initialized with a string literal](https://wiki.sei.cmu.edu/confluence/display/c/STR11-C.+Do+not+specify+the+bound+of+a+character+array+initialized+with+a+string+literal).) This code creates a copy of the string literal in the space allocated to the character array `str`. The string stored in `str` can be modified safely. + +```cpp +char str[] = "string literal"; +str[0] = 'S'; + +``` + +## Noncompliant Code Example (POSIX) + +In this noncompliant code example, a string literal is passed to the (pointer to non-`const`) parameter of the POSIX function `[mkstemp()](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mkstemp.html)`, which then modifies the characters of the string literal: + +```cpp +#include + +void func(void) { + mkstemp("/tmp/edXXXXXX"); +} +``` +The behavior of `mkstemp()` is described in more detail in [FIO21-C. Do not create temporary files in shared directories](https://wiki.sei.cmu.edu/confluence/display/c/FIO21-C.+Do+not+create+temporary+files+in+shared+directories). + +## Compliant Solution (POSIX) + +This compliant solution uses a named array instead of passing a string literal: + +```cpp +#include + +void func(void) { + static char fname[] = "/tmp/edXXXXXX"; + mkstemp(fname); +} +``` + +## Noncompliant Code Example (Result of strrchr()) + +In this noncompliant example, the `char *` result of the `strrchr()` function is used to modify the object pointed to by `pathname`. Because the argument to `strrchr()` points to a string literal, the effects of the modification are undefined. + +```cpp +#include +#include + +const char *get_dirname(const char *pathname) { + char *slash; + slash = strrchr(pathname, '/'); + if (slash) { + *slash = '\0'; /* Undefined behavior */ + } + return pathname; +} + +int main(void) { + puts(get_dirname(__FILE__)); + return 0; +} + +``` + +## Compliant Solution (Result of strrchr()) + +This compliant solution avoids modifying a `const` object, even if it is possible to obtain a non-`const` pointer to such an object by calling a standard C library function, such as `strrchr()`. To reduce the risk to callers of `get_dirname()`, a buffer and length for the directory name are passed into the function. It is insufficient to change `pathname` to require a `char *` instead of a `const char *` because conforming compilers are not required to diagnose passing a string literal to a function accepting a `char *`. + +```cpp +#include +#include +#include + +char *get_dirname(const char *pathname, char *dirname, size_t size) { + const char *slash; + slash = strrchr(pathname, '/'); + if (slash) { + ptrdiff_t slash_idx = slash - pathname; + if ((size_t)slash_idx < size) { + memcpy(dirname, pathname, slash_idx); + dirname[slash_idx] = '\0'; + return dirname; + } + } + return 0; +} + +int main(void) { + char dirname[260]; + if (get_dirname(__FILE__, dirname, sizeof(dirname))) { + puts(dirname); + } + return 0; +} +``` + +## Risk Assessment + +Modifying string literals can lead to [abnormal program termination](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-abnormaltermination) and possibly [denial-of-service attacks](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-denial-of-service). + +
    Rule Severity Likelihood Remediation Cost Priority Level
    STR30-C Low Likely Low P9 L2
    + + +## Automated Detection + +
    Tool Version Checker Description
    Astrée 22.04 string-literal-modfication write-to-string-literal Fully checked
    Axivion Bauhaus Suite 7.2.0 CertC-STR30 Fully implemented
    Compass/ROSE Can detect simple violations of this rule
    Coverity 2017.07 PW Deprecates conversion from a string literal to "char \*"
    Helix QAC 2022.2 C0556, C0752, C0753, C0754 C++3063, C++3064, C++3605, C++3606, C++3607
    Klocwork 2022.2 CERT.STR.ARG.CONST_TO_NONCONST CERT.STR.ASSIGN.CONST_TO_NONCONST
    LDRA tool suite 9.7.1 157 S Partially implemented
    Parasoft C/C++test 2022.1 CERT_C-STR30-a CERT_C-STR30-b A string literal shall not be modified Do not modify string literals
    PC-lint Plus 1.4 489, 1776 Partially supported
    Polyspace Bug Finder R2022a CERT C: Rule STR30-C Checks for writing to const qualified object (rule fully covered)
    PRQA QA-C 9.7 0556, 0752, 0753, 0754 Partially implemented
    PRQA QA-C++ 4.4 3063, 3064, 3605, 3606, 3607, 3842
    PVS-Studio 7.19 V675
    RuleChecker 22.04 string-literal-modfication Partially checked
    Splint 3.1.1
    TrustInSoft Analyzer 1.38 mem_access Exhaustively verified (see one compliant and one non-compliant example ).
    + + +## Related Vulnerabilities + +Search for [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnurability) resulting from the violation of this rule on the [CERT website](https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+STR30-C). + +## Related Guidelines + +[Key here](https://wiki.sei.cmu.edu/confluence/display/c/How+this+Coding+Standard+is+Organized#HowthisCodingStandardisOrganized-RelatedGuidelines) (explains table format and definitions) + +
    Taxonomy Taxonomy item Relationship
    CERT C Secure Coding Standard EXP05-C. Do not cast away a const qualification Prior to 2018-01-12: CERT: Unspecified Relationship
    CERT C Secure Coding Standard STR11-C. Do not specify the bound of a character array initialized with a string literal Prior to 2018-01-12: CERT: Unspecified Relationship
    ISO/IEC TS 17961:2013 Modifying string literals \[strmod\] Prior to 2018-01-12: CERT: Unspecified Relationship
    + + +## Bibliography + +
    \[ ISO/IEC 9899:2011 \] 6.4.5, "String Literals"
    \[ Plum 1991 \] Topic 1.26, "Strings—String Literals"
    \[ Summit 1995 \] comp.lang.c FAQ List, Question 1.32
    + + +## Implementation notes + +None + +## References + +* CERT-C: [STR30-C: Do not attempt to modify string literals](https://wiki.sei.cmu.edu/confluence/display/c) diff --git a/c/cert/src/rules/STR30-C/DoNotAttemptToModifyStringLiterals.qhelp b/c/cert/src/rules/STR30-C/DoNotAttemptToModifyStringLiterals.qhelp deleted file mode 100644 index 9d78ccdf9d..0000000000 --- a/c/cert/src/rules/STR30-C/DoNotAttemptToModifyStringLiterals.qhelp +++ /dev/null @@ -1,18 +0,0 @@ - - - - -

    This query implements the CERT-C rule STR30-C:

    -
    -

    Do not attempt to modify string literals

    -
    -
    - - -
  • - CERT-C: - STR30-C: Do not attempt to modify string literals - . -
  • -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/STR30-C/standard-example.c b/c/cert/src/rules/STR30-C/standard-example.c deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/c/cert/src/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator-standard.qhelp b/c/cert/src/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator-standard.qhelp deleted file mode 100644 index 458fbe3f7d..0000000000 --- a/c/cert/src/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator-standard.qhelp +++ /dev/null @@ -1,33 +0,0 @@ - - -
    -
      -
    • required
    • -
    • implementation
    • -
    • automated
    • -
    -
    - -
    -

    - ... -

    - -
    - -
    -

    - ... -

    -
    - - - - - -
    -
      -
    • ...
    • -
    -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.md b/c/cert/src/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.md new file mode 100644 index 0000000000..6334f9b720 --- /dev/null +++ b/c/cert/src/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.md @@ -0,0 +1,581 @@ +# STR31-C: Guarantee that storage for strings has sufficient space for character data and the null terminator + +This query implements the CERT-C rule STR31-C: + +> Guarantee that storage for strings has sufficient space for character data and the null terminator + + +## Description + +Copying data to a buffer that is not large enough to hold that data results in a buffer overflow. Buffer overflows occur frequently when manipulating strings \[[Seacord 2013b](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-Seacord2013)\]. To prevent such errors, either limit copies through truncation or, preferably, ensure that the destination is of sufficient size to hold the character data to be copied and the null-termination character. (See [STR03-C. Do not inadvertently truncate a string](https://wiki.sei.cmu.edu/confluence/display/c/STR03-C.+Do+not+inadvertently+truncate+a+string).) + +When strings live on the heap, this rule is a specific instance of [MEM35-C. Allocate sufficient memory for an object](https://wiki.sei.cmu.edu/confluence/display/c/MEM35-C.+Allocate+sufficient+memory+for+an+object). Because strings are represented as arrays of characters, this rule is related to both [ARR30-C. Do not form or use out-of-bounds pointers or array subscripts](https://wiki.sei.cmu.edu/confluence/display/c/ARR30-C.+Do+not+form+or+use+out-of-bounds+pointers+or+array+subscripts) and [ARR38-C. Guarantee that library functions do not form invalid pointers](https://wiki.sei.cmu.edu/confluence/display/c/ARR38-C.+Guarantee+that+library+functions+do+not+form+invalid+pointers). + +## Noncompliant Code Example (Off-by-One Error) + +This noncompliant code example demonstrates an *off-by-one* error \[[Dowd 2006](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-Dowd06)\]. The loop copies data from `src` to `dest`. However, because the loop does not account for the null-termination character, it may be incorrectly written 1 byte past the end of `dest`. + +```cpp +#include + +void copy(size_t n, char src[n], char dest[n]) { + size_t i; + + for (i = 0; src[i] && (i < n); ++i) { + dest[i] = src[i]; + } + dest[i] = '\0'; +} + +``` + +## Compliant Solution (Off-by-One Error) + +In this compliant solution, the loop termination condition is modified to account for the null-termination character that is appended to `dest`: + +```cpp +#include + +void copy(size_t n, char src[n], char dest[n]) { + size_t i; + + for (i = 0; src[i] && (i < n - 1); ++i) { + dest[i] = src[i]; + } + dest[i] = '\0'; +} + +``` + +## Noncompliant Code Example (gets()) + +The `gets()` function, which was deprecated in the C99 Technical Corrigendum 3 and removed from C11, is inherently unsafe and should never be used because it provides no way to control how much data is read into a buffer from `stdin`. This noncompliant code example assumes that `gets()` will not read more than `BUFFER_SIZE - 1` characters from `stdin`. This is an invalid assumption, and the resulting operation can result in a buffer overflow. + +The `gets()` function reads characters from the `stdin` into a destination array until end-of-file is encountered or a newline character is read. Any newline character is discarded, and a null character is written immediately after the last character read into the array. + +```cpp +#include + +#define BUFFER_SIZE 1024 + +void func(void) { + char buf[BUFFER_SIZE]; + if (gets(buf) == NULL) { + /* Handle error */ + } +} +``` +See also [MSC24-C. Do not use deprecated or obsolescent functions](https://wiki.sei.cmu.edu/confluence/display/c/MSC24-C.+Do+not+use+deprecated+or+obsolescent+functions). + +## Compliant Solution (fgets()) + +The `fgets()` function reads, at most, one less than the specified number of characters from a stream into an array. This solution is compliant because the number of characters copied from `stdin` to `buf` cannot exceed the allocated memory: + +```cpp +#include +#include + +enum { BUFFERSIZE = 32 }; + +void func(void) { + char buf[BUFFERSIZE]; + int ch; + + if (fgets(buf, sizeof(buf), stdin)) { + /* fgets() succeeded; scan for newline character */ + char *p = strchr(buf, '\n'); + if (p) { + *p = '\0'; + } else { + /* Newline not found; flush stdin to end of line */ + while ((ch = getchar()) != '\n' && ch != EOF) + ; + if (ch == EOF && !feof(stdin) && !ferror(stdin)) { + /* Character resembles EOF; handle error */ + } + } + } else { + /* fgets() failed; handle error */ + } +} +``` +The `fgets()` function is not a strict replacement for the `gets()` function because `fgets()` retains the newline character (if read) and may also return a partial line. It is possible to use `fgets()` to safely process input lines too long to store in the destination array, but this is not recommended for performance reasons. Consider using one of the following compliant solutions when replacing `gets()`. + +## Compliant Solution (gets_s()) + +The `gets_s()` function reads, at most, one less than the number of characters specified from the stream pointed to by `stdin` into an array. + +The C Standard, Annex K \[[ISO/IEC 9899:2011](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO%2FIEC9899-2011)\], states + +> No additional characters are read after a new-line character (which is discarded) or after end-of-file. The discarded new-line character does not count towards number of characters read. A null character is written immediately after the last character read into the array. + + +If end-of-file is encountered and no characters have been read into the destination array, or if a read error occurs during the operation, then the first character in the destination array is set to the null character and the other elements of the array take unspecified values: + +```cpp +#define __STDC_WANT_LIB_EXT1__ 1 +#include + +enum { BUFFERSIZE = 32 }; + +void func(void) { + char buf[BUFFERSIZE]; + + if (gets_s(buf, sizeof(buf)) == NULL) { + /* Handle error */ + } +} +``` + +## Compliant Solution (getline(), POSIX) + +The `getline()` function is similar to the `fgets()` function but can dynamically allocate memory for the input buffer. If passed a null pointer, `getline()` dynamically allocates a buffer of sufficient size to hold the input. If passed a pointer to dynamically allocated storage that is too small to hold the contents of the string, the `getline()` function resizes the buffer, using `realloc()`, rather than truncating the input. If successful, the `getline()` function returns the number of characters read, which can be used to determine if the input has any null characters before the newline. The `getline()` function works only with dynamically allocated buffers. Allocated memory must be explicitly deallocated by the caller to avoid memory leaks. (See [MEM31-C. Free dynamically allocated memory when no longer needed](https://wiki.sei.cmu.edu/confluence/display/c/MEM31-C.+Free+dynamically+allocated+memory+when+no+longer+needed).) + +```cpp +#include +#include +#include + +void func(void) { + int ch; + size_t buffer_size = 32; + char *buffer = malloc(buffer_size); + + if (!buffer) { + /* Handle error */ + return; + } + + if ((ssize_t size = getline(&buffer, &buffer_size, stdin)) + == -1) { + /* Handle error */ + } else { + char *p = strchr(buffer, '\n'); + if (p) { + *p = '\0'; + } else { + /* Newline not found; flush stdin to end of line */ + while ((ch = getchar()) != '\n' && ch != EOF) + ; + if (ch == EOF && !feof(stdin) && !ferror(stdin)) { + /* Character resembles EOF; handle error */ + } + } + } + free (buffer); +} +``` +Note that the `getline()` function uses an [in-band error indicator](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-in-banderrorindicator), in violation of [ERR02-C. Avoid in-band error indicators](https://wiki.sei.cmu.edu/confluence/display/c/ERR02-C.+Avoid+in-band+error+indicators). + +## Noncompliant Code Example (getchar()) + +Reading one character at a time provides more flexibility in controlling behavior, though with additional performance overhead. This noncompliant code example uses the `getchar()` function to read one character at a time from `stdin` instead of reading the entire line at once. The `stdin` stream is read until end-of-file is encountered or a newline character is read. Any newline character is discarded, and a null character is written immediately after the last character read into the array. Similar to the noncompliant code example that invokes `gets()`, there are no guarantees that this code will not result in a buffer overflow. + +```cpp +#include + +enum { BUFFERSIZE = 32 }; + +void func(void) { + char buf[BUFFERSIZE]; + char *p; + int ch; + p = buf; + while ((ch = getchar()) != '\n' && ch != EOF) { + *p++ = (char)ch; + } + *p++ = 0; + if (ch == EOF) { + /* Handle EOF or error */ + } +} +``` +After the loop ends, if `ch == EOF`, the loop has read through to the end of the stream without encountering a newline character, or a read error occurred before the loop encountered a newline character. To conform to [FIO34-C. Distinguish between characters read from a file and EOF or WEOF](https://wiki.sei.cmu.edu/confluence/display/c/FIO34-C.+Distinguish+between+characters+read+from+a+file+and+EOF+or+WEOF), the error-handling code must verify that an end-of-file or error has occurred by calling `feof()` or `ferror()`. + +## Compliant Solution (getchar()) + +In this compliant solution, characters are no longer copied to `buf` once `index == BUFFERSIZE - 1`, leaving room to null-terminate the string. The loop continues to read characters until the end of the line, the end of the file, or an error is encountered. When `chars_read > index`, the input string has been truncated. + +```cpp +#include + +enum { BUFFERSIZE = 32 }; + +void func(void) { + char buf[BUFFERSIZE]; + int ch; + size_t index = 0; + size_t chars_read = 0; + + while ((ch = getchar()) != '\n' && ch != EOF) { + if (index < sizeof(buf) - 1) { + buf[index++] = (char)ch; + } + chars_read++; + } + buf[index] = '\0'; /* Terminate string */ + if (ch == EOF) { + /* Handle EOF or error */ + } + if (chars_read > index) { + /* Handle truncation */ + } +} + +``` + +## Noncompliant Code Example (fscanf()) + +In this noncompliant example, the call to `fscanf()` can result in a write outside the character array `buf`: + +```cpp +#include + +enum { BUF_LENGTH = 1024 }; + +void get_data(void) { + char buf[BUF_LENGTH]; + if (1 != fscanf(stdin, "%s", buf)) { + /* Handle error */ + } + + /* Rest of function */ +} + +``` + +## Compliant Solution (fscanf()) + +In this compliant solution, the call to `fscanf()` is constrained not to overflow `buf`: + +```cpp +#include + +enum { BUF_LENGTH = 1024 }; + +void get_data(void) { + char buf[BUF_LENGTH]; + if (1 != fscanf(stdin, "%1023s", buf)) { + /* Handle error */ + } + + /* Rest of function */ +} + +``` + +## Noncompliant Code Example (argv) + +In a [hosted environment](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-hostedenvironment), arguments read from the command line are stored in process memory. The function `main()`, called at program startup, is typically declared as follows when the program accepts command-line arguments: + +```cpp +int main(int argc, char *argv[]) { /* ... */ } + +``` +Command-line arguments are passed to `main()` as pointers to strings in the array members `argv[0]` through `argv[argc - 1]`. If the value of `argc` is greater than 0, the string pointed to by `argv[0]` is, by convention, the program name. If the value of `argc` is greater than 1, the strings referenced by `argv[1]` through `argv[argc - 1]` are the program arguments. + +[Vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) can occur when inadequate space is allocated to copy a command-line argument or other program input. In this noncompliant code example, an attacker can manipulate the contents of `argv[0]` to cause a buffer overflow: + +```cpp +#include + +int main(int argc, char *argv[]) { + /* Ensure argv[0] is not null */ + const char *const name = (argc && argv[0]) ? argv[0] : ""; + char prog_name[128]; + strcpy(prog_name, name); + + return 0; +} + +``` + +## Compliant Solution (argv) + +The `strlen()` function can be used to determine the length of the strings referenced by `argv[0]` through `argv[argc - 1]` so that adequate memory can be dynamically allocated. + +```cpp +#include +#include + +int main(int argc, char *argv[]) { + /* Ensure argv[0] is not null */ + const char *const name = (argc && argv[0]) ? argv[0] : ""; + char *prog_name = (char *)malloc(strlen(name) + 1); + if (prog_name != NULL) { + strcpy(prog_name, name); + } else { + /* Handle error */ + } + free(prog_name); + return 0; +} + +``` +Remember to add a byte to the destination string size to accommodate the null-termination character. + +## Compliant Solution (argv) + +The `strcpy_s()` function provides additional safeguards, including accepting the size of the destination buffer as an additional argument. (See [STR07-C. Use the bounds-checking interfaces for string manipulation](https://wiki.sei.cmu.edu/confluence/display/c/STR07-C.+Use+the+bounds-checking+interfaces+for+string+manipulation).) + +```cpp +#define __STDC_WANT_LIB_EXT1__ 1 +#include +#include +  +int main(int argc, char *argv[]) { + /* Ensure argv[0] is not null */ + const char *const name = (argc && argv[0]) ? argv[0] : ""; + char *prog_name; + size_t prog_size; + + prog_size = strlen(name) + 1; + prog_name = (char *)malloc(prog_size); + + if (prog_name != NULL) { + if (strcpy_s(prog_name, prog_size, name)) { + /* Handle error */ + } + } else { + /* Handle error */ + } + /* ... */ +  free(prog_name); + return 0; +} + +``` +The `strcpy_s()` function can be used to copy data to or from dynamically allocated memory or a statically allocated array. If insufficient space is available, `strcpy_s()` returns an error. + +## Compliant Solution (argv) + +If an argument will not be modified or concatenated, there is no reason to make a copy of the string. Not copying a string is the best way to prevent a buffer overflow and is also the most efficient solution. Care must be taken to avoid assuming that `argv[0]` is non-null. + +```cpp +int main(int argc, char *argv[]) { + /* Ensure argv[0] is not null */ + const char * const prog_name = (argc && argv[0]) ? argv[0] : ""; + /* ... */ + return 0; +} + +``` + +## Noncompliant Code Example (getenv()) + +According to the C Standard, 7.22.4.6 \[[ISO/IEC 9899:2011](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO-IEC9899-2011)\] + +> The `getenv` function searches an environment list, provided by the host environment, for a string that matches the string pointed to by `name`. The set of environment names and the method for altering the environment list are implementation defined. + + +Environment variables can be arbitrarily large, and copying them into fixed-length arrays without first determining the size and allocating adequate storage can result in a buffer overflow. + +```cpp +#include +#include + +void func(void) { + char buff[256]; + char *editor = getenv("EDITOR"); + if (editor == NULL) { + /* EDITOR environment variable not set */ + } else { + strcpy(buff, editor); + } +} + +``` + +## Compliant Solution (getenv()) + +Environmental variables are loaded into process memory when the program is loaded. As a result, the length of these strings can be determined by calling the `strlen()` function, and the resulting length can be used to allocate adequate dynamic memory: + +```cpp +#include +#include + +void func(void) { + char *buff; + char *editor = getenv("EDITOR"); + if (editor == NULL) { + /* EDITOR environment variable not set */ + } else { + size_t len = strlen(editor) + 1; + buff = (char *)malloc(len); + if (buff == NULL) { + /* Handle error */ + } + memcpy(buff, editor, len); + free(buff); + } +} + +``` + +## Noncompliant Code Example (sprintf()) + +In this noncompliant code example, `name` refers to an external string; it could have originated from user input, the file system, or the network. The program constructs a file name from the string in preparation for opening the file. + +```cpp +#include + +void func(const char *name) { + char filename[128]; + sprintf(filename, "%s.txt", name); +} +``` +Because the `sprintf()` function makes no guarantees regarding the length of the generated string, a sufficiently long string in `name` could generate a buffer overflow. + +## Compliant Solution (sprintf()) + +The buffer overflow in the preceding noncompliant example can be prevented by adding a precision to the `%s` conversion specification. If the precision is specified, no more than that many bytes are written. The precision `123` in this compliant solution ensures that `filename` can contain the first 123 characters of `name`, the `.txt` extension, and the null terminator. + +```cpp +#include + +void func(const char *name) { + char filename[128]; + sprintf(filename, "%.123s.txt", name); +} + +``` +You can also use `*` to indicate that the precision should be provided as a variadic argument: + +```cpp +#include + +void func(const char *name) { + char filename[128]; + sprintf(filename, "%.*s.txt", sizeof(filename) - 5, name); +} +``` + +## Compliant Solution (snprintf()) + +A more general solution is to use the `snprintf()` function: + +```cpp +#include + +void func(const char *name) { + char filename[128]; + snprintf(filename, sizeof(filename), "%s.txt", name); +} + +``` + +## Risk Assessment + +Copying string data to a buffer that is too small to hold that data results in a buffer overflow. Attackers can exploit this condition to execute arbitrary code with the permissions of the vulnerable process. + +
    Rule Severity Likelihood Remediation Cost Priority Level
    STR31-C High Likely Medium P18 L1
    + + +## Automated Detection + +Array access out of bounds, Buffer overflow from incorrect string format specifier, Destination buffer overflow in string manipulation, Invalid use of standard library string routine, Missing null in string array, Pointer access out of bounds, Tainted NULL or non-null-terminated string, Use of dangerous standard function + +
    Tool Version Checker Description
    Astrée 22.04 Supported Astrée reports all buffer overflows resulting from copying data to a buffer that is not large enough to hold that data.
    Axivion Bauhaus Suite 7.2.0 CertC-STR31 Detects calls to unsafe string function that may cause buffer overflow Detects potential buffer overruns, including those caused by unsafe usage of fscanf()
    CodeSonar 7.0p0 LANG.MEM.BO LANG.MEM.TO MISC.MEM.NTERM BADFUNC.BO.\* Buffer overrun Type overrun No space for null terminator A collection of warning classes that report uses of library functions prone to internal buffer overflows
    Compass/ROSE Can detect violations of the rule. However, it is unable to handle cases involving strcpy_s() or manual string copies such as the one in the first example
    Coverity 2017.07 STRING_OVERFLOW BUFFER_SIZE OVERRUN STRING_SIZE Fully implemented
    Fortify SCA 5.0
    Helix QAC 2022.2 C2840, C2841, C2842, C2843, C2845, C2846, C2847, C2848, C2930, C2931, C2932, C2933, C2935, C2936, C2937, C2938 C++0145, C++2840, C++2841, C++2842, C++2843, C++2845, C++2846, C++2847, C++2848, C++2930, C++2931, C++2932, C++2933, C++2935, C++2936, C++2937, C++2938
    Klocwork 2022.2 SV.FMT_STR.BAD_SCAN_FORMAT SV.UNBOUND_STRING_INPUT.FUNC
    LDRA tool suite 9.7.1 489 S, 109 D, 66 X, 70 X, 71 X Partially implemented
    Parasoft C/C++test 2022.1 CERT_C-STR31-a CERT_C-STR31-b CERT_C-STR31-c CERT_C-STR31-d CERT_C-STR31-e Avoid accessing arrays out of bounds Avoid overflow when writing to a buffer Prevent buffer overflows from tainted data Avoid buffer write overflow from tainted data Avoid using unsafe string functions which may cause buffer overflows
    PC-lint Plus 1.4 421, 498 Partially supported
    Polyspace Bug Finder R2022a CERT C: Rule STR31-C Checks for: Use of dangerous standard functionse of dangerous standard function, missing null in string arrayissing null in string array, buffer overflow from incorrect string format specifieruffer overflow from incorrect string format specifier, destination buffer overflow in string manipulationestination buffer overflow in string manipulation, tainted null or non-null-terminated stringainted null or non-null-terminated string. Rule partially covered.
    PRQA QA-C 9.7 5009, 5038, 2840, 2841, 2842, 2843, 2845, 2846, 2847, 2848, 2930, 2931, 2932, 2933, 2935, 2936, 2937, 2938 Partially implemented
    PRQA QA-C++ 4.4 0145, 2840, 2841, 2842, 2843, 2845, 2846, 2847, 2848, 2930, 2931, 2932, 2933, 2935, 2936, 2937, 2938, 5006, 5038
    PVS-Studio 7.19 V518 , V645 , V727 , V755
    Splint 3.1.1
    TrustInSoft Analyzer 1.38 mem_access Exhaustively verified (see one compliant and one non-compliant example ).
    + + +## Related Vulnerabilities + +[CVE-2009-1252](http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2009-1252) results from a violation of this rule. The Network Time Protocol daemon (NTPd), before versions 4.2.4p7 and 4.2.5p74, contained calls to `sprintf` that allow an attacker to execute arbitrary code by overflowing a character array \[[xorl 2009](http://xorl.wordpress.com/2009/06/10/freebsd-sa-0911-ntpd-remote-stack-based-buffer-overflows/)\]. + +[CVE-2009-0587](http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2009-0587) results from a violation of this rule. Before version 2.24.5, Evolution Data Server performed unchecked arithmetic operations on the length of a user-input string and used the value to allocate space for a new buffer. An attacker could thereby execute arbitrary code by inputting a long string, resulting in incorrect allocation and buffer overflow \[[xorl 2009](http://xorl.wordpress.com/2009/06/10/cve-2009-0587-evolution-data-server-base64-integer-overflows/)\]. + +[CVE-2021-3156](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-3156) results from a violation of this rule in versions of Sudo before 1.9.5p2. Due to inconsistencies on whether backslashes are escaped, vulnerable versions of Sudo enabled a user to create a heap-based buffer overflow and exploit it to execute arbitrary code. [\[BC\]](https://www.bleepingcomputer.com/news/security/new-linux-sudo-flaw-lets-local-users-gain-root-privileges/). + +Search for [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) resulting from the violation of this rule on the [CERT website](https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+ARR32-C). + +## Related Guidelines + +[Key here](https://wiki.sei.cmu.edu/confluence/display/c/How+this+Coding+Standard+is+Organized#HowthisCodingStandardisOrganized-RelatedGuidelines) (explains table format and definitions) + +
    Taxonomy Taxonomy item Relationship
    CERT C Secure Coding Standard STR03-C. Do not inadvertently truncate a string Prior to 2018-01-12: CERT: Unspecified Relationship
    CERT C Secure Coding Standard STR07-C. Use the bounds-checking interfaces for remediation of existing string manipulation code MSC24-C. Do not use deprecated or obsolescent functions MEM00-C. Allocate and free memory in the same module, at the same level of abstraction FIO34-C. Distinguish between characters read from a file and EOF or WEOF Prior to 2018-01-12: CERT: Unspecified Relationship
    ISO/IEC TR 24772:2013 String Termination \[CJM\] Prior to 2018-01-12: CERT: Unspecified Relationship
    ISO/IEC TR 24772:2013 Buffer Boundary Violation (Buffer Overflow) \[HCB\] Prior to 2018-01-12: CERT: Unspecified Relationship
    ISO/IEC TR 24772:2013 Unchecked Array Copying \[XYW\] Prior to 2018-01-12: CERT: Unspecified Relationship
    ISO/IEC TS 17961:2013 Using a tainted value to write to an object using a formatted input or output function \[taintformatio\] Prior to 2018-01-12: CERT: Unspecified Relationship
    ISO/IEC TS 17961:2013 Tainted strings are passed to a string copying function \[taintstrcpy\] Prior to 2018-01-12: CERT: Unspecified Relationship
    CWE 2.11 CWE-119 , Improper Restriction of Operations within the Bounds of a Memory Buffer 2017-05-18: CERT: Rule subset of CWE
    CWE 2.11 CWE-120 , Buffer Copy without Checking Size of Input ("Classic Buffer Overflow") 2017-05-15: CERT: Exact
    CWE 2.11 CWE-123 , Write-what-where Condition 2017-06-12: CERT: Partial overlap
    CWE 2.11 CWE-125 , Out-of-bounds Read 2017-05-18: CERT: Partial overlap
    CWE 2.11 CWE-676 , Off-by-one Error 2017-05-18: CERT: Partial overlap
    + + +## CERT-CWE Mapping Notes + +[Key here](https://wiki.sei.cmu.edu/confluence/pages/viewpage.action?pageId=87152408#HowthisCodingStandardisOrganized-CERT-CWEMappingNotes) for mapping notes + +**CWE-122 and STR31-C** + +STR31-C = Union( CWE-122, list) where list = + +* Buffer overflows on strings in the stack or data segment +**CWE-125 and STR31-C** + +Independent( ARR30-C, ARR38-C, EXP39-C, INT30-C) + +STR31-C = Subset( Union( ARR30-C, ARR38-C)) + +STR32-C = Subset( ARR38-C) + +Intersection( STR31-C, CWE-125) = + +* Directly reading beyond the end of a string +STR31-C – CWE-125 = +* Directly writing beyond the end of a string +CWE-125 – STR31-C = +* Reading beyond a non-string array +* Reading beyond a string using library functions +**CWE-676 and STR31-C** +* Independent( ENV33-C, CON33-C, STR31-C, EXP33-C, MSC30-C, ERR34-C) +* STR31-C implies that several C string copy functions, like strcpy() are dangerous. +Intersection( CWE-676, STR31-C) = +* Buffer Overflow resulting from invocation of the following dangerous functions: +* gets(), fscanf(), strcpy(), sprintf() +STR31-C – CWE-676 = +* Buffer overflow that does not involve the dangerous functions listed above. +CWE-676 - STR31-C = +* Invocation of other dangerous functions +**CWE-121 and STR31-C** + +STR31-C = Union( CWE-121, list) where list = + +* Buffer overflows on strings in the heap or data segment +**CWE-123 and STR31-C** + +Independent(ARR30-C, ARR38-C) + +STR31-C = Subset( Union( ARR30-C, ARR38-C)) + +STR32-C = Subset( ARR38-C) + +Intersection( CWE-123, STR31-C) = + +* Buffer overflow that overwrites a (unrelated) pointer with untrusted data +STR31-C – CWE-123 = +* Buffer overflow that does not overwrite a (unrelated) pointer +CWE-123 – STR31-C = +* Arbitrary writes that do not involve buffer overflows +**CWE-119 and STR31-C** + +Independent( ARR30-C, ARR38-C, ARR32-C, INT30-C, INT31-C, EXP39-C, EXP33-C, FIO37-C) + +STR31-C = Subset( Union( ARR30-C, ARR38-C)) + +STR32-C = Subset( ARR38-C) + +CWE-119 = Union( STR31-C, list) where list = + +* Out-of-bounds reads or writes that are not created by string copy operations +**CWE-193 and STR31-C** + +Intersection( CWE-193, STR31-C) = Ø + +CWE-193 involves an integer computation error (typically off-by-one), which is often a precursor to (slight) buffer overflow. However the two errors occur in different operations and are thus unrelated. + +## Bibliography + +
    \[ Dowd 2006 \] Chapter 7, "Program Building Blocks" ("Loop Constructs," pp. 327–336)
    \[ Drepper 2006 \] Section 2.1.1, "Respecting Memory Bounds"
    \[ ISO/IEC 9899:2011 \] K.3.5.4.1, "The gets_s Function"
    \[ Lai 2006 \]
    \[ NIST 2006 \] SAMATE Reference Dataset Test Case ID 000-000-088
    \[ Seacord 2013b \] Chapter 2, "Strings"
    \[ xorl 2009 \] FreeBSD-SA-09:11: NTPd Remote Stack Based Buffer Overflows
    \[BC\] New Linux SUDO flaw lets local users gain root privileges
    + + +## Implementation notes + +None + +## References + +* CERT-C: [STR31-C: Guarantee that storage for strings has sufficient space for character data and the null terminator](https://wiki.sei.cmu.edu/confluence/display/c) diff --git a/c/cert/src/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.qhelp b/c/cert/src/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.qhelp deleted file mode 100644 index 4cd91b96b8..0000000000 --- a/c/cert/src/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.qhelp +++ /dev/null @@ -1,18 +0,0 @@ - - - - -

    This query implements the CERT-C rule STR31-C:

    -
    -

    Guarantee that storage for strings has sufficient space for character data and the null terminator

    -
    -
    - - -
  • - CERT-C: - STR31-C: Guarantee that storage for strings has sufficient space for character data and the null terminator - . -
  • -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/STR31-C/standard-example.c b/c/cert/src/rules/STR31-C/standard-example.c deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/c/cert/src/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString-standard.qhelp b/c/cert/src/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString-standard.qhelp deleted file mode 100644 index 458fbe3f7d..0000000000 --- a/c/cert/src/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString-standard.qhelp +++ /dev/null @@ -1,33 +0,0 @@ - - -
    -
      -
    • required
    • -
    • implementation
    • -
    • automated
    • -
    -
    - -
    -

    - ... -

    - -
    - -
    -

    - ... -

    -
    - - - - - -
    -
      -
    • ...
    • -
    -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.md b/c/cert/src/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.md new file mode 100644 index 0000000000..e2276fa58d --- /dev/null +++ b/c/cert/src/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.md @@ -0,0 +1,278 @@ +# STR32-C: Do not pass a non-null-terminated character sequence to a library function that expects a string + +This query implements the CERT-C rule STR32-C: + +> Do not pass a non-null-terminated character sequence to a library function that expects a string + + +## Description + +Many library functions accept a string or wide string argument with the constraint that the string they receive is properly null-terminated. Passing a character sequence or wide character sequence that is not null-terminated to such a function can result in accessing memory that is outside the bounds of the object. Do not pass a character sequence or wide character sequence that is not null-terminated to a library function that expects a string or wide string argument. + +## Noncompliant Code Example + +This code example is noncompliant because the character sequence `c_str` will not be null-terminated when passed as an argument to `printf().` (See [STR11-C. Do not specify the bound of a character array initialized with a string literal](https://wiki.sei.cmu.edu/confluence/display/c/STR11-C.+Do+not+specify+the+bound+of+a+character+array+initialized+with+a+string+literal) on how to properly initialize character arrays.) + +```cpp +#include + +void func(void) { + char c_str[3] = "abc"; + printf("%s\n", c_str); +} + +``` + +## Compliant Solution + +This compliant solution does not specify the bound of the character array in the array declaration. If the array bound is omitted, the compiler allocates sufficient storage to store the entire string literal, including the terminating null character. + +```cpp +#include + +void func(void) { + char c_str[] = "abc"; + printf("%s\n", c_str); +} +``` + +## Noncompliant Code Example + +This code example is noncompliant because the wide character sequence `cur_msg` will not be null-terminated when passed to `wcslen()`. This will occur if `lessen_memory_usage()` is invoked while `cur_msg_size` still has its initial value of 1024. + +```cpp +#include +#include +  +wchar_t *cur_msg = NULL; +size_t cur_msg_size = 1024; +size_t cur_msg_len = 0; + +void lessen_memory_usage(void) { + wchar_t *temp; + size_t temp_size; + + /* ... */ + + if (cur_msg != NULL) { + temp_size = cur_msg_size / 2 + 1; + temp = realloc(cur_msg, temp_size * sizeof(wchar_t)); + /* temp &and cur_msg may no longer be null-terminated */ + if (temp == NULL) { + /* Handle error */ + } + + cur_msg = temp; + cur_msg_size = temp_size; + cur_msg_len = wcslen(cur_msg); + } +} +``` + +## Compliant Solution + +In this compliant solution, `cur_msg` will always be null-terminated when passed to `wcslen()`: + +```cpp +#include +#include +  +wchar_t *cur_msg = NULL; +size_t cur_msg_size = 1024; +size_t cur_msg_len = 0; + +void lessen_memory_usage(void) { + wchar_t *temp; + size_t temp_size; + + /* ... */ + + if (cur_msg != NULL) { + temp_size = cur_msg_size / 2 + 1; + temp = realloc(cur_msg, temp_size * sizeof(wchar_t)); + /* temp and cur_msg may no longer be null-terminated */ + if (temp == NULL) { + /* Handle error */ + } + + cur_msg = temp; + /* Properly null-terminate cur_msg */ + cur_msg[temp_size - 1] = L'\0'; + cur_msg_size = temp_size; + cur_msg_len = wcslen(cur_msg); + } +} +``` + +## Noncompliant Code Example (strncpy()) + +Although the `strncpy()` function takes a string as input, it does not guarantee that the resulting value is still null-terminated. In the following noncompliant code example, if no null character is contained in the first `n` characters of the `source` array, the result will not be null-terminated. Passing a non-null-terminated character sequence to `strlen()` is undefined behavior. + +```cpp +#include + +enum { STR_SIZE = 32 }; + +size_t func(const char *source) { + char c_str[STR_SIZE]; + size_t ret = 0; + + if (source) { + c_str[sizeof(c_str) - 1] = '\0'; + strncpy(c_str, source, sizeof(c_str)); + ret = strlen(c_str); + } else { + /* Handle null pointer */ + } + return ret; +} + +``` + +## Compliant Solution (Truncation) + +This compliant solution is correct if the programmer's intent is to truncate the string: + +```cpp +#include + +enum { STR_SIZE = 32 }; + +size_t func(const char *source) { + char c_str[STR_SIZE]; + size_t ret = 0; + + if (source) { + strncpy(c_str, source, sizeof(c_str) - 1); + c_str[sizeof(c_str) - 1] = '\0'; + ret = strlen(c_str); + } else { + /* Handle null pointer */ + } + return ret; +} +``` + +## Compliant Solution (Truncation, strncpy_s()) + +The C Standard, Annex K `strncpy_s()` function can also be used to copy with truncation. The `strncpy_s()` function copies up to `n` characters from the source array to a destination array. If no null character was copied from the source array, then the `n`th position in the destination array is set to a null character, guaranteeing that the resulting string is null-terminated. + +```cpp +#define __STDC_WANT_LIB_EXT1__ 1 +#include + +enum { STR_SIZE = 32 }; + +size_t func(const char *source) { + char a[STR_SIZE]; + size_t ret = 0; + + if (source) { + errno_t err = strncpy_s( + a, sizeof(a), source, strlen(source) + ); + if (err != 0) { + /* Handle error */ + } else { + ret = strnlen_s(a, sizeof(a)); + } + } else { + /* Handle null pointer */ + } + return ret; +} + +``` + +## Compliant Solution (Copy without Truncation) + +If the programmer's intent is to copy without truncation, this compliant solution copies the data and guarantees that the resulting array is null-terminated. If the string cannot be copied, it is handled as an error condition. + +```cpp +#include + +enum { STR_SIZE = 32 }; + +size_t func(const char *source) { + char c_str[STR_SIZE]; + size_t ret = 0; + + if (source) { + if (strlen(source) < sizeof(c_str)) { + strcpy(c_str, source); + ret = strlen(c_str); + } else { + /* Handle string-too-large */ + } + } else { + /* Handle null pointer */ + } + return ret; +} +``` + +## Risk Assessment + +Failure to properly null-terminate a character sequence that is passed to a library function that expects a string can result in buffer overflows and the execution of arbitrary code with the permissions of the vulnerable process. Null-termination errors can also result in unintended information disclosure. + +
    Rule Severity Likelihood Remediation Cost Priority Level
    STR32-C High Probable Medium P12 L1
    + + +## Automated Detection + +
    Tool Version Checker Description
    Astrée 22.04 Supported Astrée supports the implementation of library stubs to fully verify this guideline.
    Axivion Bauhaus Suite 7.2.0 CertC-STR32 Partially implemented: can detect some violation of the rule
    CodeSonar 7.0p0 MISC.MEM.NTERM.CSTRING Unterminated C String
    Compass/ROSE Can detect some violations of this rule
    Coverity 2017.07 STRING_NULL Fully implemented
    Helix QAC 2022.2 C2835, C2836, C2839 C++2835, C++2836, C++2839
    Klocwork 2022.2 NNTS.MIGHTSV.STRBO.BOUND_COPY.UNTERM
    LDRA tool suite 9.7.1 404 S, 600 S Partially implemented
    Parasoft C/C++test 2022.1 CERT_C-STR32-a Avoid overflow due to reading a not zero terminated string
    Polyspace Bug Finder R2022a CERT C: Rule STR32-C Checks for: Invalid use of standard library string routinenvalid use of standard library string routine, tainted null or non-null-terminated stringainted null or non-null-terminated string. Rule partially covered.
    PRQA QA-C 9.7 2835, 2836, 2839
    PRQA QA-C++ 4.4 0145
    PVS-Studio 7.19 V692
    TrustInSoft Analyzer 1.38 match format and arguments Partially verified.
    + + +## Related Vulnerabilities + +Search for [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) resulting from the violation of this rule on the [CERT website](https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+STR32-C). + +## Related Guidelines + +[Key here](https://wiki.sei.cmu.edu/confluence/display/c/How+this+Coding+Standard+is+Organized#HowthisCodingStandardisOrganized-RelatedGuidelines) (explains table format and definitions) + +
    Taxonomy Taxonomy item Relationship
    ISO/IEC TR 24772:2013 String Termination \[CMJ\] Prior to 2018-01-12: CERT: Unspecified Relationship
    ISO/IEC TS 17961:2013 Passing a non-null-terminated character sequence to a library function that expects a string \[strmod\] Prior to 2018-01-12: CERT: Unspecified Relationship
    CWE 2.11 CWE-119 , Improper Restriction of Operations within the Bounds of a Memory Buffer 2017-05-18: CERT: Rule subset of CWE
    CWE 2.11 CWE-123 , Write-what-where Condition 2017-06-12: CERT: Partial overlap
    CWE 2.11 CWE-125 , Out-of-bounds Read 2017-05-18: CERT: Rule subset of CWE
    CWE 2.11 CWE-170 , Improper Null Termination 2017-06-13: CERT: Exact
    + + +## CERT-CWE Mapping Notes + +[Key here](https://wiki.sei.cmu.edu/confluence/pages/viewpage.action?pageId=87152408#HowthisCodingStandardisOrganized-CERT-CWEMappingNotes) for mapping notes + +**CWE-119 and STR32-C** + +Independent( ARR30-C, ARR38-C, ARR32-C, INT30-C, INT31-C, EXP39-C, EXP33-C, FIO37-C) STR31-C = Subset( Union( ARR30-C, ARR38-C)) STR32-C = Subset( ARR38-C) + +CWE-119 = Union( STR32-C, list) where list = + +* Out-of-bounds reads or writes that do not involve non-null-terminated byte strings. +**CWE-125 and STR32-C** + +Independent( ARR30-C, ARR38-C, EXP39-C, INT30-C) STR31-C = Subset( Union( ARR30-C, ARR38-C)) STR32-C = Subset( ARR38-C) + +CWE-125 = Union( STR32-C, list) where list = + +* Out-of-bounds reads that do not involve non-null-terminated byte strings. +**CWE-123 and STR32-C** + +Independent(ARR30-C, ARR38-C) STR31-C = Subset( Union( ARR30-C, ARR38-C)) STR32-C = Subset( ARR38-C) + +Intersection( CWE-123, STR32-C) = + +* Buffer overflow from passing a non-null-terminated byte string to a standard C library copying function that expects null termination, and that overwrites an (unrelated) pointer +STR32-C - CWE-123 = +* Buffer overflow from passing a non-null-terminated byte string to a standard C library copying function that expects null termination, but it does not overwrite an (unrelated) pointer +CWE-123 – STR31-C = +* Arbitrary writes that do not involve standard C library copying functions, such as strcpy() + +## Bibliography + +
    \[ Seacord 2013 \] Chapter 2, "Strings"
    \[ Viega 2005 \] Section 5.2.14, "Miscalculated NULL Termination"
    + + +## Implementation notes + +None + +## References + +* CERT-C: [STR32-C: Do not pass a non-null-terminated character sequence to a library function that expects a string](https://wiki.sei.cmu.edu/confluence/display/c) diff --git a/c/cert/src/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.qhelp b/c/cert/src/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.qhelp deleted file mode 100644 index c1f38a0a52..0000000000 --- a/c/cert/src/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.qhelp +++ /dev/null @@ -1,18 +0,0 @@ - - - - -

    This query implements the CERT-C rule STR32-C:

    -
    -

    Do not pass a non-null-terminated character sequence to a library function that expects a string

    -
    -
    - - -
  • - CERT-C: - STR32-C: Do not pass a non-null-terminated character sequence to a library function that expects a string - . -
  • -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/STR32-C/standard-example.c b/c/cert/src/rules/STR32-C/standard-example.c deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/c/cert/src/rules/STR34-C/CastCharBeforeConvertingToLargerSizes-standard.qhelp b/c/cert/src/rules/STR34-C/CastCharBeforeConvertingToLargerSizes-standard.qhelp deleted file mode 100644 index 458fbe3f7d..0000000000 --- a/c/cert/src/rules/STR34-C/CastCharBeforeConvertingToLargerSizes-standard.qhelp +++ /dev/null @@ -1,33 +0,0 @@ - - -
    -
      -
    • required
    • -
    • implementation
    • -
    • automated
    • -
    -
    - -
    -

    - ... -

    - -
    - -
    -

    - ... -

    -
    - - - - - -
    -
      -
    • ...
    • -
    -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.md b/c/cert/src/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.md new file mode 100644 index 0000000000..7334375634 --- /dev/null +++ b/c/cert/src/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.md @@ -0,0 +1,162 @@ +# STR34-C: Cast characters to unsigned char before converting to larger integer sizes + +This query implements the CERT-C rule STR34-C: + +> Cast characters to unsigned char before converting to larger integer sizes + + +## Description + +Signed character data must be converted to `unsigned char` before being assigned or converted to a larger signed type. This rule applies to both `signed char` and (plain) `char` characters on implementations where `char` is defined to have the same range, representation, and behaviors as `signed char`. + +However, this rule is applicable only in cases where the character data may contain values that can be interpreted as negative numbers. For example, if the `char` type is represented by a two's complement 8-bit value, any character value greater than +127 is interpreted as a negative value. + +This rule is a generalization of [STR37-C. Arguments to character-handling functions must be representable as an unsigned char](https://wiki.sei.cmu.edu/confluence/display/c/STR37-C.+Arguments+to+character-handling+functions+must+be+representable+as+an+unsigned+char). + +## Noncompliant Code Example + +This noncompliant code example is taken from a [vulnerability](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) in bash versions 1.14.6 and earlier that led to the release of CERT Advisory [CA-1996-22](http://www.cert.org/advisories/CA-1996-22.html). This vulnerability resulted from the sign extension of character data referenced by the `c_str` pointer in the `yy_string_get()` function in the `parse.y` module of the bash source code: + +```cpp +static int yy_string_get(void) { + register char *c_str; + register int c; + + c_str = bash_input.location.string; + c = EOF; + + /* If the string doesn't exist or is empty, EOF found */ + if (c_str && *c_str) { + c = *c_str++; + bash_input.location.string = c_str; + } + return (c); +} + +``` +The `c_str` variable is used to traverse the character string containing the command line to be parsed. As characters are retrieved from this pointer, they are stored in a variable of type `int`. For implementations in which the `char` type is defined to have the same range, representation, and behavior as `signed char`, this value is sign-extended when assigned to the `int` variable. For character code 255 decimal (−1 in two's complement form), this sign extension results in the value −1 being assigned to the integer, which is indistinguishable from `EOF`. + +## Noncompliant Code Example + +This problem can be repaired by explicitly declaring the `c_str` variable as `unsigned char`: + +```cpp +static int yy_string_get(void) { + register unsigned char *c_str; + register int c; + + c_str = bash_input.location.string; + c = EOF; + + /* If the string doesn't exist or is empty, EOF found */ + if (c_str && *c_str) { + c = *c_str++; + bash_input.location.string = c_str; + } + return (c); +} + +``` +This example, however, violates [STR04-C. Use plain char for characters in the basic character set](https://wiki.sei.cmu.edu/confluence/display/c/STR04-C.+Use+plain+char+for+characters+in+the+basic+character+set). + +## Compliant Solution + +In this compliant solution, the result of the expression `*c_str++` is cast to `unsigned char` before assignment to the `int` variable `c`: + +```cpp +static int yy_string_get(void) { + register char *c_str; + register int c; + + c_str = bash_input.location.string; + c = EOF; + + /* If the string doesn't exist or is empty, EOF found */ + if (c_str && *c_str) { + /* Cast to unsigned type */ + c = (unsigned char)*c_str++; + + bash_input.location.string = c_str; + } + return (c); +} + +``` + +## Noncompliant Code Example + +In this noncompliant code example, the cast of `*s` to `unsigned int` can result in a value in excess of `UCHAR_MAX` because of integer promotions, a violation of [ARR30-C. Do not form or use out-of-bounds pointers or array subscripts](https://wiki.sei.cmu.edu/confluence/display/c/ARR30-C.+Do+not+form+or+use+out-of-bounds+pointers+or+array+subscripts): + +```cpp +#include +#include +  +static const char table[UCHAR_MAX + 1] = { 'a' /* ... */ }; + +ptrdiff_t first_not_in_table(const char *c_str) { + for (const char *s = c_str; *s; ++s) { + if (table[(unsigned int)*s] != *s) { + return s - c_str; + } + } + return -1; +} + +``` + +## Compliant Solution + +This compliant solution casts the value of type `char` to `unsigned char` before the implicit promotion to a larger type: + +```cpp +#include +#include +  +static const char table[UCHAR_MAX + 1] = { 'a' /* ... */ }; + +ptrdiff_t first_not_in_table(const char *c_str) { + for (const char *s = c_str; *s; ++s) { + if (table[(unsigned char)*s] != *s) { + return s - c_str; + } + } + return -1; +} + +``` + +## Risk Assessment + +Conversion of character data resulting in a value in excess of `UCHAR_MAX` is an often-missed error that can result in a disturbingly broad range of potentially severe [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability). + +
    Rule Severity Likelihood Remediation Cost Priority Level
    STR34-C Medium Probable Medium P8 L2
    + + +## Automated Detection + +
    Tool Version Checker Description
    Astrée 22.04 char-sign-conversion Fully checked
    Axivion Bauhaus Suite 7.2.0 CertC-STR34 Fully implemented
    CodeSonar 7.0p0 MISC.NEGCHAR Negative Character Value
    Compass/ROSE Can detect violations of this rule when checking for violations of INT07-C. Use only explicitly signed or unsigned char type for numeric values
    Coverity 2017.07 MISRA C 2012 Rule 10.1 MISRA C 2012 Rule 10.2 MISRA C 2012 Rule 10.3 MISRA C 2012 Rule 10.4 Implemented Essential type checkers
    ECLAIR 1.2 CC2.STR34 Fully implemented
    GCC 2.95 and later -Wchar-subscripts Detects objects of type char used as array indices
    Helix QAC 2022.2 C2140, C2141, C2143, C2144, C2145, C2147, C2148, C2149, C2151, C2152, C2153, C2155 C++3051
    Klocwork 2022.2 MISRA.ETYPE.ASSIGN.2012 MISRA.ETYPE.CATEGORY.DIFFERENT.2012 MISRA.ETYPE.INAPPR.OPERAND.BINOP.2012 MISRA.ETYPE.INAPPR.OPERAND.INDEXPR.2012 MISRA.ETYPE.INAPPR.OPERAND.TERNOP.2012 MISRA.ETYPE.INAPPR.OPERAND.UNOP.2012
    LDRA tool suite 9.7.1 434 S Partially implemented
    Parasoft C/C++test 2022.1 CERT_C-STR34-b CERT_C-STR34-c CERT_C-STR34-d Cast characters to unsigned char before assignment to larger integer sizes An expressions of the 'signed char' type should not be used as an array index Cast characters to unsigned char before converting to larger integer sizes
    PC-lint Plus 1.4 571 Partially supported
    Polyspace Bug Finder R2022a CERT C: Rule STR34-C Checks for misuse of sign-extended character value (rule fully covered)
    PRQA QA-C 9.7 2140, 2141, 2143, 2144, 2145, 2147, 2148, 2149, 2151, 2152, 2153, 2155 Fully implemented
    PRQA QA-C++ 4.4 3051
    RuleChecker 22.04 char-sign-conversion Fully checked
    TrustInSoft Analyzer 1.38 out of bounds read Partially verified (exhaustively detects undefined behavior).
    + + +## Related Vulnerabilities + +[CVE-2009-0887](http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2009-0887) results from a violation of this rule. In Linux PAM (up to version 1.0.3), the `libpam` implementation of `strtok()` casts a (potentially signed) character to an integer for use as an index to an array. An attacker can exploit this vulnerability by inputting a string with non-ASCII characters, causing the cast to result in a negative index and accessing memory outside of the array \[[xorl 2009](http://xorl.wordpress.com/2009/03/26/cve-2009-0887-linux-pam-singedness-issue/)\]. + +Search for [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) resulting from the violation of this rule on the [CERT website](https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+STR34-C). + +**Related Guidelines** + +
    CERT C Secure Coding Standard STR37-C. Arguments to character-handling functions must be representable as an unsigned char STR04-C. Use plain char for characters in the basic character set ARR30-C. Do not form or use out-of-bounds pointers or array subscripts
    ISO/IEC TS 17961:2013 Conversion of signed characters to wider integer types before a check for EOF \[signconv\]
    MISRA-C:2012 Rule 10.1 (required) Rule 10.2 (required) Rule 10.3 (required) Rule 10.4 (required)
    MITRE CWE CWE-704 , Incorrect Type Conversion or Cast
    + + +## Bibliography + +
    \[ xorl 2009 \] CVE-2009-0887: Linux-PAM Signedness Issue
    + + +## Implementation notes + +None + +## References + +* CERT-C: [STR34-C: Cast characters to unsigned char before converting to larger integer sizes](https://wiki.sei.cmu.edu/confluence/display/c) diff --git a/c/cert/src/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.qhelp b/c/cert/src/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.qhelp deleted file mode 100644 index 13f1c41ec1..0000000000 --- a/c/cert/src/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.qhelp +++ /dev/null @@ -1,18 +0,0 @@ - - - - -

    This query implements the CERT-C rule STR34-C:

    -
    -

    Cast characters to unsigned char before converting to larger integer sizes

    -
    -
    - - -
  • - CERT-C: - STR34-C: Cast characters to unsigned char before converting to larger integer sizes - . -
  • -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/STR34-C/standard-example.c b/c/cert/src/rules/STR34-C/standard-example.c deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/c/cert/src/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar-standard.qhelp b/c/cert/src/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar-standard.qhelp deleted file mode 100644 index 458fbe3f7d..0000000000 --- a/c/cert/src/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar-standard.qhelp +++ /dev/null @@ -1,33 +0,0 @@ - - -
    -
      -
    • required
    • -
    • implementation
    • -
    • automated
    • -
    -
    - -
    -

    - ... -

    - -
    - -
    -

    - ... -

    -
    - - - - - -
    -
      -
    • ...
    • -
    -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar.md b/c/cert/src/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar.md new file mode 100644 index 0000000000..a956123c3b --- /dev/null +++ b/c/cert/src/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar.md @@ -0,0 +1,118 @@ +# STR37-C: Arguments to character-handling functions must be representable as an unsigned char + +This query implements the CERT-C rule STR37-C: + +> Arguments to character-handling functions must be representable as an unsigned char + + +## Description + +According to the C Standard, 7.4 \[[ISO/IEC 9899:2011](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO-IEC9899-2011)\], + +> The header `` declares several functions useful for classifying and mapping characters. In all cases the argument is an `int`, the value of which shall be representable as an `unsigned char` or shall equal the value of the macro `EOF`. If the argument has any other value, the behavior is [undefined](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior). + + +See also [undefined behavior 113](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_113). + +This rule is applicable only to code that runs on platforms where the `char` data type is defined to have the same range, representation, and behavior as `signed char`. + +Following are the character classification functions that this rule addresses: + +
    isalnum() isalpha() isascii() XSI isblank()
    iscntrl() isdigit() isgraph() islower()
    isprint() ispunct() isspace() isupper()
    isxdigit() toascii() XSI toupper() tolower()
    +XSI denotes an X/Open System Interfaces Extension to ISO/IEC 9945—POSIX. These functions are not defined by the C Standard. + + +This rule is a specific instance of [STR34-C. Cast characters to unsigned char before converting to larger integer sizes](https://wiki.sei.cmu.edu/confluence/display/c/STR34-C.+Cast+characters+to+unsigned+char+before+converting+to+larger+integer+sizes). + +## Noncompliant Code Example + +On implementations where plain `char` is signed, this code example is noncompliant because the parameter to `isspace()`, `*t`, is defined as a `const char *`, and this value might not be representable as an `unsigned char`: + +```cpp +#include +#include + +size_t count_preceding_whitespace(const char *s) { + const char *t = s; + size_t length = strlen(s) + 1; + while (isspace(*t) && (t - s < length)) { + ++t; + } + return t - s; +} +``` +The argument to `isspace()` must be `EOF` or representable as an `unsigned char`; otherwise, the result is undefined. + +## Compliant Solution + +This compliant solution casts the character to `unsigned char` before passing it as an argument to the `isspace()` function: + +```cpp +#include +#include + +size_t count_preceding_whitespace(const char *s) { + const char *t = s; + size_t length = strlen(s) + 1; + while (isspace((unsigned char)*t) && (t - s < length)) { + ++t; + } + return t - s; +} +``` + +## Risk Assessment + +Passing values to character handling functions that cannot be represented as an `unsigned char` to character handling functions is [undefined behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior). + +
    Rule Severity Likelihood Remediation Cost Priority Level
    STR37-C Low Unlikely Low P3 L3
    + + +## Automated Detection + +
    Tool Version Checker Description
    Astrée 22.04 ctype-limits Partially checked
    Axivion Bauhaus Suite 7.2.0 CertC-STR37 Fully implemented
    CodeSonar 7.0p0 MISC.NEGCHAR Negative character value
    Compass/ROSE Could detect violations of this rule by seeing if the argument to a character handling function (listed above) is not an unsigned char
    ECLAIR 1.2 CC2.STR37 Fully implemented
    Helix QAC 2022.2 C4413, C4414 C++3051
    Klocwork 2022.2 AUTOSAR.STDLIB.CCTYPE.UCHAR MISRA.ETYPE.ASSIGN.2012
    LDRA tool suite 9.7.1 663 S Fully implemented
    Parasoft C/C++test 2022.1 CERT_C-STR37-a Do not pass incorrect values to ctype.h library functions
    Polyspace Bug Finder R2022a CERT C: Rule STR37-C Checks for invalid use of standard library integer routine (rule fully covered)
    PRQA QA-C 9.7 4413, 4414 Fully implemented
    PRQA QA-C++ 4.4 3051
    RuleChecker 22.04 ctype-limits Partially checked
    TrustInSoft Analyzer 1.38 valid_char Partially verified.
    + + +## Related Vulnerabilities + +Search for [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) resulting from the violation of this rule on the [CERT website](https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+STR37-C). + +## Related Guidelines + +[Key here](https://wiki.sei.cmu.edu/confluence/display/c/How+this+Coding+Standard+is+Organized#HowthisCodingStandardisOrganized-RelatedGuidelines) (explains table format and definitions) + +
    Taxonomy Taxonomy item Relationship
    CERT C Secure Coding Standard STR34-C. Cast characters to unsigned char before converting to larger integer sizes Prior to 2018-01-12: CERT: Unspecified Relationship
    ISO/IEC TS 17961 Passing arguments to character-handling functions that are not representable as unsigned char \[chrsgnext\] Prior to 2018-01-12: CERT: Unspecified Relationship
    CWE 2.11 CWE-704 , Incorrect Type Conversion or Cast 2017-06-14: CERT: Rule subset of CWE
    + + +## CERT-CWE Mapping Notes + +[Key here](https://wiki.sei.cmu.edu/confluence/pages/viewpage.action?pageId=87152408#HowthisCodingStandardisOrganized-CERT-CWEMappingNotes) for mapping notes + +**CWE-686 and STR37-C** + +Intersection( CWE-686, STR37-C) = Ø + +STR37-C is not about the type of the argument passed (which is signed int), but about the restrictions placed on the value in this type (must be 0-UCHAR_MAX or EOF). I interpret ‘argument type’ to be specific to the C language, so CWE-686 does not apply to incorrect argument values, just incorrect types (which is relatively rare in C, but still possible). + +**CWE-704 and STR37-C** + +STR37-C = Subset( STR34-C) + +**CWE-683 and STR37-C** + +Intersection( CWE-683, STR37-C) = Ø + +STR37-C excludes mis-ordered function arguments (assuming they pass type-checking), because there is no easy way to reliably detect violations of CWE-683. + +## Bibliography + +
    \[ ISO/IEC 9899:2011 \] 7.4, "Character Handling < ctype.h >"
    \[ Kettlewell 2002 \] Section 1.1, "< ctype.h > and Characters Types"
    + + +## Implementation notes + +None + +## References + +* CERT-C: [STR37-C: Arguments to character-handling functions must be representable as an unsigned char](https://wiki.sei.cmu.edu/confluence/display/c) diff --git a/c/cert/src/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar.qhelp b/c/cert/src/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar.qhelp deleted file mode 100644 index 63fc3848bb..0000000000 --- a/c/cert/src/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar.qhelp +++ /dev/null @@ -1,18 +0,0 @@ - - - - -

    This query implements the CERT-C rule STR37-C:

    -
    -

    Arguments to character-handling functions must be representable as an unsigned char

    -
    -
    - - -
  • - CERT-C: - STR37-C: Arguments to character-handling functions must be representable as an unsigned char - . -
  • -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/STR37-C/standard-example.c b/c/cert/src/rules/STR37-C/standard-example.c deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/c/cert/src/rules/STR38-C/DoNotConfuseNarrowAndWideFunctions-standard.qhelp b/c/cert/src/rules/STR38-C/DoNotConfuseNarrowAndWideFunctions-standard.qhelp deleted file mode 100644 index 458fbe3f7d..0000000000 --- a/c/cert/src/rules/STR38-C/DoNotConfuseNarrowAndWideFunctions-standard.qhelp +++ /dev/null @@ -1,33 +0,0 @@ - - -
    -
      -
    • required
    • -
    • implementation
    • -
    • automated
    • -
    -
    - -
    -

    - ... -

    - -
    - -
    -

    - ... -

    -
    - - - - - -
    -
      -
    • ...
    • -
    -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/STR38-C/DoNotConfuseNarrowAndWideFunctions.md b/c/cert/src/rules/STR38-C/DoNotConfuseNarrowAndWideFunctions.md new file mode 100644 index 0000000000..063c452193 --- /dev/null +++ b/c/cert/src/rules/STR38-C/DoNotConfuseNarrowAndWideFunctions.md @@ -0,0 +1,138 @@ +# STR38-C: Do not confuse narrow and wide character strings and functions + +This query implements the CERT-C rule STR38-C: + +> Do not confuse narrow and wide character strings and functions + + +## Description + +Passing narrow string arguments to wide string functions or wide string arguments to narrow string functions can lead to [unexpected](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-unexpectedbehavior) and [undefined behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior). Scaling problems are likely because of the difference in size between wide and narrow characters. (See [ARR39-C. Do not add or subtract a scaled integer to a pointer.)](https://wiki.sei.cmu.edu/confluence/display/c/ARR39-C.+Do+not+add+or+subtract+a+scaled+integer+to+a+pointer) Because wide strings are terminated by a null wide character and can contain null bytes, determining the length is also problematic. + +Because `wchar_t` and `char` are distinct types, many compilers will produce a warning diagnostic if an inappropriate function is used. (See [MSC00-C. Compile cleanly at high warning levels](https://wiki.sei.cmu.edu/confluence/display/c/MSC00-C.+Compile+cleanly+at+high+warning+levels).) + +## Noncompliant Code Example (Wide Strings with Narrow String Functions) + +This noncompliant code example incorrectly uses the `strncpy()` function in an attempt to copy up to 10 wide characters. However, because wide characters can contain null bytes, the copy operation may end earlier than anticipated, resulting in the truncation of the wide string. + +```cpp +#include +#include + +void func(void) { + wchar_t wide_str1[] = L"0123456789"; + wchar_t wide_str2[] = L"0000000000"; + + strncpy(wide_str2, wide_str1, 10); +} +``` + +## Noncompliant Code Example (Narrow Strings with Wide String Functions) + +This noncompliant code example incorrectly invokes the `wcsncpy()` function to copy up to 10 wide characters from `narrow_str1` to `narrow_str2`. Because `narrow_str2` is a narrow string, it has insufficient memory to store the result of the copy and the copy will result in a buffer overflow. + +```cpp +#include + +void func(void) { + char narrow_str1[] = "01234567890123456789"; + char narrow_str2[] = "0000000000"; + + wcsncpy(narrow_str2, narrow_str1, 10); +} +``` + +## Compliant Solution + +This compliant solution uses the proper-width functions. Using `wcsncpy()` for wide character strings and `strncpy()` for narrow character strings ensures that data is not truncated and buffer overflow does not occur. + +```cpp +#include +#include + +void func(void) { + wchar_t wide_str1[] = L"0123456789"; + wchar_t wide_str2[] = L"0000000000"; + /* Use of proper-width function */ + wcsncpy(wide_str2, wide_str1, 10); + + char narrow_str1[] = "0123456789"; + char narrow_str2[] = "0000000000"; + /* Use of proper-width function */ + strncpy(narrow_str2, narrow_str1, 10); +} +``` + +## Noncompliant Code Example (strlen()) + +In this noncompliant code example, the `strlen()` function is used to determine the size of a wide character string: + +```cpp +#include +#include + +void func(void) { + wchar_t wide_str1[] = L"0123456789"; + wchar_t *wide_str2 = (wchar_t*)malloc(strlen(wide_str1) + 1); + if (wide_str2 == NULL) { + /* Handle error */ + } + /* ... */ + free(wide_str2); + wide_str2 = NULL; +} +``` +The `strlen()` function determines the number of characters that precede the terminating null character. However, wide characters can contain null bytes, particularly when expressing characters from the ASCII character set, as in this example. As a result, the `strlen()` function will return the number of bytes preceding the first null byte in the wide string. + +## Compliant Solution + +This compliant solution correctly calculates the number of bytes required to contain a copy of the wide string, including the terminating null wide character: + +```cpp +#include +#include +  +void func(void) { + wchar_t wide_str1[] = L"0123456789"; + wchar_t *wide_str2 = (wchar_t *)malloc( + (wcslen(wide_str1) + 1) * sizeof(wchar_t)); + if (wide_str2 == NULL) { + /* Handle error */ + } + /* ... */ + + free(wide_str2); + wide_str2 = NULL; +} +``` + +## Risk Assessment + +Confusing narrow and wide character strings can result in buffer overflows, data truncation, and other defects. + +
    Rule Severity Likelihood Remediation Cost Priority Level
    STR38-C High Likely Low P27 L1
    + + +## Automated Detection + +Modern compilers recognize the difference between a `char *` and a `wchar_t *`, so compiling code that violates this rule will generate warnings. It is feasible to have automated software that recognizes functions of improper width and replaces them with functions of proper width (that is, software that uses `wcsncpy()` when it recognizes that the parameters are of type `wchar_t *`). + +
    Tool Version Checker Description
    Astrée 22.04 wide-narrow-string-cast wide-narrow-string-cast-implicit Partially checked
    Axivion Bauhaus Suite 7.2.0 CertC-STR38 Fully implemented
    Clang 3.9 -Wincompatible-pointer-types
    CodeSonar 7.0p0 LANG.MEM.BO LANG.MEM.TBA Buffer Overrun Tainted Buffer Access
    Coverity 2017.07 PW Implemented
    Helix QAC 2022.2 C0432 C++0403
    Klocwork 2022.2 MISRA.ETYPE.ASSIGN.2012
    Parasoft C/C++test 2022.1 CERT_C-STR38-a Do not confuse narrow and wide character strings and functions
    PC-lint Plus 1.4 2454, 2480, 2481 Partially supported: reports illegal conversions involving pointers to char or wchar_t as well as byte/wide-oriented stream inconsistencies
    Polyspace Bug Finder R2022a CERT C: Rule STR38-C Checks for misuse of narrow or wide character string (rule fully covered)
    PRQA QA-C 9.7 0432
    PRQA QA-C++ 4.4 0403
    RuleChecker 22.04 wide-narrow-string-cast wide-narrow-string-cast-implicit Partially checked
    TrustInSoft Analyzer 1.38 pointer arithmetic Partially verified.
    + + +## Related Vulnerabilities + +Search for vulnerabilities resulting from the violation of this rule on the [CERT website](https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+STR38-C). + +## Bibliography + +
    \[ ISO/IEC 9899:2011 \] 7.24.2.4, "The strncpy Function" 7.29.4.2.2, "The wcsncpy Function"
    + + +## Implementation notes + +None + +## References + +* CERT-C: [STR38-C: Do not confuse narrow and wide character strings and functions](https://wiki.sei.cmu.edu/confluence/display/c) diff --git a/c/cert/src/rules/STR38-C/DoNotConfuseNarrowAndWideFunctions.qhelp b/c/cert/src/rules/STR38-C/DoNotConfuseNarrowAndWideFunctions.qhelp deleted file mode 100644 index 194c2526b3..0000000000 --- a/c/cert/src/rules/STR38-C/DoNotConfuseNarrowAndWideFunctions.qhelp +++ /dev/null @@ -1,18 +0,0 @@ - - - - -

    This query implements the CERT-C rule STR38-C:

    -
    -

    Do not confuse narrow and wide character strings and functions

    -
    -
    - - -
  • - CERT-C: - STR38-C: Do not confuse narrow and wide character strings and functions - . -
  • -
    -
    \ No newline at end of file diff --git a/c/cert/src/rules/STR38-C/standard-example.c b/c/cert/src/rules/STR38-C/standard-example.c deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/c/cert/test/qlpack.yml b/c/cert/test/qlpack.yml index ca1c02a93f..f07c68d211 100644 --- a/c/cert/test/qlpack.yml +++ b/c/cert/test/qlpack.yml @@ -1,4 +1,4 @@ name: cert-c-coding-standards-tests -version: 2.5.0 +version: 2.6.0-dev libraryPathDependencies: cert-c-coding-standards extractor: cpp \ No newline at end of file diff --git a/c/common/src/qlpack.yml b/c/common/src/qlpack.yml index 8a350ed757..c875247efe 100644 --- a/c/common/src/qlpack.yml +++ b/c/common/src/qlpack.yml @@ -1,3 +1,3 @@ name: common-c-coding-standards -version: 2.5.0 +version: 2.6.0-dev libraryPathDependencies: common-cpp-coding-standards diff --git a/c/common/test/includes/standard-library/LICENSE b/c/common/test/includes/standard-library/LICENSE new file mode 100644 index 0000000000..5ff71b5f5a --- /dev/null +++ b/c/common/test/includes/standard-library/LICENSE @@ -0,0 +1,193 @@ +musl as a whole is licensed under the following standard MIT license: + +---------------------------------------------------------------------- +Copyright © 2005-2020 Rich Felker, et al. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +---------------------------------------------------------------------- + +Authors/contributors include: + +A. Wilcox +Ada Worcester +Alex Dowad +Alex Suykov +Alexander Monakov +Andre McCurdy +Andrew Kelley +Anthony G. Basile +Aric Belsito +Arvid Picciani +Bartosz Brachaczek +Benjamin Peterson +Bobby Bingham +Boris Brezillon +Brent Cook +Chris Spiegel +Clément Vasseur +Daniel Micay +Daniel Sabogal +Daurnimator +David Carlier +David Edelsohn +Denys Vlasenko +Dmitry Ivanov +Dmitry V. Levin +Drew DeVault +Emil Renner Berthing +Fangrui Song +Felix Fietkau +Felix Janda +Gianluca Anzolin +Hauke Mehrtens +He X +Hiltjo Posthuma +Isaac Dunham +Jaydeep Patil +Jens Gustedt +Jeremy Huntwork +Jo-Philipp Wich +Joakim Sindholt +John Spencer +Julien Ramseier +Justin Cormack +Kaarle Ritvanen +Khem Raj +Kylie McClain +Leah Neukirchen +Luca Barbato +Luka Perkov +M Farkas-Dyck (Strake) +Mahesh Bodapati +Markus Wichmann +Masanori Ogino +Michael Clark +Michael Forney +Mikhail Kremnyov +Natanael Copa +Nicholas J. Kain +orc +Pascal Cuoq +Patrick Oppenlander +Petr Hosek +Petr Skocik +Pierre Carrier +Reini Urban +Rich Felker +Richard Pennington +Ryan Fairfax +Samuel Holland +Segev Finer +Shiz +sin +Solar Designer +Stefan Kristiansson +Stefan O'Rear +Szabolcs Nagy +Timo Teräs +Trutz Behn +Valentin Ochs +Will Dietz +William Haddon +William Pitcock + +Portions of this software are derived from third-party works licensed +under terms compatible with the above MIT license: + +The TRE regular expression implementation (src/regex/reg* and +src/regex/tre*) is Copyright © 2001-2008 Ville Laurikari and licensed +under a 2-clause BSD license (license text in the source files). The +included version has been heavily modified by Rich Felker in 2012, in +the interests of size, simplicity, and namespace cleanliness. + +Much of the math library code (src/math/* and src/complex/*) is +Copyright © 1993,2004 Sun Microsystems or +Copyright © 2003-2011 David Schultz or +Copyright © 2003-2009 Steven G. Kargl or +Copyright © 2003-2009 Bruce D. Evans or +Copyright © 2008 Stephen L. Moshier or +Copyright © 2017-2018 Arm Limited +and labelled as such in comments in the individual source files. All +have been licensed under extremely permissive terms. + +The ARM memcpy code (src/string/arm/memcpy.S) is Copyright © 2008 +The Android Open Source Project and is licensed under a two-clause BSD +license. It was taken from Bionic libc, used on Android. + +The AArch64 memcpy and memset code (src/string/aarch64/*) are +Copyright © 1999-2019, Arm Limited. + +The implementation of DES for crypt (src/crypt/crypt_des.c) is +Copyright © 1994 David Burren. It is licensed under a BSD license. + +The implementation of blowfish crypt (src/crypt/crypt_blowfish.c) was +originally written by Solar Designer and placed into the public +domain. The code also comes with a fallback permissive license for use +in jurisdictions that may not recognize the public domain. + +The smoothsort implementation (src/stdlib/qsort.c) is Copyright © 2011 +Valentin Ochs and is licensed under an MIT-style license. + +The x86_64 port was written by Nicholas J. Kain and is licensed under +the standard MIT terms. + +The mips and microblaze ports were originally written by Richard +Pennington for use in the ellcc project. The original code was adapted +by Rich Felker for build system and code conventions during upstream +integration. It is licensed under the standard MIT terms. + +The mips64 port was contributed by Imagination Technologies and is +licensed under the standard MIT terms. + +The powerpc port was also originally written by Richard Pennington, +and later supplemented and integrated by John Spencer. It is licensed +under the standard MIT terms. + +All other files which have no copyright comments are original works +produced specifically for use as part of this library, written either +by Rich Felker, the main author of the library, or by one or more +contibutors listed above. Details on authorship of individual files +can be found in the git version control history of the project. The +omission of copyright and license comments in each file is in the +interest of source tree size. + +In addition, permission is hereby granted for all public header files +(include/* and arch/*/bits/*) and crt files intended to be linked into +applications (crt/*, ldso/dlstart.c, and arch/*/crt_arch.h) to omit +the copyright notice and permission notice otherwise required by the +license, and to use these files without any requirement of +attribution. These files include substantial contributions from: + +Bobby Bingham +John Spencer +Nicholas J. Kain +Rich Felker +Richard Pennington +Stefan Kristiansson +Szabolcs Nagy + +all of whom have explicitly granted such permission. + +This file previously contained text expressing a belief that most of +the files covered by the above exception were sufficiently trivial not +to be subject to copyright, resulting in confusion over whether it +negated the permissions granted in the license. In the spirit of +permissive licensing, and of not having licensing issues being an +obstacle to adoption, that text has been removed. \ No newline at end of file diff --git a/c/common/test/qlpack.yml b/c/common/test/qlpack.yml index 39adb5dad3..8dac78eb7c 100644 --- a/c/common/test/qlpack.yml +++ b/c/common/test/qlpack.yml @@ -1,4 +1,4 @@ name: common-c-coding-standards-tests -version: 2.5.0 +version: 2.6.0-dev libraryPathDependencies: common-c-coding-standards extractor: cpp diff --git a/c/misra/src/qlpack.yml b/c/misra/src/qlpack.yml index 3f2b21007a..58fcca96e0 100644 --- a/c/misra/src/qlpack.yml +++ b/c/misra/src/qlpack.yml @@ -1,4 +1,4 @@ name: misra-c-coding-standards -version: 2.5.0 +version: 2.6.0-dev suites: codeql-suites libraryPathDependencies: common-c-coding-standards diff --git a/c/misra/src/rules/DIR-4-5/standard-example.cpp b/c/misra/src/rules/DIR-4-5/standard-example.cpp deleted file mode 100644 index aaaa1de8cf..0000000000 --- a/c/misra/src/rules/DIR-4-5/standard-example.cpp +++ /dev/null @@ -1,18 +0,0 @@ -int32_t id1_a_b_c; -int32_t id1_abc; // Non-compliant -int32_t id2_abc; // Non-compliant -int32_t id2_ABC; // Non-compliant -int32_t id3_a_bc; -int32_t id3_ab_c; // Non-compliant -int32_t id4_a_bc; -int32_t id4_ab_c; // Non-compliant -int32_t id5_ii; -int32_t id5_11; // Non-compliant -int32_t id6_i0; -int32_t id6_1O; // Non-compliant -int32_t id7_in; -int32_t id7_1h; // Non-compliant -int32_t id8_Z5; -int32_t id8_2S; // Non-compliant -int32_t id9_ZS; -int32_t id9_25; // Non-compliant \ No newline at end of file diff --git a/c/misra/src/rules/RULE-11-1/standard-example.c b/c/misra/src/rules/RULE-11-1/standard-example.c deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/c/misra/src/rules/RULE-11-2/standard-example.c b/c/misra/src/rules/RULE-11-2/standard-example.c deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/c/misra/src/rules/RULE-11-3/standard-example.c b/c/misra/src/rules/RULE-11-3/standard-example.c deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/c/misra/src/rules/RULE-11-4/standard-example.c b/c/misra/src/rules/RULE-11-4/standard-example.c deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/c/misra/src/rules/RULE-11-5/standard-example.c b/c/misra/src/rules/RULE-11-5/standard-example.c deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/c/misra/src/rules/RULE-11-6/standard-example.c b/c/misra/src/rules/RULE-11-6/standard-example.c deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/c/misra/src/rules/RULE-11-7/standard-example.c b/c/misra/src/rules/RULE-11-7/standard-example.c deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/c/misra/src/rules/RULE-11-8/standard-example.c b/c/misra/src/rules/RULE-11-8/standard-example.c deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/c/misra/src/rules/RULE-11-9/standard-example.c b/c/misra/src/rules/RULE-11-9/standard-example.c deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/c/misra/src/rules/RULE-12-1/standard-example.c b/c/misra/src/rules/RULE-12-1/standard-example.c deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/c/misra/src/rules/RULE-13-1/standard-example.c b/c/misra/src/rules/RULE-13-1/standard-example.c deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/c/misra/src/rules/RULE-13-3/standard-example.c b/c/misra/src/rules/RULE-13-3/standard-example.c deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/c/misra/src/rules/RULE-13-4/standard-example.c b/c/misra/src/rules/RULE-13-4/standard-example.c deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/c/misra/src/rules/RULE-13-5/standard-example.c b/c/misra/src/rules/RULE-13-5/standard-example.c deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/c/misra/src/rules/RULE-13-6/standard-example.c b/c/misra/src/rules/RULE-13-6/standard-example.c deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/c/misra/src/rules/RULE-17-8/standard-example.c b/c/misra/src/rules/RULE-17-8/standard-example.c deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/c/misra/src/rules/RULE-18-1/standard-example.c b/c/misra/src/rules/RULE-18-1/standard-example.c deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/c/misra/src/rules/RULE-18-2/standard-example.c b/c/misra/src/rules/RULE-18-2/standard-example.c deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/c/misra/src/rules/RULE-18-3/standard-example.c b/c/misra/src/rules/RULE-18-3/standard-example.c deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/c/misra/src/rules/RULE-18-4/standard-example.c b/c/misra/src/rules/RULE-18-4/standard-example.c deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/c/misra/src/rules/RULE-18-5/standard-example.c b/c/misra/src/rules/RULE-18-5/standard-example.c deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/c/misra/src/rules/RULE-18-6/standard-example.c b/c/misra/src/rules/RULE-18-6/standard-example.c deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/c/misra/src/rules/RULE-20-1/standard-example.c b/c/misra/src/rules/RULE-20-1/standard-example.c deleted file mode 100644 index b52af7fb03..0000000000 --- a/c/misra/src/rules/RULE-20-1/standard-example.c +++ /dev/null @@ -1,5 +0,0 @@ -#define F1_MACRO -#include "f1.h" /* Compliant */ -#include "f2.h" /* Compliant */ -int32_t i = 0; -#include "f3.h" /* Non-compliant */ \ No newline at end of file diff --git a/c/misra/src/rules/RULE-20-11/standard-example.c b/c/misra/src/rules/RULE-20-11/standard-example.c deleted file mode 100644 index 97d0f68bad..0000000000 --- a/c/misra/src/rules/RULE-20-11/standard-example.c +++ /dev/null @@ -1,3 +0,0 @@ -#define A(x) #x /* Compliant */ -#define B(x, y) x##y /* Compliant */ -#define C(x, y) #x##y /* Non-compliant */ \ No newline at end of file diff --git a/c/misra/src/rules/RULE-20-12/standard-example.c b/c/misra/src/rules/RULE-20-12/standard-example.c deleted file mode 100644 index bcfaea6e28..0000000000 --- a/c/misra/src/rules/RULE-20-12/standard-example.c +++ /dev/null @@ -1,7 +0,0 @@ -#define AA 0xffff -#define BB(x) (x) + wow##x /* Non-compliant */ -void f(void) { - int32_t wowAA = 0; - /* Expands as wowAA = ( 0xffff ) + wowAA; */ - wowAA = BB(AA); -} \ No newline at end of file diff --git a/c/misra/src/rules/RULE-20-2/standard-example.c b/c/misra/src/rules/RULE-20-2/standard-example.c deleted file mode 100644 index cfccf247a7..0000000000 --- a/c/misra/src/rules/RULE-20-2/standard-example.c +++ /dev/null @@ -1 +0,0 @@ -#include "fi'le.h" /* Non-compliant */ \ No newline at end of file diff --git a/c/misra/src/rules/RULE-20-5/standard-example.c b/c/misra/src/rules/RULE-20-5/standard-example.c deleted file mode 100644 index ad77838996..0000000000 --- a/c/misra/src/rules/RULE-20-5/standard-example.c +++ /dev/null @@ -1,7 +0,0 @@ -#define QUALIFIER volatile -#undef QUALIFIER /* Non-compliant */ -void f(QUALIFIER int32_t p) { - while (p != 0) { - ; /* Wait... */ - } -} \ No newline at end of file diff --git a/c/misra/src/rules/RULE-20-8/standard-example.c b/c/misra/src/rules/RULE-20-8/standard-example.c deleted file mode 100644 index 21ad139e39..0000000000 --- a/c/misra/src/rules/RULE-20-8/standard-example.c +++ /dev/null @@ -1,11 +0,0 @@ -#define FALSE 0 -#define TRUE 1 -#if FALSE /* Compliant */ -#endif -#if 10 /* Non-compliant */ -#endif -#if !defined(X) /* Compliant */ -#endif - -#if A > B /* Compliant assuming A and B are numeric */ -#endif \ No newline at end of file diff --git a/c/misra/src/rules/RULE-20-9/standard-example.c b/c/misra/src/rules/RULE-20-9/standard-example.c deleted file mode 100644 index 9ecd802b4c..0000000000 --- a/c/misra/src/rules/RULE-20-9/standard-example.c +++ /dev/null @@ -1,11 +0,0 @@ -#if M == 0 /* Non-compliant */ -/* Does 'M' expand to zero or is it undefined? */ -#endif -#if defined(M) /* Compliant - M is not evaluated */ -#if M == 0 /* Compliant - M is known to be defined */ -/* 'M' must expand to zero. */ -#endif -#endif -/* Compliant - B is only evaluated in ( B == 0 ) if it is defined */ -#if defined(B) && (B == 0) -#endif \ No newline at end of file diff --git a/c/misra/src/rules/RULE-22-3/standard-example.c b/c/misra/src/rules/RULE-22-3/standard-example.c deleted file mode 100644 index 757aa27115..0000000000 --- a/c/misra/src/rules/RULE-22-3/standard-example.c +++ /dev/null @@ -1,5 +0,0 @@ -#include -void fn(void) { - FILE *fw = fopen("tmp", "r+"); /* "r+" opens for read/write */ - FILE *fr = fopen("tmp", "r"); /* Non-compliant */ -} \ No newline at end of file diff --git a/c/misra/src/rules/RULE-22-4/standard-example.c b/c/misra/src/rules/RULE-22-4/standard-example.c deleted file mode 100644 index 1b5a2d9423..0000000000 --- a/c/misra/src/rules/RULE-22-4/standard-example.c +++ /dev/null @@ -1,6 +0,0 @@ -#include -void fn(void) { - FILE *fp = fopen("tmp", "r"); - (void)fprintf(fp, "What happens now?"); /* Non-compliant */ - (void)fclose(fp); -} \ No newline at end of file diff --git a/c/misra/src/rules/RULE-22-5/standard-example.c b/c/misra/src/rules/RULE-22-5/standard-example.c deleted file mode 100644 index a9a110ec5a..0000000000 --- a/c/misra/src/rules/RULE-22-5/standard-example.c +++ /dev/null @@ -1,8 +0,0 @@ -#include - -FILE *pf1; -FILE *pf2; -FILE f3; - -pf2 = pf1; /* Compliant */ -f3 = *pf2; /* Non-compliant */ diff --git a/c/misra/src/rules/RULE-22-6/standard-example.c b/c/misra/src/rules/RULE-22-6/standard-example.c deleted file mode 100644 index 8c3766ac9c..0000000000 --- a/c/misra/src/rules/RULE-22-6/standard-example.c +++ /dev/null @@ -1,15 +0,0 @@ -#include - -void fn(void) { - FILE *fp; - FILE *p; - - fp = fopen("tmp", "w"); - if (fp == NULL) { - error_action(); - } - fclose(fp); - - fprintf(fp, "?"); /* Non-compliant */ - p = fp; /* Non-compliant */ -} \ No newline at end of file diff --git a/c/misra/src/rules/RULE-22-7/standard-example1.c b/c/misra/src/rules/RULE-22-7/standard-example1.c deleted file mode 100644 index 5bfcfe840d..0000000000 --- a/c/misra/src/rules/RULE-22-7/standard-example1.c +++ /dev/null @@ -1,10 +0,0 @@ -void f1(void) { - char ch; - ch = (char)getchar(); - /* - * The following test is non-compliant. It will not be reliable as the - * return value is cast to a narrower type before checking for EOF. - */ - if (EOF != (int32_t)ch) { - } -} \ No newline at end of file diff --git a/c/misra/src/rules/RULE-22-7/standard-example2.c b/c/misra/src/rules/RULE-22-7/standard-example2.c deleted file mode 100644 index 8a0505b8ca..0000000000 --- a/c/misra/src/rules/RULE-22-7/standard-example2.c +++ /dev/null @@ -1,19 +0,0 @@ -void f2(void) { - char ch; - ch = (char)getchar(); - if (!feof(stdin)) { - } -} - -void f3(void) { - int32_t i_ch; - i_ch = getchar(); - /* - * The following test is compliant. It will be reliable as the - * unconverted return value is used when checking for EOF. - */ - if (EOF != i_ch) { - char ch; - ch = (char)i_ch; - } -} \ No newline at end of file diff --git a/c/misra/src/rules/RULE-4-10/standard-example.c b/c/misra/src/rules/RULE-4-10/standard-example.c deleted file mode 100644 index 65b8a2685d..0000000000 --- a/c/misra/src/rules/RULE-4-10/standard-example.c +++ /dev/null @@ -1,12 +0,0 @@ - -#if !defined ( identifier ) -#define identifier -/* Contents of file */ -#endif - - -#ifndef identifier -#define identifier -/* Contents of file */ -#endif - \ No newline at end of file diff --git a/c/misra/src/rules/RULE-4-8/standard-example.c b/c/misra/src/rules/RULE-4-8/standard-example.c deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/c/misra/src/rules/RULE-8-13/standard-example.c b/c/misra/src/rules/RULE-8-13/standard-example.c deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/c/misra/test/qlpack.yml b/c/misra/test/qlpack.yml index 2a121f8a63..e278dfbe3d 100644 --- a/c/misra/test/qlpack.yml +++ b/c/misra/test/qlpack.yml @@ -1,4 +1,4 @@ name: misra-c-coding-standards-tests -version: 2.5.0 +version: 2.6.0-dev libraryPathDependencies: misra-c-coding-standards extractor: cpp \ No newline at end of file diff --git a/change_notes/2021-10-26-enable-lifetime-profile.md b/change_notes/2021-10-26-enable-lifetime-profile.md new file mode 100644 index 0000000000..11c3bb3b90 --- /dev/null +++ b/change_notes/2021-10-26-enable-lifetime-profile.md @@ -0,0 +1,2 @@ + - `A3-8-1`, `A5-3-2`, `EXP54-CPP`, `STR51-CPP` + - All queries for these rules are now enabled by default. They previously disabled due to performance concerns. diff --git a/change_notes/2022-03-04-address-fp-m7-3-4.md b/change_notes/2022-03-04-address-fp-m7-3-4.md new file mode 100644 index 0000000000..5339f0b950 --- /dev/null +++ b/change_notes/2022-03-04-address-fp-m7-3-4.md @@ -0,0 +1 @@ +- Address a false positive flagged by `cpp/autosar/using-directives-used` for anonymous namespaces. \ No newline at end of file diff --git a/change_notes/2022-03-16-fix-placeholders.md b/change_notes/2022-03-16-fix-placeholders.md new file mode 100644 index 0000000000..9ba3f1856a --- /dev/null +++ b/change_notes/2022-03-16-fix-placeholders.md @@ -0,0 +1,4 @@ +- `A10-2-1` - `NonVirtualPublicOrProtectedFunctionsRedefinedQuery`: + - Fixed a typo that caused the derived class not to be displayed in the alert message +- `A10-3-3` - `VirtualFunctionsIntroducedInFinalClassQuery` + - Fixed a typo that caused the introducing class not to be displayed in the alert message diff --git a/change_notes/2022-03-18 b/change_notes/2022-03-18 new file mode 100644 index 0000000000..f458830472 --- /dev/null +++ b/change_notes/2022-03-18 @@ -0,0 +1 @@ +- Update the `create_release.sh` script to include query artifacts with Markdown help files diff --git a/change_notes/2022-03-18-address-fp-A3-3-1.md b/change_notes/2022-03-18-address-fp-A3-3-1.md new file mode 100644 index 0000000000..03c6f2cf02 --- /dev/null +++ b/change_notes/2022-03-18-address-fp-A3-3-1.md @@ -0,0 +1 @@ +- Address a false positive flagged by `cpp/autosar/external-linkage-not-declared-in-header-file` for declarations that actually were in header files \ No newline at end of file diff --git a/change_notes/2022-06-24-use-variable-entry-type-in-M3-2-1.md b/change_notes/2022-06-24-use-variable-entry-type-in-M3-2-1.md new file mode 100644 index 0000000000..ef66fcc459 --- /dev/null +++ b/change_notes/2022-06-24-use-variable-entry-type-in-M3-2-1.md @@ -0,0 +1,2 @@ +- `M3-2-1` - `DeclarationsOfAnObjectShallHaveCompatibleTypes.ql` + - Use the type of the variable declaration entries instead of the variables, as variables may exist that have multiple entries with different types. \ No newline at end of file diff --git a/cpp/autosar/src/qlpack.yml b/cpp/autosar/src/qlpack.yml index 5dc89f303b..9f3aa642fd 100644 --- a/cpp/autosar/src/qlpack.yml +++ b/cpp/autosar/src/qlpack.yml @@ -1,4 +1,4 @@ name: autosar-cpp-coding-standards -version: 2.5.0 +version: 2.6.0-dev suites: codeql-suites libraryPathDependencies: common-cpp-coding-standards diff --git a/cpp/autosar/src/rules/A0-1-1/standard-example.cpp b/cpp/autosar/src/rules/A0-1-1/standard-example.cpp deleted file mode 100644 index 5fb4373bdf..0000000000 --- a/cpp/autosar/src/rules/A0-1-1/standard-example.cpp +++ /dev/null @@ -1,57 +0,0 @@ -//% $Id: A0-1-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -#include -#include -std::uint8_t Fn1(std::uint8_t param) noexcept { - std::int32_t x{0}; // Non-compliant - DU data flow anomaly; Variable defined, - // but not used - if (param > 0) { - return 1; - } else { - return 0; - } -} -std::int32_t Fn2() noexcept { - std::int8_t x{10U}; // Compliant - variable defined and will be used - std::int8_t y{20U}; // Compliant - variable defined and will be used - std::int16_t result = x + y; // x and y variables used - x = 0; // Non-compliant - DU data flow anomaly; Variable defined, but x is - // not subsequently used and goes out of scope - y = 0; // Non-compliant - DU data flow anomaly; Variable defined, but y is - // not subsequently used and goes out of scope - return result; -} -std::int32_t Fn3(std::int32_t param) noexcept { - std::int32_t x{param + 1}; // Compliant - variable defined, and will be used - // in one of the branches - if (param > 20) - // However, scope of x variable could be reduced - { - return x; - } - return 0; -} -std::int32_t Fn4(std::int32_t param) noexcept { - std::int32_t x{param + 1}; // Compliant - variable defined, and will be used - // in some of the branches - if (param > 20) { - return x + 1; - } else if (param > 10) { - return x; - } else { - return 0; - } -} -void Fn5() noexcept { - std::array arr{}; - arr.fill(1); - constexpr std::uint8_t limit{100U}; - std::int8_t x{0}; - for (std::uint8_t i{0U}; i < limit; ++i) // Compliant by exception - on the - // final loop, value of i defined will - // not be used - { - arr[i] = arr[x]; - ++x; // Non-compliant - DU data flow anomaly on the final loop, value - // defined and not used - } -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A0-1-2/standard-example.cpp b/cpp/autosar/src/rules/A0-1-2/standard-example.cpp deleted file mode 100644 index 76828d1ea6..0000000000 --- a/cpp/autosar/src/rules/A0-1-2/standard-example.cpp +++ /dev/null @@ -1,15 +0,0 @@ -// $Id: A0-1-2.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -#include -#include -#include -std::uint8_t Fn1() noexcept { return 0U; } -void Fn2() noexcept { - std::uint8_t x = Fn1(); // Compliant - Fn1(); // Non-compliant - static_cast(Fn1()); // Compliant by exception -} -void Fn3() { - std::vector v{0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5}; - std::unique(v.begin(), v.end()); // Non-compliant - v.erase(std::unique(v.begin(), v.end()), v.end()); // Compliant -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A0-1-3/standard-example.cpp b/cpp/autosar/src/rules/A0-1-3/standard-example.cpp deleted file mode 100644 index 7b4e934dc7..0000000000 --- a/cpp/autosar/src/rules/A0-1-3/standard-example.cpp +++ /dev/null @@ -1,43 +0,0 @@ -//% $Id: A0-1-3.cpp 291350 2017-10-17 14:31:34Z jan.babst $ -#include -static void F1() // Compliant -{} -namespace { -void F2() // Non-compliant, defined function never used -{} -} // namespace -class C { -public: - C() : x(0) {} - void M1(std::int32_t i) // Compliant, member function is used - { - x = i; - } - void M2(std::int32_t i, - std::int32_t j) // Compliant, never used but declared - { - // as public - x = (i > j) ? i : j; - } - -protected: - void M1ProtectedImpl(std::int32_t j) // Compliant, never used but declared - // as protected - { - x = j; - } - -private: - std::int32_t x; - void M1PrivateImpl( - std::int32_t j) // Non-compliant, private member function never used - { - x = j; - } -}; -int main(int, char **) { - F1(); - C c; - c.M1(1); - return 0; -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A0-1-4/standard-example.cpp b/cpp/autosar/src/rules/A0-1-4/standard-example.cpp deleted file mode 100644 index 53d5822247..0000000000 --- a/cpp/autosar/src/rules/A0-1-4/standard-example.cpp +++ /dev/null @@ -1,48 +0,0 @@ -//% $Id: A0-1-4.cpp 305588 2018-01-29 11:07:35Z michal.szczepankiewicz $ -#include -#include -// Logger.hpp -class Logger { -public: - struct console_t {}; - struct file_t {}; - constexpr static console_t console = console_t(); - constexpr static file_t file = file_t(); - void init(console_t); - void init(file_t, const std::string &prefix); -}; -// Logger.cpp -void Logger::init(console_t) { - // initialization for a console logger -} -void Logger::init(file_t, const std::string &prefix) { - // initialization for a file logger for a given prefix path -} -// Message.h -struct MessagePolicy {}; -struct WriteMessagePolicy final : public MessagePolicy {}; -template struct is_mutable : std::false_type {}; -template <> struct is_mutable : std::true_type {}; -template class Message { -public: - static_assert(std::is_base_of::value == true, "Given -parameter is not derived from MessagePolicy"); -using value_type = T; -template -void set(T&& u, typename std::enable_if::value, U>::type* -= 0) { - v = u; } - private: - value_type v; -}; - -int main(int, char **) { - Logger log; - log.init(Logger::console); - log.init(Logger::file, std::string("/tmp/")); - Message read; - Message write; - // read.set(uint8_t(12)); Compilation error - write.set(uint8_t(12)); - return 0; -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A0-1-5/standard-example.cpp b/cpp/autosar/src/rules/A0-1-5/standard-example.cpp deleted file mode 100644 index 8dda133a42..0000000000 --- a/cpp/autosar/src/rules/A0-1-5/standard-example.cpp +++ /dev/null @@ -1,42 +0,0 @@ -//% $Id: A0-1-5.cpp 305588 2018-01-29 11:07:35Z michal.szczepankiewicz $ -#include -#include -// Compressor.h -class Compressor { -public: - using raw_memory_type = std::vector; - raw_memory_type Compress(const raw_memory_type &in, uint8_t ratio); - -private: - virtual raw_memory_type __Compress(const raw_memory_type &in, - uint8_t ratio) = 0; -}; -// Compressor.cpp -Compressor::raw_memory_type Compressor::Compress(const raw_memory_type &in, - uint8_t ratio) { - return __Compress(in, ratio); -} -// JPEGCompressor.h -class JPEGCompressor : public Compressor { -private: - raw_memory_type __Compress(const raw_memory_type &in, uint8_t ratio) override; -}; -// JPEGCompressor.cpp -JPEGCompressor::raw_memory_type -JPEGCompressor::__Compress(const raw_memory_type &in, uint8_t ratio) { - raw_memory_type ret; - // jpeg compression, ratio used - return ret; -} -// HuffmanCompressor.h -class HuffmanCompressor : public Compressor { -private: - raw_memory_type __Compress(const raw_memory_type &in, uint8_t) override; -}; -// JPEGCompressor.cpp -HuffmanCompressor::raw_memory_type -HuffmanCompressor::__Compress(const raw_memory_type &in, uint8_t) { - raw_memory_type ret; - // Huffman compression, no ratio parameter available in the algorithm - return ret; -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A0-1-6/standard-example.cpp b/cpp/autosar/src/rules/A0-1-6/standard-example.cpp deleted file mode 100644 index 6bd51faaa1..0000000000 --- a/cpp/autosar/src/rules/A0-1-6/standard-example.cpp +++ /dev/null @@ -1,6 +0,0 @@ -// $Id: A0-1-6.cpp$ -#include -std::uint32_t Fn() noexcept { - using LocalUIntPtr = std::uint32_t *; - return 0U; -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A0-4-1/standard-example.cpp b/cpp/autosar/src/rules/A0-4-1/standard-example.cpp deleted file mode 100644 index 64686faa99..0000000000 --- a/cpp/autosar/src/rules/A0-4-1/standard-example.cpp +++ /dev/null @@ -1,14 +0,0 @@ -//% $Id: A0-4-1.cpp 271389 2017-03-21 14:41:05Z piotr.tanski $ -#include -static_assert( - std::numeric_limits::is_iec559, - "Type float does not comply with IEEE 754 single precision format"); -static_assert( - std::numeric_limits::digits == 24, - "Type float does not comply with IEEE 754 single precision format"); -static_assert( - std::numeric_limits::is_iec559, - "type double does not comply with IEEE 754 double precision format"); -static_assert( - std::numeric_limits::digits == 53, - "Type double does not comply with IEEE 754 double precision format"); \ No newline at end of file diff --git a/cpp/autosar/src/rules/A0-4-2/standard-example.cpp b/cpp/autosar/src/rules/A0-4-2/standard-example.cpp deleted file mode 100644 index 078709038a..0000000000 --- a/cpp/autosar/src/rules/A0-4-2/standard-example.cpp +++ /dev/null @@ -1,7 +0,0 @@ -//% $Id: A0-4-2.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -void Fn() noexcept -{ - float f1{0.1F}; // Compliant - double f2{0.1}; // Compliant - long double f3{0.1L}; // Non-compliant -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A0-4-4/standard-example.cpp b/cpp/autosar/src/rules/A0-4-4/standard-example.cpp deleted file mode 100644 index f446245d40..0000000000 --- a/cpp/autosar/src/rules/A0-4-4/standard-example.cpp +++ /dev/null @@ -1,23 +0,0 @@ -//% $Id: A0-4-4.cpp 305588 2018-01-29 11:07:35Z michal.szczepankiewicz $ - -#include -#include - -float Foo(float val) -{ - //non-compliant, domain error for negative values - return std::sqrt(val); -} -float Bar(float val) -{ - //non-compliant - //domain error for val < 0 - //pole error for val==0 - return std::log(val); -} -// \return true, if a range error occurred -bool DetectRangeErr() -{ - return ((math_errhandling & MATH_ERREXCEPT) && - (fetestexcept(FE_INEXACT | FE_OVERFLOW | FE_UNDERFLOW) != 0)); -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A1-1-1/standard-example.cpp b/cpp/autosar/src/rules/A1-1-1/standard-example.cpp deleted file mode 100644 index 643cbfec8f..0000000000 --- a/cpp/autosar/src/rules/A1-1-1/standard-example.cpp +++ /dev/null @@ -1,24 +0,0 @@ -//% $Id: A1-1-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -#include -#include -void F(std::int32_t i) -{ - std::int32_t* a = nullptr; - - // __try // Non-compliant - __try is a part of Visual Studio extension - try // Compliant - try keyword is a part of C++ Language Standard - { - a = new std::int32_t[i]; - // ... - } - - // __finally // Non-compliant - __finally is a part of Visual Studio - // extension - catch ( - std::exception&) // Compliant - C++ Language Standard does not define - // finally block, only try and catch blocks - { - delete[] a; - a = nullptr; - } -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A10-1-1/standard-example.cpp b/cpp/autosar/src/rules/A10-1-1/standard-example.cpp deleted file mode 100644 index 23bb091fa9..0000000000 --- a/cpp/autosar/src/rules/A10-1-1/standard-example.cpp +++ /dev/null @@ -1,44 +0,0 @@ -// $Id: A10-1-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -#include -class A -{ - public: - void F1() noexcept(false) {} - - private: - std::int32_t x{0}; - std::int32_t y{0}; -}; -class B -{ - public: - void F2() noexcept(false) {} - - private: - std::int32_t x{0}; -}; -class C : public A, - public B // Non-compliant - A and B are both not interface classes -{ -}; -class D { - public: - virtual ~D() = 0; - virtual void F3() noexcept = 0; - virtual void F4() noexcept = 0; -}; -class E { - public: - static constexpr std::int32_t value{10}; - - virtual ~E() = 0; - virtual void F5() noexcept = 0; -}; -class F : public A, public B, - public D, public E // Non-compliant - A and B are both not interface classes -{ -}; -class G : public A, public D, - public E // Compliant - D and E are interface classes -{ -}; \ No newline at end of file diff --git a/cpp/autosar/src/rules/A10-2-1/standard-example.cpp b/cpp/autosar/src/rules/A10-2-1/standard-example.cpp deleted file mode 100644 index 7b60759121..0000000000 --- a/cpp/autosar/src/rules/A10-2-1/standard-example.cpp +++ /dev/null @@ -1,31 +0,0 @@ -// $Id: A10-2-1.cpp 317123 2018-04-23 08:48:11Z ilya.burylov $ -class A { -public: - virtual ~A() = default; - void F() noexcept {} - virtual void G() noexcept {} - -private: - void H() noexcept {} -}; -class B : public A { -public: - void F() noexcept { - } // Non-compliant - F() function from A class hidden by B class - void G() noexcept override {} // Compliant - G() function from A class - // overridden by B class -private: - void H() noexcept {} // Compliant - H() function is private in A class -}; -class C : private A { -public: - F() noexcept {} // Compliant by exception - private inheritance -}; -void Fn1(A &object) noexcept { - object.F(); // Calls F() function from A - object.G(); // Calls G() function from B -} -void Fn2() noexcept { - B b; - Fn1(b); -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A10-3-1/standard-example.cpp b/cpp/autosar/src/rules/A10-3-1/standard-example.cpp deleted file mode 100644 index 5dc3c187d4..0000000000 --- a/cpp/autosar/src/rules/A10-3-1/standard-example.cpp +++ /dev/null @@ -1,60 +0,0 @@ -// $Id: A10-3-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -class A -{ - public: - virtual ~A() {} // Compliant - virtual void F() noexcept = 0; // Compliant - virtual void G() noexcept final = 0; // Non-compliant - virtual final pure - // function is redundant - virtual void - H() noexcept final // Non-compliant - function is virtual and final - { - } - virtual void K() noexcept // Compliant - { - } - virtual void J() noexcept {} - virtual void M() noexcept // Compliant - { - } - virtual void Z() noexcept // Compliant - { - } - virtual A& operator+=(A const& rhs) noexcept // Compliant - { - // ... - return *this; - } - }; -class B : public A -{ - public: - ~B() override {} // Compliant - virtual void F() noexcept override // Non-compliant - function is specified - // with virtual and override - { - } - void K() noexcept override - final // Non-compliant - function is specified with override and final - { - } - virtual void M() noexcept // Compliant - violates A10-3-2 - { - } - void Z() noexcept override // Compliant - { - } - void J() noexcept // Non-compliant - virtual function but not marked as - // overrider - { - } - A& operator+=(A const& rhs) noexcept override // Compliant - to override - // the operator correctly, - // its signature needs to be - // the same as in the base - // class - { - // ... - return *this; - } -}; \ No newline at end of file diff --git a/cpp/autosar/src/rules/A10-3-2/standard-example.cpp b/cpp/autosar/src/rules/A10-3-2/standard-example.cpp deleted file mode 100644 index c1ce22540a..0000000000 --- a/cpp/autosar/src/rules/A10-3-2/standard-example.cpp +++ /dev/null @@ -1,46 +0,0 @@ -// $Id: A10-3-2.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -class A -{ - public: - virtual ~A() {} - virtual void F() noexcept = 0; - virtual void G() noexcept {} - virtual void Z() noexcept {} - virtual A& operator+=(A const& oth) = 0; -}; -class B : public A -{ - public: - ~B() override {} // Compliant - void F() noexcept // Non-compliant - { - } - virtual void G() noexcept // Non-compliant - { - } - void Z() noexcept override // Compliant - { - } - B& operator+=(A const& oth) override // Compliant - { - return *this; - } -}; -class C : public A -{ - public: - ~C() {} // Non-compliant - void F() noexcept override // Compliant - { - } - void G() noexcept override // Compliant - { - } - void Z() noexcept override // Compliant - { - } - C& operator+=(A const& oth) // Non-compliant - { - return *this; - } -}; \ No newline at end of file diff --git a/cpp/autosar/src/rules/A10-3-3/standard-example.cpp b/cpp/autosar/src/rules/A10-3-3/standard-example.cpp deleted file mode 100644 index 42fa358fca..0000000000 --- a/cpp/autosar/src/rules/A10-3-3/standard-example.cpp +++ /dev/null @@ -1,22 +0,0 @@ -// $Id: A10-3-3.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -class A -{ - public: - virtual ~A() = default; - virtual void F() noexcept = 0; - virtual void G() noexcept {} - }; - class B final : public A - { - public: - void F() noexcept final // Compliant - { - } - void G() noexcept override // Non-compliant - { - } - virtual void H() noexcept = 0; // Non-compliant - virtual void Z() noexcept // Non-compliant - { - } -}; \ No newline at end of file diff --git a/cpp/autosar/src/rules/A10-3-5/standard-example.cpp b/cpp/autosar/src/rules/A10-3-5/standard-example.cpp deleted file mode 100644 index 5d6098cc26..0000000000 --- a/cpp/autosar/src/rules/A10-3-5/standard-example.cpp +++ /dev/null @@ -1,76 +0,0 @@ -// $Id: A10-3-4.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -class A -{ - public: - virtual A& operator=(A const& oth) = 0; // Non-compliant - virtual A& operator+=(A const& rhs) = 0; // Non-compliant -}; -class B : public A -{ - public: - B& operator=(A const& oth) override // It needs to take an argument of type - // A& in order to override - { - return *this; - } - B& operator+=(A const& oth) override // It needs to take an argument of - // type A& in order to override - { - return *this; - } - B& operator-=(B const& oth) // Compliant - { - return *this; - } -}; -class C : public A -{ - public: - C& operator=(A const& oth) override // It needs to take an argument of type - // A& in order to override - { - return *this; - } - C& operator+=(A const& oth) override // It needs to take an argument of - { - return *this; - } - C& operator-=(C const& oth) // Compliant - { - return *this; - } -}; -// class D : public A -//{ -// public: -//D& operator=(D const& oth) override // Compile time error - this method -//does not override because of different -// signature 50 -// { -// return *this; 52 -// } -//D& operator+=(D const& oth) override // Compile time error - this method -//does not override because of different - // signature - // { - // return *this; - // } -//}; -void Fn() noexcept -{ - B b; - C c; - b = c; // Calls B::operator= and accepts an argument of type C - b += c; // Calls B::operator+= and accepts an argument of type C - c = b; // Calls C::operator= and accepts an argument of type B - c += b; // Calls C::operator+= and accepts an argument of type B - // b -= c; // Compilation error, because of types mismatch. Expected - // behavior - // c -= b; // Compilation error, because of types mismatch. Expected - // behavior - - B b2; - C c2; - b -= b2; - c -= c2; -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A11-0-1/standard-example.cpp b/cpp/autosar/src/rules/A11-0-1/standard-example.cpp deleted file mode 100644 index bcf8d895ff..0000000000 --- a/cpp/autosar/src/rules/A11-0-1/standard-example.cpp +++ /dev/null @@ -1,50 +0,0 @@ -// $Id: A11-0-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -#include -#include -class A // Compliant - A provides user-defined constructors, invariant and - // interface -{ - std::int32_t x; // Data member is private by default - public: - static constexpr std::int32_t maxValue = - std::numeric_limits::max(); - A() : x(maxValue) {} - explicit A(std::int32_t number) : x(number) {} - A(A const&) = default; - A(A&&) = default; - A& operator=(A const&) = default; - A& operator=(A&&) = default; - - std::int32_t GetX() const noexcept { return x; } - void SetX(std::int32_t number) noexcept { x = number; } -}; -struct B // Non-compliant - non-POD type defined as struct -{ - public: - static constexpr std::int32_t maxValue = - std::numeric_limits::max(); - B() : x(maxValue) {} - explicit B(std::int32_t number) : x(number) {} - B(B const&) = default; - B(B&&) = default; - B& operator=(B const&) = default; - B& operator=(B&&) = default; - - std::int32_t GetX() const noexcept { return x; } - void SetX(std::int32_t number) noexcept { x = number; } - - private: - std::int32_t x; // Need to provide private access specifier for x member -}; -struct C // Compliant - POD type defined as struct -{ - std::int32_t x; - std::int32_t y; -}; -class D // Compliant - POD type defined as class, but not compliant with - // M11-0-1 -{ - public: - std::int32_t x; - std::int32_t y; -}; \ No newline at end of file diff --git a/cpp/autosar/src/rules/A11-0-2/standard-example.cpp b/cpp/autosar/src/rules/A11-0-2/standard-example.cpp deleted file mode 100644 index f5f8a1822a..0000000000 --- a/cpp/autosar/src/rules/A11-0-2/standard-example.cpp +++ /dev/null @@ -1,41 +0,0 @@ -// $Id: A11-0-2.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -#include -struct A // Compliant -{ - std::int32_t x; - double y; -}; -struct B // Compliant -{ - std::uint8_t x; - A a; -}; -struct C // Compliant -{ - float x = 0.0f; - std::int32_t y = 0; - std::uint8_t z = 0U; -}; -struct D // Non-compliant -{ - public: - std::int32_t x; - - protected: - std::int32_t y; - - private: - std::int32_t z; -}; -struct E // Non-compliant -{ - public: - std::int32_t x; - void Fn() noexcept {} - - private: - void F1() noexcept(false) {} -}; -struct F : public D // Non-compliant -{ -}; \ No newline at end of file diff --git a/cpp/autosar/src/rules/A11-3-1/standard-example.cpp b/cpp/autosar/src/rules/A11-3-1/standard-example.cpp deleted file mode 100644 index 0a82dbcdcc..0000000000 --- a/cpp/autosar/src/rules/A11-3-1/standard-example.cpp +++ /dev/null @@ -1,21 +0,0 @@ -// $Id: A11-3-1.cpp 325916 2018-07-13 12:26:22Z christof.meerwald $ -class A -{ - public: - A& operator+=(A const& oth); - friend A const operator+(A const& lhs, A const& rhs); // Non-compliant -}; -class B -{ - public: - B& operator+=(B const& oth); - friend bool operator ==(B const& lhs, B const& rhs) // Compliant by exception - { - // Implementation - } -}; - -B const operator+(B const& lhs, B const& rhs) // Compliant -{ - // Implementation -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A12-0-1/standard-example.cpp b/cpp/autosar/src/rules/A12-0-1/standard-example.cpp deleted file mode 100644 index d8ef03ea24..0000000000 --- a/cpp/autosar/src/rules/A12-0-1/standard-example.cpp +++ /dev/null @@ -1,109 +0,0 @@ -// $Id: A12-0-1.cpp 309769 2018-03-01 17:40:29Z jan.babst $ -#include - -namespace v1 -{ -// Class is copyable and moveable via the compiler generated funtions. -// Compliant - rule of zero. -class A -{ - private: - // Member data ... -}; -} // namespace v1 - -namespace v2 -{ -// New requirement: Destructor needs to be added. -// Now the class is no longer moveable, but still copyable. The program -// still compiles, but may perform worse. -// Non-compliant - Unclear if this was the developers intent. -class A -{ - public: - ~A() - { - // ... - } - private: - // Member data ... -}; -} // namespace v2 - -namespace v3 { -// Move operations are brought back by defaulting them. -// Copy operations are defaulted since they are no longer generated -// (complies to A12-0-1 but will also be a compiler error if they are needed). -// Default constructor is defaulted since it is no longer generated -// (not required by A12-0-1 but will be a compiler error if it is needed). -// Compliant - rule of five. Programmer’s intent is clear, class behaves the -// same as v1::A. -class A -{ - public: - A() = default; - A(A const&) = default; - A(A&&) = default; - ~A() - { - // ... - } - A& operator=(A const&) = default; - A& operator=(A&&) = default; - - private: - // Member data ... -}; -} // namespace v3 - -// A class with regular (value) semantics. -// Compliant - rule of zero. -class Simple -{ - public: - // User defined constructor, also acts as default constructor. - explicit Simple(double d = 0.0, std::string s = "Hello") - : d_(d), s_(std::move(s)) - { - } - - // Compiler generated copy c’tor, move c’tor, d’tor, copy assignment, move - // assignment. - - private: - double d_; - std::string s_; -}; - -// A base class. -// Compliant - rule of five. -class Base -{ - public: - Base(Base const&) = delete; // see also A12-8-6 - Base(Base&&) = delete; // see also A12-8-6 - virtual ~Base() = default; // see also A12-4-1 - Base& operator=(Base const&) = delete; // see also A12-8-6 - Base& operator=(Base&&) = delete; // see also A12-8-6 - - // Declarations of pure virtual functions ... - - protected: - Base() = default; // in order to allow construction of derived objects -}; - -// A move-only class. -// Compliant - rule of five. -class MoveOnly -{ - public: - MoveOnly(); - MoveOnly(MoveOnly const&) = delete; - MoveOnly(MoveOnly&&) noexcept; - ~MoveOnly(); - MoveOnly& operator=(MoveOnly const&) = delete; - MoveOnly& operator=(MoveOnly&&) noexcept; - - private: - // ... -}; \ No newline at end of file diff --git a/cpp/autosar/src/rules/A12-0-2/standard-example.cpp b/cpp/autosar/src/rules/A12-0-2/standard-example.cpp deleted file mode 100644 index ea5f26145d..0000000000 --- a/cpp/autosar/src/rules/A12-0-2/standard-example.cpp +++ /dev/null @@ -1,109 +0,0 @@ -// $Id: A12-0-1.cpp 309769 2018-03-01 17:40:29Z jan.babst $ -#include - -namespace v1 -{ - // Class is copyable and moveable via the compiler generated funtions. - // Compliant - rule of zero. - class A - { - private: - // Member data ... - }; -} // namespace v1 - -namespace v2 -{ - // New requirement: Destructor needs to be added. - // Now the class is no longer moveable, but still copyable. The program - // still compiles, but may perform worse. - // Non-compliant - Unclear if this was the developers intent. - class A - { - public: - ~A() - { - // ... - } - private: - // Member data ... - }; -} // namespace v2 - -namespace v3 { - // Move operations are brought back by defaulting them. - // Copy operations are defaulted since they are no longer generated - // (complies to A12-0-1 but will also be a compiler error if they are needed). - // Default constructor is defaulted since it is no longer generated - // (not required by A12-0-1 but will be a compiler error if it is needed). - // Compliant - rule of five. Programmer’s intent is clear, class behaves the - // same as v1::A. - class A - { - public: - A() = default; - A(A const&) = default; - A(A&&) = default; - ~A() - { - // ... - } - A& operator=(A const&) = default; - A& operator=(A&&) = default; - - private: - // Member data ... - }; -} // namespace v3 - -// A class with regular (value) semantics. -// Compliant - rule of zero. -class Simple -{ - public: - // User defined constructor, also acts as default constructor. - explicit Simple(double d = 0.0, std::string s = "Hello") - : d_(d), s_(std::move(s)) - { - } - - // Compiler generated copy c’tor, move c’tor, d’tor, copy assignment, move - // assignment. - - private: - double d_; - std::string s_; -}; - -// A base class. -// Compliant - rule of five. -class Base -{ - public: - Base(Base const&) = delete; // see also A12-8-6 - Base(Base&&) = delete; // see also A12-8-6 - virtual ~Base() = default; // see also A12-4-1 - Base& operator=(Base const&) = delete; // see also A12-8-6 - Base& operator=(Base&&) = delete; // see also A12-8-6 - - // Declarations of pure virtual functions ... - - protected: - Base() = default; // in order to allow construction of derived objects -}; - -// A move-only class. -// Compliant - rule of five. -class MoveOnly -{ - public: - MoveOnly(); - MoveOnly(MoveOnly const&) = delete; - MoveOnly(MoveOnly&&) noexcept; - ~MoveOnly(); - MoveOnly& operator=(MoveOnly const&) = delete; - MoveOnly& operator=(MoveOnly&&) noexcept; - - private: - // ... -}; \ No newline at end of file diff --git a/cpp/autosar/src/rules/A12-1-1/standard-example.cpp b/cpp/autosar/src/rules/A12-1-1/standard-example.cpp deleted file mode 100644 index c18370ca0b..0000000000 --- a/cpp/autosar/src/rules/A12-1-1/standard-example.cpp +++ /dev/null @@ -1,27 +0,0 @@ -// $Id: A12-1-1.cpp 271696 2017-03-23 09:23:09Z piotr.tanski $ -#include -class Base -{ - // Implementation -}; -class VirtualBase -{ -}; -class A : public virtual VirtualBase, public Base -{ - public: - A() : VirtualBase{}, Base{}, i{0}, j{0} // Compliant - { - } - A(A const& oth) - : Base{}, j{0} // Non-compliant - VirtualBase base class and member - // i not initialized - { - } - - private: - std::int32_t i; - std::int32_t j; - static std::int32_t k; -}; -std::int32_t A::k{0}; \ No newline at end of file diff --git a/cpp/autosar/src/rules/A12-1-2/standard-example.cpp b/cpp/autosar/src/rules/A12-1-2/standard-example.cpp deleted file mode 100644 index 4162e45683..0000000000 --- a/cpp/autosar/src/rules/A12-1-2/standard-example.cpp +++ /dev/null @@ -1,45 +0,0 @@ -// $Id: A12-1-2.cpp 271696 2017-03-23 09:23:09Z piotr.tanski $ -#include -#include -class A -{ - public: - A() : i1{0}, i2{0} // Compliant - i1 and i2 are initialized by the - // constructor only. Not compliant with A12-1-3 - { - } - // Implementation - - private: - std::int32_t i1; - std::int32_t i2; -}; -class B -{ - public: - // Implementation - - private: - std::int32_t i1{0}; - std::int32_t i2{0}; // Compliant - both i1 and i2 are initialized by NSDMI only -}; -class C -{ - public: - C() : i2{0} // Non-compliant - i1 is initialized by NSDMI, i2 is in - // member in member initializer list - { - } - C(C const& oth) : i1{oth.i1}, i2{oth.i2} // Compliant by exception - { - } - C(C&& oth) - : i1{std::move(oth.i1)}, - i2{std::move(oth.i2)} // Compliant by exception - { - } - // Implementation - private: - std::int32_t i1{0}; - std::int32_t i2; -}; \ No newline at end of file diff --git a/cpp/autosar/src/rules/A12-1-3/standard-example.cpp b/cpp/autosar/src/rules/A12-1-3/standard-example.cpp deleted file mode 100644 index d7f134488d..0000000000 --- a/cpp/autosar/src/rules/A12-1-3/standard-example.cpp +++ /dev/null @@ -1,25 +0,0 @@ -// $Id: A12-1-3.cpp 291949 2017-10-19 21:26:22Z michal.szczepankiewicz $ -#include -#include -class A -{ - public: - A() : x(0), y(0.0F), str() // Non-compliant - { - } - // ... - - private: - std::int32_t x; - float y; - std::string str; -}; -class B { - public: - // ... - - private: - std::int32_t x = 0; // Compliant - float y = 0.0F; // Compliant - std::string str = ""; // Compliant -}; \ No newline at end of file diff --git a/cpp/autosar/src/rules/A12-1-4/standard-example.cpp b/cpp/autosar/src/rules/A12-1-4/standard-example.cpp deleted file mode 100644 index 881fdde1e8..0000000000 --- a/cpp/autosar/src/rules/A12-1-4/standard-example.cpp +++ /dev/null @@ -1,40 +0,0 @@ -// $Id: A12-1-4.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -#include -class A -{ - public: - explicit A(std::int32_t number) : x(number) {} // Compliant - A(A const&) = default; - A(A&&) = default; - A& operator=(A const&) = default; - A& operator=(A&&) = default; - private: - std::int32_t x; -}; -class B -{ - public: - B(std::int32_t number) : x(number) {} // Non-compliant - B(B const&) = default; - B(B&&) = default; - B& operator=(B const&) = default; - B& operator=(B&&) = default; - - private: - std::int32_t x; -}; -void F1(A a) noexcept -{ -} -void F2(B b) noexcept -{ -} -void F3() noexcept -{ - F1(A(10)); - // f1(10); // Compilation error - because of explicit constructor it is not - // possible to implicitly convert integer - // to type of class A - F2(B(20)); - F2(20); // No compilation error - implicit conversion occurs -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A12-1-5/standard-example.cpp b/cpp/autosar/src/rules/A12-1-5/standard-example.cpp deleted file mode 100644 index 03f93904a6..0000000000 --- a/cpp/autosar/src/rules/A12-1-5/standard-example.cpp +++ /dev/null @@ -1,18 +0,0 @@ -// $Id: A12-1-5.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -#include -class A -{ - private: - std::int32_t x; - std::int32_t y; -}; -class B { - public: - // Non-compliant - B(std::int32_t x, std::int32_t y) : x(x + 8), y(y) {} - explicit B(std::int32_t x) : x(x + 8), y(0) {} - - private: - std::int32_t x; - std::int32_t y; -}; \ No newline at end of file diff --git a/cpp/autosar/src/rules/A12-1-6/standard-example.cpp b/cpp/autosar/src/rules/A12-1-6/standard-example.cpp deleted file mode 100644 index 0bd3b42315..0000000000 --- a/cpp/autosar/src/rules/A12-1-6/standard-example.cpp +++ /dev/null @@ -1,26 +0,0 @@ -// $Id: A12-1-6.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -#include -class A -{ - public: - A(std::int32_t x, std::int32_t y) : x(x + 8), y(y) {} - explicit A(std::int32_t x) : A(x, 0) {} - - private: - std::int32_t x; std::int32_t y; -}; - -// Non-compliant -class B : public A -{ - public: - B(std::int32_t x, std::int32_t y) : A(x, y) {} - explicit B(std::int32_t x) : A(x) {} -}; - -// Compliant -class C : public A -{ - public: - using A::A; -}; \ No newline at end of file diff --git a/cpp/autosar/src/rules/A12-4-1/standard-example.cpp b/cpp/autosar/src/rules/A12-4-1/standard-example.cpp deleted file mode 100644 index b73b00fd87..0000000000 --- a/cpp/autosar/src/rules/A12-4-1/standard-example.cpp +++ /dev/null @@ -1,41 +0,0 @@ -// $Id: A12-4-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -class A -{ - public: - ~A() // Non-compliant - { - } -}; -class B : public A -{ -}; -class C -{ - public: - virtual ~C() // Compliant - { - } -}; -class D : public C -{ -}; -class E -{ - protected: - ~E(); // Compliant -}; -class F : public E -{ -}; -void F1(A* obj1, C* obj2) -{ - // ... - delete obj1; // Only destructor of class A will be invoked - delete obj2; // Both destructors of D and C will be invoked -} -void F2() -{ - A* a = new B; - C* c = new D; - F1(a, c); -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A12-4-2/standard-example.cpp b/cpp/autosar/src/rules/A12-4-2/standard-example.cpp deleted file mode 100644 index eace3a5fb5..0000000000 --- a/cpp/autosar/src/rules/A12-4-2/standard-example.cpp +++ /dev/null @@ -1,55 +0,0 @@ -// $Id: A12-4-2.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -class A // Non-compliant - class A should not be used as a base class because - // its destructor is not virtual, but it is - // not declared final -{ - public: - A() = default; - A(A const&) = default; - A(A&&) = default; - A& operator=(A const&) = default; - A& operator=(A&&) = default; - ~A() = default; // Public non-virtual destructor -}; -class B final // Compliant - class B can not be used as a base class, because - // it is declared final, and it should not be derived - // because its destructor is not virtual -{ - public: - B() = default; - B(B const&) = default; - B(B&&) = default; - B& operator=(B const&) = default; - B& operator=(B&&) = default; - ~B() = default; // Public non-virtual destructor -}; -class C // Compliant - class C is not final, and its destructor is virtual. It - // can be used as a base class -{ - public: - C() = default; - C(C const&) = default; - C(C&&) = default; - C& operator=(C const&) = default; - C& operator=(C&&) = default; - virtual ~C() = default; // Public virtual destructor -}; -class AA : public A -{ -}; -// class BA : public B // Compilation error - can not derive from final base -// class B -//{ -//}; -class CA : public C -{ -}; -void Fn() noexcept -{ - AA obj1; - CA obj2; - A& ref1 = obj1; - C& ref2 = obj2; - ref1.~A(); // Calls A::~A() only - ref2.~C(); // Calls both CA::~CA() and C::~C() -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A12-6-1/standard-example.cpp b/cpp/autosar/src/rules/A12-6-1/standard-example.cpp deleted file mode 100644 index 0efb93df43..0000000000 --- a/cpp/autosar/src/rules/A12-6-1/standard-example.cpp +++ /dev/null @@ -1,43 +0,0 @@ -// $Id: A12-6-1.cpp 271696 2017-03-23 09:23:09Z piotr.tanski $ -#include -#include -class A -{ - public: - A(std::int32_t n, std::string s) : number{n}, str{s} // Compliant - { - } - // Implementation - - private: - std::int32_t number; - std::string str; -}; -class B -{ - public: - B(std::int32_t n, std::string s) // Non-compliant - no member initializers - { - number = n; - str = s; - } - // Implementation - - private: - std::int32_t number; - std::string str; -}; -class C { - public: - C(std::int32_t n, std::string s) : number{n}, str{s} // Compliant - { - n += 1; // This does not violate the rule - str.erase(str.begin(), - str.begin() + 1); // This does not violate the rule - } - // Implementation - - private: - std::int32_t number; - std::string str; -}; diff --git a/cpp/autosar/src/rules/A12-7-1/standard-example.cpp b/cpp/autosar/src/rules/A12-7-1/standard-example.cpp deleted file mode 100644 index e634fdbcc7..0000000000 --- a/cpp/autosar/src/rules/A12-7-1/standard-example.cpp +++ /dev/null @@ -1,78 +0,0 @@ -// $Id: A12-7-1.cpp 271715 2017-03-23 10:13:51Z piotr.tanski $ -#include -#include -class A -{ - public: - A() : x(0), y(0) {} // Compliant - A(std::int32_t first, std::int32_t second) : x(first), y(second) {} // Compliant - - // anyway, such - // a constructor - // cannot be - // defaulted. - A(const A& oth) - : x(oth.x), - y(oth.y) // Non-compliant - equivalent to the implicitly - // defined copy constructor - { - } - A(A&& oth) - : x(std::move(oth.x)), - y(std::move( - oth.y)) // Non-compliant - equivalent to the implicitly - // defined move constructor - { - } - ~A() // Non-compliant - equivalent to the implicitly defined destructor - { - } - - private: - std::int32_t x; - std::int32_t y; -}; -class B -{ - public: - B() {} // Non-compliant - x and y are not initialized - // should be replaced with: B() : x{0}, y{0} {} - B(std::int32_t first, std::int32_t second) : x(first), y(second) {} // Compliant - - B(const B&) = - default; // Compliant - equivalent to the copy constructor of class A - B(B&&) = - default; // Compliant - equivalent to the move constructor of class A - ~B() = default; // Compliant - equivalent to the destructor of class A - - private: - std::int32_t x; - std::int32_t y; -}; -class C -{ - public: - C() = default; // Compliant - C(const C&) = default; // Compliant - C(C&&) = default; // Compliant -}; -class D -{ - public: - D() : ptr(nullptr) {} // Compliant - this is not equivalent to what the - // implicitly defined default constructor would do - D(C* p) : ptr(p) {} // Compliant - D(const D&) = default; // Shallow copy will be performed, user-defined copy - // constructor is needed to perform deep copy on ptr variable - D(D&&) = default; // ptr variable will be moved, so ptr will still point to - // the same object - ~D() = default; // ptr will not be deleted, the user-defined destructor is - // needed to delete allocated memory - - private: - C* ptr; -}; -class E // Compliant - special member functions definitions are not needed as - // class E uses only implicit definitions -{ -}; \ No newline at end of file diff --git a/cpp/autosar/src/rules/A12-8-1/standard-example.cpp b/cpp/autosar/src/rules/A12-8-1/standard-example.cpp deleted file mode 100644 index fdbc874c51..0000000000 --- a/cpp/autosar/src/rules/A12-8-1/standard-example.cpp +++ /dev/null @@ -1,62 +0,0 @@ -// $Id: A12-8-1.cpp 303582 2018-01-11 13:42:56Z michal.szczepankiewicz $ -#include -#include -class A -{ - public: - // Implementation - A(A const& oth) : x(oth.x) // Compliant - { - } - - private: - std::int32_t x; -}; -class B -{ - public: - // Implementation - B(B&& oth) : ptr(std::move(oth.ptr)) // Compliant - { - oth.ptr = nullptr; // Compliant - this is not a side-effect, in this - // case it is essential to leave moved-from object - // in a valid state, otherwise double deletion will - // occur. - } - ~B() { delete ptr; } - - private: - std::int32_t* ptr; -}; -class C -{ - public: - // Implementation - C(C const& oth) : x(oth.x) - { - // ... - x = x % 2; // Non-compliant - unrelated side-effect - } - private: - std::int32_t x; -}; - -class D -{ - public: - explicit D(std::uint32_t a) : a(a), noOfModifications(0) {} - D(const D& d) : D(d.a) {} //compliant, not copying the debug information about number of modifications - void SetA(std::uint32_t aa) - { - ++noOfModifications; - a = aa; - } - std::uint32_t GetA() const noexcept - { - return a; - } - - private: - std::uint32_t a; - std::uint64_t noOfModifications; -}; \ No newline at end of file diff --git a/cpp/autosar/src/rules/A12-8-2/standard-example.cpp b/cpp/autosar/src/rules/A12-8-2/standard-example.cpp deleted file mode 100644 index c99b8fd7f2..0000000000 --- a/cpp/autosar/src/rules/A12-8-2/standard-example.cpp +++ /dev/null @@ -1,66 +0,0 @@ -// $Id: A12-8-2.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -#include -#include -class A -{ - public: - A(const A& oth) - { - // ... - } - A(A&& oth) noexcept - { - // ... - } - A& operator=(const A& oth) & // Compliant - { - A tmp(oth); - Swap(*this, tmp); - return *this; - } - A& operator=(A&& oth) & noexcept // Compliant - { - A tmp(std::move(oth)); - Swap(*this, tmp); - return *this; - } - static void Swap(A& lhs, A& rhs) noexcept - { - std::swap(lhs.ptr1, rhs.ptr1); - std::swap(lhs.ptr2, rhs.ptr2); - } - - private: - std::int32_t* ptr1; - std::int32_t* ptr2; -}; -class B -{ - public: - B& operator=(const B& oth) & // Non-compliant - { - if (this != &oth) - { - ptr1 =new std::int32_t(*oth.ptr1); =new std::int32_t( - ptr2 =new std::int32_t( - *oth.ptr2); // Exception thrown here results in - // a memory leak of ptr1 - } - return *this; - } - B& operator=(B&& oth) & noexcept // Non-compliant - { - if (this != &oth) - { - ptr1 = std::move(oth.ptr1); - ptr2 = std::move(oth.ptr2); - oth.ptr1 = nullptr; - oth.ptr2 = nullptr; - } - return *this; - } - - private: - std::int32_t* ptr1; - std::int32_t* ptr2; -}; \ No newline at end of file diff --git a/cpp/autosar/src/rules/A12-8-3/standard-example.cpp b/cpp/autosar/src/rules/A12-8-3/standard-example.cpp deleted file mode 100644 index 8d510c7267..0000000000 --- a/cpp/autosar/src/rules/A12-8-3/standard-example.cpp +++ /dev/null @@ -1,22 +0,0 @@ -// $Id: A12-8-3.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -#include -#include -#include -#include -void F1() -{ - std::string s1{"string"}; - std::string s2{std::move(s1)}; - // ... - std::cout << s1 << "\n"; // Non-compliant - s1 does not contain "string" - // value after move operation -} -void F2() -{ - std::unique_ptr ptr1 = std::make_unique(0); - std::unique_ptr ptr2{std::move(ptr1)}; - std::cout << ptr1.get() << std::endl; // Compliant by exception - move - // construction of std::unique_ptr - // leaves moved-from object in a - // well-specified state -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A12-8-4/standard-example.cpp b/cpp/autosar/src/rules/A12-8-4/standard-example.cpp deleted file mode 100644 index 007bc36a86..0000000000 --- a/cpp/autosar/src/rules/A12-8-4/standard-example.cpp +++ /dev/null @@ -1,46 +0,0 @@ -// $Id: A12-8-4.cpp 271696 2017-03-23 09:23:09Z piotr.tanski $ -#include -#include -class A -{ - public: - // ... - A(A&& oth) - : x(std::move(oth.x)), // Compliant - s(std::move(oth.s)) // Compliant - { - } - - private: - std::int32_t x; - std::string s; -}; -class B -{ - public: - // ... - B(B&& oth) - : x(oth.x), // Compliant by exception, std::int32_t is of scalar - // type - s(oth.s) // Non-compliant - { - } - - private: - std::int32_t x; - std::string s; -}; -class C -{ - public: - // ... - C(C&& oth) - : x(oth.x), // Compliant by exception - s(std::move(oth.s)) // Compliant - { - } - - private: - std::int32_t x = 0; - std::string s = "Default string"; -}; \ No newline at end of file diff --git a/cpp/autosar/src/rules/A12-8-5/standard-example.cpp b/cpp/autosar/src/rules/A12-8-5/standard-example.cpp deleted file mode 100644 index 256ae0f104..0000000000 --- a/cpp/autosar/src/rules/A12-8-5/standard-example.cpp +++ /dev/null @@ -1,63 +0,0 @@ -// $Id: A12-8-5.cpp 271773 2017-03-23 13:16:53Z piotr.tanski $ -#include -#include -struct A -{ - std::int32_t number; - std::int32_t* ptr; - // Implementation -}; -class B -{ - public: - // ... - B& operator=(B const& oth) // Non-compliant - { - i = oth.i; - delete aPtr; - try - { - aPtr = new A(*oth.aPtr); // If this is the self-copy case, then - // the oth.a_ptr is already deleted - } - catch (std::bad_alloc&) - { - aPtr = nullptr; - } - return *this; - } - - private: - std::int16_t i = 0; - A* aPtr = nullptr; -}; -class C -{ - public: - C& operator=(C const& oth) // Compliant - { - if (this != &oth) - { - A* tmpPtr = new A(*oth.aPtr); - i = oth.i; - delete aPtr; - aPtr = tmpPtr; - } - return *this; - } - C& operator=(C&& oth) // Compliant - { - if (this != &oth) - { - A* tmpPtr = new A{std::move(*oth.aPtr)}; - i = oth.i; - delete aPtr; - aPtr = tmpPtr; - } - return *this; - } - - private: - std::int16_t i = 0; - A* aPtr = nullptr; -}; \ No newline at end of file diff --git a/cpp/autosar/src/rules/A12-8-6/standard-example.cpp b/cpp/autosar/src/rules/A12-8-6/standard-example.cpp deleted file mode 100644 index d1ab816a5c..0000000000 --- a/cpp/autosar/src/rules/A12-8-6/standard-example.cpp +++ /dev/null @@ -1,128 +0,0 @@ -// $Id: A12-8-6.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -#include -#include -#include -class A // Abstract base class -{ - public: - A() = default; - A(A const&) = default; // Non-compliant - A(A&&) = default; // Non-compliant - virtual ~A() = 0; - A& operator=(A const&) = default; // Non-compliant - A& operator=(A&&) = default; // Non-compliant -}; -class B : public A -{ -}; -class C // Abstract base class -{ - public: - C() = default; - virtual ~C() = 0; - - protected: - C(C const&) = default; // Compliant - C(C&&) = default; // Compliant - C& operator=(C const&) = default; // Compliant - C& operator=(C&&) = default; // Compliant -}; -class D : public C -{ -}; -class E // Abstract base class -{ - public: - E() = default; - virtual ~E() = 0; - E(E const&) = delete; // Compliant - E(E&&) = delete; // Compliant - E& operator=(E const&) = delete; // Compliant - E& operator=(E&&) = delete; // Compliant -}; -class F : public E -{ -}; -class G // Non-abstract base class -{ - public: - G() = default; - virtual ~G() = default; - G(G const&) = default; // Non-compliant - G(G&&) = default; // Non-compliant - G& operator=(G const&) = default; // Non-compliant - G& operator=(G&&) = default; // Non-compliant -}; -class H : public G -{ -}; -void Fn1() noexcept -{ - B obj1; - B obj2; - A* ptr1 = &obj1; - A* ptr2 = &obj2; - *ptr1 = *ptr2; // Partial assignment only - *ptr1 = std::move(*ptr2); // Partial move only - D obj3; - D obj4; - C* ptr3 = &obj3; - C* ptr4 = &obj4; - //*ptr3 = *ptr4; // Compilation error - copy assignment operator of class C - // is protected - //*ptr3 = std::move(*ptr4); // Compilation error - move assignment operator - // of class C is protected - F obj5; - F obj6; - E* ptr5 = &obj5; - E* ptr6 = &obj6; - //*ptr5 = *ptr6; // Compilation error - use of deleted copy assignment - // operator - //*ptr5 = std::move(*ptr6); // Compilation error - use of deleted move - // assignment operator - H obj7; - H obj8; - G* ptr7 = &obj7; - G* ptr8 = &obj8; - *ptr7 = *ptr8;// Partial assignment only - *ptr7 = std::move(*ptr8); // Partial move only -} -class I // Non-abstract base class -{ - public: - I() = default; - ~I() = default; - - protected: - I(I const&) = default; // Compliant - I(I&&) = default; // Compliant - I& operator=(I const&) = default; // Compliant - I& operator=(I&&) = default; // Compliant -}; -class J : public I -{ - public: - J() = default; - ~J() = default; - J(J const&) = default; - J(J&&) = default; - J& operator=(J const&) = default; - J& operator=(J&&) = default; -}; -void Fn2() noexcept -{ - std::vector v1; - // v1.push_back(J{}); // Compilation-error on calling a deleted move - // constructor of I class, slicing does not occur - // v1.push_back(I{}); // Compilation-error on calling a deleted move - // constructor of I class - - std::vector v2; - v2.push_back(J{}); // No compilation error - - std::vector> v3; - v3.push_back(std::unique_ptr{}); // No compilation error - v3.push_back(std::make_unique()); // No compilation error - v3.push_back(std::make_unique()); // No compilation error - v3.emplace_back(); // No compilation error -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A12-8-7/standard-example.cpp b/cpp/autosar/src/rules/A12-8-7/standard-example.cpp deleted file mode 100644 index 5917c4b7ac..0000000000 --- a/cpp/autosar/src/rules/A12-8-7/standard-example.cpp +++ /dev/null @@ -1,43 +0,0 @@ -// $Id: A12-8-7.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -#include -class A -{ - public: - A() = default; - A& operator*=(std::int32_t i) // Non-compliant - { - // ... - return *this; - } -}; -A F1() noexcept -{ - return A{}; -} -class B -{ - public: - B() = default; - B& operator*=(std::int32_t) & // Compliant - { - // ... - return *this; - } -}; -B F2() noexcept -{ - return B{}; -} -std::int32_t F3() noexcept -{ - return 1; -} -int main(int, char**) -{ - F1() *= 10; // Temporary result of f1() multiplied by 10. No compile-time - // error. - ; - // f2() *= 10; // Compile-time error due to ref-qualifier - ; - // f3() *= 10; // Compile-time error on built-in type -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A13-1-2/standard-example.cpp b/cpp/autosar/src/rules/A13-1-2/standard-example.cpp deleted file mode 100644 index b36e5fda21..0000000000 --- a/cpp/autosar/src/rules/A13-1-2/standard-example.cpp +++ /dev/null @@ -1,27 +0,0 @@ -// $Id: A13-1-2.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -constexpr long double operator"" _m(long double meters) // Compliant -{ - // Implementation - return meters; -} -constexpr long double operator"" _kg(long double kilograms) // Compliant -{ - // Implementation - return kilograms; -} -constexpr long double operator"" m(long double meters) // Non-compliant -{ - // Implementation - return meters; -} -constexpr long double operator"" kilograms( -long double kilograms) // Non-compliant -{ - // Implementation - return kilograms; -} -void Fn() -{ - long double weight = 20.0_kg; - long double distance = 204.8_m; -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A13-1-3/standard-example.cpp b/cpp/autosar/src/rules/A13-1-3/standard-example.cpp deleted file mode 100644 index aad872f544..0000000000 --- a/cpp/autosar/src/rules/A13-1-3/standard-example.cpp +++ /dev/null @@ -1,42 +0,0 @@ -// $Id: A13-1-3.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -#include -#include -struct Cube -{ - unsigned long long int volume; - constexpr explicit Cube(unsigned long long int v) : volume(v) {} -}; -constexpr Cube operator"" _m3(unsigned long long int volume) -{ - return Cube(volume); // Compliant -} -struct Temperature -{ - unsigned long long int kelvins; - constexpr explicit Temperature(unsigned long long int k) : kelvins(k) {} -}; -constexpr Temperature operator"" _K(unsigned long long int kelvins) -{ - return Temperature(kelvins); // Compliant -} -static void SumDistances(std::int32_t distance) -{ - static std::int32_t overallDistance = 0; - overallDistance += distance; -} -struct Distance -{ - long double kilometers; - explicit Distance(long double kms) : kilometers(kms) {} -}; -Distance operator"" _m(long double meters) -{ - SumDistances(meters); // Non-compliant - function has a side-effect - return Distance(meters / 1000); -} -void operator"" _print(const char* str) -{ - std::cout << str << '\n'; // Non-compliant - user-defined literal operator - // does not perform conversion and has a - // side-effect -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A13-2-1/standard-example.cpp b/cpp/autosar/src/rules/A13-2-1/standard-example.cpp deleted file mode 100644 index 566fe3d78e..0000000000 --- a/cpp/autosar/src/rules/A13-2-1/standard-example.cpp +++ /dev/null @@ -1,44 +0,0 @@ -// $Id: A13-2-1.cpp 271687 2017-03-23 08:57:35Z piotr.tanski $ -class A -{ - public: - // ... - A& operator=(const A&) & // Compliant - { - // ... - return *this; } - }; - -class B -{ - public: - // ... - const B& operator=(const B&) & // Non-compliant - violating consistency - // with standard types - { - // ... - return *this; - } -}; - -class C -{ - public: - // ... - C operator=(const C&) & // Non-compliant - { - // ... - return *this; - } -}; - -class D -{ - public: - // ... - D* operator=(const D&) & // Non-compliant - { - // ... - return this; - } -}; \ No newline at end of file diff --git a/cpp/autosar/src/rules/A13-2-2/standard-example.cpp b/cpp/autosar/src/rules/A13-2-2/standard-example.cpp deleted file mode 100644 index c343bf868f..0000000000 --- a/cpp/autosar/src/rules/A13-2-2/standard-example.cpp +++ /dev/null @@ -1,26 +0,0 @@ -// $Id: A13-2-2.cpp 271687 2017-03-23 08:57:35Z piotr.tanski $ -#include -class A -{ -}; - -A operator+(A const&, A const&) noexcept // Compliant -{ - return A{}; -} -std::int32_t operator/(A const&, A const&) noexcept // Compliant -{ - return 0; -} -A operator&(A const&, A const&)noexcept // Compliant -{ - return A{}; -} -const A operator-(A const&, std::int32_t) noexcept // Non-compliant -{ - return A{}; -} -A* operator|(A const&, A const&) noexcept // Non-compliant -{ - return new A{}; -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A13-2-3/standard-example.cpp b/cpp/autosar/src/rules/A13-2-3/standard-example.cpp deleted file mode 100644 index 4f64175538..0000000000 --- a/cpp/autosar/src/rules/A13-2-3/standard-example.cpp +++ /dev/null @@ -1,30 +0,0 @@ -// $Id: A13-2-3.cpp 271687 2017-03-23 08:57:35Z piotr.tanski $ -#include -class A -{ -}; - -bool operator==(A const&, A const&) noexcept // Compliant -{ - return true; -} -bool operator<(A const&, A const&) noexcept // Compliant -{ - return false; -} -bool operator!=(A const& lhs, A const& rhs) noexcept // Compliant -{ - return !(operator==(lhs, rhs)); -} -std::int32_t operator>(A const&, A const&) noexcept // Non-compliant -{ - return -1; -} -A operator>=(A const&, A const&) noexcept // Non-compliant -{ - return A{}; -} -const A& operator<=(A const& lhs, A const& rhs) noexcept // Non-compliant -{ - return lhs; -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A13-3-1/standard-example.cpp b/cpp/autosar/src/rules/A13-3-1/standard-example.cpp deleted file mode 100644 index 8ccdc8ffb1..0000000000 --- a/cpp/autosar/src/rules/A13-3-1/standard-example.cpp +++ /dev/null @@ -1,36 +0,0 @@ -// $Id: A13-3-1.cpp 309903 2018-03-02 12:54:18Z christof.meerwald $ -#include -template -void F1(T&& t) noexcept(false) -{ -} -void F1( - std::int32_t&& t) noexcept // Non-compliant - overloading a function with - // forwarding reference -{ -} -template -void F2(T&& t) noexcept(false) -{ -} -void F2(std::int32_t&) = delete; // Compliant by exception -class A -{ - public: - // Compliant by exception, constrained to not match copy/move ctors - template>, - A>::value> * = nullptr> - A(T &&value); -}; - -int main(int, char**) -{ - std::int32_t x = 0; - F1(x); - F1(+x); // Calls f1(std::int32_t&&) - F1(0); // Calls f1(std::int32_t&&) - F1(0U); // Calls f1(T&&) with T = unsigned int - F2(0); // Calls f2(T&&) with T = int - // f2(x); // Compilation error, the overloading function is deleted -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A13-5-1/standard-example.cpp b/cpp/autosar/src/rules/A13-5-1/standard-example.cpp deleted file mode 100644 index 7c96b5e0c6..0000000000 --- a/cpp/autosar/src/rules/A13-5-1/standard-example.cpp +++ /dev/null @@ -1,38 +0,0 @@ -// $Id: A13-5-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -#include -class Container1 -{ - public: - std::int32_t& operator[]( - std::int32_t index) // Compliant - non-const version - { - return container[index]; - } - std::int32_t operator[]( - std::int32_t index) const // Compliant - const version - { - return container[index]; - } - - private: - static constexpr std::int32_t maxSize = 10; - std::int32_t container[maxSize]; -}; -void Fn() noexcept -{ - Container1 c1; - std::int32_t e = c1[0]; // Non-const version called - c1[0] = 20; // Non-const version called Container1 const c2{}; - e = c2[0]; // Const version called - // c2[0] = 20; // Compilation error -} -class Container2 // Non-compliant - only non-const version of operator[] - // implemented -{ - public: - std::int32_t& operator[](std::int32_t index) { return container[index]; } - - private: - static constexpr std::int32_t maxSize = 10; - std::int32_t container[maxSize]; -}; \ No newline at end of file diff --git a/cpp/autosar/src/rules/A13-5-2/standard-example.cpp b/cpp/autosar/src/rules/A13-5-2/standard-example.cpp deleted file mode 100644 index c2010a17ff..0000000000 --- a/cpp/autosar/src/rules/A13-5-2/standard-example.cpp +++ /dev/null @@ -1,18 +0,0 @@ -// $Id: A13-5-2.cpp 303121 2018-01-09 09:03:52Z michal.szczepankiewicz $ -class A -{ - public: - explicit A(double d) : d(d) {} - explicit operator double() const { return d; } // Compliant - private: - double d; -}; - -int main(void) -{ - A a{3.1415926535897932384626433832795028841971693993751058209749445923078}; - double tmp1{a}; - // float tmp2{a}; //compilation error instead of warning, prevents from data - // precision loss - return 0; -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A13-5-3/standard-example.cpp b/cpp/autosar/src/rules/A13-5-3/standard-example.cpp deleted file mode 100644 index b794e852bd..0000000000 --- a/cpp/autosar/src/rules/A13-5-3/standard-example.cpp +++ /dev/null @@ -1,21 +0,0 @@ -// $Id: A13-5-3.cpp 305629 2018-01-29 13:29:25Z piotr.serwa $ -#include -class Complex -{ - public: - Complex (double r, double i = 0.0) : re(r), im(i) {} - explicit operator double() const noexcept { return re; } - double AsDouble() const noexcept { return re; } - - private: - double re; - double im; -}; - -int main(void) -{ - Complex c(2.0f); - std::cout << (double) c << std::endl; //compliant with A13-5-2, non-compliant with A13-5-3 - std::cout << c.AsDouble() << std::endl; //compliant - return 0; -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A13-5-4/standard-example.cpp b/cpp/autosar/src/rules/A13-5-4/standard-example.cpp deleted file mode 100644 index 1b227a15bb..0000000000 --- a/cpp/autosar/src/rules/A13-5-4/standard-example.cpp +++ /dev/null @@ -1,37 +0,0 @@ -// $Id: A13-5-4.cpp 328319 2018-08-03 14:08:42Z christof.meerwald $ -#include - -// non-compliant -class A - public: - explicit A(std::uint32_t d) : d(d) {} - friend bool operator==(A const & lhs, A const & rhs) noexcept - { - return lhs.d == rhs.d; - } - friend bool operator!=(A const & lhs, A const & rhs) noexcept - { - return lhs.d != rhs.d; - } - private: - std::uint32_t d; -}; - -// compliant -class B -{ - public: - explicit B(std::uint32_t d) : d(d) {} - - friend bool operator==(B const & lhs, B const & rhs) noexcept - { - return lhs.d ==rhs.d; - } - friend bool operator!=(B const & lhs, B const & rhs) noexcept - { - return !(lhs == rhs) - } - - private: - std::uint32_t d; -}; diff --git a/cpp/autosar/src/rules/A13-5-5/standard-example.cpp b/cpp/autosar/src/rules/A13-5-5/standard-example.cpp deleted file mode 100644 index ea91693c13..0000000000 --- a/cpp/autosar/src/rules/A13-5-5/standard-example.cpp +++ /dev/null @@ -1,55 +0,0 @@ -// $Id: A13-5-5.cpp 325916 2018-07-13 12:26:22Z christof.meerwald $ -#include - -class A -{ - public: - explicit A(std::uint32_t d) - : m_d(d) - {} - bool operator ==(A const & rhs) const // Non-compliant: member, not noexcept - { - return m_d == rhs.m_d; - } - - private: - std::uint32_t m_d; -}; - -class C -{ - public: - operator A() const; -}; - -void Foo(A const & a, C const & c) -{ - a == c; // asymmetric as "a ==c" compiles, but "c == a" doesn’t compile -} - -class B -{ - public: - explicit B(std::uint32_t d) - : m_d(d) - {} - // Compliant: non-member, identical parameter types, noexcept - friend bool operator==(B const & lhs, B const & rhs) noexcept - { - return lhs.m_d == rhs.m_d; - } - - private: - std::uint32_t m_d; }; - -class D -{ - public: - operator B() const; -}; - -void Bar(B const & b, D const & d) -{ - b == d; - d == b; -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A13-6-1/standard-example.cpp b/cpp/autosar/src/rules/A13-6-1/standard-example.cpp deleted file mode 100644 index 7347b3750d..0000000000 --- a/cpp/autosar/src/rules/A13-6-1/standard-example.cpp +++ /dev/null @@ -1,14 +0,0 @@ -// $Id: A13-6-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -#include -void Fn() noexcept -{ - std::uint32_t decimal1 = 3'000'000; // Compliant - std::uint32_t decimal2 = 4'500; // Compliant - std::uint32_t decimal3 = 54'00'30; // Non-compliant - float decimal4 = 3.141'592'653; // Compliant - float decimal5 = 3.1'4159'265'3; // Non-compliant - std::uint32_t hex1 = 0xFF'FF'FF'FF; // Compliant - std::uint32_t hex2 = 0xFAB'1'FFFFF; // Non-compliant - std::uint8_t binary1 = 0b1001'0011; // Compliant - std::uint8_t binary2 = 0b10'00'10'01; // Non-compliant -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A14-1-1/standard-example.cpp b/cpp/autosar/src/rules/A14-1-1/standard-example.cpp deleted file mode 100644 index 49a022600b..0000000000 --- a/cpp/autosar/src/rules/A14-1-1/standard-example.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include -class A -{ - public: - A() = default; - ~A() = default; - A(A const&) = delete; - A& operator=(A const&) = delete; - A(A&&) = delete; - A& operator=(A&&) = delete; -}; -class B -{ - public: - B() = default; - B(B const&) = default; - B& operator=(B const&) = default; B(B&&) = default; - B& operator=(B&&) = default; -}; -template -void F1(T const& obj) noexcept(false) -{ - static_assert(std::is_copy_constructible(), - "Given template type is not copy constructible."); // Compliant -} -template -class C -{ - // Compliant - static_assert(std::is_trivially_copy_constructible(), - "Given template type is not trivially copy constructible."); - - // Compliant - static_assert(std::is_trivially_move_constructible(), - "Given template type is not trivially move constructible."); - - // Compliant - static_assert(std::is_trivially_copy_assignable(), - "Given template type is not trivially copy assignable."); - - // Compliant - static_assert(std::is_trivially_move_assignable(), - "Given template type is not trivially move assignable."); - - public: - C() = default; - C(C const&) = default; - C& operator=(C const&) = default; - C(C&&) = default; - C& operator=(C&&) = default; - - private: - T c; -}; - -template -class D -{ - public: - D() = default; - D(D const&) = default; // Non-compliant - T may not be copyable - D& operator=(D const&) = default; // Non-compliant - T may not be copyable - D(D&&) = default; // Non-compliant - T may not be movable - D& operator=(D&&) = default; // Non-compliant - T may not be movable - - private: - T d; -}; - -void F2() noexcept -{ - A a; - B b; - // f1(a); // Class A is not copy constructible, compile-time error - // occurs - F1(b); // Class B is copy constructible - // C c1; // Class A can not be used for template class C, compile-time - // error occurs - C c2; // Class B can be used for template class C - D d1; - // D d2 = d1; // Class D can not be copied, because class A is not - // copyable, compile=time error occurs - // D d3 = std::move(d1); // Class D can not be moved, because class A is - // not movable, compile-time error occurs - D d4; - D d5 = d4; - D d6 = std::move(d4); -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A14-5-1/standard-example.cpp b/cpp/autosar/src/rules/A14-5-1/standard-example.cpp deleted file mode 100644 index 617b4e4e15..0000000000 --- a/cpp/autosar/src/rules/A14-5-1/standard-example.cpp +++ /dev/null @@ -1,61 +0,0 @@ -// $Id: A14-5-1.cpp 309903 2018-03-02 12:54:18Z christof.meerwald $ -#include -#include - -class A -{ - public: - // Compliant: template constructor does not participate in overload - // resolution for copy/move operations - template, A>::value> * = nullptr> - - A(const T &value) - : m_value { value } - {} - - private: - std::int32_t m_value; -}; - -void Foo(A const &a) -{ - A myA { a }; // will use the implicit copy ctor, not the template converting ctor - - A a2 { 2 }; // will use the template converting ctor -} - -class B -{ - public: - B(const B &) = default; - B(B &&) = default; - - // Compliant: forwarding constructor does not participate in overload - // resolution for copy/move operations - template>, - B>::value> * = nullptr> - - B(T &&value); -}; - -void Bar(B b) -{ - B myB { b }; // will use the copy ctor, not the forwarding ctor -} - -class C -{ - public: - C(const C &) = default; - C(C &&) = default; - - // Non-Compliant: unconstrained template constructor template - C(T &); -}; - -void Bar(C c) -{ - C myC { c }; // will use template ctor instead of copy ctor -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A14-5-2/standard-example.cpp b/cpp/autosar/src/rules/A14-5-2/standard-example.cpp deleted file mode 100644 index 054e404a4f..0000000000 --- a/cpp/autosar/src/rules/A14-5-2/standard-example.cpp +++ /dev/null @@ -1,31 +0,0 @@ -// $Id: A14-5-2.cpp 323444 2018-06-22 14:38:18Z christof.meerwald $ -#include -template -class A -{ - public: - enum State // Non-Compliant: member doesn’t depend on template parameter - { - State1, - State2 - }; - - State GetState(); -}; - -class B_Base -{ - public: - enum State // Compliant: not a member of a class template - { - State1, - State2 - }; -}; - -template -class B : B_Base -{ - public: - State GetState(); -}; \ No newline at end of file diff --git a/cpp/autosar/src/rules/A14-5-3/standard-example.cpp b/cpp/autosar/src/rules/A14-5-3/standard-example.cpp deleted file mode 100644 index a6c134feeb..0000000000 --- a/cpp/autosar/src/rules/A14-5-3/standard-example.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// $Id: A14-5-3.cpp $ -#include -template -class B -{ - public: - bool operator+(long rhs); - void f() - { - *this + 10; } - }; - -namespace NS1 -{ - class A {}; - - template - bool operator+( T, std::int32_t ); // Non-Compliant: a member of namespace - // with other declarations -} - -namespace NS2 -{ - void g(); - - template - bool operator+( T, std::int32_t ); // Compliant: a member of namespace - // with declarations of functions only -} - -template class B; // NS1::operator+ will be used in function B::f() - // instead of B::operator+ \ No newline at end of file diff --git a/cpp/autosar/src/rules/A14-7-1/standard-example.cpp b/cpp/autosar/src/rules/A14-7-1/standard-example.cpp deleted file mode 100644 index 9bd0e2ef43..0000000000 --- a/cpp/autosar/src/rules/A14-7-1/standard-example.cpp +++ /dev/null @@ -1,53 +0,0 @@ -// $Id: A14-7-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -#include -class A -{ - public: - void SetProperty(std::int32_t x) noexcept { property = x; } - void DoSomething() noexcept {} - - private: - std::int32_t property; -}; -struct B -{ -}; -class C -{ - public: - void DoSomething() noexcept {} -}; -template -class D -{ - public: - void F1() {} - void F2() - { - T t; - t.SetProperty(0); - } - void F3() - { - T t; - t.DoSomething(); - } -}; - -void Fn() noexcept -{ - D d1; // Compliant - struct A provides all needed members - d1.F1(); - d1.F2(); - d1.F3(); - - D d2; // Non-compliant - struct B does not provide needed members d2.F1(); - // d2.f2(); // Compilation error - no ’property’ in struct B - // d2.f3(); // Compilation error - no member named ’doSomething’ in struct - // B - - D d3; // Non-compliant - struct C does not provide property - d3.F1(); - // d3.F2(); // Compilation error - no property in struct C - d3.F3(); -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A14-7-2/standard-example.cpp b/cpp/autosar/src/rules/A14-7-2/standard-example.cpp deleted file mode 100644 index 998ac2eb2c..0000000000 --- a/cpp/autosar/src/rules/A14-7-2/standard-example.cpp +++ /dev/null @@ -1,53 +0,0 @@ -// $Id: A14-7-2.cpp 312645 2018-03-21 11:44:35Z michal.szczepankiewicz $ -#include -//in A.hpp -#include -struct A -{ - std::uint8_t x; -}; - -namespace std { - //compliant, case (2) - //template specialization for the user-defined type - //in the same file as the type declaration - template <> - struct hash - { - size_t operator()(const A& a) const noexcept - { - return std::hash()(a.x); - } - }; -} - -//traits.hpp -#include -#include -template -struct is_serializable : std::false_type {}; - -//compliant, case (1) -template <> -struct is_serializable : std::true_type {}; - -//func.cpp -#include -//non-compliant, not declared -//in the same file as -//is_serializable class -template <> -struct is_serializable : std::true_type {}; - -template ::value>> - std::vector serialize(const T& t) -{ - //only a basic stub - return std::vector{t}; -} - -#include -int main() -{ - serialize(std::uint8_t{3}); -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A14-8-2/standard-example.cpp b/cpp/autosar/src/rules/A14-8-2/standard-example.cpp deleted file mode 100644 index d54ce4371e..0000000000 --- a/cpp/autosar/src/rules/A14-8-2/standard-example.cpp +++ /dev/null @@ -1,54 +0,0 @@ -// $Id: A14-8-2.cpp 312698 2018-03-21 13:17:36Z michal.szczepankiewicz $ -#include -#include -#include -template -void F1(T t) -{ - //compliant, (a) - std::cout << "(a)" << std::endl; -} - -template <> -void F1<>(uint16_t* p) -{ - //non-compliant - //(x), explicit specialization of - //(a), not (b), due to declaration - //order - std::cout << "(x)" << std::endl; -} - -template -void F1(T* p) -{ - //compliant, (b), overloads (a) - std::cout << "(b)" << std::endl; -} - -template <> -void F1<>(uint8_t* p) -{ - //non-compliant - //(c), explicit specialization of (b) - std::cout << "(c)" << std::endl; -} - -void F1(uint8_t* p) -{ - //compliant - //(d), plain function, overloads with (a), (b) - //but not with (c) - std::cout << "(d)" << std::endl; -} - -int main(void) -{ - auto sp8 = std::make_unique(3); - auto sp16 = std::make_unique(3); - - F1(sp8.get()); //calls (d), which might be - //confusing, but (c) is non-compliant - F1(sp16.get()); //calls (b), which might be - //confusing, but (b) is non-compliant -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A15-0-1/standard-example.cpp b/cpp/autosar/src/rules/A15-0-1/standard-example.cpp deleted file mode 100644 index 9e289def98..0000000000 --- a/cpp/autosar/src/rules/A15-0-1/standard-example.cpp +++ /dev/null @@ -1,127 +0,0 @@ -//% $Id: A15-0-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -#include -#include -#include -#include -std::uint8_t ComputeCrc(std::string &msg); -bool IsMessageCrcCorrect1(std::string &message) { - std::uint8_t computedCRC = ComputeCrc(message); - std::uint8_t receivedCRC = message.at(0); - - if (computedCRC != receivedCRC) { - throw std::logic_error( - "Computed CRC is invalid."); // Non-compliant - CheckMessageCRC() - // was able to perform - // its task, nothing exceptional about its invalid result - } - - return true; -} -bool IsMessageCrcCorrect2(std::string &message) { - bool isCorrect = true; - std::uint8_t computedCRC = ComputeCrc(message); - std::uint8_t receivedCRC = message.at(0); - - if (computedCRC != receivedCRC) { - isCorrect = false; // Compliant - if CRC is not correct, then return "false" - } - - return isCorrect; -} -void SendData(std::string message) { - if (message.empty()) { - throw std::logic_error("Preconditions are not met."); // Compliant - - // SendData() was - // not able to - // perform its - // task - } - - bool sendTimeoutReached = false; - - // Implementation - if (sendTimeoutReached) { - throw std::runtime_error( - "Timeout on sending a message has been reached."); // Compliant - - // SendData() - // did not - // perform its - // task - } -} -std::int32_t FindIndex(std::vector &v, std::int32_t x) noexcept { - try { - std::size_t size = v.size(); - for (std::size_t i = 0U; i < size; ++i) { - if (v.at(i) == x) // v.at() throws an std::out_of_range exception - { - throw i; // Non-compliant - nothing exceptional about finding a - // value in vector - } - } - } - - catch (std::size_t - foundIdx) // Non-compliant - nothing exceptional about finding a - // value in vector - { - return foundIdx; - } - - catch (std::out_of_range - &e) // Compliant - std::out_of_range error shall be handled - { - return -1; - } - - return -1; -} -bool ReadFile(std::string &filename) noexcept { - try { - std::ifstream file(filename, std::ios_base::in); - if (!file.is_open()) { - throw std::runtime_error( - "File cannot be opened"); // Compliant - error on opening a - // file is an exceptional case - } - - char c = file.get(); - - if (!file.good()) { - throw std::runtime_error( - "Cannot read from file"); // Compliant - error on reading from - // file is an exceptional case - } - } - - catch (std::exception &e) { - return false; - } - - return true; -} -void Fn1(std::uint32_t x) // Non-compliant - inefficient and less readable - // version than its obvious alternative, e.g. fn2() -// function -{ - try { - if (x < 10) { - throw 10; - } - - // Action "A" - } - - catch (std::int32_t y) { - // Action "B" - } -} -void Fn2( - std::uint32_t x) // Compliant - the same functionality as fn1() function -{ - if (x < 10) { - // Action "B" - } else { - // Action "A" - } -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A15-0-2/standard-example.cpp b/cpp/autosar/src/rules/A15-0-2/standard-example.cpp deleted file mode 100644 index 09705a88e7..0000000000 --- a/cpp/autosar/src/rules/A15-0-2/standard-example.cpp +++ /dev/null @@ -1,96 +0,0 @@ -//% $Id: A15-0-2.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -#include -#include -class C1 -{ - public: - C1(const C1& rhs) - { - CopyBad(rhs); // Non-compliant - if an exception is thrown, an object - // will be left in an indeterminate state - CopyGood(rhs); // Compliant - full object will be properly copied or - // none of its properties will be changed - } - ~C1() { delete[] e; } - void CopyBad(const C1& rhs) - { - if (this != &rhs) - { - delete[] e; - e = nullptr; // e changed before the block where an exception can - // be thrown - s = rhs.s; // s changed before the block where an exception can be - // thrown - - if (s > 0) - { - e = new std::int32_t[s]; // If an exception will be thrown - // here, the - // object will be left in an indeterminate - // state - std::memcpy(e, rhs.e, s * sizeof(std::int32_t)); - } - } - } - void CopyGood(const C1& rhs) - { - std::int32_t* eTmp = nullptr; - if (rhs.s > 0) - { - eTmp = new std::int32_t[rhs.s]; // If an exception will be thrown - // here, the - // object will be left unchanged - std::memcpy(eTmp, rhs.e, rhs.s * sizeof(std::int32_t)); - } - - delete[] e; - e = eTmp; - s = rhs.s; - } - - private: - std::int32_t* e; - std::size_t s; -}; -class A -{ - public: - A() = default; -}; -class C2 -{ - public: - C2() : a1(new A), a2(new A) // Non-compliant - if a2 memory allocation - // fails, a1 will never be deallocated - { - } - - private: - A* a1; - A* a2; -}; -class C3 -{ - public: - C3() : a1(nullptr), a2(nullptr) // Compliant - { - try - { - a1 =new A; - a2 = new A; // If memory allocation for a2 fails, catch-block will - // deallocate a1 - } - catch (...) - { - delete a1; - a1 = nullptr; - delete a2; - a2 = nullptr; - throw; - } - } - - private: - A* a1; - A* a2; -}; \ No newline at end of file diff --git a/cpp/autosar/src/rules/A15-0-3/standard-example.cpp b/cpp/autosar/src/rules/A15-0-3/standard-example.cpp deleted file mode 100644 index 8776d66c75..0000000000 --- a/cpp/autosar/src/rules/A15-0-3/standard-example.cpp +++ /dev/null @@ -1,66 +0,0 @@ -//% $Id: A15-0-3.cpp 271687 2017-03-23 08:57:35Z piotr.tanski $ -#include -#include -#include -class A -{ - public: - explicit A(std::int32_t value) noexcept(false) : x(value) - { - if (x == 0) - { - throw std::invalid_argument("Constructor: Invalid Argument"); - } - } - - private: - std::int32_t x; -}; -int main(int, char**) -{ - constexpr std::int32_t limit = 10; - std::vector vec1; // Constructor and assignment operator of A class - // throw exceptions - - try - { - for (std::int32_t i = 1; i < limit; ++i) - { - vec1.push_back(A(i)); // Constructor of A class will not throw for - // value from 1 to 10 - } - - vec1.emplace(vec1.begin(), 0); // Non-compliant - constructor A(0) throws in an - // emplace() method of std::vector. This leads to - // unexpected result of emplace() method. Throwing an - // exception inside an object constructor in emplace() - // leads to duplication of one of vector’s elements. - // Vector invariants are valid and the object is destructible. - } - catch (std::invalid_argument& e) - { - // Handle an exception - } - - std::vector vec2; - vec2.reserve(limit); - try - { - for (std::int32_t i = limit - 1; i >= 0; --i) - { - vec2.push_back(A(i)); // Compliant - constructor of A(0) throws for - // i = 0, but in this case strong exception - // safety is guaranteed. While push_back() - // offers strong exception safety guarantee, - // push_back can only succeed to add a new - // element or fails and does not change the - // container - } - } - catch (std::invalid_argument& e) - { - // Handle an exception - } - - return 0; -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A15-0-4/standard-example.cpp b/cpp/autosar/src/rules/A15-0-4/standard-example.cpp deleted file mode 100644 index 0eb83b7cfc..0000000000 --- a/cpp/autosar/src/rules/A15-0-4/standard-example.cpp +++ /dev/null @@ -1,82 +0,0 @@ -//% $Id: A15-0-4.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -#include -#include -#include -class InvalidArguments : public std::logic_error // Compliant - invalid - // arguments error is - // "unchecked" exception -{ -public: - using std::logic_error::logic_error; -}; -class OutOfMemory : public std::bad_alloc - -{ -public: - using std::bad_alloc::bad_alloc; -}; -Compliant - insufficient memory error is - "unchecked" exception class DivisionByZero - : public std::logic_error // Compliant - division by zero -// error is "unchecked" -// exception - -{ -public: - using std::logic_error::logic_error; -}; - -class CommunicationError : public std::logic_error // Non-compliant - - // communication error - // should be "checked" -// exception but defined to be "unchecked" -{ -public: - using std::logic_error::logic_error; -}; -double Division(std::int32_t a, std::int32_t b) noexcept(false) { - // ... - if (b == 0) { - throw DivisionByZero( - "Division by zero error"); // Unchecked exception thrown correctly - } - - // ... -} -void Allocate(std::uint32_t bytes) noexcept(false) { - // ... - throw OutOfMemory(); // Unchecked exception thrown correctly -} -void InitializeSocket() noexcept(false) { - bool validParameters = true; - - // ... - if (!validParameters) { - throw InvalidArguments("Invalid parameters passed"); // Unchecked - // exception - // thrown - // correctly - } -} -void SendData(std::int32_t socket) noexcept(false) { - // ... - bool isSentSuccessfully = true; - - // ... - if (!isSentSuccessfully) { - throw CommunicationError("Could not send data"); // Unchecked exception - // thrown when checked - // exception should - // be. - } -} -void IterateOverContainer(const std::vector &container, - std::uint64_t length) noexcept(false) { - for (std::uint64_t idx{0U}; idx < length; ++idx) { - int32_t value = container.at(idx); // at() throws std::out_of_range - // exception when passed integer - // exceeds the size of container. - // Unchecked exception thrown - // correctly - } -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A15-0-5/standard-example.cpp b/cpp/autosar/src/rules/A15-0-5/standard-example.cpp deleted file mode 100644 index a0c6cd2e20..0000000000 --- a/cpp/autosar/src/rules/A15-0-5/standard-example.cpp +++ /dev/null @@ -1,102 +0,0 @@ -//% $Id: A15-0-5.cpp 309502 2018-02-28 09:17:39Z michal.szczepankiewicz $ -#include -#include -#include - -// @checkedException -class CommunicationError - : public std::exception // Compliant - communication error is "checked" -{ -public: - explicit CommunicationError(const char *message) : msg(message) {} - CommunicationError(CommunicationError const &) noexcept = default; - CommunicationError &operator=(CommunicationError const &) noexcept = default; - ~CommunicationError() override = default; - - const char *what() const noexcept override { return msg; } - -private: - const char *msg; -}; - -// @checkedException -class BusError : public CommunicationError // Compliant - bus error is "checked" -{ -public: - using CommunicationError::CommunicationError; -}; - -// @checkedException -class Timeout : public std::runtime_error // Compliant - communication timeout - // is "checked" -{ -public: - using std::runtime_error::runtime_error; -}; - -// @checkedException -class PreconditionsError : public std::exception // Non-compliant - error on - // preconditions check should - // be "unchecked" but is - // defined to be "checked" -{ - // Implementation -}; - -void Fn1(std::uint8_t *buffer, std::uint8_t bufferLength) noexcept(false) { - bool sentSuccessfully = true; - - // ... - if (!sentSuccessfully) { - throw CommunicationError( - "Could not send data"); // Checked exception thrown correctly - } -} -void Fn2(std::uint8_t *buffer, std::uint8_t bufferLength) noexcept(false) { - bool initSuccessfully = true; - - if (!initSuccessfully) { - throw PreconditionsError(); // An exception thrown on preconditions - // check failure should be "Unchecked", but - // PreconditionsError is "Checked" - } - - // ... - bool sentSuccessfully = true; - bool isTimeout = false; - - // ... - if (!sentSuccessfully) { - throw BusError("Could not send data"); // Checked exception thrown correctly - } - - // ... - if (isTimeout) { - throw Timeout("Timeout reached"); // Checked exception thrown correctly - } -} -void Fn3(std::uint8_t *buffer) noexcept(false) { - bool isResourceBusy = false; - - // ... - if (isResourceBusy) { - throw std::runtime_error( - "Resource is busy now"); // Checked exception thrown correctly - } -} -class Thread // Class which mimics the std::thread -{ -public: - // Implementation - - Thread() noexcept(false) { - bool resourcesAvailable = false; - // ... - if (!resourcesAvailable) { - throw std::system_error( - static_cast(std::errc::resource_unavailable_try_again), - std::generic_category()); // Compliant - correct usage of - // checked exception system_error - } - } -}; \ No newline at end of file diff --git a/cpp/autosar/src/rules/A15-1-1/standard-example.cpp b/cpp/autosar/src/rules/A15-1-1/standard-example.cpp deleted file mode 100644 index e3dea32ba6..0000000000 --- a/cpp/autosar/src/rules/A15-1-1/standard-example.cpp +++ /dev/null @@ -1,51 +0,0 @@ -//% $Id: A15-1-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -#include -#include -class A { - // Implementation -}; -class MyException : public std::logic_error { -public: - using std::logic_error::logic_error; - // Implementation -}; -void F1() { - throw -1; // Non-compliant - integer literal thrown -} -void F2() { - throw nullptr; // Non-compliant - null-pointer-constant thrown -} -void F3() { throw A(); } -Non - compliant - user - - defined type that does not inherit from std::exception thrown void F4() { - throw std::logic_error{ - "Logic Error"}; // Compliant - std library exception thrown -} -void F5() { - throw MyException{"Logic Error"}; // Compliant - user-defined type that - // inherits from std::exception thrown -} -void F6() { - throw std::make_shared( - std::logic_error("Logic Error")); // Non-compliant - shared_ptr does - // not inherit from std::exception -} -void F7() { - try { - F6(); - } - - catch (std::exception &e) // An exception of - // std::shared_ptr type will not - // be caught here - { - // Handle an exception - } catch (std::shared_ptr &e) // An exception of - // std::shared_ptr - // type will be caught here, but - // unable to access - // std::logic_error information - { - // Handle an exception - } -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A15-1-2/standard-example.cpp b/cpp/autosar/src/rules/A15-1-2/standard-example.cpp deleted file mode 100644 index fcad62db58..0000000000 --- a/cpp/autosar/src/rules/A15-1-2/standard-example.cpp +++ /dev/null @@ -1,36 +0,0 @@ -//% $Id: A15-1-2.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -#include -class A { - // Implementation -}; -void Fn(std::int16_t i) { - A a1; - A &a2 = a1; - A *a3 = new A; - - if (i < 10) { - throw a1; // Compliant - copyable object thrown - } else if (i < 20) { - throw A(); // Compliant - copyable object thrown - } - - else if (i < 30) { - throw a2; // Compliant - copyable object thrown - } - - else if (i < 40) { - throw &a1; // Non-compliant - pointer type thrown - } - - else if (i < 50) { - throw a3; // Non-compliant - pointer type thrown - } - - else if (i < 60) { - throw(*a3); // Compliant - memory leak occurs, violates other rules - } - - else { - throw new A; // Non-compliant - pointer type thrown - } -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A15-1-3/standard-example.cpp b/cpp/autosar/src/rules/A15-1-3/standard-example.cpp deleted file mode 100644 index c808fc3a59..0000000000 --- a/cpp/autosar/src/rules/A15-1-3/standard-example.cpp +++ /dev/null @@ -1,67 +0,0 @@ -//% $Id: A15-1-3.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -#include -#include -#include -#include -static std::string ComposeMessage(const char *file, const char *func, - std::int32_t line, - const std::string &message) noexcept { - std::stringstream s; - s << "(" << file << ", " << func << ":" << line << "): " << message; - - return s.str(); -} -void F1() { - // ... - throw std::logic_error("Error"); -} -void F2() { - // ... - throw std::logic_error("Error"); // Non-compliant - both exception type and - // error message are not unique -} -void F3() { - // ... - throw std::invalid_argument("Error"); // Compliant - exception type is unique -} -void F4() noexcept(false) { - // ... - throw std::logic_error("f3(): preconditions were not met"); // Compliant - - // error - // message is - // unique -} -void F5() noexcept(false) { - // ... - throw std::logic_error(ComposeMessage( - __FILE__, __func__, __LINE__, - "postconditions were not met")); // Compliant - error message is unique -} -void F6() noexcept { - try { - F1(); - F2(); - F3(); - } - - catch (std::invalid_argument &e) { - std::cout << e.what() << ’\n’; // Only f3() throws this type of - // exception, it is easy to deduce which - // function threw - } catch (std::logic_error &e) { - std::cout << e.what() << ’\n’; // f1() and f2() throw exactly the same - // exceptions, unable to deduce which - // function threw - } - - try { - F4(); - F5(); - } - - catch (std::logic_error &e) { - std::cout << e.what() << ’\n’; // Debugging process simplified, because - // of unique error message it is known - // which function threw - } -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A15-1-4/standard-example.cpp b/cpp/autosar/src/rules/A15-1-4/standard-example.cpp deleted file mode 100644 index 4118ba12cb..0000000000 --- a/cpp/autosar/src/rules/A15-1-4/standard-example.cpp +++ /dev/null @@ -1,156 +0,0 @@ -//% $Id: A15-1-4.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -#include -#include -#include -extern std::uint32_t F1(); -void FVeryBad() noexcept(false) -{ - std::logic_error* e = new std::logic_error("Logic Error 1"); - // ... - std::uint32_t i = F1(); - - if (i < 10) - { - throw(*e); // Non-compliant - fVeryBad() is not able to clean-up - // allocated memory - } - - // ... - delete e; -} -void FBad() noexcept(false) -{ - std::int32_t* x = new std::int32_t(0); - // ... - std::uint32_t i = F1(); - - if (i < 10) - { - throw std::logic_error("Logic Error 2"); // Non-compliant - exits from - // fBad() without cleaning-up - // allocated resources and - // causes a memory leak - } - else if (i < 20) - { - throw std::runtime_error("Runtime Error 3"); // Non-compliant - exits - // from fBad() without - // cleaning-up allocated - // resources and causes a - // memory leak - } - - // ... - delete x; // Deallocates claimed resource only in the end of fBad() scope -} -void FGood() noexcept(false) -{ - std::int32_t* y = new std::int32_t(0); - // ... - std::uint32_t i = F1(); - - if (i < 10) - { - delete y; // Deletes allocated resource before throwing an exception - throw std::logic_error("Logic Error 4"); // Compliant - deleting y - // variable before exception - // leaves the fGood() scope - } - - else if (i < 20) - { - delete y; // Deletes allocated resource before throwing an exception - throw std::runtime_error("Runtime Error 5"); // Compliant - deleting y - // exception leaves the - // fGood() scope - } - - else if (i < 30) - { - delete y; // Deletes allocated resource before throwing an exception - // again, difficult to maintain - throw std::invalid_argument("Invalid Argument 1"); // Compliant - deleting - // y variable before - // exception leaves the - // fGood() scope - } - - // ... - delete y; // Deallocates claimed resource also in the end of fGood() scope -} -void FBest() noexcept(false) -{ - std::unique_ptr z = std::make_unique(0); - // ... - std::uint32_t i = F1(); - - if (i < 10) - { - throw std::logic_error("Logic Error 6"); // Compliant - leaving the - // fBest() scope causes - // deallocation of all - // automatic variables, unique_ptrs, too - } - else if (i < 20) - { - throw std::runtime_error("Runtime Error 3"); // Compliant - leaving the - // fBest() scope causes - // deallocation of all - // automatic variables, - // unique_ptrs, too - } - - else if (i < 30) - { - throw std::invalid_argument("Invalid Argument 2"); // Compliant - leaving the fBest() scope - // causes deallocation of all automatic - // variables, unique_ptrs, too - } - - // ... - // z is deallocated automatically here, too -} -class CRaii // Simple class that follows RAII pattern -{ - public: - CRaii(std::int32_t* pointer) noexcept : x(pointer) {} - ~CRaii() - { - delete x; - x = nullptr; - } - - private: - std::int32_t* x; -}; -void FBest2() noexcept(false) -{ - CRaii a1(new std::int32_t(10)); - // ... - std::uint32_t i = F1(); - - if (i < 10) - { - throw std::logic_error("Logic Error 7"); // Compliant - leaving the - // fBest2() scope causes a1 - // variable deallocation - // automatically - } - else if (i < 20) - { - throw std::runtime_error("Runtime Error 4"); // Compliant - leaving the - // fBest2() scope causes - // a1 variable - // deallocation - // automatically - } - else if (i < 30) - { - throw std::invalid_argument("Invalid Argument 3"); // Compliant - leaving the fBest2() scope - // causes a1 variable deallocation - // automatically - } - - // ... - // a1 is deallocated automatically here, too -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A15-1-5/standard-example.cpp b/cpp/autosar/src/rules/A15-1-5/standard-example.cpp deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/cpp/autosar/src/rules/A15-2-1/standard-example.cpp b/cpp/autosar/src/rules/A15-2-1/standard-example.cpp deleted file mode 100644 index 3ae6a5f86d..0000000000 --- a/cpp/autosar/src/rules/A15-2-1/standard-example.cpp +++ /dev/null @@ -1,40 +0,0 @@ -//% $Id: A15-2-1.cpp 271927 2017-03-24 12:01:35Z piotr.tanski $ -#include -#include -class A { -public: - A() noexcept : x(0) { - // ... - } - explicit A(std::int32_t n) : x(n) { - // ... - throw std::runtime_error("Unexpected error"); - } - A(std::int32_t i, std::int32_t j) noexcept : x(i + j) { - try { - // ... - throw std::runtime_error("Error"); - // ... - } - - catch (std::exception &e) { - } - } - -private: - std::int32_t x; -}; -static A a1; // Compliant - default constructor of type A is noexcept -static A a2(5); // Non-compliant - constructor of type A throws, and the - // exception will not be caught by the handler in main function -static A a3(5, 10); // Compliant - constructor of type A is noexcept, it - // handles exceptions internally -int main(int, char **) { - try { - // program code - } catch (...) { - // Handle exceptions - } - - return 0; -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A15-2-2/standard-example.cpp b/cpp/autosar/src/rules/A15-2-2/standard-example.cpp deleted file mode 100644 index 80f49cd002..0000000000 --- a/cpp/autosar/src/rules/A15-2-2/standard-example.cpp +++ /dev/null @@ -1,98 +0,0 @@ -//% $Id: A15-2-2.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -#include -#include -class A { -public: - A() = default; -}; -class C1 { -public: - C1() - noexcept(false) - : a1(new A), a2(new A) // Non-compliant - if a2 memory allocation - // fails, a1 will never be deallocated - {} - C1(A *pA1, A *pA2) - noexcept - : a1(pA1), a2(pA2) // Compliant - memory allocated outside of C1 - // constructor, and no exceptions can be thrown - {} - -private: - A *a1; - A *a2; -}; -class C2 { -public: - C2() noexcept(false) : a1(nullptr), a2(nullptr) { - try { - a1 = new A; - a2 = new A; // If memory allocation for a2 fails, catch-block will - // deallocate a1 - } - - catch (std::exception &e) { - throw; // Non-compliant - whenever a2 allocation throws an - // exception, a1 will never be deallocated - } - } - -private: - A *a1; - A *a2; -}; -class C3 { -public: - C3() noexcept(false) : a1(nullptr), a2(nullptr), file("./filename.txt") { - try { - a1 = new A; - a2 = new A; - - if (!file.good()) { - throw std::runtime_error("Could not open file."); - } - } - - catch (std::exception &e) { - delete a1; - a1 = nullptr; - delete a2; - a2 = nullptr; - file.close(); - throw; // Compliant - all resources are deallocated before the - // constructor exits with an exception - } - } - -private: - A *a1; - A *a2; - std::ofstream file; -}; -class C4 { -public: - C4() : x(0), y(0) { - // Does not need to check preconditions here - x and y initialized with - // correct values - } - C4(std::int32_t first, std::int32_t second) - noexcept(false) : x(first), y(second) { - CheckPreconditions(x, - y); // Compliant - if constructor failed to create a - // valid object, then throw an exception - } - static void CheckPreconditions(std::int32_t x, - std::int32_t y) noexcept(false) { - if (x < 0 || x > 1000) { - throw std::invalid_argument("Preconditions of class C4 were not met"); - } - - else if (y < 0 || y > 1000) { - throw std::invalid_argument("Preconditions of class C4 were not met"); - } - } - -private: - std::int32_t x; // Acceptable range: <0; 1000> - std::int32_t y; // Acceptable range: <0; 1000> -}; \ No newline at end of file diff --git a/cpp/autosar/src/rules/A15-3-3/standard-example.cpp b/cpp/autosar/src/rules/A15-3-3/standard-example.cpp deleted file mode 100644 index f0fa2f4aa9..0000000000 --- a/cpp/autosar/src/rules/A15-3-3/standard-example.cpp +++ /dev/null @@ -1,64 +0,0 @@ -//% $Id: A15-3-3.cpp 309502 2018-02-28 09:17:39Z michal.szczepankiewicz $ -#include - -// base exception class from external library that is used -class ExtLibraryBaseException {}; - -int MainGood(int, char **) // Compliant -{ - try { - // program code - } catch (std::runtime_error &e) { - // Handle runtime errors - } catch (std::logic_error &e) { - // Handle logic errors - } catch (ExtLibraryBaseException &e) { - // Handle all expected exceptions - // from an external library - } catch (std::exception &e) { - // Handle all expected exceptions - } catch (...) { - // Handle all unexpected exceptions - } - - return 0; -} -int MainBad(int, char **) // Non-compliant - neither unexpected exceptions - // nor external libraries exceptions are caught -{ - try { - // program code - } catch (std::runtime_error &e) { - // Handle runtime errors - } catch (std::logic_error &e) { - // Handle logic errors - } catch (std::exception &e) { - // Handle all expected exceptions - } - - return 0; -} -void ThreadMainGood() // Compliant -{ - try { - // thread code - } catch (ExtLibraryBaseException &e) { - // Handle all expected exceptions - // from an external library - } catch (std::exception &e) { - // Handle all expected exception - } catch (...) { - // Handle all unexpected exception - } -} - -void ThreadMainBad() // Non-compliant - neither unexpected exceptions - // nor external libraries exceptions are caught -{ - try { - // thread code - } catch (std::exception &e) { - // Handle all expected exceptions - } - // Uncaught unexpected exception will cause an immediate program termination -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A15-3-4/standard-example.cpp b/cpp/autosar/src/rules/A15-3-4/standard-example.cpp deleted file mode 100644 index 156217b610..0000000000 --- a/cpp/autosar/src/rules/A15-3-4/standard-example.cpp +++ /dev/null @@ -1,110 +0,0 @@ -//% $Id: A15-3-4.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -#include -#include -extern std::int32_t Fn(); // Prototype of external third-party library function -void F1() noexcept(false) { - try { - std::int32_t ret = Fn(); - // ... - } - - // ... - catch (...) // Compliant - { - // Handle all unexpected exceptions from fn() function - } -} -void F2() noexcept(false) { - std::int32_t ret = - Fn(); // Non-compliant - can not be sure whether fn() throws or not - - if (ret < 10) { - throw std::underflow_error("Error"); - } - - else if (ret < 20) { - // ... - } else if (ret < 30) { - throw std::overflow_error("Error"); - } - - else { - throw std::range_error("Error"); - } -} -void F3() noexcept(false) { - try { - F2(); - } - - catch (std::exception &e) // Non-compliant - caught exception is too - // general, no information which error occured - { - // Nothing to do - throw; - } -} -void F4() noexcept(false) { - try { - F3(); - } - - catch (...) // Non-compliant - no information about the exception - { - // Nothing to do - throw; - } -} -class ExecutionManager { -public: - ExecutionManager() = default; - void Execute() noexcept(false) { - try { - F3(); - } - - // ... - catch (std::exception &e) // Compliant - { - // Handle all expected exceptions - } catch (...) // Compliant - { - // Handle all unexpected exceptions - } - } -}; -void ThreadMain() noexcept { - try { - F3(); - } - - // ... - catch (std::exception &e) // Compliant - { - // Handle all expected exceptions - } catch (...) // Compliant - { - // Handle all unexpected exceptions - } -} -int main(int, char **) { - try { - ExecutionManager execManager; - execManager.Execute(); - // ... - std::thread t(&ThreadMain); - // ... - F4(); - } - - // ... - catch (std::exception &e) // Compliant - { - // Handle all expected exceptions - } catch (...) // Compliant - { - // Handle all unexpected exceptions - } - - return 0; -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A15-3-5/standard-example.cpp b/cpp/autosar/src/rules/A15-3-5/standard-example.cpp deleted file mode 100644 index 16aa0bc7f1..0000000000 --- a/cpp/autosar/src/rules/A15-3-5/standard-example.cpp +++ /dev/null @@ -1,38 +0,0 @@ -//% $Id: A15-3-5.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -#include -#include -class Exception : public std::runtime_error { -public: - using std::runtime_error::runtime_error; - const char *what() const noexcept(true) override { - return "Exception error message"; - } -}; -void Fn() { - try { - // ... - throw std::runtime_error("Error"); - // ... - throw Exception("Error"); - } - - catch (const std::logic_error &e) // Compliant - caught by const reference - { - // Handle exception - } catch (std::runtime_error &e) // Compliant - caught by reference - { - std::cout << e.what() << "\n"; // "Error" or "Exception error message" - // will be printed, depending upon the - // actual type of thrown object - throw e; // The exception re-thrown is of its original type - } - - catch (std::runtime_error - e) // Non-compliant - derived types will be caught as the base type - { - std::cout << e.what() - << "\n"; // Will always call what() method from std::runtime_error - throw e; // The exception re-thrown is of the std::runtime_error type, - // not the original exception type - } -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A15-4-1/standard-example.cpp b/cpp/autosar/src/rules/A15-4-1/standard-example.cpp deleted file mode 100644 index 6ca3be1e3c..0000000000 --- a/cpp/autosar/src/rules/A15-4-1/standard-example.cpp +++ /dev/null @@ -1,12 +0,0 @@ -//% $Id: A15-4-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -#include -void F1() noexcept; // Compliant - note that noexcept is the same as -// noexcept(true) -void F2() throw(); // Non-compliant - dynamic exception-specification is -// deprecated -void F3() noexcept(false); // Compliant -void F4() throw(std::runtime_error); // Non-compliant - dynamic -// exception-specification is deprecated -void F5() throw( - ...); // Non-compliant - dynamic exception-specification is deprecated -template void F6() noexcept(noexcept(T())); // Compliant \ No newline at end of file diff --git a/cpp/autosar/src/rules/A15-4-2/standard-example.cpp b/cpp/autosar/src/rules/A15-4-2/standard-example.cpp deleted file mode 100644 index a19ba926db..0000000000 --- a/cpp/autosar/src/rules/A15-4-2/standard-example.cpp +++ /dev/null @@ -1,29 +0,0 @@ -//% $Id: A15-4-2.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -#include -// library.h -void LibraryFunc(); -// project.cpp -void F1() noexcept { - // ... - throw std::runtime_error("Error"); // Non-compliant - f1 declared to be - // noexcept, but exits with exception. - // This leads to std::terminate() call -} -void F2() noexcept(true) { - try { - // ... - throw std::runtime_error( - "Error"); // Compliant - exception will not leave f2 - } catch (std::runtime_error &e) { - // Handle runtime error - } -} -void F3() noexcept(false) { - // ... - throw std::runtime_error("Error"); // Compliant -} -void F4() noexcept( - false) // Compliant - no information whether library_func() throws or not -{ - LibraryFunc(); -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A15-4-3/standard-example.cpp b/cpp/autosar/src/rules/A15-4-3/standard-example.cpp deleted file mode 100644 index d9a54aabfd..0000000000 --- a/cpp/autosar/src/rules/A15-4-3/standard-example.cpp +++ /dev/null @@ -1,50 +0,0 @@ -//% $Id: A15-4-3.cpp 317753 2018-04-27 07:44:02Z jan.babst $ -// f1.hpp -void Fn() noexcept; - -// f1.cpp -// #include -void Fn() noexcept // Compliant -{ - // Implementation -} - -// f2.cpp -// #include -void Fn() noexcept(false) // Non-compliant - different exception specifier -{ - // Implementation -} - -class A { -public: - void F() noexcept; - void G() noexcept(false); - virtual void V1() noexcept = 0; - virtual void V2() noexcept(false) = 0; -}; -void A::F() noexcept // Compliant -// void A::F() noexcept(false) // Non-compliant - different exception specifier -// than in declaration -{ - // Implementation -} -void A::G() noexcept(false) // Compliant -// void A::G() noexcept // Non-compliant - different exception specifier than -// in declaration -{ - // Implementation -} -class B : public A { -public: - void V1() noexcept override // Compliant - // void V1() noexcept(false) override // Non-compliant - less restrictive - // exception specifier in derived method, non-compilable - { - // Implementation - } - void V2() noexcept override // Compliant - stricter noexcept specification - { - // Implementation - } -}; \ No newline at end of file diff --git a/cpp/autosar/src/rules/A15-4-4/standard-example.cpp b/cpp/autosar/src/rules/A15-4-4/standard-example.cpp deleted file mode 100644 index 240c434991..0000000000 --- a/cpp/autosar/src/rules/A15-4-4/standard-example.cpp +++ /dev/null @@ -1,66 +0,0 @@ -//% $Id: A15-4-4.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -#include -#include -void F1(); // Compliant - f1, without noexcept specification, declares to throw -// exceptions implicitly -void F2() noexcept; // Compliant - f2 does not throw exceptions -void F3() noexcept(true); // Compliant - f3 does not throw exceptions -void F4() noexcept(false); // Compliant - f4 declares to throw exceptions -void F5() noexcept // Compliant - f5 does not throw exceptions -{ - try { - F1(); // Exception handling needed, f1 has no noexcept specification - } - - catch (std::exception &e) { - // Handle exceptions - } - - F2(); // Exception handling not needed, f2 is noexcept - F3(); // Exception handling not needed, f3 is noexcept(true) - - try { - F4(); // Exception handling needed, f4 is noexcept(false) - } - - catch (std::exception &e) { - // Handle exceptions - } -} -template -void F6() noexcept(noexcept(T())); // Compliant - function f6() may be - // noexcept(true) or noexcept(false) - // depending on constructor of class T -template class A { -public: - A() - noexcept(noexcept(T())) // Compliant - constructor of class A may be - // noexcept(true) or noexcept(false) depending on - // constructor of class T - {} -}; -class C1 { -public: - C1() - noexcept( - true) // Compliant - constructor of class C1 does not throw exceptions - {} - // ... -}; -class C2 { -public: - C2() // Compliant - constructor of class C2 throws exceptions - {} - // ... -}; -void F7() noexcept // Compliant - f7 does not throw exceptions -{ - std::cout << noexcept(A()) << ’\n’; // prints ’1’ - constructor of - // A class is noexcept(true) - // because constructor of C1 class - // is declared to be noexcept(true) - std::cout << noexcept(A()) << ’\n’; // prints ’0’ - constructor of - // A class is noexcept(false) - // because constructor of C2 class - // has no noexcept specifier -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A15-4-5/standard-example.cpp b/cpp/autosar/src/rules/A15-4-5/standard-example.cpp deleted file mode 100644 index 31144429e9..0000000000 --- a/cpp/autosar/src/rules/A15-4-5/standard-example.cpp +++ /dev/null @@ -1,68 +0,0 @@ -//% $Id: A15-4-5.cpp 309502 2018-02-28 09:17:39Z michal.szczepankiewicz $ -#include -#include - -/// @checkedException -class CommunicationError : public std::exception { - // Implementation -}; -/// @checkedException -class BusError : public CommunicationError { - // Implementation -}; -/// @checkedException -class Timeout : public std::runtime_error { -public: - using std::runtime_error::runtime_error; - // Implementation -}; -/// @throw CommunicationError Communication error -/// @throw BusError Bus error -/// @throw Timeout On send timeout exception -void Send1(std::uint8_t *buffer, - std::uint8_t bufferLength) noexcept(false) // Compliant - All and - // only those checked - // exceptions that can be - // thrown are specified -{ - // ... - throw CommunicationError(); - // ... - throw BusError(); - // ... - throw Timeout("Timeout reached"); - // ... -} -/// @throw CommunicationError Communication error -void Send2(std::uint8_t *buffer, - std::uint8_t bufferLength) noexcept(false) // Non-compliant - checked - // exceptions that can be - // thrown are missing from - // specification -{ - // ... - throw CommunicationError(); - // ... - throw Timeout("Timeout reached"); - // ... -} -class MemoryPartitioningError : std::exception { - // Implementation -}; -/// @throw CommunicationError Communication error -/// @throw BusError Bus error -/// @throw Timeout On send timeout exception -/// @throw MemoryPartitioningError Memory partitioning error prevents message -/// from being sent. -void Send3( - std::uint8_t *buffer, - std::uint8_t bufferLength) noexcept(false) // Non-compliant - additional - // checked exceptions are - // specified -{ - // ... - throw CommunicationError(); - // ... - throw Timeout("Timeout reached"); - // ... -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A15-5-1/standard-example.cpp b/cpp/autosar/src/rules/A15-5-1/standard-example.cpp deleted file mode 100644 index f4fb8fe23f..0000000000 --- a/cpp/autosar/src/rules/A15-5-1/standard-example.cpp +++ /dev/null @@ -1,130 +0,0 @@ -//% $Id: A15-5-1.cpp 309720 2018-03-01 14:05:17Z jan.babst $ -#include -#include -class C1 { -public: - C1() = default; - - // Compliant - move constructor is non-throwing and declared to be noexcept - C1(C1 &&rhs) noexcept {} - - // Compliant - move assignment operator is non-throwing and declared to be - // noexcept - C1 &operator=(C1 &&rhs) noexcept { return *this; } - - // Compliant - destructor is non-throwing and declared to be noexcept by - // default - ~C1() noexcept {} -}; - -void Swap(C1 &lhs, - C1 &rhs) noexcept // Compliant - swap function is non-throwing and - // declared to be noexcept -{ - // Implementation -} - -class C2 { -public: - C2() = default; - - // Compliant - move constructor is non-throwing and declared to be noexcept - C2(C2 &&rhs) noexcept { - try { - // ... - throw std::runtime_error( - "Error"); // Exception will not escape this function - } - - catch (std::exception &e) { - // Handle error - } - } - - C2 &operator=(C2 &&rhs) noexcept { - try { - // ... - throw std::runtime_error( - "Error"); // Exception will not escape this function - } - - catch (std::exception &e) { - // Handle error - } - return *this; - } - - // Compliant - destructor is non-throwing and declared to be noexcept by - // default - ~C2() { - try { - // ... - throw std::runtime_error( - "Error"); // Exception will not escape this function - } - - catch (std::exception &e) { - // Handle error - } - } -}; - -// Non-compliant - swap function is declared to be noexcept(false) -void Swap(C2 &lhs, C2 &rhs) noexcept(false) { - // ... - // Non-compliant - Implementation exits with an exception - throw std::runtime_error("Swap function failed"); -} - -class C3 { -public: - C3() = default; - C3(C3 &&rhs) // Non-compliant - move constructor throws - { - // ... - throw std::runtime_error("Error"); - } - C3 &operator=(C3 &&rhs) // Non-compliant - move assignment operator throws - { - // ... - throw std::runtime_error("Error"); - return *this; - } - ~C3() // Non-compliant - destructor exits with an exception - { - throw std::runtime_error("Error"); - } - static void operator delete(void *ptr, std::size_t sz) { - // ... - throw std::runtime_error("Error"); // Non-compliant - deallocation - // function exits with an exception - } -}; - -void Fn() { - C3 c1; // program terminates when c1 is destroyed - C3 *c2 = new C3; - // ... - delete c2; // program terminates when c2 is deleted -} - -template class Optional { -public: - // ... - - // Compliant by exception - Optional(Optional &&other) noexcept( - std::is_nothrow_move_constructible::value) { - // ... - } - - // Compliant by exception - Optional &operator=(Optional &&other) noexcept( - std::is_nothrow_move_assignable::value - &&std::is_nothrow_move_constructible::value) { - // ... - return *this; - } - - // ... -}; \ No newline at end of file diff --git a/cpp/autosar/src/rules/A15-5-2/standard-example.cpp b/cpp/autosar/src/rules/A15-5-2/standard-example.cpp deleted file mode 100644 index 8ec5195c2f..0000000000 --- a/cpp/autosar/src/rules/A15-5-2/standard-example.cpp +++ /dev/null @@ -1,42 +0,0 @@ -//% $Id: A15-5-2.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -#include -#include -void F1() noexcept(false); -void F2() // Non-compliant -{ - F1(); // A call to throwing f1() may result in an implicit call to - // std::terminate() -} -void F3() // Compliant -{ - try { - F1(); // Handles all exceptions from f1() and does not re-throw - } catch (...) { - // Handle an exception - } -} -void F4(const char *log) { - // Report a log error - // ... - std::exit(0); // Call std::exit() function which safely cleans up resources -} -void F5() // Compliant by exception -{ - try { - F1(); - } catch (...) { - F4("f1() function failed"); - } -} -int main(int, char **) { - if (std::atexit(&F2) != 0) { - // Handle an error - } - - if (std::atexit(&F3) != 0) { - // Handle an error - } - - // ... - return 0; -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A15-5-3/standard-example.cpp b/cpp/autosar/src/rules/A15-5-3/standard-example.cpp deleted file mode 100644 index cea162b1aa..0000000000 --- a/cpp/autosar/src/rules/A15-5-3/standard-example.cpp +++ /dev/null @@ -1,58 +0,0 @@ -//% $Id: A15-5-3.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -#include -#include -extern bool F1(); -class A { -public: - A() noexcept(false) { - // ... - throw std::runtime_error("Error1"); - } - ~A() { - // ... - throw std::runtime_error("Error2"); // Non-compliant - std::terminate() - // called on throwing an exception - // from noexcept(true) destructor - } -}; -class B { -public: - ~B() noexcept(false) { - // ... - throw std::runtime_error("Error3"); - } -}; -void F2() { throw; } -void ThreadFunc() { - A a; // Throws an exception from a’s constructor and does not handle it in - // thread_func() -} -void F3() { - try { - std::thread t(&ThreadFunc); // Non-compliant - std::terminate() called - // on throwing an exception from - // thread_func() - - if (F1()) { - throw std::logic_error("Error4"); - } - - else { - F2(); // Non-compliant - std::terminate() called if there is no - // active exception to be re-thrown by f2 - } - } catch (...) { - B b; // Non-compliant - std::terminate() called on throwing an - // exception from b’s destructor during exception handling - - // ... - F2(); - } -} -static A a; // Non-compliant - std::terminate() called on throwing an exception - // during program’s start-up phase -int main(int, char **) { - F3(); // Non-compliant - std::terminate() called if std::logic_error is - // thrown - return 0; -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A16-0-1/standard-example.cpp b/cpp/autosar/src/rules/A16-0-1/standard-example.cpp deleted file mode 100644 index 4de09dbe32..0000000000 --- a/cpp/autosar/src/rules/A16-0-1/standard-example.cpp +++ /dev/null @@ -1,51 +0,0 @@ -// $Id: A16-0-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -#pragma once // Non-compliant - implementation-defined feature - -#ifndef HEADER_FILE_NAME // Compliant - include guard -#define HEADER_FILE_NAME // Compliant - include guard - -#include // Compliant - unconditional file inclusion - -#ifdef WIN32 -#include // Compliant - conditional file inclusion -#endif - -#ifdef WIN32 - std::int32_t fn1( - std::int16_t x, - std::int16_t y) noexcept; // Non-compliant - not a file inclusion -#endif - -#if defined VERSION && VERSION > 2011L // Compliant - #include // Compliant - conditional file inclusion -#elif VERSION > 1998L // Compliant - #include // Compliant - conditional file inclusion -#endif // Compliant - -#define MAX_ARRAY_SIZE 1024U // Non-compliant -#ifndef MAX_ARRAY_SIZE // Non-compliant - #error "MAX_ARRAY_SIZE has not been defined" // Non-compliant -#endif // Non-compliant -#undef MAX_ARRAY_SIZE // Non-compliant - -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) // Non-compliant - -#define PLUS2(X) ((X) + 2) // Non-compliant - function should be used instead -#define PI 3.14159F// Non-compliant - constexpr should be used instead -#define std ::int32_t long // Non-compliant - ’using’ should be used instead -#define STARTIF if( // Non-compliant - language redefinition -#define HEADER "filename.h" // Non-compliant - string literal - -void Fn2() noexcept -{ - #ifdef __linux__ // Non-compliant - ifdef not used for file inclusion - // ... - #elif WIN32 // Non-compliant - elif not used for file inclusion - // ... - #elif __APPLE__ // Non-compliant - elif not used for file inclusion - // ... - #else // Non-compliant - else not used for file inclusion - // ... - #endif // Non-compliant - endif not used for file inclusion or include guards -} -#endif // Compliant - include guard \ No newline at end of file diff --git a/cpp/autosar/src/rules/A16-2-1/standard-example.cpp b/cpp/autosar/src/rules/A16-2-1/standard-example.cpp deleted file mode 100644 index 05b742a718..0000000000 --- a/cpp/autosar/src/rules/A16-2-1/standard-example.cpp +++ /dev/null @@ -1,10 +0,0 @@ -// $Id: A16-2-1.cpp 271687 2017-03-23 08:57:35Z piotr.tanski $ - -// #include // Compliant -// #include // Compliant -// #include "directory/headerfile.hpp" // Compliant -// #include "headerfile.hpp" // Compliant -// #include // Non-compliant -// #include // Non-compliant -// #include <"headerfile.hpp"> // Non-compliant -// #include // Non-compliant \ No newline at end of file diff --git a/cpp/autosar/src/rules/A16-2-2/standard-example.cpp b/cpp/autosar/src/rules/A16-2-2/standard-example.cpp deleted file mode 100644 index 07dcb1dd16..0000000000 --- a/cpp/autosar/src/rules/A16-2-2/standard-example.cpp +++ /dev/null @@ -1,23 +0,0 @@ -// $Id: A16-2-2.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -#include // Non-compliant - nothing from algorithm header file is used -#include // Non-compliant - nothing from array header file is used -#include // Compliant - std::int32_t, std::uint8_t are used -#include // Compliant - cout is used -#include // Compliant - out_of_range is used -#include // Compliant - vector is used -void Fn1() noexcept { - std::int32_t x = 0; - // ... - std::uint8_t y = 0; - // ... -} -void Fn2() noexcept(false) { - try { - std::vector v; - // ... - std::uint8_t idx = 3; - std::int32_t value = v.at(idx); - } catch (std::out_of_range &e) { - std::cout << e.what() << ’\n’; - } -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A16-6-1/standard-example.cpp b/cpp/autosar/src/rules/A16-6-1/standard-example.cpp deleted file mode 100644 index ebbd826b31..0000000000 --- a/cpp/autosar/src/rules/A16-6-1/standard-example.cpp +++ /dev/null @@ -1,19 +0,0 @@ -// $Id: A16-6-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -#include -#include -constexpr std::int32_t value = 0; -#if value > 10 - #error "Incorrect value" // Non-compliant -#endif -void F1() noexcept -{ - static_assert(value <= 10, "Incorrect value"); // Compliant - // ... -} -template -void F2(T& a) -{ - static_assert(std::is_copy_constructible::value, - "f2() function requires copying"); // Compliant - // ... -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A16-7-1/standard-example.cpp b/cpp/autosar/src/rules/A16-7-1/standard-example.cpp deleted file mode 100644 index 09079b8813..0000000000 --- a/cpp/autosar/src/rules/A16-7-1/standard-example.cpp +++ /dev/null @@ -1,6 +0,0 @@ -// $Id: A16-7-1.hpp 270497 2017-03-14 14:58:50Z piotr.tanski $ -// #pragma once // Non-compliant - implementation-defined manner -#ifndef A16_7_1_HPP // Compliant - equivalent to #pragma once directive - #define A16_7_1_HPP - // ... -#endif \ No newline at end of file diff --git a/cpp/autosar/src/rules/A17-0-1/standard-example.cpp b/cpp/autosar/src/rules/A17-0-1/standard-example.cpp deleted file mode 100644 index ad453dac51..0000000000 --- a/cpp/autosar/src/rules/A17-0-1/standard-example.cpp +++ /dev/null @@ -1,3 +0,0 @@ -// $Id: A17-0-1.cpp 271389 2017-03-21 14:41:05Z piotr.tanski $ -#undef __TIME__ // Non-compliant -#define __LINE__ 20 // Non-compliant \ No newline at end of file diff --git a/cpp/autosar/src/rules/A17-1-1/standard-example.cpp b/cpp/autosar/src/rules/A17-1-1/standard-example.cpp deleted file mode 100644 index 7c0afaeba9..0000000000 --- a/cpp/autosar/src/rules/A17-1-1/standard-example.cpp +++ /dev/null @@ -1,54 +0,0 @@ -// $Id: A17-1-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -#include -#include -#include -#include -#include - -void Fn1(const char *filename) // Compliant - C code is isolated; fn1() - // function is a wrapper. -{ - FILE *handle = fopen(filename, "rb"); - if (handle == NULL) { - throw std::system_error(errno, std::system_category()); - } - // ... - fclose(handle); -} - -void Fn2() noexcept { - try { - Fn1("filename.txt"); // Compliant - fn1() allows you to use C code like - // C++ code - - // ... - } catch (std::system_error &e) { - std::cerr << "Error: " << e.code() << " - " << e.what() << ’\n’; - } -} - -std::int32_t Fn3(const char *filename) noexcept // Non-compliant - placing C -// functions calls along with C++ -// code forces a developer to be -// responsible for C-specific error -// handling, explicit resource -// cleanup, etc. -{ - FILE *handle = fopen(filename, "rb"); - if (handle == NULL) { - std::cerr << "An error occured: " << errno << " - " << strerror(errno) - << ’\n’; - return errno; - } - - try { - // ... - fclose(handle); - } catch (std::system_error &e) { - fclose(handle); - } catch (std::exception &e) { - fclose(handle); - } - - return errno; -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A17-6-1/standard-example.cpp b/cpp/autosar/src/rules/A17-6-1/standard-example.cpp deleted file mode 100644 index 48d11eb9bd..0000000000 --- a/cpp/autosar/src/rules/A17-6-1/standard-example.cpp +++ /dev/null @@ -1,52 +0,0 @@ -// $Id: A17-6-1.cpp 305588 2018-01-29 11:07:35Z michal.szczepankiewicz $ -#include -#include -#include -#include -#include -namespace std -{ - // Non-compliant - An alias definition is added to namespace std. - // This is a compile error in C++17, since std::byte is already defined. - using byte = std::uint8_t; - - // Non-compliant - A function definition added to namespace std. - pair operator+(pair const& x, pair const& y) - { - return pair(x.first + y.first, x.second + y.second); - } - -} // namespace std - -struct MyType -{ - int value; -}; - -namespace std -{ - // Non-compliant - std::numeric_limits may not be specialized for - // non-arithmetic types [limits.numeric]. - template <> - struct numeric_limits : numeric_limits - { - }; - - // Non-compliant - Structures in , except for std::common_type, // may not be specialized [meta.type.synop]. - template <> - struct is_arithmetic : true_type - { - }; - - // Compliant - std::hash may be specialized for a user type if the - // specialization fulfills the requirements in [unord.hash]. - template <> - struct hash - { - using result_type = size_t; // deprecated in C++17 using argument_type = MyType; // deprecated in C++17 - size_t operator()(MyType const& x) const noexcept - { - return hash()(x.value); - } - }; -} // namespace std \ No newline at end of file diff --git a/cpp/autosar/src/rules/A18-0-2/standard-example.cpp b/cpp/autosar/src/rules/A18-0-2/standard-example.cpp deleted file mode 100644 index 634b432b4d..0000000000 --- a/cpp/autosar/src/rules/A18-0-2/standard-example.cpp +++ /dev/null @@ -1,34 +0,0 @@ -// $Id: A18-0-2.cpp 312092 2018-03-16 15:47:01Z jan.babst $ -#include -#include -#include -#include - -std::int32_t F1(const char* str) noexcept -{ -return atoi(str); // Non-compliant - undefined behavior if str can not - // be converted -} -std::int32_t F2(std::string const& str) noexcept(false) -{ -return std::stoi(str); // Compliant - throws a std::invalid_argument - // exception if str can not be converted -} -std::uint16_t ReadFromStdin1() // non-compliant -{ -std::uint16_t a; -std::cin >> a; // no error detection -return a; -} -std::uint16_t ReadFromStdin2() // compliant -{ -std::uint16_t a; -std::cin.clear(); // clear all flags -std::cin >> a; -if (std::cin.fail()) -{ -throw std::runtime_error{"unable to read an integer"}; -} -std::cin.clear(); // clear all flags for subsequent operations -return a; -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A18-1-1/standard-example.cpp b/cpp/autosar/src/rules/A18-1-1/standard-example.cpp deleted file mode 100644 index ac83e88eb0..0000000000 --- a/cpp/autosar/src/rules/A18-1-1/standard-example.cpp +++ /dev/null @@ -1,19 +0,0 @@ -// $Id: A18-1-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -#include -#include -#include -void Fn() noexcept -{ - const std::uint8_t size = 10; - std::int32_t a1[size]; // Non-compliant - std::array a2; // Compliant - // ... - std::sort(a1, a1 + size); - std::sort(a2.begin(), a2.end()); // More readable and maintainable way of - // working with STL algorithms -} -class A -{ - public: - static constexpr std::uint8_t array[]{0, 1, 2}; // Compliant by exception -}; \ No newline at end of file diff --git a/cpp/autosar/src/rules/A18-1-2/standard-example.cpp b/cpp/autosar/src/rules/A18-1-2/standard-example.cpp deleted file mode 100644 index e6ac4ab384..0000000000 --- a/cpp/autosar/src/rules/A18-1-2/standard-example.cpp +++ /dev/null @@ -1,20 +0,0 @@ -// $Id: A18-1-2.cpp 312108 2018-03-16 17:56:49Z jan.babst $ -#include -#include - -class BoolWrapper -{ - public: - BoolWrapper() = default; - constexpr BoolWrapper(bool b) : b_(b) {} // implicit by design - constexpr operator bool() const { return b_; } // implicit by design - private: - bool b_{}; -}; - -void Fn() noexcept -{ - std::vector v1; // Compliant - std::vector v2; // Non-compliant - std::vector v3{true, false, true, false}; // Compliant -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A18-1-3/standard-example.cpp b/cpp/autosar/src/rules/A18-1-3/standard-example.cpp deleted file mode 100644 index 4c5f55c7f5..0000000000 --- a/cpp/autosar/src/rules/A18-1-3/standard-example.cpp +++ /dev/null @@ -1,11 +0,0 @@ -// $Id: A18-1-3.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -#include -#include -#include -void Fn() noexcept -{ - std::auto_ptr ptr1(new std::int32_t(10)); // Non-compliant - std::unique_ptr ptr2 = - std::make_unique(10); // Compliant - std::vector> v; // Non-compliant -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A18-1-4/standard-example.cpp b/cpp/autosar/src/rules/A18-1-4/standard-example.cpp deleted file mode 100644 index 16d7065d2a..0000000000 --- a/cpp/autosar/src/rules/A18-1-4/standard-example.cpp +++ /dev/null @@ -1,42 +0,0 @@ -// $Id: A18-1-4.cpp 313638 2018-03-26 15:34:51Z jan.babst $ -#include -class A {}; -void F1() { - // Create a dynamically allocated array of 10 objects of type A. - auto up1 = std::make_unique(10); // Compliant - - std::unique_ptr up2{up1.release()}; // Non-compliant -} -void F2() { - auto up1 = std::make_unique(10); // Compliant - - std::unique_ptr up2; - up2.reset(up1.release()); // Non-compliant -} -void F3() { - auto up = std::make_unique(10); // Compliant - - std::shared_ptr sp{up.release()}; // Non-compliant -} -void F4() { - auto up = std::make_unique(10); // Compliant - - std::shared_ptr sp; - sp.reset(up.release()); // Non-compliant -} -void F5() { - auto up = std::make_unique(10); // Compliant - - // sp will obtain its deleter from up, so the array will be correctly - // deallocated. However, this is no longer allowed in C++17. - std::shared_ptr sp{std::move(up)}; // Non-compliant - sp.reset(new A{}); // leads to undefined behavior -} -void F6() { - auto up = std::make_unique(10); // Compliant - - // Well behaving, but error-prone - std::shared_ptr sp{up.release(), - std::default_delete{}}; // Non-compliant - sp.reset(new A{}); // leads to undefined behavior -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A18-1-6/standard-example.cpp b/cpp/autosar/src/rules/A18-1-6/standard-example.cpp deleted file mode 100644 index e9a5baa447..0000000000 --- a/cpp/autosar/src/rules/A18-1-6/standard-example.cpp +++ /dev/null @@ -1,73 +0,0 @@ -#include -#include -#include -#include -class A -{ - public: - A(uint32_t x, uint32_t y) noexcept : x(x), y(y) {} - uint32_t GetX() const noexcept { return x; } - uint32_t GetY() const noexcept { return y; } - - friend bool operator == (const A &lhs, const A &rhs) noexcept - { return lhs.x == rhs.x && lhs.y == rhs.y; } - private: - uint32_t x; - uint32_t y; -}; - -class B -{ - public: - B(uint32_t x, uint32_t y) noexcept : x(x), y(y) {} - uint32_t GetX() const noexcept { return x; } - uint32_t GetY() const noexcept { return y; } - - friend bool operator == (const B &lhs, const B &rhs) noexcept - { return lhs.x == rhs.x && lhs.y == rhs.y; } - private: - uint32_t x; uint32_t y; }; - -namespace std -{ - // Compliant - template <> struct hash { - std::size_t operator()(const A& a) const noexcept - { - auto h1 = std::hash{}(a.GetX()); - std::size_t seed { h1 + 0x9e3779b9 }; - auto h2 = std::hash{}(a.GetY()); - seed ^= h2 + 0x9e3779b9 + (seed << 6) + (seed >> 2); - return seed; - } - }; - - // Non-compliant: string concatenation can potentially throw - template <> - struct hash - { - std::size_t operator()(const B& b) const - { - std::string s{std::to_string(b.GetX()) + ',' + std::to_string(b.GetY())}; - return std::hash{}(s); - } - }; -} - -int main() -{ - std::unordered_map m1 { { A{5, 7}, true } }; - - if (m1.count(A{4, 3}) != 0) - { - // .... - } - - std::unordered_map m2 { { B{5, 7}, true } }; - - // Lookup can potentially throw if hash function throws - if (m2.count(B{4, 3}) != 0) - { - // .... - } -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A18-5-1/standard-example.cpp b/cpp/autosar/src/rules/A18-5-1/standard-example.cpp deleted file mode 100644 index 8aa440efdc..0000000000 --- a/cpp/autosar/src/rules/A18-5-1/standard-example.cpp +++ /dev/null @@ -1,51 +0,0 @@ -// $Id: A18-5-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -#include -#include -void F1() noexcept(false) -{ - // Non-compliant - std::int32_t* p1 = static_cast(malloc(sizeof(std::int32_t))); - *p1 = 0; - - // Compliant - std::int32_t* p2 = new std::int32_t(0); - - // Compliant - delete p2; - - // Non-compliant - free(p1); - - // Non-compliant - std::int32_t* array1 = static_cast(calloc(10, sizeof(std::int32_t))); - - // Non-compliant - std::int32_t* array2 = - static_cast(realloc(array1, 10 * sizeof(std::int32_t))); - - // Compliant - std::int32_t* array3 = new std::int32_t[10]; - - // Compliant - delete[] array3; - - // Non-compliant - free(array2); - - // Non-compliant - free(array1); -} -void F2() noexcept(false) -{ - // Non-compliant - std::int32_t* p1 = static_cast(malloc(sizeof(std::int32_t))); - // Non-compliant - undefined behavior - delete p1; - - std::int32_t* p2 = new std::int32_t(0); // Compliant - free(p2); // Non-compliant - undefined behavior -} -void operator delete(void* ptr) noexcept -{ - std::free(ptr); // Compliant by exception -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A18-5-10/standard-example.cpp b/cpp/autosar/src/rules/A18-5-10/standard-example.cpp deleted file mode 100644 index 4ace128da8..0000000000 --- a/cpp/autosar/src/rules/A18-5-10/standard-example.cpp +++ /dev/null @@ -1,14 +0,0 @@ -//% $Id: A18-5-10.cpp 305629 2018-01-29 13:29:25Z piotr.serwa $ -#include -#include -void Foo() { - uint8_t c; - uint64_t *ptr = ::new (&c) uint64_t; - // non-compliant, insufficient storage -} -void Bar() { - uint8_t c; // Used elsewhere in the function - uint8_t buf[sizeof(uint64_t)]; - uint64_t *ptr = ::new (buf) uint64_t; - // non-compliant, storage not properly aligned -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A18-5-11/standard-example.cpp b/cpp/autosar/src/rules/A18-5-11/standard-example.cpp deleted file mode 100644 index 7b99525fb3..0000000000 --- a/cpp/autosar/src/rules/A18-5-11/standard-example.cpp +++ /dev/null @@ -1,17 +0,0 @@ -//% $Id: A18-5-11.cpp 316977 2018-04-20 12:37:31Z christof.meerwald $ -#include - -class A { -public: - static void *operator new(std::size_t s); // Compliant: operator new - static void operator delete(void *ptr); // defined together with - // operator delete -}; - -class B { -public: - static void *operator new(std::size_t s); // Non-compliant: operator - static void *operator new[](std::size_t s); // new defined without - // corresponding operator - // delete -}; \ No newline at end of file diff --git a/cpp/autosar/src/rules/A18-5-2/standard-example.cpp b/cpp/autosar/src/rules/A18-5-2/standard-example.cpp deleted file mode 100644 index 2cce855159..0000000000 --- a/cpp/autosar/src/rules/A18-5-2/standard-example.cpp +++ /dev/null @@ -1,63 +0,0 @@ -// $Id: A18-5-2.cpp 316977 2018-04-20 12:37:31Z christof.meerwald $ -#include -#include -#include -std::int32_t Fn1() { - std::int32_t errorCode{0}; - std::int32_t *ptr = new std::int32_t{0}; // Non-compliant - new expression - // ... - if (errorCode != 0) { - throw std::runtime_error{"Error"}; // Memory leak could occur here - } - // ... - if (errorCode != 0) { - return 1; // Memory leak could occur here - } - // ... - delete ptr; // Non-compliant - delete expression - return errorCode; -} -std::int32_t Fn2() { - std::int32_t errorCode{0}; - std::unique_ptr ptr1 = std::make_unique( - 0); // Compliant - alternative for ’new std::int32_t(0)’ - std::unique_ptr ptr2( - new std::int32_t{0}); // Non-compliant - unique_ptr provides make_unique - // function which shall be used instead of explicit - // new expression - std::shared_ptr ptr3 = - std::make_shared(0); // Compliant - std::vector array; // Compliant - // alternative for dynamic array - if (errorCode != 0) { - throw std::runtime_error{"Error"}; // No memory leaks - } - // ... - if (errorCode != 0) { - return 1; // No memory leaks - } - // ... - return errorCode; // No memory leaks -} -template class ObjectManager { -public: - explicit ObjectManager(T *obj) : object{obj} {} - ~ObjectManager() { delete object; } // Compliant by exception - // Implementation -private: - T *object; -}; -std::int32_t Fn3() { - std::int32_t errorCode{0}; - ObjectManager manager{ - new std::int32_t{0}}; // Compliant by exception - if (errorCode != 0) { - throw std::runtime_error{"Error"}; // No memory leak - } - // ... - if (errorCode != 0) { - return 1; // No memory leak - } - // ... - return errorCode; // No memory leak -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A18-5-3/standard-example.cpp b/cpp/autosar/src/rules/A18-5-3/standard-example.cpp deleted file mode 100644 index 2f687d9b7c..0000000000 --- a/cpp/autosar/src/rules/A18-5-3/standard-example.cpp +++ /dev/null @@ -1,30 +0,0 @@ -// $Id: A18-5-3.cpp 316977 2018-04-20 12:37:31Z christof.meerwald $ -#include - -void Fn1() -{ - std::int32_t* array = - new std::int32_t[10]; // new expression used to allocate an - // array object - // ... - delete array; // Non-compliant - array delete expression supposed - // to be used -} -void Fn2() -{ - std::int32_t* object = new std::int32_t{0}; // new operator used to - // allocate the memory for an - // integer type - // ... - delete[] object; // Non-compliant - non-array delete expression supposed - // to be used - -} -void Fn3() -{ - std::int32_t* object = new std::int32_t{0}; - std::int32_t* array = new std::int32_t[10]; - // ... - delete[] array; // Compliant - delete object; // Compliant -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A18-5-4/standard-example.cpp b/cpp/autosar/src/rules/A18-5-4/standard-example.cpp deleted file mode 100644 index fa15081106..0000000000 --- a/cpp/autosar/src/rules/A18-5-4/standard-example.cpp +++ /dev/null @@ -1,12 +0,0 @@ -//% $Id: A18-5-4.cpp 289415 2017-10-04 09:10:20Z piotr.serwa $ -#include -void operator delete(void *ptr) noexcept // Compliant - sized version is defined -{ - std::free(ptr); -} -void operator delete( - void *ptr, - std::size_t size) noexcept // Compliant - unsized version is defined -{ - std::free(ptr); -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A18-5-5/standard-example.cpp b/cpp/autosar/src/rules/A18-5-5/standard-example.cpp deleted file mode 100644 index ba61ad7ec4..0000000000 --- a/cpp/autosar/src/rules/A18-5-5/standard-example.cpp +++ /dev/null @@ -1,31 +0,0 @@ -//% $Id: A18-5-5.cpp 289815 2017-10-06 11:19:11Z michal.szczepankiewicz $ -#define __GNU_SOURCE -#include -#include -void* MallocBad(size_t size) // Non-compliant, malloc from libc does not - // guarantee deterministic execution time -{ - void* (*libcMalloc)(size_t) = (void* (*)(size_t))dlsym(RTLD_NEXT, "malloc"); - return libcMalloc(size); -} - -void FreeBad(void* ptr) // Non-compliant, malloc from libc does not guarantee - // deterministic execution time -{ - void (*libcFree)(void*) = (void (*)(void*))dlsym(RTLD_NEXT, "free"); - libcFree(ptr); -} - -void* MallocGood(size_t size) // Compliant - custom malloc implementation that - // will guarantee deterministic execution time -{ - // Custom implementation that provides deterministic worst-case execution - // time -} - -void FreeGood(void* ptr) // Compliant - custom malloc implementation that will - // guarantee deterministic execution time -{ - // Custom implementation that provides deterministic worst-case execution - // time -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A18-5-8/standard-example.cpp b/cpp/autosar/src/rules/A18-5-8/standard-example.cpp deleted file mode 100644 index 2a618c07aa..0000000000 --- a/cpp/autosar/src/rules/A18-5-8/standard-example.cpp +++ /dev/null @@ -1,32 +0,0 @@ -//% $Id: A18-5-8.cpp 311792 2018-03-15 04:15:08Z christof.meerwald $ -#include -#include -#include -class StackBitmap { -public: - constexpr static size_t maxSize = 65535; - using BitmapRawType = std::array; - StackBitmap(const std::string &path, uint32_t bitmapSize) { - // read bitmapSize bytes from the file path - } - const BitmapRawType &GetBitmap() const noexcept { return bmp; } - -private: - BitmapRawType bmp; -}; -void AddWidgetToLayout(int32_t row, int32_t col) { - auto idx = std::make_pair(row, col); // Compliant - auto spIdx = - std::make_shared>(row, col); // Non-compliant - // addWidget to index idx -} -uint8_t CalcAverageBitmapColor(const std::string &path, uint32_t bitmapSize) { - std::vector bmp1(bitmapSize); // Compliant - // read bitmap from path - StackBitmap bmp2(path, bitmapSize); // Non-compliant - bmp2.GetBitmap(); -} -int main(int, char **) { - AddWidgetToLayout(5, 8); - CalcAverageBitmapColor("path/to/bitmap.bmp", 32000); -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A18-5-9/standard-example.cpp b/cpp/autosar/src/rules/A18-5-9/standard-example.cpp deleted file mode 100644 index ca6de1b2f3..0000000000 --- a/cpp/autosar/src/rules/A18-5-9/standard-example.cpp +++ /dev/null @@ -1,8 +0,0 @@ -//% $Id: A18-5-9.cpp 305629 2018-01-29 13:29:25Z piotr.serwa $ -#include -void *operator new(std::size_t count, const std::nothrow_t &tag) { - extern void *custom_alloc(std::size_t); // Implemented elsewhere; may return - nullptr if (void *ret = custom_alloc(count)) { return ret; } - throw std::bad_alloc(); // non-compliant, this version of new method shall not - // throw exceptions -} diff --git a/cpp/autosar/src/rules/A18-9-1/standard-example.cpp b/cpp/autosar/src/rules/A18-9-1/standard-example.cpp deleted file mode 100644 index cf578902d6..0000000000 --- a/cpp/autosar/src/rules/A18-9-1/standard-example.cpp +++ /dev/null @@ -1,29 +0,0 @@ -// $Id: A18-9-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -#include -#include -class A -{ - // Implementation -}; -void Fn(A const& a, double y) noexcept -{ - // Implementation -} -void F1() noexcept -{ - double y = 0.0; - auto function = std::bind(&Fn, std::placeholders::_1, y); // Non-compliant - // ... - A const a{}; - function(a); -} -void F2() noexcept -{ - auto lambda = [](A const& a) -> void { - double y = 0.0; - Fn(a, y); - }; // Compliant - // ... - A const a{}; - lambda(a); -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A18-9-2/standard-example.cpp b/cpp/autosar/src/rules/A18-9-2/standard-example.cpp deleted file mode 100644 index 8cf6e3db8c..0000000000 --- a/cpp/autosar/src/rules/A18-9-2/standard-example.cpp +++ /dev/null @@ -1,45 +0,0 @@ -// $Id: A18-9-2.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -#include -#include -#include -class A -{ - public: - explicit A(std::string&& s) - : str(std::move(s)) - { - } - - private: - std::string str; -}; -class B -{ -}; -void Fn1(const B& lval) -{ - // Compliant - forwarding rvalue reference -} -void Fn1(B&& rval) -{ -} -template -void Fn2(T&& param) -{ - Fn1(std::forward(param)); // Compliant - forwarding forwarding reference -} -template -void Fn3(T&& param) -{ - Fn1(std::move(param)); // Non-compliant - forwarding forwarding reference - // via std::move -} -void Fn4() noexcept -{ - B b1; - B& b2 = b1; - Fn2(b2); // fn1(const B&) is called - Fn2(std::move(b1)); // fn1(B&&) is called - Fn3(b2); // fn1(B&&) is called - Fn3(std::move(b1)); // fn1(B&&) is called -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A18-9-3/standard-example.cpp b/cpp/autosar/src/rules/A18-9-3/standard-example.cpp deleted file mode 100644 index 3a4184a89e..0000000000 --- a/cpp/autosar/src/rules/A18-9-3/standard-example.cpp +++ /dev/null @@ -1,13 +0,0 @@ -// $Id: A18-9-3.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -#include -class A -{ - // Implementation -}; -void F1() -{ - const A a1{}; - A a2 = a1; // Compliant - copy constructor is called - A a3 = std::move(a1); // Non-compliant - copy constructor is called - // implicitly instead of move constructor -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A18-9-4/standard-example.cpp b/cpp/autosar/src/rules/A18-9-4/standard-example.cpp deleted file mode 100644 index 6cc31b5dd1..0000000000 --- a/cpp/autosar/src/rules/A18-9-4/standard-example.cpp +++ /dev/null @@ -1,14 +0,0 @@ -// $Id: A18-9-4.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $ -#include -#include -#include -template -void F1(T1 const& t1, T2& t2){ - // ... -}; -template -void F2(T1&& t1, T2&& t2) -{ - f1(std::forward(t1), std::forward(t2)); - ++t2; // Non-compliant -}; \ No newline at end of file diff --git a/cpp/autosar/src/rules/A2-10-1/standard-example.cpp b/cpp/autosar/src/rules/A2-10-1/standard-example.cpp deleted file mode 100644 index 706e794e28..0000000000 --- a/cpp/autosar/src/rules/A2-10-1/standard-example.cpp +++ /dev/null @@ -1,51 +0,0 @@ -//% $Id: A2-10-1.cpp 313834 2018-03-27 11:35:19Z michal.szczepankiewicz $ -#include -std::int32_t sum = 0; -namespace -{ - std::int32_t sum; // Non-compliant, hides sum in outer scope -} -class C1 -{ - std::int32_t sum; // Compliant, does not hide sum in outer scope -}; -namespace n1 -{ - std::int32_t sum; // Compliant, does not hide sum in outer scope - namespace n2 - { - std::int32_t sum; // Compliant, does not hide sum in outer scope - } -} - -std::int32_t idx; -void F1(std::int32_t idx) -{ - //Non-compliant, hides idx in outer scope -} - -void F2() -{ - std::int32_t max = 5; - - for (std::int32_t idx = 0; idx < max; - ++idx) // Non-compliant, hides idx in outer scope - { - for (std::int32_t idx = 0; idx < max; - ++idx) // Non-compliant, hides idx in outer scope - { - } - } -} - -void F3() -{ - std::int32_t i = 0; - std::int32_t j = 0; - auto lambda = [i]() { - std::int32_t j = - 10; // Compliant - j was not captured, so it does not hide - // j in outer scope - return i + j; - }; -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A2-10-4/standard-example.cpp b/cpp/autosar/src/rules/A2-10-4/standard-example.cpp deleted file mode 100644 index 637c033f3d..0000000000 --- a/cpp/autosar/src/rules/A2-10-4/standard-example.cpp +++ /dev/null @@ -1,23 +0,0 @@ -//% $Id: A2-10-4.cpp 305382 2018-01-26 06:32:15Z michal.szczepankiewicz $ -#include -// f1.cpp -namespace ns1 -{ - static std::int32_t globalvariable = 0; -} - -// f2.cpp -namespace ns1 -{ -// static std::int32_t globalvariable = 0; // Non-compliant - identifier reused -// in ns1 namespace in f1.cpp -} -namespace ns2 -{ - static std::int32_t globalvariable = - 0; // Compliant - identifier reused, but in another namespace -} - -// f3.cpp -static std::int32_t globalvariable = - 0; // Compliant - identifier reused, but in another namespace \ No newline at end of file diff --git a/cpp/autosar/src/rules/A2-10-5/standard-example.cpp b/cpp/autosar/src/rules/A2-10-5/standard-example.cpp deleted file mode 100644 index 56d54ca26c..0000000000 --- a/cpp/autosar/src/rules/A2-10-5/standard-example.cpp +++ /dev/null @@ -1,22 +0,0 @@ -//% $Id: A2-10-5.cpp 305382 2018-01-26 06:32:15Z michal.szczepankiewicz $ -#include -// f1.cpp -namespace n_s1 -{ - static std::int32_t globalvariable = 0; -} -static std::int32_t filevariable = 5; // Compliant - identifier not reused -static void Globalfunction(); - -// f2.cpp -namespace n_s1 -{ - // static std::int32_t globalvariable = 0; // Non-compliant - identifier reused - static std::int16_t modulevariable = 10; // Compliant - identifier not reused -} -namespace n_s2 -{ - static std::int16_t modulevariable2 = 20; -} -static void Globalfunction(); // Non-compliant - identifier reused -static std::int16_t modulevariable2 = 15; // Non-compliant - identifier reused \ No newline at end of file diff --git a/cpp/autosar/src/rules/A2-10-6/standard-example.cpp b/cpp/autosar/src/rules/A2-10-6/standard-example.cpp deleted file mode 100644 index b1a4e754a6..0000000000 --- a/cpp/autosar/src/rules/A2-10-6/standard-example.cpp +++ /dev/null @@ -1,35 +0,0 @@ -//% $Id: A2-10-6.cpp 313821 2018-03-27 11:16:14Z michal.szczepankiewicz $ -#include - -namespace NS1 { - class G {}; - void G() {} //non-compliant, hides class G -} - -namespace NS2 { - enum class H { VALUE=0, }; - std::uint8_t H = 17; //non-compliant, hides - //scoped enum H -} - -namespace NS3 { - class J {}; - enum H //does not hide NS2::H, but non-compliant to A7-2-3 - { - J=0, //non-compliant, hides class J - }; -} - -int main(void) -{ - NS1::G(); - //NS1::G a; //compilation error, NS1::G is a function - //after a name lookup procedure - class NS1::G a{}; //accessing hidden class type name - - enum NS2::H b ; //accessing scoped enum NS2::H - NS2::H = 7; - - class NS3::J c{}; //accessing hidden class type name - std::uint8_t z = NS3::J; -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A2-13-1/standard-example.cpp b/cpp/autosar/src/rules/A2-13-1/standard-example.cpp deleted file mode 100644 index 88dbd62aad..0000000000 --- a/cpp/autosar/src/rules/A2-13-1/standard-example.cpp +++ /dev/null @@ -1,8 +0,0 @@ -//% $Id: A2-13-1.cpp 305629 2018-01-29 13:29:25Z piotr.serwa $ -#include -void F() -{ - const std::string a = "\k"; // Non-compliant - const std::string b = "\n"; // Compliant - const std::string c = "\U0001f34c"; // Compliant -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A2-13-3/standard-example.cpp b/cpp/autosar/src/rules/A2-13-3/standard-example.cpp deleted file mode 100644 index 975c0cab1f..0000000000 --- a/cpp/autosar/src/rules/A2-13-3/standard-example.cpp +++ /dev/null @@ -1,4 +0,0 @@ -//% $Id: A2-13-3.cpp 305629 2018-01-29 13:29:25Z piotr.serwa $ -char16_t string1[] = u"ABC"; // Compliant -char32_t string2[] = U"DEF"; // Compliant -wchar_t string3[] = L"GHI"; // Non-compliant \ No newline at end of file diff --git a/cpp/autosar/src/rules/A2-13-4/standard-example.cpp b/cpp/autosar/src/rules/A2-13-4/standard-example.cpp deleted file mode 100644 index a0fbc8d9ed..0000000000 --- a/cpp/autosar/src/rules/A2-13-4/standard-example.cpp +++ /dev/null @@ -1,17 +0,0 @@ -//% $Id: A2-13-4.cpp 307578 2018-02-14 14:46:20Z michal.szczepankiewicz $ -int main(void) -{ - char* nc1 = "AUTOSAR"; //non-compliant - char nc2[] = "AUTOSAR"; //compliant with A2-13-4, non-compliant with A18 -1-1 - - char nc3[8] = "AUTOSAR"; //compliant with A2-13-4, non-compliant with A18 -1-1 - - nc1[3] = 'a'; // undefined behaviour - const char* c1 = "AUTOSAR"; //compliant - const char c2[] = "AUTOSAR"; //compliant with A2-13-4, non-compliant with A18-1-1 - - const char c3[8] = "AUTOSAR"; //compliant with A2-13-4, non-compliant with A18-1-1 - - //c1[3] = ’a’; //compilation error - return 0; -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A2-13-5/standard-example.cpp b/cpp/autosar/src/rules/A2-13-5/standard-example.cpp deleted file mode 100644 index a44d094112..0000000000 --- a/cpp/autosar/src/rules/A2-13-5/standard-example.cpp +++ /dev/null @@ -1,11 +0,0 @@ -//% $Id: A2-13-5.cpp 305629 2018-01-29 13:29:25Z piotr.serwa $ -#include - -int main(void) -{ - std::int16_t a = 0x0f0f; //non-compliant - std::int16_t b = 0x0f0F; //non-compliant - std::int16_t c = 0x0F0F; //compliant - - return 0; -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A2-13-6/standard-example.cpp b/cpp/autosar/src/rules/A2-13-6/standard-example.cpp deleted file mode 100644 index 0a3bd48609..0000000000 --- a/cpp/autosar/src/rules/A2-13-6/standard-example.cpp +++ /dev/null @@ -1,12 +0,0 @@ -//% $Id: A2-13-6.cpp 307578 2018-02-14 14:46:20Z michal.szczepankiewicz $ -#include -void F() -{ - const std::string c = "\U0001f34c"; // Compliant -} - -//non-compliant -void \U0001f615() -{ - // -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A2-3-1/standard-example.cpp b/cpp/autosar/src/rules/A2-3-1/standard-example.cpp deleted file mode 100644 index 71bedf986a..0000000000 --- a/cpp/autosar/src/rules/A2-3-1/standard-example.cpp +++ /dev/null @@ -1,9 +0,0 @@ -// $Id: A2-3-1.cpp 307578 2018-02-14 14:46:20Z michal.szczepankiewicz $ -#include -void Fn() noexcept -{ - std::int32_t sum = 0; // Compliant - // std::int32_t £_value = 10; // Non-compliant - // sum += £_value; // Non-compliant - // Variable sum stores £ pounds // Non-compliant -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A2-7-1/standard-example.cpp b/cpp/autosar/src/rules/A2-7-1/standard-example.cpp deleted file mode 100644 index 272d0dca2e..0000000000 --- a/cpp/autosar/src/rules/A2-7-1/standard-example.cpp +++ /dev/null @@ -1,13 +0,0 @@ -// $Id: A2-7-1.cpp 305382 2018-01-26 06:32:15Z michal.szczepankiewicz $ -#include -void Fn() noexcept -{ - std::int8_t idx = 0; - // Incrementing idx before the loop starts // Requirement X.X.X \\ - ++idx; // Non-compliant - ++idx was unexpectedly commented-out because of \ character occurrence in the end of C++ comment - constexpr std::int8_t limit = 10; - for (; idx <= limit; ++idx) - { - // ... - } -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A2-7-2/standard-example.cpp b/cpp/autosar/src/rules/A2-7-2/standard-example.cpp deleted file mode 100644 index 512f57147e..0000000000 --- a/cpp/autosar/src/rules/A2-7-2/standard-example.cpp +++ /dev/null @@ -1,34 +0,0 @@ -// $Id: A2-7-2.cpp 305382 2018-01-26 06:32:15Z michal.szczepankiewicz $ -#include -void Fn1() noexcept -{ - std::int32_t i = 0; - ///* - // /* ++i; /* incrementing the variable i */ - // * // Non-compliant - C-style comments nesting is not supported, - // compilation error - for (; i < 10; ++i) { - // ... - } -} -void Fn2() noexcept -{ - std::int32_t i = 0; - // ++i; // Incrementing the variable i // Non-compliant - code should not - // be commented-out - for (; i < 10; ++i) - { - // ... } - } -} -void Fn3() noexcept -{ - std::int32_t i = 0; - ++i; // Incrementing the variable i using ++i syntax // Compliant - code - // is not commented-out, but ++i occurs in a - // comment too - for (; i < 10; ++i) - { - // ... - } -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A2-7-3/standard-example.cpp b/cpp/autosar/src/rules/A2-7-3/standard-example.cpp deleted file mode 100644 index aecfdabc19..0000000000 --- a/cpp/autosar/src/rules/A2-7-3/standard-example.cpp +++ /dev/null @@ -1,39 +0,0 @@ -//% $Id: A2-7-3.hpp 305382 2018-01-26 06:32:15Z michal.szczepankiewicz $ -#include - -void F1(std::int32_t) noexcept; // Non-compliant documentation - -std::int32_t F2(std::int16_t input1, - std::int32_t input2); // Non-compliant documentation -/// @brief Function description -/// -/// @param input1 input1 parameter description -/// @param input2 input2 parameter description -/// @throw std::runtime_error conditions to runtime_error occur -/// -/// @return return value description -std::int32_t F3( - std::int16_t input1, - std::int16_t input2) noexcept(false); // Compliant documentation - -/// @brief Class responsibility -class C // Compliant documentation -{ - public: - /// @brief Constructor description - /// - /// @param input1 input1 parameter description - /// @param input2 input2 parameter description - C(std::int32_t input1, float input2) : x{input1}, y{input2} {} - - /// @brief Method description - /// - /// @return return value description - std::int32_t const* GetX() const noexcept { return &x; } - - private: - /// @brief Data member description - std::int32_t x; - /// @brief Data member description - float y; -}; diff --git a/cpp/autosar/src/rules/A20-8-1/standard-example.cpp b/cpp/autosar/src/rules/A20-8-1/standard-example.cpp deleted file mode 100644 index a18eb3122f..0000000000 --- a/cpp/autosar/src/rules/A20-8-1/standard-example.cpp +++ /dev/null @@ -1,14 +0,0 @@ -// $Id: A20-8-1.cpp 305588 2018-01-29 11:07:35Z michal.szczepankiewicz $ -#include -void Foo() -{ - uint32_t *i = new uint32_t{5}; - std::shared_ptr p1(i); - std::shared_ptr p2(i); // non-compliant -} - -void Bar() -{ - std::shared_ptr p1 = std::make_shared(5); - std::shared_ptr p2(p1); //compliant -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A20-8-2/standard-example.cpp b/cpp/autosar/src/rules/A20-8-2/standard-example.cpp deleted file mode 100644 index fa38046f29..0000000000 --- a/cpp/autosar/src/rules/A20-8-2/standard-example.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// $Id: A20-8-2.cpp 308981 2018-02-26 08:11:52Z michal.szczepankiewicz $ -#include -#include -struct A -{ - A(std::uint8_t xx, std::uint8_t yy) : x(xx), y(yy) {} - std::uint8_t x; - std::uint8_t y; -}; - -//consumes object obj or just uses it -void Foo(A* obj) { } -void Bar(std::unique_ptr obj) { } - -int main(void) -{ - A* a = new A(3,5); //non-compliant with A18-5-2 - std::unique_ptr spA = std::make_unique(3,5); - - //non-compliant, not clear if function assumes - //ownership of the object - std::thread th1{&Foo, a}; - std::thread th2{&Foo, a}; - //compliant, it is clear that function Bar - //assumes ownership - std::thread th3{&Bar, std::move(spA)}; - - th1.join(); - th2.join(); - th3.join(); - return 0; -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A20-8-3/standard-example.cpp b/cpp/autosar/src/rules/A20-8-3/standard-example.cpp deleted file mode 100644 index 5393fddd6d..0000000000 --- a/cpp/autosar/src/rules/A20-8-3/standard-example.cpp +++ /dev/null @@ -1,39 +0,0 @@ -// $Id: A20-8-3.cpp 308507 2018-02-21 13:23:57Z michal.szczepankiewicz $ -#include -#include -#include -struct A -{ - A(std::uint8_t xx, std::uint8_t yy) : x(xx), y(yy) {} - std::uint8_t x; - std::uint8_t y; -}; - -void Foo(A* obj) { } -void Bar(A* obj) { } - -void Foo2(std::shared_ptr obj) { } -void Bar2(std::shared_ptr obj) { } - -int main(void) -{ - A* a = new A(3,5); //non-compliant with A18-5-2 - std::shared_ptr spA = std::make_shared(3,5); - - //non-compliant, not clear who is responsible - //for deleting object a - std::thread th1{&Foo, a}; - std::thread th2{&Bar, a}; - - //compliant, object spA gets deleted - //when last shared_ptr gets destructed - std::thread th3{&Foo2, spA}; - std::thread th4{&Bar2, spA}; - - th1.join(); - th2.join(); - th3.join(); - th4.join(); - - return 0; -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A20-8-4/standard-example.cpp b/cpp/autosar/src/rules/A20-8-4/standard-example.cpp deleted file mode 100644 index 94509465bb..0000000000 --- a/cpp/autosar/src/rules/A20-8-4/standard-example.cpp +++ /dev/null @@ -1,40 +0,0 @@ -// $Id: A20-8-4.cpp 308507 2018-02-21 13:23:57Z michal.szczepankiewicz $ -#include -#include -#include -struct A -{ - A(std::uint8_t xx, std::uint8_t yy) : x(xx), y(yy) {} - std::uint8_t x; std::uint8_t y; -}; - -void Func() -{ - auto spA = std::make_shared(3,5); - //non-compliant, shared_ptr used only locally - //without copying it -} - -void Foo(std::unique_ptr obj) { } -void Bar(std::shared_ptr obj) { } - -int main(void) -{ - std::shared_ptr spA = std::make_shared(3,5); - std::unique_ptr upA = std::make_unique(4,6); - - //compliant, object accesses in parallel - std::thread th1{&Bar, spA}; - std::thread th2{&Bar, spA}; - std::thread th3{&Bar, spA}; - - //compliant, object accesses only by 1 thread - std::thread th4{&Foo, std::move(upA)}; - - th1.join(); - th2.join(); - th3.join(); - th4.join(); - - return 0; -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A20-8-5/standard-example.cpp b/cpp/autosar/src/rules/A20-8-5/standard-example.cpp deleted file mode 100644 index a46315a07e..0000000000 --- a/cpp/autosar/src/rules/A20-8-5/standard-example.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// $Id: A20-8-5.cpp 308507 2018-02-21 13:23:57Z michal.szczepankiewicz $ -#include -#include -#include -struct A -{ - A() { throw std::runtime_error("example"); } - A(std::uint8_t xx, std::uint8_t yy) : x(xx), y(yy) {} - std::uint8_t x; - std::uint8_t y; -}; - -void Foo(std::unique_ptr a, std::unique_ptr b) { } -int main(void) -{ - //compliant - std::unique_ptr upA = std::make_unique(4,6); - //non-compliant - std::unique_ptr upA2 = std::unique_ptr(new A(5,7)); - - //non-compliant, potential memory leak, as A class constructor throws - Foo(std::unique_ptr(new A()), std::unique_ptr(new A())); - //non-compliant, potential memory leak, as A class constructor throws - Foo(std::make_unique(4,6), std::unique_ptr(new A())); - //compliant, no memory leaks - Foo(std::make_unique(4,6), std::make_unique(4,6)); - - //compliant by exception - std::unique_ptr> ptr(new A(4,5), [](A* b) { delete b; } ); - - return 0; -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A20-8-6/standard-example.cpp b/cpp/autosar/src/rules/A20-8-6/standard-example.cpp deleted file mode 100644 index e6c6a36d74..0000000000 --- a/cpp/autosar/src/rules/A20-8-6/standard-example.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// $Id: A20-8-6.cpp 308507 2018-02-21 13:23:57Z michal.szczepankiewicz $ -#include -#include -#include -struct A -{ - A() { throw std::runtime_error("example"); } - A(std::uint8_t xx, std::uint8_t yy) : x(xx), y(yy) {} - std::uint8_t x; - std::uint8_t y; -}; - -void Foo(std::shared_ptr a, std::shared_ptr b) { } -int main(void) -{ - //compliant - std::shared_ptr upA = std::make_shared(4,6); - //non-compliant - std::shared_ptr upA2 = std::shared_ptr(new A(5,7)); - - //non-compliant, potential memory leak, as A class constructor throws - Foo(std::shared_ptr(new A()), std::shared_ptr(new A())); - //non-compliant, potential memory leak, as A class constructor throws - Foo(std::make_shared(4,6), std::shared_ptr(new A())); - //compliant, no memory leaks - Foo(std::make_shared(4,6), std::make_shared(4,6)); - - //compliant by exception - std::shared_ptr ptr(new A(4,5), [](A* b) { delete b; } ); - - return 0; -} \ No newline at end of file diff --git a/cpp/autosar/src/rules/A20-8-7/standard-example.cpp b/cpp/autosar/src/rules/A20-8-7/standard-example.cpp deleted file mode 100644 index 34ae460369..0000000000 --- a/cpp/autosar/src/rules/A20-8-7/standard-example.cpp +++ /dev/null @@ -1,50 +0,0 @@ -// $Id: A20-8-7.cpp 308795 2018-02-23 09:27:03Z michal.szczepankiewicz $ -#include -template