Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 466e110

Browse files
author
Robert Marsh
committed
C++: add new interprocedural escape analysis
1 parent bd39698 commit 466e110

8 files changed

Lines changed: 359 additions & 188 deletions

File tree

cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1310,6 +1310,13 @@ class CallInstruction extends Instruction {
13101310
result = getAnOperand()
13111311
}
13121312

1313+
/**
1314+
* Gets the `Function` that the call targets, if this is statically known.
1315+
*/
1316+
final Function getStaticCallTarget() {
1317+
result = getCallTarget().(FunctionInstruction).getFunctionSymbol()
1318+
}
1319+
13131320
/**
13141321
* Gets all of the arguments of the call, including the `this` pointer, if any.
13151322
*/

cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll

Lines changed: 75 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@ predicate operandIsConsumedWithoutEscaping(Operand operand) {
6262
)
6363
)
6464
}
65-
6665
/**
6766
* If the result of instruction `instr` is an integer constant, returns the
6867
* value of that constant. Otherwise, returns unknown.
@@ -143,7 +142,7 @@ predicate operandIsPropagated(Operand operand, IntValue bitOffset) {
143142
* Holds if any address held in operand number `tag` of instruction `instr`
144143
* escapes outside the domain of the analysis.
145144
*/
146-
predicate operandEscapes(Operand operand) {
145+
predicate operandEscapes(Operand operand) {
147146
// Conservatively assume that the address escapes unless one of the following
148147
// holds:
149148
not (
@@ -152,9 +151,66 @@ predicate operandEscapes(Operand operand) {
152151
// The address is propagated to the result of the instruction, but that
153152
// result does not itself escape.
154153
operandIsPropagated(operand, _) and not resultEscapes(operand.getUseInstruction())
154+
or
155+
// The address is passed as an argument to a function from which it does not escape
156+
exists(CallInstruction ci, FunctionIR f, InitializeParameterInstruction ipi |
157+
ci = operand.getUseInstruction() and
158+
f.getFunction() = ci.getStaticCallTarget() and
159+
ipi.getParameter() = f.getFunction().getParameter(operand.(PositionalArgumentOperand).getIndex()) and
160+
not resultEscapesNonReturn(ipi) and
161+
(
162+
not resultReturned(ipi)
163+
or
164+
not resultEscapes(operand.getUseInstruction())
165+
)
166+
)
155167
)
156168
}
157169

170+
predicate operandEscapesNonReturn(Operand operand) {
171+
// Conservatively assume that the address escapes unless one of the following
172+
// holds:
173+
not (
174+
// The operand is used in a way that does not escape the instruction
175+
operandIsConsumedWithoutEscaping(operand) or
176+
// The address is propagated to the result of the instruction, but that
177+
// result does not itself escape.
178+
operandIsPropagated(operand, _) and
179+
not resultEscapesNonReturn(operand.getUseInstruction())
180+
or
181+
// The operand is used in a function call from which the operand does not escape
182+
exists(CallInstruction ci, FunctionIR f, InitializeParameterInstruction ipi |
183+
ci = operand.getUseInstruction() and
184+
f.getFunction() = ci.getStaticCallTarget() and
185+
ipi.getParameter() = f.getFunction().getParameter(operand.(PositionalArgumentOperand).getIndex()) and
186+
not resultEscapesNonReturn(ipi) and
187+
not resultEscapesNonReturn(ci)
188+
) or
189+
operand instanceof ReturnValueOperand
190+
)
191+
}
192+
193+
predicate operandReturned(Operand operand) {
194+
// The address is propagated to the result of the instruction, and that result itself is returned
195+
operandIsPropagated(operand, _) and resultReturned(operand.getUseInstruction())
196+
or
197+
// The operand is used in a function call which returns it, and the return value is then returned
198+
exists(CallInstruction ci, FunctionIR f, InitializeParameterInstruction ipi |
199+
ci = operand.getUseInstruction() and
200+
f.getFunction() = ci.getStaticCallTarget() and
201+
ipi.getParameter() = f.getFunction().getParameter(operand.(PositionalArgumentOperand).getIndex()) and
202+
resultReturned(ipi) and
203+
resultReturned(ci)
204+
)
205+
or
206+
// The address is returned
207+
operand instanceof ReturnValueOperand
208+
}
209+
210+
predicate resultReturned(Instruction instr) {
211+
operandReturned(instr.getAUse())
212+
}
213+
158214
/**
159215
* Holds if any address held in the result of instruction `instr` escapes
160216
* outside the domain of the analysis.
@@ -164,6 +220,11 @@ predicate resultEscapes(Instruction instr) {
164220
operandEscapes(instr.getAUse())
165221
}
166222

223+
predicate resultEscapesNonReturn(Instruction instr) {
224+
// The result escapes if it has at least one use that escapes.
225+
operandEscapesNonReturn(instr.getAUse())
226+
}
227+
167228
/**
168229
* Holds if the address of the specified local variable or parameter escapes the
169230
* domain of the analysis.
@@ -176,7 +237,7 @@ private predicate automaticVariableAddressEscapes(IRAutomaticVariable var) {
176237
exists(VariableAddressInstruction instr |
177238
instr.getEnclosingFunctionIR() = funcIR and
178239
instr.getVariable() = var and
179-
resultEscapes(instr)
240+
resultEscapesNonReturn(instr)
180241
)
181242
)
182243
}
@@ -207,7 +268,17 @@ predicate resultPointsTo(Instruction instr, IRVariable var, IntValue bitOffset)
207268
// If an operand is propagated, then the result points to the same variable,
208269
// offset by the bit offset from the propagation.
209270
resultPointsTo(operand.getDefinitionInstruction(), var, originalBitOffset) and
210-
operandIsPropagated(operand, propagatedBitOffset) and
271+
(
272+
operandIsPropagated(operand, propagatedBitOffset)
273+
or
274+
exists(CallInstruction ci, FunctionIR f, InitializeParameterInstruction ipi |
275+
ci = operand.getUseInstruction() and
276+
f.getFunction() = ci.getStaticCallTarget() and
277+
ipi.getParameter() = f.getFunction().getParameter(operand.(PositionalArgumentOperand).getIndex()) and
278+
resultReturned(ipi) and
279+
propagatedBitOffset = Ints::unknown()
280+
)
281+
) and
211282
bitOffset = Ints::add(originalBitOffset, propagatedBitOffset)
212283
)
213284
}

cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1310,6 +1310,13 @@ class CallInstruction extends Instruction {
13101310
result = getAnOperand()
13111311
}
13121312

1313+
/**
1314+
* Gets the `Function` that the call targets, if this is statically known.
1315+
*/
1316+
final Function getStaticCallTarget() {
1317+
result = getCallTarget().(FunctionInstruction).getFunctionSymbol()
1318+
}
1319+
13131320
/**
13141321
* Gets all of the arguments of the call, including the `this` pointer, if any.
13151322
*/

cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1310,6 +1310,13 @@ class CallInstruction extends Instruction {
13101310
result = getAnOperand()
13111311
}
13121312

1313+
/**
1314+
* Gets the `Function` that the call targets, if this is statically known.
1315+
*/
1316+
final Function getStaticCallTarget() {
1317+
result = getCallTarget().(FunctionInstruction).getFunctionSymbol()
1318+
}
1319+
13131320
/**
13141321
* Gets all of the arguments of the call, including the `this` pointer, if any.
13151322
*/

cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll

Lines changed: 75 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@ predicate operandIsConsumedWithoutEscaping(Operand operand) {
6262
)
6363
)
6464
}
65-
6665
/**
6766
* If the result of instruction `instr` is an integer constant, returns the
6867
* value of that constant. Otherwise, returns unknown.
@@ -143,7 +142,7 @@ predicate operandIsPropagated(Operand operand, IntValue bitOffset) {
143142
* Holds if any address held in operand number `tag` of instruction `instr`
144143
* escapes outside the domain of the analysis.
145144
*/
146-
predicate operandEscapes(Operand operand) {
145+
predicate operandEscapes(Operand operand) {
147146
// Conservatively assume that the address escapes unless one of the following
148147
// holds:
149148
not (
@@ -152,9 +151,66 @@ predicate operandEscapes(Operand operand) {
152151
// The address is propagated to the result of the instruction, but that
153152
// result does not itself escape.
154153
operandIsPropagated(operand, _) and not resultEscapes(operand.getUseInstruction())
154+
or
155+
// The address is passed as an argument to a function from which it does not escape
156+
exists(CallInstruction ci, FunctionIR f, InitializeParameterInstruction ipi |
157+
ci = operand.getUseInstruction() and
158+
f.getFunction() = ci.getStaticCallTarget() and
159+
ipi.getParameter() = f.getFunction().getParameter(operand.(PositionalArgumentOperand).getIndex()) and
160+
not resultEscapesNonReturn(ipi) and
161+
(
162+
not resultReturned(ipi)
163+
or
164+
not resultEscapes(operand.getUseInstruction())
165+
)
166+
)
155167
)
156168
}
157169

170+
predicate operandEscapesNonReturn(Operand operand) {
171+
// Conservatively assume that the address escapes unless one of the following
172+
// holds:
173+
not (
174+
// The operand is used in a way that does not escape the instruction
175+
operandIsConsumedWithoutEscaping(operand) or
176+
// The address is propagated to the result of the instruction, but that
177+
// result does not itself escape.
178+
operandIsPropagated(operand, _) and
179+
not resultEscapesNonReturn(operand.getUseInstruction())
180+
or
181+
// The operand is used in a function call from which the operand does not escape
182+
exists(CallInstruction ci, FunctionIR f, InitializeParameterInstruction ipi |
183+
ci = operand.getUseInstruction() and
184+
f.getFunction() = ci.getStaticCallTarget() and
185+
ipi.getParameter() = f.getFunction().getParameter(operand.(PositionalArgumentOperand).getIndex()) and
186+
not resultEscapesNonReturn(ipi) and
187+
not resultEscapesNonReturn(ci)
188+
) or
189+
operand instanceof ReturnValueOperand
190+
)
191+
}
192+
193+
predicate operandReturned(Operand operand) {
194+
// The address is propagated to the result of the instruction, and that result itself is returned
195+
operandIsPropagated(operand, _) and resultReturned(operand.getUseInstruction())
196+
or
197+
// The operand is used in a function call which returns it, and the return value is then returned
198+
exists(CallInstruction ci, FunctionIR f, InitializeParameterInstruction ipi |
199+
ci = operand.getUseInstruction() and
200+
f.getFunction() = ci.getStaticCallTarget() and
201+
ipi.getParameter() = f.getFunction().getParameter(operand.(PositionalArgumentOperand).getIndex()) and
202+
resultReturned(ipi) and
203+
resultReturned(ci)
204+
)
205+
or
206+
// The address is returned
207+
operand instanceof ReturnValueOperand
208+
}
209+
210+
predicate resultReturned(Instruction instr) {
211+
operandReturned(instr.getAUse())
212+
}
213+
158214
/**
159215
* Holds if any address held in the result of instruction `instr` escapes
160216
* outside the domain of the analysis.
@@ -164,6 +220,11 @@ predicate resultEscapes(Instruction instr) {
164220
operandEscapes(instr.getAUse())
165221
}
166222

223+
predicate resultEscapesNonReturn(Instruction instr) {
224+
// The result escapes if it has at least one use that escapes.
225+
operandEscapesNonReturn(instr.getAUse())
226+
}
227+
167228
/**
168229
* Holds if the address of the specified local variable or parameter escapes the
169230
* domain of the analysis.
@@ -176,7 +237,7 @@ private predicate automaticVariableAddressEscapes(IRAutomaticVariable var) {
176237
exists(VariableAddressInstruction instr |
177238
instr.getEnclosingFunctionIR() = funcIR and
178239
instr.getVariable() = var and
179-
resultEscapes(instr)
240+
resultEscapesNonReturn(instr)
180241
)
181242
)
182243
}
@@ -207,7 +268,17 @@ predicate resultPointsTo(Instruction instr, IRVariable var, IntValue bitOffset)
207268
// If an operand is propagated, then the result points to the same variable,
208269
// offset by the bit offset from the propagation.
209270
resultPointsTo(operand.getDefinitionInstruction(), var, originalBitOffset) and
210-
operandIsPropagated(operand, propagatedBitOffset) and
271+
(
272+
operandIsPropagated(operand, propagatedBitOffset)
273+
or
274+
exists(CallInstruction ci, FunctionIR f, InitializeParameterInstruction ipi |
275+
ci = operand.getUseInstruction() and
276+
f.getFunction() = ci.getStaticCallTarget() and
277+
ipi.getParameter() = f.getFunction().getParameter(operand.(PositionalArgumentOperand).getIndex()) and
278+
resultReturned(ipi) and
279+
propagatedBitOffset = Ints::unknown()
280+
)
281+
) and
211282
bitOffset = Ints::add(originalBitOffset, propagatedBitOffset)
212283
)
213284
}

0 commit comments

Comments
 (0)