Skip to content

Commit d483c3c

Browse files
author
Nikita Kraiouchkine
committed
Update EXP32-C query and test
1 parent 3d337ce commit d483c3c

File tree

3 files changed

+48
-32
lines changed

3 files changed

+48
-32
lines changed

c/cert/src/rules/EXP32-C/DoNotAccessVolatileObjectWithNonVolatileReference.ql

Lines changed: 38 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -13,53 +13,61 @@
1313

1414
import cpp
1515
import codingstandards.c.cert
16+
import semmle.code.cpp.controlflow.Dereferenced
17+
import semmle.code.cpp.controlflow.StackVariableReachability
18+
19+
abstract class UndefinedVolatilePointerExpr extends Expr {
20+
abstract string getMessage();
21+
}
22+
23+
/**
24+
* Gets the depth of a pointer's base type's volatile qualifier
25+
*/
26+
int getAVolatileDepth(PointerType pt) {
27+
pt.getBaseType().isVolatile() and result = 1
28+
or
29+
result = getAVolatileDepth(pt.getBaseType()) + 1
30+
}
1631

1732
/**
1833
* A `Cast` which converts from a pointer to a volatile-qualified type
1934
* to a pointer to a non-volatile-qualified type.
2035
*/
21-
class CastFromVolatileToNonVolatileBaseType extends Cast {
36+
class CastFromVolatileToNonVolatileBaseType extends Cast, UndefinedVolatilePointerExpr {
2237
CastFromVolatileToNonVolatileBaseType() {
23-
this.getExpr().getType().(PointerType).getBaseType*().isVolatile() and
24-
this.getActualType() instanceof PointerType and
25-
not this.getActualType().(PointerType).getBaseType*().isVolatile()
38+
exists(int i |
39+
i = getAVolatileDepth(this.getExpr().getType()) and
40+
not i = getAVolatileDepth(this.getActualType())
41+
)
42+
}
43+
44+
override string getMessage() {
45+
result = "Cast of object with a volatile-qualified type to a non-volatile-qualified type."
2646
}
2747
}
2848

2949
/**
3050
* An `AssignExpr` with an *lvalue* that is a pointer to a volatile base type and
3151
* and *rvalue* that is not also a pointer to a volatile base type.
3252
*/
33-
class NonVolatileObjectAssignedToVolatilePointer extends AssignExpr {
53+
class NonVolatileObjectAssignedToVolatilePointer extends AssignExpr, UndefinedVolatilePointerExpr {
3454
NonVolatileObjectAssignedToVolatilePointer() {
35-
this.getLValue().getType().(DerivedType).getBaseType*().isVolatile() and
36-
not this.getRValue().getUnconverted().getType().(DerivedType).getBaseType*().isVolatile()
55+
exists(int i |
56+
not i = getAVolatileDepth(this.getRValue().getType()) and
57+
i = getAVolatileDepth(this.getLValue().(VariableAccess).getTarget().getType())
58+
) and
59+
exists(VariableAccess va |
60+
va = this.getRValue().getAChild*().(VariableAccess).getTarget().getAnAccess() and
61+
this.getASuccessor+() = va
62+
)
3763
}
3864

39-
/**
40-
* All `VariableAccess` expressions which are transitive successors of
41-
* this `Expr` and which access the variable accessed in the *rvalue* of this `Expr`
42-
*/
43-
Expr getASubsequentAccessOfAssignedObject() {
65+
override string getMessage() {
4466
result =
45-
any(VariableAccess va |
46-
va = this.getRValue().getAChild*().(VariableAccess).getTarget().getAnAccess() and
47-
this.getASuccessor+() = va
48-
|
49-
va
50-
)
67+
"Assignment indicates a volatile object, but a later access of the object occurs via a non-volatile pointer."
5168
}
5269
}
5370

54-
from Expr e, string message
55-
where
56-
not isExcluded(e, Pointers3Package::doNotAccessVolatileObjectWithNonVolatileReferenceQuery()) and
57-
(
58-
e instanceof CastFromVolatileToNonVolatileBaseType and
59-
message = "Cast of object with a volatile-qualified type to a non-volatile-qualified type."
60-
or
61-
exists(e.(NonVolatileObjectAssignedToVolatilePointer).getASubsequentAccessOfAssignedObject()) and
62-
message =
63-
"Non-volatile object referenced via pointer to volatile type and later accessed via its original object of a non-volatile-qualified type."
64-
)
65-
select e, message
71+
from UndefinedVolatilePointerExpr e
72+
where not isExcluded(e, Pointers3Package::doNotAccessVolatileObjectWithNonVolatileReferenceQuery())
73+
select e, e.getMessage()
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
| test.c:5:13:5:21 | (int *)... | Cast of object with a volatile-qualified type to a non-volatile-qualified type. |
22
| test.c:6:13:6:31 | (int *)... | Cast of object with a volatile-qualified type to a non-volatile-qualified type. |
3-
| 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. |
4-
| 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. |
3+
| test.c:14:3:14:55 | ... = ... | Assignment indicates a volatile object, but a later access of the object occurs via a non-volatile pointer. |
4+
| test.c:24:3:25:36 | ... = ... | Assignment indicates a volatile object, but a later access of the object occurs via a non-volatile pointer. |
5+
| test.c:42:24:42:41 | (int *)... | Cast of object with a volatile-qualified type to a non-volatile-qualified type. |

c/cert/test/rules/EXP32-C/test.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,11 @@ void test_volatile_not_lost_by_assignment_and_cast() {
3535
compliant_pointer_to_pointer = &compliant_pointer; // COMPLIANT
3636
*compliant_pointer_to_pointer = &val;
3737
*compliant_pointer; // Volatile object is accessed through a volatile pointer
38+
}
39+
40+
void test_volatile_lost_by_assignment_and_cast_2() {
41+
volatile int *ptr = 0;
42+
int *volatile ptr2 = (int *volatile)ptr; // NON_COMPLIANT
43+
*ptr2; // Volatile object dereferenced through volatile pointer to
44+
// non-volatile object
3845
}

0 commit comments

Comments
 (0)