Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 0 additions & 15 deletions c/cert/src/rules/DCL40-C/ExternalIdentifiers.qll

This file was deleted.

41 changes: 5 additions & 36 deletions c/cert/src/rules/DCL40-C/IncompatibleFunctionDeclarations.ql
Original file line number Diff line number Diff line change
Expand Up @@ -21,42 +21,11 @@

import cpp
import codingstandards.c.cert
import codingstandards.cpp.types.Compatible
import ExternalIdentifiers
import codingstandards.cpp.rules.incompatiblefunctiondeclaration.IncompatibleFunctionDeclaration

predicate interestedInFunctions(
FunctionDeclarationEntry f1, FunctionDeclarationEntry f2, ExternalIdentifiers d
) {
not f1 = f2 and
d = f1.getDeclaration() and
d = f2.getDeclaration()
module IncompatibleFunctionDeclarationsCppConfig implements IncompatibleFunctionDeclarationConfigSig
{
Query getQuery() { result = Declarations2Package::incompatibleFunctionDeclarationsQuery() }
}

predicate interestedInFunctions(FunctionDeclarationEntry f1, FunctionDeclarationEntry f2) {
interestedInFunctions(f1, f2, _)
}

module FuncDeclEquiv =
FunctionDeclarationTypeEquivalence<TypesCompatibleConfig, interestedInFunctions/2>;

from ExternalIdentifiers d, FunctionDeclarationEntry f1, FunctionDeclarationEntry f2
where
not isExcluded(f1, Declarations2Package::incompatibleFunctionDeclarationsQuery()) and
not isExcluded(f2, Declarations2Package::incompatibleFunctionDeclarationsQuery()) and
interestedInFunctions(f1, f2, d) and
(
//return type check
not FuncDeclEquiv::equalReturnTypes(f1, f2)
or
//parameter type check
not FuncDeclEquiv::equalParameterTypes(f1, f2)
) and
// Apply ordering on start line, trying to avoid the optimiser applying this join too early
// in the pipeline
exists(int f1Line, int f2Line |
f1.getLocation().hasLocationInfo(_, f1Line, _, _, _) and
f2.getLocation().hasLocationInfo(_, f2Line, _, _, _) and
f1Line >= f2Line
)
select f1, "The object $@ is not compatible with re-declaration $@", f1, f1.getName(), f2,
f2.getName()
import IncompatibleFunctionDeclaration<IncompatibleFunctionDeclarationsCppConfig>
20 changes: 7 additions & 13 deletions c/cert/src/rules/DCL40-C/IncompatibleObjectDeclarations.ql
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* @name DCL40-C: Do not create incompatible declarations of the same function or object
* @description Declaring incompatible objects, in other words same named objects of different
* types, then accessing those objects can lead to undefined behaviour.
* @kind problem
* @ kind problem
* @precision high
* @problem.severity error
* @tags external/cert/id/dcl40-c
Expand All @@ -20,16 +20,10 @@

import cpp
import codingstandards.c.cert
import ExternalIdentifiers
import codingstandards.cpp.rules.incompatibleobjectdeclaration.IncompatibleObjectDeclaration

from VariableDeclarationEntry decl1, VariableDeclarationEntry decl2
where
not isExcluded(decl1, Declarations2Package::incompatibleObjectDeclarationsQuery()) and
not isExcluded(decl2, Declarations2Package::incompatibleObjectDeclarationsQuery()) and
not decl1.getUnspecifiedType() = decl2.getUnspecifiedType() and
decl1.getDeclaration() instanceof ExternalIdentifiers and
decl2.getDeclaration() instanceof ExternalIdentifiers and
decl1.getLocation().getStartLine() >= decl2.getLocation().getStartLine() and
decl1.getVariable().getName() = decl2.getVariable().getName()
select decl1, "The object $@ is not compatible with re-declaration $@", decl1, decl1.getName(),
decl2, decl2.getName()
module IncompatibleObjectDeclarationsCppConfig implements IncompatibleObjectDeclarationConfigSig {
Query getQuery() { result = Declarations2Package::incompatibleObjectDeclarationsQuery() }
}

import IncompatibleObjectDeclaration<IncompatibleObjectDeclarationsCppConfig>

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
c/common/test/rules/incompatiblefunctiondeclaration/IncompatibleFunctionDeclaration.ql

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
c/common/test/rules/incompatibleobjectdeclaration/IncompatibleObjectDeclaration.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
| test1.c:4:12:4:12 | declaration of f | The object is not compatible with a re-declaration $@. | test.c:4:6:4:6 | definition of f | f |
| test.c:4:6:4:6 | definition of f | The object is not compatible with a re-declaration $@. | test1.c:4:12:4:12 | declaration of f | f |
| test.c:8:6:8:7 | declaration of f1 | The object is not compatible with a re-declaration $@. | test1.c:5:13:5:14 | declaration of f1 | f1 |
| test.c:9:6:9:7 | definition of f2 | The object is not compatible with a re-declaration $@. | test1.c:6:6:6:7 | definition of f2 | f2 |
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// GENERATED FILE - DO NOT MODIFY
import codingstandards.cpp.rules.incompatiblefunctiondeclaration.IncompatibleFunctionDeclaration

module TestFileConfig implements IncompatibleFunctionDeclarationConfigSig {
Query getQuery() { result instanceof TestQuery }
}

import IncompatibleFunctionDeclaration<TestFileConfig>
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
| test1.c:2:12:2:12 | declaration of i | The object is not compatible with a re-declaration $@. | test.c:1:7:1:7 | definition of i | i |
| test.c:2:5:2:5 | definition of a | The object is not compatible with a re-declaration $@. | test1.c:1:13:1:13 | declaration of a | a |
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// GENERATED FILE - DO NOT MODIFY
import codingstandards.cpp.rules.incompatibleobjectdeclaration.IncompatibleObjectDeclaration

module TestFileConfig implements IncompatibleObjectDeclarationConfigSig {
Query getQuery() { result instanceof TestQuery }
}

import IncompatibleObjectDeclaration<TestFileConfig>
10 changes: 10 additions & 0 deletions c/common/test/rules/incompatibleobjectdeclaration/test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
short i; // NON_COMPLIANT
int a[] = {1, 2, 3, 4}; // NON_COMPLIANT

long f(int a) { // NON_COMPLIANT
return a * 2;
}

void f1(long a); // NON_COMPLIANT
void f2() {} // NON_COMPLIANT
int f3(); // COMPLIANT
7 changes: 7 additions & 0 deletions c/common/test/rules/incompatibleobjectdeclaration/test1.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
extern int *a; // NON_COMPLIANT
extern int i; // NON_COMPLIANT

extern int f(int a); // NON_COMPLIANT
extern void f1(int a); // NON_COMPLIANT
void f2(int a, ...) {} // NON_COMPLIANT
int f3(); // COMPLIANT
2 changes: 2 additions & 0 deletions change_notes/2026-03-27-update-compatible-objects-DCL40-C.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- `DCL40-C` - `IncompatibleObjectDeclarations.ql`:
- Enhanced the query's ability to compare objects with array type, which will reduce false positives.
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/
import cpp
import RuleMetadata
import codingstandards.cpp.exclusions.RuleMetadata

newtype Declarations2Query =
TIncompatibleObjectDeclarationsCppQuery() or
TIncompatibleFunctionDeclarationsCppQuery() or
TLocalVariableStaticStorageDurationQuery()

predicate isDeclarations2QueryMetadata(Query query, string queryId, string ruleId, string category) {
query =
// `Query` instance for the `incompatibleObjectDeclarationsCpp` query
Declarations2Package::incompatibleObjectDeclarationsCppQuery() and
queryId =
// `@id` for the `incompatibleObjectDeclarationsCpp` query
"cpp/misra/incompatible-object-declarations-cpp" and
ruleId = "RULE-6-2-2" and
category = "required"
or
query =
// `Query` instance for the `incompatibleFunctionDeclarationsCpp` query
Declarations2Package::incompatibleFunctionDeclarationsCppQuery() and
queryId =
// `@id` for the `incompatibleFunctionDeclarationsCpp` query
"cpp/misra/incompatible-function-declarations-cpp" and
ruleId = "RULE-6-2-2" and
category = "required"
or
query =
// `Query` instance for the `localVariableStaticStorageDuration` query
Declarations2Package::localVariableStaticStorageDurationQuery() and
queryId =
// `@id` for the `localVariableStaticStorageDuration` query
"cpp/misra/local-variable-static-storage-duration" and
ruleId = "RULE-6-7-1" and
category = "required"
}

module Declarations2Package {
Query incompatibleObjectDeclarationsCppQuery() {
//autogenerate `Query` type
result =
// `Query` type for `incompatibleObjectDeclarationsCpp` query
TQueryCPP(TDeclarations2PackageQuery(TIncompatibleObjectDeclarationsCppQuery()))
}

Query incompatibleFunctionDeclarationsCppQuery() {
//autogenerate `Query` type
result =
// `Query` type for `incompatibleFunctionDeclarationsCpp` query
TQueryCPP(TDeclarations2PackageQuery(TIncompatibleFunctionDeclarationsCppQuery()))
}

Query localVariableStaticStorageDurationQuery() {
//autogenerate `Query` type
result =
// `Query` type for `localVariableStaticStorageDuration` query
TQueryCPP(TDeclarations2PackageQuery(TLocalVariableStaticStorageDurationQuery()))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import DeadCode8
import DeadCode9
import Declarations
import Declarations1
import Declarations2
import ExceptionSafety
import Exceptions1
import Exceptions2
Expand Down Expand Up @@ -123,6 +124,7 @@ newtype TCPPQuery =
TDeadCode9PackageQuery(DeadCode9Query q) or
TDeclarationsPackageQuery(DeclarationsQuery q) or
TDeclarations1PackageQuery(Declarations1Query q) or
TDeclarations2PackageQuery(Declarations2Query q) or
TExceptionSafetyPackageQuery(ExceptionSafetyQuery q) or
TExceptions1PackageQuery(Exceptions1Query q) or
TExceptions2PackageQuery(Exceptions2Query q) or
Expand Down Expand Up @@ -216,6 +218,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat
isDeadCode9QueryMetadata(query, queryId, ruleId, category) or
isDeclarationsQueryMetadata(query, queryId, ruleId, category) or
isDeclarations1QueryMetadata(query, queryId, ruleId, category) or
isDeclarations2QueryMetadata(query, queryId, ruleId, category) or
isExceptionSafetyQueryMetadata(query, queryId, ruleId, category) or
isExceptions1QueryMetadata(query, queryId, ruleId, category) or
isExceptions2QueryMetadata(query, queryId, ruleId, category) or
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/**
* Provides a configurable module IncompatibleFunctionDeclaration with a `problems` predicate
* for the following issue:
* Declaring incompatible functions, in other words same named function of different
* return types or with different numbers of parameters or parameter types, then
* accessing those functions can lead to undefined behaviour.
*/

import cpp
import codingstandards.cpp.Customizations
import codingstandards.cpp.Exclusions
import codingstandards.cpp.Identifiers
import codingstandards.cpp.types.Compatible

predicate interestedInFunctions(
FunctionDeclarationEntry f1, FunctionDeclarationEntry f2, ExternalIdentifiers d1,
ExternalIdentifiers d2
) {
not f1 = f2 and
d1 = f1.getDeclaration() and
d2 = f2.getDeclaration() and
f1.getName() = f2.getName()
}

predicate interestedInFunctions(FunctionDeclarationEntry f1, FunctionDeclarationEntry f2) {
interestedInFunctions(f1, f2, _, _)
}

module FuncDeclEquiv =
FunctionDeclarationTypeEquivalence<TypesCompatibleConfig, interestedInFunctions/2>;

signature module IncompatibleFunctionDeclarationConfigSig {
Query getQuery();
}

module IncompatibleFunctionDeclaration<IncompatibleFunctionDeclarationConfigSig Config> {
query predicate problems(
FunctionDeclarationEntry f1, string message, FunctionDeclarationEntry f2, string secondMessage
) {
exists(ExternalIdentifiers d1, ExternalIdentifiers d2 |
not isExcluded(f1, Config::getQuery()) and
not isExcluded(f2, Config::getQuery()) and
interestedInFunctions(f1, f2, d1, d2) and
(
//return type check
not FuncDeclEquiv::equalReturnTypes(f1, f2)
or
//parameter type check
not FuncDeclEquiv::equalParameterTypes(f1, f2)
) and
// Apply ordering on start line, trying to avoid the optimiser applying this join too early
// in the pipeline
exists(int f1Line, int f2Line |
f1.getLocation().hasLocationInfo(_, f1Line, _, _, _) and
f2.getLocation().hasLocationInfo(_, f2Line, _, _, _) and
f1Line >= f2Line
) and
secondMessage = f2.getName() and
message = "The object is not compatible with a re-declaration $@."
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/**
* Provides a configurable module IncompatibleObjectDeclaration with a `problems` predicate
* for the following issue:
* Declaring incompatible objects, in other words same named objects of different
* types, then accessing those objects can lead to undefined behavior.
*/

import cpp
import codingstandards.cpp.Customizations
import codingstandards.cpp.Exclusions
import codingstandards.cpp.Identifiers
import codingstandards.cpp.types.Compatible

signature module IncompatibleObjectDeclarationConfigSig {
Query getQuery();
}

predicate relevantTypes(Type a, Type b) {
exists(VariableDeclarationEntry varA, VariableDeclarationEntry varB |
not varA = varB and
varA.getVariable().getName() = varB.getVariable().getName() and
a = varA.getType() and
b = varB.getType()
)
}

module IncompatibleObjectDeclaration<IncompatibleObjectDeclarationConfigSig Config> {
query predicate problems(
VariableDeclarationEntry decl1, string message, VariableDeclarationEntry decl2,
string secondMessage
) {
not isExcluded(decl1, Config::getQuery()) and
not isExcluded(decl2, Config::getQuery()) and
not TypeEquivalence<TypesCompatibleConfig, relevantTypes/2>::equalTypes(decl1.getType(),
decl2.getType()) and
not decl1 = decl2 and
decl1.getDeclaration() instanceof ExternalIdentifiers and
decl2.getDeclaration() instanceof ExternalIdentifiers and
decl1.getLocation().getStartLine() >= decl2.getLocation().getStartLine() and
decl1.getVariable().getName() = decl2.getVariable().getName() and
secondMessage = decl2.getName() and
message = "The object is not compatible with a re-declaration $@."
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
| test1.cpp:1:12:1:12 | declaration of f | The object is not compatible with a re-declaration $@. | test.cpp:1:6:1:6 | definition of f | f |
| test.cpp:1:6:1:6 | definition of f | The object is not compatible with a re-declaration $@. | test1.cpp:1:12:1:12 | declaration of f | f |
| test.cpp:5:6:5:7 | declaration of f1 | The object is not compatible with a re-declaration $@. | test1.cpp:2:13:2:14 | declaration of f1 | f1 |
| test.cpp:6:6:6:7 | definition of f2 | The object is not compatible with a re-declaration $@. | test1.cpp:3:6:3:7 | definition of f2 | f2 |
| test.cpp:9:17:9:18 | declaration of f4 | The object is not compatible with a re-declaration $@. | test1.cpp:6:17:6:18 | declaration of f4 | f4 |
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// GENERATED FILE - DO NOT MODIFY
import codingstandards.cpp.rules.incompatiblefunctiondeclaration.IncompatibleFunctionDeclaration

module TestFileConfig implements IncompatibleFunctionDeclarationConfigSig {
Query getQuery() { result instanceof TestQuery }
}

import IncompatibleFunctionDeclaration<TestFileConfig>
10 changes: 10 additions & 0 deletions cpp/common/test/rules/incompatiblefunctiondeclaration/test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
long f(int a) { // NON_COMPLIANT
return a * 2;
}

void f1(long a); // NON_COMPLIANT
void f2() {} // NON_COMPLIANT
int f3(); // COMPLIANT

extern "C" long f4(int a); // NON_COMPLIANT
long f5(); // NON_COMPLIANT[FALSE_NEGATIVE]
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
extern int f(int a); // NON_COMPLIANT
extern void f1(int a); // NON_COMPLIANT
void f2(int a, ...) {} // NON_COMPLIANT
int f3(); // COMPLIANT

extern "C" long f4(char a); // NON_COMPLIANT
long f5() noexcept; // NON_COMPLIANT[FALSE_NEGATIVE]
Loading
Loading