@@ -15,177 +15,14 @@ import cpp
15
15
import semmle.code.cpp.dataflow.new.DataFlow
16
16
import semmle.code.cpp.ir.IR
17
17
import FlowAfterFree
18
- import UseAfterFree:: PathGraph
18
+ import UseAfterFree
19
+ import UseAfterFreeTrace:: PathGraph
19
20
20
- /**
21
- * Holds if `call` is a call to a function that obviously
22
- * doesn't dereference its `i`'th argument.
23
- */
24
- private predicate externalCallNeverDereferences ( FormattingFunctionCall call , int arg ) {
25
- exists ( int formatArg |
26
- pragma [ only_bind_out ] ( call .getFormatArgument ( formatArg ) ) =
27
- pragma [ only_bind_out ] ( call .getArgument ( arg ) ) and
28
- call .getFormat ( ) .( FormatLiteral ) .getConvSpec ( formatArg ) != "%s"
29
- )
30
- }
31
-
32
- predicate isUse0 ( Expr e ) {
33
- not isFree ( _, _, e , _) and
34
- (
35
- e = any ( PointerDereferenceExpr pde ) .getOperand ( )
36
- or
37
- e = any ( PointerFieldAccess pfa ) .getQualifier ( )
38
- or
39
- e = any ( ArrayExpr ae ) .getArrayBase ( )
40
- or
41
- e = any ( Call call ) .getQualifier ( )
42
- or
43
- // Assume any function without a body will dereference the pointer
44
- exists ( int i , Call call , Function f |
45
- e = call .getArgument ( i ) and
46
- f = call .getTarget ( ) and
47
- not f .hasEntryPoint ( ) and
48
- // Exclude known functions we know won't dereference the pointer.
49
- // For example, a call such as `printf("%p", myPointer)`.
50
- not externalCallNeverDereferences ( call , i )
51
- )
52
- )
53
- }
54
-
55
- module ParameterSinks {
56
- import semmle.code.cpp.ir.ValueNumbering
57
-
58
- predicate flowsToUse ( DataFlow:: Node n ) {
59
- isUse0 ( n .asExpr ( ) )
60
- or
61
- exists ( DataFlow:: Node succ |
62
- flowsToUse ( succ ) and
63
- DataFlow:: localFlowStep ( n , succ )
64
- )
65
- }
66
-
67
- private predicate flowsFromParam ( DataFlow:: Node n ) {
68
- flowsToUse ( n ) and
69
- (
70
- n .asParameter ( ) .getUnspecifiedType ( ) instanceof PointerType
71
- or
72
- exists ( DataFlow:: Node prev |
73
- flowsFromParam ( prev ) and
74
- DataFlow:: localFlowStep ( prev , n )
75
- )
76
- )
77
- }
78
-
79
- private predicate step ( DataFlow:: Node n1 , DataFlow:: Node n2 ) {
80
- flowsFromParam ( n1 ) and
81
- flowsFromParam ( n2 ) and
82
- DataFlow:: localFlowStep ( n1 , n2 )
83
- }
84
-
85
- private predicate paramToUse ( DataFlow:: Node n1 , DataFlow:: Node n2 ) = fastTC( step / 2 ) ( n1 , n2 )
86
-
87
- private predicate hasFlow (
88
- DataFlow:: Node source , InitializeParameterInstruction init , DataFlow:: Node sink
89
- ) {
90
- pragma [ only_bind_out ] ( source .asParameter ( ) ) = pragma [ only_bind_out ] ( init .getParameter ( ) ) and
91
- paramToUse ( source , sink ) and
92
- isUse0 ( sink .asExpr ( ) )
93
- }
94
-
95
- private InitializeParameterInstruction getAnAlwaysDereferencedParameter0 ( ) {
96
- exists ( DataFlow:: Node source , DataFlow:: Node sink , IRBlock b1 , int i1 , IRBlock b2 , int i2 |
97
- hasFlow ( pragma [ only_bind_into ] ( source ) , result , pragma [ only_bind_into ] ( sink ) ) and
98
- source .hasIndexInBlock ( b1 , pragma [ only_bind_into ] ( i1 ) ) and
99
- sink .hasIndexInBlock ( b2 , pragma [ only_bind_into ] ( i2 ) ) and
100
- strictlyPostDominates ( b2 , i2 , b1 , i1 )
101
- )
102
- }
103
-
104
- private CallInstruction getAnAlwaysReachedCallInstruction ( ) {
105
- exists ( IRFunction f | result .getBlock ( ) .postDominates ( f .getEntryBlock ( ) ) )
106
- }
107
-
108
- pragma [ nomagic]
109
- private predicate callHasTargetAndArgument ( Function f , int i , Instruction argument ) {
110
- exists ( CallInstruction call |
111
- call .getStaticCallTarget ( ) = f and
112
- call .getArgument ( i ) = argument and
113
- call = getAnAlwaysReachedCallInstruction ( )
114
- )
115
- }
116
-
117
- pragma [ nomagic]
118
- private predicate initializeParameterInFunction ( Function f , int i ) {
119
- exists ( InitializeParameterInstruction init |
120
- pragma [ only_bind_out ] ( init .getEnclosingFunction ( ) ) = f and
121
- init .hasIndex ( i ) and
122
- init = getAnAlwaysDereferencedParameter ( )
123
- )
124
- }
125
-
126
- pragma [ nomagic]
127
- private predicate alwaysDereferencedArgumentHasValueNumber ( ValueNumber vn ) {
128
- exists ( int i , Function f , Instruction argument |
129
- callHasTargetAndArgument ( f , i , argument ) and
130
- initializeParameterInFunction ( pragma [ only_bind_into ] ( f ) , pragma [ only_bind_into ] ( i ) ) and
131
- vn .getAnInstruction ( ) = argument
132
- )
133
- }
134
-
135
- InitializeParameterInstruction getAnAlwaysDereferencedParameter ( ) {
136
- result = getAnAlwaysDereferencedParameter0 ( )
137
- or
138
- exists ( ValueNumber vn |
139
- alwaysDereferencedArgumentHasValueNumber ( vn ) and
140
- vn .getAnInstruction ( ) = result
141
- )
142
- }
143
- }
144
-
145
- module IsUse {
146
- private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplCommon
147
-
148
- predicate isUse ( DataFlow:: Node n , Expr e ) {
149
- isUse0 ( e ) and n .asExpr ( ) = e
150
- or
151
- exists ( CallInstruction call , InitializeParameterInstruction init |
152
- n .asOperand ( ) .getDef ( ) .getUnconvertedResultExpression ( ) = e and
153
- pragma [ only_bind_into ] ( init ) = ParameterSinks:: getAnAlwaysDereferencedParameter ( ) and
154
- viableParamArg ( call , DataFlow:: instructionNode ( init ) , n ) and
155
- pragma [ only_bind_out ] ( init .getEnclosingFunction ( ) ) =
156
- pragma [ only_bind_out ] ( call .getStaticCallTarget ( ) )
157
- )
158
- }
159
- }
160
-
161
- import IsUse
162
-
163
- /**
164
- * `dealloc1` is a deallocation expression, `e` is an expression that dereferences a
165
- * pointer, and the `(dealloc1, e)` pair should be excluded by the `FlowFromFree` library.
166
- */
167
- bindingset [ dealloc1, e]
168
- predicate isExcludeFreeUsePair ( DeallocationExpr dealloc1 , Expr e ) {
169
- // From https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-mmfreepagesfrommdl:
170
- // "After calling MmFreePagesFromMdl, the caller must also call ExFreePool
171
- // to release the memory that was allocated for the MDL structure."
172
- dealloc1 .( FunctionCall ) .getTarget ( ) .hasGlobalName ( "MmFreePagesFromMdl" ) and
173
- isExFreePoolCall ( _, e )
174
- }
175
-
176
- module UseAfterFreeParam implements FlowFromFreeParamSig {
177
- predicate isSink = isUse / 2 ;
178
-
179
- predicate isExcluded = isExcludeFreeUsePair / 2 ;
180
-
181
- predicate sourceSinkIsRelated = defaultSourceSinkIsRelated / 2 ;
182
- }
183
-
184
- module UseAfterFree = FlowFromFree< UseAfterFreeParam > ;
21
+ module UseAfterFreeTrace = FlowFromFree< UseAfterFreeParam > ;
185
22
186
- from UseAfterFree :: PathNode source , UseAfterFree :: PathNode sink , DeallocationExpr dealloc
23
+ from UseAfterFreeTrace :: PathNode source , UseAfterFreeTrace :: PathNode sink , DeallocationExpr dealloc
187
24
where
188
- UseAfterFree :: flowPath ( source , sink ) and
25
+ UseAfterFreeTrace :: flowPath ( source , sink ) and
189
26
isFree ( source .getNode ( ) , _, _, dealloc )
190
27
select sink .getNode ( ) , source , sink , "Memory may have been previously freed by $@." , dealloc ,
191
28
dealloc .toString ( )
0 commit comments