@@ -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/**
@@ -60,8 +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+ predicate operandEscapesDomain ( Operand operand ) {
71+ not operandIsConsumedWithoutEscaping ( operand ) and
72+ not operandIsPropagated ( operand , _) and
73+ not isArgumentForParameter ( _, operand , _) and
74+ not isOnlyEscapesViaReturnArgument ( operand )
6475}
76+
6577/**
6678 * If the result of instruction `instr` is an integer constant, returns the
6779 * value of that constant. Otherwise, returns unknown.
@@ -133,58 +145,32 @@ predicate operandIsPropagated(Operand operand, IntValue bitOffset) {
133145 // offset of the field.
134146 bitOffset = getFieldBitOffset ( instr .( FieldAddressInstruction ) .getField ( ) ) or
135147 // A copy propagates the source value.
136- operand = instr .( CopyInstruction ) .getSourceValueOperand ( ) and bitOffset = 0
137- )
138- )
139- }
140-
141- /**
142- * Holds if any address held in operand number `tag` of instruction `instr`
143- * escapes outside the domain of the analysis.
144- */
145- predicate operandEscapes ( Operand operand ) {
146- // Conservatively assume that the address escapes unless one of the following
147- // holds:
148- not (
149- // The operand is used in a way that does not escape the instruction
150- operandIsConsumedWithoutEscaping ( operand ) or
151- // The address is propagated to the result of the instruction, but that
152- // result does not itself escape.
153- operandIsPropagated ( operand , _) and not resultEscapes ( operand .getUseInstruction ( ) )
154- or
155- // The operand is used in a function call from which the operand does not escape
156- exists ( CallInstruction ci , Instruction init |
157- ci = operand .getUseInstruction ( ) and
158- isArgumentForParameter ( ci , operand , init ) and
159- not resultEscapesNonReturn ( init ) and
160- (
161- not resultReturned ( init )
162- or
163- not resultEscapes ( operand .getUseInstruction ( ) )
164- )
148+ operand = instr .( CopyInstruction ) .getSourceValueOperand ( ) and bitOffset = 0 or
149+ // Some functions are known to propagate an argument
150+ isAlwaysReturnedArgument ( operand ) and bitOffset = 0
165151 )
166152 )
167153}
168154
169155predicate operandEscapesNonReturn ( Operand operand ) {
170- // Conservatively assume that the address escapes unless one of the following
171- // holds:
172- not (
173- // The operand is used in a way that does not escape the instruction
174- operandIsConsumedWithoutEscaping ( operand ) or
175- // The address is propagated to the result of the instruction, but that
176- // result does not itself escape.
177- operandIsPropagated ( operand , _) and
178- not resultEscapesNonReturn ( operand .getUseInstruction ( ) )
179- or
180- // The operand is used in a function call from which the operand does not escape
181- exists ( CallInstruction ci , Instruction init |
182- isArgumentForParameter ( ci , operand , init ) and
183- not resultEscapesNonReturn ( init ) and
184- not resultEscapesNonReturn ( ci )
185- ) or
186- operand .getUseInstruction ( ) instanceof ReturnValueInstruction
156+ // The address is propagated to the result of the instruction, and that result itself is returned
157+ operandIsPropagated ( operand , _) and resultEscapesNonReturn ( operand .getUseInstruction ( ) )
158+ or
159+ // The operand is used in a function call which returns it, and the return value is then returned
160+ exists ( CallInstruction ci , Instruction init |
161+ ci = operand .getUseInstruction ( ) and
162+ isArgumentForParameter ( ci , operand , init ) and
163+ (
164+ resultReturned ( init ) and
165+ resultEscapesNonReturn ( ci )
166+ or
167+ resultEscapesNonReturn ( init )
168+ )
187169 )
170+ or
171+ isOnlyEscapesViaReturnArgument ( operand ) and resultEscapesNonReturn ( operand .getUseInstruction ( ) )
172+ or
173+ operandEscapesDomain ( operand )
188174}
189175
190176
@@ -202,6 +188,8 @@ predicate operandReturned(Operand operand) {
202188 or
203189 // The address is returned
204190 operand .getUseInstruction ( ) instanceof ReturnValueInstruction
191+ or
192+ isOnlyEscapesViaReturnArgument ( operand ) and resultReturned ( operand .getUseInstruction ( ) )
205193}
206194
207195predicate isArgumentForParameter ( CallInstruction ci , Operand operand , Instruction init ) {
@@ -215,7 +203,29 @@ predicate isArgumentForParameter(CallInstruction ci, Operand operand, Instructio
215203 init .getEnclosingFunction ( ) = f and
216204 operand instanceof ThisArgumentOperand
217205 ) and
218- not f .isVirtual ( )
206+ not f .isVirtual ( ) and
207+ not f instanceof AliasFunction
208+ )
209+ }
210+
211+ predicate isAlwaysReturnedArgument ( Operand operand ) {
212+ exists ( AliasFunction f |
213+ f = operand .getUseInstruction ( ) .( CallInstruction ) .getStaticCallTarget ( ) and
214+ f .parameterIsAlwaysReturned ( operand .( PositionalArgumentOperand ) .getIndex ( ) )
215+ )
216+ }
217+
218+ predicate isOnlyEscapesViaReturnArgument ( Operand operand ) {
219+ exists ( AliasFunction f |
220+ f = operand .getUseInstruction ( ) .( CallInstruction ) .getStaticCallTarget ( ) and
221+ f .parameterEscapesOnlyViaReturn ( operand .( PositionalArgumentOperand ) .getIndex ( ) )
222+ )
223+ }
224+
225+ predicate isNeverEscapesArgument ( Operand operand ) {
226+ exists ( AliasFunction f |
227+ f = operand .getUseInstruction ( ) .( CallInstruction ) .getStaticCallTarget ( ) and
228+ f .parameterNeverEscapes ( operand .( PositionalArgumentOperand ) .getIndex ( ) )
219229 )
220230}
221231
@@ -227,12 +237,7 @@ predicate resultReturned(Instruction instr) {
227237 * Holds if any address held in the result of instruction `instr` escapes
228238 * outside the domain of the analysis.
229239 */
230- predicate resultEscapes ( Instruction instr ) {
231- // The result escapes if it has at least one use that escapes.
232- operandEscapes ( instr .getAUse ( ) )
233- }
234-
235- predicate resultEscapesNonReturn ( Instruction instr ) {
240+ predicate resultEscapesNonReturn ( Instruction instr ) {
236241 // The result escapes if it has at least one use that escapes.
237242 operandEscapesNonReturn ( instr .getAUse ( ) )
238243}
0 commit comments