@@ -9,6 +9,7 @@ import codingstandards.cpp.Exclusions
99import codingstandards.cpp.Allocations
1010import semmle.code.cpp.dataflow.DataFlow
1111import semmle.code.cpp.dataflow.DataFlow2
12+ import DataFlow:: PathGraph
1213
1314/**
1415 * A pointer to potentially dynamically allocated memory
@@ -38,41 +39,54 @@ class FreeExprSink extends DataFlow::Node {
3839}
3940
4041/**
41- * A data-flow configuration that tracks flow from an `AllocExprSource` to
42- * the value assigned to a variable.
42+ * An `Expr` that is an `AddressOfExpr` of a `Variable`.
43+ *
44+ * `Field`s of `PointerType` are not included in order to reduce false-positives,
45+ * as the data-flow library sometimes equates pointers to their underlying data.
4346 */
44- class AllocExprSourceToAssignedValueConfig extends DataFlow2:: Configuration {
45- AllocExprSourceToAssignedValueConfig ( ) { this = "AllocExprSourceToAssignedValueConfig" }
46-
47- override predicate isSource ( DataFlow:: Node source ) { source instanceof AllocExprSource }
48-
49- override predicate isSink ( DataFlow:: Node sink ) {
50- sink .asExpr ( ) = any ( Variable v ) .getAnAssignedValue ( )
51- }
52- }
53-
54- /**
55- * An assignment of a value that is not a dynamically allocated pointer to a variable.
56- */
57- class NonDynamicallyAllocatedVariableAssignment extends DataFlow:: Node {
58- NonDynamicallyAllocatedVariableAssignment ( ) {
59- exists ( Variable v |
60- this .asExpr ( ) = v .getAnAssignedValue ( ) and
61- not this .asExpr ( ) instanceof NullValue and
62- not any ( AllocExprSourceToAssignedValueConfig cfg ) .hasFlowTo ( this )
63- )
47+ class AddressOfExprSourceNode extends Expr {
48+ AddressOfExprSourceNode ( ) {
49+ exists ( VariableAccess va |
50+ this .( AddressOfExpr ) .getOperand ( ) = va and
51+ (
52+ va .getTarget ( ) instanceof StackVariable or
53+ va .getTarget ( ) instanceof GlobalVariable or
54+ // allow address-of field, but only if that field is not a pointer type,
55+ // as there may be nested allocations assigned to fields of pointer types.
56+ va .( FieldAccess ) .getTarget ( ) .getUnderlyingType ( ) instanceof ArithmeticType
57+ )
58+ or
59+ this = va and
60+ exists ( GlobalVariable gv |
61+ gv = va .getTarget ( ) and
62+ (
63+ gv .getUnderlyingType ( ) instanceof ArithmeticType or
64+ not exists ( gv .getAnAssignedValue ( ) ) or
65+ exists ( AddressOfExprSourceNode other |
66+ DataFlow:: localExprFlow ( other , gv .getAnAssignedValue ( ) )
67+ )
68+ )
69+ )
70+ ) and
71+ // exclude alloc(&allocated_ptr) cases
72+ not any ( DynamicMemoryAllocationToAddressOfDefiningArgConfig cfg )
73+ .hasFlowTo ( DataFlow:: definitionByReferenceNodeFromArgument ( this ) )
6474 }
6575}
6676
6777/**
6878 * A data-flow configuration that tracks flow from an `AllocExprSource` to a `FreeExprSink`.
6979 */
70- class DynamicMemoryAllocationToFreeConfig extends DataFlow:: Configuration {
71- DynamicMemoryAllocationToFreeConfig ( ) { this = "DynamicMemoryAllocationToFreeConfig" }
80+ class DynamicMemoryAllocationToAddressOfDefiningArgConfig extends DataFlow2:: Configuration {
81+ DynamicMemoryAllocationToAddressOfDefiningArgConfig ( ) {
82+ this = "DynamicMemoryAllocationToAddressOfDefiningArgConfig"
83+ }
7284
7385 override predicate isSource ( DataFlow:: Node source ) { source instanceof AllocExprSource }
7486
75- override predicate isSink ( DataFlow:: Node sink ) { sink instanceof FreeExprSink }
87+ override predicate isSink ( DataFlow:: Node sink ) {
88+ sink .asDefiningArgument ( ) instanceof AddressOfExpr
89+ }
7690}
7791
7892/**
@@ -83,14 +97,14 @@ class NonDynamicPointerToFreeConfig extends DataFlow::Configuration {
8397 NonDynamicPointerToFreeConfig ( ) { this = "NonDynamicPointerToFreeConfig" }
8498
8599 override predicate isSource ( DataFlow:: Node source ) {
86- source instanceof NonDynamicallyAllocatedVariableAssignment
100+ source . asExpr ( ) instanceof AddressOfExprSourceNode
87101 }
88102
89103 override predicate isSink ( DataFlow:: Node sink ) { sink instanceof FreeExprSink }
90104
91105 override predicate isBarrierOut ( DataFlow:: Node node ) {
92106 // the default interprocedural data-flow model flows through any field or array assignment
93- // expressionsto the qualifier (array base, pointer dereferenced, or qualifier) instead of the
107+ // expressions to the qualifier (array base, pointer dereferenced, or qualifier) instead of the
94108 // individual element or field that the assignment modifies. this default behaviour causes
95109 // false positives for future frees of the object base, so we remove the edges
96110 // between those assignments from the graph with `isBarrierOut`.
@@ -103,25 +117,22 @@ class NonDynamicPointerToFreeConfig extends DataFlow::Configuration {
103117 )
104118 )
105119 }
120+
121+ override predicate isBarrierIn ( DataFlow:: Node node ) {
122+ // only the last source expression is relevant
123+ isSource ( node )
124+ }
106125}
107126
108127abstract class OnlyFreeMemoryAllocatedDynamicallySharedSharedQuery extends Query { }
109128
110129Query getQuery ( ) { result instanceof OnlyFreeMemoryAllocatedDynamicallySharedSharedQuery }
111130
112131query predicate problems (
113- FreeExprSink free , string message , DataFlow:: Node source , string sourceDescription
132+ DataFlow :: PathNode element , DataFlow :: PathNode source , DataFlow:: PathNode sink , string message
114133) {
115- not isExcluded ( free .asExpr ( ) , getQuery ( ) ) and
116- (
117- not any ( DynamicMemoryAllocationToFreeConfig cfg ) .hasFlowTo ( free ) and
118- not any ( NonDynamicPointerToFreeConfig cfg ) .hasFlowTo ( free ) and
119- message = "Free expression frees non-dynamically allocated memory." and
120- source = free and
121- sourceDescription = ""
122- or
123- any ( NonDynamicPointerToFreeConfig cfg ) .hasFlow ( source , free ) and
124- message = "Free expression frees $@ which was not dynamically allocated." and
125- sourceDescription = "memory"
126- )
134+ not isExcluded ( element .getNode ( ) .asExpr ( ) , getQuery ( ) ) and
135+ element = sink and
136+ any ( NonDynamicPointerToFreeConfig cfg ) .hasFlowPath ( source , sink ) and
137+ message = "Free expression frees memory which was not dynamically allocated."
127138}
0 commit comments