diff --git a/.vscode/tasks.json b/.vscode/tasks.json index d1f141cced..2e2941222b 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -233,6 +233,7 @@ "Pointers", "Pointers1", "Pointers2", + "Pointers3", "Scope", "SideEffects1", "SideEffects2", diff --git a/c/cert/src/rules/EXP32-C/DoNotAccessVolatileObjectWithNonVolatileReference.md b/c/cert/src/rules/EXP32-C/DoNotAccessVolatileObjectWithNonVolatileReference.md new file mode 100644 index 0000000000..449644423b --- /dev/null +++ b/c/cert/src/rules/EXP32-C/DoNotAccessVolatileObjectWithNonVolatileReference.md @@ -0,0 +1,18 @@ +# EXP32-C: Do not access a volatile object through a nonvolatile reference + +This query implements the CERT-C rule EXP32-C: + +> Do not access a volatile object through a nonvolatile reference + + +## CERT + +** REPLACE THIS BY RUNNING THE SCRIPT `scripts/help/cert-help-extraction.py` ** + +## Implementation notes + +None + +## References + +* CERT-C: [EXP32-C: Do not access a volatile object through a nonvolatile reference](https://wiki.sei.cmu.edu/confluence/display/c) diff --git a/c/cert/src/rules/EXP32-C/DoNotAccessVolatileObjectWithNonVolatileReference.ql b/c/cert/src/rules/EXP32-C/DoNotAccessVolatileObjectWithNonVolatileReference.ql new file mode 100644 index 0000000000..fe6acfb44b --- /dev/null +++ b/c/cert/src/rules/EXP32-C/DoNotAccessVolatileObjectWithNonVolatileReference.ql @@ -0,0 +1,65 @@ +/** + * @id c/cert/do-not-access-volatile-object-with-non-volatile-reference + * @name EXP32-C: Do not access a volatile object through a nonvolatile reference + * @description If an an object defined with a volatile-qualified type is referred to with an lvalue + * of a non-volatile-qualified type, the behavior is undefined. + * @kind problem + * @precision high + * @problem.severity error + * @tags external/cert/id/exp32-c + * correctness + * external/cert/obligation/rule + */ + +import cpp +import codingstandards.c.cert + +/** + * A `Cast` which converts from a pointer to a volatile-qualified type + * to a pointer to a non-volatile-qualified type. + */ +class CastFromVolatileToNonVolatileBaseType extends Cast { + CastFromVolatileToNonVolatileBaseType() { + this.getExpr().getType().(PointerType).getBaseType*().isVolatile() and + this.getActualType() instanceof PointerType and + not this.getActualType().(PointerType).getBaseType*().isVolatile() + } +} + +/** + * An `AssignExpr` with an *lvalue* that is a pointer to a volatile base type and + * and *rvalue* that is not also a pointer to a volatile base type. + */ +class NonVolatileObjectAssignedToVolatilePointer extends AssignExpr { + NonVolatileObjectAssignedToVolatilePointer() { + this.getLValue().getType().(DerivedType).getBaseType*().isVolatile() and + not this.getRValue().getUnconverted().getType().(DerivedType).getBaseType*().isVolatile() + } + + /** + * All `VariableAccess` expressions which are transitive successors of + * this `Expr` and which access the variable accessed in the *rvalue* of this `Expr` + */ + Expr getASubsequentAccessOfAssignedObject() { + result = + any(VariableAccess va | + va = this.getRValue().getAChild*().(VariableAccess).getTarget().getAnAccess() and + this.getASuccessor+() = va + | + va + ) + } +} + +from Expr e, string message +where + not isExcluded(e, Pointers3Package::doNotAccessVolatileObjectWithNonVolatileReferenceQuery()) and + ( + e instanceof CastFromVolatileToNonVolatileBaseType and + message = "Cast of object with a volatile-qualified type to a non-volatile-qualified type." + or + exists(e.(NonVolatileObjectAssignedToVolatilePointer).getASubsequentAccessOfAssignedObject()) and + message = + "Non-volatile object referenced via pointer to volatile type and later accessed via its original object of a non-volatile-qualified type." + ) +select e, message diff --git a/c/cert/src/rules/EXP36-C/DoNotCastPointerToMoreStrictlyAlignedPointerType.md b/c/cert/src/rules/EXP36-C/DoNotCastPointerToMoreStrictlyAlignedPointerType.md new file mode 100644 index 0000000000..870ae704aa --- /dev/null +++ b/c/cert/src/rules/EXP36-C/DoNotCastPointerToMoreStrictlyAlignedPointerType.md @@ -0,0 +1,18 @@ +# EXP36-C: Do not cast pointers into more strictly aligned pointer types + +This query implements the CERT-C rule EXP36-C: + +> Do not cast pointers into more strictly aligned pointer types + + +## CERT + +** REPLACE THIS BY RUNNING THE SCRIPT `scripts/help/cert-help-extraction.py` ** + +## Implementation notes + +None + +## References + +* CERT-C: [EXP36-C: Do not cast pointers into more strictly aligned pointer types](https://wiki.sei.cmu.edu/confluence/display/c) diff --git a/c/cert/src/rules/EXP36-C/DoNotCastPointerToMoreStrictlyAlignedPointerType.ql b/c/cert/src/rules/EXP36-C/DoNotCastPointerToMoreStrictlyAlignedPointerType.ql new file mode 100644 index 0000000000..b1c2b6e305 --- /dev/null +++ b/c/cert/src/rules/EXP36-C/DoNotCastPointerToMoreStrictlyAlignedPointerType.ql @@ -0,0 +1,170 @@ +/** + * @id c/cert/do-not-cast-pointer-to-more-strictly-aligned-pointer-type + * @name EXP36-C: Do not cast pointers into more strictly aligned pointer types + * @description Converting a pointer to a different type results in undefined behavior if the + * pointer is not correctly aligned for the new type. + * @kind path-problem + * @precision high + * @problem.severity error + * @tags external/cert/id/exp36-c + * correctness + * external/cert/obligation/rule + */ + +import cpp +import codingstandards.c.cert +import codingstandards.cpp.Alignment +import semmle.code.cpp.dataflow.DataFlow +import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis +import DataFlow::PathGraph + +/** + * An expression with a type that has defined alignment requirements + */ +abstract class ExprWithAlignment extends Expr { + /** + * Gets the alignment requirements in bytes for the underlying `Expr` + */ + abstract int getAlignment(); + + /** + * Gets a descriptive string describing the type of expression + */ + abstract string getKind(); +} + +/** + * A class extending `AddressOfExpr` and `ExprWithAlignment` to reason about the + * alignment of base types addressed with C address-of expressions + */ +class AddressOfAlignedVariableExpr extends AddressOfExpr, ExprWithAlignment { + AddressOfAlignedVariableExpr() { this.getAddressable() instanceof Variable } + + AlignAs alignAsAttribute() { result = this.getAddressable().(Variable).getAnAttribute() } + + override int getAlignment() { + result = alignAsAttribute().getArgument(0).getValueInt() + or + result = alignAsAttribute().getArgument(0).getValueType().getSize() + or + not exists(alignAsAttribute()) and + result = this.getAddressable().(Variable).getType().getAlignment() + } + + override string getKind() { result = "address-of expression" } +} + +/** + * A class extending `FunctionCall` and `ExprWithAlignment` to reason about the + * alignment of pointers allocated with calls to C standard library allocation functions + */ +class DefinedAlignmentAllocationExpr extends FunctionCall, ExprWithAlignment { + int alignment; + + DefinedAlignmentAllocationExpr() { + this.getTarget().getName() = "aligned_alloc" and + lowerBound(this.getArgument(0)) = upperBound(this.getArgument(0)) and + alignment = upperBound(this.getArgument(0)) + or + this.getTarget().getName() = ["malloc", "calloc", "realloc"] and + alignment = getGlobalMaxAlignT() + } + + override int getAlignment() { result = alignment } + + override string getKind() { result = "call to " + this.getTarget().getName() } +} + +/** + * A class extending `VariableAccess` and `ExprWithAlignment` to reason about the + * alignment of pointers accessed based solely on the pointers' base types. + */ +class DefaultAlignedPointerAccessExpr extends VariableAccess, ExprWithAlignment { + DefaultAlignedPointerAccessExpr() { + this.getTarget().getUnspecifiedType() instanceof PointerType and + not this.getTarget().getUnspecifiedType() instanceof VoidPointerType + } + + override int getAlignment() { + result = this.getTarget().getType().(PointerType).getBaseType().getAlignment() + } + + override string getKind() { result = "pointer base type" } +} + +/** + * A data-flow configuration for analysing the flow of `ExprWithAlignment` pointer expressions + * to casts which perform pointer type conversions and potentially create pointer alignment issues. + */ +class ExprWithAlignmentToCStyleCastConfiguration extends DataFlow::Configuration { + ExprWithAlignmentToCStyleCastConfiguration() { + this = "ExprWithAlignmentToCStyleCastConfiguration" + } + + override predicate isSource(DataFlow::Node source) { + source.asExpr() instanceof ExprWithAlignment + } + + override predicate isSink(DataFlow::Node sink) { + exists(CStyleCast cast | + cast.getUnderlyingType() instanceof PointerType and + cast.getUnconverted() = sink.asExpr() + ) + } +} + +/** + * A data-flow configuration for tracking flow from `AddressOfExpr` which provide + * most reliable or explicitly defined alignment information to the less reliable + * `DefaultAlignedPointerAccessExpr` expressions. + * + * This data-flow configuration is used + * to exclude an `DefaultAlignedPointerAccessExpr` as a source if a preceding source + * defined by this configuration provides more accurate alignment information. + */ +class AllocationOrAddressOfExprToDefaultAlignedPointerAccessConfig extends DataFlow::Configuration { + AllocationOrAddressOfExprToDefaultAlignedPointerAccessConfig() { + this = "AllocationOrAddressOfExprToDefaultAlignedPointerAccessConfig" + } + + override predicate isSource(DataFlow::Node source) { + source.asExpr() instanceof AddressOfAlignedVariableExpr or + source.asExpr() instanceof DefinedAlignmentAllocationExpr + } + + override predicate isSink(DataFlow::Node sink) { + sink.asExpr() instanceof DefaultAlignedPointerAccessExpr + } +} + +from + DataFlow::PathNode source, DataFlow::PathNode sink, ExprWithAlignment expr, CStyleCast cast, + Type toBaseType, int alignmentFrom, int alignmentTo +where + not isExcluded(cast, Pointers3Package::doNotCastPointerToMoreStrictlyAlignedPointerTypeQuery()) and + any(ExprWithAlignmentToCStyleCastConfiguration config).hasFlowPath(source, sink) and + source.getNode().asExpr() = expr and + sink.getNode().asExpr() = cast.getUnconverted() and + ( + // possibility 1: the source node (ExprWithAlignment) is NOT a DefaultAlignedPointerAccessExpr + // meaning that its alignment info is accurate regardless of any preceding ExprWithAlignment nodes + expr instanceof DefaultAlignedPointerAccessExpr + implies + ( + // possibility 2: the source node (ExprWithAlignment) IS a DefaultAlignedPointerAccessExpr + // meaning that its alignment info is only accurate if no preceding ExprWithAlignment nodes exist + not any(AllocationOrAddressOfExprToDefaultAlignedPointerAccessConfig config) + .hasFlowTo(source.getNode()) and + expr instanceof DefaultAlignedPointerAccessExpr and + cast.getUnconverted() instanceof VariableAccess + ) + ) and + toBaseType = cast.getActualType().(PointerType).getBaseType() and + alignmentTo = toBaseType.getAlignment() and + alignmentFrom = expr.getAlignment() and + // only flag cases where the cast's target type has stricter alignment requirements than the source + alignmentFrom < alignmentTo +select sink, source, sink, + "Cast from pointer with " + alignmentFrom + + "-byte alignment (defined by $@) to pointer with base type " + toBaseType.getUnderlyingType() + + " with " + alignmentTo + "-byte alignment.", expr.getUnconverted(), expr.getKind() diff --git a/c/cert/test/rules/EXP32-C/DoNotAccessVolatileObjectWithNonVolatileReference.expected b/c/cert/test/rules/EXP32-C/DoNotAccessVolatileObjectWithNonVolatileReference.expected new file mode 100644 index 0000000000..d8fd01bbae --- /dev/null +++ b/c/cert/test/rules/EXP32-C/DoNotAccessVolatileObjectWithNonVolatileReference.expected @@ -0,0 +1,4 @@ +| test.c:5:13:5:21 | (int *)... | Cast of object with a volatile-qualified type to a non-volatile-qualified type. | +| test.c:6:13:6:31 | (int *)... | Cast of object with a volatile-qualified type to a non-volatile-qualified type. | +| test.c:14:3:14:55 | ... = ... | Non-volatile object referenced via pointer to volatile type and later accessed via its original object of a non-volatile-qualified type. | +| test.c:24:3:25:36 | ... = ... | Non-volatile object referenced via pointer to volatile type and later accessed via its original object of a non-volatile-qualified type. | diff --git a/c/cert/test/rules/EXP32-C/DoNotAccessVolatileObjectWithNonVolatileReference.qlref b/c/cert/test/rules/EXP32-C/DoNotAccessVolatileObjectWithNonVolatileReference.qlref new file mode 100644 index 0000000000..90635c935e --- /dev/null +++ b/c/cert/test/rules/EXP32-C/DoNotAccessVolatileObjectWithNonVolatileReference.qlref @@ -0,0 +1 @@ +rules/EXP32-C/DoNotAccessVolatileObjectWithNonVolatileReference.ql \ No newline at end of file diff --git a/c/cert/test/rules/EXP32-C/test.c b/c/cert/test/rules/EXP32-C/test.c new file mode 100644 index 0000000000..d9b07ac84d --- /dev/null +++ b/c/cert/test/rules/EXP32-C/test.c @@ -0,0 +1,38 @@ +volatile int *volatile_f(); + +void test_cast_away_volatile() { + volatile int *l1 = volatile_f(); // COMPLIANT + int *l2 = (int *)l1; // NON_COMPLIANT + int *l3 = (int *)volatile_f(); // NON_COMPLIANT + *l2; // Volatile object is accessed through a non-volatile pointer +} + +void test_volatile_lost_by_assignment() { + static volatile int val = 0; + static int *non_compliant_pointer; + static volatile int **compliant_pointer_to_pointer; + compliant_pointer_to_pointer = &non_compliant_pointer; // NON_COMPLIANT + *compliant_pointer_to_pointer = &val; + *non_compliant_pointer; // Volatile object is accessed through a non-volatile + // pointer +} + +void test_volatile_lost_by_assignment_and_cast() { + static volatile int val = 0; + static int *non_compliant_pointer; + static volatile int **compliant_pointer_to_pointer; + compliant_pointer_to_pointer = + (int **)&non_compliant_pointer; // NON_COMPLIANT + *compliant_pointer_to_pointer = &val; + *non_compliant_pointer; // Volatile object is accessed through a non-volatile + // pointer +} + +void test_volatile_not_lost_by_assignment_and_cast() { + static volatile int val = 0; + static volatile int *compliant_pointer; + static volatile int **compliant_pointer_to_pointer; + compliant_pointer_to_pointer = &compliant_pointer; // COMPLIANT + *compliant_pointer_to_pointer = &val; + *compliant_pointer; // Volatile object is accessed through a volatile pointer +} \ No newline at end of file diff --git a/c/cert/test/rules/EXP36-C/DoNotCastPointerToMoreStrictlyAlignedPointerType.expected b/c/cert/test/rules/EXP36-C/DoNotCastPointerToMoreStrictlyAlignedPointerType.expected new file mode 100644 index 0000000000..e523be08fb --- /dev/null +++ b/c/cert/test/rules/EXP36-C/DoNotCastPointerToMoreStrictlyAlignedPointerType.expected @@ -0,0 +1,282 @@ +edges +| test.c:75:14:75:16 | & ... | test.c:76:11:76:12 | v1 | +| test.c:75:14:75:16 | & ... | test.c:77:12:77:13 | v1 | +| test.c:75:14:75:16 | & ... | test.c:78:10:78:11 | v1 | +| test.c:75:14:75:16 | & ... | test.c:79:12:79:13 | v1 | +| test.c:75:14:75:16 | & ... | test.c:80:11:80:12 | v1 | +| test.c:75:14:75:16 | & ... | test.c:81:13:81:14 | v1 | +| test.c:84:14:84:16 | & ... | test.c:85:11:85:12 | v2 | +| test.c:84:14:84:16 | & ... | test.c:86:12:86:13 | v2 | +| test.c:84:14:84:16 | & ... | test.c:87:10:87:11 | v2 | +| test.c:84:14:84:16 | & ... | test.c:88:12:88:13 | v2 | +| test.c:84:14:84:16 | & ... | test.c:89:11:89:12 | v2 | +| test.c:84:14:84:16 | & ... | test.c:90:13:90:14 | v2 | +| test.c:93:14:93:16 | & ... | test.c:94:11:94:12 | v3 | +| test.c:93:14:93:16 | & ... | test.c:95:12:95:13 | v3 | +| test.c:93:14:93:16 | & ... | test.c:96:10:96:11 | v3 | +| test.c:93:14:93:16 | & ... | test.c:97:12:97:13 | v3 | +| test.c:93:14:93:16 | & ... | test.c:98:11:98:12 | v3 | +| test.c:93:14:93:16 | & ... | test.c:99:13:99:14 | v3 | +| test.c:102:14:102:16 | & ... | test.c:103:11:103:12 | v4 | +| test.c:102:14:102:16 | & ... | test.c:104:12:104:13 | v4 | +| test.c:102:14:102:16 | & ... | test.c:105:10:105:11 | v4 | +| test.c:102:14:102:16 | & ... | test.c:106:12:106:13 | v4 | +| test.c:102:14:102:16 | & ... | test.c:107:11:107:12 | v4 | +| test.c:102:14:102:16 | & ... | test.c:108:13:108:14 | v4 | +| test.c:111:14:111:16 | & ... | test.c:112:11:112:12 | v5 | +| test.c:111:14:111:16 | & ... | test.c:113:12:113:13 | v5 | +| test.c:111:14:111:16 | & ... | test.c:114:10:114:11 | v5 | +| test.c:111:14:111:16 | & ... | test.c:115:12:115:13 | v5 | +| test.c:111:14:111:16 | & ... | test.c:116:11:116:12 | v5 | +| test.c:111:14:111:16 | & ... | test.c:117:13:117:14 | v5 | +| test.c:120:14:120:16 | & ... | test.c:121:11:121:12 | v6 | +| test.c:120:14:120:16 | & ... | test.c:122:12:122:13 | v6 | +| test.c:120:14:120:16 | & ... | test.c:123:10:123:11 | v6 | +| test.c:120:14:120:16 | & ... | test.c:124:12:124:13 | v6 | +| test.c:120:14:120:16 | & ... | test.c:125:11:125:12 | v6 | +| test.c:120:14:120:16 | & ... | test.c:126:13:126:14 | v6 | +| test.c:129:22:129:22 | v | test.c:129:22:129:22 | v | +| test.c:129:22:129:22 | v | test.c:130:17:130:17 | v | +| test.c:135:21:135:23 | & ... | test.c:129:22:129:22 | v | +| test.c:138:21:138:23 | & ... | test.c:129:22:129:22 | v | +| test.c:166:24:166:29 | call to malloc | test.c:167:13:167:15 | & ... | +| test.c:166:24:166:29 | call to malloc | test.c:167:14:167:15 | s1 | +| test.c:166:24:166:29 | call to malloc | test.c:168:16:168:18 | & ... | +| test.c:166:24:166:29 | call to malloc | test.c:168:17:168:18 | s1 | +| test.c:166:24:166:29 | call to malloc | test.c:169:13:169:14 | s1 | +| test.c:166:24:166:29 | call to malloc | test.c:169:13:169:14 | s1 | +| test.c:166:24:166:29 | call to malloc | test.c:169:13:169:14 | s1 | +| test.c:166:24:166:29 | call to malloc | test.c:169:13:169:14 | s1 | +| test.c:166:24:166:29 | call to malloc | test.c:171:15:171:16 | s1 | +| test.c:166:24:166:29 | call to malloc | test.c:176:16:176:17 | s1 | +| test.c:167:14:167:15 | s1 | test.c:167:13:167:15 | & ... | +| test.c:168:17:168:18 | s1 | test.c:168:16:168:18 | & ... | +| test.c:169:13:169:14 | ref arg s1 | test.c:171:15:171:16 | s1 | +| test.c:169:13:169:14 | ref arg s1 | test.c:176:16:176:17 | s1 | +| test.c:169:13:169:14 | s1 | test.c:129:22:129:22 | v | +| test.c:169:13:169:14 | s1 | test.c:129:22:129:22 | v | +| test.c:169:13:169:14 | s1 | test.c:169:13:169:14 | ref arg s1 | +| test.c:172:14:172:15 | s2 | test.c:172:13:172:15 | & ... | +| test.c:173:12:173:13 | s2 | test.c:173:11:173:13 | & ... | +| test.c:174:13:174:14 | s2 | test.c:129:22:129:22 | v | +| test.c:177:14:177:15 | s3 | test.c:177:13:177:15 | & ... | +| test.c:178:12:178:13 | s3 | test.c:178:11:178:13 | & ... | +| test.c:179:13:179:14 | s3 | test.c:129:22:129:22 | v | +| test.c:183:14:183:26 | call to aligned_alloc | test.c:184:11:184:12 | v1 | +| test.c:183:14:183:26 | call to aligned_alloc | test.c:185:10:185:11 | v1 | +| test.c:183:14:183:26 | call to aligned_alloc | test.c:186:13:186:14 | v1 | +| test.c:183:14:183:26 | call to aligned_alloc | test.c:187:13:187:14 | v1 | +| test.c:187:13:187:14 | v1 | test.c:129:22:129:22 | v | +| test.c:189:14:189:26 | call to aligned_alloc | test.c:190:13:190:14 | v2 | +| test.c:190:13:190:14 | v2 | test.c:129:22:129:22 | v | +| test.c:222:8:222:9 | p2 | test.c:223:11:223:12 | v1 | +| test.c:222:8:222:9 | p2 | test.c:224:12:224:13 | v1 | +| test.c:222:8:222:9 | p2 | test.c:225:10:225:11 | v1 | +| test.c:222:8:222:9 | p2 | test.c:226:12:226:13 | v1 | +| test.c:222:8:222:9 | p2 | test.c:227:11:227:12 | v1 | +| test.c:222:8:222:9 | p2 | test.c:228:13:228:14 | v1 | +nodes +| test.c:7:11:7:13 | & ... | semmle.label | & ... | +| test.c:8:12:8:14 | & ... | semmle.label | & ... | +| test.c:9:10:9:12 | & ... | semmle.label | & ... | +| test.c:10:11:10:13 | & ... | semmle.label | & ... | +| test.c:11:12:11:14 | & ... | semmle.label | & ... | +| test.c:12:13:12:15 | & ... | semmle.label | & ... | +| test.c:15:11:15:13 | & ... | semmle.label | & ... | +| test.c:16:12:16:14 | & ... | semmle.label | & ... | +| test.c:17:10:17:12 | & ... | semmle.label | & ... | +| test.c:18:11:18:13 | & ... | semmle.label | & ... | +| test.c:19:12:19:14 | & ... | semmle.label | & ... | +| test.c:20:13:20:15 | & ... | semmle.label | & ... | +| test.c:23:11:23:13 | & ... | semmle.label | & ... | +| test.c:24:12:24:14 | & ... | semmle.label | & ... | +| test.c:25:10:25:12 | & ... | semmle.label | & ... | +| test.c:26:12:26:14 | & ... | semmle.label | & ... | +| test.c:27:11:27:13 | & ... | semmle.label | & ... | +| test.c:28:13:28:15 | & ... | semmle.label | & ... | +| test.c:31:11:31:13 | & ... | semmle.label | & ... | +| test.c:32:12:32:14 | & ... | semmle.label | & ... | +| test.c:33:10:33:12 | & ... | semmle.label | & ... | +| test.c:34:12:34:14 | & ... | semmle.label | & ... | +| test.c:35:11:35:13 | & ... | semmle.label | & ... | +| test.c:36:13:36:15 | & ... | semmle.label | & ... | +| test.c:39:11:39:13 | & ... | semmle.label | & ... | +| test.c:40:12:40:14 | & ... | semmle.label | & ... | +| test.c:41:10:41:12 | & ... | semmle.label | & ... | +| test.c:42:12:42:14 | & ... | semmle.label | & ... | +| test.c:43:11:43:13 | & ... | semmle.label | & ... | +| test.c:44:13:44:15 | & ... | semmle.label | & ... | +| test.c:47:11:47:13 | & ... | semmle.label | & ... | +| test.c:48:12:48:14 | & ... | semmle.label | & ... | +| test.c:49:10:49:12 | & ... | semmle.label | & ... | +| test.c:50:12:50:14 | & ... | semmle.label | & ... | +| test.c:51:11:51:13 | & ... | semmle.label | & ... | +| test.c:52:13:52:15 | & ... | semmle.label | & ... | +| test.c:57:11:57:13 | & ... | semmle.label | & ... | +| test.c:58:12:58:14 | & ... | semmle.label | & ... | +| test.c:59:10:59:12 | & ... | semmle.label | & ... | +| test.c:60:12:60:14 | & ... | semmle.label | & ... | +| test.c:61:11:61:13 | & ... | semmle.label | & ... | +| test.c:62:13:62:15 | & ... | semmle.label | & ... | +| test.c:65:11:65:13 | & ... | semmle.label | & ... | +| test.c:66:12:66:14 | & ... | semmle.label | & ... | +| test.c:67:10:67:12 | & ... | semmle.label | & ... | +| test.c:68:12:68:14 | & ... | semmle.label | & ... | +| test.c:69:11:69:13 | & ... | semmle.label | & ... | +| test.c:70:13:70:15 | & ... | semmle.label | & ... | +| test.c:75:14:75:16 | & ... | semmle.label | & ... | +| test.c:75:14:75:16 | & ... | semmle.label | & ... | +| test.c:76:11:76:12 | v1 | semmle.label | v1 | +| test.c:77:12:77:13 | v1 | semmle.label | v1 | +| test.c:78:10:78:11 | v1 | semmle.label | v1 | +| test.c:79:12:79:13 | v1 | semmle.label | v1 | +| test.c:80:11:80:12 | v1 | semmle.label | v1 | +| test.c:81:13:81:14 | v1 | semmle.label | v1 | +| test.c:84:14:84:16 | & ... | semmle.label | & ... | +| test.c:84:14:84:16 | & ... | semmle.label | & ... | +| test.c:85:11:85:12 | v2 | semmle.label | v2 | +| test.c:86:12:86:13 | v2 | semmle.label | v2 | +| test.c:87:10:87:11 | v2 | semmle.label | v2 | +| test.c:88:12:88:13 | v2 | semmle.label | v2 | +| test.c:89:11:89:12 | v2 | semmle.label | v2 | +| test.c:90:13:90:14 | v2 | semmle.label | v2 | +| test.c:93:14:93:16 | & ... | semmle.label | & ... | +| test.c:93:14:93:16 | & ... | semmle.label | & ... | +| test.c:94:11:94:12 | v3 | semmle.label | v3 | +| test.c:95:12:95:13 | v3 | semmle.label | v3 | +| test.c:96:10:96:11 | v3 | semmle.label | v3 | +| test.c:97:12:97:13 | v3 | semmle.label | v3 | +| test.c:98:11:98:12 | v3 | semmle.label | v3 | +| test.c:99:13:99:14 | v3 | semmle.label | v3 | +| test.c:102:14:102:16 | & ... | semmle.label | & ... | +| test.c:102:14:102:16 | & ... | semmle.label | & ... | +| test.c:103:11:103:12 | v4 | semmle.label | v4 | +| test.c:104:12:104:13 | v4 | semmle.label | v4 | +| test.c:105:10:105:11 | v4 | semmle.label | v4 | +| test.c:106:12:106:13 | v4 | semmle.label | v4 | +| test.c:107:11:107:12 | v4 | semmle.label | v4 | +| test.c:108:13:108:14 | v4 | semmle.label | v4 | +| test.c:111:14:111:16 | & ... | semmle.label | & ... | +| test.c:111:14:111:16 | & ... | semmle.label | & ... | +| test.c:112:11:112:12 | v5 | semmle.label | v5 | +| test.c:113:12:113:13 | v5 | semmle.label | v5 | +| test.c:114:10:114:11 | v5 | semmle.label | v5 | +| test.c:115:12:115:13 | v5 | semmle.label | v5 | +| test.c:116:11:116:12 | v5 | semmle.label | v5 | +| test.c:117:13:117:14 | v5 | semmle.label | v5 | +| test.c:120:14:120:16 | & ... | semmle.label | & ... | +| test.c:120:14:120:16 | & ... | semmle.label | & ... | +| test.c:121:11:121:12 | v6 | semmle.label | v6 | +| test.c:122:12:122:13 | v6 | semmle.label | v6 | +| test.c:123:10:123:11 | v6 | semmle.label | v6 | +| test.c:124:12:124:13 | v6 | semmle.label | v6 | +| test.c:125:11:125:12 | v6 | semmle.label | v6 | +| test.c:126:13:126:14 | v6 | semmle.label | v6 | +| test.c:129:22:129:22 | v | semmle.label | v | +| test.c:129:22:129:22 | v | semmle.label | v | +| test.c:129:22:129:22 | v | semmle.label | v | +| test.c:130:17:130:17 | v | semmle.label | v | +| test.c:135:21:135:23 | & ... | semmle.label | & ... | +| test.c:135:21:135:23 | & ... | semmle.label | & ... | +| test.c:138:21:138:23 | & ... | semmle.label | & ... | +| test.c:138:21:138:23 | & ... | semmle.label | & ... | +| test.c:158:13:158:20 | & ... | semmle.label | & ... | +| test.c:161:13:161:20 | & ... | semmle.label | & ... | +| test.c:162:16:162:18 | & ... | semmle.label | & ... | +| test.c:166:24:166:29 | call to malloc | semmle.label | call to malloc | +| test.c:166:24:166:29 | call to malloc | semmle.label | call to malloc | +| test.c:166:24:166:29 | call to malloc | semmle.label | call to malloc | +| test.c:167:13:167:15 | & ... | semmle.label | & ... | +| test.c:167:14:167:15 | s1 | semmle.label | s1 | +| test.c:167:14:167:15 | s1 | semmle.label | s1 | +| test.c:168:16:168:18 | & ... | semmle.label | & ... | +| test.c:168:17:168:18 | s1 | semmle.label | s1 | +| test.c:168:17:168:18 | s1 | semmle.label | s1 | +| test.c:169:13:169:14 | ref arg s1 | semmle.label | ref arg s1 | +| test.c:169:13:169:14 | s1 | semmle.label | s1 | +| test.c:169:13:169:14 | s1 | semmle.label | s1 | +| test.c:169:13:169:14 | s1 | semmle.label | s1 | +| test.c:169:13:169:14 | s1 | semmle.label | s1 | +| test.c:171:15:171:16 | s1 | semmle.label | s1 | +| test.c:172:13:172:15 | & ... | semmle.label | & ... | +| test.c:172:14:172:15 | s2 | semmle.label | s2 | +| test.c:173:11:173:13 | & ... | semmle.label | & ... | +| test.c:173:12:173:13 | s2 | semmle.label | s2 | +| test.c:174:13:174:14 | s2 | semmle.label | s2 | +| test.c:174:13:174:14 | s2 | semmle.label | s2 | +| test.c:176:16:176:17 | s1 | semmle.label | s1 | +| test.c:177:13:177:15 | & ... | semmle.label | & ... | +| test.c:177:14:177:15 | s3 | semmle.label | s3 | +| test.c:178:11:178:13 | & ... | semmle.label | & ... | +| test.c:178:12:178:13 | s3 | semmle.label | s3 | +| test.c:179:13:179:14 | s3 | semmle.label | s3 | +| test.c:179:13:179:14 | s3 | semmle.label | s3 | +| test.c:183:14:183:26 | call to aligned_alloc | semmle.label | call to aligned_alloc | +| test.c:184:11:184:12 | v1 | semmle.label | v1 | +| test.c:185:10:185:11 | v1 | semmle.label | v1 | +| test.c:186:13:186:14 | v1 | semmle.label | v1 | +| test.c:187:13:187:14 | v1 | semmle.label | v1 | +| test.c:189:14:189:26 | call to aligned_alloc | semmle.label | call to aligned_alloc | +| test.c:190:13:190:14 | v2 | semmle.label | v2 | +| test.c:214:11:214:12 | p2 | semmle.label | p2 | +| test.c:215:12:215:13 | p2 | semmle.label | p2 | +| test.c:216:10:216:11 | p2 | semmle.label | p2 | +| test.c:217:11:217:12 | p2 | semmle.label | p2 | +| test.c:218:12:218:13 | p2 | semmle.label | p2 | +| test.c:219:13:219:14 | p2 | semmle.label | p2 | +| test.c:222:8:222:9 | p2 | semmle.label | p2 | +| test.c:222:8:222:9 | p2 | semmle.label | p2 | +| test.c:223:11:223:12 | v1 | semmle.label | v1 | +| test.c:224:12:224:13 | v1 | semmle.label | v1 | +| test.c:225:10:225:11 | v1 | semmle.label | v1 | +| test.c:226:12:226:13 | v1 | semmle.label | v1 | +| test.c:227:11:227:12 | v1 | semmle.label | v1 | +| test.c:228:13:228:14 | v1 | semmle.label | v1 | +subpaths +| test.c:169:13:169:14 | s1 | test.c:129:22:129:22 | v | test.c:129:22:129:22 | v | test.c:169:13:169:14 | ref arg s1 | +#select +| test.c:8:12:8:14 | & ... | test.c:8:12:8:14 | & ... | test.c:8:12:8:14 | & ... | Cast from pointer with 1-byte alignment (defined by $@) to pointer with base type short with 2-byte alignment. | test.c:8:12:8:14 | & ... | address-of expression | +| test.c:9:10:9:12 | & ... | test.c:9:10:9:12 | & ... | test.c:9:10:9:12 | & ... | Cast from pointer with 1-byte alignment (defined by $@) to pointer with base type int with 4-byte alignment. | test.c:9:10:9:12 | & ... | address-of expression | +| test.c:10:11:10:13 | & ... | test.c:10:11:10:13 | & ... | test.c:10:11:10:13 | & ... | Cast from pointer with 1-byte alignment (defined by $@) to pointer with base type long with 8-byte alignment. | test.c:10:11:10:13 | & ... | address-of expression | +| test.c:11:12:11:14 | & ... | test.c:11:12:11:14 | & ... | test.c:11:12:11:14 | & ... | Cast from pointer with 1-byte alignment (defined by $@) to pointer with base type float with 4-byte alignment. | test.c:11:12:11:14 | & ... | address-of expression | +| test.c:12:13:12:15 | & ... | test.c:12:13:12:15 | & ... | test.c:12:13:12:15 | & ... | Cast from pointer with 1-byte alignment (defined by $@) to pointer with base type double with 8-byte alignment. | test.c:12:13:12:15 | & ... | address-of expression | +| test.c:17:10:17:12 | & ... | test.c:17:10:17:12 | & ... | test.c:17:10:17:12 | & ... | Cast from pointer with 2-byte alignment (defined by $@) to pointer with base type int with 4-byte alignment. | test.c:17:10:17:12 | & ... | address-of expression | +| test.c:18:11:18:13 | & ... | test.c:18:11:18:13 | & ... | test.c:18:11:18:13 | & ... | Cast from pointer with 2-byte alignment (defined by $@) to pointer with base type long with 8-byte alignment. | test.c:18:11:18:13 | & ... | address-of expression | +| test.c:19:12:19:14 | & ... | test.c:19:12:19:14 | & ... | test.c:19:12:19:14 | & ... | Cast from pointer with 2-byte alignment (defined by $@) to pointer with base type float with 4-byte alignment. | test.c:19:12:19:14 | & ... | address-of expression | +| test.c:20:13:20:15 | & ... | test.c:20:13:20:15 | & ... | test.c:20:13:20:15 | & ... | Cast from pointer with 2-byte alignment (defined by $@) to pointer with base type double with 8-byte alignment. | test.c:20:13:20:15 | & ... | address-of expression | +| test.c:27:11:27:13 | & ... | test.c:27:11:27:13 | & ... | test.c:27:11:27:13 | & ... | Cast from pointer with 4-byte alignment (defined by $@) to pointer with base type long with 8-byte alignment. | test.c:27:11:27:13 | & ... | address-of expression | +| test.c:28:13:28:15 | & ... | test.c:28:13:28:15 | & ... | test.c:28:13:28:15 | & ... | Cast from pointer with 4-byte alignment (defined by $@) to pointer with base type double with 8-byte alignment. | test.c:28:13:28:15 | & ... | address-of expression | +| test.c:35:11:35:13 | & ... | test.c:35:11:35:13 | & ... | test.c:35:11:35:13 | & ... | Cast from pointer with 4-byte alignment (defined by $@) to pointer with base type long with 8-byte alignment. | test.c:35:11:35:13 | & ... | address-of expression | +| test.c:36:13:36:15 | & ... | test.c:36:13:36:15 | & ... | test.c:36:13:36:15 | & ... | Cast from pointer with 4-byte alignment (defined by $@) to pointer with base type double with 8-byte alignment. | test.c:36:13:36:15 | & ... | address-of expression | +| test.c:61:11:61:13 | & ... | test.c:61:11:61:13 | & ... | test.c:61:11:61:13 | & ... | Cast from pointer with 4-byte alignment (defined by $@) to pointer with base type long with 8-byte alignment. | test.c:61:11:61:13 | & ... | address-of expression | +| test.c:62:13:62:15 | & ... | test.c:62:13:62:15 | & ... | test.c:62:13:62:15 | & ... | Cast from pointer with 4-byte alignment (defined by $@) to pointer with base type double with 8-byte alignment. | test.c:62:13:62:15 | & ... | address-of expression | +| test.c:77:12:77:13 | v1 | test.c:75:14:75:16 | & ... | test.c:77:12:77:13 | v1 | Cast from pointer with 1-byte alignment (defined by $@) to pointer with base type short with 2-byte alignment. | test.c:75:14:75:16 | & ... | address-of expression | +| test.c:78:10:78:11 | v1 | test.c:75:14:75:16 | & ... | test.c:78:10:78:11 | v1 | Cast from pointer with 1-byte alignment (defined by $@) to pointer with base type int with 4-byte alignment. | test.c:75:14:75:16 | & ... | address-of expression | +| test.c:79:12:79:13 | v1 | test.c:75:14:75:16 | & ... | test.c:79:12:79:13 | v1 | Cast from pointer with 1-byte alignment (defined by $@) to pointer with base type float with 4-byte alignment. | test.c:75:14:75:16 | & ... | address-of expression | +| test.c:80:11:80:12 | v1 | test.c:75:14:75:16 | & ... | test.c:80:11:80:12 | v1 | Cast from pointer with 1-byte alignment (defined by $@) to pointer with base type long with 8-byte alignment. | test.c:75:14:75:16 | & ... | address-of expression | +| test.c:81:13:81:14 | v1 | test.c:75:14:75:16 | & ... | test.c:81:13:81:14 | v1 | Cast from pointer with 1-byte alignment (defined by $@) to pointer with base type double with 8-byte alignment. | test.c:75:14:75:16 | & ... | address-of expression | +| test.c:87:10:87:11 | v2 | test.c:84:14:84:16 | & ... | test.c:87:10:87:11 | v2 | Cast from pointer with 2-byte alignment (defined by $@) to pointer with base type int with 4-byte alignment. | test.c:84:14:84:16 | & ... | address-of expression | +| test.c:88:12:88:13 | v2 | test.c:84:14:84:16 | & ... | test.c:88:12:88:13 | v2 | Cast from pointer with 2-byte alignment (defined by $@) to pointer with base type float with 4-byte alignment. | test.c:84:14:84:16 | & ... | address-of expression | +| test.c:89:11:89:12 | v2 | test.c:84:14:84:16 | & ... | test.c:89:11:89:12 | v2 | Cast from pointer with 2-byte alignment (defined by $@) to pointer with base type long with 8-byte alignment. | test.c:84:14:84:16 | & ... | address-of expression | +| test.c:90:13:90:14 | v2 | test.c:84:14:84:16 | & ... | test.c:90:13:90:14 | v2 | Cast from pointer with 2-byte alignment (defined by $@) to pointer with base type double with 8-byte alignment. | test.c:84:14:84:16 | & ... | address-of expression | +| test.c:98:11:98:12 | v3 | test.c:93:14:93:16 | & ... | test.c:98:11:98:12 | v3 | Cast from pointer with 4-byte alignment (defined by $@) to pointer with base type long with 8-byte alignment. | test.c:93:14:93:16 | & ... | address-of expression | +| test.c:99:13:99:14 | v3 | test.c:93:14:93:16 | & ... | test.c:99:13:99:14 | v3 | Cast from pointer with 4-byte alignment (defined by $@) to pointer with base type double with 8-byte alignment. | test.c:93:14:93:16 | & ... | address-of expression | +| test.c:107:11:107:12 | v4 | test.c:102:14:102:16 | & ... | test.c:107:11:107:12 | v4 | Cast from pointer with 4-byte alignment (defined by $@) to pointer with base type long with 8-byte alignment. | test.c:102:14:102:16 | & ... | address-of expression | +| test.c:108:13:108:14 | v4 | test.c:102:14:102:16 | & ... | test.c:108:13:108:14 | v4 | Cast from pointer with 4-byte alignment (defined by $@) to pointer with base type double with 8-byte alignment. | test.c:102:14:102:16 | & ... | address-of expression | +| test.c:130:17:130:17 | v | test.c:135:21:135:23 | & ... | test.c:130:17:130:17 | v | Cast from pointer with 1-byte alignment (defined by $@) to pointer with base type int with 4-byte alignment. | test.c:135:21:135:23 | & ... | address-of expression | +| test.c:130:17:130:17 | v | test.c:174:13:174:14 | s2 | test.c:130:17:130:17 | v | Cast from pointer with 2-byte alignment (defined by $@) to pointer with base type int with 4-byte alignment. | test.c:174:13:174:14 | s2 | pointer base type | +| test.c:130:17:130:17 | v | test.c:179:13:179:14 | s3 | test.c:130:17:130:17 | v | Cast from pointer with 2-byte alignment (defined by $@) to pointer with base type int with 4-byte alignment. | test.c:179:13:179:14 | s3 | pointer base type | +| test.c:130:17:130:17 | v | test.c:189:14:189:26 | call to aligned_alloc | test.c:130:17:130:17 | v | Cast from pointer with 2-byte alignment (defined by $@) to pointer with base type int with 4-byte alignment. | test.c:189:14:189:26 | call to aligned_alloc | call to aligned_alloc | +| test.c:158:13:158:20 | & ... | test.c:158:13:158:20 | & ... | test.c:158:13:158:20 | & ... | Cast from pointer with 1-byte alignment (defined by $@) to pointer with base type unsigned long with 8-byte alignment. | test.c:158:13:158:20 | & ... | address-of expression | +| test.c:162:16:162:18 | & ... | test.c:162:16:162:18 | & ... | test.c:162:16:162:18 | & ... | Cast from pointer with 8-byte alignment (defined by $@) to pointer with base type S3 with 64-byte alignment. | test.c:162:16:162:18 | & ... | address-of expression | +| test.c:168:16:168:18 | & ... | test.c:166:24:166:29 | call to malloc | test.c:168:16:168:18 | & ... | Cast from pointer with 16-byte alignment (defined by $@) to pointer with base type S3 with 64-byte alignment. | test.c:166:24:166:29 | call to malloc | call to malloc | +| test.c:168:16:168:18 | & ... | test.c:168:16:168:18 | & ... | test.c:168:16:168:18 | & ... | Cast from pointer with 8-byte alignment (defined by $@) to pointer with base type S3 with 64-byte alignment. | test.c:168:16:168:18 | & ... | address-of expression | +| test.c:186:13:186:14 | v1 | test.c:183:14:183:26 | call to aligned_alloc | test.c:186:13:186:14 | v1 | Cast from pointer with 4-byte alignment (defined by $@) to pointer with base type unsigned long with 8-byte alignment. | test.c:183:14:183:26 | call to aligned_alloc | call to aligned_alloc | +| test.c:216:10:216:11 | p2 | test.c:216:10:216:11 | p2 | test.c:216:10:216:11 | p2 | Cast from pointer with 2-byte alignment (defined by $@) to pointer with base type int with 4-byte alignment. | test.c:216:10:216:11 | p2 | pointer base type | +| test.c:217:11:217:12 | p2 | test.c:217:11:217:12 | p2 | test.c:217:11:217:12 | p2 | Cast from pointer with 2-byte alignment (defined by $@) to pointer with base type long with 8-byte alignment. | test.c:217:11:217:12 | p2 | pointer base type | +| test.c:218:12:218:13 | p2 | test.c:218:12:218:13 | p2 | test.c:218:12:218:13 | p2 | Cast from pointer with 2-byte alignment (defined by $@) to pointer with base type float with 4-byte alignment. | test.c:218:12:218:13 | p2 | pointer base type | +| test.c:219:13:219:14 | p2 | test.c:219:13:219:14 | p2 | test.c:219:13:219:14 | p2 | Cast from pointer with 2-byte alignment (defined by $@) to pointer with base type double with 8-byte alignment. | test.c:219:13:219:14 | p2 | pointer base type | +| test.c:225:10:225:11 | v1 | test.c:222:8:222:9 | p2 | test.c:225:10:225:11 | v1 | Cast from pointer with 2-byte alignment (defined by $@) to pointer with base type int with 4-byte alignment. | test.c:222:8:222:9 | p2 | pointer base type | +| test.c:226:12:226:13 | v1 | test.c:222:8:222:9 | p2 | test.c:226:12:226:13 | v1 | Cast from pointer with 2-byte alignment (defined by $@) to pointer with base type float with 4-byte alignment. | test.c:222:8:222:9 | p2 | pointer base type | +| test.c:227:11:227:12 | v1 | test.c:222:8:222:9 | p2 | test.c:227:11:227:12 | v1 | Cast from pointer with 2-byte alignment (defined by $@) to pointer with base type long with 8-byte alignment. | test.c:222:8:222:9 | p2 | pointer base type | +| test.c:228:13:228:14 | v1 | test.c:222:8:222:9 | p2 | test.c:228:13:228:14 | v1 | Cast from pointer with 2-byte alignment (defined by $@) to pointer with base type double with 8-byte alignment. | test.c:222:8:222:9 | p2 | pointer base type | diff --git a/c/cert/test/rules/EXP36-C/DoNotCastPointerToMoreStrictlyAlignedPointerType.qlref b/c/cert/test/rules/EXP36-C/DoNotCastPointerToMoreStrictlyAlignedPointerType.qlref new file mode 100644 index 0000000000..9e655176f7 --- /dev/null +++ b/c/cert/test/rules/EXP36-C/DoNotCastPointerToMoreStrictlyAlignedPointerType.qlref @@ -0,0 +1 @@ +rules/EXP36-C/DoNotCastPointerToMoreStrictlyAlignedPointerType.ql \ No newline at end of file diff --git a/c/cert/test/rules/EXP36-C/test.c b/c/cert/test/rules/EXP36-C/test.c new file mode 100644 index 0000000000..b32e2ab80f --- /dev/null +++ b/c/cert/test/rules/EXP36-C/test.c @@ -0,0 +1,229 @@ +#include +#include +#include + +void test_direct_cast_alignment() { + char c1 = 1; // assuming 1-byte alignment + (char *)&c1; // COMPLIANT + (short *)&c1; // NON_COMPLIANT + (int *)&c1; // NON_COMPLIANT + (long *)&c1; // NON_COMPLIANT + (float *)&c1; // NON_COMPLIANT + (double *)&c1; // NON_COMPLIANT + + short s1 = 1; // assuming 2-byte alignment + (char *)&s1; // COMPLIANT + (short *)&s1; // COMPLIANT + (int *)&s1; // NON_COMPLIANT + (long *)&s1; // NON_COMPLIANT + (float *)&s1; // NON_COMPLIANT + (double *)&s1; // NON_COMPLIANT + + int i1 = 1; // assuming 4-byte alignment + (char *)&i1; // COMPLIANT + (short *)&i1; // COMPLIANT + (int *)&i1; // COMPLIANT + (float *)&i1; // COMPLIANT + (long *)&i1; // NON_COMPLIANT - assuming 8 byte alignment for longs + (double *)&i1; // NON_COMPLIANT + + float f1 = 1; // assuming 4-byte alignment + (char *)&f1; // COMPLIANT + (short *)&f1; // COMPLIANT + (int *)&f1; // COMPLIANT + (float *)&f1; // COMPLIANT + (long *)&f1; // NON_COMPLIANT + (double *)&f1; // NON_COMPLIANT + + long l1 = 1; // assuming 8-byte alignment + (char *)&l1; // COMPLIANT + (short *)&l1; // COMPLIANT + (int *)&l1; // COMPLIANT + (float *)&l1; // COMPLIANT + (long *)&l1; // COMPLIANT + (double *)&l1; // COMPLIANT + + double d1 = 1; // assuming 8-byte alignment + (char *)&d1; // COMPLIANT + (short *)&d1; // COMPLIANT + (int *)&d1; // COMPLIANT + (float *)&d1; // COMPLIANT + (long *)&d1; // COMPLIANT + (double *)&d1; // COMPLIANT +} + +void custom_aligned_types() { + alignas(int) char c1 = 1; + (char *)&c1; // COMPLIANT + (short *)&c1; // COMPLIANT + (int *)&c1; // COMPLIANT + (float *)&c1; // COMPLIANT + (long *)&c1; // NON_COMPLIANT + (double *)&c1; // NON_COMPLIANT + + alignas(32) char c2 = 1; + (char *)&c2; // COMPLIANT + (short *)&c2; // COMPLIANT + (int *)&c2; // COMPLIANT + (float *)&c2; // COMPLIANT + (long *)&c2; // COMPLIANT + (double *)&c2; // COMPLIANT +} + +void test_via_void_ptr_var_direct() { + char c1 = 1; + void *v1 = &c1; + (char *)v1; // COMPLIANT + (short *)v1; // NON_COMPLIANT + (int *)v1; // NON_COMPLIANT + (float *)v1; // NON_COMPLIANT + (long *)v1; // NON_COMPLIANT + (double *)v1; // NON_COMPLIANT + + short s1 = 1; + void *v2 = &s1; + (char *)v2; // COMPLIANT + (short *)v2; // COMPLIANT + (int *)v2; // NON_COMPLIANT + (float *)v2; // NON_COMPLIANT + (long *)v2; // NON_COMPLIANT + (double *)v2; // NON_COMPLIANT + + int i1 = 1; + void *v3 = &i1; + (char *)v3; // COMPLIANT + (short *)v3; // COMPLIANT + (int *)v3; // COMPLIANT + (float *)v3; // COMPLIANT + (long *)v3; // NON_COMPLIANT - assuming 8 byte alignment for longs + (double *)v3; // NON_COMPLIANT - but only on x64 + + float f1 = 1; + void *v4 = &f1; + (char *)v4; // COMPLIANT + (short *)v4; // COMPLIANT + (int *)v4; // COMPLIANT + (float *)v4; // COMPLIANT + (long *)v4; // NON_COMPLIANT - assuming 8 byte alignment for longs + (double *)v4; // NON_COMPLIANT + + long l1 = 1; + void *v5 = &l1; + (char *)v5; // COMPLIANT + (short *)v5; // COMPLIANT + (int *)v5; // COMPLIANT + (float *)v5; // COMPLIANT + (long *)v5; // COMPLIANT + (double *)v5; // COMPLIANT + + double d1 = 1; + void *v6 = &d1; + (char *)v6; // COMPLIANT + (short *)v6; // COMPLIANT + (int *)v6; // COMPLIANT + (float *)v6; // COMPLIANT + (long *)v6; // COMPLIANT + (double *)v6; // COMPLIANT +} + +int *cast_away(void *v) { + return (int *)v; // compliance depends on context +} + +void test_via_void_indirect() { + char c1 = 1; + cast_away((void *)&c1); // NON_COMPLIANT + + int i1 = 1; + cast_away((void *)&i1); // COMPLIANT +} + +struct S1 { + char c1; + unsigned char data[8]; +}; + +struct S2 { + char c1; + alignas(size_t) unsigned char data[8]; +}; + +struct S3 { + char c1; + alignas(64) unsigned char data[8]; +}; + +void test_struct_alignment() { + struct S1 s1; + (size_t *)&s1.data; // NON_COMPLIANT + + struct S2 s2; + (size_t *)&s2.data; // COMPLIANT + (struct S3 *)&s2; // NON_COMPLIANT +} + +void test_malloc_alignment_and_pointer_arithmetic() { + short *s1 = (short *)malloc(64); + (size_t *)&s1; // COMPLIANT + (struct S3 *)&s1; // NON_COMPLIANT - over-aligned struct + cast_away(s1); // COMPLIANT + + short *s2 = s1 + 1; + (size_t *)&s2; // NON_COMPLIANT[FALSE_NEGATIVE] + (char *)&s2; // COMPLIANT + cast_away(s2); // NON_COMPLIANT + + short *s3 = &s1[1]; + (size_t *)&s3; // NON_COMPLIANT[FALSE_NEGATIVE] + (char *)&s3; // COMPLIANT + cast_away(s3); // NON_COMPLIANT +} + +void test_aligned_alloc_alignment() { + void *v1 = aligned_alloc(4, 8); + (char *)v1; // COMPLIANT + (int *)v1; // COMPLIANT + (size_t *)v1; // NON_COMPLIANT + cast_away(v1); // COMPLIANT + + void *v2 = aligned_alloc(2, 8); + cast_away(v2); // NON_COMPLIANT +} + +void test_standalone_pointer_cast_alignment(void *p1, short *p2) { + void *v1; + + // void* direct + (char *)p1; // COMPLIANT + (short *)p1; // COMPLIANT + (int *)p1; // COMPLIANT + (float *)p1; // COMPLIANT + (long *)p1; // COMPLIANT + (double *)p1; // COMPLIANT + + // void* indirect via void* + v1 = p1; // COMPLIANT + (char *)v1; // COMPLIANT + (short *)v1; // COMPLIANT + (int *)v1; // COMPLIANT + (float *)v1; // COMPLIANT + (long *)v1; // COMPLIANT + (double *)v1; // COMPLIANT + + // short* direct + (char *)p2; // COMPLIANT + (short *)p2; // COMPLIANT + (int *)p2; // NON_COMPLIANT + (long *)p2; // NON_COMPLIANT + (float *)p2; // NON_COMPLIANT + (double *)p2; // NON_COMPLIANT + + // short* indirect via void* + v1 = p2; // COMPLIANT + (char *)v1; // COMPLIANT + (short *)v1; // COMPLIANT + (int *)v1; // NON_COMPLIANT + (float *)v1; // NON_COMPLIANT + (long *)v1; // NON_COMPLIANT + (double *)v1; // NON_COMPLIANT +} \ No newline at end of file diff --git a/c/cert/test/rules/EXP39-C/test.c b/c/cert/test/rules/EXP39-C/test.c new file mode 100644 index 0000000000..1b67ec028e --- /dev/null +++ b/c/cert/test/rules/EXP39-C/test.c @@ -0,0 +1,99 @@ +void test_incompatible_arithmetic() { + float f = 0.0f; + int *p = (int *)&f; // NON_COMPLIANT - arithmetic types are not compatible + // with each other + (*p)++; + + short s[2]; + (int *)&s; // NON_COMPLIANT + + (short(*)[4]) & s; // NON_COMPLIANT - array of size 2 is not compatible with + // array of size 4 (n1570 6.7.6.2 paragraph 7) + (short(*)[2]) & s; // COMPLIANT + + // char may be signed or unsigned, and so is not compatible with either + char c1; + (signed char *)&c1; // NON_COMPLIANT + (unsigned char *)&c1; // NON_COMPLIANT + (char *)&c1; // NON_COMPLIANT + + // int is defined as signed, so is compatible with all the signed versions + // (long, short etc. are similar) + int i1; + (signed int *)&i1; // COMPLIANT + (int *)&i1; // COMPLIANT + (signed *)&i1; // COMPLIANT + (unsigned int *)&i1; // NON_COMPLIANT + (const int *)&i1; // NON_COMPLIANT +} + +struct { + int a; +} * s1; +struct { + int a; +} * s2; +struct S1 { + int a; +} * s3; +struct S1 *s4; + +// TODO test across files +void test_incompatible_structs() { + // s1 and s2 do not have tags, and are therefore not compatible + s1 = s2; // NON_COMPLIANT + // s3 tag is inconsistent with s1 tag + s1 = s3; // NON_COMPLIANT + s3 = s1; // NON_COMPLIANT + // s4 tag is consistent with s3 tag + s3 = s4; // COMPLIANT + s4 = s3; // COMPLIANT +} + +enum E1 { E1A, E1B }; +enum E2 { E2A, E2B }; + +void test_enums() { + enum E1 e1 = E1A; + enum E2 e2 = e1; // COMPLIANT + // Enums are also compatible with one of `char`, a signed integer type or an + // unsigned integer type. It is implementation defined which is used, so + // choose an appropriate type below for this test + (int *)&e1; // COMPLIANT +} + +int *void_cast(void *v) { return (int *)v; } + +void test_indirect_cast() { + float f1 = 0.0f; + void_cast(&f1); // NON_COMPLIANT + int i1 = 0; + void_cast(&i1); // COMPLIANT +} + +signed f(int y) { return y; } +int g(signed int x) { return x; } + +// 6.7.6.3 p15 +void test_compatible_functions() { + signed (*f1)(int) = &g; // COMPLIANT + int (*g1)(signed int) = &f; // COMPLIANT +} + +struct S2 { + int a; + int b; +}; + +struct S3 { + int a; + int b; +}; + +void test_realloc() { + struct S2 *s2 = (struct S2 *)malloc(sizeof(struct S2)); + struct S3 *s3 = (struct S3 *)realloc(s2, sizeof(struct S3)); + s3->a; // NON_COMPLIANT + memset(s3, 0, sizeof(struct S3)); + s3->a; // COMPLIANT +} \ No newline at end of file diff --git a/c/cert/test/rules/EXP43-C/test.c b/c/cert/test/rules/EXP43-C/test.c new file mode 100644 index 0000000000..8527f7ce84 --- /dev/null +++ b/c/cert/test/rules/EXP43-C/test.c @@ -0,0 +1,76 @@ +#include +#include + +int *restrict g1; +int *restrict g2; + +void test_global_local() { + int *restrict i1 = g1; // COMPLIANT + int *restrict i2 = g2; // COMPLIANT + int *restrict i3 = i2; // NON_COMPLIANT + g1 = g2; // NON_COMPLIANT + i1 = i2; // NON_COMPLIANT +} + +void copy(int *restrict p1, int *restrict p2, size_t s) { + for (size_t i = 0; i < s; ++i) { + p2[i] = p1[i]; + } +} + +void test_restrict_params() { + int i1 = 1; + int i2 = 2; + copy(&i1, &i1, 1); // NON_COMPLIANT + copy(&i1, &i2, 1); // COMPLIANT + + int x[10]; + copy(x[0], x[1], 1); // COMPLIANT - non overlapping + copy(x[0], x[1], 2); // NON_COMPLIANT - overlapping +} + +void test_strcpy() { + char s1[] = "my test string"; + char s2[] = "my other string"; + strcpy(&s1, &s1 + 3); // NON_COMPLIANT + strcpy(&s2, &s1); // COMPLIANT +} + +void test_strcpy_s() { + char s1[] = "my test string"; + char s2[] = "my other string"; + strcpy_s(&s1, &s1 + 3); // NON_COMPLIANT + strcpy_s(&s2, sizeof(s2), &s1); // COMPLIANT +} + +void test_memcpy() { + char s1[] = "my test string"; + char s2[] = "my other string"; + memcpy(&s1, &s1 + 3, 5); // NON_COMPLIANT + memcpy(&s2, &s1 + 3, 5); // COMPLIANT +} + +void test_memcpy_s() { + char s1[] = "my test string"; + char s2[] = "my other string"; + memcpy_s(&s1, sizeof(s1), &s1 + 3, 5); // NON_COMPLIANT + memcpy_s(&s2, sizeof(s2), &s1 + 3, 5); // COMPLIANT +} + +void test_memmove() { + char s1[] = "my test string"; + char s2[] = "my other string"; + memmove(&s1, &s1 + 3, 5); // COMPLIANT + memmove(&s2, &s1 + 3, 5); // COMPLIANT +} + +void test_scanf() { + char s1[200] = "%10s"; + scanf(&s2, &s2 + 4); // NON_COMPLIANT +} + +// TODO also consider the following: +// strncpy(), strncpy_s() +// strcat(), strcat_s() +// strncat(), strncat_s() +// strtok_s() \ No newline at end of file diff --git a/c/misra/src/rules/RULE-11-7/CastBetweenPointerToObjectAndNonIntArithmeticType.ql b/c/misra/src/rules/RULE-11-7/CastBetweenPointerToObjectAndNonIntArithmeticType.ql index 2aa49ae2a0..3be7644b9d 100644 --- a/c/misra/src/rules/RULE-11-7/CastBetweenPointerToObjectAndNonIntArithmeticType.ql +++ b/c/misra/src/rules/RULE-11-7/CastBetweenPointerToObjectAndNonIntArithmeticType.ql @@ -32,4 +32,4 @@ where [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 + "Cast performed between a pointer to object type and a non-integer arithmetic type." \ 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 index 0b96b3c747..133e568499 100644 --- a/c/misra/test/rules/RULE-11-7/CastBetweenPointerToObjectAndNonIntArithmeticType.expected +++ b/c/misra/test/rules/RULE-11-7/CastBetweenPointerToObjectAndNonIntArithmeticType.expected @@ -1,3 +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. | +| test.c:5:13:5:20 | (bool)... | Cast performed between a pointer to object type and a non-integer arithmetic type. | +| test.c:7:21:7:28 | (bool)... | Cast performed between a pointer to object type and a non-integer arithmetic type. | +| test.c:8:8:8:16 | (int *)... | Cast performed between a pointer to object type and a non-integer arithmetic type. | diff --git a/change_notes/2022-11-14-fix-RULE-11-7-message.md b/change_notes/2022-11-14-fix-RULE-11-7-message.md new file mode 100644 index 0000000000..f1cb253f3b --- /dev/null +++ b/change_notes/2022-11-14-fix-RULE-11-7-message.md @@ -0,0 +1,2 @@ + - `RULE-11-7` - `CastBetweenPointerToObjectAndNonIntArithmeticType.ql` + - Corrected the query output message to describe a cast involving a pointer to an object rather than a void pointer. \ No newline at end of file diff --git a/cpp/cert/src/rules/MEM57-CPP/UsingDefaultOperatorNewForOverAlignedTypes.ql b/cpp/cert/src/rules/MEM57-CPP/UsingDefaultOperatorNewForOverAlignedTypes.ql index d0210791d4..8fc33f8457 100644 --- a/cpp/cert/src/rules/MEM57-CPP/UsingDefaultOperatorNewForOverAlignedTypes.ql +++ b/cpp/cert/src/rules/MEM57-CPP/UsingDefaultOperatorNewForOverAlignedTypes.ql @@ -14,26 +14,7 @@ import cpp import codingstandards.cpp.cert - -/* - * In theory each compilation of each file can have a different `max_align_t` value (for example, - * if the same file is compiled under different compilers in the same database). We don't have the - * fine-grained data to determine which compilation each operator new call is from, so we instead - * report only in cases where there's a single clear alignment for the whole database. - */ - -class MaxAlignT extends TypedefType { - MaxAlignT() { getName() = "max_align_t" } -} - -/** - * Gets the alignment for `max_align_t`, assuming there is a single consistent alignment for the - * database. - */ -int getGlobalMaxAlignT() { - count(MaxAlignT m | | m.getAlignment()) = 1 and - result = any(MaxAlignT t).getAlignment() -} +import codingstandards.cpp.Alignment from NewOrNewArrayExpr newExpr, Type overAlignedType where diff --git a/cpp/common/src/codingstandards/cpp/Alignment.qll b/cpp/common/src/codingstandards/cpp/Alignment.qll new file mode 100644 index 0000000000..c254d7909a --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/Alignment.qll @@ -0,0 +1,25 @@ +/** + * Provides a library with additional modeling for C and C++ memory alignment constructs. + */ + +import cpp + +/* + * In theory each compilation of each file can have a different `max_align_t` value (for example, + * if the same file is compiled under different compilers in the same database). We don't have the + * fine-grained data to determine which compilation each operator new call is from, so we instead + * report only in cases where there's a single clear alignment for the whole database. + */ + +class MaxAlignT extends TypedefType { + MaxAlignT() { getName() = "max_align_t" } +} + +/** + * Gets the alignment for `max_align_t`, assuming there is a single consistent alignment for the + * database. + */ +int getGlobalMaxAlignT() { + count(MaxAlignT m | | m.getAlignment()) = 1 and + result = any(MaxAlignT t).getAlignment() +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Pointers3.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Pointers3.qll new file mode 100644 index 0000000000..9c4741f620 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Pointers3.qll @@ -0,0 +1,74 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype Pointers3Query = + TDoNotAccessVolatileObjectWithNonVolatileReferenceQuery() or + TDoNotCastPointerToMoreStrictlyAlignedPointerTypeQuery() or + TDoNotAccessVariableViaPointerOfIncompatibleTypeQuery() or + TUndefinedBehaviorWithRestrictQualifiedPointersQuery() + +predicate isPointers3QueryMetadata(Query query, string queryId, string ruleId) { + query = + // `Query` instance for the `doNotAccessVolatileObjectWithNonVolatileReference` query + Pointers3Package::doNotAccessVolatileObjectWithNonVolatileReferenceQuery() and + queryId = + // `@id` for the `doNotAccessVolatileObjectWithNonVolatileReference` query + "c/cert/do-not-access-volatile-object-with-non-volatile-reference" and + ruleId = "EXP32-C" + or + query = + // `Query` instance for the `doNotCastPointerToMoreStrictlyAlignedPointerType` query + Pointers3Package::doNotCastPointerToMoreStrictlyAlignedPointerTypeQuery() and + queryId = + // `@id` for the `doNotCastPointerToMoreStrictlyAlignedPointerType` query + "c/cert/do-not-cast-pointer-to-more-strictly-aligned-pointer-type" and + ruleId = "EXP36-C" + or + query = + // `Query` instance for the `doNotAccessVariableViaPointerOfIncompatibleType` query + Pointers3Package::doNotAccessVariableViaPointerOfIncompatibleTypeQuery() and + queryId = + // `@id` for the `doNotAccessVariableViaPointerOfIncompatibleType` query + "c/cert/do-not-access-variable-via-pointer-of-incompatible-type" and + ruleId = "EXP39-C" + or + query = + // `Query` instance for the `undefinedBehaviorWithRestrictQualifiedPointers` query + Pointers3Package::undefinedBehaviorWithRestrictQualifiedPointersQuery() and + queryId = + // `@id` for the `undefinedBehaviorWithRestrictQualifiedPointers` query + "c/cert/undefined-behavior-with-restrict-qualified-pointers" and + ruleId = "EXP43-C" +} + +module Pointers3Package { + Query doNotAccessVolatileObjectWithNonVolatileReferenceQuery() { + //autogenerate `Query` type + result = + // `Query` type for `doNotAccessVolatileObjectWithNonVolatileReference` query + TQueryC(TPointers3PackageQuery(TDoNotAccessVolatileObjectWithNonVolatileReferenceQuery())) + } + + Query doNotCastPointerToMoreStrictlyAlignedPointerTypeQuery() { + //autogenerate `Query` type + result = + // `Query` type for `doNotCastPointerToMoreStrictlyAlignedPointerType` query + TQueryC(TPointers3PackageQuery(TDoNotCastPointerToMoreStrictlyAlignedPointerTypeQuery())) + } + + Query doNotAccessVariableViaPointerOfIncompatibleTypeQuery() { + //autogenerate `Query` type + result = + // `Query` type for `doNotAccessVariableViaPointerOfIncompatibleType` query + TQueryC(TPointers3PackageQuery(TDoNotAccessVariableViaPointerOfIncompatibleTypeQuery())) + } + + Query undefinedBehaviorWithRestrictQualifiedPointersQuery() { + //autogenerate `Query` type + result = + // `Query` type for `undefinedBehaviorWithRestrictQualifiedPointers` query + TQueryC(TPointers3PackageQuery(TUndefinedBehaviorWithRestrictQualifiedPointersQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll index ad05d9b737..1a0ac56434 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll @@ -24,6 +24,7 @@ import Language1 import Misc import Pointers1 import Pointers2 +import Pointers3 import Preprocessor1 import Preprocessor2 import Preprocessor3 @@ -60,6 +61,7 @@ newtype TCQuery = TMiscPackageQuery(MiscQuery q) or TPointers1PackageQuery(Pointers1Query q) or TPointers2PackageQuery(Pointers2Query q) or + TPointers3PackageQuery(Pointers3Query q) or TPreprocessor1PackageQuery(Preprocessor1Query q) or TPreprocessor2PackageQuery(Preprocessor2Query q) or TPreprocessor3PackageQuery(Preprocessor3Query q) or @@ -96,6 +98,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId) { isMiscQueryMetadata(query, queryId, ruleId) or isPointers1QueryMetadata(query, queryId, ruleId) or isPointers2QueryMetadata(query, queryId, ruleId) or + isPointers3QueryMetadata(query, queryId, ruleId) or isPreprocessor1QueryMetadata(query, queryId, ruleId) or isPreprocessor2QueryMetadata(query, queryId, ruleId) or isPreprocessor3QueryMetadata(query, queryId, ruleId) or diff --git a/rule_packages/c/Pointers3.json b/rule_packages/c/Pointers3.json new file mode 100644 index 0000000000..e395543690 --- /dev/null +++ b/rule_packages/c/Pointers3.json @@ -0,0 +1,80 @@ +{ + "CERT-C": { + "EXP32-C": { + "properties": { + "obligation": "rule" + }, + "queries": [ + { + "description": "If an an object defined with a volatile-qualified type is referred to with an lvalue of a non-volatile-qualified type, the behavior is undefined.", + "kind": "problem", + "name": "Do not access a volatile object through a nonvolatile reference", + "precision": "high", + "severity": "error", + "short_name": "DoNotAccessVolatileObjectWithNonVolatileReference", + "tags": [ + "correctness" + ] + } + ], + "title": "Do not access a volatile object through a nonvolatile reference" + }, + "EXP36-C": { + "properties": { + "obligation": "rule" + }, + "queries": [ + { + "description": "Converting a pointer to a different type results in undefined behavior if the pointer is not correctly aligned for the new type.", + "kind": "path-problem", + "name": "Do not cast pointers into more strictly aligned pointer types", + "precision": "high", + "severity": "error", + "short_name": "DoNotCastPointerToMoreStrictlyAlignedPointerType", + "tags": [ + "correctness" + ] + } + ], + "title": "Do not cast pointers into more strictly aligned pointer types" + }, + "EXP39-C": { + "properties": { + "obligation": "rule" + }, + "queries": [ + { + "description": "Modifying underlying pointer data through a pointer of an incompatible type can lead to unpredictable results.", + "kind": "problem", + "name": "Do not access a variable through a pointer of an incompatible type", + "precision": "very-high", + "severity": "error", + "short_name": "DoNotAccessVariableViaPointerOfIncompatibleType", + "tags": [ + "correctness" + ] + } + ], + "title": "Do not access a variable through a pointer of an incompatible type" + }, + "EXP43-C": { + "properties": { + "obligation": "rule" + }, + "queries": [ + { + "description": "", + "kind": "problem", + "name": "Avoid undefined behavior when using restrict-qualified pointers", + "precision": "very-high", + "severity": "error", + "short_name": "UndefinedBehaviorWithRestrictQualifiedPointers", + "tags": [ + "correctness" + ] + } + ], + "title": "Avoid undefined behavior when using restrict-qualified pointers" + } + } +} \ No newline at end of file