11private import AliasAnalysisInternal
2- private import cpp
32private import InputIR
4- private import semmle.code.cpp.ir.internal.IntegerConstant as Ints
5- private import semmle.code.cpp.ir.implementation.IRConfiguration
6- private import semmle.code.cpp.models.interfaces.Alias
3+ private import AliasAnalysisImports
74
85private class IntValue = Ints:: IntValue ;
96
10- /**
11- * Gets the offset of field `field` in bits.
12- */
13- private IntValue getFieldBitOffset ( Field field ) {
14- if field instanceof BitField
15- then result = Ints:: add ( Ints:: mul ( field .getByteOffset ( ) , 8 ) , field .( BitField ) .getBitOffset ( ) )
16- else result = Ints:: mul ( field .getByteOffset ( ) , 8 )
17- }
18-
197/**
208 * Holds if the operand `tag` of instruction `instr` is used in a way that does
219 * not result in any address held in that operand from escaping beyond the
@@ -36,7 +24,7 @@ private predicate operandIsConsumedWithoutEscaping(Operand operand) {
3624 instr instanceof PointerDiffInstruction
3725 or
3826 // Converting an address to a `bool` does not escape the address.
39- instr .( ConvertInstruction ) .getResultType ( ) instanceof BoolType
27+ instr .( ConvertInstruction ) .getResultIRType ( ) instanceof IRBooleanType
4028 )
4129 )
4230 or
@@ -111,13 +99,10 @@ private predicate operandIsPropagated(Operand operand, IntValue bitOffset) {
11199 bitOffset = Ints:: unknown ( )
112100 or
113101 // Conversion to another pointer type propagates the source address.
114- exists ( ConvertInstruction convert , Type resultType |
102+ exists ( ConvertInstruction convert , IRType resultType |
115103 convert = instr and
116- resultType = convert .getResultType ( ) and
117- (
118- resultType instanceof PointerType or
119- resultType instanceof Class //REVIEW: Remove when all glvalues are pointers
120- ) and
104+ resultType = convert .getResultIRType ( ) and
105+ resultType instanceof IRAddressType and
121106 bitOffset = 0
122107 )
123108 or
@@ -131,7 +116,7 @@ private predicate operandIsPropagated(Operand operand, IntValue bitOffset) {
131116 or
132117 // Computing a field address from a pointer propagates the address plus the
133118 // offset of the field.
134- bitOffset = getFieldBitOffset ( instr .( FieldAddressInstruction ) .getField ( ) )
119+ bitOffset = Language :: getFieldBitOffset ( instr .( FieldAddressInstruction ) .getField ( ) )
135120 or
136121 // A copy propagates the source value.
137122 operand = instr .( CopyInstruction ) .getSourceValueOperand ( ) and bitOffset = 0
@@ -212,7 +197,7 @@ private predicate operandReturned(Operand operand, IntValue bitOffset) {
212197}
213198
214199private predicate isArgumentForParameter ( CallInstruction ci , Operand operand , Instruction init ) {
215- exists ( Function f |
200+ exists ( Language :: Function f |
216201 ci = operand .getUse ( ) and
217202 f = ci .getStaticCallTarget ( ) and
218203 (
@@ -223,27 +208,27 @@ private predicate isArgumentForParameter(CallInstruction ci, Operand operand, In
223208 init .getEnclosingFunction ( ) = f and
224209 operand instanceof ThisArgumentOperand
225210 ) and
226- not f . isVirtual ( ) and
227- not f instanceof AliasFunction
211+ not Language :: isFunctionVirtual ( f ) and
212+ not f instanceof AliasModels :: AliasFunction
228213 )
229214}
230215
231216private predicate isAlwaysReturnedArgument ( Operand operand ) {
232- exists ( AliasFunction f |
217+ exists ( AliasModels :: AliasFunction f |
233218 f = operand .getUse ( ) .( CallInstruction ) .getStaticCallTarget ( ) and
234219 f .parameterIsAlwaysReturned ( operand .( PositionalArgumentOperand ) .getIndex ( ) )
235220 )
236221}
237222
238223private predicate isOnlyEscapesViaReturnArgument ( Operand operand ) {
239- exists ( AliasFunction f |
224+ exists ( AliasModels :: AliasFunction f |
240225 f = operand .getUse ( ) .( CallInstruction ) .getStaticCallTarget ( ) and
241226 f .parameterEscapesOnlyViaReturn ( operand .( PositionalArgumentOperand ) .getIndex ( ) )
242227 )
243228}
244229
245230private predicate isNeverEscapesArgument ( Operand operand ) {
246- exists ( AliasFunction f |
231+ exists ( AliasModels :: AliasFunction f |
247232 f = operand .getUse ( ) .( CallInstruction ) .getStaticCallTarget ( ) and
248233 f .parameterNeverEscapes ( operand .( PositionalArgumentOperand ) .getIndex ( ) )
249234 )
@@ -265,61 +250,86 @@ private predicate resultEscapesNonReturn(Instruction instr) {
265250}
266251
267252/**
268- * Holds if the address of the specified local variable or parameter escapes the
269- * domain of the analysis.
253+ * Holds if the address of `allocation` escapes outside the domain of the analysis. This can occur
254+ * either because the allocation's address is taken within the function and escapes, or because the
255+ * allocation is marked as always escaping via `alwaysEscapes()`.
270256 */
271- private predicate automaticVariableAddressEscapes ( IRAutomaticVariable var ) {
272- // The variable's address escapes if the result of any
273- // VariableAddressInstruction that computes the variable's address escapes.
274- exists ( VariableAddressInstruction instr |
275- instr .getIRVariable ( ) = var and
276- resultEscapesNonReturn ( instr )
257+ predicate allocationEscapes ( Configuration:: Allocation allocation ) {
258+ allocation .alwaysEscapes ( )
259+ or
260+ exists ( IREscapeAnalysisConfiguration config |
261+ config .useSoundEscapeAnalysis ( ) and resultEscapesNonReturn ( allocation .getABaseInstruction ( ) )
277262 )
278263}
279264
280265/**
281- * Holds if the address of the specified variable escapes the domain of the
282- * analysis.
266+ * Equivalent to `operandIsPropagated()`, but includes interprocedural propagation.
283267 */
284- predicate variableAddressEscapes ( IRVariable var ) {
285- exists ( IREscapeAnalysisConfiguration config |
286- config .useSoundEscapeAnalysis ( ) and
287- automaticVariableAddressEscapes ( var .( IRAutomaticVariable ) )
288- )
268+ private predicate operandIsPropagatedIncludingByCall ( Operand operand , IntValue bitOffset ) {
269+ operandIsPropagated ( operand , bitOffset )
289270 or
290- // All variables with static storage duration have their address escape, even when escape analysis
291- // is allowed to be unsound. Otherwise, we won't have a definition for any non-escaped global
292- // variable. Normally, we rely on `AliasedDefinition` to handle that.
293- not var instanceof IRAutomaticVariable
271+ exists ( CallInstruction call , Instruction init |
272+ isArgumentForParameter ( call , operand , init ) and
273+ resultReturned ( init , bitOffset )
274+ )
294275}
295276
296277/**
297- * Holds if the result of instruction `instr` points within variable `var`, at
298- * bit offset `bitOffset` within the variable. If the result points within
299- * `var`, but at an unknown or non-constant offset, then `bitOffset` is unknown.
278+ * Holds if `addrOperand` is at offset `bitOffset` from the value of instruction `base`. The offset
279+ * may be `unknown()`.
300280 */
301- predicate resultPointsTo ( Instruction instr , IRVariable var , IntValue bitOffset ) {
302- // The address of a variable points to that variable, at offset 0.
303- instr .( VariableAddressInstruction ) .getIRVariable ( ) = var and
304- bitOffset = 0
305- or
306- // A string literal is just a special read-only global variable.
307- instr .( StringConstantInstruction ) .getIRVariable ( ) = var and
308- bitOffset = 0
281+ private predicate hasBaseAndOffset ( AddressOperand addrOperand , Instruction base , IntValue bitOffset ) {
282+ base = addrOperand .getDef ( ) and bitOffset = 0 // Base case
309283 or
310- exists ( Operand operand , IntValue originalBitOffset , IntValue propagatedBitOffset |
311- operand = instr .getAnOperand ( ) and
312- // If an operand is propagated, then the result points to the same variable,
313- // offset by the bit offset from the propagation.
314- resultPointsTo ( operand .getAnyDef ( ) , var , originalBitOffset ) and
315- (
316- operandIsPropagated ( operand , propagatedBitOffset )
317- or
318- exists ( CallInstruction ci , Instruction init |
319- isArgumentForParameter ( ci , operand , init ) and
320- resultReturned ( init , propagatedBitOffset )
321- )
322- ) and
323- bitOffset = Ints:: add ( originalBitOffset , propagatedBitOffset )
284+ exists (
285+ Instruction middle , int previousBitOffset , Operand middleOperand , IntValue additionalBitOffset
286+ |
287+ // We already have an offset from `middle`.
288+ hasBaseAndOffset ( addrOperand , middle , previousBitOffset ) and
289+ // `middle` is propagated from `base`.
290+ middleOperand = middle .getAnOperand ( ) and
291+ operandIsPropagatedIncludingByCall ( middleOperand , additionalBitOffset ) and
292+ base = middleOperand .getDef ( ) and
293+ bitOffset = Ints:: add ( previousBitOffset , additionalBitOffset )
294+ )
295+ }
296+
297+ /**
298+ * Holds if `addrOperand` is at constant offset `bitOffset` from the value of instruction `base`.
299+ * Only holds for the `base` with the longest chain of propagation to `addrOperand`.
300+ */
301+ predicate addressOperandBaseAndConstantOffset (
302+ AddressOperand addrOperand , Instruction base , int bitOffset
303+ ) {
304+ hasBaseAndOffset ( addrOperand , base , bitOffset ) and
305+ Ints:: hasValue ( bitOffset ) and
306+ not exists ( Instruction previousBase , int previousBitOffset |
307+ hasBaseAndOffset ( addrOperand , previousBase , previousBitOffset ) and
308+ previousBase = base .getAnOperand ( ) .getDef ( ) and
309+ Ints:: hasValue ( previousBitOffset )
310+ )
311+ }
312+
313+ /**
314+ * Gets the allocation into which `addrOperand` points, if known.
315+ */
316+ Configuration:: Allocation getAddressOperandAllocation ( AddressOperand addrOperand ) {
317+ addressOperandAllocationAndOffset ( addrOperand , result , _)
318+ }
319+
320+ /**
321+ * Holds if `addrOperand` is at offset `bitOffset` from a base instruction of `allocation`. The
322+ * offset may be `unknown()`.
323+ */
324+ predicate addressOperandAllocationAndOffset (
325+ AddressOperand addrOperand , Configuration:: Allocation allocation , IntValue bitOffset
326+ ) {
327+ exists ( Instruction base |
328+ allocation .getABaseInstruction ( ) = base and
329+ hasBaseAndOffset ( addrOperand , base , bitOffset ) and
330+ not exists ( Instruction previousBase |
331+ hasBaseAndOffset ( addrOperand , previousBase , _) and
332+ previousBase = base .getAnOperand ( ) .getDef ( )
333+ )
324334 )
325335}
0 commit comments