@@ -3,6 +3,8 @@ import cpp
33private import InputIR
44private import semmle.code.cpp.ir.internal.IntegerConstant as Ints
55
6+ private import semmle.code.cpp.models.interfaces.Alias
7+
68private class IntValue = Ints:: IntValue ;
79
810/**
@@ -46,7 +48,7 @@ private IntValue getFieldBitOffset(Field field) {
4648 * not result in any address held in that operand from escaping beyond the
4749 * instruction.
4850 */
49- predicate operandIsConsumedWithoutEscaping ( Operand operand ) {
51+ private predicate operandIsConsumedWithoutEscaping ( Operand operand ) {
5052 // The source/destination address of a Load/Store does not escape (but the
5153 // loaded/stored value could).
5254 operand instanceof AddressOperand or
@@ -60,7 +62,18 @@ predicate operandIsConsumedWithoutEscaping(Operand operand) {
6062 // Converting an address to a `bool` does not escape the address.
6163 instr .( ConvertInstruction ) .getResultType ( ) instanceof BoolType
6264 )
63- )
65+ ) or
66+ // Some standard function arguments never escape
67+ isNeverEscapesArgument ( operand )
68+ }
69+
70+ private predicate operandEscapesDomain ( Operand operand ) {
71+ not operandIsConsumedWithoutEscaping ( operand ) and
72+ not operandIsPropagated ( operand , _) and
73+ not isArgumentForParameter ( _, operand , _) and
74+ not isOnlyEscapesViaReturnArgument ( operand ) and
75+ not operand .getUseInstruction ( ) instanceof ReturnValueInstruction and
76+ not operand instanceof PhiOperand
6477}
6578
6679/**
@@ -98,7 +111,7 @@ IntValue getPointerBitOffset(PointerOffsetInstruction instr) {
98111 * `bitOffset`. If the address is propagated, but the offset is not known to be
99112 * a constant, then `bitOffset` is unknown.
100113 */
101- predicate operandIsPropagated ( Operand operand , IntValue bitOffset ) {
114+ private predicate operandIsPropagated ( Operand operand , IntValue bitOffset ) {
102115 exists ( Instruction instr |
103116 instr = operand .getUseInstruction ( ) and
104117 (
@@ -134,50 +147,146 @@ predicate operandIsPropagated(Operand operand, IntValue bitOffset) {
134147 // offset of the field.
135148 bitOffset = getFieldBitOffset ( instr .( FieldAddressInstruction ) .getField ( ) ) or
136149 // A copy propagates the source value.
137- operand = instr .( CopyInstruction ) .getSourceValueOperand ( ) and bitOffset = 0
150+ operand = instr .( CopyInstruction ) .getSourceValueOperand ( ) and bitOffset = 0 or
151+ // Some functions are known to propagate an argument
152+ isAlwaysReturnedArgument ( operand ) and bitOffset = 0
138153 )
139154 )
140155}
141156
142- /**
143- * Holds if any address held in operand number `tag` of instruction `instr`
144- * escapes outside the domain of the analysis.
145- */
146- predicate operandEscapes ( Operand operand ) {
147- // Conservatively assume that the address escapes unless one of the following
148- // holds:
149- not (
150- // The operand is used in a way that does not escape the instruction
151- operandIsConsumedWithoutEscaping ( operand ) or
152- // The address is propagated to the result of the instruction, but that
153- // result does not itself escape.
154- operandIsPropagated ( operand , _ ) and not resultEscapes ( operand . getUseInstruction ( ) )
157+ private predicate operandEscapesNonReturn ( Operand operand ) {
158+ // The address is propagated to the result of the instruction, and that result itself is returned
159+ operandIsPropagated ( operand , _ ) and resultEscapesNonReturn ( operand . getUseInstruction ( ) )
160+ or
161+ // The operand is used in a function call which returns it, and the return value is then returned
162+ exists ( CallInstruction ci , Instruction init |
163+ isArgumentForParameter ( ci , operand , init ) and
164+ (
165+ resultMayReachReturn ( init ) and
166+ resultEscapesNonReturn ( ci )
167+ or
168+ resultEscapesNonReturn ( init )
169+ )
155170 )
171+ or
172+ isOnlyEscapesViaReturnArgument ( operand ) and resultEscapesNonReturn ( operand .getUseInstruction ( ) )
173+ or
174+ operand instanceof PhiOperand and
175+ resultEscapesNonReturn ( operand .getUseInstruction ( ) )
176+ or
177+ operandEscapesDomain ( operand )
178+ }
179+
180+ private predicate operandMayReachReturn ( Operand operand ) {
181+ // The address is propagated to the result of the instruction, and that result itself is returned
182+ operandIsPropagated ( operand , _) and
183+ resultMayReachReturn ( operand .getUseInstruction ( ) )
184+ or
185+ // The operand is used in a function call which returns it, and the return value is then returned
186+ exists ( CallInstruction ci , Instruction init |
187+ isArgumentForParameter ( ci , operand , init ) and
188+ resultMayReachReturn ( init ) and
189+ resultMayReachReturn ( ci )
190+ )
191+ or
192+ // The address is returned
193+ operand .getUseInstruction ( ) instanceof ReturnValueInstruction
194+ or
195+ isOnlyEscapesViaReturnArgument ( operand ) and resultMayReachReturn ( operand .getUseInstruction ( ) )
196+ or
197+ operand instanceof PhiOperand and
198+ resultMayReachReturn ( operand .getUseInstruction ( ) )
199+ }
200+
201+ private predicate operandReturned ( Operand operand , IntValue bitOffset ) {
202+ // The address is propagated to the result of the instruction, and that result itself is returned
203+ exists ( IntValue bitOffset1 , IntValue bitOffset2 |
204+ operandIsPropagated ( operand , bitOffset1 ) and
205+ resultReturned ( operand .getUseInstruction ( ) , bitOffset2 ) and
206+ bitOffset = Ints:: add ( bitOffset1 , bitOffset2 )
207+ )
208+ or
209+ // The operand is used in a function call which returns it, and the return value is then returned
210+ exists ( CallInstruction ci , Instruction init , IntValue bitOffset1 , IntValue bitOffset2 |
211+ isArgumentForParameter ( ci , operand , init ) and
212+ resultReturned ( init , bitOffset1 ) and
213+ resultReturned ( ci , bitOffset2 ) and
214+ bitOffset = Ints:: add ( bitOffset1 , bitOffset2 )
215+
216+ )
217+ or
218+ // The address is returned
219+ operand .getUseInstruction ( ) instanceof ReturnValueInstruction and
220+ bitOffset = 0
221+ or
222+ isOnlyEscapesViaReturnArgument ( operand ) and resultReturned ( operand .getUseInstruction ( ) , _) and
223+ bitOffset = Ints:: unknown ( )
224+ }
225+
226+ private predicate isArgumentForParameter ( CallInstruction ci , Operand operand , Instruction init ) {
227+ exists ( Function f |
228+ ci = operand .getUseInstruction ( ) and
229+ f = ci .getStaticCallTarget ( ) and
230+ (
231+ init .( InitializeParameterInstruction ) .getParameter ( ) = f .getParameter ( operand .( PositionalArgumentOperand ) .getIndex ( ) )
232+ or
233+ init instanceof InitializeThisInstruction and
234+ init .getEnclosingFunction ( ) = f and
235+ operand instanceof ThisArgumentOperand
236+ ) and
237+ not f .isVirtual ( ) and
238+ not f instanceof AliasFunction
239+ )
240+ }
241+
242+ private predicate isAlwaysReturnedArgument ( Operand operand ) {
243+ exists ( AliasFunction f |
244+ f = operand .getUseInstruction ( ) .( CallInstruction ) .getStaticCallTarget ( ) and
245+ f .parameterIsAlwaysReturned ( operand .( PositionalArgumentOperand ) .getIndex ( ) )
246+ )
247+ }
248+
249+ private predicate isOnlyEscapesViaReturnArgument ( Operand operand ) {
250+ exists ( AliasFunction f |
251+ f = operand .getUseInstruction ( ) .( CallInstruction ) .getStaticCallTarget ( ) and
252+ f .parameterEscapesOnlyViaReturn ( operand .( PositionalArgumentOperand ) .getIndex ( ) )
253+ )
254+ }
255+
256+ private predicate isNeverEscapesArgument ( Operand operand ) {
257+ exists ( AliasFunction f |
258+ f = operand .getUseInstruction ( ) .( CallInstruction ) .getStaticCallTarget ( ) and
259+ f .parameterNeverEscapes ( operand .( PositionalArgumentOperand ) .getIndex ( ) )
260+ )
261+ }
262+
263+ private predicate resultReturned ( Instruction instr , IntValue bitOffset ) {
264+ operandReturned ( instr .getAUse ( ) , bitOffset )
265+ }
266+
267+ private predicate resultMayReachReturn ( Instruction instr ) {
268+ operandMayReachReturn ( instr .getAUse ( ) )
156269}
157270
158271/**
159272 * Holds if any address held in the result of instruction `instr` escapes
160273 * outside the domain of the analysis.
161274 */
162- predicate resultEscapes ( Instruction instr ) {
275+ private predicate resultEscapesNonReturn ( Instruction instr ) {
163276 // The result escapes if it has at least one use that escapes.
164- operandEscapes ( instr .getAUse ( ) )
277+ operandEscapesNonReturn ( instr .getAUse ( ) )
165278}
166279
167280/**
168281 * Holds if the address of the specified local variable or parameter escapes the
169282 * domain of the analysis.
170283 */
171284private predicate automaticVariableAddressEscapes ( IRAutomaticVariable var ) {
172- exists ( FunctionIR funcIR |
173- funcIR = var .getEnclosingFunctionIR ( ) and
174- // The variable's address escapes if the result of any
175- // VariableAddressInstruction that computes the variable's address escapes.
176- exists ( VariableAddressInstruction instr |
177- instr .getEnclosingFunctionIR ( ) = funcIR and
178- instr .getVariable ( ) = var and
179- resultEscapes ( instr )
180- )
285+ // The variable's address escapes if the result of any
286+ // VariableAddressInstruction that computes the variable's address escapes.
287+ exists ( VariableAddressInstruction instr |
288+ instr .getVariable ( ) = var and
289+ resultEscapesNonReturn ( instr )
181290 )
182291}
183292
@@ -207,7 +316,14 @@ predicate resultPointsTo(Instruction instr, IRVariable var, IntValue bitOffset)
207316 // If an operand is propagated, then the result points to the same variable,
208317 // offset by the bit offset from the propagation.
209318 resultPointsTo ( operand .getDefinitionInstruction ( ) , var , originalBitOffset ) and
210- operandIsPropagated ( operand , propagatedBitOffset ) and
319+ (
320+ operandIsPropagated ( operand , propagatedBitOffset )
321+ or
322+ exists ( CallInstruction ci , Instruction init |
323+ isArgumentForParameter ( ci , operand , init ) and
324+ resultReturned ( init , propagatedBitOffset )
325+ )
326+ ) and
211327 bitOffset = Ints:: add ( originalBitOffset , propagatedBitOffset )
212328 )
213329}
0 commit comments